From e93bf69b448d4f4ce6c3fe7b7acfa904afe058c0 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Tue, 25 Oct 2022 01:46:10 +0200 Subject: Rework error throwing, and test it --- src/libexpr/tests/error_traces.cc | 96 +++++++++++++++++++++++++++++++++++++++ src/libexpr/tests/primops.cc | 6 +++ 2 files changed, 102 insertions(+) create mode 100644 src/libexpr/tests/error_traces.cc (limited to 'src/libexpr/tests') diff --git a/src/libexpr/tests/error_traces.cc b/src/libexpr/tests/error_traces.cc new file mode 100644 index 000000000..6905dd561 --- /dev/null +++ b/src/libexpr/tests/error_traces.cc @@ -0,0 +1,96 @@ +#include +#include + +#include "libexprtests.hh" + +namespace nix { + + using namespace testing; + + // Testing eval of PrimOp's + class ErrorTraceTest : public LibExprTest { }; + +#define ASSERT_TRACE1(args, type, message) \ + ASSERT_THROW( \ + try { \ + eval("builtins." args); \ + } catch (BaseError & e) { \ + ASSERT_EQ(PrintToString(e.info().msg), \ + PrintToString(message)); \ + auto trace = e.info().traces.rbegin(); \ + ASSERT_EQ(PrintToString(trace->hint), \ + PrintToString(hintfmt("while calling the '%s' builtin", "genericClosure"))); \ + throw; \ + } \ + , type \ + ) + +#define ASSERT_TRACE2(args, type, message, context) \ + ASSERT_THROW( \ + try { \ + eval("builtins." args); \ + } catch (BaseError & e) { \ + ASSERT_EQ(PrintToString(e.info().msg), \ + PrintToString(message)); \ + 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", "genericClosure"))); \ + throw; \ + } \ + , type \ + ) + + //TEST_F(ErrorTraceTest, genericClosure) { + //ASSERT_THROW( + //try { + //eval("builtins.genericClosure 1 1"); + //} catch (BaseError & e) { + //ASSERT_EQ(PrintToString(e.info().msg), PrintToString(hintfmt("value is %s while a set was expected", "an integer"))); + //throw; + //}, TypeError); + //} + + 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_TRACE1("genericClosure {}", + TypeError, + hintfmt("attribute '%s' missing %s", "startSet", normaltxt("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")); + // Okay: "genericClosure { startSet = []; }" + 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")); // TODO: inconsistent naming + + 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_TRACE1("genericClosure { startSet = [{ key = 1;}]; operator = item: [ {} ]; }", + TypeError, + hintfmt("attribute '%s' missing %s", "key", normaltxt("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")); + } + +} /* namespace nix */ diff --git a/src/libexpr/tests/primops.cc b/src/libexpr/tests/primops.cc index 16cf66d2c..a4102753c 100644 --- a/src/libexpr/tests/primops.cc +++ b/src/libexpr/tests/primops.cc @@ -836,4 +836,10 @@ namespace nix { 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 */ -- cgit v1.2.3 From d6f5734c630f893e8695bd37ca2b0dbf2bb24daa Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Tue, 25 Oct 2022 01:57:18 +0200 Subject: Complete genericClosure tests --- src/libexpr/tests/error_traces.cc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/libexpr/tests') diff --git a/src/libexpr/tests/error_traces.cc b/src/libexpr/tests/error_traces.cc index 6905dd561..8741ecdd2 100644 --- a/src/libexpr/tests/error_traces.cc +++ b/src/libexpr/tests/error_traces.cc @@ -43,16 +43,6 @@ namespace nix { , type \ ) - //TEST_F(ErrorTraceTest, genericClosure) { - //ASSERT_THROW( - //try { - //eval("builtins.genericClosure 1 1"); - //} catch (BaseError & e) { - //ASSERT_EQ(PrintToString(e.info().msg), PrintToString(hintfmt("value is %s while a set was expected", "an integer"))); - //throw; - //}, TypeError); - //} - TEST_F(ErrorTraceTest, genericClosure) { \ ASSERT_TRACE2("genericClosure 1", TypeError, @@ -67,7 +57,9 @@ namespace nix { TypeError, hintfmt("value is %s while a list was expected", "an integer"), hintfmt("while evaluating the 'startSet' attribute passed as argument to builtins.genericClosure")); + // Okay: "genericClosure { startSet = []; }" + ASSERT_TRACE2("genericClosure { startSet = [{ key = 1;}]; operator = true; }", TypeError, hintfmt("value is %s while a function was expected", "a Boolean"), @@ -91,6 +83,12 @@ namespace nix { 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")); + } } /* namespace nix */ -- cgit v1.2.3