mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-22 05:56:15 +02:00
assert: Report why values aren't equal
This commit is contained in:
parent
509be0e77a
commit
d63bd8295e
29 changed files with 532 additions and 5 deletions
|
@ -1759,9 +1759,24 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
||||||
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
if (!state.evalBool(env, cond, pos, "in the condition of the assert statement")) {
|
if (!state.evalBool(env, cond, pos, "in the condition of the assert statement")) {
|
||||||
std::ostringstream out;
|
auto exprStr = ({
|
||||||
cond->show(state.symbols, out);
|
std::ostringstream out;
|
||||||
state.error<AssertionError>("assertion '%1%' failed", out.str()).atPos(pos).withFrame(env, *this).debugThrow();
|
cond->show(state.symbols, out);
|
||||||
|
out.str();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (auto eq = dynamic_cast<ExprOpEq *>(cond)) {
|
||||||
|
try {
|
||||||
|
Value v1; eq->e1->eval(state, env, v1);
|
||||||
|
Value v2; eq->e2->eval(state, env, v2);
|
||||||
|
state.assertEqValues(v1, v2, eq->pos, "in an equality assertion");
|
||||||
|
} catch (AssertionError & e) {
|
||||||
|
e.addTrace(state.positions[pos], "while evaluating the condition of the assertion '%s'", exprStr);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.error<AssertionError>("assertion '%1%' failed", exprStr).atPos(pos).withFrame(env, *this).debugThrow();
|
||||||
}
|
}
|
||||||
body->eval(state, env, v);
|
body->eval(state, env, v);
|
||||||
}
|
}
|
||||||
|
@ -2418,6 +2433,216 @@ SingleDerivedPath EvalState::coerceToSingleDerivedPath(const PosIdx pos, Value &
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: This implementation must match eqValues!
|
||||||
|
// We accept this burden because informative error messages for
|
||||||
|
// `assert a == b; x` are critical for our users' testing UX.
|
||||||
|
void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
|
||||||
|
{
|
||||||
|
// This implementation must match eqValues.
|
||||||
|
forceValue(v1, pos);
|
||||||
|
forceValue(v2, pos);
|
||||||
|
|
||||||
|
if (&v1 == &v2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Special case type-compatibility between float and int
|
||||||
|
if ((v1.type() == nInt || v1.type() == nFloat) && (v2.type() == nInt || v2.type() == nFloat)) {
|
||||||
|
if (eqValues(v1, v2, pos, errorCtx)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
error<AssertionError>(
|
||||||
|
"%s with value '%s' is not equal to %s with value '%s'",
|
||||||
|
showType(v1),
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
showType(v2),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v1.type() != v2.type()) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"%s of value '%s' is not equal to %s of value '%s'",
|
||||||
|
showType(v1),
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
showType(v2),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v1.type()) {
|
||||||
|
case nInt:
|
||||||
|
if (v1.integer() != v2.integer()) {
|
||||||
|
error<AssertionError>("integer '%d' is not equal to integer '%d'", v1.integer(), v2.integer()).debugThrow();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nBool:
|
||||||
|
if (v1.boolean() != v2.boolean()) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"boolean '%s' is not equal to boolean '%s'",
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nString:
|
||||||
|
if (strcmp(v1.c_str(), v2.c_str()) != 0) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"string '%s' is not equal to string '%s'",
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nPath:
|
||||||
|
if (v1.payload.path.accessor != v2.payload.path.accessor) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"path '%s' is not equal to path '%s' because their accessors are different",
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
if (strcmp(v1.payload.path.path, v2.payload.path.path) != 0) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"path '%s' is not equal to path '%s'",
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nNull:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nList:
|
||||||
|
if (v1.listSize() != v2.listSize()) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"list of size '%d' is not equal to list of size '%d', left hand side is '%s', right hand side is '%s'",
|
||||||
|
v1.listSize(),
|
||||||
|
v2.listSize(),
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
for (size_t n = 0; n < v1.listSize(); ++n) {
|
||||||
|
try {
|
||||||
|
assertEqValues(*v1.listElems()[n], *v2.listElems()[n], pos, errorCtx);
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(positions[pos], "while comparing list element %d", n);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nAttrs: {
|
||||||
|
if (isDerivation(v1) && isDerivation(v2)) {
|
||||||
|
auto i = v1.attrs()->get(sOutPath);
|
||||||
|
auto j = v2.attrs()->get(sOutPath);
|
||||||
|
if (i && j) {
|
||||||
|
try {
|
||||||
|
assertEqValues(*i->value, *j->value, pos, errorCtx);
|
||||||
|
return;
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(positions[pos], "while comparing a derivation by its '%s' attribute", "outPath");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v1.attrs()->size() != v2.attrs()->size()) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"attribute names of attribute set '%s' differs from attribute set '%s'",
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like normal comparison, we compare the attributes in non-deterministic Symbol index order.
|
||||||
|
// This function is called when eqValues has found a difference, so to reliably
|
||||||
|
// report about its result, we should follow in its literal footsteps and not
|
||||||
|
// try anything fancy that could lead to an error.
|
||||||
|
Bindings::const_iterator i, j;
|
||||||
|
for (i = v1.attrs()->begin(), j = v2.attrs()->begin(); i != v1.attrs()->end(); ++i, ++j) {
|
||||||
|
if (i->name != j->name) {
|
||||||
|
// A difference in a sorted list means that one attribute is not contained in the other, but we don't
|
||||||
|
// know which. Let's find out. Could use <, but this is more clear.
|
||||||
|
if (!v2.attrs()->get(i->name)) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"attribute name '%s' is contained in '%s', but not in '%s'",
|
||||||
|
symbols[i->name],
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
if (!v1.attrs()->get(j->name)) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"attribute name '%s' is missing in '%s', but is contained in '%s'",
|
||||||
|
symbols[j->name],
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
assertEqValues(*i->value, *j->value, pos, errorCtx);
|
||||||
|
} catch (Error & e) {
|
||||||
|
// The order of traces is reversed, so this presents as
|
||||||
|
// where left hand side is
|
||||||
|
// at <pos>
|
||||||
|
// where right hand side is
|
||||||
|
// at <pos>
|
||||||
|
// while comparing attribute '<name>'
|
||||||
|
if (j->pos != noPos)
|
||||||
|
e.addTrace(positions[j->pos], "where right hand side is");
|
||||||
|
if (i->pos != noPos)
|
||||||
|
e.addTrace(positions[i->pos], "where left hand side is");
|
||||||
|
e.addTrace(positions[pos], "while comparing attribute '%s'", symbols[i->name]);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case nFunction:
|
||||||
|
error<AssertionError>("distinct functions and immediate comparisons of identical functions compare as unequal")
|
||||||
|
.debugThrow();
|
||||||
|
|
||||||
|
case nExternal:
|
||||||
|
if (!(*v1.external() == *v2.external())) {
|
||||||
|
error<AssertionError>(
|
||||||
|
"external value '%s' is not equal to external value '%s'",
|
||||||
|
ValuePrinter(*this, v1, errorPrintOptions),
|
||||||
|
ValuePrinter(*this, v2, errorPrintOptions))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nFloat:
|
||||||
|
// !!!
|
||||||
|
if (!(v1.fpoint() == v2.fpoint())) {
|
||||||
|
error<AssertionError>("float '%f' is not equal to float '%f'", v1.fpoint(), v2.fpoint()).debugThrow();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case nThunk: // Must not be left by forceValue
|
||||||
|
default:
|
||||||
|
// This should never happen, because eqValues already throws an
|
||||||
|
// error for this, and this function should only be called when
|
||||||
|
// eqValues has found a difference, and it should match
|
||||||
|
// its behavior.
|
||||||
|
error<EvalBaseError>(
|
||||||
|
"cannot compare %1% with %2%; is assertEqValues out of sync with eqValues?", showType(v1), showType(v2))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This implementation must match assertEqValues
|
||||||
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
|
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v1, pos);
|
forceValue(v1, pos);
|
||||||
|
@ -2491,6 +2716,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
||||||
return *v1.external() == *v2.external();
|
return *v1.external() == *v2.external();
|
||||||
|
|
||||||
case nFloat:
|
case nFloat:
|
||||||
|
// !!!
|
||||||
return v1.fpoint() == v2.fpoint();
|
return v1.fpoint() == v2.fpoint();
|
||||||
|
|
||||||
case nThunk: // Must not be left by forceValue
|
case nThunk: // Must not be left by forceValue
|
||||||
|
|
|
@ -644,6 +644,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx);
|
bool eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like `eqValues`, but throws an `AssertionError` if not equal.
|
||||||
|
*
|
||||||
|
* WARNING:
|
||||||
|
* Callers should call `eqValues` first and report if `assertEqValues` behaves
|
||||||
|
* incorrectly. (e.g. if it doesn't throw if eqValues returns false or vice versa)
|
||||||
|
*/
|
||||||
|
void assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx);
|
||||||
|
|
||||||
bool isFunctor(Value & fun);
|
bool isFunctor(Value & fun);
|
||||||
|
|
||||||
// FIXME: use std::span
|
// FIXME: use std::span
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ a = true; } == { a = true; b = true; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-attrs-names-2.nix:1:1:
|
||||||
|
1| assert { a = true; } == { a = true; b = true; };
|
||||||
|
| ^
|
||||||
|
2| throw "unreachable"
|
||||||
|
|
||||||
|
error: attribute names of attribute set '{ a = true; }' differs from attribute set '{ a = true; b = true; }'
|
|
@ -0,0 +1,2 @@
|
||||||
|
assert { a = true; } == { a = true; b = true; };
|
||||||
|
throw "unreachable"
|
|
@ -0,0 +1,8 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ a = true; b = true; } == { a = true; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-attrs-names.nix:1:1:
|
||||||
|
1| assert { a = true; b = true; } == { a = true; };
|
||||||
|
| ^
|
||||||
|
2| throw "unreachable"
|
||||||
|
|
||||||
|
error: attribute names of attribute set '{ a = true; b = true; }' differs from attribute set '{ a = true; }'
|
|
@ -0,0 +1,2 @@
|
||||||
|
assert { a = true; b = true; } == { a = true; };
|
||||||
|
throw "unreachable"
|
|
@ -0,0 +1,26 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ foo = { outPath = "/nix/store/0"; type = "derivation"; }; } == { foo = { devious = true; outPath = "/nix/store/1"; type = "derivation"; }; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-derivations-extra.nix:1:1:
|
||||||
|
1| assert
|
||||||
|
| ^
|
||||||
|
2| { foo = { type = "derivation"; outPath = "/nix/store/0"; }; }
|
||||||
|
|
||||||
|
… while comparing attribute 'foo'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-derivations-extra.nix:2:5:
|
||||||
|
1| assert
|
||||||
|
2| { foo = { type = "derivation"; outPath = "/nix/store/0"; }; }
|
||||||
|
| ^
|
||||||
|
3| ==
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-derivations-extra.nix:4:5:
|
||||||
|
3| ==
|
||||||
|
4| { foo = { type = "derivation"; outPath = "/nix/store/1"; devious = true; }; };
|
||||||
|
| ^
|
||||||
|
5| throw "unreachable"
|
||||||
|
|
||||||
|
… while comparing a derivation by its 'outPath' attribute
|
||||||
|
|
||||||
|
error: string '"/nix/store/0"' is not equal to string '"/nix/store/1"'
|
|
@ -0,0 +1,5 @@
|
||||||
|
assert
|
||||||
|
{ foo = { type = "derivation"; outPath = "/nix/store/0"; }; }
|
||||||
|
==
|
||||||
|
{ foo = { type = "derivation"; outPath = "/nix/store/1"; devious = true; }; };
|
||||||
|
throw "unreachable"
|
|
@ -0,0 +1,26 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ foo = { ignored = (abort "not ignored"); outPath = "/nix/store/0"; type = "derivation"; }; } == { foo = { ignored = (abort "not ignored"); outPath = "/nix/store/1"; type = "derivation"; }; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-derivations.nix:1:1:
|
||||||
|
1| assert
|
||||||
|
| ^
|
||||||
|
2| { foo = { type = "derivation"; outPath = "/nix/store/0"; ignored = abort "not ignored"; }; }
|
||||||
|
|
||||||
|
… while comparing attribute 'foo'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-derivations.nix:2:5:
|
||||||
|
1| assert
|
||||||
|
2| { foo = { type = "derivation"; outPath = "/nix/store/0"; ignored = abort "not ignored"; }; }
|
||||||
|
| ^
|
||||||
|
3| ==
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-derivations.nix:4:5:
|
||||||
|
3| ==
|
||||||
|
4| { foo = { type = "derivation"; outPath = "/nix/store/1"; ignored = abort "not ignored"; }; };
|
||||||
|
| ^
|
||||||
|
5| throw "unreachable"
|
||||||
|
|
||||||
|
… while comparing a derivation by its 'outPath' attribute
|
||||||
|
|
||||||
|
error: string '"/nix/store/0"' is not equal to string '"/nix/store/1"'
|
|
@ -0,0 +1,5 @@
|
||||||
|
assert
|
||||||
|
{ foo = { type = "derivation"; outPath = "/nix/store/0"; ignored = abort "not ignored"; }; }
|
||||||
|
==
|
||||||
|
{ foo = { type = "derivation"; outPath = "/nix/store/1"; ignored = abort "not ignored"; }; };
|
||||||
|
throw "unreachable"
|
22
tests/functional/lang/eval-fail-assert-equal-floats.err.exp
Normal file
22
tests/functional/lang/eval-fail-assert-equal-floats.err.exp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ b = 1; } == { b = 1.01; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-floats.nix:1:1:
|
||||||
|
1| assert { b = 1.0; } == { b = 1.01; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
… while comparing attribute 'b'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-floats.nix:1:10:
|
||||||
|
1| assert { b = 1.0; } == { b = 1.01; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-floats.nix:1:26:
|
||||||
|
1| assert { b = 1.0; } == { b = 1.01; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
error: a float with value '1' is not equal to a float with value '1.01'
|
2
tests/functional/lang/eval-fail-assert-equal-floats.nix
Normal file
2
tests/functional/lang/eval-fail-assert-equal-floats.nix
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
assert { b = 1.0; } == { b = 1.01; };
|
||||||
|
abort "unreachable"
|
|
@ -0,0 +1,9 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '((x: x) == (x: x))'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-function-direct.nix:3:1:
|
||||||
|
2| # This only compares a direct comparison and makes no claims about functions in nested structures.
|
||||||
|
3| assert
|
||||||
|
| ^
|
||||||
|
4| (x: x)
|
||||||
|
|
||||||
|
error: distinct functions and immediate comparisons of identical functions compare as unequal
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Note: functions in nested structures, e.g. attributes, may be optimized away by pointer identity optimization.
|
||||||
|
# This only compares a direct comparison and makes no claims about functions in nested structures.
|
||||||
|
assert
|
||||||
|
(x: x)
|
||||||
|
==
|
||||||
|
(x: x);
|
||||||
|
abort "unreachable"
|
|
@ -0,0 +1,8 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '(1 == 1.1)'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-int-float.nix:1:1:
|
||||||
|
1| assert 1 == 1.1;
|
||||||
|
| ^
|
||||||
|
2| throw "unreachable"
|
||||||
|
|
||||||
|
error: an integer with value '1' is not equal to a float with value '1.1'
|
|
@ -0,0 +1,2 @@
|
||||||
|
assert 1 == 1.1;
|
||||||
|
throw "unreachable"
|
22
tests/functional/lang/eval-fail-assert-equal-ints.err.exp
Normal file
22
tests/functional/lang/eval-fail-assert-equal-ints.err.exp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ b = 1; } == { b = 2; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-ints.nix:1:1:
|
||||||
|
1| assert { b = 1; } == { b = 2; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
… while comparing attribute 'b'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-ints.nix:1:10:
|
||||||
|
1| assert { b = 1; } == { b = 2; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-ints.nix:1:24:
|
||||||
|
1| assert { b = 1; } == { b = 2; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
error: an integer with value '1' is not equal to an integer with value '2'
|
2
tests/functional/lang/eval-fail-assert-equal-ints.nix
Normal file
2
tests/functional/lang/eval-fail-assert-equal-ints.nix
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
assert { b = 1; } == { b = 2; };
|
||||||
|
abort "unreachable"
|
|
@ -0,0 +1,8 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '([ (1) (0) ] == [ (10) ])'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-list-length.nix:1:1:
|
||||||
|
1| assert [ 1 0 ] == [ 10 ];
|
||||||
|
| ^
|
||||||
|
2| throw "unreachable"
|
||||||
|
|
||||||
|
error: list of size '2' is not equal to list of size '1', left hand side is '[ 1 0 ]', right hand side is '[ 10 ]'
|
|
@ -0,0 +1,2 @@
|
||||||
|
assert [ 1 0 ] == [ 10 ];
|
||||||
|
throw "unreachable"
|
|
@ -0,0 +1,8 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '(/pwd/lang/foo == /pwd/lang/bar)'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-paths.nix:1:1:
|
||||||
|
1| assert ./foo == ./bar;
|
||||||
|
| ^
|
||||||
|
2| throw "unreachable"
|
||||||
|
|
||||||
|
error: path '/pwd/lang/foo' is not equal to path '/pwd/lang/bar'
|
2
tests/functional/lang/eval-fail-assert-equal-paths.nix
Normal file
2
tests/functional/lang/eval-fail-assert-equal-paths.nix
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
assert ./foo == ./bar;
|
||||||
|
throw "unreachable"
|
|
@ -0,0 +1,22 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ ding = false; } == { ding = null; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-type-nested.nix:1:1:
|
||||||
|
1| assert { ding = false; } == { ding = null; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
… while comparing attribute 'ding'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-type-nested.nix:1:10:
|
||||||
|
1| assert { ding = false; } == { ding = null; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-type-nested.nix:1:31:
|
||||||
|
1| assert { ding = false; } == { ding = null; };
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
error: a Boolean of value 'false' is not equal to null of value 'null'
|
|
@ -0,0 +1,2 @@
|
||||||
|
assert { ding = false; } == { ding = null; };
|
||||||
|
abort "unreachable"
|
|
@ -0,0 +1,8 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '(false == null)'
|
||||||
|
at /pwd/lang/eval-fail-assert-equal-type.nix:1:1:
|
||||||
|
1| assert false == null;
|
||||||
|
| ^
|
||||||
|
2| abort "unreachable"
|
||||||
|
|
||||||
|
error: a Boolean of value 'false' is not equal to null of value 'null'
|
2
tests/functional/lang/eval-fail-assert-equal-type.nix
Normal file
2
tests/functional/lang/eval-fail-assert-equal-type.nix
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
assert false == null;
|
||||||
|
abort "unreachable"
|
74
tests/functional/lang/eval-fail-assert-nested-bool.err.exp
Normal file
74
tests/functional/lang/eval-fail-assert-nested-bool.err.exp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
error:
|
||||||
|
… while evaluating the condition of the assertion '({ a = { b = [ ({ c = { d = true; }; }) ]; }; } == { a = { b = [ ({ c = { d = false; }; }) ]; }; })'
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:1:
|
||||||
|
1| assert
|
||||||
|
| ^
|
||||||
|
2| { a.b = [ { c.d = true; } ]; }
|
||||||
|
|
||||||
|
… while comparing attribute 'a'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:2:5:
|
||||||
|
1| assert
|
||||||
|
2| { a.b = [ { c.d = true; } ]; }
|
||||||
|
| ^
|
||||||
|
3| ==
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:4:5:
|
||||||
|
3| ==
|
||||||
|
4| { a.b = [ { c.d = false; } ]; };
|
||||||
|
| ^
|
||||||
|
5|
|
||||||
|
|
||||||
|
… while comparing attribute 'b'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:2:5:
|
||||||
|
1| assert
|
||||||
|
2| { a.b = [ { c.d = true; } ]; }
|
||||||
|
| ^
|
||||||
|
3| ==
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:4:5:
|
||||||
|
3| ==
|
||||||
|
4| { a.b = [ { c.d = false; } ]; };
|
||||||
|
| ^
|
||||||
|
5|
|
||||||
|
|
||||||
|
… while comparing list element 0
|
||||||
|
|
||||||
|
… while comparing attribute 'c'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:2:15:
|
||||||
|
1| assert
|
||||||
|
2| { a.b = [ { c.d = true; } ]; }
|
||||||
|
| ^
|
||||||
|
3| ==
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:4:15:
|
||||||
|
3| ==
|
||||||
|
4| { a.b = [ { c.d = false; } ]; };
|
||||||
|
| ^
|
||||||
|
5|
|
||||||
|
|
||||||
|
… while comparing attribute 'd'
|
||||||
|
|
||||||
|
… where left hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:2:15:
|
||||||
|
1| assert
|
||||||
|
2| { a.b = [ { c.d = true; } ]; }
|
||||||
|
| ^
|
||||||
|
3| ==
|
||||||
|
|
||||||
|
… where right hand side is
|
||||||
|
at /pwd/lang/eval-fail-assert-nested-bool.nix:4:15:
|
||||||
|
3| ==
|
||||||
|
4| { a.b = [ { c.d = false; } ]; };
|
||||||
|
| ^
|
||||||
|
5|
|
||||||
|
|
||||||
|
error: boolean 'true' is not equal to boolean 'false'
|
6
tests/functional/lang/eval-fail-assert-nested-bool.nix
Normal file
6
tests/functional/lang/eval-fail-assert-nested-bool.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
assert
|
||||||
|
{ a.b = [ { c.d = true; } ]; }
|
||||||
|
==
|
||||||
|
{ a.b = [ { c.d = false; } ]; };
|
||||||
|
|
||||||
|
abort "unreachable"
|
|
@ -20,9 +20,11 @@ error:
|
||||||
| ^
|
| ^
|
||||||
3|
|
3|
|
||||||
|
|
||||||
error: assertion '(arg == "y")' failed
|
… while evaluating the condition of the assertion '(arg == "y")'
|
||||||
at /pwd/lang/eval-fail-assert.nix:2:12:
|
at /pwd/lang/eval-fail-assert.nix:2:12:
|
||||||
1| let {
|
1| let {
|
||||||
2| x = arg: assert arg == "y"; 123;
|
2| x = arg: assert arg == "y"; 123;
|
||||||
| ^
|
| ^
|
||||||
3|
|
3|
|
||||||
|
|
||||||
|
error: string '"x"' is not equal to string '"y"'
|
||||||
|
|
Loading…
Reference in a new issue