Bitcoin Core  26.99.0
P2P Digital Currency
fs_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 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 //
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_₿_🏃"};
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);
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 << "bitcoin";
56  }
57  {
58  std::ifstream file{tmpfile2};
59  std::string input_buffer;
60  file >> input_buffer;
61  BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
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, "bitcointests");
78  }
79  {
80  std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::trunc};
81  file << "bitcoin";
82  }
83  {
84  std::ifstream file{tmpfile1};
85  std::string input_buffer;
86  file >> input_buffer;
87  BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
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 
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
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));
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));
160 
161  fs::remove(symlink);
162  fs::remove(dir);
163 }
164 #endif // __MINGW64__
165 
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
unsigned char u8
BOOST_AUTO_TEST_SUITE_END()
bool RenameOver(fs::path src, fs::path dest)
Rename src to dest.
Definition: fs_helpers.cpp:250
BOOST_AUTO_TEST_CASE(fsbridge_pathtostring)
Definition: fs_tests.cpp:17
static path u8path(const std::string &utf8_str)
Definition: fs.h:75
static bool create_directories(const std::filesystem::path &p)
Create directory (and if necessary its parents), unless the leaf directory already exists or is a sym...
Definition: fs.h:190
static bool exists(const path &p)
Definition: fs.h:89
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:36
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
Basic testing setup.
Definition: setup_common.h:49