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