Line data Source code
1 : // Copyright (c) 2011-2021 The Bitcoin Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : // 5 : #include <fs.h> 6 : #include <test/util/setup_common.h> 7 : #include <util/getuniquepath.h> 8 : #include <util/system.h> 9 : 10 : #include <boost/test/unit_test.hpp> 11 : 12 : #include <fstream> 13 : #include <ios> 14 : #include <string> 15 : 16 146 : BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup) 17 : 18 149 : BOOST_AUTO_TEST_CASE(fsbridge_pathtostring) 19 : { 20 1 : std::string u8_str = "fs_tests_∋_🏃"; 21 1 : std::u8string str8{u8"fs_tests_∋_🏃"}; 22 1 : BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(u8_str)), u8_str); 23 1 : BOOST_CHECK_EQUAL(fs::u8path(u8_str).utf8string(), u8_str); 24 1 : BOOST_CHECK_EQUAL(fs::path(str8).utf8string(), u8_str); 25 1 : BOOST_CHECK(fs::path(str8).u8string() == str8); 26 1 : BOOST_CHECK_EQUAL(fs::PathFromString(u8_str).utf8string(), u8_str); 27 1 : BOOST_CHECK_EQUAL(fs::PathToString(fs::u8path(u8_str)), u8_str); 28 : #ifndef WIN32 29 : // On non-windows systems, verify that arbitrary byte strings containing 30 : // invalid UTF-8 can be round tripped successfully with PathToString and 31 : // PathFromString. On non-windows systems, paths are just byte strings so 32 : // these functions do not do any encoding. On windows, paths are Unicode, 33 : // and these functions do encoding and decoding, so the behavior of this 34 : // test would be undefined. 35 1 : std::string invalid_u8_str = "\xf0"; 36 1 : BOOST_CHECK_EQUAL(invalid_u8_str.size(), 1); 37 1 : BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(invalid_u8_str)), invalid_u8_str); 38 : #endif 39 1 : } 40 : 41 149 : BOOST_AUTO_TEST_CASE(fsbridge_stem) 42 : { 43 1 : std::string test_filename = "fs_tests_∋_🏃.dat"; 44 1 : std::string expected_stem = "fs_tests_∋_🏃"; 45 1 : BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(test_filename).stem()), expected_stem); 46 1 : } 47 : 48 149 : BOOST_AUTO_TEST_CASE(fsbridge_fstream) 49 : { 50 1 : fs::path tmpfolder = m_args.GetDataDirBase(); 51 : // tmpfile1 should be the same as tmpfile2 52 1 : fs::path tmpfile1 = tmpfolder / fs::u8path("fs_tests_∋_🏃"); 53 1 : fs::path tmpfile2 = tmpfolder / fs::path(u8"fs_tests_∋_🏃"); 54 : { 55 1 : std::ofstream file{tmpfile1}; 56 1 : file << "bitcoin"; 57 1 : } 58 : { 59 1 : std::ifstream file{tmpfile2}; 60 1 : std::string input_buffer; 61 1 : file >> input_buffer; 62 1 : BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); 63 1 : } 64 : { 65 1 : std::ifstream file{tmpfile1, std::ios_base::in | std::ios_base::ate}; 66 1 : std::string input_buffer; 67 1 : file >> input_buffer; 68 1 : BOOST_CHECK_EQUAL(input_buffer, ""); 69 1 : } 70 : { 71 1 : std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::app}; 72 1 : file << "tests"; 73 1 : } 74 : { 75 1 : std::ifstream file{tmpfile1}; 76 1 : std::string input_buffer; 77 1 : file >> input_buffer; 78 1 : BOOST_CHECK_EQUAL(input_buffer, "bitcointests"); 79 1 : } 80 : { 81 1 : std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::trunc}; 82 1 : file << "bitcoin"; 83 1 : } 84 : { 85 1 : std::ifstream file{tmpfile1}; 86 1 : std::string input_buffer; 87 1 : file >> input_buffer; 88 1 : BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); 89 1 : } 90 : { 91 1 : fs::path p1 = GetUniquePath(tmpfolder); 92 1 : fs::path p2 = GetUniquePath(tmpfolder); 93 1 : fs::path p3 = GetUniquePath(tmpfolder); 94 : 95 : // Ensure that the parent path is always the same. 96 1 : BOOST_CHECK_EQUAL(tmpfolder, p1.parent_path()); 97 1 : BOOST_CHECK_EQUAL(tmpfolder, p2.parent_path()); 98 1 : BOOST_CHECK_EQUAL(tmpfolder, p3.parent_path()); 99 : 100 : // Ensure that generated paths are actually different. 101 1 : BOOST_CHECK(p1 != p2); 102 1 : BOOST_CHECK(p2 != p3); 103 1 : BOOST_CHECK(p1 != p3); 104 1 : } 105 : { 106 : // Join an absolute path and a relative path. 107 1 : fs::path p = fsbridge::AbsPathJoin(tmpfolder, fs::u8path("fs_tests_∋_🏃")); 108 1 : BOOST_CHECK(p.is_absolute()); 109 1 : BOOST_CHECK_EQUAL(tmpfile1, p); 110 1 : } 111 : { 112 : // Join two absolute paths. 113 1 : fs::path p = fsbridge::AbsPathJoin(tmpfile1, tmpfile2); 114 1 : BOOST_CHECK(p.is_absolute()); 115 1 : BOOST_CHECK_EQUAL(tmpfile2, p); 116 1 : } 117 : { 118 : // Ensure joining with empty paths does not add trailing path components. 119 1 : BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, "")); 120 1 : BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, {})); 121 : } 122 1 : } 123 : 124 149 : BOOST_AUTO_TEST_CASE(rename) 125 : { 126 1 : const fs::path tmpfolder{m_args.GetDataDirBase()}; 127 : 128 1 : const fs::path path1{GetUniquePath(tmpfolder)}; 129 1 : const fs::path path2{GetUniquePath(tmpfolder)}; 130 : 131 1 : const std::string path1_contents{"1111"}; 132 1 : const std::string path2_contents{"2222"}; 133 : 134 : { 135 1 : std::ofstream file{path1}; 136 1 : file << path1_contents; 137 1 : } 138 : 139 : { 140 1 : std::ofstream file{path2}; 141 1 : file << path2_contents; 142 1 : } 143 : 144 : // Rename path1 -> path2. 145 1 : BOOST_CHECK(RenameOver(path1, path2)); 146 : 147 1 : BOOST_CHECK(!fs::exists(path1)); 148 : 149 : { 150 1 : std::ifstream file{path2}; 151 1 : std::string contents; 152 1 : file >> contents; 153 1 : BOOST_CHECK_EQUAL(contents, path1_contents); 154 1 : } 155 1 : fs::remove(path2); 156 1 : } 157 : 158 : #ifndef __MINGW64__ // no symlinks on mingw 159 149 : BOOST_AUTO_TEST_CASE(create_directories) 160 : { 161 : // Test fs::create_directories workaround. 162 1 : const fs::path tmpfolder{m_args.GetDataDirBase()}; 163 : 164 1 : const fs::path dir{GetUniquePath(tmpfolder)}; 165 1 : fs::create_directory(dir); 166 1 : BOOST_CHECK(fs::exists(dir)); 167 1 : BOOST_CHECK(fs::is_directory(dir)); 168 1 : BOOST_CHECK(!fs::create_directories(dir)); 169 : 170 1 : const fs::path symlink{GetUniquePath(tmpfolder)}; 171 1 : fs::create_directory_symlink(dir, symlink); 172 1 : BOOST_CHECK(fs::exists(symlink)); 173 1 : BOOST_CHECK(fs::is_symlink(symlink)); 174 1 : BOOST_CHECK(fs::is_directory(symlink)); 175 1 : BOOST_CHECK(!fs::create_directories(symlink)); 176 : 177 1 : fs::remove(symlink); 178 1 : fs::remove(dir); 179 1 : } 180 : #endif // __MINGW64__ 181 : 182 146 : BOOST_AUTO_TEST_SUITE_END() 183 :