Merge pull request #7713 from obsidiansystems/more-rapid-check

Add more property tests
This commit is contained in:
Robert Hensing 2023-01-30 18:54:53 +01:00 committed by GitHub
commit c9b9260f34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 381 additions and 43 deletions

6
.gitignore vendored
View file

@ -37,14 +37,14 @@ perl/Makefile.config
/src/libexpr/parser-tab.hh /src/libexpr/parser-tab.hh
/src/libexpr/parser-tab.output /src/libexpr/parser-tab.output
/src/libexpr/nix.tbl /src/libexpr/nix.tbl
/src/libexpr/tests/libexpr-tests /src/libexpr/tests/libnixexpr-tests
# /src/libstore/ # /src/libstore/
*.gen.* *.gen.*
/src/libstore/tests/libstore-tests /src/libstore/tests/libnixstore-tests
# /src/libutil/ # /src/libutil/
/src/libutil/tests/libutil-tests /src/libutil/tests/libnixutil-tests
/src/nix/nix /src/nix/nix

View file

@ -3,6 +3,9 @@ programs-list :=
# Build a program with symbolic name $(1). The program is defined by # Build a program with symbolic name $(1). The program is defined by
# various variables prefixed by $(1)_: # various variables prefixed by $(1)_:
# #
# - $(1)_NAME: the name of the program (e.g. foo); defaults to
# $(1).
#
# - $(1)_DIR: the directory where the (non-installed) program will be # - $(1)_DIR: the directory where the (non-installed) program will be
# placed. # placed.
# #
@ -23,11 +26,12 @@ programs-list :=
# - $(1)_INSTALL_DIR: the directory where the program will be # - $(1)_INSTALL_DIR: the directory where the program will be
# installed; defaults to $(bindir). # installed; defaults to $(bindir).
define build-program define build-program
$(1)_NAME ?= $(1)
_d := $(buildprefix)$$($(1)_DIR) _d := $(buildprefix)$$($(1)_DIR)
_srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src))) _srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src)))
$(1)_OBJS := $$(addprefix $(buildprefix), $$(addsuffix .o, $$(basename $$(_srcs)))) $(1)_OBJS := $$(addprefix $(buildprefix), $$(addsuffix .o, $$(basename $$(_srcs))))
_libs := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_PATH)) _libs := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_PATH))
$(1)_PATH := $$(_d)/$(1) $(1)_PATH := $$(_d)/$$($(1)_NAME)
$$(eval $$(call create-dir, $$(_d))) $$(eval $$(call create-dir, $$(_d)))
@ -38,7 +42,7 @@ define build-program
ifdef $(1)_INSTALL_DIR ifdef $(1)_INSTALL_DIR
$(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$(1) $(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$$($(1)_NAME)
$$(eval $$(call create-dir, $$($(1)_INSTALL_DIR))) $$(eval $$(call create-dir, $$($(1)_INSTALL_DIR)))

View file

@ -1,7 +1,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "libexprtests.hh" #include "tests/libexpr.hh"
namespace nix { namespace nix {

View file

@ -1,4 +1,4 @@
#include "libexprtests.hh" #include "tests/libexpr.hh"
#include "value-to-json.hh" #include "value-to-json.hh"
namespace nix { namespace nix {

View file

@ -7,18 +7,19 @@
#include "eval-inline.hh" #include "eval-inline.hh"
#include "store-api.hh" #include "store-api.hh"
#include "tests/libstore.hh"
namespace nix { namespace nix {
class LibExprTest : public ::testing::Test { class LibExprTest : public LibStoreTest {
public: public:
static void SetUpTestSuite() { static void SetUpTestSuite() {
initLibStore(); LibStoreTest::SetUpTestSuite();
initGC(); initGC();
} }
protected: protected:
LibExprTest() LibExprTest()
: store(openStore("dummy://")) : LibStoreTest()
, state({}, store) , state({}, store)
{ {
} }
@ -36,7 +37,6 @@ namespace nix {
return state.symbols.create(value); return state.symbols.create(value);
} }
ref<Store> store;
EvalState state; EvalState state;
}; };

View file

@ -2,6 +2,8 @@ check: libexpr-tests_RUN
programs += libexpr-tests programs += libexpr-tests
libexpr-tests_NAME := libnixexpr-tests
libexpr-tests_DIR := $(d) libexpr-tests_DIR := $(d)
libexpr-tests_INSTALL_DIR := libexpr-tests_INSTALL_DIR :=
@ -12,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 = 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,7 +1,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "libexprtests.hh" #include "tests/libexpr.hh"
namespace nix { namespace nix {
class CaptureLogger : public Logger class CaptureLogger : public Logger

View file

@ -1,4 +1,4 @@
#include "libexprtests.hh" #include "tests/libexpr.hh"
namespace nix { namespace nix {
// Testing of trivial expressions // Testing of trivial expressions

View file

@ -1,6 +1,10 @@
#include "value/context.hh" #include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
#include "libexprtests.hh" #include "tests/path.hh"
#include "tests/libexpr.hh"
#include "tests/value/context.hh"
namespace nix { namespace nix {
@ -70,3 +74,54 @@ TEST_F(NixStringContextElemTest, built) {
} }
} }
namespace rc {
using namespace nix;
Gen<NixStringContextElem::Opaque> Arbitrary<NixStringContextElem::Opaque>::arbitrary()
{
return gen::just(NixStringContextElem::Opaque {
.path = *gen::arbitrary<StorePath>(),
});
}
Gen<NixStringContextElem::DrvDeep> Arbitrary<NixStringContextElem::DrvDeep>::arbitrary()
{
return gen::just(NixStringContextElem::DrvDeep {
.drvPath = *gen::arbitrary<StorePath>(),
});
}
Gen<NixStringContextElem::Built> Arbitrary<NixStringContextElem::Built>::arbitrary()
{
return gen::just(NixStringContextElem::Built {
.drvPath = *gen::arbitrary<StorePath>(),
.output = (*gen::arbitrary<StorePathName>()).name,
});
}
Gen<NixStringContextElem> Arbitrary<NixStringContextElem>::arbitrary()
{
switch (*gen::inRange<uint8_t>(0, 2)) {
case 0:
return gen::just<NixStringContextElem>(*gen::arbitrary<NixStringContextElem::Opaque>());
case 1:
return gen::just<NixStringContextElem>(*gen::arbitrary<NixStringContextElem::DrvDeep>());
default:
return gen::just<NixStringContextElem>(*gen::arbitrary<NixStringContextElem::Built>());
}
}
}
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,30 @@
#pragma once
#include <rapidcheck/gen/Arbitrary.h>
#include <value/context.hh>
namespace rc {
using namespace nix;
template<>
struct Arbitrary<NixStringContextElem::Opaque> {
static Gen<NixStringContextElem::Opaque> arbitrary();
};
template<>
struct Arbitrary<NixStringContextElem::Built> {
static Gen<NixStringContextElem::Built> arbitrary();
};
template<>
struct Arbitrary<NixStringContextElem::DrvDeep> {
static Gen<NixStringContextElem::DrvDeep> arbitrary();
};
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,62 @@
#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::Opaque> Arbitrary<DerivedPath::Opaque>::arbitrary()
{
return gen::just(DerivedPath::Opaque {
.path = *gen::arbitrary<StorePath>(),
});
}
Gen<DerivedPath::Built> Arbitrary<DerivedPath::Built>::arbitrary()
{
return gen::just(DerivedPath::Built {
.drvPath = *gen::arbitrary<StorePath>(),
.outputs = *gen::arbitrary<OutputsSpec>(),
});
}
Gen<DerivedPath> Arbitrary<DerivedPath>::arbitrary()
{
switch (*gen::inRange<uint8_t>(0, 1)) {
case 0:
return gen::just<DerivedPath>(*gen::arbitrary<DerivedPath::Opaque>());
default:
return gen::just<DerivedPath>(*gen::arbitrary<DerivedPath::Built>());
}
}
}
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,28 @@
#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::Opaque> {
static Gen<DerivedPath::Opaque> arbitrary();
};
template<>
struct Arbitrary<DerivedPath::Built> {
static Gen<DerivedPath::Built> arbitrary();
};
template<>
struct Arbitrary<DerivedPath> {
static Gen<DerivedPath> arbitrary();
};
}

View file

@ -1,6 +1,20 @@
check: libstore-tests_RUN check: libstore-tests-exe_RUN
programs += libstore-tests programs += libstore-tests-exe
libstore-tests-exe_NAME = libnixstore-tests
libstore-tests-exe_DIR := $(d)
libstore-tests-exe_INSTALL_DIR :=
libstore-tests-exe_LIBS = libstore-tests
libstore-tests-exe_LDFLAGS := $(GTEST_LIBS)
libraries += libstore-tests
libstore-tests_NAME = libnixstore-tests
libstore-tests_DIR := $(d) libstore-tests_DIR := $(d)
@ -10,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,7 +7,9 @@
#include "path-regex.hh" #include "path-regex.hh"
#include "store-api.hh" #include "store-api.hh"
#include "libstoretests.hh" #include "tests/hash.hh"
#include "tests/libstore.hh"
#include "tests/path.hh"
namespace nix { namespace nix {
@ -73,17 +75,14 @@ void showValue(const StorePath & p, std::ostream & os) {
namespace rc { namespace rc {
using namespace nix; using namespace nix;
template<> Gen<StorePathName> Arbitrary<StorePathName>::arbitrary()
struct Arbitrary<StorePath> {
static Gen<StorePath> arbitrary();
};
Gen<StorePath> Arbitrary<StorePath>::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)) {
@ -118,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

@ -0,0 +1,28 @@
#pragma once
#include <rapidcheck/gen/Arbitrary.h>
#include <path.hh>
namespace nix {
struct StorePathName {
std::string name;
};
}
namespace rc {
using namespace nix;
template<>
struct Arbitrary<StorePathName> {
static Gen<StorePathName> arbitrary();
};
template<>
struct Arbitrary<StorePath> {
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,14 +2,28 @@ check: libutil-tests_RUN
programs += libutil-tests programs += libutil-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)
libutil-tests_INSTALL_DIR := 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)