16e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#ifndef FILESYSTEM_TEST_HELPER_HPP
26e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#define FILESYSTEM_TEST_HELPER_HPP
36e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
46e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#include <experimental/filesystem>
56e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#include <cassert>
66e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#include <cstdio> // for printf
76e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#include <string>
86e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#include <fstream>
96e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#include <random>
1040d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier#include <chrono>
116e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
126e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiseliernamespace fs = std::experimental::filesystem;
136e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
146e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// static test helpers
156e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
166e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
176e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#warning "STATIC TESTS DISABLED"
186e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#else // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
196e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
206e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiseliernamespace StaticEnv {
216e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
226e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierinline fs::path makePath(fs::path const& p) {
23374a33d1b9a9808c3f641867bb5e68a8e93bd9caEric Fiselier    // env_path is expected not to contain symlinks.
246e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static const fs::path env_path = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;
256e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    return env_path / p;
266e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
276e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
286e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path Root = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;
296e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
306e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path TestFileList[] = {
316e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("empty_file"),
326e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("non_empty_file"),
336e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("dir1/file1"),
346e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("dir1/file2")
356e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
366e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierconst std::size_t TestFileListSize = sizeof(TestFileList) / sizeof(fs::path);
376e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
386e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path TestDirList[] = {
396e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("dir1"),
406e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("dir1/dir2"),
416e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        makePath("dir1/dir2/dir3")
426e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
436e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierconst std::size_t TestDirListSize = sizeof(TestDirList) / sizeof(fs::path);
446e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
456e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path File          = TestFileList[0];
466e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path Dir           = TestDirList[0];
476e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path Dir2          = TestDirList[1];
486e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path Dir3          = TestDirList[2];
496e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path SymlinkToFile = makePath("symlink_to_empty_file");
506e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path SymlinkToDir  = makePath("symlink_to_dir");
516e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path BadSymlink    = makePath("bad_symlink");
526e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path DNE           = makePath("DNE");
536e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path EmptyFile     = TestFileList[0];
546e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path NonEmptyFile  = TestFileList[1];
556e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path CharFile      = "/dev/null"; // Hopefully this exists
566e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
576e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path DirIterationList[] = {
586e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2"),
596e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/file1"),
606e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/file2")
616e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
626e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierconst std::size_t DirIterationListSize = sizeof(DirIterationList)
636e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier                                        / sizeof(fs::path);
646e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
656e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path DirIterationListDepth1[] = {
666e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/afile3"),
676e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/dir3"),
686e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/symlink_to_dir3"),
696e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/file4"),
706e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
716e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
726e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path RecDirIterationList[] = {
736e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2"),
746e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/file1"),
756e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/file2"),
766e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/afile3"),
776e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/dir3"),
786e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/symlink_to_dir3"),
796e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/file4"),
806e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/dir3/file5")
816e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
826e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
836e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstatic const fs::path RecDirFollowSymlinksIterationList[] = {
846e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2"),
856e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/file1"),
866e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/file2"),
876e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/afile3"),
886e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/dir3"),
896e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/file4"),
906e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/dir3/file5"),
916e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/symlink_to_dir3"),
926e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    makePath("dir1/dir2/symlink_to_dir3/file5"),
936e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
946e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
956e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier} // namespace StaticEnv
966e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
976e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#endif // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
986e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
996e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
1006e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#warning LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be defined
1016e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#else // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
1026e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1036e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER
1046e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#error LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER must be defined
1056e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#endif
1066e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1076e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstruct scoped_test_env
1086e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier{
1096e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    scoped_test_env() : test_root(random_env_path())
1106e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        { fs_helper_run(fs_make_cmd("init_test_directory", test_root)); }
1116e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1126e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    ~scoped_test_env()
1136e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        { fs_helper_run(fs_make_cmd("destroy_test_directory", test_root)); }
1146e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1156e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    scoped_test_env(scoped_test_env const &) = delete;
1166e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    scoped_test_env & operator=(scoped_test_env const &) = delete;
1176e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1186e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    fs::path make_env_path(std::string p) { return sanitize_path(p); }
1196e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1206e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string sanitize_path(std::string raw) {
1216e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        assert(raw.find("..") == std::string::npos);
1226e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        std::string const& root = test_root.native();
1236e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        if (root.compare(0, root.size(), raw, 0, root.size()) != 0) {
1246e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            assert(raw.front() != '\\');
1256e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            fs::path tmp(test_root);
1266e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            tmp /= raw;
1276e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            return std::move(const_cast<std::string&>(tmp.native()));
1286e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        }
1296e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return raw;
1306e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1316e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1326e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string create_file(std::string filename, std::size_t size = 0) {
1336e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        filename = sanitize_path(std::move(filename));
1346e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        std::string out_str(size, 'a');
1356e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        {
1366e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::ofstream out(filename.c_str());
1376e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            out << out_str;
1386e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        }
1396e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return filename;
1406e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1416e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1426e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string create_dir(std::string filename) {
1436e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        filename = sanitize_path(std::move(filename));
1446e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        fs_helper_run(fs_make_cmd("create_dir", filename));
1456e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return filename;
1466e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1476e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1486e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string create_symlink(std::string source, std::string to) {
1496e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        source = sanitize_path(std::move(source));
1506e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        to = sanitize_path(std::move(to));
1516e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        fs_helper_run(fs_make_cmd("create_symlink", source, to));
1526e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return to;
1536e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1546e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1556e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string create_hardlink(std::string source, std::string to) {
1566e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        source = sanitize_path(std::move(source));
1576e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        to = sanitize_path(std::move(to));
1586e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        fs_helper_run(fs_make_cmd("create_hardlink", source, to));
1596e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return to;
1606e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1616e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1626e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string create_fifo(std::string file) {
1636e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        file = sanitize_path(std::move(file));
1646e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        fs_helper_run(fs_make_cmd("create_fifo", file));
1656e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return file;
1666e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1676e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1686e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  // OS X and FreeBSD doesn't support socket files so we shouldn't even
1696e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  // allow tests to call this unguarded.
1706e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#if !defined(__FreeBSD__) && !defined(__APPLE__)
1716e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    std::string create_socket(std::string file) {
1726e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        file = sanitize_path(std::move(file));
1736e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        fs_helper_run(fs_make_cmd("create_socket", file));
1746e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return file;
1756e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1766e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#endif
1776e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1786e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    fs::path const test_root;
1796e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1806e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierprivate:
1816e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static char to_hex(int ch) {
1826e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return ch < 10 ? static_cast<char>('0' + ch)
1836e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier                       : static_cast<char>('a' + (ch - 10));
1846e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1856e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1866e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static char random_hex_char() {
1876e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        static std::mt19937 rd { std::random_device{}() };
1886e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        static std::uniform_int_distribution<int> mrand{0, 15};
1896e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return to_hex( mrand(rd) );
1906e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1916e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
1926e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static std::string unique_path_suffix() {
1936e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        std::string model = "test.%%%%%%";
1946e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        for (auto & ch :  model) {
1956e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            if (ch == '%') ch = random_hex_char();
1966e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        }
1976e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return model;
1986e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
1996e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2006e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    // This could potentially introduce a filesystem race with other tests
2016e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    // running at the same time, but oh well, it's just test code.
2026e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static inline fs::path random_env_path() {
2036e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        static const char* env_path = LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT;
2046e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        fs::path p = fs::path(env_path) / unique_path_suffix();
2056e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        assert(p.parent_path() == env_path);
2066e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return p;
2076e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2086e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2096e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static inline std::string make_arg(std::string const& arg) {
2106e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return "'" + arg + "'";
2116e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2126e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2136e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static inline std::string make_arg(std::size_t arg) {
2146e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return std::to_string(arg);
2156e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2166e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2176e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    template <class T>
2186e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static inline std::string
2196e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    fs_make_cmd(std::string const& cmd_name, T const& arg) {
2206e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return cmd_name + "(" + make_arg(arg) + ")";
2216e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2226e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2236e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    template <class T, class U>
2246e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static inline std::string
2256e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    fs_make_cmd(std::string const& cmd_name, T const& arg1, U const& arg2) {
2266e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return cmd_name + "(" + make_arg(arg1) + ", " + make_arg(arg2) + ")";
2276e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2286e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2296e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static inline void fs_helper_run(std::string const& raw_cmd) {
2306e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        // check that the fs test root in the enviroment matches what we were
2316e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        // compiled with.
2326e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        static bool checked = checkDynamicTestRoot();
2330e5ebbc77c3c2cfd7d835fcfe40fcb65df0c5598Eric Fiselier        ((void)checked);
2346e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        std::string cmd = LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER;
2356e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        cmd += " \"" + raw_cmd + "\"";
2366e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        int ret = std::system(cmd.c_str());
2376e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        assert(ret == 0);
2386e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2396e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2406e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    static bool checkDynamicTestRoot() {
241374a33d1b9a9808c3f641867bb5e68a8e93bd9caEric Fiselier        // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT is expected not to contain symlinks.
2426e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        char* fs_root = std::getenv("LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT");
2436e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        if (!fs_root) {
2446e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be a defined "
2456e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier                         "environment variable when running the test.\n");
2466e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::abort();
2476e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        }
2486e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        if (std::string(fs_root) != LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT) {
2496e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT enviroment variable"
2506e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier                        " must have the same value as when the test was compiled.\n");
2516e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::printf("   Current Value:  '%s'\n", fs_root);
2526e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::printf("   Expected Value: '%s'\n", LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT);
2536e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            std::abort();
2546e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        }
2556e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        return true;
2566e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
2576e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2586e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
2596e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2606e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#endif // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
2616e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2626e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// Misc test types
2636e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2646e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#define CONCAT2(LHS, RHS) LHS##RHS
2656e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#define CONCAT(LHS, RHS) CONCAT2(LHS, RHS)
2666e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#define MKSTR(Str) {Str, CONCAT(L, Str), CONCAT(u, Str), CONCAT(U, Str)}
2676e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2686e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstruct MultiStringType {
2696e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  const char* s;
2706e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  const wchar_t* w;
2716e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  const char16_t* u16;
2726e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  const char32_t* u32;
2736e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2746e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  operator const char* () const { return s; }
2756e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  operator const wchar_t* () const { return w; }
2766e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  operator const char16_t* () const { return u16; }
2776e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  operator const char32_t* () const { return u32; }
2786e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
2796e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
2806e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierconst MultiStringType PathList[] = {
2816e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR(""),
2826e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR(" "),
2836e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("//"),
2846e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("."),
2856e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR(".."),
2866e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo"),
2876e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/"),
2886e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/foo"),
2896e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/"),
2906e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/foo/"),
2916e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/bar"),
2926e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/foo/bar"),
2936e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("//net"),
2946e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("//net/foo"),
2956e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("///foo///"),
2966e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("///foo///bar"),
2976e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/."),
2986e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("./"),
2996e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/.."),
3006e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("../"),
3016e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/."),
3026e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/.."),
3036e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/./"),
3046e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/./bar"),
3056e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/../"),
3066e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("foo/../bar"),
3076e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:"),
3086e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:/"),
3096e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:foo"),
3106e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:/foo"),
3116e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:foo/"),
3126e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:/foo/"),
3136e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:/foo/bar"),
3146e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("prn:"),
3156e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:\\"),
3166e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:\\foo"),
3176e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:foo\\"),
3186e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:\\foo\\"),
3196e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:\\foo/"),
3206e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("c:/foo\\bar"),
3216e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("//"),
3226e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        MKSTR("/finally/we/need/one/really/really/really/really/really/really/really/long/string")
3236e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier};
3246e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierconst unsigned PathListSize = sizeof(PathList) / sizeof(MultiStringType);
3256e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
3266e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiseliertemplate <class Iter>
3276e9a694dce70319e60dbdfb09cf055bacb4c948eEric FiselierIter IterEnd(Iter B) {
3286e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  using VT = typename std::iterator_traits<Iter>::value_type;
3296e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  for (; *B != VT{}; ++B)
3306e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    ;
3316e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  return B;
3326e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
3336e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
3346e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiseliertemplate <class CharT>
3356e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierconst CharT* StrEnd(CharT const* P) {
3366e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    return IterEnd(P);
3376e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
3386e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
3396e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiseliertemplate <class CharT>
3406e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierstd::size_t StrLen(CharT const* P) {
3416e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    return StrEnd(P) - P;
3426e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
3436e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
3446e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// Testing the allocation behavior of the code_cvt functions requires
3456e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// *knowing* that the allocation was not done by "path::__str_".
3466e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// This hack forces path to allocate enough memory.
3476e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierinline void PathReserve(fs::path& p, std::size_t N) {
3486e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  auto const& native_ref = p.native();
3496e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  const_cast<std::string&>(native_ref).reserve(N);
3506e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
3516e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
3526e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiseliertemplate <class Iter1, class Iter2>
3536e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierbool checkCollectionsEqual(
3546e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    Iter1 start1, Iter1 const end1
3556e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  , Iter2 start2, Iter2 const end2
3566e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier  )
3576e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier{
3586e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    while (start1 != end1 && start2 != end2) {
3596e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        if (*start1 != *start2) {
3606e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier            return false;
3616e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        }
3626e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier        ++start1; ++start2;
3636e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    }
3646e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    return (start1 == end1 && start2 == end2);
3656e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
3666e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
367880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier
368880e38b206ee452f777922dfa61a959cee0067cbEric Fiseliertemplate <class Iter1, class Iter2>
369880e38b206ee452f777922dfa61a959cee0067cbEric Fiselierbool checkCollectionsEqualBackwards(
370880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier    Iter1 const start1, Iter1 end1
371880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier  , Iter2 const start2, Iter2 end2
372880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier  )
373880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier{
374880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier    while (start1 != end1 && start2 != end2) {
375880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier        --end1; --end2;
376880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier        if (*end1 != *end2) {
377880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier            return false;
378880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier        }
379880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier    }
380880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier    return (start1 == end1 && start2 == end2);
381880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier}
382880e38b206ee452f777922dfa61a959cee0067cbEric Fiselier
3836e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// We often need to test that the error_code was cleared if no error occurs
38416e2ba19dfffdcf9bba202eb8a27fd79e3d15303Stephan T. Lavavej// this function returns an error_code which is set to an error that will
3856e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier// never be returned by the filesystem functions.
3866e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselierinline std::error_code GetTestEC() {
3876e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier    return std::make_error_code(std::errc::address_family_not_supported);
3886e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier}
3896e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier
39040d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier// Provide our own Sleep routine since std::this_thread::sleep_for is not
39140d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier// available in single-threaded mode.
39240d9e09d892af387d97a8ab507f440ff027cd206Eric Fiseliervoid SleepFor(std::chrono::seconds dur) {
39340d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier    using namespace std::chrono;
39429c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier#if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
39529c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier    using Clock = system_clock;
39629c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier#else
39729c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier    using Clock = steady_clock;
39829c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier#endif
39929c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier    const auto wake_time = Clock::now() + dur;
40029c26b91df36522bf83d4a5ceb37f75c32b360edEric Fiselier    while (Clock::now() < wake_time)
40140d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier        ;
40240d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier}
40340d9e09d892af387d97a8ab507f440ff027cd206Eric Fiselier
4046e9a694dce70319e60dbdfb09cf055bacb4c948eEric Fiselier#endif /* FILESYSTEM_TEST_HELPER_HPP */
405