#include "libexpr/attr-set.hh" #include <cstdio> #include <optional> #include <string> #include <vector> #include <bits/stdint-intn.h> #include <gc/gc_cpp.h> #include <gtest/gtest.h> #include <rapidcheck.h> #include <rapidcheck/Assertions.h> #include <rapidcheck/gen/Arbitrary.h> #include <rapidcheck/gen/Build.h> #include <rapidcheck/gen/Create.h> #include <rapidcheck/gen/Transform.h> #include <rapidcheck/gtest.h> #include "libexpr/eval.hh" #include "libexpr/nixexpr.hh" #include "libexpr/symbol-table.hh" #include "libexpr/value.hh" #include "tests/dummy-store.hh" static nix::SymbolTable* symbol_table; namespace rc { using nix::Pos; using nix::Value; // TODO(grfn): These arbitrary implementations should be pulled out to a util // file sooner rather than later template <> struct Arbitrary<nix::Symbol> { static Gen<nix::Symbol> arbitrary() { return gen::map(gen::arbitrary<std::string>(), [](std::string s) { return symbol_table->Create(s); }); } }; template <> struct Arbitrary<Value> { static Gen<nix::Value> arbitrary() { return gen::build(gen::construct<Value>(), // TODO(grfn) generalize to more types gen::set(&Value::type, gen::just(nix::ValueType::tInt)), gen::set(&Value::integer, gen::arbitrary<int64_t>())); } }; template <> struct Arbitrary<Value*> { static Gen<nix::Value*> arbitrary() { return gen::apply( [](nix::ValueType typ, int i) { auto ret = new (GC) Value(); ret->type = typ; ret->integer = i; return ret; }, gen::just(nix::ValueType::tInt), gen::arbitrary<int64_t>()); } }; template <> struct Arbitrary<nix::Pos> { static Gen<nix::Pos> arbitrary() { return gen::construct<nix::Pos>(gen::arbitrary<nix::Symbol>(), gen::arbitrary<unsigned int>(), gen::arbitrary<unsigned int>()); } }; template <> struct Arbitrary<nix::Pos*> { static Gen<nix::Pos*> arbitrary() { return gen::apply( [](unsigned int line, unsigned int column) { return new (GC) Pos({}, line, column); }, gen::arbitrary<unsigned int>(), gen::arbitrary<unsigned int>()); } }; template <> struct Arbitrary<nix::Attr> { static Gen<nix::Attr> arbitrary() { return gen::construct<nix::Attr>(gen::arbitrary<nix::Symbol>(), gen::arbitrary<Value*>(), gen::arbitrary<nix::Pos*>()); } }; template <> struct Arbitrary<nix::Bindings> { static Gen<nix::Bindings> arbitrary() { return gen::map(gen::arbitrary<std::vector<nix::Attr>>(), [](auto attrs) { nix::Bindings res; for (const auto& attr : attrs) { res.push_back(attr); } return res; }); } }; } // namespace rc namespace nix { using nix::tests::DummyStore; class AttrSetTest : public ::testing::Test { protected: EvalState* eval_state_{}; void SetUp() override { nix::initGC(); auto store = std::make_shared<DummyStore>(); eval_state_ = new EvalState({"."}, ref<Store>(store)); symbol_table = &eval_state_->symbols; } void assert_bindings_equal(nix::Bindings& lhs, nix::Bindings& rhs) { Value lhs_val{}; Value rhs_val{}; lhs_val.type = rhs_val.type = ValueType::tAttrs; lhs_val.attrs = &lhs; rhs_val.attrs = &lhs; RC_ASSERT(eval_state_->eqValues(lhs_val, rhs_val)); } }; class AttrSetMonoidTest : public AttrSetTest {}; RC_GTEST_FIXTURE_PROP(AttrSetMonoidTest, mergeLeftIdentity, (nix::Bindings && bindings)) { auto empty_bindings = nix::Bindings::NewGC(); auto result = *Bindings::Merge(*empty_bindings, bindings); assert_bindings_equal(result, bindings); } RC_GTEST_FIXTURE_PROP(AttrSetMonoidTest, mergeRightIdentity, (nix::Bindings && bindings)) { auto empty_bindings = nix::Bindings::NewGC(); auto result = *Bindings::Merge(bindings, *empty_bindings); assert_bindings_equal(result, bindings); } RC_GTEST_FIXTURE_PROP(AttrSetMonoidTest, mergeAssociative, (nix::Bindings && bindings_1, nix::Bindings&& bindings_2, nix::Bindings&& bindings_3)) { assert_bindings_equal( *Bindings::Merge(bindings_1, *Bindings::Merge(bindings_2, bindings_3)), *Bindings::Merge(*Bindings::Merge(bindings_1, bindings_2), bindings_3)); } } // namespace nix