-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Print all failed test in a test suite which is an arr.ai tuple. #631
base: master
Are you sure you want to change the base?
Conversation
Pull Request Test Coverage Report for Build 656b2ecd1faae2d5c274d338996f403805eb1a8d-PR-631Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
cmd/arrai/multiple_cases_test.arrai contrib/json_test.arrai contrib/util_test.arrai contrib/xml_test.arrai examples/test/multiple_cases_test.arrai examples/test/single_case_test.arrai failed test: not equal expected: Hello, arrai! actual: Hello22, arrai! �[1;37mcmd/arrai/multiple_cases_test.arrai:4:18:�[0m # Added expression let to clarify the actual result can be a complex expression testCase1: //�[1;31mtest.assert.equal("Hello, arrai!", let words = ["Hello22", "arrai!"];//seq.join(", ", words))�[0m, unexpected size expected: 1 actual: {Hello, arrai!} �[1;37mcmd/arrai/multiple_cases_test.arrai:6:18:�[0m testCase2: //test.assert.unequal("Hello, arrai!", //seq.join(", ", ["Nihao", "arrai!"])), testCase3: //�[1;31mtest.assert.size(1, {"Hello", "arrai!"})�[0m, cmd/arrai/multiple_cases_test.arrai failed 5/6 tests passed.
cmd/arrai/multiple_cases_test.arrai contrib/json_test.arrai contrib/util_test.arrai contrib/xml_test.arrai examples/test/multiple_cases_test.arrai examples/test/single_case_test.arrai failed test: not equal expected: Hello, arrai! actual: Hello22, arrai! �[1;37mcmd/arrai/multiple_cases_test.arrai:4:18:�[0m # Added expression let to clarify the actual result can be a complex expression testCase1: //�[1;31mtest.assert.equal("Hello, arrai!", let words = ["Hello22", "arrai!"];//seq.join(", ", words))�[0m, unexpected size expected: 1 actual: {Hello, arrai!} �[1;37mcmd/arrai/multiple_cases_test.arrai:6:18:�[0m testCase2: //test.assert.unequal("Hello, arrai!", //seq.join(", ", ["Nihao", "arrai!"])), testCase3: //�[1;31mtest.assert.size(1, {"Hello", "arrai!"})�[0m, cmd/arrai/multiple_cases_test.arrai failed 5/6 tests passed.
cmd/arrai/multiple_cases_test.arrai contrib/json_test.arrai contrib/util_test.arrai contrib/xml_test.arrai examples/test/multiple_cases_test.arrai examples/test/single_case_test.arrai failed test: not equal expected: Hello, arrai! actual: Hello22, arrai! �[1;37mcmd/arrai/multiple_cases_test.arrai:4:18:�[0m # Added expression let to clarify the actual result can be a complex expression testCase1: //�[1;31mtest.assert.equal("Hello, arrai!", let words = ["Hello22", "arrai!"];//seq.join(", ", words))�[0m, unexpected size expected: 1 actual: {Hello, arrai!} �[1;37mcmd/arrai/multiple_cases_test.arrai:6:18:�[0m testCase2: //test.assert.unequal("Hello, arrai!", //seq.join(", ", ["Nihao", "arrai!"])), testCase3: //�[1;31mtest.assert.size(1, {"Hello", "arrai!"})�[0m, cmd/arrai/multiple_cases_test.arrai failed 5/6 tests passed.
if cmd, isStr := ctx.Value(CmdIdentifier{Name: "test"}).(string); isStr && cmd == "test" { | ||
return e.evalTests(ctx, local) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be required. test.Test
should explicitly unpack the TupleExpr and evaluate each component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type TupleExpr struct {
ExprScanner
attrs []AttrExpr
attrMap map[string]Expr
}
This is current definition of TupleExpr
, so it has to change attrs
to Attrs
to unpack in test.Test
. Is it acceptable? Or it can add new functions in expr_tuple.go
or package rel
for test
.
|
||
// Errors is sequence of error | ||
type Errors struct { | ||
errors []error | ||
} | ||
|
||
// Error returns string represents Errors | ||
func (errs Errors) Error() string { | ||
if len(errs.errors) == 0 { | ||
return "" | ||
} | ||
|
||
var result strings.Builder | ||
for i, err := range errs.errors { | ||
if i > 0 { | ||
result.WriteString("\n\n") | ||
} | ||
result.WriteString(err.Error()) | ||
} | ||
return result.String() | ||
} | ||
|
||
// CmdIdentifier identifies an arrai command like test, shell and eval etc. | ||
type CmdIdentifier struct { | ||
Name string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should live in internal/test/
, since it should only be used in the case of testing.
In general, test-related code should not be mixed in with implementation code.
@@ -151,3 +155,22 @@ func (e *TupleExpr) Eval(ctx context.Context, local Scope) (Value, error) { | |||
// TODO: Construct new tuple directly | |||
return tuple.(*GenericTuple).Canonical(), nil | |||
} | |||
|
|||
func (e *TupleExpr) evalTests(ctx context.Context, local Scope) (Value, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, this should be in internal/test
. It could probably be an extension of the isRecursivelyTrue
function, rather than a separate thing (i.e. in a test, we would want to report all of the errors at all levels of a data structure, not just for tuples and not just one level deep).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current code can't support this approach. The code value, err := expr.Eval(ctx, scope)
calculates the value, as its implementation when one error happens in evaluation, it will stop executing and return a nil
as value
. So it can't calculate the value with some code like isRecursivelyTrue
.
And as current expr
definition, it can't do the similar thing like isRecursivelyTrue
too, refers #631 (comment).
I think it has to do a leverage, open access to attributes in expr
or add some functions in package rel
which can be used by test
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So my thinking is:
- The
_test.arrai
file should at least compile. If it doesn't you shouldn't expect good error reporting. - If the test compiles, then its output will be a data structure: a set, array, dict or tuple (assume for now it's not just a single bool, though that should be allowed).
- Consider the data structure as a tree: it has some branches (internal tree-shaped nodes) and some leaves (primitives, probably booleans). For each leaf that is not
true
, we want to report a failure and include the path through the branches to that leaf, the comparison that failed, and what the expected and actual values were.
To do this, we first evaluate the file and get the data structure and walk through all of the nodes. For each leaf node, add an Entry
to a list with the path we took to get there. If the leaf is not true
, then we do some more work to complete the report.
I'm going to make a key assumption here because it simplifies things a lot and will be largely true in practice. Assume that the data structure containing the test output is statically defined (i.e. a literal, not generated by some other code). Each branch is either a set, array, dict or tuple, and each leaf is some other kind of expression.
So to get the failed comparison, parse the test file and walk the AST in search of the lowest tuple or sequence attribute found in the failed path. If there are multiple (e.g. empty
which could be used in different cases), work your way back up through the parent nodes to find the right one.
Once you have the leaf node (unevaluated at this point), search inside that for a comparison operator (something that returns true: =
, >
, <:
, (<=)
, etc.). When you find one, replace it with some analogue to //test.assert*
which, instead of returning true
or false
, evaluates to a tuple with the data you want to report (expected source and value, actual source and value).
Evaluate that modified AST and walk it, compiling the report from the leaf tuples. Fin.
I expect that I'm glossing over the complexity of "find the comparison", but it's conceptually possible.
You might argue "wow that's hard; this PR is an improvement, shouldn't we just merge it and do the more complete solution as a follow-up?" Maybe. I'm wary because a) it's mixing test code with implementation which is a code smell for both test and implementation code, and b) it's not in the same direction as the solution described above; we would ultimately plan to delete this test code, so why commit it in the first place and add an extra complexity and maintenance burden?
Fixes # .
Changes proposed in this pull request:
Checklist: