More property tests

Also put proper comparison methods on `DerivedPath` and
`NixStringContextElem`, which is needed for the tests but good in
general.
This commit is contained in:
John Ericson 2023-01-29 13:52:38 -05:00
parent ec0c0efec6
commit ecd3e4ebd7
15 changed files with 279 additions and 24 deletions

View file

@ -14,6 +14,6 @@ libexpr-tests_SOURCES := \
libexpr-tests_CXXFLAGS += -I src/libexpr -I src/libutil -I src/libstore -I src/libexpr/tests libexpr-tests_CXXFLAGS += -I src/libexpr -I src/libutil -I src/libstore -I src/libexpr/tests
libexpr-tests_LIBS = libstore-tests libexpr libutil libstore libfetchers libexpr-tests_LIBS = libstore-tests libutils-tests libexpr libutil libstore libfetchers
libexpr-tests_LDFLAGS := $(GTEST_LIBS) -lgmock libexpr-tests_LDFLAGS := $(GTEST_LIBS) -lgmock

View file

@ -1,6 +1,10 @@
#include "value/context.hh" #include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
#include "tests/path.hh"
#include "tests/libexpr.hh" #include "tests/libexpr.hh"
#include "tests/value/context.hh"
namespace nix { namespace nix {
@ -70,3 +74,39 @@ TEST_F(NixStringContextElemTest, built) {
} }
} }
namespace rc {
using namespace nix;
Gen<NixStringContextElem> Arbitrary<NixStringContextElem>::arbitrary()
{
switch (*gen::inRange<uint8_t>(0, 2)) {
case 0:
return gen::just((NixStringContextElem) NixStringContextElem::Opaque {
.path = *gen::arbitrary<StorePath>(),
});
case 1:
return gen::just((NixStringContextElem) NixStringContextElem::DrvDeep {
.drvPath = *gen::arbitrary<StorePath>(),
});
default:
return gen::just((NixStringContextElem) NixStringContextElem::Built {
.drvPath = *gen::arbitrary<StorePath>(),
.output = (*gen::arbitrary<StorePathName>()).name,
});
}
}
}
namespace nix {
RC_GTEST_FIXTURE_PROP(
NixStringContextElemTest,
prop_round_rip,
(const NixStringContextElem & o))
{
RC_ASSERT(o == NixStringContextElem::parse(store(), o.to_string(store())));
}
}

View file

@ -0,0 +1,15 @@
#pragma once
#include <rapidcheck/gen/Arbitrary.h>
#include <value/context.hh>
namespace rc {
using namespace nix;
template<>
struct Arbitrary<NixStringContextElem> {
static Gen<NixStringContextElem> arbitrary();
};
}

