/ src / test / fs_tests.cpp
fs_tests.cpp
  1  // Copyright (c) 2011-present 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 <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.std_path()};
 55          file << "bitcoin";
 56      }
 57      {
 58          std::ifstream file{tmpfile2.std_path()};
 59          std::string input_buffer;
 60          file >> input_buffer;
 61          BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
 62      }
 63      {
 64          std::ifstream file{tmpfile1.std_path(), 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_path(), std::ios_base::out | std::ios_base::app};
 71          file << "tests";
 72      }
 73      {
 74          std::ifstream file{tmpfile1.std_path()};
 75          std::string input_buffer;
 76          file >> input_buffer;
 77          BOOST_CHECK_EQUAL(input_buffer, "bitcointests");
 78      }
 79      {
 80          std::ofstream file{tmpfile2.std_path(), std::ios_base::out | std::ios_base::trunc};
 81          file << "bitcoin";
 82      }
 83      {
 84          std::ifstream file{tmpfile1.std_path()};
 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  
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.std_path()};
120          file << path1_contents;
121      }
122  
123      {
124          std::ofstream file{path2.std_path()};
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.std_path()};
135          std::string contents;
136          file >> contents;
137          BOOST_CHECK_EQUAL(contents, path1_contents);
138      }
139      fs::remove(path2);
140  }
141  
142  BOOST_AUTO_TEST_SUITE_END()