mirror of
https://github.com/NixOS/nix
synced 2025-06-30 15:48:00 +02:00
For example, instead of doing #include "nix/store-config.hh" #include "nix/derived-path.hh" Now do #include "nix/store/config.hh" #include "nix/store/derived-path.hh" This was originally planned in the issue, and also recent requested by Eelco. Most of the change is purely mechanical. There is just one small additional issue. See how, in the example above, we took this opportunity to also turn `<comp>-config.hh` into `<comp>/config.hh`. Well, there was already a `nix/util/config.{cc,hh}`. Even though there is not a public configuration header for libutil (which also would be called `nix/util/config.{cc,hh}`) that's still confusing, To avoid any such confusion, we renamed that to `nix/util/configuration.{cc,hh}`. Finally, note that the libflake headers already did this, so we didn't need to do anything to them. We wouldn't want to mistakenly get `nix/flake/flake/flake.hh`! Progress on #7876
301 lines
9.6 KiB
C++
301 lines
9.6 KiB
C++
#include "nix/expr/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; }; }"
|
|
)
|
|
);
|
|
|
|
// The following macros ultimately define 48 tests (16 variations on three
|
|
// templates). Each template tests an expression that can be written in 2^4
|
|
// different ways, by making four choices about whether to write a particular
|
|
// attribute path segment as `x.y = ...;` (collapsed) or `x = { y = ...; };`
|
|
// (expanded).
|
|
//
|
|
// The nestedAttrsetMergeXXXX tests check that the expression
|
|
// `{ a.b.c = 1; a.b.d = 2; }` has the same value regardless of how it is
|
|
// expanded. (That exact expression is exercised in test
|
|
// nestedAttrsetMerge0000, because it is fully collapsed. The test
|
|
// nestedAttrsetMerge1001 would instead examine
|
|
// `{ a = { b.c = 1; }; a.b = { d = 2; }; }`.)
|
|
//
|
|
// The nestedAttrsetMergeDupXXXX tests check that the expression
|
|
// `{ a.b.c = 1; a.b.c = 2; }` throws a duplicate attribute error, again
|
|
// regardless of how it is expanded.
|
|
//
|
|
// The nestedAttrsetMergeLetXXXX tests check that the expression
|
|
// `let a.b.c = 1; a.b.d = 2; in a` has the same value regardless of how it is
|
|
// expanded.
|
|
#define X_EXPAND_IF0(k, v) k "." v
|
|
#define X_EXPAND_IF1(k, v) k " = { " v " };"
|
|
#define X4(w, x, y, z) \
|
|
TEST_F(TrivialExpressionTest, nestedAttrsetMerge##w##x##y##z) { \
|
|
auto v = eval("{ a.b = { c = 1; d = 2; }; } == { " \
|
|
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
|
|
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " }"); \
|
|
ASSERT_THAT(v, IsTrue()); \
|
|
}; \
|
|
TEST_F(TrivialExpressionTest, nestedAttrsetMergeDup##w##x##y##z) { \
|
|
ASSERT_THROW(eval("{ " \
|
|
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
|
|
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "c = 2;")) " }"), Error); \
|
|
}; \
|
|
TEST_F(TrivialExpressionTest, nestedAttrsetMergeLet##w##x##y##z) { \
|
|
auto v = eval("{ b = { c = 1; d = 2; }; } == (let " \
|
|
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
|
|
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " in a)"); \
|
|
ASSERT_THAT(v, IsTrue()); \
|
|
};
|
|
#define X3(...) X4(__VA_ARGS__, 0) X4(__VA_ARGS__, 1)
|
|
#define X2(...) X3(__VA_ARGS__, 0) X3(__VA_ARGS__, 1)
|
|
#define X1(...) X2(__VA_ARGS__, 0) X2(__VA_ARGS__, 1)
|
|
X1(0) X1(1)
|
|
#undef X_EXPAND_IF0
|
|
#undef X_EXPAND_IF1
|
|
#undef X1
|
|
#undef X2
|
|
#undef X3
|
|
#undef X4
|
|
|
|
TEST_F(TrivialExpressionTest, functor) {
|
|
auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5");
|
|
ASSERT_THAT(v, IsIntEq(15));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, forwardPipe) {
|
|
auto v = eval("1 |> builtins.add 2 |> builtins.mul 3");
|
|
ASSERT_THAT(v, IsIntEq(9));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, backwardPipe) {
|
|
auto v = eval("builtins.add 1 <| builtins.mul 2 <| 3");
|
|
ASSERT_THAT(v, IsIntEq(7));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, forwardPipeEvaluationOrder) {
|
|
auto v = eval("1 |> null |> (x: 2)");
|
|
ASSERT_THAT(v, IsIntEq(2));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, backwardPipeEvaluationOrder) {
|
|
auto v = eval("(x: 1) <| null <| 2");
|
|
ASSERT_THAT(v, IsIntEq(1));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, differentPipeOperatorsDoNotAssociate) {
|
|
ASSERT_THROW(eval("(x: 1) <| 2 |> (x: 3)"), ParseError);
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, differentPipeOperatorsParensLeft) {
|
|
auto v = eval("((x: 1) <| 2) |> (x: 3)");
|
|
ASSERT_THAT(v, IsIntEq(3));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, differentPipeOperatorsParensRight) {
|
|
auto v = eval("(x: 1) <| (2 |> (x: 3))");
|
|
ASSERT_THAT(v, IsIntEq(1));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, forwardPipeLowestPrecedence) {
|
|
auto v = eval("false -> true |> (x: !x)");
|
|
ASSERT_THAT(v, IsFalse());
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, backwardPipeLowestPrecedence) {
|
|
auto v = eval("(x: !x) <| false -> true");
|
|
ASSERT_THAT(v, IsFalse());
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, forwardPipeStrongerThanElse) {
|
|
auto v = eval("if true then 1 else 2 |> 3");
|
|
ASSERT_THAT(v, IsIntEq(1));
|
|
}
|
|
|
|
TEST_F(TrivialExpressionTest, backwardPipeStrongerThanElse) {
|
|
auto v = eval("if true then 1 else 2 <| 3");
|
|
ASSERT_THAT(v, IsIntEq(1));
|
|
}
|
|
|
|
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 */
|