View file

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "util.hh" #include "util.hh"
#include "comparator.hh"
#include "path.hh" #include "path.hh"
#include <optional> #include <variant>
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
@ -32,6 +33,8 @@ class Store;
*/ */
struct NixStringContextElem_Opaque { struct NixStringContextElem_Opaque {
StorePath path; StorePath path;
GENERATE_CMP(NixStringContextElem_Opaque, me->path);
}; };
/* Path to a derivation and its entire build closure. /* Path to a derivation and its entire build closure.
@ -44,6 +47,8 @@ struct NixStringContextElem_Opaque {
*/ */
struct NixStringContextElem_DrvDeep { struct NixStringContextElem_DrvDeep {
StorePath drvPath; StorePath drvPath;
GENERATE_CMP(NixStringContextElem_DrvDeep, me->drvPath);
}; };
/* Derivation output. /* Derivation output.
@ -53,6 +58,8 @@ struct NixStringContextElem_DrvDeep {
struct NixStringContextElem_Built { struct NixStringContextElem_Built {
StorePath drvPath; StorePath drvPath;
std::string output; std::string output;
GENERATE_CMP(NixStringContextElem_Built, me->drvPath, me->output);
}; };
using _NixStringContextElem_Raw = std::variant< using _NixStringContextElem_Raw = std::variant<

View file

@ -4,8 +4,9 @@
#include "path.hh" #include "path.hh"
#include "realisation.hh" #include "realisation.hh"
#include "outputs-spec.hh" #include "outputs-spec.hh"
#include "comparator.hh"
#include <optional> #include <variant>
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
@ -27,8 +28,7 @@ struct DerivedPathOpaque {
std::string to_string(const Store & store) const; std::string to_string(const Store & store) const;
static DerivedPathOpaque parse(const Store & store, std::string_view); static DerivedPathOpaque parse(const Store & store, std::string_view);
bool operator < (const DerivedPathOpaque & b) const GENERATE_CMP(DerivedPathOpaque, me->path);
{ return path < b.path; }
}; };
/** /**
@ -51,8 +51,7 @@ struct DerivedPathBuilt {
static DerivedPathBuilt parse(const Store & store, std::string_view, std::string_view); static DerivedPathBuilt parse(const Store & store, std::string_view, std::string_view);
nlohmann::json toJSON(ref<Store> store) const; nlohmann::json toJSON(ref<Store> store) const;
bool operator < (const DerivedPathBuilt & b) const GENERATE_CMP(DerivedPathBuilt, me->drvPath, me->outputs);
{ return std::make_pair(drvPath, outputs) < std::make_pair(b.drvPath, b.outputs); }
}; };
using _DerivedPathRaw = std::variant< using _DerivedPathRaw = std::variant<
@ -96,6 +95,8 @@ struct BuiltPathBuilt {
nlohmann::json toJSON(ref<Store> store) const; nlohmann::json toJSON(ref<Store> store) const;
static BuiltPathBuilt parse(const Store & store, std::string_view); static BuiltPathBuilt parse(const Store & store, std::string_view);
GENERATE_CMP(BuiltPathBuilt, me->drvPath, me->outputs);
}; };
using _BuiltPathRaw = std::variant< using _BuiltPathRaw = std::variant<

View file

@ -0,0 +1,52 @@
#include <regex>
#include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
#include "tests/derived-path.hh"
#include "tests/libstore.hh"
namespace rc {
using namespace nix;
Gen<DerivedPath> Arbitrary<DerivedPath>::arbitrary()
{
switch (*gen::inRange<uint8_t>(0, 1)) {
case 0:
return gen::just((DerivedPath) DerivedPath::Opaque {
.path = *gen::arbitrary<StorePath>(),
});
default:
return gen::just((DerivedPath) DerivedPath::Built {
.drvPath = *gen::arbitrary<StorePath>(),
.outputs = *gen::arbitrary<OutputsSpec>(),
});
}
}
}
namespace nix {
class DerivedPathTest : public LibStoreTest
{
};
// FIXME: `RC_GTEST_FIXTURE_PROP` isn't calling `SetUpTestSuite` because it is
// no a real fixture.
//
// See https://github.com/emil-e/rapidcheck/blob/master/doc/gtest.md#rc_gtest_fixture_propfixture-name-args
TEST_F(DerivedPathTest, force_init)
{
}
RC_GTEST_FIXTURE_PROP(
DerivedPathTest,
prop_round_rip,
(const DerivedPath & o))
{
RC_ASSERT(o == DerivedPath::parse(*store, o.to_string(*store)));
}
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <rapidcheck/gen/Arbitrary.h>
#include <derived-path.hh>
#include "tests/path.hh"
#include "tests/outputs-spec.hh"
namespace rc {
using namespace nix;
template<>
struct Arbitrary<DerivedPath> {
static Gen<DerivedPath> arbitrary();
};
}

View file

@ -24,6 +24,6 @@ libstore-tests_SOURCES := $(wildcard $(d)/*.cc)
libstore-tests_CXXFLAGS += -I src/libstore -I src/libutil libstore-tests_CXXFLAGS += -I src/libstore -I src/libutil
libstore-tests_LIBS = libstore libutil libstore-tests_LIBS = libutil-tests libstore libutil
libstore-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) libstore-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS)

View file

@ -2,6 +2,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
namespace nix { namespace nix {
@ -199,3 +200,34 @@ TEST_JSON(ExtendedOutputsSpec, names, R"(["a","b"])", (ExtendedOutputsSpec::Expl
#undef TEST_JSON #undef TEST_JSON
} }
namespace rc {
using namespace nix;
Gen<OutputsSpec> Arbitrary<OutputsSpec>::arbitrary()
{
switch (*gen::inRange<uint8_t>(0, 1)) {
case 0:
return gen::just((OutputsSpec) OutputsSpec::All { });
default:
return gen::just((OutputsSpec) OutputsSpec::Names {
*gen::nonEmpty(gen::container<StringSet>(gen::map(
gen::arbitrary<StorePathName>(),
[](StorePathName n) { return n.name; }))),
});
}
}
}
namespace nix {
RC_GTEST_PROP(
OutputsSpec,
prop_round_rip,
(const OutputsSpec & o))
{
RC_ASSERT(o == OutputsSpec::parse(o.to_string()));
}
}

View file

@ -0,0 +1,17 @@
#pragma once
#include <rapidcheck/gen/Arbitrary.h>
#include <outputs-spec.hh>
#include <tests/path.hh>
namespace rc {
using namespace nix;
template<>
struct Arbitrary<OutputsSpec> {
static Gen<OutputsSpec> arbitrary();
};
}

View file

@ -7,6 +7,7 @@
#include "path-regex.hh" #include "path-regex.hh"
#include "store-api.hh" #include "store-api.hh"
#include "tests/hash.hh"
#include "tests/libstore.hh" #include "tests/libstore.hh"
#include "tests/path.hh" #include "tests/path.hh"
@ -74,12 +75,14 @@ void showValue(const StorePath & p, std::ostream & os) {
namespace rc { namespace rc {
using namespace nix; using namespace nix;
Gen<StorePath> Arbitrary<StorePath>::arbitrary() Gen<StorePathName> Arbitrary<StorePathName>::arbitrary()
{ {
auto len = *gen::inRange<size_t>(1, StorePath::MaxPathLen); auto len = *gen::inRange<size_t>(
1,
StorePath::MaxPathLen - std::string_view { HASH_PART }.size());
std::string pre { HASH_PART "-" }; std::string pre;
pre.reserve(pre.size() + len); pre.reserve(len);
for (size_t c = 0; c < len; ++c) { for (size_t c = 0; c < len; ++c) {
switch (auto i = *gen::inRange<uint8_t>(0, 10 + 2 * 26 + 6)) { switch (auto i = *gen::inRange<uint8_t>(0, 10 + 2 * 26 + 6)) {
@ -114,7 +117,17 @@ Gen<StorePath> Arbitrary<StorePath>::arbitrary()
} }
} }
return gen::just(StorePath { pre }); return gen::just(StorePathName {
.name = std::move(pre),
});
}
Gen<StorePath> Arbitrary<StorePath>::arbitrary()
{
return gen::just(StorePath {
*gen::arbitrary<Hash>(),
(*gen::arbitrary<StorePathName>()).name,
});
} }
} // namespace rc } // namespace rc

View file

@ -1,12 +1,25 @@
#pragma once #pragma once
#include <rapidcheck.h> #include <rapidcheck/gen/Arbitrary.h>
#include "path.hh" #include <path.hh>
namespace nix {
struct StorePathName {
std::string name;
};
}
namespace rc { namespace rc {
using namespace nix; using namespace nix;
template<>
struct Arbitrary<StorePathName> {
static Gen<StorePathName> arbitrary();
};
template<> template<>
struct Arbitrary<StorePath> { struct Arbitrary<StorePath> {
static Gen<StorePath> arbitrary(); static Gen<StorePath> arbitrary();

View file

@ -1,5 +1,12 @@
#include "hash.hh" #include <regex>
#include <nlohmann/json.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
#include <hash.hh>
#include "tests/hash.hh"
namespace nix { namespace nix {
@ -73,3 +80,16 @@ namespace nix {
"c7d329eeb6dd26545e96e55b874be909"); "c7d329eeb6dd26545e96e55b874be909");
} }
} }
namespace rc {
using namespace nix;
Gen<Hash> Arbitrary<Hash>::arbitrary()
{
Hash hash(htSHA1);
for (size_t i = 0; i < hash.hashSize; ++i)
hash.hash[i] = *gen::arbitrary<uint8_t>();
return gen::just(hash);
}
}

15
src/libutil/tests/hash.hh Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <rapidcheck/gen/Arbitrary.h>
#include <hash.hh>
namespace rc {
using namespace nix;
template<>
struct Arbitrary<Hash> {
static Gen<Hash> arbitrary();
};
}

View file

@ -2,7 +2,19 @@ check: libutil-tests_RUN
programs += libutil-tests programs += libutil-tests
libutil-tests_NAME := libnixutil-tests libutil-tests-exe_NAME = libnixutil-tests
libutil-tests-exe_DIR := $(d)
libutil-tests-exe_INSTALL_DIR :=
libutil-tests-exe_LIBS = libutil-tests
libutil-tests-exe_LDFLAGS := $(GTEST_LIBS)
libraries += libutil-tests
libutil-tests_NAME = libnixutil-tests
libutil-tests_DIR := $(d) libutil-tests_DIR := $(d)
@ -10,8 +22,8 @@ libutil-tests_INSTALL_DIR :=
libutil-tests_SOURCES := $(wildcard $(d)/*.cc) libutil-tests_SOURCES := $(wildcard $(d)/*.cc)
libutil-tests_CXXFLAGS += -I src/libutil -I src/libexpr libutil-tests_CXXFLAGS += -I src/libutil
libutil-tests_LIBS = libutil libutil-tests_LIBS = libutil
libutil-tests_LDFLAGS := $(GTEST_LIBS) libutil-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS)