aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src/tests.files.cpp
blob: 56b0ceac6e444d7da10501e851d6472f950dc709 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "tests.pch.h"

#include <vcpkg/base/files.h>
#include <vcpkg/base/strings.h>

#include <iostream>
#include <filesystem> // required for filesystem::create_{directory_}symlink
#include <random>

#include <windows.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest1
{
    class FilesTest : public TestClass<FilesTest>
    {
        using uid = std::uniform_int_distribution<std::uint64_t>;

    public:
        FilesTest()
        {
            HKEY key;
            const auto status = RegOpenKeyExW(
                HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, 0, &key);

            if (status == ERROR_FILE_NOT_FOUND)
            {
                ALLOW_SYMLINKS = false;
                std::clog << "Symlinks are not allowed on this system\n";
            }
            else
            {
				// if we get a permissions error, we still know that we're in developer mode
                ALLOW_SYMLINKS = true;
            }

			if (status == ERROR_SUCCESS) RegCloseKey(key);
        }

    private:
        TEST_METHOD(remove_all)
        {
            auto urbg = get_urbg(0);

            fs::path temp_dir;

            {
                wchar_t* tmp = static_cast<wchar_t*>(calloc(32'767, 2));

                if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767))
                {
                    Assert::Fail(L"GetEnvironmentVariable(\"TEMP\") failed");
                }

                temp_dir = tmp;

                std::string dir_name = "vcpkg-tmp-dir-";
                dir_name += get_random_filename(urbg);

                temp_dir /= dir_name;
            }

            auto& fs = vcpkg::Files::get_real_filesystem();

            std::clog << "temp dir is: " << temp_dir << '\n';

            create_directory_tree(urbg, fs, 0, temp_dir);

            std::error_code ec;
            fs::path fp;
            fs.remove_all(temp_dir, ec, fp);
            Assert::IsFalse(bool(ec));

            Assert::IsFalse(fs.exists(temp_dir));
        }

        bool ALLOW_SYMLINKS;

        std::mt19937_64 get_urbg(std::uint64_t index)
        {
            // smallest prime > 2**63 - 1
            return std::mt19937_64{index + 9223372036854775837};
        }

        std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); }

        void create_directory_tree(std::mt19937_64& urbg,
                                   vcpkg::Files::Filesystem& fs,
                                   std::uint64_t depth,
                                   const fs::path& base)
        {
            std::random_device rd;
            constexpr std::uint64_t max_depth = 5;
            constexpr std::uint64_t width = 5;
            const auto type = depth < max_depth ? uid{0, 9}(urbg) : uid{7, 9}(urbg);

			// 0 <= type < 7 : directory
			// 7 = type : regular
			// 8 = type : regular symlink (regular file if !ALLOW_SYMLINKS)
			// 9 = type : directory symlink (^^)

            std::error_code ec;
            if (type >= 7)
            {
                // I don't want to move urbg forward conditionally
                if (type == 7 || !ALLOW_SYMLINKS)
                {
					// regular file
                    fs.write_contents(base, "", ec);
                }
                else if (type == 8)
                {
                    // regular symlink
                    fs.write_contents(base, "", ec);
                    Assert::IsFalse(bool(ec));
                    const std::filesystem::path basep = base.native();
                    auto basep_link = basep;
                    basep_link.replace_filename(basep.filename().native() + L"-link");
                    std::filesystem::create_symlink(basep, basep_link, ec);
                }
                else
                {
                    // directory symlink
                    std::filesystem::path basep = base.native();
                    std::filesystem::create_directory_symlink(basep / "..", basep, ec);
                }

                Assert::IsFalse(bool(ec));

            }
            else
            {
				// directory
                fs.create_directory(base, ec);
                Assert::IsFalse(bool(ec));

                for (int i = 0; i < width; ++i)
                {
                    create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg));
                }
        
            }

        }
    };
}