diff options
Diffstat (limited to 'src')
64 files changed, 96 insertions, 7747 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ef2d7e768..c2f6609f4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1536,7 +1536,9 @@ static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args, auto path = realisePath(state, pos, arg, { .checkForPureEval = false }); /* SourcePath doesn't know about trailing slash. */ - auto mustBeDir = arg.type() == nString && arg.str().ends_with("/"); + auto mustBeDir = arg.type() == nString + && (arg.str().ends_with("/") + || arg.str().ends_with("/.")); try { auto checked = state.checkSourcePath(path); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index f040a3510..d108d7d50 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -395,7 +395,8 @@ static RegisterPrimOp primop_fetchGit({ - `shallow` (default: `false`) - A Boolean parameter that specifies whether fetching a shallow clone is allowed. + A Boolean parameter that specifies whether fetching from a shallow remote repository is allowed. + This still performs a full clone of what is available on the remote. - `allRefs` diff --git a/src/libexpr/tests/derived-path.cc b/src/libexpr/tests/derived-path.cc deleted file mode 100644 index d5fc6f201..000000000 --- a/src/libexpr/tests/derived-path.cc +++ /dev/null @@ -1,68 +0,0 @@ -#include <nlohmann/json.hpp> -#include <gtest/gtest.h> -#include <rapidcheck/gtest.h> - -#include "tests/derived-path.hh" -#include "tests/libexpr.hh" - -namespace nix { - -// Testing of trivial expressions -class DerivedPathExpressionTest : public LibExprTest {}; - -// 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(DerivedPathExpressionTest, force_init) -{ -} - -#ifndef COVERAGE - -RC_GTEST_FIXTURE_PROP( - DerivedPathExpressionTest, - prop_opaque_path_round_trip, - (const SingleDerivedPath::Opaque & o)) -{ - auto * v = state.allocValue(); - state.mkStorePathString(o.path, *v); - auto d = state.coerceToSingleDerivedPath(noPos, *v, ""); - RC_ASSERT(SingleDerivedPath { o } == d); -} - -// TODO use DerivedPath::Built for parameter once it supports a single output -// path only. - -RC_GTEST_FIXTURE_PROP( - DerivedPathExpressionTest, - prop_derived_path_built_placeholder_round_trip, - (const SingleDerivedPath::Built & b)) -{ - /** - * We set these in tests rather than the regular globals so we don't have - * to worry about race conditions if the tests run concurrently. - */ - ExperimentalFeatureSettings mockXpSettings; - mockXpSettings.set("experimental-features", "ca-derivations"); - - auto * v = state.allocValue(); - state.mkOutputString(*v, b, std::nullopt, mockXpSettings); - auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, ""); - RC_ASSERT(SingleDerivedPath { b } == d); -} - -RC_GTEST_FIXTURE_PROP( - DerivedPathExpressionTest, - prop_derived_path_built_out_path_round_trip, - (const SingleDerivedPath::Built & b, const StorePath & outPath)) -{ - auto * v = state.allocValue(); - state.mkOutputString(*v, b, outPath); - auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, ""); - RC_ASSERT(SingleDerivedPath { b } == d); -} - -#endif - -} /* namespace nix */ diff --git a/src/libexpr/tests/error_traces.cc b/src/libexpr/tests/error_traces.cc deleted file mode 100644 index 285651256..000000000 --- a/src/libexpr/tests/error_traces.cc +++ /dev/null @@ -1,1298 +0,0 @@ -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -#include "tests/libexpr.hh" - -namespace nix { - - using namespace testing; - - // Testing eval of PrimOp's - class ErrorTraceTest : public LibExprTest { }; - - TEST_F(ErrorTraceTest, TraceBuilder) { - ASSERT_THROW( - state.error("Not much").debugThrow<EvalError>(), - EvalError - ); - - ASSERT_THROW( - state.error("Not much").withTrace(noPos, "No more").debugThrow<EvalError>(), - EvalError - ); - - ASSERT_THROW( - try { - try { - state.error("Not much").withTrace(noPos, "No more").debugThrow<EvalError>(); - } catch (Error & e) { - e.addTrace(state.positions[noPos], "Something", ""); - throw; - } - } catch (BaseError & e) { - ASSERT_EQ(PrintToString(e.info().msg), - PrintToString(hintfmt("Not much"))); - auto trace = e.info().traces.rbegin(); - ASSERT_EQ(e.info().traces.size(), 2); - ASSERT_EQ(PrintToString(trace->hint), - PrintToString(hintfmt("No more"))); - trace++; - ASSERT_EQ(PrintToString(trace->hint), - PrintToString(hintfmt("Something"))); - throw; - } - , EvalError - ); - } - - TEST_F(ErrorTraceTest, NestedThrows) { - try { - state.error("Not much").withTrace(noPos, "No more").debugThrow<EvalError>(); - } catch (BaseError & e) { - try { - state.error("Not much more").debugThrow<EvalError>(); - } catch (Error & e2) { - e.addTrace(state.positions[noPos], "Something", ""); - //e2.addTrace(state.positions[noPos], "Something", ""); - ASSERT_TRUE(e.info().traces.size() == 2); - ASSERT_TRUE(e2.info().traces.size() == 0); - ASSERT_FALSE(&e.info() == &e2.info()); - } - } - } - -#define ASSERT_TRACE1(args, type, message) \ - ASSERT_THROW( \ - std::string expr(args); \ - std::string name = expr.substr(0, expr.find(" ")); \ - try { \ - Value v = eval("builtins." args); \ - state.forceValueDeep(v); \ - } catch (BaseError & e) { \ - ASSERT_EQ(PrintToString(e.info().msg), \ - PrintToString(message)); \ - ASSERT_EQ(e.info().traces.size(), 1) << "while testing " args << std::endl << e.what(); \ - auto trace = e.info().traces.rbegin(); \ - ASSERT_EQ(PrintToString(trace->hint), \ - PrintToString(hintfmt("while calling the '%s' builtin", name))); \ - throw; \ - } \ - , type \ - ) - -#define ASSERT_TRACE2(args, type, message, context) \ - ASSERT_THROW( \ - std::string expr(args); \ - std::string name = expr.substr(0, expr.find(" ")); \ - try { \ - Value v = eval("builtins." args); \ - state.forceValueDeep(v); \ - } catch (BaseError & e) { \ - ASSERT_EQ(PrintToString(e.info().msg), \ - PrintToString(message)); \ - ASSERT_EQ(e.info().traces.size(), 2) << "while testing " args << std::endl << e.what(); \ - auto trace = e.info().traces.rbegin(); \ - ASSERT_EQ(PrintToString(trace->hint), \ - PrintToString(context)); \ - ++trace; \ - ASSERT_EQ(PrintToString(trace->hint), \ - PrintToString(hintfmt("while calling the '%s' builtin", name))); \ - throw; \ - } \ - , type \ - ) - - TEST_F(ErrorTraceTest, genericClosure) { - ASSERT_TRACE2("genericClosure 1", - TypeError, - hintfmt("value is %s while a set was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure {}", - TypeError, - hintfmt("attribute '%s' missing", "startSet"), - hintfmt("in the attrset passed as argument to builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure { startSet = 1; }", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = true; }", - TypeError, - hintfmt("value is %s while a function was expected", "a Boolean"), - hintfmt("while evaluating the 'operator' attribute passed as argument to builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: true; }", - TypeError, - hintfmt("value is %s while a list was expected", "a Boolean"), - hintfmt("while evaluating the return value of the `operator` passed to builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: [ true ]; }", - TypeError, - hintfmt("value is %s while a set was expected", "a Boolean"), - hintfmt("while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: [ {} ]; }", - TypeError, - hintfmt("attribute '%s' missing", "key"), - hintfmt("in one of the attrsets generated by (or initially passed to) builtins.genericClosure")); - - ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = item: [{ key = ''a''; }]; }", - EvalError, - hintfmt("cannot compare %s with %s", "a string", "an integer"), - hintfmt("while comparing the `key` attributes of two genericClosure elements")); - - ASSERT_TRACE2("genericClosure { startSet = [ true ]; operator = item: [{ key = ''a''; }]; }", - TypeError, - hintfmt("value is %s while a set was expected", "a Boolean"), - hintfmt("while evaluating one of the elements generated by (or initially passed to) builtins.genericClosure")); - - } - - - TEST_F(ErrorTraceTest, replaceStrings) { - ASSERT_TRACE2("replaceStrings 0 0 {}", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.replaceStrings")); - - ASSERT_TRACE2("replaceStrings [] 0 {}", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the second argument passed to builtins.replaceStrings")); - - ASSERT_TRACE1("replaceStrings [ 0 ] [] {}", - EvalError, - hintfmt("'from' and 'to' arguments passed to builtins.replaceStrings have different lengths")); - - ASSERT_TRACE2("replaceStrings [ 1 ] [ \"new\" ] {}", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating one of the strings to replace passed to builtins.replaceStrings")); - - ASSERT_TRACE2("replaceStrings [ \"oo\" ] [ true ] \"foo\"", - TypeError, - hintfmt("value is %s while a string was expected", "a Boolean"), - hintfmt("while evaluating one of the replacement strings passed to builtins.replaceStrings")); - - ASSERT_TRACE2("replaceStrings [ \"old\" ] [ \"new\" ] {}", - TypeError, - hintfmt("value is %s while a string was expected", "a set"), - hintfmt("while evaluating the third argument passed to builtins.replaceStrings")); - - } - - - TEST_F(ErrorTraceTest, scopedImport) { - } - - - TEST_F(ErrorTraceTest, import) { - } - - - TEST_F(ErrorTraceTest, typeOf) { - } - - - TEST_F(ErrorTraceTest, isNull) { - } - - - TEST_F(ErrorTraceTest, isFunction) { - } - - - TEST_F(ErrorTraceTest, isInt) { - } - - - TEST_F(ErrorTraceTest, isFloat) { - } - - - TEST_F(ErrorTraceTest, isString) { - } - - - TEST_F(ErrorTraceTest, isBool) { - } - - - TEST_F(ErrorTraceTest, isPath) { - } - - - TEST_F(ErrorTraceTest, break) { - } - - - TEST_F(ErrorTraceTest, abort) { - } - - - TEST_F(ErrorTraceTest, throw) { - } - - - TEST_F(ErrorTraceTest, addErrorContext) { - } - - - TEST_F(ErrorTraceTest, ceil) { - ASSERT_TRACE2("ceil \"foo\"", - TypeError, - hintfmt("value is %s while a float was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.ceil")); - - } - - - TEST_F(ErrorTraceTest, floor) { - ASSERT_TRACE2("floor \"foo\"", - TypeError, - hintfmt("value is %s while a float was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.floor")); - - } - - - TEST_F(ErrorTraceTest, tryEval) { - } - - - TEST_F(ErrorTraceTest, getEnv) { - ASSERT_TRACE2("getEnv [ ]", - TypeError, - hintfmt("value is %s while a string was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.getEnv")); - - } - - - TEST_F(ErrorTraceTest, seq) { - } - - - TEST_F(ErrorTraceTest, deepSeq) { - } - - - TEST_F(ErrorTraceTest, trace) { - } - - - TEST_F(ErrorTraceTest, placeholder) { - ASSERT_TRACE2("placeholder []", - TypeError, - hintfmt("value is %s while a string was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.placeholder")); - - } - - - TEST_F(ErrorTraceTest, toPath) { - ASSERT_TRACE2("toPath []", - TypeError, - hintfmt("cannot coerce %s to a string", "a list"), - hintfmt("while evaluating the first argument passed to builtins.toPath")); - - ASSERT_TRACE2("toPath \"foo\"", - EvalError, - hintfmt("string '%s' doesn't represent an absolute path", "foo"), - hintfmt("while evaluating the first argument passed to builtins.toPath")); - - } - - - TEST_F(ErrorTraceTest, storePath) { - ASSERT_TRACE2("storePath true", - TypeError, - hintfmt("cannot coerce %s to a string", "a Boolean"), - hintfmt("while evaluating the first argument passed to builtins.storePath")); - - } - - - TEST_F(ErrorTraceTest, pathExists) { - ASSERT_TRACE2("pathExists []", - TypeError, - hintfmt("cannot coerce %s to a string", "a list"), - hintfmt("while realising the context of a path")); - - ASSERT_TRACE2("pathExists \"zorglub\"", - EvalError, - hintfmt("string '%s' doesn't represent an absolute path", "zorglub"), - hintfmt("while realising the context of a path")); - - } - - - TEST_F(ErrorTraceTest, baseNameOf) { - ASSERT_TRACE2("baseNameOf []", - TypeError, - hintfmt("cannot coerce %s to a string", "a list"), - hintfmt("while evaluating the first argument passed to builtins.baseNameOf")); - - } - - - TEST_F(ErrorTraceTest, dirOf) { - } - - - TEST_F(ErrorTraceTest, readFile) { - } - - - TEST_F(ErrorTraceTest, findFile) { - } - - - TEST_F(ErrorTraceTest, hashFile) { - } - - - TEST_F(ErrorTraceTest, readDir) { - } - - - TEST_F(ErrorTraceTest, toXML) { - } - - - TEST_F(ErrorTraceTest, toJSON) { - } - - - TEST_F(ErrorTraceTest, fromJSON) { - } - - - TEST_F(ErrorTraceTest, toFile) { - } - - - TEST_F(ErrorTraceTest, filterSource) { - ASSERT_TRACE2("filterSource [] []", - TypeError, - hintfmt("cannot coerce %s to a string", "a list"), - hintfmt("while evaluating the second argument (the path to filter) passed to builtins.filterSource")); - - ASSERT_TRACE2("filterSource [] \"foo\"", - EvalError, - hintfmt("string '%s' doesn't represent an absolute path", "foo"), - hintfmt("while evaluating the second argument (the path to filter) passed to builtins.filterSource")); - - ASSERT_TRACE2("filterSource [] ./.", - TypeError, - hintfmt("value is %s while a function was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.filterSource")); - - // Usupported by store "dummy" - - // ASSERT_TRACE2("filterSource (_: 1) ./.", - // TypeError, - // hintfmt("attempt to call something which is not a function but %s", "an integer"), - // hintfmt("while adding path '/home/layus/projects/nix'")); - - // ASSERT_TRACE2("filterSource (_: _: 1) ./.", - // TypeError, - // hintfmt("value is %s while a Boolean was expected", "an integer"), - // hintfmt("while evaluating the return value of the path filter function")); - - } - - - TEST_F(ErrorTraceTest, path) { - } - - - TEST_F(ErrorTraceTest, attrNames) { - ASSERT_TRACE2("attrNames []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the argument passed to builtins.attrNames")); - - } - - - TEST_F(ErrorTraceTest, attrValues) { - ASSERT_TRACE2("attrValues []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the argument passed to builtins.attrValues")); - - } - - - TEST_F(ErrorTraceTest, getAttr) { - ASSERT_TRACE2("getAttr [] []", - TypeError, - hintfmt("value is %s while a string was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.getAttr")); - - ASSERT_TRACE2("getAttr \"foo\" []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the second argument passed to builtins.getAttr")); - - ASSERT_TRACE2("getAttr \"foo\" {}", - TypeError, - hintfmt("attribute '%s' missing", "foo"), - hintfmt("in the attribute set under consideration")); - - } - - - TEST_F(ErrorTraceTest, unsafeGetAttrPos) { - } - - - TEST_F(ErrorTraceTest, hasAttr) { - ASSERT_TRACE2("hasAttr [] []", - TypeError, - hintfmt("value is %s while a string was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.hasAttr")); - - ASSERT_TRACE2("hasAttr \"foo\" []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the second argument passed to builtins.hasAttr")); - - } - - - TEST_F(ErrorTraceTest, isAttrs) { - } - - - TEST_F(ErrorTraceTest, removeAttrs) { - ASSERT_TRACE2("removeAttrs \"\" \"\"", - TypeError, - hintfmt("value is %s while a set was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.removeAttrs")); - - ASSERT_TRACE2("removeAttrs \"\" [ 1 ]", - TypeError, - hintfmt("value is %s while a set was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.removeAttrs")); - - ASSERT_TRACE2("removeAttrs \"\" [ \"1\" ]", - TypeError, - hintfmt("value is %s while a set was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.removeAttrs")); - - } - - - TEST_F(ErrorTraceTest, listToAttrs) { - ASSERT_TRACE2("listToAttrs 1", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the argument passed to builtins.listToAttrs")); - - ASSERT_TRACE2("listToAttrs [ 1 ]", - TypeError, - hintfmt("value is %s while a set was expected", "an integer"), - hintfmt("while evaluating an element of the list passed to builtins.listToAttrs")); - - ASSERT_TRACE2("listToAttrs [ {} ]", - TypeError, - hintfmt("attribute '%s' missing", "name"), - hintfmt("in a {name=...; value=...;} pair")); - - ASSERT_TRACE2("listToAttrs [ { name = 1; } ]", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the `name` attribute of an element of the list passed to builtins.listToAttrs")); - - ASSERT_TRACE2("listToAttrs [ { name = \"foo\"; } ]", - TypeError, - hintfmt("attribute '%s' missing", "value"), - hintfmt("in a {name=...; value=...;} pair")); - - } - - - TEST_F(ErrorTraceTest, intersectAttrs) { - ASSERT_TRACE2("intersectAttrs [] []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.intersectAttrs")); - - ASSERT_TRACE2("intersectAttrs {} []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the second argument passed to builtins.intersectAttrs")); - - } - - - TEST_F(ErrorTraceTest, catAttrs) { - ASSERT_TRACE2("catAttrs [] {}", - TypeError, - hintfmt("value is %s while a string was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.catAttrs")); - - ASSERT_TRACE2("catAttrs \"foo\" {}", - TypeError, - hintfmt("value is %s while a list was expected", "a set"), - hintfmt("while evaluating the second argument passed to builtins.catAttrs")); - - ASSERT_TRACE2("catAttrs \"foo\" [ 1 ]", - TypeError, - hintfmt("value is %s while a set was expected", "an integer"), - hintfmt("while evaluating an element in the list passed as second argument to builtins.catAttrs")); - - ASSERT_TRACE2("catAttrs \"foo\" [ { foo = 1; } 1 { bar = 5;} ]", - TypeError, - hintfmt("value is %s while a set was expected", "an integer"), - hintfmt("while evaluating an element in the list passed as second argument to builtins.catAttrs")); - - } - - - TEST_F(ErrorTraceTest, functionArgs) { - ASSERT_TRACE1("functionArgs {}", - TypeError, - hintfmt("'functionArgs' requires a function")); - - } - - - TEST_F(ErrorTraceTest, mapAttrs) { - ASSERT_TRACE2("mapAttrs [] []", - TypeError, - hintfmt("value is %s while a set was expected", "a list"), - hintfmt("while evaluating the second argument passed to builtins.mapAttrs")); - - // XXX: defered - // ASSERT_TRACE2("mapAttrs \"\" { foo.bar = 1; }", - // TypeError, - // hintfmt("attempt to call something which is not a function but %s", "a string"), - // hintfmt("while evaluating the attribute 'foo'")); - - // ASSERT_TRACE2("mapAttrs (x: x + \"1\") { foo.bar = 1; }", - // TypeError, - // hintfmt("attempt to call something which is not a function but %s", "a string"), - // hintfmt("while evaluating the attribute 'foo'")); - - // ASSERT_TRACE2("mapAttrs (x: y: x + 1) { foo.bar = 1; }", - // TypeError, - // hintfmt("cannot coerce %s to a string", "an integer"), - // hintfmt("while evaluating a path segment")); - - } - - - TEST_F(ErrorTraceTest, zipAttrsWith) { - ASSERT_TRACE2("zipAttrsWith [] [ 1 ]", - TypeError, - hintfmt("value is %s while a function was expected", "a list"), - hintfmt("while evaluating the first argument passed to builtins.zipAttrsWith")); - - ASSERT_TRACE2("zipAttrsWith (_: 1) [ 1 ]", - TypeError, - hintfmt("value is %s while a set was expected", "an integer"), - hintfmt("while evaluating a value of the list passed as second argument to builtins.zipAttrsWith")); - - // XXX: How to properly tell that the fucntion takes two arguments ? - // The same question also applies to sort, and maybe others. - // Due to lazyness, we only create a thunk, and it fails later on. - // ASSERT_TRACE2("zipAttrsWith (_: 1) [ { foo = 1; } ]", - // TypeError, - // hintfmt("attempt to call something which is not a function but %s", "an integer"), - // hintfmt("while evaluating the attribute 'foo'")); - - // XXX: Also deferred deeply - // ASSERT_TRACE2("zipAttrsWith (a: b: a + b) [ { foo = 1; } { foo = 2; } ]", - // TypeError, - // hintfmt("cannot coerce %s to a string", "a list"), - // hintfmt("while evaluating a path segment")); - - } - - - TEST_F(ErrorTraceTest, isList) { - } - - - TEST_F(ErrorTraceTest, elemAt) { - ASSERT_TRACE2("elemAt \"foo\" (-1)", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.elemAt")); - - ASSERT_TRACE1("elemAt [] (-1)", - Error, - hintfmt("list index %d is out of bounds", -1)); - - ASSERT_TRACE1("elemAt [\"foo\"] 3", - Error, - hintfmt("list index %d is out of bounds", 3)); - - } - - - TEST_F(ErrorTraceTest, head) { - ASSERT_TRACE2("head 1", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.elemAt")); - - ASSERT_TRACE1("head []", - Error, - hintfmt("list index %d is out of bounds", 0)); - - } - - - TEST_F(ErrorTraceTest, tail) { - ASSERT_TRACE2("tail 1", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.tail")); - - ASSERT_TRACE1("tail []", - Error, - hintfmt("'tail' called on an empty list")); - - } - - - TEST_F(ErrorTraceTest, map) { - ASSERT_TRACE2("map 1 \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.map")); - - ASSERT_TRACE2("map 1 [ 1 ]", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.map")); - - } - - - TEST_F(ErrorTraceTest, filter) { - ASSERT_TRACE2("filter 1 \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.filter")); - - ASSERT_TRACE2("filter 1 [ \"foo\" ]", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.filter")); - - ASSERT_TRACE2("filter (_: 5) [ \"foo\" ]", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the return value of the filtering function passed to builtins.filter")); - - } - - - TEST_F(ErrorTraceTest, elem) { - ASSERT_TRACE2("elem 1 \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.elem")); - - } - - - TEST_F(ErrorTraceTest, concatLists) { - ASSERT_TRACE2("concatLists 1", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.concatLists")); - - ASSERT_TRACE2("concatLists [ 1 ]", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating a value of the list passed to builtins.concatLists")); - - ASSERT_TRACE2("concatLists [ [1] \"foo\" ]", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating a value of the list passed to builtins.concatLists")); - - } - - - TEST_F(ErrorTraceTest, length) { - ASSERT_TRACE2("length 1", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.length")); - - ASSERT_TRACE2("length \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the first argument passed to builtins.length")); - - } - - - TEST_F(ErrorTraceTest, foldlPrime) { - ASSERT_TRACE2("foldl' 1 \"foo\" true", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.foldlStrict")); - - ASSERT_TRACE2("foldl' (_: 1) \"foo\" true", - TypeError, - hintfmt("value is %s while a list was expected", "a Boolean"), - hintfmt("while evaluating the third argument passed to builtins.foldlStrict")); - - ASSERT_TRACE1("foldl' (_: 1) \"foo\" [ true ]", - TypeError, - hintfmt("attempt to call something which is not a function but %s", "an integer")); - - ASSERT_TRACE2("foldl' (a: b: a && b) \"foo\" [ true ]", - TypeError, - hintfmt("value is %s while a Boolean was expected", "a string"), - hintfmt("in the left operand of the AND (&&) operator")); - - } - - - TEST_F(ErrorTraceTest, any) { - ASSERT_TRACE2("any 1 \"foo\"", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.any")); - - ASSERT_TRACE2("any (_: 1) \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.any")); - - ASSERT_TRACE2("any (_: 1) [ \"foo\" ]", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the return value of the function passed to builtins.any")); - - } - - - TEST_F(ErrorTraceTest, all) { - ASSERT_TRACE2("all 1 \"foo\"", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.all")); - - ASSERT_TRACE2("all (_: 1) \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.all")); - - ASSERT_TRACE2("all (_: 1) [ \"foo\" ]", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the return value of the function passed to builtins.all")); - - } - - - TEST_F(ErrorTraceTest, genList) { - ASSERT_TRACE2("genList 1 \"foo\"", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.genList")); - - ASSERT_TRACE2("genList 1 2", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.genList", "an integer")); - - // XXX: defered - // ASSERT_TRACE2("genList (x: x + \"foo\") 2 #TODO", - // TypeError, - // hintfmt("cannot add %s to an integer", "a string"), - // hintfmt("while evaluating anonymous lambda")); - - ASSERT_TRACE1("genList false (-3)", - EvalError, - hintfmt("cannot create list of size %d", -3)); - - } - - - TEST_F(ErrorTraceTest, sort) { - ASSERT_TRACE2("sort 1 \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.sort")); - - ASSERT_TRACE2("sort 1 [ \"foo\" ]", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.sort")); - - ASSERT_TRACE1("sort (_: 1) [ \"foo\" \"bar\" ]", - TypeError, - hintfmt("attempt to call something which is not a function but %s", "an integer")); - - ASSERT_TRACE2("sort (_: _: 1) [ \"foo\" \"bar\" ]", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the return value of the sorting function passed to builtins.sort")); - - // XXX: Trace too deep, need better asserts - // ASSERT_TRACE1("sort (a: b: a <= b) [ \"foo\" {} ] # TODO", - // TypeError, - // hintfmt("cannot compare %s with %s", "a string", "a set")); - - // ASSERT_TRACE1("sort (a: b: a <= b) [ {} {} ] # TODO", - // TypeError, - // hintfmt("cannot compare %s with %s; values of that type are incomparable", "a set", "a set")); - - } - - - TEST_F(ErrorTraceTest, partition) { - ASSERT_TRACE2("partition 1 \"foo\"", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.partition")); - - ASSERT_TRACE2("partition (_: 1) \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.partition")); - - ASSERT_TRACE2("partition (_: 1) [ \"foo\" ]", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the return value of the partition function passed to builtins.partition")); - - } - - - TEST_F(ErrorTraceTest, groupBy) { - ASSERT_TRACE2("groupBy 1 \"foo\"", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.groupBy")); - - ASSERT_TRACE2("groupBy (_: 1) \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.groupBy")); - - ASSERT_TRACE2("groupBy (x: x) [ \"foo\" \"bar\" 1 ]", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the return value of the grouping function passed to builtins.groupBy")); - - } - - - TEST_F(ErrorTraceTest, concatMap) { - ASSERT_TRACE2("concatMap 1 \"foo\"", - TypeError, - hintfmt("value is %s while a function was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.concatMap")); - - ASSERT_TRACE2("concatMap (x: 1) \"foo\"", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the second argument passed to builtins.concatMap")); - - ASSERT_TRACE2("concatMap (x: 1) [ \"foo\" ] # TODO", - TypeError, - hintfmt("value is %s while a list was expected", "an integer"), - hintfmt("while evaluating the return value of the function passed to buitlins.concatMap")); - - ASSERT_TRACE2("concatMap (x: \"foo\") [ 1 2 ] # TODO", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the return value of the function passed to buitlins.concatMap")); - - } - - - TEST_F(ErrorTraceTest, add) { - ASSERT_TRACE2("add \"foo\" 1", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the first argument of the addition")); - - ASSERT_TRACE2("add 1 \"foo\"", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the second argument of the addition")); - - } - - - TEST_F(ErrorTraceTest, sub) { - ASSERT_TRACE2("sub \"foo\" 1", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the first argument of the subtraction")); - - ASSERT_TRACE2("sub 1 \"foo\"", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the second argument of the subtraction")); - - } - - - TEST_F(ErrorTraceTest, mul) { - ASSERT_TRACE2("mul \"foo\" 1", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the first argument of the multiplication")); - - ASSERT_TRACE2("mul 1 \"foo\"", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the second argument of the multiplication")); - - } - - - TEST_F(ErrorTraceTest, div) { - ASSERT_TRACE2("div \"foo\" 1 # TODO: an integer was expected -> a number", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the first operand of the division")); - - ASSERT_TRACE2("div 1 \"foo\"", - TypeError, - hintfmt("value is %s while a float was expected", "a string"), - hintfmt("while evaluating the second operand of the division")); - - ASSERT_TRACE1("div \"foo\" 0", - EvalError, - hintfmt("division by zero")); - - } - - - TEST_F(ErrorTraceTest, bitAnd) { - ASSERT_TRACE2("bitAnd 1.1 2", - TypeError, - hintfmt("value is %s while an integer was expected", "a float"), - hintfmt("while evaluating the first argument passed to builtins.bitAnd")); - - ASSERT_TRACE2("bitAnd 1 2.2", - TypeError, - hintfmt("value is %s while an integer was expected", "a float"), - hintfmt("while evaluating the second argument passed to builtins.bitAnd")); - - } - - - TEST_F(ErrorTraceTest, bitOr) { - ASSERT_TRACE2("bitOr 1.1 2", - TypeError, - hintfmt("value is %s while an integer was expected", "a float"), - hintfmt("while evaluating the first argument passed to builtins.bitOr")); - - ASSERT_TRACE2("bitOr 1 2.2", - TypeError, - hintfmt("value is %s while an integer was expected", "a float"), - hintfmt("while evaluating the second argument passed to builtins.bitOr")); - - } - - - TEST_F(ErrorTraceTest, bitXor) { - ASSERT_TRACE2("bitXor 1.1 2", - TypeError, - hintfmt("value is %s while an integer was expected", "a float"), - hintfmt("while evaluating the first argument passed to builtins.bitXor")); - - ASSERT_TRACE2("bitXor 1 2.2", - TypeError, - hintfmt("value is %s while an integer was expected", "a float"), - hintfmt("while evaluating the second argument passed to builtins.bitXor")); - - } - - - TEST_F(ErrorTraceTest, lessThan) { - ASSERT_TRACE1("lessThan 1 \"foo\"", - EvalError, - hintfmt("cannot compare %s with %s", "an integer", "a string")); - - ASSERT_TRACE1("lessThan {} {}", - EvalError, - hintfmt("cannot compare %s with %s; values of that type are incomparable", "a set", "a set")); - - ASSERT_TRACE2("lessThan [ 1 2 ] [ \"foo\" ]", - EvalError, - hintfmt("cannot compare %s with %s", "an integer", "a string"), - hintfmt("while comparing two list elements")); - - } - - - TEST_F(ErrorTraceTest, toString) { - ASSERT_TRACE2("toString { a = 1; }", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating the first argument passed to builtins.toString")); - - } - - - TEST_F(ErrorTraceTest, substring) { - ASSERT_TRACE2("substring {} \"foo\" true", - TypeError, - hintfmt("value is %s while an integer was expected", "a set"), - hintfmt("while evaluating the first argument (the start offset) passed to builtins.substring")); - - ASSERT_TRACE2("substring 3 \"foo\" true", - TypeError, - hintfmt("value is %s while an integer was expected", "a string"), - hintfmt("while evaluating the second argument (the substring length) passed to builtins.substring")); - - ASSERT_TRACE2("substring 0 3 {}", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating the third argument (the string) passed to builtins.substring")); - - ASSERT_TRACE1("substring (-3) 3 \"sometext\"", - EvalError, - hintfmt("negative start position in 'substring'")); - - } - - - TEST_F(ErrorTraceTest, stringLength) { - ASSERT_TRACE2("stringLength {} # TODO: context is missing ???", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating the argument passed to builtins.stringLength")); - - } - - - TEST_F(ErrorTraceTest, hashString) { - ASSERT_TRACE2("hashString 1 {}", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.hashString")); - - ASSERT_TRACE1("hashString \"foo\" \"content\"", - UsageError, - hintfmt("unknown hash algorithm '%s'", "foo")); - - ASSERT_TRACE2("hashString \"sha256\" {}", - TypeError, - hintfmt("value is %s while a string was expected", "a set"), - hintfmt("while evaluating the second argument passed to builtins.hashString")); - - } - - - TEST_F(ErrorTraceTest, match) { - ASSERT_TRACE2("match 1 {}", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.match")); - - ASSERT_TRACE2("match \"foo\" {}", - TypeError, - hintfmt("value is %s while a string was expected", "a set"), - hintfmt("while evaluating the second argument passed to builtins.match")); - - ASSERT_TRACE1("match \"(.*\" \"\"", - EvalError, - hintfmt("invalid regular expression '%s'", "(.*")); - - } - - - TEST_F(ErrorTraceTest, split) { - ASSERT_TRACE2("split 1 {}", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.split")); - - ASSERT_TRACE2("split \"foo\" {}", - TypeError, - hintfmt("value is %s while a string was expected", "a set"), - hintfmt("while evaluating the second argument passed to builtins.split")); - - ASSERT_TRACE1("split \"f(o*o\" \"1foo2\"", - EvalError, - hintfmt("invalid regular expression '%s'", "f(o*o")); - - } - - - TEST_F(ErrorTraceTest, concatStringsSep) { - ASSERT_TRACE2("concatStringsSep 1 {}", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument (the separator string) passed to builtins.concatStringsSep")); - - ASSERT_TRACE2("concatStringsSep \"foo\" {}", - TypeError, - hintfmt("value is %s while a list was expected", "a set"), - hintfmt("while evaluating the second argument (the list of strings to concat) passed to builtins.concatStringsSep")); - - ASSERT_TRACE2("concatStringsSep \"foo\" [ 1 2 {} ] # TODO: coerce to string is buggy", - TypeError, - hintfmt("cannot coerce %s to a string", "an integer"), - hintfmt("while evaluating one element of the list of strings to concat passed to builtins.concatStringsSep")); - - } - - - TEST_F(ErrorTraceTest, parseDrvName) { - ASSERT_TRACE2("parseDrvName 1", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.parseDrvName")); - - } - - - TEST_F(ErrorTraceTest, compareVersions) { - ASSERT_TRACE2("compareVersions 1 {}", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.compareVersions")); - - ASSERT_TRACE2("compareVersions \"abd\" {}", - TypeError, - hintfmt("value is %s while a string was expected", "a set"), - hintfmt("while evaluating the second argument passed to builtins.compareVersions")); - - } - - - TEST_F(ErrorTraceTest, splitVersion) { - ASSERT_TRACE2("splitVersion 1", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the first argument passed to builtins.splitVersion")); - - } - - - TEST_F(ErrorTraceTest, traceVerbose) { - } - - - /* // Needs different ASSERTs - TEST_F(ErrorTraceTest, derivationStrict) { - ASSERT_TRACE2("derivationStrict \"\"", - TypeError, - hintfmt("value is %s while a set was expected", "a string"), - hintfmt("while evaluating the argument passed to builtins.derivationStrict")); - - ASSERT_TRACE2("derivationStrict {}", - TypeError, - hintfmt("attribute '%s' missing", "name"), - hintfmt("in the attrset passed as argument to builtins.derivationStrict")); - - ASSERT_TRACE2("derivationStrict { name = 1; }", - TypeError, - hintfmt("value is %s while a string was expected", "an integer"), - hintfmt("while evaluating the `name` attribute passed to builtins.derivationStrict")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; }", - TypeError, - hintfmt("required attribute 'builder' missing"), - hintfmt("while evaluating derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; __structuredAttrs = 15; }", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the `__structuredAttrs` attribute passed to builtins.derivationStrict")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; __ignoreNulls = 15; }", - TypeError, - hintfmt("value is %s while a Boolean was expected", "an integer"), - hintfmt("while evaluating the `__ignoreNulls` attribute passed to builtins.derivationStrict")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; outputHashMode = 15; }", - TypeError, - hintfmt("invalid value '15' for 'outputHashMode' attribute"), - hintfmt("while evaluating the attribute 'outputHashMode' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; outputHashMode = \"custom\"; }", - TypeError, - hintfmt("invalid value 'custom' for 'outputHashMode' attribute"), - hintfmt("while evaluating the attribute 'outputHashMode' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = {}; }", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating the attribute 'system' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = {}; }", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"drv\"; }", - TypeError, - hintfmt("invalid derivation output name 'drv'"), - hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = []; }", - TypeError, - hintfmt("derivation cannot have an empty set of outputs"), - hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = [ \"drv\" ]; }", - TypeError, - hintfmt("invalid derivation output name 'drv'"), - hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = [ \"out\" \"out\" ]; }", - TypeError, - hintfmt("duplicate derivation output 'out'"), - hintfmt("while evaluating the attribute 'outputs' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; __contentAddressed = \"true\"; }", - TypeError, - hintfmt("value is %s while a Boolean was expected", "a string"), - hintfmt("while evaluating the attribute '__contentAddressed' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; __impure = \"true\"; }", - TypeError, - hintfmt("value is %s while a Boolean was expected", "a string"), - hintfmt("while evaluating the attribute '__impure' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; __impure = \"true\"; }", - TypeError, - hintfmt("value is %s while a Boolean was expected", "a string"), - hintfmt("while evaluating the attribute '__impure' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = \"foo\"; }", - TypeError, - hintfmt("value is %s while a list was expected", "a string"), - hintfmt("while evaluating the attribute 'args' of derivation 'foo'")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ {} ]; }", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating an element of the argument list")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; args = [ \"a\" {} ]; }", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating an element of the argument list")); - - ASSERT_TRACE2("derivationStrict { name = \"foo\"; builder = 1; system = 1; outputs = \"out\"; FOO = {}; }", - TypeError, - hintfmt("cannot coerce %s to a string", "a set"), - hintfmt("while evaluating the attribute 'FOO' of derivation 'foo'")); - - } - */ - -} /* namespace nix */ diff --git a/src/libexpr/tests/flakeref.cc b/src/libexpr/tests/flakeref.cc deleted file mode 100644 index 2b7809b93..000000000 --- a/src/libexpr/tests/flakeref.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include <gtest/gtest.h> - -#include "flake/flakeref.hh" - -namespace nix { - -/* ----------- tests for flake/flakeref.hh --------------------------------------------------*/ - - /* ---------------------------------------------------------------------------- - * to_string - * --------------------------------------------------------------------------*/ - - TEST(to_string, doesntReencodeUrl) { - auto s = "http://localhost:8181/test/+3d.tar.gz"; - auto flakeref = parseFlakeRef(s); - auto parsed = flakeref.to_string(); - auto expected = "http://localhost:8181/test/%2B3d.tar.gz"; - - ASSERT_EQ(parsed, expected); - } - -} diff --git a/src/libexpr/tests/json.cc b/src/libexpr/tests/json.cc deleted file mode 100644 index 7586bdd9b..000000000 --- a/src/libexpr/tests/json.cc +++ /dev/null @@ -1,68 +0,0 @@ -#include "tests/libexpr.hh" -#include "value-to-json.hh" - -namespace nix { -// Testing the conversion to JSON - - class JSONValueTest : public LibExprTest { - protected: - std::string getJSONValue(Value& value) { - std::stringstream ss; - NixStringContext ps; - printValueAsJSON(state, true, value, noPos, ss, ps); - return ss.str(); - } - }; - - TEST_F(JSONValueTest, null) { - Value v; - v.mkNull(); - ASSERT_EQ(getJSONValue(v), "null"); - } - - TEST_F(JSONValueTest, BoolFalse) { - Value v; - v.mkBool(false); - ASSERT_EQ(getJSONValue(v),"false"); - } - - TEST_F(JSONValueTest, BoolTrue) { - Value v; - v.mkBool(true); - ASSERT_EQ(getJSONValue(v), "true"); - } - - TEST_F(JSONValueTest, IntPositive) { - Value v; - v.mkInt(100); - ASSERT_EQ(getJSONValue(v), "100"); - } - - TEST_F(JSONValueTest, IntNegative) { - Value v; - v.mkInt(-100); - ASSERT_EQ(getJSONValue(v), "-100"); - } - - TEST_F(JSONValueTest, String) { - Value v; - v.mkString("test"); - ASSERT_EQ(getJSONValue(v), "\"test\""); - } - - TEST_F(JSONValueTest, StringQuotes) { - Value v; - - v.mkString("test\""); - ASSERT_EQ(getJSONValue(v), "\"test\\\"\""); - } - - // The dummy store doesn't support writing files. Fails with this exception message: - // C++ exception with description "error: operation 'addToStoreFromDump' is - // not supported by store 'dummy'" thrown in the test body. - TEST_F(JSONValueTest, DISABLED_Path) { - Value v; - v.mkPath("test"); - ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\""); - } -} /* namespace nix */ diff --git a/src/libexpr/tests/libexpr.hh b/src/libexpr/tests/libexpr.hh deleted file mode 100644 index b8e65aafe..000000000 --- a/src/libexpr/tests/libexpr.hh +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once -///@file - -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -#include "value.hh" -#include "nixexpr.hh" -#include "eval.hh" -#include "eval-inline.hh" -#include "store-api.hh" - -#include "tests/libstore.hh" - -namespace nix { - class LibExprTest : public LibStoreTest { - public: - static void SetUpTestSuite() { - LibStoreTest::SetUpTestSuite(); - initGC(); - } - - protected: - LibExprTest() - : LibStoreTest() - , state({}, store) - { - } - Value eval(std::string input, bool forceValue = true) { - Value v; - Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root)); - assert(e); - state.eval(e, v); - if (forceValue) - state.forceValue(v, noPos); - return v; - } - - Symbol createSymbol(const char * value) { - return state.symbols.create(value); - } - - EvalState state; - }; - - MATCHER(IsListType, "") { - return arg != nList; - } - - MATCHER(IsList, "") { - return arg.type() == nList; - } - - MATCHER(IsString, "") { - return arg.type() == nString; - } - - MATCHER(IsNull, "") { - return arg.type() == nNull; - } - - MATCHER(IsThunk, "") { - return arg.type() == nThunk; - } - - MATCHER(IsAttrs, "") { - return arg.type() == nAttrs; - } - - MATCHER_P(IsStringEq, s, fmt("The string is equal to \"%1%\"", s)) { - if (arg.type() != nString) { - return false; - } - return std::string_view(arg.string.s) == s; - } - - MATCHER_P(IsIntEq, v, fmt("The string is equal to \"%1%\"", v)) { - if (arg.type() != nInt) { - return false; - } - return arg.integer == v; - } - - MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v)) { - if (arg.type() != nFloat) { - return false; - } - return arg.fpoint == v; - } - - MATCHER(IsTrue, "") { - if (arg.type() != nBool) { - return false; - } - return arg.boolean == true; - } - - MATCHER(IsFalse, "") { - if (arg.type() != nBool) { - return false; - } - return arg.boolean == false; - } - - MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) { - if (arg.type() != nPath) { - *result_listener << "Expected a path got " << arg.type(); - return false; - } else if (std::string_view(arg.string.s) != p) { - *result_listener << "Expected a path that equals \"" << p << "\" but got: " << arg.string.s; - return false; - } - return true; - } - - - MATCHER_P(IsListOfSize, n, fmt("Is a list of size [%1%]", n)) { - if (arg.type() != nList) { - *result_listener << "Expected list got " << arg.type(); - return false; - } else if (arg.listSize() != (size_t)n) { - *result_listener << "Expected as list of size " << n << " got " << arg.listSize(); - return false; - } - return true; - } - - MATCHER_P(IsAttrsOfSize, n, fmt("Is a set of size [%1%]", n)) { - if (arg.type() != nAttrs) { - *result_listener << "Expected set got " << arg.type(); - return false; - } else if (arg.attrs->size() != (size_t)n) { - *result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs->size(); - return false; - } - return true; - } - - -} /* namespace nix */ diff --git a/src/libexpr/tests/local.mk b/src/libexpr/tests/local.mk deleted file mode 100644 index 331a5ead6..000000000 --- a/src/libexpr/tests/local.mk +++ /dev/null @@ -1,19 +0,0 @@ -check: libexpr-tests_RUN - -programs += libexpr-tests - -libexpr-tests_NAME := libnixexpr-tests - -libexpr-tests_DIR := $(d) - -libexpr-tests_INSTALL_DIR := - -libexpr-tests_SOURCES := \ - $(wildcard $(d)/*.cc) \ - $(wildcard $(d)/value/*.cc) - -libexpr-tests_CXXFLAGS += -I src/libexpr -I src/libutil -I src/libstore -I src/libexpr/tests -I src/libfetchers - -libexpr-tests_LIBS = libstore-tests libutils-tests libexpr libutil libstore libfetchers - -libexpr-tests_LDFLAGS := $(GTEST_LIBS) -lgmock diff --git a/src/libexpr/tests/primops.cc b/src/libexpr/tests/primops.cc deleted file mode 100644 index ce3b5d11f..000000000 --- a/src/libexpr/tests/primops.cc +++ /dev/null @@ -1,832 +0,0 @@ -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -#include "tests/libexpr.hh" - -namespace nix { - class CaptureLogger : public Logger - { - std::ostringstream oss; - - public: - CaptureLogger() {} - - std::string get() const { - return oss.str(); - } - - void log(Verbosity lvl, std::string_view s) override { - oss << s << std::endl; - } - - void logEI(const ErrorInfo & ei) override { - showErrorInfo(oss, ei, loggerSettings.showTrace.get()); - } - }; - - class CaptureLogging { - Logger * oldLogger; - std::unique_ptr<CaptureLogger> tempLogger; - public: - CaptureLogging() : tempLogger(std::make_unique<CaptureLogger>()) { - oldLogger = logger; - logger = tempLogger.get(); - } - - ~CaptureLogging() { - logger = oldLogger; - } - - std::string get() const { - return tempLogger->get(); - } - }; - - - // Testing eval of PrimOp's - class PrimOpTest : public LibExprTest {}; - - - TEST_F(PrimOpTest, throw) { - ASSERT_THROW(eval("throw \"foo\""), ThrownError); - } - - TEST_F(PrimOpTest, abort) { - ASSERT_THROW(eval("abort \"abort\""), Abort); - } - - TEST_F(PrimOpTest, ceil) { - auto v = eval("builtins.ceil 1.9"); - ASSERT_THAT(v, IsIntEq(2)); - } - - TEST_F(PrimOpTest, floor) { - auto v = eval("builtins.floor 1.9"); - ASSERT_THAT(v, IsIntEq(1)); - } - - TEST_F(PrimOpTest, tryEvalFailure) { - auto v = eval("builtins.tryEval (throw \"\")"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - auto s = createSymbol("success"); - auto p = v.attrs->get(s); - ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsFalse()); - } - - TEST_F(PrimOpTest, tryEvalSuccess) { - auto v = eval("builtins.tryEval 123"); - ASSERT_THAT(v, IsAttrs()); - auto s = createSymbol("success"); - auto p = v.attrs->get(s); - ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsTrue()); - s = createSymbol("value"); - p = v.attrs->get(s); - ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsIntEq(123)); - } - - TEST_F(PrimOpTest, getEnv) { - setenv("_NIX_UNIT_TEST_ENV_VALUE", "test value", 1); - auto v = eval("builtins.getEnv \"_NIX_UNIT_TEST_ENV_VALUE\""); - ASSERT_THAT(v, IsStringEq("test value")); - } - - TEST_F(PrimOpTest, seq) { - ASSERT_THROW(eval("let x = throw \"test\"; in builtins.seq x { }"), ThrownError); - } - - TEST_F(PrimOpTest, seqNotDeep) { - auto v = eval("let x = { z = throw \"test\"; }; in builtins.seq x { }"); - ASSERT_THAT(v, IsAttrs()); - } - - TEST_F(PrimOpTest, deepSeq) { - ASSERT_THROW(eval("let x = { z = throw \"test\"; }; in builtins.deepSeq x { }"), ThrownError); - } - - TEST_F(PrimOpTest, trace) { - CaptureLogging l; - auto v = eval("builtins.trace \"test string 123\" 123"); - ASSERT_THAT(v, IsIntEq(123)); - auto text = l.get(); - ASSERT_NE(text.find("test string 123"), std::string::npos); - } - - TEST_F(PrimOpTest, placeholder) { - auto v = eval("builtins.placeholder \"out\""); - ASSERT_THAT(v, IsStringEq("/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")); - } - - TEST_F(PrimOpTest, baseNameOf) { - auto v = eval("builtins.baseNameOf /some/path"); - ASSERT_THAT(v, IsStringEq("path")); - } - - TEST_F(PrimOpTest, dirOf) { - auto v = eval("builtins.dirOf /some/path"); - ASSERT_THAT(v, IsPathEq("/some")); - } - - TEST_F(PrimOpTest, attrValues) { - auto v = eval("builtins.attrValues { x = \"foo\"; a = 1; }"); - ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); - ASSERT_THAT(*v.listElems()[1], IsStringEq("foo")); - } - - TEST_F(PrimOpTest, getAttr) { - auto v = eval("builtins.getAttr \"x\" { x = \"foo\"; }"); - ASSERT_THAT(v, IsStringEq("foo")); - } - - TEST_F(PrimOpTest, getAttrNotFound) { - // FIXME: TypeError is really bad here, also the error wording is worse - // than on Nix <=2.3 - ASSERT_THROW(eval("builtins.getAttr \"y\" { }"), TypeError); - } - - TEST_F(PrimOpTest, unsafeGetAttrPos) { - // The `y` attribute is at position - const char* expr = "builtins.unsafeGetAttrPos \"y\" { y = \"x\"; }"; - auto v = eval(expr); - ASSERT_THAT(v, IsNull()); - } - - TEST_F(PrimOpTest, hasAttr) { - auto v = eval("builtins.hasAttr \"x\" { x = 1; }"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, hasAttrNotFound) { - auto v = eval("builtins.hasAttr \"x\" { }"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, isAttrs) { - auto v = eval("builtins.isAttrs {}"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, isAttrsFalse) { - auto v = eval("builtins.isAttrs null"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, removeAttrs) { - auto v = eval("builtins.removeAttrs { x = 1; } [\"x\"]"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(PrimOpTest, removeAttrsRetains) { - auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - ASSERT_NE(v.attrs->find(createSymbol("y")), nullptr); - } - - TEST_F(PrimOpTest, listToAttrsEmptyList) { - auto v = eval("builtins.listToAttrs []"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - ASSERT_EQ(v.type(), nAttrs); - ASSERT_EQ(v.attrs->size(), 0); - } - - TEST_F(PrimOpTest, listToAttrsNotFieldName) { - ASSERT_THROW(eval("builtins.listToAttrs [{}]"), Error); - } - - TEST_F(PrimOpTest, listToAttrs) { - auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - auto key = v.attrs->find(createSymbol("key")); - ASSERT_NE(key, nullptr); - ASSERT_THAT(*key->value, IsIntEq(123)); - } - - TEST_F(PrimOpTest, intersectAttrs) { - auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - auto b = v.attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(3)); - } - - TEST_F(PrimOpTest, catAttrs) { - auto v = eval("builtins.catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]"); - ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); - ASSERT_THAT(*v.listElems()[1], IsIntEq(2)); - } - - TEST_F(PrimOpTest, functionArgs) { - auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto x = v.attrs->find(createSymbol("x")); - ASSERT_NE(x, nullptr); - ASSERT_THAT(*x->value, IsFalse()); - - auto y = v.attrs->find(createSymbol("y")); - ASSERT_NE(y, nullptr); - ASSERT_THAT(*y->value, IsTrue()); - } - - TEST_F(PrimOpTest, mapAttrs) { - auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto a = v.attrs->find(createSymbol("a")); - ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsThunk()); - state.forceValue(*a->value, noPos); - ASSERT_THAT(*a->value, IsIntEq(10)); - - auto b = v.attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsThunk()); - state.forceValue(*b->value, noPos); - ASSERT_THAT(*b->value, IsIntEq(20)); - } - - TEST_F(PrimOpTest, isList) { - auto v = eval("builtins.isList []"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, isListFalse) { - auto v = eval("builtins.isList null"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, elemtAt) { - auto v = eval("builtins.elemAt [0 1 2 3] 3"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, elemtAtOutOfBounds) { - ASSERT_THROW(eval("builtins.elemAt [0 1 2 3] 5"), Error); - } - - TEST_F(PrimOpTest, head) { - auto v = eval("builtins.head [ 3 2 1 0 ]"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, headEmpty) { - ASSERT_THROW(eval("builtins.head [ ]"), Error); - } - - TEST_F(PrimOpTest, headWrongType) { - ASSERT_THROW(eval("builtins.head { }"), Error); - } - - TEST_F(PrimOpTest, tail) { - auto v = eval("builtins.tail [ 3 2 1 0 ]"); - ASSERT_THAT(v, IsListOfSize(3)); - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(2 - static_cast<int>(n))); - } - - TEST_F(PrimOpTest, tailEmpty) { - ASSERT_THROW(eval("builtins.tail []"), Error); - } - - TEST_F(PrimOpTest, map) { - auto v = eval("map (x: \"foo\" + x) [ \"bar\" \"bla\" \"abc\" ]"); - ASSERT_THAT(v, IsListOfSize(3)); - auto elem = v.listElems()[0]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("foobar")); - - elem = v.listElems()[1]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("foobla")); - - elem = v.listElems()[2]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("fooabc")); - } - - TEST_F(PrimOpTest, filter) { - auto v = eval("builtins.filter (x: x == 2) [ 3 2 3 2 3 2 ]"); - ASSERT_THAT(v, IsListOfSize(3)); - for (const auto elem : v.listItems()) - ASSERT_THAT(*elem, IsIntEq(2)); - } - - TEST_F(PrimOpTest, elemTrue) { - auto v = eval("builtins.elem 3 [ 1 2 3 4 5 ]"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, elemFalse) { - auto v = eval("builtins.elem 6 [ 1 2 3 4 5 ]"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, concatLists) { - auto v = eval("builtins.concatLists [[1 2] [3 4]]"); - ASSERT_THAT(v, IsListOfSize(4)); - for (const auto [i, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(static_cast<int>(i)+1)); - } - - TEST_F(PrimOpTest, length) { - auto v = eval("builtins.length [ 1 2 3 ]"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, foldStrict) { - auto v = eval("builtins.foldl' (a: b: a + b) 0 [1 2 3]"); - ASSERT_THAT(v, IsIntEq(6)); - } - - TEST_F(PrimOpTest, anyTrue) { - auto v = eval("builtins.any (x: x == 2) [ 1 2 3 ]"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, anyFalse) { - auto v = eval("builtins.any (x: x == 5) [ 1 2 3 ]"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, allTrue) { - auto v = eval("builtins.all (x: x > 0) [ 1 2 3 ]"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, allFalse) { - auto v = eval("builtins.all (x: x <= 0) [ 1 2 3 ]"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, genList) { - auto v = eval("builtins.genList (x: x + 1) 3"); - ASSERT_EQ(v.type(), nList); - ASSERT_EQ(v.listSize(), 3); - for (const auto [i, elem] : enumerate(v.listItems())) { - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsIntEq(static_cast<int>(i)+1)); - } - } - - TEST_F(PrimOpTest, sortLessThan) { - auto v = eval("builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]"); - ASSERT_EQ(v.type(), nList); - ASSERT_EQ(v.listSize(), 6); - - const std::vector<int> numbers = { 42, 77, 147, 249, 483, 526 }; - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(numbers[n])); - } - - TEST_F(PrimOpTest, partition) { - auto v = eval("builtins.partition (x: x > 10) [1 23 9 3 42]"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto right = v.attrs->get(createSymbol("right")); - ASSERT_NE(right, nullptr); - ASSERT_THAT(*right->value, IsListOfSize(2)); - ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23)); - ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42)); - - auto wrong = v.attrs->get(createSymbol("wrong")); - ASSERT_NE(wrong, nullptr); - ASSERT_EQ(wrong->value->type(), nList); - ASSERT_EQ(wrong->value->listSize(), 3); - ASSERT_THAT(*wrong->value, IsListOfSize(3)); - ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1)); - ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9)); - ASSERT_THAT(*wrong->value->listElems()[2], IsIntEq(3)); - } - - TEST_F(PrimOpTest, concatMap) { - auto v = eval("builtins.concatMap (x: x ++ [0]) [ [1 2] [3 4] ]"); - ASSERT_EQ(v.type(), nList); - ASSERT_EQ(v.listSize(), 6); - - const std::vector<int> numbers = { 1, 2, 0, 3, 4, 0 }; - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(numbers[n])); - } - - TEST_F(PrimOpTest, addInt) { - auto v = eval("builtins.add 3 5"); - ASSERT_THAT(v, IsIntEq(8)); - } - - TEST_F(PrimOpTest, addFloat) { - auto v = eval("builtins.add 3.0 5.0"); - ASSERT_THAT(v, IsFloatEq(8.0)); - } - - TEST_F(PrimOpTest, addFloatToInt) { - auto v = eval("builtins.add 3.0 5"); - ASSERT_THAT(v, IsFloatEq(8.0)); - - v = eval("builtins.add 3 5.0"); - ASSERT_THAT(v, IsFloatEq(8.0)); - } - - TEST_F(PrimOpTest, subInt) { - auto v = eval("builtins.sub 5 2"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, subFloat) { - auto v = eval("builtins.sub 5.0 2.0"); - ASSERT_THAT(v, IsFloatEq(3.0)); - } - - TEST_F(PrimOpTest, subFloatFromInt) { - auto v = eval("builtins.sub 5.0 2"); - ASSERT_THAT(v, IsFloatEq(3.0)); - - v = eval("builtins.sub 4 2.0"); - ASSERT_THAT(v, IsFloatEq(2.0)); - } - - TEST_F(PrimOpTest, mulInt) { - auto v = eval("builtins.mul 3 5"); - ASSERT_THAT(v, IsIntEq(15)); - } - - TEST_F(PrimOpTest, mulFloat) { - auto v = eval("builtins.mul 3.0 5.0"); - ASSERT_THAT(v, IsFloatEq(15.0)); - } - - TEST_F(PrimOpTest, mulFloatMixed) { - auto v = eval("builtins.mul 3 5.0"); - ASSERT_THAT(v, IsFloatEq(15.0)); - - v = eval("builtins.mul 2.0 5"); - ASSERT_THAT(v, IsFloatEq(10.0)); - } - - TEST_F(PrimOpTest, divInt) { - auto v = eval("builtins.div 5 (-1)"); - ASSERT_THAT(v, IsIntEq(-5)); - } - - TEST_F(PrimOpTest, divIntZero) { - ASSERT_THROW(eval("builtins.div 5 0"), EvalError); - } - - TEST_F(PrimOpTest, divFloat) { - auto v = eval("builtins.div 5.0 (-1)"); - ASSERT_THAT(v, IsFloatEq(-5.0)); - } - - TEST_F(PrimOpTest, divFloatZero) { - ASSERT_THROW(eval("builtins.div 5.0 0.0"), EvalError); - } - - TEST_F(PrimOpTest, bitOr) { - auto v = eval("builtins.bitOr 1 2"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, bitXor) { - auto v = eval("builtins.bitXor 3 2"); - ASSERT_THAT(v, IsIntEq(1)); - } - - TEST_F(PrimOpTest, lessThanFalse) { - auto v = eval("builtins.lessThan 3 1"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, lessThanTrue) { - auto v = eval("builtins.lessThan 1 3"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, toStringAttrsThrows) { - ASSERT_THROW(eval("builtins.toString {}"), EvalError); - } - - TEST_F(PrimOpTest, toStringLambdaThrows) { - ASSERT_THROW(eval("builtins.toString (x: x)"), EvalError); - } - - class ToStringPrimOpTest : - public PrimOpTest, - public testing::WithParamInterface<std::tuple<std::string, std::string_view>> - {}; - - TEST_P(ToStringPrimOpTest, toString) { - const auto [input, output] = GetParam(); - auto v = eval(input); - ASSERT_THAT(v, IsStringEq(output)); - } - -#define CASE(input, output) (std::make_tuple(std::string_view("builtins.toString " input), std::string_view(output))) - INSTANTIATE_TEST_SUITE_P( - toString, - ToStringPrimOpTest, - testing::Values( - CASE(R"("foo")", "foo"), - CASE(R"(1)", "1"), - CASE(R"([1 2 3])", "1 2 3"), - CASE(R"(.123)", "0.123000"), - CASE(R"(true)", "1"), - CASE(R"(false)", ""), - CASE(R"(null)", ""), - CASE(R"({ v = "bar"; __toString = self: self.v; })", "bar"), - CASE(R"({ v = "bar"; __toString = self: self.v; outPath = "foo"; })", "bar"), - CASE(R"({ outPath = "foo"; })", "foo"), - CASE(R"(./test)", "/test") - ) - ); -#undef CASE - - TEST_F(PrimOpTest, substring){ - auto v = eval("builtins.substring 0 3 \"nixos\""); - ASSERT_THAT(v, IsStringEq("nix")); - } - - TEST_F(PrimOpTest, substringSmallerString){ - auto v = eval("builtins.substring 0 3 \"n\""); - ASSERT_THAT(v, IsStringEq("n")); - } - - TEST_F(PrimOpTest, substringEmptyString){ - auto v = eval("builtins.substring 1 3 \"\""); - ASSERT_THAT(v, IsStringEq("")); - } - - TEST_F(PrimOpTest, stringLength) { - auto v = eval("builtins.stringLength \"123\""); - ASSERT_THAT(v, IsIntEq(3)); - } - TEST_F(PrimOpTest, hashStringMd5) { - auto v = eval("builtins.hashString \"md5\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("912ec803b2ce49e4a541068d495ab570")); - } - - TEST_F(PrimOpTest, hashStringSha1) { - auto v = eval("builtins.hashString \"sha1\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("3da541559918a808c2402bba5012f6c60b27661c")); - } - - TEST_F(PrimOpTest, hashStringSha256) { - auto v = eval("builtins.hashString \"sha256\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b")); - } - - TEST_F(PrimOpTest, hashStringSha512) { - auto v = eval("builtins.hashString \"sha512\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1")); - } - - TEST_F(PrimOpTest, hashStringInvalidHashType) { - ASSERT_THROW(eval("builtins.hashString \"foobar\" \"asdf\""), Error); - } - - TEST_F(PrimOpTest, nixPath) { - auto v = eval("builtins.nixPath"); - ASSERT_EQ(v.type(), nList); - // We can't test much more as currently the EvalSettings are a global - // that we can't easily swap / replace - } - - TEST_F(PrimOpTest, langVersion) { - auto v = eval("builtins.langVersion"); - ASSERT_EQ(v.type(), nInt); - } - - TEST_F(PrimOpTest, storeDir) { - auto v = eval("builtins.storeDir"); - ASSERT_THAT(v, IsStringEq(settings.nixStore)); - } - - TEST_F(PrimOpTest, nixVersion) { - auto v = eval("builtins.nixVersion"); - ASSERT_THAT(v, IsStringEq(nixVersion)); - } - - TEST_F(PrimOpTest, currentSystem) { - auto v = eval("builtins.currentSystem"); - ASSERT_THAT(v, IsStringEq(settings.thisSystem.get())); - } - - TEST_F(PrimOpTest, derivation) { - auto v = eval("derivation"); - ASSERT_EQ(v.type(), nFunction); - ASSERT_TRUE(v.isLambda()); - ASSERT_NE(v.lambda.fun, nullptr); - ASSERT_TRUE(v.lambda.fun->hasFormals()); - } - - TEST_F(PrimOpTest, currentTime) { - auto v = eval("builtins.currentTime"); - ASSERT_EQ(v.type(), nInt); - ASSERT_TRUE(v.integer > 0); - } - - TEST_F(PrimOpTest, splitVersion) { - auto v = eval("builtins.splitVersion \"1.2.3git\""); - ASSERT_THAT(v, IsListOfSize(4)); - - const std::vector<std::string_view> strings = { "1", "2", "3", "git" }; - for (const auto [n, p] : enumerate(v.listItems())) - ASSERT_THAT(*p, IsStringEq(strings[n])); - } - - class CompareVersionsPrimOpTest : - public PrimOpTest, - public testing::WithParamInterface<std::tuple<std::string, const int>> - {}; - - TEST_P(CompareVersionsPrimOpTest, compareVersions) { - auto [expression, expectation] = GetParam(); - auto v = eval(expression); - ASSERT_THAT(v, IsIntEq(expectation)); - } - -#define CASE(a, b, expected) (std::make_tuple("builtins.compareVersions \"" #a "\" \"" #b "\"", expected)) - INSTANTIATE_TEST_SUITE_P( - compareVersions, - CompareVersionsPrimOpTest, - testing::Values( - // The first two are weird cases. Intuition tells they should - // be the same but they aren't. - CASE(1.0, 1.0.0, -1), - CASE(1.0.0, 1.0, 1), - // the following are from the nix-env manual: - CASE(1.0, 2.3, -1), - CASE(2.1, 2.3, -1), - CASE(2.3, 2.3, 0), - CASE(2.5, 2.3, 1), - CASE(3.1, 2.3, 1), - CASE(2.3.1, 2.3, 1), - CASE(2.3.1, 2.3a, 1), - CASE(2.3pre1, 2.3, -1), - CASE(2.3pre3, 2.3pre12, -1), - CASE(2.3a, 2.3c, -1), - CASE(2.3pre1, 2.3c, -1), - CASE(2.3pre1, 2.3q, -1) - ) - ); -#undef CASE - - - class ParseDrvNamePrimOpTest : - public PrimOpTest, - public testing::WithParamInterface<std::tuple<std::string, std::string_view, std::string_view>> - {}; - - TEST_P(ParseDrvNamePrimOpTest, parseDrvName) { - auto [input, expectedName, expectedVersion] = GetParam(); - const auto expr = fmt("builtins.parseDrvName \"%1%\"", input); - auto v = eval(expr); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto name = v.attrs->find(createSymbol("name")); - ASSERT_TRUE(name); - ASSERT_THAT(*name->value, IsStringEq(expectedName)); - - auto version = v.attrs->find(createSymbol("version")); - ASSERT_TRUE(version); - ASSERT_THAT(*version->value, IsStringEq(expectedVersion)); - } - - INSTANTIATE_TEST_SUITE_P( - parseDrvName, - ParseDrvNamePrimOpTest, - testing::Values( - std::make_tuple("nix-0.12pre12876", "nix", "0.12pre12876"), - std::make_tuple("a-b-c-1234pre5+git", "a-b-c", "1234pre5+git") - ) - ); - - TEST_F(PrimOpTest, replaceStrings) { - // FIXME: add a test that verifies the string context is as expected - auto v = eval("builtins.replaceStrings [\"oo\" \"a\"] [\"a\" \"i\"] \"foobar\""); - ASSERT_EQ(v.type(), nString); - ASSERT_EQ(v.string.s, std::string_view("fabir")); - } - - TEST_F(PrimOpTest, concatStringsSep) { - // FIXME: add a test that verifies the string context is as expected - auto v = eval("builtins.concatStringsSep \"%\" [\"foo\" \"bar\" \"baz\"]"); - ASSERT_EQ(v.type(), nString); - ASSERT_EQ(std::string_view(v.string.s), "foo%bar%baz"); - } - - TEST_F(PrimOpTest, split1) { - // v = [ "" [ "a" ] "c" ] - auto v = eval("builtins.split \"(a)b\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(3)); - - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); - - ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - - ASSERT_THAT(*v.listElems()[2], IsStringEq("c")); - } - - TEST_F(PrimOpTest, split2) { - // v is expected to be a list [ "" [ "a" ] "b" [ "c"] "" ] - auto v = eval("builtins.split \"([ac])\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(5)); - - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); - - ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - - ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); - - ASSERT_THAT(*v.listElems()[3], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsStringEq("c")); - - ASSERT_THAT(*v.listElems()[4], IsStringEq("")); - } - - TEST_F(PrimOpTest, split3) { - auto v = eval("builtins.split \"(a)|(c)\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(5)); - - // First list element - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); - - // 2nd list element is a list [ "" null ] - ASSERT_THAT(*v.listElems()[1], IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - ASSERT_THAT(*v.listElems()[1]->listElems()[1], IsNull()); - - // 3rd element - ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); - - // 4th element is a list: [ null "c" ] - ASSERT_THAT(*v.listElems()[3], IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsNull()); - ASSERT_THAT(*v.listElems()[3]->listElems()[1], IsStringEq("c")); - - // 5th element is the empty string - ASSERT_THAT(*v.listElems()[4], IsStringEq("")); - } - - TEST_F(PrimOpTest, split4) { - auto v = eval("builtins.split \"([[:upper:]]+)\" \" FOO \""); - ASSERT_THAT(v, IsListOfSize(3)); - auto first = v.listElems()[0]; - auto second = v.listElems()[1]; - auto third = v.listElems()[2]; - - ASSERT_THAT(*first, IsStringEq(" ")); - - ASSERT_THAT(*second, IsListOfSize(1)); - ASSERT_THAT(*second->listElems()[0], IsStringEq("FOO")); - - ASSERT_THAT(*third, IsStringEq(" ")); - } - - TEST_F(PrimOpTest, match1) { - auto v = eval("builtins.match \"ab\" \"abc\""); - ASSERT_THAT(v, IsNull()); - } - - TEST_F(PrimOpTest, match2) { - auto v = eval("builtins.match \"abc\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(0)); - } - - TEST_F(PrimOpTest, match3) { - auto v = eval("builtins.match \"a(b)(c)\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("b")); - ASSERT_THAT(*v.listElems()[1], IsStringEq("c")); - } - - TEST_F(PrimOpTest, match4) { - auto v = eval("builtins.match \"[[:space:]]+([[:upper:]]+)[[:space:]]+\" \" FOO \""); - ASSERT_THAT(v, IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO")); - } - - TEST_F(PrimOpTest, attrNames) { - auto v = eval("builtins.attrNames { x = 1; y = 2; z = 3; a = 2; }"); - ASSERT_THAT(v, IsListOfSize(4)); - - // ensure that the list is sorted - const std::vector<std::string_view> expected { "a", "x", "y", "z" }; - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsStringEq(expected[n])); - } - - TEST_F(PrimOpTest, genericClosure_not_strict) { - // Operator should not be used when startSet is empty - auto v = eval("builtins.genericClosure { startSet = []; }"); - ASSERT_THAT(v, IsListOfSize(0)); - } -} /* namespace nix */ diff --git a/src/libexpr/tests/search-path.cc b/src/libexpr/tests/search-path.cc deleted file mode 100644 index dbe7ab95f..000000000 --- a/src/libexpr/tests/search-path.cc +++ /dev/null @@ -1,90 +0,0 @@ -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -#include "search-path.hh" - -namespace nix { - -TEST(SearchPathElem, parse_justPath) { - ASSERT_EQ( - SearchPath::Elem::parse("foo"), - (SearchPath::Elem { - .prefix = SearchPath::Prefix { .s = "" }, - .path = SearchPath::Path { .s = "foo" }, - })); -} - -TEST(SearchPathElem, parse_emptyPrefix) { - ASSERT_EQ( - SearchPath::Elem::parse("=foo"), - (SearchPath::Elem { - .prefix = SearchPath::Prefix { .s = "" }, - .path = SearchPath::Path { .s = "foo" }, - })); -} - -TEST(SearchPathElem, parse_oneEq) { - ASSERT_EQ( - SearchPath::Elem::parse("foo=bar"), - (SearchPath::Elem { - .prefix = SearchPath::Prefix { .s = "foo" }, - .path = SearchPath::Path { .s = "bar" }, - })); -} - -TEST(SearchPathElem, parse_twoEqs) { - ASSERT_EQ( - SearchPath::Elem::parse("foo=bar=baz"), - (SearchPath::Elem { - .prefix = SearchPath::Prefix { .s = "foo" }, - .path = SearchPath::Path { .s = "bar=baz" }, - })); -} - - -TEST(SearchPathElem, suffixIfPotentialMatch_justPath) { - SearchPath::Prefix prefix { .s = "" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("any/thing"), std::optional { "any/thing" }); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_misleadingPrefix1) { - SearchPath::Prefix prefix { .s = "foo" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("fooX"), std::nullopt); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_misleadingPrefix2) { - SearchPath::Prefix prefix { .s = "foo" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("fooX/bar"), std::nullopt); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_partialPrefix) { - SearchPath::Prefix prefix { .s = "fooX" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("foo"), std::nullopt); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_exactPrefix) { - SearchPath::Prefix prefix { .s = "foo" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("foo"), std::optional { "" }); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_multiKey) { - SearchPath::Prefix prefix { .s = "foo/bar" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/bar/baz"), std::optional { "baz" }); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_trailingSlash) { - SearchPath::Prefix prefix { .s = "foo" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/"), std::optional { "" }); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_trailingDoubleSlash) { - SearchPath::Prefix prefix { .s = "foo" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("foo//"), std::optional { "/" }); -} - -TEST(SearchPathElem, suffixIfPotentialMatch_trailingPath) { - SearchPath::Prefix prefix { .s = "foo" }; - ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/bar/baz"), std::optional { "bar/baz" }); -} - -} diff --git a/src/libexpr/tests/trivial.cc b/src/libexpr/tests/trivial.cc deleted file mode 100644 index 171727ac7..000000000 --- a/src/libexpr/tests/trivial.cc +++ /dev/null @@ -1,196 +0,0 @@ -#include "tests/libexpr.hh" - -namespace nix { - // Testing of trivial expressions - class TrivialExpressionTest : public LibExprTest {}; - - TEST_F(TrivialExpressionTest, true) { - auto v = eval("true"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(TrivialExpressionTest, false) { - auto v = eval("false"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(TrivialExpressionTest, null) { - auto v = eval("null"); - ASSERT_THAT(v, IsNull()); - } - - TEST_F(TrivialExpressionTest, 1) { - auto v = eval("1"); - ASSERT_THAT(v, IsIntEq(1)); - } - - TEST_F(TrivialExpressionTest, 1plus1) { - auto v = eval("1+1"); - ASSERT_THAT(v, IsIntEq(2)); - } - - TEST_F(TrivialExpressionTest, minus1) { - auto v = eval("-1"); - ASSERT_THAT(v, IsIntEq(-1)); - } - - TEST_F(TrivialExpressionTest, 1minus1) { - auto v = eval("1-1"); - ASSERT_THAT(v, IsIntEq(0)); - } - - TEST_F(TrivialExpressionTest, lambdaAdd) { - auto v = eval("let add = a: b: a + b; in add 1 2"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(TrivialExpressionTest, list) { - auto v = eval("[]"); - ASSERT_THAT(v, IsListOfSize(0)); - } - - TEST_F(TrivialExpressionTest, attrs) { - auto v = eval("{}"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(TrivialExpressionTest, float) { - auto v = eval("1.234"); - ASSERT_THAT(v, IsFloatEq(1.234)); - } - - TEST_F(TrivialExpressionTest, updateAttrs) { - auto v = eval("{ a = 1; } // { b = 2; a = 3; }"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - auto a = v.attrs->find(createSymbol("a")); - ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsIntEq(3)); - - auto b = v.attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(2)); - } - - TEST_F(TrivialExpressionTest, hasAttrOpFalse) { - auto v = eval("{} ? a"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(TrivialExpressionTest, hasAttrOpTrue) { - auto v = eval("{ a = 123; } ? a"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(TrivialExpressionTest, withFound) { - auto v = eval("with { a = 23; }; a"); - ASSERT_THAT(v, IsIntEq(23)); - } - - TEST_F(TrivialExpressionTest, withNotFound) { - ASSERT_THROW(eval("with {}; a"), Error); - } - - TEST_F(TrivialExpressionTest, withOverride) { - auto v = eval("with { a = 23; }; with { a = 42; }; a"); - ASSERT_THAT(v, IsIntEq(42)); - } - - TEST_F(TrivialExpressionTest, letOverWith) { - auto v = eval("let a = 23; in with { a = 1; }; a"); - ASSERT_THAT(v, IsIntEq(23)); - } - - TEST_F(TrivialExpressionTest, multipleLet) { - auto v = eval("let a = 23; in let a = 42; in a"); - ASSERT_THAT(v, IsIntEq(42)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgs) { - auto v = eval("({ a ? 123 }: a) {}"); - ASSERT_THAT(v, IsIntEq(123)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgsOverride) { - auto v = eval("({ a ? 123 }: a) { a = 5; }"); - ASSERT_THAT(v, IsIntEq(5)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureBack) { - auto v = eval("({ a ? 123 }@args: args) {}"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureFront) { - auto v = eval("(args@{ a ? 123 }: args) {}"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(TrivialExpressionTest, assertThrows) { - ASSERT_THROW(eval("let x = arg: assert arg == 1; 123; in x 2"), Error); - } - - TEST_F(TrivialExpressionTest, assertPassed) { - auto v = eval("let x = arg: assert arg == 1; 123; in x 1"); - ASSERT_THAT(v, IsIntEq(123)); - } - - class AttrSetMergeTrvialExpressionTest : - public TrivialExpressionTest, - public testing::WithParamInterface<const char*> - {}; - - TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy) { - // Usually Nix rejects duplicate keys in an attrset but it does allow - // so if it is an attribute set that contains disjoint sets of keys. - // The below is equivalent to `{a.b = 1; a.c = 2; }`. - // The attribute set `a` will be a Thunk at first as the attribuets - // have to be merged (or otherwise computed) and that is done in a lazy - // manner. - - auto expr = GetParam(); - auto v = eval(expr); - ASSERT_THAT(v, IsAttrsOfSize(1)); - - auto a = v.attrs->find(createSymbol("a")); - ASSERT_NE(a, nullptr); - - ASSERT_THAT(*a->value, IsThunk()); - state.forceValue(*a->value, noPos); - - ASSERT_THAT(*a->value, IsAttrsOfSize(2)); - - auto b = a->value->attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(1)); - - auto c = a->value->attrs->find(createSymbol("c")); - ASSERT_NE(c, nullptr); - ASSERT_THAT(*c->value, IsIntEq(2)); - } - - INSTANTIATE_TEST_SUITE_P( - attrsetMergeLazy, - AttrSetMergeTrvialExpressionTest, - testing::Values( - "{ a.b = 1; a.c = 2; }", - "{ a = { b = 1; }; a = { c = 2; }; }" - ) - ); - - TEST_F(TrivialExpressionTest, functor) { - auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5"); - ASSERT_THAT(v, IsIntEq(15)); - } - - TEST_F(TrivialExpressionTest, bindOr) { - auto v = eval("{ or = 1; }"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - auto b = v.attrs->find(createSymbol("or")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(1)); - } - - TEST_F(TrivialExpressionTest, orCantBeUsed) { - ASSERT_THROW(eval("let or = 1; in or"), Error); - } -} /* namespace nix */ diff --git a/src/libexpr/tests/value/context.cc b/src/libexpr/tests/value/context.cc deleted file mode 100644 index 92d4889ab..000000000 --- a/src/libexpr/tests/value/context.cc +++ /dev/null @@ -1,162 +0,0 @@ -#include <nlohmann/json.hpp> -#include <gtest/gtest.h> -#include <rapidcheck/gtest.h> - -#include "tests/path.hh" -#include "tests/libexpr.hh" -#include "tests/value/context.hh" - -namespace nix { - -// Test a few cases of invalid string context elements. - -TEST(NixStringContextElemTest, empty_invalid) { - EXPECT_THROW( - NixStringContextElem::parse(""), - BadNixStringContextElem); -} - -TEST(NixStringContextElemTest, single_bang_invalid) { - EXPECT_THROW( - NixStringContextElem::parse("!"), - BadNixStringContextElem); -} - -TEST(NixStringContextElemTest, double_bang_invalid) { - EXPECT_THROW( - NixStringContextElem::parse("!!/"), - BadStorePath); -} - -TEST(NixStringContextElemTest, eq_slash_invalid) { - EXPECT_THROW( - NixStringContextElem::parse("=/"), - BadStorePath); -} - -TEST(NixStringContextElemTest, slash_invalid) { - EXPECT_THROW( - NixStringContextElem::parse("/"), - BadStorePath); -} - -/** - * Round trip (string <-> data structure) test for - * `NixStringContextElem::Opaque`. - */ -TEST(NixStringContextElemTest, opaque) { - std::string_view opaque = "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x"; - auto elem = NixStringContextElem::parse(opaque); - auto * p = std::get_if<NixStringContextElem::Opaque>(&elem.raw); - ASSERT_TRUE(p); - ASSERT_EQ(p->path, StorePath { opaque }); - ASSERT_EQ(elem.to_string(), opaque); -} - -/** - * Round trip (string <-> data structure) test for - * `NixStringContextElem::DrvDeep`. - */ -TEST(NixStringContextElemTest, drvDeep) { - std::string_view drvDeep = "=g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv"; - auto elem = NixStringContextElem::parse(drvDeep); - auto * p = std::get_if<NixStringContextElem::DrvDeep>(&elem.raw); - ASSERT_TRUE(p); - ASSERT_EQ(p->drvPath, StorePath { drvDeep.substr(1) }); - ASSERT_EQ(elem.to_string(), drvDeep); -} - -/** - * Round trip (string <-> data structure) test for a simpler - * `NixStringContextElem::Built`. - */ -TEST(NixStringContextElemTest, built_opaque) { - std::string_view built = "!foo!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv"; - auto elem = NixStringContextElem::parse(built); - auto * p = std::get_if<NixStringContextElem::Built>(&elem.raw); - ASSERT_TRUE(p); - ASSERT_EQ(p->output, "foo"); - ASSERT_EQ(*p->drvPath, ((SingleDerivedPath) SingleDerivedPath::Opaque { - .path = StorePath { built.substr(5) }, - })); - ASSERT_EQ(elem.to_string(), built); -} - -/** - * Round trip (string <-> data structure) test for a more complex, - * inductive `NixStringContextElem::Built`. - */ -TEST(NixStringContextElemTest, built_built) { - /** - * We set these in tests rather than the regular globals so we don't have - * to worry about race conditions if the tests run concurrently. - */ - ExperimentalFeatureSettings mockXpSettings; - mockXpSettings.set("experimental-features", "dynamic-derivations ca-derivations"); - - std::string_view built = "!foo!bar!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv"; - auto elem = NixStringContextElem::parse(built, mockXpSettings); - auto * p = std::get_if<NixStringContextElem::Built>(&elem.raw); - ASSERT_TRUE(p); - ASSERT_EQ(p->output, "foo"); - auto * drvPath = std::get_if<SingleDerivedPath::Built>(&*p->drvPath); - ASSERT_TRUE(drvPath); - ASSERT_EQ(drvPath->output, "bar"); - ASSERT_EQ(*drvPath->drvPath, ((SingleDerivedPath) SingleDerivedPath::Opaque { - .path = StorePath { built.substr(9) }, - })); - ASSERT_EQ(elem.to_string(), built); -} - -/** - * Without the right experimental features enabled, we cannot parse a - * complex inductive string context element. - */ -TEST(NixStringContextElemTest, built_built_xp) { - ASSERT_THROW( - NixStringContextElem::parse("!foo!bar!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv"), MissingExperimentalFeature); -} - -} - -namespace rc { -using namespace nix; - -Gen<NixStringContextElem::DrvDeep> Arbitrary<NixStringContextElem::DrvDeep>::arbitrary() -{ - return gen::just(NixStringContextElem::DrvDeep { - .drvPath = *gen::arbitrary<StorePath>(), - }); -} - -Gen<NixStringContextElem> Arbitrary<NixStringContextElem>::arbitrary() -{ - switch (*gen::inRange<uint8_t>(0, std::variant_size_v<NixStringContextElem::Raw>)) { - case 0: - return gen::just<NixStringContextElem>(*gen::arbitrary<NixStringContextElem::Opaque>()); - case 1: - return gen::just<NixStringContextElem>(*gen::arbitrary<NixStringContextElem::DrvDeep>()); - case 2: - return gen::just<NixStringContextElem>(*gen::arbitrary<NixStringContextElem::Built>()); - default: - assert(false); - } -} - -} - -namespace nix { - -#ifndef COVERAGE - -RC_GTEST_PROP( - NixStringContextElemTest, - prop_round_rip, - (const NixStringContextElem & o)) -{ - RC_ASSERT(o == NixStringContextElem::parse(o.to_string())); -} - -#endif - -} diff --git a/src/libexpr/tests/value/context.hh b/src/libexpr/tests/value/context.hh deleted file mode 100644 index c0bc97ba3..000000000 --- a/src/libexpr/tests/value/context.hh +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -///@file - -#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(); -}; - -} diff --git a/src/libexpr/tests/value/print.cc b/src/libexpr/tests/value/print.cc deleted file mode 100644 index 5e96e12ec..000000000 --- a/src/libexpr/tests/value/print.cc +++ /dev/null @@ -1,236 +0,0 @@ -#include "tests/libexpr.hh" - -#include "value.hh" - -namespace nix { - -using namespace testing; - -struct ValuePrintingTests : LibExprTest -{ - template<class... A> - void test(Value v, std::string_view expected, A... args) - { - std::stringstream out; - v.print(state.symbols, out, args...); - ASSERT_EQ(out.str(), expected); - } -}; - -TEST_F(ValuePrintingTests, tInt) -{ - Value vInt; - vInt.mkInt(10); - test(vInt, "10"); -} - -TEST_F(ValuePrintingTests, tBool) -{ - Value vBool; - vBool.mkBool(true); - test(vBool, "true"); -} - -TEST_F(ValuePrintingTests, tString) -{ - Value vString; - vString.mkString("some-string"); - test(vString, "\"some-string\""); -} - -TEST_F(ValuePrintingTests, tPath) -{ - Value vPath; - vPath.mkString("/foo"); - test(vPath, "\"/foo\""); -} - -TEST_F(ValuePrintingTests, tNull) -{ - Value vNull; - vNull.mkNull(); - test(vNull, "null"); -} - -TEST_F(ValuePrintingTests, tAttrs) -{ - Value vOne; - vOne.mkInt(1); - - Value vTwo; - vTwo.mkInt(2); - - BindingsBuilder builder(state, state.allocBindings(10)); - builder.insert(state.symbols.create("one"), &vOne); - builder.insert(state.symbols.create("two"), &vTwo); - - Value vAttrs; - vAttrs.mkAttrs(builder.finish()); - - test(vAttrs, "{ one = 1; two = 2; }"); -} - -TEST_F(ValuePrintingTests, tList) -{ - Value vOne; - vOne.mkInt(1); - - Value vTwo; - vTwo.mkInt(2); - - Value vList; - state.mkList(vList, 5); - vList.bigList.elems[0] = &vOne; - vList.bigList.elems[1] = &vTwo; - vList.bigList.size = 3; - - test(vList, "[ 1 2 (nullptr) ]"); -} - -TEST_F(ValuePrintingTests, vThunk) -{ - Value vThunk; - vThunk.mkThunk(nullptr, nullptr); - - test(vThunk, "<CODE>"); -} - -TEST_F(ValuePrintingTests, vApp) -{ - Value vApp; - vApp.mkApp(nullptr, nullptr); - - test(vApp, "<CODE>"); -} - -TEST_F(ValuePrintingTests, vLambda) -{ - Value vLambda; - vLambda.mkLambda(nullptr, nullptr); - - test(vLambda, "<LAMBDA>"); -} - -TEST_F(ValuePrintingTests, vPrimOp) -{ - Value vPrimOp; - vPrimOp.mkPrimOp(nullptr); - - test(vPrimOp, "<PRIMOP>"); -} - -TEST_F(ValuePrintingTests, vPrimOpApp) -{ - Value vPrimOpApp; - vPrimOpApp.mkPrimOpApp(nullptr, nullptr); - - test(vPrimOpApp, "<PRIMOP-APP>"); -} - -TEST_F(ValuePrintingTests, vExternal) -{ - struct MyExternal : ExternalValueBase - { - public: - std::string showType() const override - { - return ""; - } - std::string typeOf() const override - { - return ""; - } - virtual std::ostream & print(std::ostream & str) const override - { - str << "testing-external!"; - return str; - } - } myExternal; - Value vExternal; - vExternal.mkExternal(&myExternal); - - test(vExternal, "testing-external!"); -} - -TEST_F(ValuePrintingTests, vFloat) -{ - Value vFloat; - vFloat.mkFloat(2.0); - - test(vFloat, "2"); -} - -TEST_F(ValuePrintingTests, vBlackhole) -{ - Value vBlackhole; - vBlackhole.mkBlackhole(); - test(vBlackhole, "«potential infinite recursion»"); -} - -TEST_F(ValuePrintingTests, depthAttrs) -{ - Value vOne; - vOne.mkInt(1); - - Value vTwo; - vTwo.mkInt(2); - - BindingsBuilder builder(state, state.allocBindings(10)); - builder.insert(state.symbols.create("one"), &vOne); - builder.insert(state.symbols.create("two"), &vTwo); - - Value vAttrs; - vAttrs.mkAttrs(builder.finish()); - - BindingsBuilder builder2(state, state.allocBindings(10)); - builder2.insert(state.symbols.create("one"), &vOne); - builder2.insert(state.symbols.create("two"), &vTwo); - builder2.insert(state.symbols.create("nested"), &vAttrs); - - Value vNested; - vNested.mkAttrs(builder2.finish()); - - test(vNested, "{ nested = «too deep»; one = «too deep»; two = «too deep»; }", false, 1); - test(vNested, "{ nested = { one = «too deep»; two = «too deep»; }; one = 1; two = 2; }", false, 2); - test(vNested, "{ nested = { one = 1; two = 2; }; one = 1; two = 2; }", false, 3); - test(vNested, "{ nested = { one = 1; two = 2; }; one = 1; two = 2; }", false, 4); -} - -TEST_F(ValuePrintingTests, depthList) -{ - Value vOne; - vOne.mkInt(1); - - Value vTwo; - vTwo.mkInt(2); - - BindingsBuilder builder(state, state.allocBindings(10)); - builder.insert(state.symbols.create("one"), &vOne); - builder.insert(state.symbols.create("two"), &vTwo); - - Value vAttrs; - vAttrs.mkAttrs(builder.finish()); - - BindingsBuilder builder2(state, state.allocBindings(10)); - builder2.insert(state.symbols.create("one"), &vOne); - builder2.insert(state.symbols.create("two"), &vTwo); - builder2.insert(state.symbols.create("nested"), &vAttrs); - - Value vNested; - vNested.mkAttrs(builder2.finish()); - - Value vList; - state.mkList(vList, 5); - vList.bigList.elems[0] = &vOne; - vList.bigList.elems[1] = &vTwo; - vList.bigList.elems[2] = &vNested; - vList.bigList.size = 3; - - test(vList, "[ «too deep» «too deep» «too deep» ]", false, 1); - test(vList, "[ 1 2 { nested = «too deep»; one = «too deep»; two = «too deep»; } ]", false, 2); - test(vList, "[ 1 2 { nested = { one = «too deep»; two = «too deep»; }; one = 1; two = 2; } ]", false, 3); - test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", false, 4); - test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", false, 5); -} - -} // namespace nix diff --git a/src/libstore/build/create-derivation-and-realise-goal.cc b/src/libstore/build/create-derivation-and-realise-goal.cc deleted file mode 100644 index 60f67956d..000000000 --- a/src/libstore/build/create-derivation-and-realise-goal.cc +++ /dev/null @@ -1,157 +0,0 @@ -#include "create-derivation-and-realise-goal.hh" -#include "worker.hh" - -namespace nix { - -CreateDerivationAndRealiseGoal::CreateDerivationAndRealiseGoal(ref<SingleDerivedPath> drvReq, - const OutputsSpec & wantedOutputs, Worker & worker, BuildMode buildMode) - : Goal(worker, DerivedPath::Built { .drvPath = drvReq, .outputs = wantedOutputs }) - , drvReq(drvReq) - , wantedOutputs(wantedOutputs) - , buildMode(buildMode) -{ - state = &CreateDerivationAndRealiseGoal::getDerivation; - name = fmt( - "outer obtaining drv from '%s' and then building outputs %s", - drvReq->to_string(worker.store), - std::visit(overloaded { - [&](const OutputsSpec::All) -> std::string { - return "* (all of them)"; - }, - [&](const OutputsSpec::Names os) { - return concatStringsSep(", ", quoteStrings(os)); - }, - }, wantedOutputs.raw)); - trace("created outer"); - - worker.updateProgress(); -} - - -CreateDerivationAndRealiseGoal::~CreateDerivationAndRealiseGoal() -{ -} - - -static StorePath pathPartOfReq(const SingleDerivedPath & req) -{ - return std::visit(overloaded { - [&](const SingleDerivedPath::Opaque & bo) { - return bo.path; - }, - [&](const SingleDerivedPath::Built & bfd) { - return pathPartOfReq(*bfd.drvPath); - }, - }, req.raw()); -} - - -std::string CreateDerivationAndRealiseGoal::key() -{ - /* Ensure that derivations get built in order of their name, - i.e. a derivation named "aardvark" always comes before "baboon". And - substitution goals and inner derivation goals always happen before - derivation goals (due to "b$"). */ - return "c$" + std::string(pathPartOfReq(*drvReq).name()) + "$" + drvReq->to_string(worker.store); -} - - -void CreateDerivationAndRealiseGoal::timedOut(Error && ex) -{ -} - - -void CreateDerivationAndRealiseGoal::work() -{ - (this->*state)(); -} - - -void CreateDerivationAndRealiseGoal::addWantedOutputs(const OutputsSpec & outputs) -{ - /* If we already want all outputs, there is nothing to do. */ - auto newWanted = wantedOutputs.union_(outputs); - bool needRestart = !newWanted.isSubsetOf(wantedOutputs); - wantedOutputs = newWanted; - - if (!needRestart) return; - - if (!optDrvPath) - // haven't started steps where the outputs matter yet - return; - worker.makeDerivationGoal(*optDrvPath, outputs, buildMode); -} - - -void CreateDerivationAndRealiseGoal::getDerivation() -{ - trace("outer init"); - - /* The first thing to do is to make sure that the derivation - exists. If it doesn't, it may be created through a - substitute. */ - if (auto optDrvPath = [this]() -> std::optional<StorePath> { - if (buildMode != bmNormal) return std::nullopt; - - auto drvPath = StorePath::dummy; - try { - drvPath = resolveDerivedPath(worker.store, *drvReq); - } catch (MissingRealisation &) { - return std::nullopt; - } - return worker.evalStore.isValidPath(drvPath) || worker.store.isValidPath(drvPath) - ? std::optional { drvPath } - : std::nullopt; - }()) { - trace(fmt("already have drv '%s' for '%s', can go straight to building", - worker.store.printStorePath(*optDrvPath), - drvReq->to_string(worker.store))); - - loadAndBuildDerivation(); - } else { - trace("need to obtain drv we want to build"); - - addWaitee(worker.makeGoal(DerivedPath::fromSingle(*drvReq))); - - state = &CreateDerivationAndRealiseGoal::loadAndBuildDerivation; - if (waitees.empty()) work(); - } -} - - -void CreateDerivationAndRealiseGoal::loadAndBuildDerivation() -{ - trace("outer load and build derivation"); - - if (nrFailed != 0) { - amDone(ecFailed, Error("cannot build missing derivation '%s'", drvReq->to_string(worker.store))); - return; - } - - StorePath drvPath = resolveDerivedPath(worker.store, *drvReq); - /* Build this step! */ - concreteDrvGoal = worker.makeDerivationGoal(drvPath, wantedOutputs, buildMode); - addWaitee(upcast_goal(concreteDrvGoal)); - state = &CreateDerivationAndRealiseGoal::buildDone; - optDrvPath = std::move(drvPath); - if (waitees.empty()) work(); -} - - -void CreateDerivationAndRealiseGoal::buildDone() -{ - trace("outer build done"); - - buildResult = upcast_goal(concreteDrvGoal)->getBuildResult(DerivedPath::Built { - .drvPath = drvReq, - .outputs = wantedOutputs, - }); - - if (buildResult.success()) - amDone(ecSuccess); - else - amDone(ecFailed, Error("building '%s' failed", drvReq->to_string(worker.store))); -} - - -} diff --git a/src/libstore/build/create-derivation-and-realise-goal.hh b/src/libstore/build/create-derivation-and-realise-goal.hh deleted file mode 100644 index ca936fc95..000000000 --- a/src/libstore/build/create-derivation-and-realise-goal.hh +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "parsed-derivations.hh" -#include "lock.hh" -#include "store-api.hh" -#include "pathlocks.hh" -#include "goal.hh" - -namespace nix { - -struct DerivationGoal; - -/** - * This goal type is essentially the serial composition (like function - * composition) of a goal for getting a derivation, and then a - * `DerivationGoal` using the newly-obtained derivation. - * - * In the (currently experimental) general inductive case of derivations - * that are themselves build outputs, that first goal will be *another* - * `CreateDerivationAndRealiseGoal`. In the (much more common) base-case - * where the derivation has no provence and is just referred to by - * (content-addressed) store path, that first goal is a - * `SubstitutionGoal`. - * - * If we already have the derivation (e.g. if the evalutator has created - * the derivation locally and then instructured the store to build it), - * we can skip the first goal entirely as a small optimization. - */ -struct CreateDerivationAndRealiseGoal : public Goal -{ - /** - * How to obtain a store path of the derivation to build. - */ - ref<SingleDerivedPath> drvReq; - - /** - * The path of the derivation, once obtained. - **/ - std::optional<StorePath> optDrvPath; - - /** - * The goal for the corresponding concrete derivation. - **/ - std::shared_ptr<DerivationGoal> concreteDrvGoal; - - /** - * The specific outputs that we need to build. - */ - OutputsSpec wantedOutputs; - - typedef void (CreateDerivationAndRealiseGoal::*GoalState)(); - GoalState state; - - /** - * The final output paths of the build. - * - * - For input-addressed derivations, always the precomputed paths - * - * - For content-addressed derivations, calcuated from whatever the - * hash ends up being. (Note that fixed outputs derivations that - * produce the "wrong" output still install that data under its - * true content-address.) - */ - OutputPathMap finalOutputs; - - BuildMode buildMode; - - CreateDerivationAndRealiseGoal(ref<SingleDerivedPath> drvReq, - const OutputsSpec & wantedOutputs, Worker & worker, - BuildMode buildMode = bmNormal); - virtual ~CreateDerivationAndRealiseGoal(); - - void timedOut(Error && ex) override; - - std::string key() override; - - void work() override; - - /** - * Add wanted outputs to an already existing derivation goal. - */ - void addWantedOutputs(const OutputsSpec & outputs); - - /** - * The states. - */ - void getDerivation(); - void loadAndBuildDerivation(); - void buildDone(); - - JobCategory jobCategory() const override { - return JobCategory::Administration; - }; -}; - -} diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 6472ecd99..83c0a3135 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -71,7 +71,7 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, , wantedOutputs(wantedOutputs) , buildMode(buildMode) { - state = &DerivationGoal::loadDerivation; + state = &DerivationGoal::getDerivation; name = fmt( "building of '%s' from .drv file", DerivedPath::Built { makeConstantStorePathRef(drvPath), wantedOutputs }.to_string(worker.store)); @@ -164,6 +164,24 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs) } +void DerivationGoal::getDerivation() +{ + trace("init"); + + /* The first thing to do is to make sure that the derivation + exists. If it doesn't, it may be created through a + substitute. */ + if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) { + loadDerivation(); + return; + } + + addWaitee(upcast_goal(worker.makePathSubstitutionGoal(drvPath))); + + state = &DerivationGoal::loadDerivation; +} + + void DerivationGoal::loadDerivation() { trace("loading derivation"); @@ -1498,24 +1516,23 @@ void DerivationGoal::waiteeDone(GoalPtr waitee, ExitCode result) if (!useDerivation) return; auto & fullDrv = *dynamic_cast<Derivation *>(drv.get()); - std::optional info = tryGetConcreteDrvGoal(waitee); - if (!info) return; - const auto & [dg, drvReq] = *info; + auto * dg = dynamic_cast<DerivationGoal *>(&*waitee); + if (!dg) return; - auto * nodeP = fullDrv.inputDrvs.findSlot(drvReq.get()); + auto * nodeP = fullDrv.inputDrvs.findSlot(DerivedPath::Opaque { .path = dg->drvPath }); if (!nodeP) return; auto & outputs = nodeP->value; for (auto & outputName : outputs) { - auto buildResult = dg.get().getBuildResult(DerivedPath::Built { - .drvPath = makeConstantStorePathRef(dg.get().drvPath), + auto buildResult = dg->getBuildResult(DerivedPath::Built { + .drvPath = makeConstantStorePathRef(dg->drvPath), .outputs = OutputsSpec::Names { outputName }, }); if (buildResult.success()) { auto i = buildResult.builtOutputs.find(outputName); if (i != buildResult.builtOutputs.end()) inputDrvOutputs.insert_or_assign( - { dg.get().drvPath, outputName }, + { dg->drvPath, outputName }, i->second.outPath); } } diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh index 62b122c27..ddb5ee1e3 100644 --- a/src/libstore/build/derivation-goal.hh +++ b/src/libstore/build/derivation-goal.hh @@ -52,10 +52,6 @@ struct InitialOutput { /** * A goal for building some or all of the outputs of a derivation. - * - * The derivation must already be present, either in the store in a drv - * or in memory. If the derivation itself needs to be gotten first, a - * `CreateDerivationAndRealiseGoal` goal must be used instead. */ struct DerivationGoal : public Goal { @@ -235,6 +231,7 @@ struct DerivationGoal : public Goal /** * The states. */ + void getDerivation(); void loadDerivation(); void haveDerivation(); void outputsSubstitutionTried(); diff --git a/src/libstore/build/entry-points.cc b/src/libstore/build/entry-points.cc index f0f0e5519..13ff22f45 100644 --- a/src/libstore/build/entry-points.cc +++ b/src/libstore/build/entry-points.cc @@ -1,6 +1,5 @@ #include "worker.hh" #include "substitution-goal.hh" -#include "create-derivation-and-realise-goal.hh" #include "derivation-goal.hh" #include "local-store.hh" @@ -16,7 +15,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod worker.run(goals); - StringSet failed; + StorePathSet failed; std::optional<Error> ex; for (auto & i : goals) { if (i->ex) { @@ -26,10 +25,10 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod ex = std::move(i->ex); } if (i->exitCode != Goal::ecSuccess) { - if (auto i2 = dynamic_cast<CreateDerivationAndRealiseGoal *>(i.get())) - failed.insert(i2->drvReq->to_string(*this)); + if (auto i2 = dynamic_cast<DerivationGoal *>(i.get())) + failed.insert(i2->drvPath); else if (auto i2 = dynamic_cast<PathSubstitutionGoal *>(i.get())) - failed.insert(printStorePath(i2->storePath)); + failed.insert(i2->storePath); } } @@ -38,7 +37,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod throw std::move(*ex); } else if (!failed.empty()) { if (ex) logError(ex->info()); - throw Error(worker.failingExitStatus(), "build of %s failed", concatStringsSep(", ", quoteStrings(failed))); + throw Error(worker.failingExitStatus(), "build of %s failed", showPaths(failed)); } } diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh index 01d3c3491..9af083230 100644 --- a/src/libstore/build/goal.hh +++ b/src/libstore/build/goal.hh @@ -49,16 +49,6 @@ enum struct JobCategory { * A substitution an arbitrary store object; it will use network resources. */ Substitution, - /** - * A goal that does no "real" work by itself, and just exists to depend on - * other goals which *do* do real work. These goals therefore are not - * limited. - * - * These goals cannot infinitely create themselves, so there is no risk of - * a "fork bomb" type situation (which would be a problem even though the - * goal do no real work) either. - */ - Administration, }; struct Goal : public std::enable_shared_from_this<Goal> diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc index b4a634e7b..37cb86b91 100644 --- a/src/libstore/build/worker.cc +++ b/src/libstore/build/worker.cc @@ -2,7 +2,6 @@ #include "worker.hh" #include "substitution-goal.hh" #include "drv-output-substitution-goal.hh" -#include "create-derivation-and-realise-goal.hh" #include "local-derivation-goal.hh" #include "hook-instance.hh" @@ -42,24 +41,6 @@ Worker::~Worker() } -std::shared_ptr<CreateDerivationAndRealiseGoal> Worker::makeCreateDerivationAndRealiseGoal( - ref<SingleDerivedPath> drvReq, - const OutputsSpec & wantedOutputs, - BuildMode buildMode) -{ - std::weak_ptr<CreateDerivationAndRealiseGoal> & goal_weak = outerDerivationGoals.ensureSlot(*drvReq).value; - std::shared_ptr<CreateDerivationAndRealiseGoal> goal = goal_weak.lock(); - if (!goal) { - goal = std::make_shared<CreateDerivationAndRealiseGoal>(drvReq, wantedOutputs, *this, buildMode); - goal_weak = goal; - wakeUp(goal); - } else { - goal->addWantedOutputs(wantedOutputs); - } - return goal; -} - - std::shared_ptr<DerivationGoal> Worker::makeDerivationGoalCommon( const StorePath & drvPath, const OutputsSpec & wantedOutputs, @@ -130,7 +111,10 @@ GoalPtr Worker::makeGoal(const DerivedPath & req, BuildMode buildMode) { return std::visit(overloaded { [&](const DerivedPath::Built & bfd) -> GoalPtr { - return makeCreateDerivationAndRealiseGoal(bfd.drvPath, bfd.outputs, buildMode); + if (auto bop = std::get_if<DerivedPath::Opaque>(&*bfd.drvPath)) + return makeDerivationGoal(bop->path, bfd.outputs, buildMode); + else + throw UnimplementedError("Building dynamic derivations in one shot is not yet implemented."); }, [&](const DerivedPath::Opaque & bo) -> GoalPtr { return makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair); @@ -139,46 +123,24 @@ GoalPtr Worker::makeGoal(const DerivedPath & req, BuildMode buildMode) } -template<typename K, typename V, typename F> -static void cullMap(std::map<K, V> & goalMap, F f) -{ - for (auto i = goalMap.begin(); i != goalMap.end();) - if (!f(i->second)) - i = goalMap.erase(i); - else ++i; -} - - template<typename K, typename G> static void removeGoal(std::shared_ptr<G> goal, std::map<K, std::weak_ptr<G>> & goalMap) { /* !!! inefficient */ - cullMap(goalMap, [&](const std::weak_ptr<G> & gp) -> bool { - return gp.lock() != goal; - }); -} - -template<typename K> -static void removeGoal(std::shared_ptr<CreateDerivationAndRealiseGoal> goal, std::map<K, DerivedPathMap<std::weak_ptr<CreateDerivationAndRealiseGoal>>::ChildNode> & goalMap); - -template<typename K> -static void removeGoal(std::shared_ptr<CreateDerivationAndRealiseGoal> goal, std::map<K, DerivedPathMap<std::weak_ptr<CreateDerivationAndRealiseGoal>>::ChildNode> & goalMap) -{ - /* !!! inefficient */ - cullMap(goalMap, [&](DerivedPathMap<std::weak_ptr<CreateDerivationAndRealiseGoal>>::ChildNode & node) -> bool { - if (node.value.lock() == goal) - node.value.reset(); - removeGoal(goal, node.childMap); - return !node.value.expired() || !node.childMap.empty(); - }); + for (auto i = goalMap.begin(); + i != goalMap.end(); ) + if (i->second.lock() == goal) { + auto j = i; ++j; + goalMap.erase(i); + i = j; + } + else ++i; } void Worker::removeGoal(GoalPtr goal) { - if (auto drvGoal = std::dynamic_pointer_cast<CreateDerivationAndRealiseGoal>(goal)) - nix::removeGoal(drvGoal, outerDerivationGoals.map); - else if (auto drvGoal = std::dynamic_pointer_cast<DerivationGoal>(goal)) + if (auto drvGoal = std::dynamic_pointer_cast<DerivationGoal>(goal)) nix::removeGoal(drvGoal, derivationGoals); else if (auto subGoal = std::dynamic_pointer_cast<PathSubstitutionGoal>(goal)) nix::removeGoal(subGoal, substitutionGoals); @@ -236,19 +198,8 @@ void Worker::childStarted(GoalPtr goal, const std::set<int> & fds, child.respectTimeouts = respectTimeouts; children.emplace_back(child); if (inBuildSlot) { - switch (goal->jobCategory()) { - case JobCategory::Substitution: - nrSubstitutions++; - break; - case JobCategory::Build: - nrLocalBuilds++; - break; - case JobCategory::Administration: - /* Intentionally not limited, see docs */ - break; - default: - abort(); - } + if (goal->jobCategory() == JobCategory::Substitution) nrSubstitutions++; + else nrLocalBuilds++; } } @@ -260,20 +211,12 @@ void Worker::childTerminated(Goal * goal, bool wakeSleepers) if (i == children.end()) return; if (i->inBuildSlot) { - switch (goal->jobCategory()) { - case JobCategory::Substitution: + if (goal->jobCategory() == JobCategory::Substitution) { assert(nrSubstitutions > 0); nrSubstitutions--; - break; - case JobCategory::Build: + } else { assert(nrLocalBuilds > 0); nrLocalBuilds--; - break; - case JobCategory::Administration: - /* Intentionally not limited, see docs */ - break; - default: - abort(); } } @@ -324,9 +267,9 @@ void Worker::run(const Goals & _topGoals) for (auto & i : _topGoals) { topGoals.insert(i); - if (auto goal = dynamic_cast<CreateDerivationAndRealiseGoal *>(i.get())) { + if (auto goal = dynamic_cast<DerivationGoal *>(i.get())) { topPaths.push_back(DerivedPath::Built { - .drvPath = goal->drvReq, + .drvPath = makeConstantStorePathRef(goal->drvPath), .outputs = goal->wantedOutputs, }); } else if (auto goal = dynamic_cast<PathSubstitutionGoal *>(i.get())) { @@ -589,19 +532,4 @@ GoalPtr upcast_goal(std::shared_ptr<DrvOutputSubstitutionGoal> subGoal) return subGoal; } -GoalPtr upcast_goal(std::shared_ptr<DerivationGoal> subGoal) -{ - return subGoal; -} - -std::optional<std::pair<std::reference_wrapper<const DerivationGoal>, std::reference_wrapper<const SingleDerivedPath>>> tryGetConcreteDrvGoal(GoalPtr waitee) -{ - auto * odg = dynamic_cast<CreateDerivationAndRealiseGoal *>(&*waitee); - if (!odg) return std::nullopt; - return {{ - std::cref(*odg->concreteDrvGoal), - std::cref(*odg->drvReq), - }}; -} - } diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh index 6f6d25d7d..23ad87914 100644 --- a/src/libstore/build/worker.hh +++ b/src/libstore/build/worker.hh @@ -4,7 +4,6 @@ #include "types.hh" #include "lock.hh" #include "store-api.hh" -#include "derived-path-map.hh" #include "goal.hh" #include "realisation.hh" @@ -14,7 +13,6 @@ namespace nix { /* Forward definition. */ -struct CreateDerivationAndRealiseGoal; struct DerivationGoal; struct PathSubstitutionGoal; class DrvOutputSubstitutionGoal; @@ -33,26 +31,10 @@ class DrvOutputSubstitutionGoal; */ GoalPtr upcast_goal(std::shared_ptr<PathSubstitutionGoal> subGoal); GoalPtr upcast_goal(std::shared_ptr<DrvOutputSubstitutionGoal> subGoal); -GoalPtr upcast_goal(std::shared_ptr<DerivationGoal> subGoal); typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point; /** - * The current implementation of impure derivations has - * `DerivationGoal`s accumulate realisations from their waitees. - * Unfortunately, `DerivationGoal`s don't directly depend on other - * goals, but instead depend on `CreateDerivationAndRealiseGoal`s. - * - * We try not to share any of the details of any goal type with any - * other, for sake of modularity and quicker rebuilds. This means we - * cannot "just" downcast and fish out the field. So as an escape hatch, - * we have made the function, written in `worker.cc` where all the goal - * types are visible, and use it instead. - */ - -std::optional<std::pair<std::reference_wrapper<const DerivationGoal>, std::reference_wrapper<const SingleDerivedPath>>> tryGetConcreteDrvGoal(GoalPtr waitee); - -/** * A mapping used to remember for each child process to what goal it * belongs, and file descriptors for receiving log data and output * path creation commands. @@ -119,9 +101,6 @@ private: * Maps used to prevent multiple instantiations of a goal for the * same derivation / path. */ - - DerivedPathMap<std::weak_ptr<CreateDerivationAndRealiseGoal>> outerDerivationGoals; - std::map<StorePath, std::weak_ptr<DerivationGoal>> derivationGoals; std::map<StorePath, std::weak_ptr<PathSubstitutionGoal>> substitutionGoals; std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals; @@ -209,9 +188,6 @@ public: * @ref DerivationGoal "derivation goal" */ private: - std::shared_ptr<CreateDerivationAndRealiseGoal> makeCreateDerivationAndRealiseGoal( - ref<SingleDerivedPath> drvPath, - const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal); std::shared_ptr<DerivationGoal> makeDerivationGoalCommon( const StorePath & drvPath, const OutputsSpec & wantedOutputs, std::function<std::shared_ptr<DerivationGoal>()> mkDrvGoal); diff --git a/src/libstore/derived-path-map.cc b/src/libstore/derived-path-map.cc index 437b6a71a..5982c04b3 100644 --- a/src/libstore/derived-path-map.cc +++ b/src/libstore/derived-path-map.cc @@ -51,11 +51,8 @@ typename DerivedPathMap<V>::ChildNode * DerivedPathMap<V>::findSlot(const Single // instantiations -#include "create-derivation-and-realise-goal.hh" namespace nix { -template struct DerivedPathMap<std::weak_ptr<CreateDerivationAndRealiseGoal>>; - GENERATE_CMP_EXT( template<>, DerivedPathMap<std::set<std::string>>::ChildNode, diff --git a/src/libstore/derived-path-map.hh b/src/libstore/derived-path-map.hh index 4a2c90733..4d72b301e 100644 --- a/src/libstore/derived-path-map.hh +++ b/src/libstore/derived-path-map.hh @@ -20,11 +20,8 @@ namespace nix { * * @param V A type to instantiate for each output. It should probably * should be an "optional" type so not every interior node has to have a - * value. For example, the scheduler uses - * `DerivedPathMap<std::weak_ptr<CreateDerivationAndRealiseGoal>>` to - * remember which goals correspond to which outputs. `* const Something` - * or `std::optional<Something>` would also be good choices for - * "optional" types. + * value. `* const Something` or `std::optional<Something>` would be + * good choices for "optional" types. */ template<typename V> struct DerivedPathMap { diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 26c87391c..516cbef83 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -776,7 +776,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) } }; - /* Synchronisation point for testing, see tests/gc-concurrent.sh. */ + /* Synchronisation point for testing, see tests/functional/gc-concurrent.sh. */ if (auto p = getEnv("_NIX_TEST_GC_SYNC")) readFile(*p); diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 5a4cb1824..9c25d9868 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -24,6 +24,9 @@ #include "config-impl.hh" +#ifdef __APPLE__ +#include <sys/sysctl.h> +#endif namespace nix { @@ -154,6 +157,29 @@ unsigned int Settings::getDefaultCores() return concurrency; } +#if __APPLE__ +static bool hasVirt() { + + int hasVMM; + int hvSupport; + size_t size; + + size = sizeof(hasVMM); + if (sysctlbyname("kern.hv_vmm_present", &hasVMM, &size, NULL, 0) == 0) { + if (hasVMM) + return false; + } + + // whether the kernel and hardware supports virt + size = sizeof(hvSupport); + if (sysctlbyname("kern.hv_support", &hvSupport, &size, NULL, 0) == 0) { + return hvSupport == 1; + } else { + return false; + } +} +#endif + StringSet Settings::getDefaultSystemFeatures() { /* For backwards compatibility, accept some "features" that are @@ -170,6 +196,11 @@ StringSet Settings::getDefaultSystemFeatures() features.insert("kvm"); #endif + #if __APPLE__ + if (hasVirt()) + features.insert("apple-virt"); + #endif + return features; } diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index cf10edebd..dba7d78ef 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -708,6 +708,7 @@ public: `kvm` feature. This setting by default includes `kvm` if `/dev/kvm` is accessible, + `apple-virt` if hardware virtualization is available on macOS, and the pseudo-features `nixos-test`, `benchmark` and `big-parallel` that are used in Nixpkgs to route builds to specific machines. )", {}, false}; diff --git a/src/libstore/path-regex.hh b/src/libstore/path-regex.hh index 4f8dc4c1f..a44e6a2eb 100644 --- a/src/libstore/path-regex.hh +++ b/src/libstore/path-regex.hh @@ -3,6 +3,6 @@ namespace nix { -static constexpr std::string_view nameRegexStr = R"([0-9a-zA-Z\+\-\._\?=]+)"; +static constexpr std::string_view nameRegexStr = R"([0-9a-zA-Z\+\-_\?=][0-9a-zA-Z\+\-\._\?=]*)"; } diff --git a/src/libstore/path.cc b/src/libstore/path.cc index 552e83114..3c6b9fc10 100644 --- a/src/libstore/path.cc +++ b/src/libstore/path.cc @@ -11,6 +11,8 @@ static void checkName(std::string_view path, std::string_view name) if (name.size() > StorePath::MaxPathLen) throw BadStorePath("store path '%s' has a name longer than %d characters", path, StorePath::MaxPathLen); + if (name[0] == '.') + throw BadStorePath("store path '%s' starts with illegal character '.'", path); // See nameRegexStr for the definition for (auto c : name) if (!((c >= '0' && c <= '9') diff --git a/src/libstore/tests/derivation.cc b/src/libstore/tests/derivation.cc deleted file mode 100644 index c360c9707..000000000 --- a/src/libstore/tests/derivation.cc +++ /dev/null @@ -1,369 +0,0 @@ -#include <nlohmann/json.hpp> -#include <gtest/gtest.h> - -#include "experimental-features.hh" -#include "derivations.hh" - -#include "tests/libstore.hh" - -namespace nix { - -class DerivationTest : public LibStoreTest -{ -public: - /** - * We set these in tests rather than the regular globals so we don't have - * to worry about race conditions if the tests run concurrently. - */ - ExperimentalFeatureSettings mockXpSettings; -}; - -class CaDerivationTest : public DerivationTest -{ - void SetUp() override - { - mockXpSettings.set("experimental-features", "ca-derivations"); - } -}; - -class DynDerivationTest : public DerivationTest -{ - void SetUp() override - { - mockXpSettings.set("experimental-features", "dynamic-derivations ca-derivations"); - } -}; - -class ImpureDerivationTest : public DerivationTest -{ - void SetUp() override - { - mockXpSettings.set("experimental-features", "impure-derivations"); - } -}; - -TEST_F(DerivationTest, BadATerm_version) { - ASSERT_THROW( - parseDerivation( - *store, - R"(DrvWithVersion("invalid-version",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))", - "whatever", - mockXpSettings), - FormatError); -} - -TEST_F(DynDerivationTest, BadATerm_oldVersionDynDeps) { - ASSERT_THROW( - parseDerivation( - *store, - R"(Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",(["cat","dog"],[("cat",["kitten"]),("goose",["gosling"])]))],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))", - "dyn-dep-derivation", - mockXpSettings), - FormatError); -} - -#define TEST_JSON(FIXTURE, NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \ - TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _to_json) { \ - using nlohmann::literals::operator "" _json; \ - ASSERT_EQ( \ - STR ## _json, \ - (DerivationOutput { VAL }).toJSON( \ - *store, \ - DRV_NAME, \ - OUTPUT_NAME)); \ - } \ - \ - TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _from_json) { \ - using nlohmann::literals::operator "" _json; \ - ASSERT_EQ( \ - DerivationOutput { VAL }, \ - DerivationOutput::fromJSON( \ - *store, \ - DRV_NAME, \ - OUTPUT_NAME, \ - STR ## _json, \ - mockXpSettings)); \ - } - -TEST_JSON(DerivationTest, inputAddressed, - R"({ - "path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name" - })", - (DerivationOutput::InputAddressed { - .path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"), - }), - "drv-name", "output-name") - -TEST_JSON(DerivationTest, caFixedFlat, - R"({ - "hashAlgo": "sha256", - "hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f", - "path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name" - })", - (DerivationOutput::CAFixed { - .ca = { - .method = FileIngestionMethod::Flat, - .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), - }, - }), - "drv-name", "output-name") - -TEST_JSON(DerivationTest, caFixedNAR, - R"({ - "hashAlgo": "r:sha256", - "hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f", - "path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name" - })", - (DerivationOutput::CAFixed { - .ca = { - .method = FileIngestionMethod::Recursive, - .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), - }, - }), - "drv-name", "output-name") - -TEST_JSON(DynDerivationTest, caFixedText, - R"({ - "hashAlgo": "text:sha256", - "hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f", - "path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name" - })", - (DerivationOutput::CAFixed { - .ca = { - .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), - }, - }), - "drv-name", "output-name") - -TEST_JSON(CaDerivationTest, caFloating, - R"({ - "hashAlgo": "r:sha256" - })", - (DerivationOutput::CAFloating { - .method = FileIngestionMethod::Recursive, - .hashType = htSHA256, - }), - "drv-name", "output-name") - -TEST_JSON(DerivationTest, deferred, - R"({ })", - DerivationOutput::Deferred { }, - "drv-name", "output-name") - -TEST_JSON(ImpureDerivationTest, impure, - R"({ - "hashAlgo": "r:sha256", - "impure": true - })", - (DerivationOutput::Impure { - .method = FileIngestionMethod::Recursive, - .hashType = htSHA256, - }), - "drv-name", "output-name") - -#undef TEST_JSON - -#define TEST_JSON(FIXTURE, NAME, STR, VAL) \ - TEST_F(FIXTURE, Derivation_ ## NAME ## _to_json) { \ - using nlohmann::literals::operator "" _json; \ - ASSERT_EQ( \ - STR ## _json, \ - (VAL).toJSON(*store)); \ - } \ - \ - TEST_F(FIXTURE, Derivation_ ## NAME ## _from_json) { \ - using nlohmann::literals::operator "" _json; \ - ASSERT_EQ( \ - (VAL), \ - Derivation::fromJSON( \ - *store, \ - STR ## _json, \ - mockXpSettings)); \ - } - -#define TEST_ATERM(FIXTURE, NAME, STR, VAL, DRV_NAME) \ - TEST_F(FIXTURE, Derivation_ ## NAME ## _to_aterm) { \ - ASSERT_EQ( \ - STR, \ - (VAL).unparse(*store, false)); \ - } \ - \ - TEST_F(FIXTURE, Derivation_ ## NAME ## _from_aterm) { \ - auto parsed = parseDerivation( \ - *store, \ - STR, \ - DRV_NAME, \ - mockXpSettings); \ - ASSERT_EQ( \ - (VAL).toJSON(*store), \ - parsed.toJSON(*store)); \ - ASSERT_EQ( \ - (VAL), \ - parsed); \ - } - -Derivation makeSimpleDrv(const Store & store) { - Derivation drv; - drv.name = "simple-derivation"; - drv.inputSrcs = { - store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"), - }; - drv.inputDrvs = { - .map = { - { - store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"), - { - .value = { - "cat", - "dog", - }, - }, - }, - }, - }; - drv.platform = "wasm-sel4"; - drv.builder = "foo"; - drv.args = { - "bar", - "baz", - }; - drv.env = { - { - "BIG_BAD", - "WOLF", - }, - }; - return drv; -} - -TEST_JSON(DerivationTest, simple, - R"({ - "name": "simple-derivation", - "inputSrcs": [ - "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1" - ], - "inputDrvs": { - "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": { - "dynamicOutputs": {}, - "outputs": [ - "cat", - "dog" - ] - } - }, - "system": "wasm-sel4", - "builder": "foo", - "args": [ - "bar", - "baz" - ], - "env": { - "BIG_BAD": "WOLF" - }, - "outputs": {} - })", - makeSimpleDrv(*store)) - -TEST_ATERM(DerivationTest, simple, - R"(Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))", - makeSimpleDrv(*store), - "simple-derivation") - -Derivation makeDynDepDerivation(const Store & store) { - Derivation drv; - drv.name = "dyn-dep-derivation"; - drv.inputSrcs = { - store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"), - }; - drv.inputDrvs = { - .map = { - { - store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"), - DerivedPathMap<StringSet>::ChildNode { - .value = { - "cat", - "dog", - }, - .childMap = { - { - "cat", - DerivedPathMap<StringSet>::ChildNode { - .value = { - "kitten", - }, - }, - }, - { - "goose", - DerivedPathMap<StringSet>::ChildNode { - .value = { - "gosling", - }, - }, - }, - }, - }, - }, - }, - }; - drv.platform = "wasm-sel4"; - drv.builder = "foo"; - drv.args = { - "bar", - "baz", - }; - drv.env = { - { - "BIG_BAD", - "WOLF", - }, - }; - return drv; -} - -TEST_JSON(DynDerivationTest, dynDerivationDeps, - R"({ - "name": "dyn-dep-derivation", - "inputSrcs": [ - "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1" - ], - "inputDrvs": { - "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": { - "dynamicOutputs": { - "cat": { - "dynamicOutputs": {}, - "outputs": ["kitten"] - }, - "goose": { - "dynamicOutputs": {}, - "outputs": ["gosling"] - } - }, - "outputs": [ - "cat", - "dog" - ] - } - }, - "system": "wasm-sel4", - "builder": "foo", - "args": [ - "bar", - "baz" - ], - "env": { - "BIG_BAD": "WOLF" - }, - "outputs": {} - })", - makeDynDepDerivation(*store)) - -TEST_ATERM(DynDerivationTest, dynDerivationDeps, - R"(DrvWithVersion("xp-dyn-drv",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",(["cat","dog"],[("cat",["kitten"]),("goose",["gosling"])]))],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))", - makeDynDepDerivation(*store), - "dyn-dep-derivation") - -#undef TEST_JSON -#undef TEST_ATERM - -} diff --git a/src/libstore/tests/derived-path.cc b/src/libstore/tests/derived-path.cc deleted file mode 100644 index 3fa3c0801..000000000 --- a/src/libstore/tests/derived-path.cc +++ /dev/null @@ -1,153 +0,0 @@ -#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<SingleDerivedPath::Built> Arbitrary<SingleDerivedPath::Built>::arbitrary() -{ - return gen::just(SingleDerivedPath::Built { - .drvPath = make_ref<SingleDerivedPath>(*gen::arbitrary<SingleDerivedPath>()), - .output = (*gen::arbitrary<StorePathName>()).name, - }); -} - -Gen<DerivedPath::Built> Arbitrary<DerivedPath::Built>::arbitrary() -{ - return gen::just(DerivedPath::Built { - .drvPath = make_ref<SingleDerivedPath>(*gen::arbitrary<SingleDerivedPath>()), - .outputs = *gen::arbitrary<OutputsSpec>(), - }); -} - -Gen<SingleDerivedPath> Arbitrary<SingleDerivedPath>::arbitrary() -{ - switch (*gen::inRange<uint8_t>(0, std::variant_size_v<SingleDerivedPath::Raw>)) { - case 0: - return gen::just<SingleDerivedPath>(*gen::arbitrary<SingleDerivedPath::Opaque>()); - case 1: - return gen::just<SingleDerivedPath>(*gen::arbitrary<SingleDerivedPath::Built>()); - default: - assert(false); - } -} - -Gen<DerivedPath> Arbitrary<DerivedPath>::arbitrary() -{ - switch (*gen::inRange<uint8_t>(0, std::variant_size_v<DerivedPath::Raw>)) { - case 0: - return gen::just<DerivedPath>(*gen::arbitrary<DerivedPath::Opaque>()); - case 1: - return gen::just<DerivedPath>(*gen::arbitrary<DerivedPath::Built>()); - default: - assert(false); - } -} - -} - -namespace nix { - -class DerivedPathTest : public LibStoreTest -{ -}; - -/** - * Round trip (string <-> data structure) test for - * `DerivedPath::Opaque`. - */ -TEST_F(DerivedPathTest, opaque) { - std::string_view opaque = "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x"; - auto elem = DerivedPath::parse(*store, opaque); - auto * p = std::get_if<DerivedPath::Opaque>(&elem); - ASSERT_TRUE(p); - ASSERT_EQ(p->path, store->parseStorePath(opaque)); - ASSERT_EQ(elem.to_string(*store), opaque); -} - -/** - * Round trip (string <-> data structure) test for a simpler - * `DerivedPath::Built`. - */ -TEST_F(DerivedPathTest, built_opaque) { - std::string_view built = "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv^bar,foo"; - auto elem = DerivedPath::parse(*store, built); - auto * p = std::get_if<DerivedPath::Built>(&elem); - ASSERT_TRUE(p); - ASSERT_EQ(p->outputs, ((OutputsSpec) OutputsSpec::Names { "foo", "bar" })); - ASSERT_EQ(*p->drvPath, ((SingleDerivedPath) SingleDerivedPath::Opaque { - .path = store->parseStorePath(built.substr(0, 49)), - })); - ASSERT_EQ(elem.to_string(*store), built); -} - -/** - * Round trip (string <-> data structure) test for a more complex, - * inductive `DerivedPath::Built`. - */ -TEST_F(DerivedPathTest, built_built) { - /** - * We set these in tests rather than the regular globals so we don't have - * to worry about race conditions if the tests run concurrently. - */ - ExperimentalFeatureSettings mockXpSettings; - mockXpSettings.set("experimental-features", "dynamic-derivations ca-derivations"); - - std::string_view built = "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv^foo^bar,baz"; - auto elem = DerivedPath::parse(*store, built, mockXpSettings); - auto * p = std::get_if<DerivedPath::Built>(&elem); - ASSERT_TRUE(p); - ASSERT_EQ(p->outputs, ((OutputsSpec) OutputsSpec::Names { "bar", "baz" })); - auto * drvPath = std::get_if<SingleDerivedPath::Built>(&*p->drvPath); - ASSERT_TRUE(drvPath); - ASSERT_EQ(drvPath->output, "foo"); - ASSERT_EQ(*drvPath->drvPath, ((SingleDerivedPath) SingleDerivedPath::Opaque { - .path = store->parseStorePath(built.substr(0, 49)), - })); - ASSERT_EQ(elem.to_string(*store), built); -} - -/** - * Without the right experimental features enabled, we cannot parse a - * complex inductive derived path. - */ -TEST_F(DerivedPathTest, built_built_xp) { - ASSERT_THROW( - DerivedPath::parse(*store, "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv^foo^bar,baz"), - MissingExperimentalFeature); -} - -#ifndef COVERAGE - -RC_GTEST_FIXTURE_PROP( - DerivedPathTest, - prop_legacy_round_rip, - (const DerivedPath & o)) -{ - RC_ASSERT(o == DerivedPath::parseLegacy(*store, o.to_string_legacy(*store))); -} - -RC_GTEST_FIXTURE_PROP( - DerivedPathTest, - prop_round_rip, - (const DerivedPath & o)) -{ - RC_ASSERT(o == DerivedPath::parse(*store, o.to_string(*store))); -} - -#endif - -} diff --git a/src/libstore/tests/derived-path.hh b/src/libstore/tests/derived-path.hh deleted file mode 100644 index 98d61f228..000000000 --- a/src/libstore/tests/derived-path.hh +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -///@file - -#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<SingleDerivedPath::Opaque> { - static Gen<SingleDerivedPath::Opaque> arbitrary(); -}; - -template<> -struct Arbitrary<SingleDerivedPath::Built> { - static Gen<SingleDerivedPath::Built> arbitrary(); -}; - -template<> -struct Arbitrary<SingleDerivedPath> { - static Gen<SingleDerivedPath> arbitrary(); -}; - -template<> -struct Arbitrary<DerivedPath::Built> { - static Gen<DerivedPath::Built> arbitrary(); -}; - -template<> -struct Arbitrary<DerivedPath> { - static Gen<DerivedPath> arbitrary(); -}; - -} diff --git a/src/libstore/tests/downstream-placeholder.cc b/src/libstore/tests/downstream-placeholder.cc deleted file mode 100644 index fd29530ac..000000000 --- a/src/libstore/tests/downstream-placeholder.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include <gtest/gtest.h> - -#include "downstream-placeholder.hh" - -namespace nix { - -TEST(DownstreamPlaceholder, unknownCaOutput) { - /** - * We set these in tests rather than the regular globals so we don't have - * to worry about race conditions if the tests run concurrently. - */ - ExperimentalFeatureSettings mockXpSettings; - mockXpSettings.set("experimental-features", "ca-derivations"); - - ASSERT_EQ( - DownstreamPlaceholder::unknownCaOutput( - StorePath { "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv" }, - "out", - mockXpSettings).render(), - "/0c6rn30q4frawknapgwq386zq358m8r6msvywcvc89n6m5p2dgbz"); -} - -TEST(DownstreamPlaceholder, unknownDerivation) { - /** - * Same reason as above - */ - ExperimentalFeatureSettings mockXpSettings; - mockXpSettings.set("experimental-features", "dynamic-derivations ca-derivations"); - - ASSERT_EQ( - DownstreamPlaceholder::unknownDerivation( - DownstreamPlaceholder::unknownCaOutput( - StorePath { "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv.drv" }, - "out", - mockXpSettings), - "out", - mockXpSettings).render(), - "/0gn6agqxjyyalf0dpihgyf49xq5hqxgw100f0wydnj6yqrhqsb3w"); -} - -} diff --git a/src/libstore/tests/libstore.hh b/src/libstore/tests/libstore.hh deleted file mode 100644 index ef93457b5..000000000 --- a/src/libstore/tests/libstore.hh +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -///@file - -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -#include "store-api.hh" - -namespace nix { - -class LibStoreTest : public ::testing::Test { - public: - static void SetUpTestSuite() { - initLibStore(); - } - - protected: - LibStoreTest() - : store(openStore("dummy://")) - { } - - ref<Store> store; -}; - - -} /* namespace nix */ diff --git a/src/libstore/tests/local.mk b/src/libstore/tests/local.mk deleted file mode 100644 index 03becc7d1..000000000 --- a/src/libstore/tests/local.mk +++ /dev/null @@ -1,29 +0,0 @@ -check: libstore-tests-exe_RUN - -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_INSTALL_DIR := - -libstore-tests_SOURCES := $(wildcard $(d)/*.cc) - -libstore-tests_CXXFLAGS += -I src/libstore -I src/libutil - -libstore-tests_LIBS = libutil-tests libstore libutil - -libstore-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) diff --git a/src/libstore/tests/machines.cc b/src/libstore/tests/machines.cc deleted file mode 100644 index f51052b14..000000000 --- a/src/libstore/tests/machines.cc +++ /dev/null @@ -1,169 +0,0 @@ -#include "machines.hh" -#include "globals.hh" - -#include <gmock/gmock-matchers.h> - -using testing::Contains; -using testing::ElementsAre; -using testing::EndsWith; -using testing::Eq; -using testing::Field; -using testing::SizeIs; - -using nix::absPath; -using nix::FormatError; -using nix::getMachines; -using nix::Machine; -using nix::Machines; -using nix::pathExists; -using nix::Settings; -using nix::settings; - -class Environment : public ::testing::Environment { - public: - void SetUp() override { settings.thisSystem = "TEST_ARCH-TEST_OS"; } -}; - -testing::Environment* const foo_env = - testing::AddGlobalTestEnvironment(new Environment); - -TEST(machines, getMachinesWithEmptyBuilders) { - settings.builders = ""; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(0)); -} - -TEST(machines, getMachinesUriOnly) { - settings.builders = "nix@scratchy.labs.cs.uu.nl"; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(1)); - EXPECT_THAT(actual[0], Field(&Machine::storeUri, Eq("ssh://nix@scratchy.labs.cs.uu.nl"))); - EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("TEST_ARCH-TEST_OS"))); - EXPECT_THAT(actual[0], Field(&Machine::sshKey, SizeIs(0))); - EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(1))); - EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(1))); - EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, SizeIs(0))); - EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, SizeIs(0))); - EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, SizeIs(0))); -} - -TEST(machines, getMachinesDefaults) { - settings.builders = "nix@scratchy.labs.cs.uu.nl - - - - - - -"; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(1)); - EXPECT_THAT(actual[0], Field(&Machine::storeUri, Eq("ssh://nix@scratchy.labs.cs.uu.nl"))); - EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("TEST_ARCH-TEST_OS"))); - EXPECT_THAT(actual[0], Field(&Machine::sshKey, SizeIs(0))); - EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(1))); - EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(1))); - EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, SizeIs(0))); - EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, SizeIs(0))); - EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, SizeIs(0))); -} - -TEST(machines, getMachinesWithNewLineSeparator) { - settings.builders = "nix@scratchy.labs.cs.uu.nl\nnix@itchy.labs.cs.uu.nl"; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(2)); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")))); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@itchy.labs.cs.uu.nl")))); -} - -TEST(machines, getMachinesWithSemicolonSeparator) { - settings.builders = "nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl"; - Machines actual = getMachines(); - EXPECT_THAT(actual, SizeIs(2)); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")))); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@itchy.labs.cs.uu.nl")))); -} - -TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) { - settings.builders = "nix@scratchy.labs.cs.uu.nl i686-linux " - "/home/nix/.ssh/id_scratchy_auto 8 3 kvm " - "benchmark SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(1)); - EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl"))); - EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("i686-linux"))); - EXPECT_THAT(actual[0], Field(&Machine::sshKey, Eq("/home/nix/.ssh/id_scratchy_auto"))); - EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(8))); - EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(3))); - EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, ElementsAre("kvm"))); - EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, ElementsAre("benchmark"))); - EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, Eq("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); -} - -TEST(machines, - getMachinesWithCorrectCompleteSingleBuilderWithTabColumnDelimiter) { - settings.builders = - "nix@scratchy.labs.cs.uu.nl\ti686-linux\t/home/nix/.ssh/" - "id_scratchy_auto\t8\t3\tkvm\tbenchmark\tSSH+HOST+PUBLIC+" - "KEY+BASE64+ENCODED=="; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(1)); - EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl"))); - EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("i686-linux"))); - EXPECT_THAT(actual[0], Field(&Machine::sshKey, Eq("/home/nix/.ssh/id_scratchy_auto"))); - EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(8))); - EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(3))); - EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, ElementsAre("kvm"))); - EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, ElementsAre("benchmark"))); - EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, Eq("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); -} - -TEST(machines, getMachinesWithMultiOptions) { - settings.builders = "nix@scratchy.labs.cs.uu.nl Arch1,Arch2 - - - " - "SupportedFeature1,SupportedFeature2 " - "MandatoryFeature1,MandatoryFeature2"; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(1)); - EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl"))); - EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("Arch1", "Arch2"))); - EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, ElementsAre("SupportedFeature1", "SupportedFeature2"))); - EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, ElementsAre("MandatoryFeature1", "MandatoryFeature2"))); -} - -TEST(machines, getMachinesWithIncorrectFormat) { - settings.builders = "nix@scratchy.labs.cs.uu.nl - - eight"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - -1"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 three"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 -3"; - EXPECT_THROW(getMachines(), FormatError); - settings.builders = "nix@scratchy.labs.cs.uu.nl - - 8 3 - - BAD_BASE64"; - EXPECT_THROW(getMachines(), FormatError); -} - -TEST(machines, getMachinesWithCorrectFileReference) { - auto path = absPath("src/libstore/tests/test-data/machines.valid"); - ASSERT_TRUE(pathExists(path)); - - settings.builders = std::string("@") + path; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(3)); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl")))); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@itchy.labs.cs.uu.nl")))); - EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@poochie.labs.cs.uu.nl")))); -} - -TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) { - auto path = "/dev/null"; - ASSERT_TRUE(pathExists(path)); - - settings.builders = std::string("@") + path; - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(0)); -} - -TEST(machines, getMachinesWithIncorrectFileReference) { - settings.builders = std::string("@") + absPath("/not/a/file"); - Machines actual = getMachines(); - ASSERT_THAT(actual, SizeIs(0)); -} - -TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) { - settings.builders = std::string("@") + absPath("src/libstore/tests/test-data/machines.bad_format"); - EXPECT_THROW(getMachines(), FormatError); -} diff --git a/src/libstore/tests/nar-info-disk-cache.cc b/src/libstore/tests/nar-info-disk-cache.cc deleted file mode 100644 index b4bdb8329..000000000 --- a/src/libstore/tests/nar-info-disk-cache.cc +++ /dev/null @@ -1,123 +0,0 @@ -#include "nar-info-disk-cache.hh" - -#include <gtest/gtest.h> -#include <rapidcheck/gtest.h> -#include "sqlite.hh" -#include <sqlite3.h> - - -namespace nix { - -TEST(NarInfoDiskCacheImpl, create_and_read) { - // This is a large single test to avoid some setup overhead. - - int prio = 12345; - bool wantMassQuery = true; - - Path tmpDir = createTempDir(); - AutoDelete delTmpDir(tmpDir); - Path dbPath(tmpDir + "/test-narinfo-disk-cache.sqlite"); - - int savedId; - int barId; - SQLite db; - SQLiteStmt getIds; - - { - auto cache = getTestNarInfoDiskCache(dbPath); - - // Set up "background noise" and check that different caches receive different ids - { - auto bc1 = cache->createCache("https://bar", "/nix/storedir", wantMassQuery, prio); - auto bc2 = cache->createCache("https://xyz", "/nix/storedir", false, 12); - ASSERT_NE(bc1, bc2); - barId = bc1; - } - - // Check that the fields are saved and returned correctly. This does not test - // the select statement yet, because of in-memory caching. - savedId = cache->createCache("http://foo", "/nix/storedir", wantMassQuery, prio);; - { - auto r = cache->upToDateCacheExists("http://foo"); - ASSERT_TRUE(r); - ASSERT_EQ(r->priority, prio); - ASSERT_EQ(r->wantMassQuery, wantMassQuery); - ASSERT_EQ(savedId, r->id); - } - - // We're going to pay special attention to the id field because we had a bug - // that changed it. - db = SQLite(dbPath); - getIds.create(db, "select id from BinaryCaches where url = 'http://foo'"); - - { - auto q(getIds.use()); - ASSERT_TRUE(q.next()); - ASSERT_EQ(savedId, q.getInt(0)); - ASSERT_FALSE(q.next()); - } - - // Pretend that the caches are older, but keep one up to date, as "background noise" - db.exec("update BinaryCaches set timestamp = timestamp - 1 - 7 * 24 * 3600 where url <> 'https://xyz';"); - - // This shows that the in-memory cache works - { - auto r = cache->upToDateCacheExists("http://foo"); - ASSERT_TRUE(r); - ASSERT_EQ(r->priority, prio); - ASSERT_EQ(r->wantMassQuery, wantMassQuery); - } - } - - { - // We can't clear the in-memory cache, so we use a new cache object. This is - // more realistic anyway. - auto cache2 = getTestNarInfoDiskCache(dbPath); - - { - auto r = cache2->upToDateCacheExists("http://foo"); - ASSERT_FALSE(r); - } - - // "Update", same data, check that the id number is reused - cache2->createCache("http://foo", "/nix/storedir", wantMassQuery, prio); - - { - auto r = cache2->upToDateCacheExists("http://foo"); - ASSERT_TRUE(r); - ASSERT_EQ(r->priority, prio); - ASSERT_EQ(r->wantMassQuery, wantMassQuery); - ASSERT_EQ(r->id, savedId); - } - - { - auto q(getIds.use()); - ASSERT_TRUE(q.next()); - auto currentId = q.getInt(0); - ASSERT_FALSE(q.next()); - ASSERT_EQ(currentId, savedId); - } - - // Check that the fields can be modified, and the id remains the same - { - auto r0 = cache2->upToDateCacheExists("https://bar"); - ASSERT_FALSE(r0); - - cache2->createCache("https://bar", "/nix/storedir", !wantMassQuery, prio + 10); - auto r = cache2->upToDateCacheExists("https://bar"); - ASSERT_EQ(r->wantMassQuery, !wantMassQuery); - ASSERT_EQ(r->priority, prio + 10); - ASSERT_EQ(r->id, barId); - } - - // // Force update (no use case yet; we only retrieve cache metadata when stale based on timestamp) - // { - // cache2->createCache("https://bar", "/nix/storedir", wantMassQuery, prio + 20); - // auto r = cache2->upToDateCacheExists("https://bar"); - // ASSERT_EQ(r->wantMassQuery, wantMassQuery); - // ASSERT_EQ(r->priority, prio + 20); - // } - } -} - -} diff --git a/src/libstore/tests/outputs-spec.cc b/src/libstore/tests/outputs-spec.cc deleted file mode 100644 index 952945185..000000000 --- a/src/libstore/tests/outputs-spec.cc +++ /dev/null @@ -1,239 +0,0 @@ -#include "outputs-spec.hh" - -#include <nlohmann/json.hpp> -#include <gtest/gtest.h> -#include <rapidcheck/gtest.h> - -namespace nix { - -#ifndef NDEBUG -TEST(OutputsSpec, no_empty_names) { - ASSERT_DEATH(OutputsSpec::Names { std::set<std::string> { } }, ""); -} -#endif - -#define TEST_DONT_PARSE(NAME, STR) \ - TEST(OutputsSpec, bad_ ## NAME) { \ - std::optional OutputsSpecOpt = \ - OutputsSpec::parseOpt(STR); \ - ASSERT_FALSE(OutputsSpecOpt); \ - } - -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,*") - -#undef TEST_DONT_PARSE - -TEST(OutputsSpec, all) { - std::string_view str = "*"; - OutputsSpec expected = OutputsSpec::All { }; - ASSERT_EQ(OutputsSpec::parse(str), expected); - ASSERT_EQ(expected.to_string(), str); -} - -TEST(OutputsSpec, names_out) { - std::string_view str = "out"; - OutputsSpec expected = OutputsSpec::Names { "out" }; - ASSERT_EQ(OutputsSpec::parse(str), expected); - ASSERT_EQ(expected.to_string(), str); -} - -TEST(OutputsSpec, names_underscore) { - std::string_view str = "a_b"; - OutputsSpec expected = OutputsSpec::Names { "a_b" }; - ASSERT_EQ(OutputsSpec::parse(str), expected); - ASSERT_EQ(expected.to_string(), str); -} - -TEST(OutputsSpec, names_numberic) { - std::string_view str = "01"; - OutputsSpec expected = OutputsSpec::Names { "01" }; - ASSERT_EQ(OutputsSpec::parse(str), expected); - ASSERT_EQ(expected.to_string(), str); -} - -TEST(OutputsSpec, names_out_bin) { - OutputsSpec expected = OutputsSpec::Names { "out", "bin" }; - ASSERT_EQ(OutputsSpec::parse("out,bin"), expected); - // N.B. This normalization is OK. - ASSERT_EQ(expected.to_string(), "bin,out"); -} - -#define TEST_SUBSET(X, THIS, THAT) \ - X((OutputsSpec { THIS }).isSubsetOf(THAT)); - -TEST(OutputsSpec, subsets_all_all) { - TEST_SUBSET(ASSERT_TRUE, OutputsSpec::All { }, OutputsSpec::All { }); -} - -TEST(OutputsSpec, subsets_names_all) { - TEST_SUBSET(ASSERT_TRUE, OutputsSpec::Names { "a" }, OutputsSpec::All { }); -} - -TEST(OutputsSpec, subsets_names_names_eq) { - TEST_SUBSET(ASSERT_TRUE, OutputsSpec::Names { "a" }, OutputsSpec::Names { "a" }); -} - -TEST(OutputsSpec, subsets_names_names_noneq) { - TEST_SUBSET(ASSERT_TRUE, OutputsSpec::Names { "a" }, (OutputsSpec::Names { "a", "b" })); -} - -TEST(OutputsSpec, not_subsets_all_names) { - TEST_SUBSET(ASSERT_FALSE, OutputsSpec::All { }, OutputsSpec::Names { "a" }); -} - -TEST(OutputsSpec, not_subsets_names_names) { - TEST_SUBSET(ASSERT_FALSE, (OutputsSpec::Names { "a", "b" }), (OutputsSpec::Names { "a" })); -} - -#undef TEST_SUBSET - -#define TEST_UNION(RES, THIS, THAT) \ - ASSERT_EQ(OutputsSpec { RES }, (OutputsSpec { THIS }).union_(THAT)); - -TEST(OutputsSpec, union_all_all) { - TEST_UNION(OutputsSpec::All { }, OutputsSpec::All { }, OutputsSpec::All { }); -} - -TEST(OutputsSpec, union_all_names) { - TEST_UNION(OutputsSpec::All { }, OutputsSpec::All { }, OutputsSpec::Names { "a" }); -} - -TEST(OutputsSpec, union_names_all) { - TEST_UNION(OutputsSpec::All { }, OutputsSpec::Names { "a" }, OutputsSpec::All { }); -} - -TEST(OutputsSpec, union_names_names) { - TEST_UNION((OutputsSpec::Names { "a", "b" }), OutputsSpec::Names { "a" }, OutputsSpec::Names { "b" }); -} - -#undef TEST_UNION - -#define TEST_DONT_PARSE(NAME, STR) \ - TEST(ExtendedOutputsSpec, bad_ ## NAME) { \ - std::optional extendedOutputsSpecOpt = \ - ExtendedOutputsSpec::parseOpt(STR); \ - ASSERT_FALSE(extendedOutputsSpecOpt); \ - } - -TEST_DONT_PARSE(carot_empty, "^") -TEST_DONT_PARSE(prefix_carot_empty, "foo^") -TEST_DONT_PARSE(garbage, "^&*()") -TEST_DONT_PARSE(double_star, "^**") -TEST_DONT_PARSE(star_first, "^*,foo") -TEST_DONT_PARSE(star_second, "^foo,*") - -#undef TEST_DONT_PARSE - -TEST(ExtendedOutputsSpec, defeault) { - std::string_view str = "foo"; - auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(str); - ASSERT_EQ(prefix, "foo"); - ExtendedOutputsSpec expected = ExtendedOutputsSpec::Default { }; - ASSERT_EQ(extendedOutputsSpec, expected); - ASSERT_EQ(std::string { prefix } + expected.to_string(), str); -} - -TEST(ExtendedOutputsSpec, all) { - std::string_view str = "foo^*"; - auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(str); - ASSERT_EQ(prefix, "foo"); - ExtendedOutputsSpec expected = OutputsSpec::All { }; - ASSERT_EQ(extendedOutputsSpec, expected); - ASSERT_EQ(std::string { prefix } + expected.to_string(), str); -} - -TEST(ExtendedOutputsSpec, out) { - std::string_view str = "foo^out"; - auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(str); - ASSERT_EQ(prefix, "foo"); - ExtendedOutputsSpec expected = OutputsSpec::Names { "out" }; - ASSERT_EQ(extendedOutputsSpec, expected); - ASSERT_EQ(std::string { prefix } + expected.to_string(), str); -} - -TEST(ExtendedOutputsSpec, out_bin) { - auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse("foo^out,bin"); - ASSERT_EQ(prefix, "foo"); - ExtendedOutputsSpec expected = OutputsSpec::Names { "out", "bin" }; - ASSERT_EQ(extendedOutputsSpec, expected); - ASSERT_EQ(std::string { prefix } + expected.to_string(), "foo^bin,out"); -} - -TEST(ExtendedOutputsSpec, many_carrot) { - auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse("foo^bar^out,bin"); - ASSERT_EQ(prefix, "foo^bar"); - ExtendedOutputsSpec expected = OutputsSpec::Names { "out", "bin" }; - ASSERT_EQ(extendedOutputsSpec, expected); - ASSERT_EQ(std::string { prefix } + expected.to_string(), "foo^bar^bin,out"); -} - - -#define TEST_JSON(TYPE, NAME, STR, VAL) \ - \ - TEST(TYPE, NAME ## _to_json) { \ - using nlohmann::literals::operator "" _json; \ - ASSERT_EQ( \ - STR ## _json, \ - ((nlohmann::json) TYPE { VAL })); \ - } \ - \ - TEST(TYPE, NAME ## _from_json) { \ - using nlohmann::literals::operator "" _json; \ - ASSERT_EQ( \ - TYPE { VAL }, \ - (STR ## _json).get<TYPE>()); \ - } - -TEST_JSON(OutputsSpec, all, R"(["*"])", OutputsSpec::All { }) -TEST_JSON(OutputsSpec, name, R"(["a"])", OutputsSpec::Names { "a" }) -TEST_JSON(OutputsSpec, names, R"(["a","b"])", (OutputsSpec::Names { "a", "b" })) - -TEST_JSON(ExtendedOutputsSpec, def, R"(null)", ExtendedOutputsSpec::Default { }) -TEST_JSON(ExtendedOutputsSpec, all, R"(["*"])", ExtendedOutputsSpec::Explicit { OutputsSpec::All { } }) -TEST_JSON(ExtendedOutputsSpec, name, R"(["a"])", ExtendedOutputsSpec::Explicit { OutputsSpec::Names { "a" } }) -TEST_JSON(ExtendedOutputsSpec, names, R"(["a","b"])", (ExtendedOutputsSpec::Explicit { OutputsSpec::Names { "a", "b" } })) - -#undef TEST_JSON - -} - -namespace rc { -using namespace nix; - -Gen<OutputsSpec> Arbitrary<OutputsSpec>::arbitrary() -{ - switch (*gen::inRange<uint8_t>(0, std::variant_size_v<OutputsSpec::Raw>)) { - case 0: - return gen::just((OutputsSpec) OutputsSpec::All { }); - case 1: - return gen::just((OutputsSpec) OutputsSpec::Names { - *gen::nonEmpty(gen::container<StringSet>(gen::map( - gen::arbitrary<StorePathName>(), - [](StorePathName n) { return n.name; }))), - }); - default: - assert(false); - } -} - -} - -namespace nix { - -#ifndef COVERAGE - -RC_GTEST_PROP( - OutputsSpec, - prop_round_rip, - (const OutputsSpec & o)) -{ - RC_ASSERT(o == OutputsSpec::parse(o.to_string())); -} - -#endif - -} diff --git a/src/libstore/tests/outputs-spec.hh b/src/libstore/tests/outputs-spec.hh deleted file mode 100644 index ded331b33..000000000 --- a/src/libstore/tests/outputs-spec.hh +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -///@file - -#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(); -}; - -} diff --git a/src/libstore/tests/path.cc b/src/libstore/tests/path.cc deleted file mode 100644 index efa35ef2b..000000000 --- a/src/libstore/tests/path.cc +++ /dev/null @@ -1,157 +0,0 @@ -#include <regex> - -#include <nlohmann/json.hpp> -#include <gtest/gtest.h> -#include <rapidcheck/gtest.h> - -#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") - -#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<StorePathName> Arbitrary<StorePathName>::arbitrary() -{ - auto len = *gen::inRange<size_t>( - 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<uint8_t>(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: - 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<StorePath> Arbitrary<StorePath>::arbitrary() -{ - return gen::just(StorePath { - *gen::arbitrary<Hash>(), - (*gen::arbitrary<StorePathName>()).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 - -} diff --git a/src/libstore/tests/path.hh b/src/libstore/tests/path.hh deleted file mode 100644 index 21cb62310..000000000 --- a/src/libstore/tests/path.hh +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -///@file - -#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(); -}; - -} diff --git a/src/libstore/tests/references.cc b/src/libstore/tests/references.cc deleted file mode 100644 index d91d1cedd..000000000 --- a/src/libstore/tests/references.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "references.hh" - -#include <gtest/gtest.h> - -namespace nix { - -TEST(references, scan) -{ - std::string hash1 = "dc04vv14dak1c1r48qa0m23vr9jy8sm0"; - std::string hash2 = "zc842j0rz61mjsp3h3wp5ly71ak6qgdn"; - - { - RefScanSink scanner(StringSet{hash1}); - auto s = "foobar"; - scanner(s); - ASSERT_EQ(scanner.getResult(), StringSet{}); - } - - { - RefScanSink scanner(StringSet{hash1}); - auto s = "foobar" + hash1 + "xyzzy"; - scanner(s); - ASSERT_EQ(scanner.getResult(), StringSet{hash1}); - } - - { - RefScanSink scanner(StringSet{hash1, hash2}); - auto s = "foobar" + hash1 + "xyzzy" + hash2; - scanner(((std::string_view) s).substr(0, 10)); - scanner(((std::string_view) s).substr(10, 5)); - scanner(((std::string_view) s).substr(15, 5)); - scanner(((std::string_view) s).substr(20)); - ASSERT_EQ(scanner.getResult(), StringSet({hash1, hash2})); - } - - { - RefScanSink scanner(StringSet{hash1, hash2}); - auto s = "foobar" + hash1 + "xyzzy" + hash2; - for (auto & i : s) - scanner(std::string(1, i)); - ASSERT_EQ(scanner.getResult(), StringSet({hash1, hash2})); - } -} - -} diff --git a/src/libstore/tests/test-data/machines.bad_format b/src/libstore/tests/test-data/machines.bad_format deleted file mode 100644 index 7255a1216..000000000 --- a/src/libstore/tests/test-data/machines.bad_format +++ /dev/null @@ -1 +0,0 @@ -nix@scratchy.labs.cs.uu.nl - - eight diff --git a/src/libstore/tests/test-data/machines.valid b/src/libstore/tests/test-data/machines.valid deleted file mode 100644 index 1a6c8017c..000000000 --- a/src/libstore/tests/test-data/machines.valid +++ /dev/null @@ -1,3 +0,0 @@ -nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm -nix@itchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2 -nix@poochie.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 1 2 kvm benchmark c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFDQVFDWWV5R1laNTNzd1VjMUZNSHBWL1BCcXlKaFR5S1JoRkpWWVRpRHlQN2h5c1JGa0w4VDlLOGdhL2Y2L3c3QjN2SjNHSFRIUFkybENiUEdZbGNLd2h6M2ZRbFNNOEViNi95b3ZLajdvM1FsMEx5Y0dzdGJvRmcwWkZKNldncUxsR0ltS0NobUlxOGZ3TW5ZTWUxbnRQeTBUZFZjSU1tOTV3YzF3SjBMd2c3cEVMRmtHazdkeTVvYnM4a3lGZ0pORDVRSmFwQWJjeWp4Z1QzdzdMcktNZ2xzeWhhd01JNVpkMGZsQTVudW5OZ3pid3plYVhLaUsyTW0vdGJXYTU1YTd4QmNYdHpIZGlPSWdSajJlRWxaMGh5bk10YjBmcklsdmxIcEtLaVFaZ3pQdCtIVXQ2bXpRMkRVME52MGYyYnNSU0krOGpJU2pQcmdlcVVHRldMUzVIUTg2N2xSMlpiaWtyclhZNTdqbVFEZk5DRHY1VFBHZU9UekFEd2pjMDc2aFZ3VFJCd3VTZFhtaWNxTS95b3lrWitkV1dnZ25MenE5QU1tdlNZcDhmZkZDcS9CSDBZNUFXWTFHay9vS3hMVTNaOWt3ZDd2UWNFQWFCQ2dxdnVZRGdTaHE1RlhndDM3OVZESWtEL05ZSTg2QXVvajVDRmVNTzlRM2pJSlRadlh6c1VldjVoSnA2djcxSVh5ODVtbTY5R20zcXdicVE1SjVQZDU1Um56SitpaW5BNjZxTEFSc0Y4amNsSnd5ekFXclBoYU9DRVY2bjVMeVhVazhzMW9EVVR4V1pWN25rVkFTbHJ0MllGcjN5dzdjRTRXQVhsemhHcDhocmdLMVVkMUlyeDVnZWRaSnBWcy9uNWVybmJFMUxmb2x5UHUvRUFIWlh6VGd4dHVDUFNobXc9PQo= diff --git a/src/libutil/tests/canon-path.cc b/src/libutil/tests/canon-path.cc deleted file mode 100644 index fc94ccc3d..000000000 --- a/src/libutil/tests/canon-path.cc +++ /dev/null @@ -1,162 +0,0 @@ -#include "canon-path.hh" - -#include <gtest/gtest.h> - -namespace nix { - - TEST(CanonPath, basic) { - { - CanonPath p("/"); - ASSERT_EQ(p.abs(), "/"); - ASSERT_EQ(p.rel(), ""); - ASSERT_EQ(p.baseName(), std::nullopt); - ASSERT_EQ(p.dirOf(), std::nullopt); - ASSERT_FALSE(p.parent()); - } - - { - CanonPath p("/foo//"); - ASSERT_EQ(p.abs(), "/foo"); - ASSERT_EQ(p.rel(), "foo"); - ASSERT_EQ(*p.baseName(), "foo"); - ASSERT_EQ(*p.dirOf(), ""); // FIXME: do we want this? - ASSERT_EQ(p.parent()->abs(), "/"); - } - - { - CanonPath p("foo/bar"); - ASSERT_EQ(p.abs(), "/foo/bar"); - ASSERT_EQ(p.rel(), "foo/bar"); - ASSERT_EQ(*p.baseName(), "bar"); - ASSERT_EQ(*p.dirOf(), "/foo"); - ASSERT_EQ(p.parent()->abs(), "/foo"); - } - - { - CanonPath p("foo//bar/"); - ASSERT_EQ(p.abs(), "/foo/bar"); - ASSERT_EQ(p.rel(), "foo/bar"); - ASSERT_EQ(*p.baseName(), "bar"); - ASSERT_EQ(*p.dirOf(), "/foo"); - } - } - - TEST(CanonPath, pop) { - CanonPath p("foo/bar/x"); - ASSERT_EQ(p.abs(), "/foo/bar/x"); - p.pop(); - ASSERT_EQ(p.abs(), "/foo/bar"); - p.pop(); - ASSERT_EQ(p.abs(), "/foo"); - p.pop(); - ASSERT_EQ(p.abs(), "/"); - } - - TEST(CanonPath, removePrefix) { - CanonPath p1("foo/bar"); - CanonPath p2("foo/bar/a/b/c"); - ASSERT_EQ(p2.removePrefix(p1).abs(), "/a/b/c"); - ASSERT_EQ(p1.removePrefix(p1).abs(), "/"); - ASSERT_EQ(p1.removePrefix(CanonPath("/")).abs(), "/foo/bar"); - } - - TEST(CanonPath, iter) { - { - CanonPath p("a//foo/bar//"); - std::vector<std::string_view> ss; - for (auto & c : p) ss.push_back(c); - ASSERT_EQ(ss, std::vector<std::string_view>({"a", "foo", "bar"})); - } - - { - CanonPath p("/"); - std::vector<std::string_view> ss; - for (auto & c : p) ss.push_back(c); - ASSERT_EQ(ss, std::vector<std::string_view>()); - } - } - - TEST(CanonPath, concat) { - { - CanonPath p1("a//foo/bar//"); - CanonPath p2("xyzzy/bla"); - ASSERT_EQ((p1 + p2).abs(), "/a/foo/bar/xyzzy/bla"); - } - - { - CanonPath p1("/"); - CanonPath p2("/a/b"); - ASSERT_EQ((p1 + p2).abs(), "/a/b"); - } - - { - CanonPath p1("/a/b"); - CanonPath p2("/"); - ASSERT_EQ((p1 + p2).abs(), "/a/b"); - } - - { - CanonPath p("/foo/bar"); - ASSERT_EQ((p + "x").abs(), "/foo/bar/x"); - } - - { - CanonPath p("/"); - ASSERT_EQ((p + "foo" + "bar").abs(), "/foo/bar"); - } - } - - TEST(CanonPath, within) { - ASSERT_TRUE(CanonPath("foo").isWithin(CanonPath("foo"))); - ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("bar"))); - ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("fo"))); - ASSERT_TRUE(CanonPath("foo/bar").isWithin(CanonPath("foo"))); - ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("foo/bar"))); - ASSERT_TRUE(CanonPath("/foo/bar/default.nix").isWithin(CanonPath("/"))); - ASSERT_TRUE(CanonPath("/").isWithin(CanonPath("/"))); - } - - TEST(CanonPath, sort) { - ASSERT_FALSE(CanonPath("foo") < CanonPath("foo")); - ASSERT_TRUE (CanonPath("foo") < CanonPath("foo/bar")); - ASSERT_TRUE (CanonPath("foo/bar") < CanonPath("foo!")); - ASSERT_FALSE(CanonPath("foo!") < CanonPath("foo")); - ASSERT_TRUE (CanonPath("foo") < CanonPath("foo!")); - } - - TEST(CanonPath, allowed) { - std::set<CanonPath> allowed { - CanonPath("foo/bar"), - CanonPath("foo!"), - CanonPath("xyzzy"), - CanonPath("a/b/c"), - }; - - ASSERT_TRUE (CanonPath("foo/bar").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("foo/bar/bla").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("foo").isAllowed(allowed)); - ASSERT_FALSE(CanonPath("bar").isAllowed(allowed)); - ASSERT_FALSE(CanonPath("bar/a").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("a").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("a/b").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("a/b/c").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("a/b/c/d").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("a/b/c/d/e").isAllowed(allowed)); - ASSERT_FALSE(CanonPath("a/b/a").isAllowed(allowed)); - ASSERT_FALSE(CanonPath("a/b/d").isAllowed(allowed)); - ASSERT_FALSE(CanonPath("aaa").isAllowed(allowed)); - ASSERT_FALSE(CanonPath("zzz").isAllowed(allowed)); - ASSERT_TRUE (CanonPath("/").isAllowed(allowed)); - } - - TEST(CanonPath, makeRelative) { - CanonPath d("/foo/bar"); - ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar")), "."); - ASSERT_EQ(d.makeRelative(CanonPath("/foo")), ".."); - ASSERT_EQ(d.makeRelative(CanonPath("/")), "../.."); - ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy")), "xyzzy"); - ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy/bla")), "xyzzy/bla"); - ASSERT_EQ(d.makeRelative(CanonPath("/foo/xyzzy/bla")), "../xyzzy/bla"); - ASSERT_EQ(d.makeRelative(CanonPath("/xyzzy/bla")), "../../xyzzy/bla"); - } -} diff --git a/src/libutil/tests/chunked-vector.cc b/src/libutil/tests/chunked-vector.cc deleted file mode 100644 index 868d11f6f..000000000 --- a/src/libutil/tests/chunked-vector.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "chunked-vector.hh" - -#include <gtest/gtest.h> - -namespace nix { - TEST(ChunkedVector, InitEmpty) { - auto v = ChunkedVector<int, 2>(100); - ASSERT_EQ(v.size(), 0); - } - - TEST(ChunkedVector, GrowsCorrectly) { - auto v = ChunkedVector<int, 2>(100); - for (auto i = 1; i < 20; i++) { - v.add(i); - ASSERT_EQ(v.size(), i); - } - } - - TEST(ChunkedVector, AddAndGet) { - auto v = ChunkedVector<int, 2>(100); - for (auto i = 1; i < 20; i++) { - auto [i2, idx] = v.add(i); - auto & i3 = v[idx]; - ASSERT_EQ(i, i2); - ASSERT_EQ(&i2, &i3); - } - } - - TEST(ChunkedVector, ForEach) { - auto v = ChunkedVector<int, 2>(100); - for (auto i = 1; i < 20; i++) { - v.add(i); - } - int count = 0; - v.forEach([&count](int elt) { - count++; - }); - ASSERT_EQ(count, v.size()); - } - - TEST(ChunkedVector, OverflowOK) { - // Similar to the AddAndGet, but intentionnally use a small - // initial ChunkedVector to force it to overflow - auto v = ChunkedVector<int, 2>(2); - for (auto i = 1; i < 20; i++) { - auto [i2, idx] = v.add(i); - auto & i3 = v[idx]; - ASSERT_EQ(i, i2); - ASSERT_EQ(&i2, &i3); - } - } - -} - diff --git a/src/libutil/tests/closure.cc b/src/libutil/tests/closure.cc deleted file mode 100644 index 7597e7807..000000000 --- a/src/libutil/tests/closure.cc +++ /dev/null @@ -1,70 +0,0 @@ -#include "closure.hh" -#include <gtest/gtest.h> - -namespace nix { - -using namespace std; - -map<string, set<string>> testGraph = { - { "A", { "B", "C", "G" } }, - { "B", { "A" } }, // Loops back to A - { "C", { "F" } }, // Indirect reference - { "D", { "A" } }, // Not reachable, but has backreferences - { "E", {} }, // Just not reachable - { "F", {} }, - { "G", { "G" } }, // Self reference -}; - -TEST(closure, correctClosure) { - set<string> aClosure; - set<string> expectedClosure = {"A", "B", "C", "F", "G"}; - computeClosure<string>( - {"A"}, - aClosure, - [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { - promise<set<string>> promisedNodes; - promisedNodes.set_value(testGraph[currentNode]); - processEdges(promisedNodes); - } - ); - - ASSERT_EQ(aClosure, expectedClosure); -} - -TEST(closure, properlyHandlesDirectExceptions) { - struct TestExn {}; - set<string> aClosure; - EXPECT_THROW( - computeClosure<string>( - {"A"}, - aClosure, - [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { - throw TestExn(); - } - ), - TestExn - ); -} - -TEST(closure, properlyHandlesExceptionsInPromise) { - struct TestExn {}; - set<string> aClosure; - EXPECT_THROW( - computeClosure<string>( - {"A"}, - aClosure, - [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { - promise<set<string>> promise; - try { - throw TestExn(); - } catch (...) { - promise.set_exception(std::current_exception()); - } - processEdges(promise); - } - ), - TestExn - ); -} - -} diff --git a/src/libutil/tests/compression.cc b/src/libutil/tests/compression.cc deleted file mode 100644 index bbbf3500f..000000000 --- a/src/libutil/tests/compression.cc +++ /dev/null @@ -1,96 +0,0 @@ -#include "compression.hh" -#include <gtest/gtest.h> - -namespace nix { - - /* ---------------------------------------------------------------------------- - * compress / decompress - * --------------------------------------------------------------------------*/ - - TEST(compress, compressWithUnknownMethod) { - ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); - } - - TEST(compress, noneMethodDoesNothingToTheInput) { - auto o = compress("none", "this-is-a-test"); - - ASSERT_EQ(o, "this-is-a-test"); - } - - TEST(decompress, decompressNoneCompressed) { - auto method = "none"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, str); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressEmptyCompressed) { - // Empty-method decompression used e.g. by S3 store - // (Content-Encoding == ""). - auto method = ""; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, str); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressXzCompressed) { - auto method = "xz"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressBzip2Compressed) { - auto method = "bzip2"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressBrCompressed) { - auto method = "br"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressInvalidInputThrowsCompressionError) { - auto method = "bzip2"; - auto str = "this is a string that does not qualify as valid bzip2 data"; - - ASSERT_THROW(decompress(method, str), CompressionError); - } - - /* ---------------------------------------------------------------------------- - * compression sinks - * --------------------------------------------------------------------------*/ - - TEST(makeCompressionSink, noneSinkDoesNothingToInput) { - StringSink strSink; - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto sink = makeCompressionSink("none", strSink); - (*sink)(inputString); - sink->finish(); - - ASSERT_STREQ(strSink.s.c_str(), inputString); - } - - TEST(makeCompressionSink, compressAndDecompress) { - StringSink strSink; - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto decompressionSink = makeDecompressionSink("bzip2", strSink); - auto sink = makeCompressionSink("bzip2", *decompressionSink); - - (*sink)(inputString); - sink->finish(); - decompressionSink->finish(); - - ASSERT_STREQ(strSink.s.c_str(), inputString); - } - -} diff --git a/src/libutil/tests/config.cc b/src/libutil/tests/config.cc deleted file mode 100644 index 886e70da5..000000000 --- a/src/libutil/tests/config.cc +++ /dev/null @@ -1,295 +0,0 @@ -#include "config.hh" -#include "args.hh" - -#include <sstream> -#include <gtest/gtest.h> -#include <nlohmann/json.hpp> - -namespace nix { - - /* ---------------------------------------------------------------------------- - * Config - * --------------------------------------------------------------------------*/ - - TEST(Config, setUndefinedSetting) { - Config config; - ASSERT_EQ(config.set("undefined-key", "value"), false); - } - - TEST(Config, setDefinedSetting) { - Config config; - std::string value; - Setting<std::string> foo{&config, value, "name-of-the-setting", "description"}; - ASSERT_EQ(config.set("name-of-the-setting", "value"), true); - } - - TEST(Config, getDefinedSetting) { - Config config; - std::string value; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> foo{&config, value, "name-of-the-setting", "description"}; - - config.getSettings(settings, /* overriddenOnly = */ false); - const auto iter = settings.find("name-of-the-setting"); - ASSERT_NE(iter, settings.end()); - ASSERT_EQ(iter->second.value, ""); - ASSERT_EQ(iter->second.description, "description\n"); - } - - TEST(Config, getDefinedOverriddenSettingNotSet) { - Config config; - std::string value; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> foo{&config, value, "name-of-the-setting", "description"}; - - config.getSettings(settings, /* overriddenOnly = */ true); - const auto e = settings.find("name-of-the-setting"); - ASSERT_EQ(e, settings.end()); - } - - TEST(Config, getDefinedSettingSet1) { - Config config; - std::string value; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> setting{&config, value, "name-of-the-setting", "description"}; - - setting.assign("value"); - - config.getSettings(settings, /* overriddenOnly = */ false); - const auto iter = settings.find("name-of-the-setting"); - ASSERT_NE(iter, settings.end()); - ASSERT_EQ(iter->second.value, "value"); - ASSERT_EQ(iter->second.description, "description\n"); - } - - TEST(Config, getDefinedSettingSet2) { - Config config; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> setting{&config, "", "name-of-the-setting", "description"}; - - ASSERT_TRUE(config.set("name-of-the-setting", "value")); - - config.getSettings(settings, /* overriddenOnly = */ false); - const auto e = settings.find("name-of-the-setting"); - ASSERT_NE(e, settings.end()); - ASSERT_EQ(e->second.value, "value"); - ASSERT_EQ(e->second.description, "description\n"); - } - - TEST(Config, addSetting) { - class TestSetting : public AbstractSetting { - public: - TestSetting() : AbstractSetting("test", "test", {}) {} - void set(const std::string & value, bool append) override {} - std::string to_string() const override { return {}; } - bool isAppendable() override { return false; } - }; - - Config config; - TestSetting setting; - - ASSERT_FALSE(config.set("test", "value")); - config.addSetting(&setting); - ASSERT_TRUE(config.set("test", "value")); - ASSERT_FALSE(config.set("extra-test", "value")); - } - - TEST(Config, withInitialValue) { - const StringMap initials = { - { "key", "value" }, - }; - Config config(initials); - - { - std::map<std::string, Config::SettingInfo> settings; - config.getSettings(settings, /* overriddenOnly = */ false); - ASSERT_EQ(settings.find("key"), settings.end()); - } - - Setting<std::string> setting{&config, "default-value", "key", "description"}; - - { - std::map<std::string, Config::SettingInfo> settings; - config.getSettings(settings, /* overriddenOnly = */ false); - ASSERT_EQ(settings["key"].value, "value"); - } - } - - TEST(Config, resetOverridden) { - Config config; - config.resetOverridden(); - } - - TEST(Config, resetOverriddenWithSetting) { - Config config; - Setting<std::string> setting{&config, "", "name-of-the-setting", "description"}; - - { - std::map<std::string, Config::SettingInfo> settings; - - setting.set("foo"); - ASSERT_EQ(setting.get(), "foo"); - config.getSettings(settings, /* overriddenOnly = */ true); - ASSERT_TRUE(settings.empty()); - } - - { - std::map<std::string, Config::SettingInfo> settings; - - setting.override("bar"); - ASSERT_TRUE(setting.overridden); - ASSERT_EQ(setting.get(), "bar"); - config.getSettings(settings, /* overriddenOnly = */ true); - ASSERT_FALSE(settings.empty()); - } - - { - std::map<std::string, Config::SettingInfo> settings; - - config.resetOverridden(); - ASSERT_FALSE(setting.overridden); - config.getSettings(settings, /* overriddenOnly = */ true); - ASSERT_TRUE(settings.empty()); - } - } - - TEST(Config, toJSONOnEmptyConfig) { - ASSERT_EQ(Config().toJSON().dump(), "{}"); - } - - TEST(Config, toJSONOnNonEmptyConfig) { - using nlohmann::literals::operator "" _json; - Config config; - Setting<std::string> setting{ - &config, - "", - "name-of-the-setting", - "description", - }; - setting.assign("value"); - - ASSERT_EQ(config.toJSON(), - R"#({ - "name-of-the-setting": { - "aliases": [], - "defaultValue": "", - "description": "description\n", - "documentDefault": true, - "value": "value", - "experimentalFeature": null - } - })#"_json); - } - - TEST(Config, toJSONOnNonEmptyConfigWithExperimentalSetting) { - using nlohmann::literals::operator "" _json; - Config config; - Setting<std::string> setting{ - &config, - "", - "name-of-the-setting", - "description", - {}, - true, - Xp::Flakes, - }; - setting.assign("value"); - - ASSERT_EQ(config.toJSON(), - R"#({ - "name-of-the-setting": { - "aliases": [], - "defaultValue": "", - "description": "description\n", - "documentDefault": true, - "value": "value", - "experimentalFeature": "flakes" - } - })#"_json); - } - - TEST(Config, setSettingAlias) { - Config config; - Setting<std::string> setting{&config, "", "some-int", "best number", { "another-int" }}; - ASSERT_TRUE(config.set("some-int", "1")); - ASSERT_EQ(setting.get(), "1"); - ASSERT_TRUE(config.set("another-int", "2")); - ASSERT_EQ(setting.get(), "2"); - ASSERT_TRUE(config.set("some-int", "3")); - ASSERT_EQ(setting.get(), "3"); - } - - /* FIXME: The reapplyUnknownSettings method doesn't seem to do anything - * useful (these days). Whenever we add a new setting to Config the - * unknown settings are always considered. In which case is this function - * actually useful? Is there some way to register a Setting without calling - * addSetting? */ - TEST(Config, DISABLED_reapplyUnknownSettings) { - Config config; - ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue")); - Setting<std::string> setting{&config, "default", "name-of-the-setting", "description"}; - ASSERT_EQ(setting.get(), "default"); - config.reapplyUnknownSettings(); - ASSERT_EQ(setting.get(), "unknownvalue"); - } - - TEST(Config, applyConfigEmpty) { - Config config; - std::map<std::string, Config::SettingInfo> settings; - config.applyConfig(""); - config.getSettings(settings); - ASSERT_TRUE(settings.empty()); - } - - TEST(Config, applyConfigEmptyWithComment) { - Config config; - std::map<std::string, Config::SettingInfo> settings; - config.applyConfig("# just a comment"); - config.getSettings(settings); - ASSERT_TRUE(settings.empty()); - } - - TEST(Config, applyConfigAssignment) { - Config config; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> setting{&config, "", "name-of-the-setting", "description"}; - config.applyConfig( - "name-of-the-setting = value-from-file #useful comment\n" - "# name-of-the-setting = foo\n" - ); - config.getSettings(settings); - ASSERT_FALSE(settings.empty()); - ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file"); - } - - TEST(Config, applyConfigWithReassignedSetting) { - Config config; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> setting{&config, "", "name-of-the-setting", "description"}; - config.applyConfig( - "name-of-the-setting = first-value\n" - "name-of-the-setting = second-value\n" - ); - config.getSettings(settings); - ASSERT_FALSE(settings.empty()); - ASSERT_EQ(settings["name-of-the-setting"].value, "second-value"); - } - - TEST(Config, applyConfigFailsOnMissingIncludes) { - Config config; - std::map<std::string, Config::SettingInfo> settings; - Setting<std::string> setting{&config, "", "name-of-the-setting", "description"}; - - ASSERT_THROW(config.applyConfig( - "name-of-the-setting = value-from-file\n" - "# name-of-the-setting = foo\n" - "include /nix/store/does/not/exist.nix" - ), Error); - } - - TEST(Config, applyConfigInvalidThrows) { - Config config; - ASSERT_THROW(config.applyConfig("value == key"), UsageError); - ASSERT_THROW(config.applyConfig("value "), UsageError); - } -} diff --git a/src/libutil/tests/git.cc b/src/libutil/tests/git.cc deleted file mode 100644 index 5b5715fc2..000000000 --- a/src/libutil/tests/git.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include "git.hh" -#include <gtest/gtest.h> - -namespace nix { - - TEST(GitLsRemote, parseSymrefLineWithReference) { - auto line = "ref: refs/head/main HEAD"; - auto res = git::parseLsRemoteLine(line); - ASSERT_TRUE(res.has_value()); - ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic); - ASSERT_EQ(res->target, "refs/head/main"); - ASSERT_EQ(res->reference, "HEAD"); - } - - TEST(GitLsRemote, parseSymrefLineWithNoReference) { - auto line = "ref: refs/head/main"; - auto res = git::parseLsRemoteLine(line); - ASSERT_TRUE(res.has_value()); - ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic); - ASSERT_EQ(res->target, "refs/head/main"); - ASSERT_EQ(res->reference, std::nullopt); - } - - TEST(GitLsRemote, parseObjectRefLine) { - auto line = "abc123 refs/head/main"; - auto res = git::parseLsRemoteLine(line); - ASSERT_TRUE(res.has_value()); - ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Object); - ASSERT_EQ(res->target, "abc123"); - ASSERT_EQ(res->reference, "refs/head/main"); - } -} - diff --git a/src/libutil/tests/hash.cc b/src/libutil/tests/hash.cc deleted file mode 100644 index e4e928b3b..000000000 --- a/src/libutil/tests/hash.cc +++ /dev/null @@ -1,95 +0,0 @@ -#include <regex> - -#include <nlohmann/json.hpp> -#include <gtest/gtest.h> -#include <rapidcheck/gtest.h> - -#include <hash.hh> - -#include "tests/hash.hh" - -namespace nix { - - /* ---------------------------------------------------------------------------- - * hashString - * --------------------------------------------------------------------------*/ - - TEST(hashString, testKnownMD5Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc1321 - auto s1 = ""; - auto hash = hashString(HashType::htMD5, s1); - ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e"); - } - - TEST(hashString, testKnownMD5Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc1321 - auto s2 = "abc"; - auto hash = hashString(HashType::htMD5, s2); - ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72"); - } - - TEST(hashString, testKnownSHA1Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc3174 - auto s = "abc"; - auto hash = hashString(HashType::htSHA1, s); - ASSERT_EQ(hash.to_string(Base::Base16, true),"sha1:a9993e364706816aba3e25717850c26c9cd0d89d"); - } - - TEST(hashString, testKnownSHA1Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc3174 - auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - auto hash = hashString(HashType::htSHA1, s); - ASSERT_EQ(hash.to_string(Base::Base16, true),"sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1"); - } - - TEST(hashString, testKnownSHA256Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abc"; - - auto hash = hashString(HashType::htSHA256, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); - } - - TEST(hashString, testKnownSHA256Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - auto hash = hashString(HashType::htSHA256, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); - } - - TEST(hashString, testKnownSHA512Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abc"; - auto hash = hashString(HashType::htSHA512, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9" - "7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd" - "454d4423643ce80e2a9ac94fa54ca49f"); - } - - TEST(hashString, testKnownSHA512Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; - - auto hash = hashString(HashType::htSHA512, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1" - "7299aeadb6889018501d289e4900f7e4331b99dec4b5433a" - "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); -} - -} diff --git a/src/libutil/tests/hash.hh b/src/libutil/tests/hash.hh deleted file mode 100644 index 1f9fa59ae..000000000 --- a/src/libutil/tests/hash.hh +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -///@file - -#include <rapidcheck/gen/Arbitrary.h> - -#include <hash.hh> - -namespace rc { -using namespace nix; - -template<> -struct Arbitrary<Hash> { - static Gen<Hash> arbitrary(); -}; - -} diff --git a/src/libutil/tests/hilite.cc b/src/libutil/tests/hilite.cc deleted file mode 100644 index 1ff5980d5..000000000 --- a/src/libutil/tests/hilite.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "hilite.hh" - -#include <gtest/gtest.h> - -namespace nix { -/* ----------- tests for fmt.hh -------------------------------------------------*/ - - TEST(hiliteMatches, noHighlight) { - ASSERT_STREQ(hiliteMatches("Hello, world!", std::vector<std::smatch>(), "(", ")").c_str(), "Hello, world!"); - } - - TEST(hiliteMatches, simpleHighlight) { - std::string str = "Hello, world!"; - std::regex re = std::regex("world"); - auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); - ASSERT_STREQ( - hiliteMatches(str, matches, "(", ")").c_str(), - "Hello, (world)!" - ); - } - - TEST(hiliteMatches, multipleMatches) { - std::string str = "Hello, world, world, world, world, world, world, Hello!"; - std::regex re = std::regex("world"); - auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); - ASSERT_STREQ( - hiliteMatches(str, matches, "(", ")").c_str(), - "Hello, (world), (world), (world), (world), (world), (world), Hello!" - ); - } - - TEST(hiliteMatches, overlappingMatches) { - std::string str = "world, Hello, world, Hello, world, Hello, world, Hello, world!"; - std::regex re = std::regex("Hello, world"); - std::regex re2 = std::regex("world, Hello"); - auto v = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); - for(auto it = std::sregex_iterator(str.begin(), str.end(), re2); it != std::sregex_iterator(); ++it) { - v.push_back(*it); - } - ASSERT_STREQ( - hiliteMatches(str, v, "(", ")").c_str(), - "(world, Hello, world, Hello, world, Hello, world, Hello, world)!" - ); - } - - TEST(hiliteMatches, complexOverlappingMatches) { - std::string str = "legacyPackages.x86_64-linux.git-crypt"; - std::vector regexes = { - std::regex("t-cry"), - std::regex("ux\\.git-cry"), - std::regex("git-c"), - std::regex("pt"), - }; - std::vector<std::smatch> matches; - for(auto regex : regexes) - { - for(auto it = std::sregex_iterator(str.begin(), str.end(), regex); it != std::sregex_iterator(); ++it) { - matches.push_back(*it); - } - } - ASSERT_STREQ( - hiliteMatches(str, matches, "(", ")").c_str(), - "legacyPackages.x86_64-lin(ux.git-crypt)" - ); - } -} diff --git a/src/libutil/tests/local.mk b/src/libutil/tests/local.mk deleted file mode 100644 index 167915439..000000000 --- a/src/libutil/tests/local.mk +++ /dev/null @@ -1,29 +0,0 @@ -check: libutil-tests_RUN - -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_INSTALL_DIR := - -libutil-tests_SOURCES := $(wildcard $(d)/*.cc) - -libutil-tests_CXXFLAGS += -I src/libutil - -libutil-tests_LIBS = libutil - -libutil-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) diff --git a/src/libutil/tests/logging.cc b/src/libutil/tests/logging.cc deleted file mode 100644 index 2ffdc2e9b..000000000 --- a/src/libutil/tests/logging.cc +++ /dev/null @@ -1,370 +0,0 @@ -#if 0 - -#include "logging.hh" -#include "nixexpr.hh" -#include "util.hh" -#include <fstream> - -#include <gtest/gtest.h> - -namespace nix { - - /* ---------------------------------------------------------------------------- - * logEI - * --------------------------------------------------------------------------*/ - - const char *test_file = - "previous line of code\n" - "this is the problem line of code\n" - "next line of code\n"; - const char *one_liner = - "this is the other problem line of code"; - - TEST(logEI, catpuresBasicProperties) { - - MakeError(TestError, Error); - ErrorInfo::programName = std::optional("error-unit-test"); - - try { - throw TestError("an error for testing purposes"); - } catch (Error &e) { - testing::internal::CaptureStderr(); - logger->logEI(e.info()); - auto str = testing::internal::GetCapturedStderr(); - - ASSERT_STREQ(str.c_str(),"\x1B[31;1merror:\x1B[0m\x1B[34;1m --- TestError --- error-unit-test\x1B[0m\nan error for testing purposes\n"); - } - } - - TEST(logEI, jsonOutput) { - SymbolTable testTable; - auto problem_file = testTable.create("random.nix"); - testing::internal::CaptureStderr(); - - makeJSONLogger(*logger)->logEI({ - .name = "error name", - .msg = hintfmt("this hint has %1% templated %2%!!", - "yellow", - "values"), - .errPos = Pos(foFile, problem_file, 02, 13) - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "@nix {\"action\":\"msg\",\"column\":13,\"file\":\"random.nix\",\"level\":0,\"line\":2,\"msg\":\"\\u001b[31;1merror:\\u001b[0m\\u001b[34;1m --- error name --- error-unit-test\\u001b[0m\\n\\u001b[34;1mat: \\u001b[33;1m(2:13)\\u001b[34;1m in file: \\u001b[0mrandom.nix\\n\\nerror without any code lines.\\n\\nthis hint has \\u001b[33;1myellow\\u001b[0m templated \\u001b[33;1mvalues\\u001b[0m!!\",\"raw_msg\":\"this hint has \\u001b[33;1myellow\\u001b[0m templated \\u001b[33;1mvalues\\u001b[0m!!\"}\n"); - } - - TEST(logEI, appendingHintsToPreviousError) { - - MakeError(TestError, Error); - ErrorInfo::programName = std::optional("error-unit-test"); - - try { - auto e = Error("initial error"); - throw TestError(e.info()); - } catch (Error &e) { - ErrorInfo ei = e.info(); - ei.msg = hintfmt("%s; subsequent error message.", normaltxt(e.info().msg.str())); - - testing::internal::CaptureStderr(); - logger->logEI(ei); - auto str = testing::internal::GetCapturedStderr(); - - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- TestError --- error-unit-test\x1B[0m\ninitial error; subsequent error message.\n"); - } - - } - - TEST(logEI, picksUpSysErrorExitCode) { - - MakeError(TestError, Error); - ErrorInfo::programName = std::optional("error-unit-test"); - - try { - auto x = readFile(-1); - } - catch (SysError &e) { - testing::internal::CaptureStderr(); - logError(e.info()); - auto str = testing::internal::GetCapturedStderr(); - - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- SysError --- error-unit-test\x1B[0m\nstatting file: \x1B[33;1mBad file descriptor\x1B[0m\n"); - } - } - - TEST(logEI, loggingErrorOnInfoLevel) { - testing::internal::CaptureStderr(); - - logger->logEI({ .level = lvlInfo, - .name = "Info name", - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[32;1minfo:\x1B[0m\x1B[34;1m --- Info name --- error-unit-test\x1B[0m\nInfo description\n"); - } - - TEST(logEI, loggingErrorOnTalkativeLevel) { - verbosity = lvlTalkative; - - testing::internal::CaptureStderr(); - - logger->logEI({ .level = lvlTalkative, - .name = "Talkative name", - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[32;1mtalk:\x1B[0m\x1B[34;1m --- Talkative name --- error-unit-test\x1B[0m\nTalkative description\n"); - } - - TEST(logEI, loggingErrorOnChattyLevel) { - verbosity = lvlChatty; - - testing::internal::CaptureStderr(); - - logger->logEI({ .level = lvlChatty, - .name = "Chatty name", - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[32;1mchat:\x1B[0m\x1B[34;1m --- Chatty name --- error-unit-test\x1B[0m\nTalkative description\n"); - } - - TEST(logEI, loggingErrorOnDebugLevel) { - verbosity = lvlDebug; - - testing::internal::CaptureStderr(); - - logger->logEI({ .level = lvlDebug, - .name = "Debug name", - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[33;1mdebug:\x1B[0m\x1B[34;1m --- Debug name --- error-unit-test\x1B[0m\nDebug description\n"); - } - - TEST(logEI, loggingErrorOnVomitLevel) { - verbosity = lvlVomit; - - testing::internal::CaptureStderr(); - - logger->logEI({ .level = lvlVomit, - .name = "Vomit name", - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[32;1mvomit:\x1B[0m\x1B[34;1m --- Vomit name --- error-unit-test\x1B[0m\nVomit description\n"); - } - - /* ---------------------------------------------------------------------------- - * logError - * --------------------------------------------------------------------------*/ - - TEST(logError, logErrorWithoutHintOrCode) { - testing::internal::CaptureStderr(); - - logError({ - .name = "name", - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- name --- error-unit-test\x1B[0m\nerror description\n"); - } - - TEST(logError, logErrorWithPreviousAndNextLinesOfCode) { - SymbolTable testTable; - auto problem_file = testTable.create(test_file); - - testing::internal::CaptureStderr(); - - logError({ - .name = "error name", - .msg = hintfmt("this hint has %1% templated %2%!!", - "yellow", - "values"), - .errPos = Pos(foString, problem_file, 02, 13), - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- error name --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m from string\x1B[0m\n\nerror with code lines\n\n 1| previous line of code\n 2| this is the problem line of code\n | \x1B[31;1m^\x1B[0m\n 3| next line of code\n\nthis hint has \x1B[33;1myellow\x1B[0m templated \x1B[33;1mvalues\x1B[0m!!\n"); - } - - TEST(logError, logErrorWithInvalidFile) { - SymbolTable testTable; - auto problem_file = testTable.create("invalid filename"); - testing::internal::CaptureStderr(); - - logError({ - .name = "error name", - .msg = hintfmt("this hint has %1% templated %2%!!", - "yellow", - "values"), - .errPos = Pos(foFile, problem_file, 02, 13) - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- error name --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m in file: \x1B[0minvalid filename\n\nerror without any code lines.\n\nthis hint has \x1B[33;1myellow\x1B[0m templated \x1B[33;1mvalues\x1B[0m!!\n"); - } - - TEST(logError, logErrorWithOnlyHintAndName) { - testing::internal::CaptureStderr(); - - logError({ - .name = "error name", - .msg = hintfmt("hint %1%", "only"), - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- error name --- error-unit-test\x1B[0m\nhint \x1B[33;1monly\x1B[0m\n"); - - } - - /* ---------------------------------------------------------------------------- - * logWarning - * --------------------------------------------------------------------------*/ - - TEST(logWarning, logWarningWithNameDescriptionAndHint) { - testing::internal::CaptureStderr(); - - logWarning({ - .name = "name", - .msg = hintfmt("there was a %1%", "warning"), - }); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[33;1mwarning:\x1B[0m\x1B[34;1m --- name --- error-unit-test\x1B[0m\nwarning description\n\nthere was a \x1B[33;1mwarning\x1B[0m\n"); - } - - TEST(logWarning, logWarningWithFileLineNumAndCode) { - - SymbolTable testTable; - auto problem_file = testTable.create(test_file); - - testing::internal::CaptureStderr(); - - logWarning({ - .name = "warning name", - .msg = hintfmt("this hint has %1% templated %2%!!", - "yellow", - "values"), - .errPos = Pos(foStdin, problem_file, 2, 13), - }); - - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[33;1mwarning:\x1B[0m\x1B[34;1m --- warning name --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m from stdin\x1B[0m\n\nwarning description\n\n 1| previous line of code\n 2| this is the problem line of code\n | \x1B[31;1m^\x1B[0m\n 3| next line of code\n\nthis hint has \x1B[33;1myellow\x1B[0m templated \x1B[33;1mvalues\x1B[0m!!\n"); - } - - /* ---------------------------------------------------------------------------- - * traces - * --------------------------------------------------------------------------*/ - - TEST(addTrace, showTracesWithShowTrace) { - SymbolTable testTable; - auto problem_file = testTable.create(test_file); - auto oneliner_file = testTable.create(one_liner); - auto invalidfilename = testTable.create("invalid filename"); - - auto e = AssertionError(ErrorInfo { - .name = "wat", - .msg = hintfmt("it has been %1% days since our last error", "zero"), - .errPos = Pos(foString, problem_file, 2, 13), - }); - - e.addTrace(Pos(foStdin, oneliner_file, 1, 19), "while trying to compute %1%", 42); - e.addTrace(std::nullopt, "while doing something without a %1%", "pos"); - e.addTrace(Pos(foFile, invalidfilename, 100, 1), "missing %s", "nix file"); - - testing::internal::CaptureStderr(); - - loggerSettings.showTrace.assign(true); - - logError(e.info()); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- AssertionError --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m from string\x1B[0m\n\nshow-traces\n\n 1| previous line of code\n 2| this is the problem line of code\n | \x1B[31;1m^\x1B[0m\n 3| next line of code\n\nit has been \x1B[33;1mzero\x1B[0m days since our last error\n\x1B[34;1m---- show-trace ----\x1B[0m\n\x1B[34;1mtrace: \x1B[0mwhile trying to compute \x1B[33;1m42\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(1:19)\x1B[34;1m from stdin\x1B[0m\n\n 1| this is the other problem line of code\n | \x1B[31;1m^\x1B[0m\n\n\x1B[34;1mtrace: \x1B[0mwhile doing something without a \x1B[33;1mpos\x1B[0m\n\x1B[34;1mtrace: \x1B[0mmissing \x1B[33;1mnix file\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(100:1)\x1B[34;1m in file: \x1B[0minvalid filename\n"); - } - - TEST(addTrace, hideTracesWithoutShowTrace) { - SymbolTable testTable; - auto problem_file = testTable.create(test_file); - auto oneliner_file = testTable.create(one_liner); - auto invalidfilename = testTable.create("invalid filename"); - - auto e = AssertionError(ErrorInfo { - .name = "wat", - .msg = hintfmt("it has been %1% days since our last error", "zero"), - .errPos = Pos(foString, problem_file, 2, 13), - }); - - e.addTrace(Pos(foStdin, oneliner_file, 1, 19), "while trying to compute %1%", 42); - e.addTrace(std::nullopt, "while doing something without a %1%", "pos"); - e.addTrace(Pos(foFile, invalidfilename, 100, 1), "missing %s", "nix file"); - - testing::internal::CaptureStderr(); - - loggerSettings.showTrace.assign(false); - - logError(e.info()); - - auto str = testing::internal::GetCapturedStderr(); - ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- AssertionError --- error-unit-test\x1B[0m\n\x1B[34;1mat: \x1B[33;1m(2:13)\x1B[34;1m from string\x1B[0m\n\nhide traces\n\n 1| previous line of code\n 2| this is the problem line of code\n | \x1B[31;1m^\x1B[0m\n 3| next line of code\n\nit has been \x1B[33;1mzero\x1B[0m days since our last error\n"); - } - - - /* ---------------------------------------------------------------------------- - * hintfmt - * --------------------------------------------------------------------------*/ - - TEST(hintfmt, percentStringWithoutArgs) { - - const char *teststr = "this is 100%s correct!"; - - ASSERT_STREQ( - hintfmt(teststr).str().c_str(), - teststr); - - } - - TEST(hintfmt, fmtToHintfmt) { - - ASSERT_STREQ( - hintfmt(fmt("the color of this this text is %1%", "not yellow")).str().c_str(), - "the color of this this text is not yellow"); - - } - - TEST(hintfmt, tooFewArguments) { - - ASSERT_STREQ( - hintfmt("only one arg %1% %2%", "fulfilled").str().c_str(), - "only one arg " ANSI_WARNING "fulfilled" ANSI_NORMAL " "); - - } - - TEST(hintfmt, tooManyArguments) { - - ASSERT_STREQ( - hintfmt("what about this %1% %2%", "%3%", "one", "two").str().c_str(), - "what about this " ANSI_WARNING "%3%" ANSI_NORMAL " " ANSI_YELLOW "one" ANSI_NORMAL); - - } - - /* ---------------------------------------------------------------------------- - * ErrPos - * --------------------------------------------------------------------------*/ - - TEST(errpos, invalidPos) { - - // contains an invalid symbol, which we should not dereference! - Pos invalid; - - // constructing without access violation. - ErrPos ep(invalid); - - // assignment without access violation. - ep = invalid; - - } - -} - -#endif diff --git a/src/libutil/tests/lru-cache.cc b/src/libutil/tests/lru-cache.cc deleted file mode 100644 index 091d3d5ed..000000000 --- a/src/libutil/tests/lru-cache.cc +++ /dev/null @@ -1,130 +0,0 @@ -#include "lru-cache.hh" -#include <gtest/gtest.h> - -namespace nix { - - /* ---------------------------------------------------------------------------- - * size - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, sizeOfEmptyCacheIsZero) { - LRUCache<std::string, std::string> c(10); - ASSERT_EQ(c.size(), 0); - } - - TEST(LRUCache, sizeOfSingleElementCacheIsOne) { - LRUCache<std::string, std::string> c(10); - c.upsert("foo", "bar"); - ASSERT_EQ(c.size(), 1); - } - - /* ---------------------------------------------------------------------------- - * upsert / get - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, getFromEmptyCache) { - LRUCache<std::string, std::string> c(10); - auto val = c.get("x"); - ASSERT_EQ(val.has_value(), false); - } - - TEST(LRUCache, getExistingValue) { - LRUCache<std::string, std::string> c(10); - c.upsert("foo", "bar"); - auto val = c.get("foo"); - ASSERT_EQ(val, "bar"); - } - - TEST(LRUCache, getNonExistingValueFromNonEmptyCache) { - LRUCache<std::string, std::string> c(10); - c.upsert("foo", "bar"); - auto val = c.get("another"); - ASSERT_EQ(val.has_value(), false); - } - - TEST(LRUCache, upsertOnZeroCapacityCache) { - LRUCache<std::string, std::string> c(0); - c.upsert("foo", "bar"); - auto val = c.get("foo"); - ASSERT_EQ(val.has_value(), false); - } - - TEST(LRUCache, updateExistingValue) { - LRUCache<std::string, std::string> c(1); - c.upsert("foo", "bar"); - - auto val = c.get("foo"); - ASSERT_EQ(val.value_or("error"), "bar"); - ASSERT_EQ(c.size(), 1); - - c.upsert("foo", "changed"); - val = c.get("foo"); - ASSERT_EQ(val.value_or("error"), "changed"); - ASSERT_EQ(c.size(), 1); - } - - TEST(LRUCache, overwriteOldestWhenCapacityIsReached) { - LRUCache<std::string, std::string> c(3); - c.upsert("one", "eins"); - c.upsert("two", "zwei"); - c.upsert("three", "drei"); - - ASSERT_EQ(c.size(), 3); - ASSERT_EQ(c.get("one").value_or("error"), "eins"); - - // exceed capacity - c.upsert("another", "whatever"); - - ASSERT_EQ(c.size(), 3); - // Retrieving "one" makes it the most recent element thus - // two will be the oldest one and thus replaced. - ASSERT_EQ(c.get("two").has_value(), false); - ASSERT_EQ(c.get("another").value(), "whatever"); - } - - /* ---------------------------------------------------------------------------- - * clear - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, clearEmptyCache) { - LRUCache<std::string, std::string> c(10); - c.clear(); - ASSERT_EQ(c.size(), 0); - } - - TEST(LRUCache, clearNonEmptyCache) { - LRUCache<std::string, std::string> c(10); - c.upsert("one", "eins"); - c.upsert("two", "zwei"); - c.upsert("three", "drei"); - ASSERT_EQ(c.size(), 3); - c.clear(); - ASSERT_EQ(c.size(), 0); - } - - /* ---------------------------------------------------------------------------- - * erase - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, eraseFromEmptyCache) { - LRUCache<std::string, std::string> c(10); - ASSERT_EQ(c.erase("foo"), false); - ASSERT_EQ(c.size(), 0); - } - - TEST(LRUCache, eraseMissingFromNonEmptyCache) { - LRUCache<std::string, std::string> c(10); - c.upsert("one", "eins"); - ASSERT_EQ(c.erase("foo"), false); - ASSERT_EQ(c.size(), 1); - ASSERT_EQ(c.get("one").value_or("error"), "eins"); - } - - TEST(LRUCache, eraseFromNonEmptyCache) { - LRUCache<std::string, std::string> c(10); - c.upsert("one", "eins"); - ASSERT_EQ(c.erase("one"), true); - ASSERT_EQ(c.size(), 0); - ASSERT_EQ(c.get("one").value_or("empty"), "empty"); - } -} diff --git a/src/libutil/tests/pool.cc b/src/libutil/tests/pool.cc deleted file mode 100644 index 127e42dda..000000000 --- a/src/libutil/tests/pool.cc +++ /dev/null @@ -1,127 +0,0 @@ -#include "pool.hh" -#include <gtest/gtest.h> - -namespace nix { - - struct TestResource - { - - TestResource() { - static int counter = 0; - num = counter++; - } - - int dummyValue = 1; - bool good = true; - int num; - }; - - /* ---------------------------------------------------------------------------- - * Pool - * --------------------------------------------------------------------------*/ - - TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity) { - auto isGood = [](const ref<TestResource> & r) { return r->good; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - - ASSERT_EQ(pool.count(), 0); - ASSERT_EQ(pool.capacity(), 1); - } - - TEST(Pool, freshPoolCanGetAResource) { - auto isGood = [](const ref<TestResource> & r) { return r->good; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - ASSERT_EQ(pool.count(), 0); - - TestResource r = *(pool.get()); - - ASSERT_EQ(pool.count(), 1); - ASSERT_EQ(pool.capacity(), 1); - ASSERT_EQ(r.dummyValue, 1); - ASSERT_EQ(r.good, true); - } - - TEST(Pool, capacityCanBeIncremented) { - auto isGood = [](const ref<TestResource> & r) { return r->good; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - ASSERT_EQ(pool.capacity(), 1); - pool.incCapacity(); - ASSERT_EQ(pool.capacity(), 2); - } - - TEST(Pool, capacityCanBeDecremented) { - auto isGood = [](const ref<TestResource> & r) { return r->good; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - ASSERT_EQ(pool.capacity(), 1); - pool.decCapacity(); - ASSERT_EQ(pool.capacity(), 0); - } - - TEST(Pool, flushBadDropsOutOfScopeResources) { - auto isGood = [](const ref<TestResource> & r) { return false; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - - { - auto _r = pool.get(); - ASSERT_EQ(pool.count(), 1); - } - - pool.flushBad(); - ASSERT_EQ(pool.count(), 0); - } - - // Test that the resources we allocate are being reused when they are still good. - TEST(Pool, reuseResource) { - auto isGood = [](const ref<TestResource> & r) { return true; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - - // Compare the instance counter between the two handles. We expect them to be equal - // as the pool should hand out the same (still) good one again. - int counter = -1; - { - Pool<TestResource>::Handle h = pool.get(); - counter = h->num; - } // the first handle goes out of scope - - { // the second handle should contain the same resource (with the same counter value) - Pool<TestResource>::Handle h = pool.get(); - ASSERT_EQ(h->num, counter); - } - } - - // Test that the resources we allocate are being thrown away when they are no longer good. - TEST(Pool, badResourceIsNotReused) { - auto isGood = [](const ref<TestResource> & r) { return false; }; - auto createResource = []() { return make_ref<TestResource>(); }; - - Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood); - - // Compare the instance counter between the two handles. We expect them - // to *not* be equal as the pool should hand out a new instance after - // the first one was returned. - int counter = -1; - { - Pool<TestResource>::Handle h = pool.get(); - counter = h->num; - } // the first handle goes out of scope - - { - // the second handle should contain a different resource (with a - //different counter value) - Pool<TestResource>::Handle h = pool.get(); - ASSERT_NE(h->num, counter); - } - } -} diff --git a/src/libutil/tests/references.cc b/src/libutil/tests/references.cc deleted file mode 100644 index a517d9aa1..000000000 --- a/src/libutil/tests/references.cc +++ /dev/null @@ -1,46 +0,0 @@ -#include "references.hh" -#include <gtest/gtest.h> - -namespace nix { - -using std::string; - -struct RewriteParams { - string originalString, finalString; - StringMap rewrites; - - friend std::ostream& operator<<(std::ostream& os, const RewriteParams& bar) { - StringSet strRewrites; - for (auto & [from, to] : bar.rewrites) - strRewrites.insert(from + "->" + to); - return os << - "OriginalString: " << bar.originalString << std::endl << - "Rewrites: " << concatStringsSep(",", strRewrites) << std::endl << - "Expected result: " << bar.finalString; - } -}; - -class RewriteTest : public ::testing::TestWithParam<RewriteParams> { -}; - -TEST_P(RewriteTest, IdentityRewriteIsIdentity) { - RewriteParams param = GetParam(); - StringSink rewritten; - auto rewriter = RewritingSink(param.rewrites, rewritten); - rewriter(param.originalString); - rewriter.flush(); - ASSERT_EQ(rewritten.s, param.finalString); -} - -INSTANTIATE_TEST_CASE_P( - references, - RewriteTest, - ::testing::Values( - RewriteParams{ "foooo", "baroo", {{"foo", "bar"}, {"bar", "baz"}}}, - RewriteParams{ "foooo", "bazoo", {{"fou", "bar"}, {"foo", "baz"}}}, - RewriteParams{ "foooo", "foooo", {}} - ) -); - -} - diff --git a/src/libutil/tests/suggestions.cc b/src/libutil/tests/suggestions.cc deleted file mode 100644 index 279994abc..000000000 --- a/src/libutil/tests/suggestions.cc +++ /dev/null @@ -1,43 +0,0 @@ -#include "suggestions.hh" -#include <gtest/gtest.h> - -namespace nix { - - struct LevenshteinDistanceParam { - std::string s1, s2; - int distance; - }; - - class LevenshteinDistanceTest : - public testing::TestWithParam<LevenshteinDistanceParam> { - }; - - TEST_P(LevenshteinDistanceTest, CorrectlyComputed) { - auto params = GetParam(); - - ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance); - ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance); - } - - INSTANTIATE_TEST_SUITE_P(LevenshteinDistance, LevenshteinDistanceTest, - testing::Values( - LevenshteinDistanceParam{"foo", "foo", 0}, - LevenshteinDistanceParam{"foo", "", 3}, - LevenshteinDistanceParam{"", "", 0}, - LevenshteinDistanceParam{"foo", "fo", 1}, - LevenshteinDistanceParam{"foo", "oo", 1}, - LevenshteinDistanceParam{"foo", "fao", 1}, - LevenshteinDistanceParam{"foo", "abc", 3} - ) - ); - - TEST(Suggestions, Trim) { - auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo"); - auto onlyOne = suggestions.trim(1); - ASSERT_EQ(onlyOne.suggestions.size(), 1); - ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo"); - - auto closest = suggestions.trim(999, 2); - ASSERT_EQ(closest.suggestions.size(), 3); - } -} diff --git a/src/libutil/tests/tests.cc b/src/libutil/tests/tests.cc deleted file mode 100644 index f3c1e8248..000000000 --- a/src/libutil/tests/tests.cc +++ /dev/null @@ -1,659 +0,0 @@ -#include "util.hh" -#include "types.hh" - -#include <limits.h> -#include <gtest/gtest.h> - -#include <numeric> - -namespace nix { - -/* ----------- tests for util.hh ------------------------------------------------*/ - - /* ---------------------------------------------------------------------------- - * absPath - * --------------------------------------------------------------------------*/ - - TEST(absPath, doesntChangeRoot) { - auto p = absPath("/"); - - ASSERT_EQ(p, "/"); - } - - - - - TEST(absPath, turnsEmptyPathIntoCWD) { - char cwd[PATH_MAX+1]; - auto p = absPath(""); - - ASSERT_EQ(p, getcwd((char*)&cwd, PATH_MAX)); - } - - TEST(absPath, usesOptionalBasePathWhenGiven) { - char _cwd[PATH_MAX+1]; - char* cwd = getcwd((char*)&_cwd, PATH_MAX); - - auto p = absPath("", cwd); - - ASSERT_EQ(p, cwd); - } - - TEST(absPath, isIdempotent) { - char _cwd[PATH_MAX+1]; - char* cwd = getcwd((char*)&_cwd, PATH_MAX); - auto p1 = absPath(cwd); - auto p2 = absPath(p1); - - ASSERT_EQ(p1, p2); - } - - - TEST(absPath, pathIsCanonicalised) { - auto path = "/some/path/with/trailing/dot/."; - auto p1 = absPath(path); - auto p2 = absPath(p1); - - ASSERT_EQ(p1, "/some/path/with/trailing/dot"); - ASSERT_EQ(p1, p2); - } - - /* ---------------------------------------------------------------------------- - * canonPath - * --------------------------------------------------------------------------*/ - - TEST(canonPath, removesTrailingSlashes) { - auto path = "/this/is/a/path//"; - auto p = canonPath(path); - - ASSERT_EQ(p, "/this/is/a/path"); - } - - TEST(canonPath, removesDots) { - auto path = "/this/./is/a/path/./"; - auto p = canonPath(path); - - ASSERT_EQ(p, "/this/is/a/path"); - } - - TEST(canonPath, removesDots2) { - auto path = "/this/a/../is/a////path/foo/.."; - auto p = canonPath(path); - - ASSERT_EQ(p, "/this/is/a/path"); - } - - TEST(canonPath, requiresAbsolutePath) { - ASSERT_ANY_THROW(canonPath(".")); - ASSERT_ANY_THROW(canonPath("..")); - ASSERT_ANY_THROW(canonPath("../")); - ASSERT_DEATH({ canonPath(""); }, "path != \"\""); - } - - /* ---------------------------------------------------------------------------- - * dirOf - * --------------------------------------------------------------------------*/ - - TEST(dirOf, returnsEmptyStringForRoot) { - auto p = dirOf("/"); - - ASSERT_EQ(p, "/"); - } - - TEST(dirOf, returnsFirstPathComponent) { - auto p1 = dirOf("/dir/"); - ASSERT_EQ(p1, "/dir"); - auto p2 = dirOf("/dir"); - ASSERT_EQ(p2, "/"); - auto p3 = dirOf("/dir/.."); - ASSERT_EQ(p3, "/dir"); - auto p4 = dirOf("/dir/../"); - ASSERT_EQ(p4, "/dir/.."); - } - - /* ---------------------------------------------------------------------------- - * baseNameOf - * --------------------------------------------------------------------------*/ - - TEST(baseNameOf, emptyPath) { - auto p1 = baseNameOf(""); - ASSERT_EQ(p1, ""); - } - - TEST(baseNameOf, pathOnRoot) { - auto p1 = baseNameOf("/dir"); - ASSERT_EQ(p1, "dir"); - } - - TEST(baseNameOf, relativePath) { - auto p1 = baseNameOf("dir/foo"); - ASSERT_EQ(p1, "foo"); - } - - TEST(baseNameOf, pathWithTrailingSlashRoot) { - auto p1 = baseNameOf("/"); - ASSERT_EQ(p1, ""); - } - - TEST(baseNameOf, trailingSlash) { - auto p1 = baseNameOf("/dir/"); - ASSERT_EQ(p1, "dir"); - } - - /* ---------------------------------------------------------------------------- - * isInDir - * --------------------------------------------------------------------------*/ - - TEST(isInDir, trivialCase) { - auto p1 = isInDir("/foo/bar", "/foo"); - ASSERT_EQ(p1, true); - } - - TEST(isInDir, notInDir) { - auto p1 = isInDir("/zes/foo/bar", "/foo"); - ASSERT_EQ(p1, false); - } - - // XXX: hm, bug or feature? :) Looking at the implementation - // this might be problematic. - TEST(isInDir, emptyDir) { - auto p1 = isInDir("/zes/foo/bar", ""); - ASSERT_EQ(p1, true); - } - - /* ---------------------------------------------------------------------------- - * isDirOrInDir - * --------------------------------------------------------------------------*/ - - TEST(isDirOrInDir, trueForSameDirectory) { - ASSERT_EQ(isDirOrInDir("/nix", "/nix"), true); - ASSERT_EQ(isDirOrInDir("/", "/"), true); - } - - TEST(isDirOrInDir, trueForEmptyPaths) { - ASSERT_EQ(isDirOrInDir("", ""), true); - } - - TEST(isDirOrInDir, falseForDisjunctPaths) { - ASSERT_EQ(isDirOrInDir("/foo", "/bar"), false); - } - - TEST(isDirOrInDir, relativePaths) { - ASSERT_EQ(isDirOrInDir("/foo/..", "/foo"), true); - } - - // XXX: while it is possible to use "." or ".." in the - // first argument this doesn't seem to work in the second. - TEST(isDirOrInDir, DISABLED_shouldWork) { - ASSERT_EQ(isDirOrInDir("/foo/..", "/foo/."), true); - - } - - /* ---------------------------------------------------------------------------- - * pathExists - * --------------------------------------------------------------------------*/ - - TEST(pathExists, rootExists) { - ASSERT_TRUE(pathExists("/")); - } - - TEST(pathExists, cwdExists) { - ASSERT_TRUE(pathExists(".")); - } - - TEST(pathExists, bogusPathDoesNotExist) { - ASSERT_FALSE(pathExists("/schnitzel/darmstadt/pommes")); - } - - /* ---------------------------------------------------------------------------- - * concatStringsSep - * --------------------------------------------------------------------------*/ - - TEST(concatStringsSep, buildCommaSeparatedString) { - Strings strings; - strings.push_back("this"); - strings.push_back("is"); - strings.push_back("great"); - - ASSERT_EQ(concatStringsSep(",", strings), "this,is,great"); - } - - TEST(concatStringsSep, buildStringWithEmptySeparator) { - Strings strings; - strings.push_back("this"); - strings.push_back("is"); - strings.push_back("great"); - - ASSERT_EQ(concatStringsSep("", strings), "thisisgreat"); - } - - TEST(concatStringsSep, buildSingleString) { - Strings strings; - strings.push_back("this"); - - ASSERT_EQ(concatStringsSep(",", strings), "this"); - } - - /* ---------------------------------------------------------------------------- - * hasPrefix - * --------------------------------------------------------------------------*/ - - TEST(hasPrefix, emptyStringHasNoPrefix) { - ASSERT_FALSE(hasPrefix("", "foo")); - } - - TEST(hasPrefix, emptyStringIsAlwaysPrefix) { - ASSERT_TRUE(hasPrefix("foo", "")); - ASSERT_TRUE(hasPrefix("jshjkfhsadf", "")); - } - - TEST(hasPrefix, trivialCase) { - ASSERT_TRUE(hasPrefix("foobar", "foo")); - } - - /* ---------------------------------------------------------------------------- - * hasSuffix - * --------------------------------------------------------------------------*/ - - TEST(hasSuffix, emptyStringHasNoSuffix) { - ASSERT_FALSE(hasSuffix("", "foo")); - } - - TEST(hasSuffix, trivialCase) { - ASSERT_TRUE(hasSuffix("foo", "foo")); - ASSERT_TRUE(hasSuffix("foobar", "bar")); - } - - /* ---------------------------------------------------------------------------- - * base64Encode - * --------------------------------------------------------------------------*/ - - TEST(base64Encode, emptyString) { - ASSERT_EQ(base64Encode(""), ""); - } - - TEST(base64Encode, encodesAString) { - ASSERT_EQ(base64Encode("quod erat demonstrandum"), "cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="); - } - - TEST(base64Encode, encodeAndDecode) { - auto s = "quod erat demonstrandum"; - auto encoded = base64Encode(s); - auto decoded = base64Decode(encoded); - - ASSERT_EQ(decoded, s); - } - - TEST(base64Encode, encodeAndDecodeNonPrintable) { - char s[256]; - std::iota(std::rbegin(s), std::rend(s), 0); - - auto encoded = base64Encode(s); - auto decoded = base64Decode(encoded); - - EXPECT_EQ(decoded.length(), 255); - ASSERT_EQ(decoded, s); - } - - /* ---------------------------------------------------------------------------- - * base64Decode - * --------------------------------------------------------------------------*/ - - TEST(base64Decode, emptyString) { - ASSERT_EQ(base64Decode(""), ""); - } - - TEST(base64Decode, decodeAString) { - ASSERT_EQ(base64Decode("cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="), "quod erat demonstrandum"); - } - - TEST(base64Decode, decodeThrowsOnInvalidChar) { - ASSERT_THROW(base64Decode("cXVvZCBlcm_0IGRlbW9uc3RyYW5kdW0="), Error); - } - - /* ---------------------------------------------------------------------------- - * getLine - * --------------------------------------------------------------------------*/ - - TEST(getLine, all) { - { - auto [line, rest] = getLine("foo\nbar\nxyzzy"); - ASSERT_EQ(line, "foo"); - ASSERT_EQ(rest, "bar\nxyzzy"); - } - - { - auto [line, rest] = getLine("foo\r\nbar\r\nxyzzy"); - ASSERT_EQ(line, "foo"); - ASSERT_EQ(rest, "bar\r\nxyzzy"); - } - - { - auto [line, rest] = getLine("foo\n"); - ASSERT_EQ(line, "foo"); - ASSERT_EQ(rest, ""); - } - - { - auto [line, rest] = getLine("foo"); - ASSERT_EQ(line, "foo"); - ASSERT_EQ(rest, ""); - } - - { - auto [line, rest] = getLine(""); - ASSERT_EQ(line, ""); - ASSERT_EQ(rest, ""); - } - } - - /* ---------------------------------------------------------------------------- - * toLower - * --------------------------------------------------------------------------*/ - - TEST(toLower, emptyString) { - ASSERT_EQ(toLower(""), ""); - } - - TEST(toLower, nonLetters) { - auto s = "!@(*$#)(@#=\\234_"; - ASSERT_EQ(toLower(s), s); - } - - // std::tolower() doesn't handle unicode characters. In the context of - // store paths this isn't relevant but doesn't hurt to record this behavior - // here. - TEST(toLower, umlauts) { - auto s = "ÄÖÜ"; - ASSERT_EQ(toLower(s), "ÄÖÜ"); - } - - /* ---------------------------------------------------------------------------- - * string2Float - * --------------------------------------------------------------------------*/ - - TEST(string2Float, emptyString) { - ASSERT_EQ(string2Float<double>(""), std::nullopt); - } - - TEST(string2Float, trivialConversions) { - ASSERT_EQ(string2Float<double>("1.0"), 1.0); - - ASSERT_EQ(string2Float<double>("0.0"), 0.0); - - ASSERT_EQ(string2Float<double>("-100.25"), -100.25); - } - - /* ---------------------------------------------------------------------------- - * string2Int - * --------------------------------------------------------------------------*/ - - TEST(string2Int, emptyString) { - ASSERT_EQ(string2Int<int>(""), std::nullopt); - } - - TEST(string2Int, trivialConversions) { - ASSERT_EQ(string2Int<int>("1"), 1); - - ASSERT_EQ(string2Int<int>("0"), 0); - - ASSERT_EQ(string2Int<int>("-100"), -100); - } - - /* ---------------------------------------------------------------------------- - * statusOk - * --------------------------------------------------------------------------*/ - - TEST(statusOk, zeroIsOk) { - ASSERT_EQ(statusOk(0), true); - ASSERT_EQ(statusOk(1), false); - } - - - /* ---------------------------------------------------------------------------- - * rewriteStrings - * --------------------------------------------------------------------------*/ - - TEST(rewriteStrings, emptyString) { - StringMap rewrites; - rewrites["this"] = "that"; - - ASSERT_EQ(rewriteStrings("", rewrites), ""); - } - - TEST(rewriteStrings, emptyRewrites) { - StringMap rewrites; - - ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that"); - } - - TEST(rewriteStrings, successfulRewrite) { - StringMap rewrites; - rewrites["this"] = "that"; - - ASSERT_EQ(rewriteStrings("this and that", rewrites), "that and that"); - } - - TEST(rewriteStrings, doesntOccur) { - StringMap rewrites; - rewrites["foo"] = "bar"; - - ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that"); - } - - /* ---------------------------------------------------------------------------- - * replaceStrings - * --------------------------------------------------------------------------*/ - - TEST(replaceStrings, emptyString) { - ASSERT_EQ(replaceStrings("", "this", "that"), ""); - ASSERT_EQ(replaceStrings("this and that", "", ""), "this and that"); - } - - TEST(replaceStrings, successfulReplace) { - ASSERT_EQ(replaceStrings("this and that", "this", "that"), "that and that"); - } - - TEST(replaceStrings, doesntOccur) { - ASSERT_EQ(replaceStrings("this and that", "foo", "bar"), "this and that"); - } - - /* ---------------------------------------------------------------------------- - * trim - * --------------------------------------------------------------------------*/ - - TEST(trim, emptyString) { - ASSERT_EQ(trim(""), ""); - } - - TEST(trim, removesWhitespace) { - ASSERT_EQ(trim("foo"), "foo"); - ASSERT_EQ(trim(" foo "), "foo"); - ASSERT_EQ(trim(" foo bar baz"), "foo bar baz"); - ASSERT_EQ(trim(" \t foo bar baz\n"), "foo bar baz"); - } - - /* ---------------------------------------------------------------------------- - * chomp - * --------------------------------------------------------------------------*/ - - TEST(chomp, emptyString) { - ASSERT_EQ(chomp(""), ""); - } - - TEST(chomp, removesWhitespace) { - ASSERT_EQ(chomp("foo"), "foo"); - ASSERT_EQ(chomp("foo "), "foo"); - ASSERT_EQ(chomp(" foo "), " foo"); - ASSERT_EQ(chomp(" foo bar baz "), " foo bar baz"); - ASSERT_EQ(chomp("\t foo bar baz\n"), "\t foo bar baz"); - } - - /* ---------------------------------------------------------------------------- - * quoteStrings - * --------------------------------------------------------------------------*/ - - TEST(quoteStrings, empty) { - Strings s = { }; - Strings expected = { }; - - ASSERT_EQ(quoteStrings(s), expected); - } - - TEST(quoteStrings, emptyStrings) { - Strings s = { "", "", "" }; - Strings expected = { "''", "''", "''" }; - ASSERT_EQ(quoteStrings(s), expected); - - } - - TEST(quoteStrings, trivialQuote) { - Strings s = { "foo", "bar", "baz" }; - Strings expected = { "'foo'", "'bar'", "'baz'" }; - - ASSERT_EQ(quoteStrings(s), expected); - } - - TEST(quoteStrings, quotedStrings) { - Strings s = { "'foo'", "'bar'", "'baz'" }; - Strings expected = { "''foo''", "''bar''", "''baz''" }; - - ASSERT_EQ(quoteStrings(s), expected); - } - - /* ---------------------------------------------------------------------------- - * tokenizeString - * --------------------------------------------------------------------------*/ - - TEST(tokenizeString, empty) { - Strings expected = { }; - - ASSERT_EQ(tokenizeString<Strings>(""), expected); - } - - TEST(tokenizeString, tokenizeSpacesWithDefaults) { - auto s = "foo bar baz"; - Strings expected = { "foo", "bar", "baz" }; - - ASSERT_EQ(tokenizeString<Strings>(s), expected); - } - - TEST(tokenizeString, tokenizeTabsWithDefaults) { - auto s = "foo\tbar\tbaz"; - Strings expected = { "foo", "bar", "baz" }; - - ASSERT_EQ(tokenizeString<Strings>(s), expected); - } - - TEST(tokenizeString, tokenizeTabsSpacesWithDefaults) { - auto s = "foo\t bar\t baz"; - Strings expected = { "foo", "bar", "baz" }; - - ASSERT_EQ(tokenizeString<Strings>(s), expected); - } - - TEST(tokenizeString, tokenizeTabsSpacesNewlineWithDefaults) { - auto s = "foo\t\n bar\t\n baz"; - Strings expected = { "foo", "bar", "baz" }; - - ASSERT_EQ(tokenizeString<Strings>(s), expected); - } - - TEST(tokenizeString, tokenizeTabsSpacesNewlineRetWithDefaults) { - auto s = "foo\t\n\r bar\t\n\r baz"; - Strings expected = { "foo", "bar", "baz" }; - - ASSERT_EQ(tokenizeString<Strings>(s), expected); - - auto s2 = "foo \t\n\r bar \t\n\r baz"; - Strings expected2 = { "foo", "bar", "baz" }; - - ASSERT_EQ(tokenizeString<Strings>(s2), expected2); - } - - TEST(tokenizeString, tokenizeWithCustomSep) { - auto s = "foo\n,bar\n,baz\n"; - Strings expected = { "foo\n", "bar\n", "baz\n" }; - - ASSERT_EQ(tokenizeString<Strings>(s, ","), expected); - } - - /* ---------------------------------------------------------------------------- - * get - * --------------------------------------------------------------------------*/ - - TEST(get, emptyContainer) { - StringMap s = { }; - auto expected = nullptr; - - ASSERT_EQ(get(s, "one"), expected); - } - - TEST(get, getFromContainer) { - StringMap s; - s["one"] = "yi"; - s["two"] = "er"; - auto expected = "yi"; - - ASSERT_EQ(*get(s, "one"), expected); - } - - TEST(getOr, emptyContainer) { - StringMap s = { }; - auto expected = "yi"; - - ASSERT_EQ(getOr(s, "one", "yi"), expected); - } - - TEST(getOr, getFromContainer) { - StringMap s; - s["one"] = "yi"; - s["two"] = "er"; - auto expected = "yi"; - - ASSERT_EQ(getOr(s, "one", "nope"), expected); - } - - /* ---------------------------------------------------------------------------- - * filterANSIEscapes - * --------------------------------------------------------------------------*/ - - TEST(filterANSIEscapes, emptyString) { - auto s = ""; - auto expected = ""; - - ASSERT_EQ(filterANSIEscapes(s), expected); - } - - TEST(filterANSIEscapes, doesntChangePrintableChars) { - auto s = "09 2q304ruyhr slk2-19024 kjsadh sar f"; - - ASSERT_EQ(filterANSIEscapes(s), s); - } - - TEST(filterANSIEscapes, filtersColorCodes) { - auto s = "\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m"; - - ASSERT_EQ(filterANSIEscapes(s, true, 2), " A" ); - ASSERT_EQ(filterANSIEscapes(s, true, 3), " A " ); - ASSERT_EQ(filterANSIEscapes(s, true, 4), " A " ); - ASSERT_EQ(filterANSIEscapes(s, true, 5), " A B" ); - ASSERT_EQ(filterANSIEscapes(s, true, 8), " A B C" ); - } - - TEST(filterANSIEscapes, expandsTabs) { - auto s = "foo\tbar\tbaz"; - - ASSERT_EQ(filterANSIEscapes(s, true), "foo bar baz" ); - } - - TEST(filterANSIEscapes, utf8) { - ASSERT_EQ(filterANSIEscapes("foobar", true, 5), "fooba"); - ASSERT_EQ(filterANSIEscapes("fóóbär", true, 6), "fóóbär"); - ASSERT_EQ(filterANSIEscapes("fóóbär", true, 5), "fóóbä"); - ASSERT_EQ(filterANSIEscapes("fóóbär", true, 3), "fóó"); - ASSERT_EQ(filterANSIEscapes("f€€bär", true, 4), "f€€b"); - ASSERT_EQ(filterANSIEscapes("f𐍈𐍈bär", true, 4), "f𐍈𐍈b"); - } - -} diff --git a/src/libutil/tests/url.cc b/src/libutil/tests/url.cc deleted file mode 100644 index a908631e6..000000000 --- a/src/libutil/tests/url.cc +++ /dev/null @@ -1,338 +0,0 @@ -#include "url.hh" -#include <gtest/gtest.h> - -namespace nix { - -/* ----------- tests for url.hh --------------------------------------------------*/ - - std::string print_map(std::map<std::string, std::string> m) { - std::map<std::string, std::string>::iterator it; - std::string s = "{ "; - for (it = m.begin(); it != m.end(); ++it) { - s += "{ "; - s += it->first; - s += " = "; - s += it->second; - s += " } "; - } - s += "}"; - return s; - } - - - std::ostream& operator<<(std::ostream& os, const ParsedURL& p) { - return os << "\n" - << "url: " << p.url << "\n" - << "base: " << p.base << "\n" - << "scheme: " << p.scheme << "\n" - << "authority: " << p.authority.value() << "\n" - << "path: " << p.path << "\n" - << "query: " << print_map(p.query) << "\n" - << "fragment: " << p.fragment << "\n"; - } - - TEST(parseURL, parsesSimpleHttpUrl) { - auto s = "http://www.example.org/file.tar.gz"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://www.example.org/file.tar.gz", - .base = "http://www.example.org/file.tar.gz", - .scheme = "http", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesSimpleHttpsUrl) { - auto s = "https://www.example.org/file.tar.gz"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "https://www.example.org/file.tar.gz", - .base = "https://www.example.org/file.tar.gz", - .scheme = "https", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesSimpleHttpUrlWithQueryAndFragment) { - auto s = "https://www.example.org/file.tar.gz?download=fast&when=now#hello"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "https://www.example.org/file.tar.gz", - .base = "https://www.example.org/file.tar.gz", - .scheme = "https", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { { "download", "fast" }, { "when", "now" } }, - .fragment = "hello", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesSimpleHttpUrlWithComplexFragment) { - auto s = "http://www.example.org/file.tar.gz?field=value#?foo=bar%23"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://www.example.org/file.tar.gz", - .base = "http://www.example.org/file.tar.gz", - .scheme = "http", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { { "field", "value" } }, - .fragment = "?foo=bar#", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesFilePlusHttpsUrl) { - auto s = "file+https://www.example.org/video.mp4"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "file+https://www.example.org/video.mp4", - .base = "https://www.example.org/video.mp4", - .scheme = "file+https", - .authority = "www.example.org", - .path = "/video.mp4", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, rejectsAuthorityInUrlsWithFileTransportation) { - auto s = "file://www.example.org/video.mp4"; - ASSERT_THROW(parseURL(s), Error); - } - - TEST(parseURL, parseIPv4Address) { - auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://127.0.0.1:8080/file.tar.gz", - .base = "https://127.0.0.1:8080/file.tar.gz", - .scheme = "http", - .authority = "127.0.0.1:8080", - .path = "/file.tar.gz", - .query = (StringMap) { { "download", "fast" }, { "when", "now" } }, - .fragment = "hello", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parseScopedRFC4007IPv6Address) { - auto s = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080", - .base = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080", - .scheme = "http", - .authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080", - .path = "", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - - } - - TEST(parseURL, parseIPv6Address) { - auto s = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", - .base = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", - .scheme = "http", - .authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", - .path = "", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - - } - - TEST(parseURL, parseEmptyQueryParams) { - auto s = "http://127.0.0.1:8080/file.tar.gz?&&&&&"; - auto parsed = parseURL(s); - ASSERT_EQ(parsed.query, (StringMap) { }); - } - - TEST(parseURL, parseUserPassword) { - auto s = "http://user:pass@www.example.org:8080/file.tar.gz"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://user:pass@www.example.org/file.tar.gz", - .base = "http://user:pass@www.example.org/file.tar.gz", - .scheme = "http", - .authority = "user:pass@www.example.org:8080", - .path = "/file.tar.gz", - .query = (StringMap) { }, - .fragment = "", - }; - - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parseFileURLWithQueryAndFragment) { - auto s = "file:///none/of//your/business"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "", - .base = "", - .scheme = "file", - .authority = "", - .path = "/none/of//your/business", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - - } - - TEST(parseURL, parsedUrlsIsEqualToItself) { - auto s = "http://www.example.org/file.tar.gz"; - auto url = parseURL(s); - - ASSERT_TRUE(url == url); - } - - TEST(parseURL, parseFTPUrl) { - auto s = "ftp://ftp.nixos.org/downloads/nixos.iso"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "ftp://ftp.nixos.org/downloads/nixos.iso", - .base = "ftp://ftp.nixos.org/downloads/nixos.iso", - .scheme = "ftp", - .authority = "ftp.nixos.org", - .path = "/downloads/nixos.iso", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesAnythingInUriFormat) { - auto s = "whatever://github.com/NixOS/nixpkgs.git"; - auto parsed = parseURL(s); - } - - TEST(parseURL, parsesAnythingInUriFormatWithoutDoubleSlash) { - auto s = "whatever:github.com/NixOS/nixpkgs.git"; - auto parsed = parseURL(s); - } - - TEST(parseURL, emptyStringIsInvalidURL) { - ASSERT_THROW(parseURL(""), Error); - } - - /* ---------------------------------------------------------------------------- - * decodeQuery - * --------------------------------------------------------------------------*/ - - TEST(decodeQuery, emptyStringYieldsEmptyMap) { - auto d = decodeQuery(""); - ASSERT_EQ(d, (StringMap) { }); - } - - TEST(decodeQuery, simpleDecode) { - auto d = decodeQuery("yi=one&er=two"); - ASSERT_EQ(d, ((StringMap) { { "yi", "one" }, { "er", "two" } })); - } - - TEST(decodeQuery, decodeUrlEncodedArgs) { - auto d = decodeQuery("arg=%3D%3D%40%3D%3D"); - ASSERT_EQ(d, ((StringMap) { { "arg", "==@==" } })); - } - - TEST(decodeQuery, decodeArgWithEmptyValue) { - auto d = decodeQuery("arg="); - ASSERT_EQ(d, ((StringMap) { { "arg", ""} })); - } - - /* ---------------------------------------------------------------------------- - * percentDecode - * --------------------------------------------------------------------------*/ - - TEST(percentDecode, decodesUrlEncodedString) { - std::string s = "==@=="; - std::string d = percentDecode("%3D%3D%40%3D%3D"); - ASSERT_EQ(d, s); - } - - TEST(percentDecode, multipleDecodesAreIdempotent) { - std::string once = percentDecode("%3D%3D%40%3D%3D"); - std::string twice = percentDecode(once); - - ASSERT_EQ(once, twice); - } - - TEST(percentDecode, trailingPercent) { - std::string s = "==@==%"; - std::string d = percentDecode("%3D%3D%40%3D%3D%25"); - - ASSERT_EQ(d, s); - } - - - /* ---------------------------------------------------------------------------- - * percentEncode - * --------------------------------------------------------------------------*/ - - TEST(percentEncode, encodesUrlEncodedString) { - std::string s = percentEncode("==@=="); - std::string d = "%3D%3D%40%3D%3D"; - ASSERT_EQ(d, s); - } - - TEST(percentEncode, keepArgument) { - std::string a = percentEncode("abd / def"); - std::string b = percentEncode("abd / def", "/"); - ASSERT_EQ(a, "abd%20%2F%20def"); - ASSERT_EQ(b, "abd%20/%20def"); - } - - TEST(percentEncode, inverseOfDecode) { - std::string original = "%3D%3D%40%3D%3D"; - std::string once = percentEncode(original); - std::string back = percentDecode(once); - - ASSERT_EQ(back, original); - } - - TEST(percentEncode, trailingPercent) { - std::string s = percentEncode("==@==%"); - std::string d = "%3D%3D%40%3D%3D%25"; - - ASSERT_EQ(d, s); - } - -} diff --git a/src/libutil/tests/xml-writer.cc b/src/libutil/tests/xml-writer.cc deleted file mode 100644 index adcde25c9..000000000 --- a/src/libutil/tests/xml-writer.cc +++ /dev/null @@ -1,105 +0,0 @@ -#include "xml-writer.hh" -#include <gtest/gtest.h> -#include <sstream> - -namespace nix { - - /* ---------------------------------------------------------------------------- - * XMLWriter - * --------------------------------------------------------------------------*/ - - TEST(XMLWriter, emptyObject) { - std::stringstream out; - { - XMLWriter t(false, out); - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n"); - } - - TEST(XMLWriter, objectWithEmptyElement) { - std::stringstream out; - { - XMLWriter t(false, out); - t.openElement("foobar"); - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar></foobar>"); - } - - TEST(XMLWriter, objectWithElementWithAttrs) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = { - { "foo", "bar" } - }; - t.openElement("foobar", attrs); - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\"></foobar>"); - } - - TEST(XMLWriter, objectWithElementWithEmptyAttrs) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = {}; - t.openElement("foobar", attrs); - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar></foobar>"); - } - - TEST(XMLWriter, objectWithElementWithAttrsEscaping) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = { - { "<key>", "<value>" } - }; - t.openElement("foobar", attrs); - } - - // XXX: While "<value>" is escaped, "<key>" isn't which I think is a bug. - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar <key>=\"<value>\"></foobar>"); - } - - TEST(XMLWriter, objectWithElementWithAttrsIndented) { - std::stringstream out; - { - XMLWriter t(true, out); - XMLAttrs attrs = { - { "foo", "bar" } - }; - t.openElement("foobar", attrs); - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\">\n</foobar>\n"); - } - - TEST(XMLWriter, writeEmptyElement) { - std::stringstream out; - { - XMLWriter t(false, out); - t.writeEmptyElement("foobar"); - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar />"); - } - - TEST(XMLWriter, writeEmptyElementWithAttributes) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = { - { "foo", "bar" } - }; - t.writeEmptyElement("foobar", attrs); - - } - - ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\" />"); - } - -} diff --git a/src/libutil/url-parts.hh b/src/libutil/url-parts.hh index 98162b0f7..12026921f 100644 --- a/src/libutil/url-parts.hh +++ b/src/libutil/url-parts.hh @@ -30,7 +30,7 @@ extern std::regex refRegex; /// Instead of defining what a good Git Ref is, we define what a bad Git Ref is /// This is because of the definition of a ref in refs.c in https://github.com/git/git -/// See tests/fetchGitRefs.sh for the full definition +/// See tests/functional/fetchGitRefs.sh for the full definition const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$"; extern std::regex badGitRefRegex; diff --git a/src/nix/main.cc b/src/nix/main.cc index d05bac68e..eb510eecc 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -218,7 +218,8 @@ static void showHelp(std::vector<std::string> subcommand, NixArgs & toplevel) vDump->mkString(toplevel.dumpCli()); auto vRes = state.allocValue(); - state.callFunction(*vGenerateManpage, *vDump, *vRes, noPos); + state.callFunction(*vGenerateManpage, state.getBuiltin("false"), *vRes, noPos); + state.callFunction(*vRes, *vDump, *vRes, noPos); auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md")); if (!attr) |