#include #include #include #include #include "path-regex.hh" #include "store-api.hh" #include "tests/hash.hh" #include "tests/libstore.hh" #include "tests/path.hh" namespace nix { #define STORE_DIR "/nix/store/" #define HASH_PART "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q" class StorePathTest : public LibStoreTest { }; static std::regex nameRegex { std::string { nameRegexStr } }; #define TEST_DONT_PARSE(NAME, STR) \ TEST_F(StorePathTest, bad_ ## NAME) { \ std::string_view str = \ STORE_DIR HASH_PART "-" STR; \ ASSERT_THROW( \ store->parseStorePath(str), \ BadStorePath); \ std::string name { STR }; \ EXPECT_FALSE(std::regex_match(name, nameRegex)); \ } TEST_DONT_PARSE(empty, "") TEST_DONT_PARSE(garbage, "&*()") TEST_DONT_PARSE(double_star, "**") TEST_DONT_PARSE(star_first, "*,foo") TEST_DONT_PARSE(star_second, "foo,*") TEST_DONT_PARSE(bang, "foo!o") TEST_DONT_PARSE(dotfile, ".gitignore") #undef TEST_DONT_PARSE #define TEST_DO_PARSE(NAME, STR) \ TEST_F(StorePathTest, good_ ## NAME) { \ std::string_view str = \ STORE_DIR HASH_PART "-" STR; \ auto p = store->parseStorePath(str); \ std::string name { p.name() }; \ EXPECT_TRUE(std::regex_match(name, nameRegex)); \ } // 0-9 a-z A-Z + - . _ ? = TEST_DO_PARSE(numbers, "02345") TEST_DO_PARSE(lower_case, "foo") TEST_DO_PARSE(upper_case, "FOO") TEST_DO_PARSE(plus, "foo+bar") TEST_DO_PARSE(dash, "foo-dev") TEST_DO_PARSE(underscore, "foo_bar") TEST_DO_PARSE(period, "foo.txt") TEST_DO_PARSE(question_mark, "foo?why") TEST_DO_PARSE(equals_sign, "foo=foo") #undef TEST_DO_PARSE // For rapidcheck void showValue(const StorePath & p, std::ostream & os) { os << p.to_string(); } } namespace rc { using namespace nix; Gen Arbitrary::arbitrary() { auto len = *gen::inRange( 1, StorePath::MaxPathLen - std::string_view { HASH_PART }.size()); std::string pre; pre.reserve(len); for (size_t c = 0; c < len; ++c) { switch (auto i = *gen::inRange(0, 10 + 2 * 26 + 6)) { case 0 ... 9: pre += '0' + i; case 10 ... 35: pre += 'A' + (i - 10); break; case 36 ... 61: pre += 'a' + (i - 36); break; case 62: pre += '+'; break; case 63: pre += '-'; break; case 64: // names aren't permitted to start with a period, // so just fall through to the next case here if (c != 0) { pre += '.'; break; } case 65: pre += '_'; break; case 66: pre += '?'; break; case 67: pre += '='; break; default: assert(false); } } return gen::just(StorePathName { .name = std::move(pre), }); } Gen Arbitrary::arbitrary() { return gen::just(StorePath { *gen::arbitrary(), (*gen::arbitrary()).name, }); } } // namespace rc namespace nix { #ifndef COVERAGE RC_GTEST_FIXTURE_PROP( StorePathTest, prop_regex_accept, (const StorePath & p)) { RC_ASSERT(std::regex_match(std::string { p.name() }, nameRegex)); } RC_GTEST_FIXTURE_PROP( StorePathTest, prop_round_rip, (const StorePath & p)) { RC_ASSERT(p == store->parseStorePath(store->printStorePath(p))); } #endif }