fs_tests.cpp raw

   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()
 143