Mathematica Asked by masterxilo on February 20, 2021
I really like this form of assertion failure:
On[Assert];
Assert[1 + 1 == True];
Assert::asrttf: Assertion test 1+1==True evaluated to 2==True that is neither True nor False.
Assert::asrtf: Assertion 1+1==True failed.
I would like something like Assert::asrttf to be generated every time, even say in this case:
Assert[1 + 1 == "2"];
instead of just
Assert::asrtf: Assertion 1+1==2 failed.
I would like to see the intermediate stage
Assert::asrtfr: Assertion 1+1==”2″ failed. Assertion test 1+1==”2″ evaluated to 2==”2″ which is False.
As I have indicated above, I’d also like to see the expression in InputForm
, not StandardForm.
Do I have to do this extension manually? What have others come up with?
Defining $AssertFunction
might be a place to get started, but it is not ideal since when it gets called, the evaluation will have already happened. You will change the program behaviour if you evaluate things again.
Here's an alternative which only generates one message per assertion and has standard evaluation behaviour (I believe)
(* -- Extend Assert --*)
Unprotect@Assert;
Assert::asrttf =
"Assertion test `1` evaluated to `2` that is neither True nor
False. `3`";
Assert::asrtfr =
"Assertion failed. Assertion test `1` evaluated to `2` which is
False. `3`";
Assert::asrtf = "Assertion `1` failed. `2`";
ClearAll[AssertSub, HeldInputForm, formatExtra];
AssertSub~SetAttributes~HoldAllComplete;(*HoldAll to avoid undesired
re-evaluations*)
HeldInputForm~SetAttributes~HoldAllComplete;
HeldInputForm[x_] := RawBoxes@MakeBoxes@HoldForm@InputForm@x;
formatExtra[extra___] := Row[(*HeldInputForm/@*){extra}];
call$AssertFunction~SetAttributes~HoldAllComplete;
call$AssertFunction[test_, extra___] := $AssertFunction[
HoldComplete[Assert[test, extra]]]
AssertSub[True, ___] := Null;
AssertSub[False, test_, HoldComplete@op_,
HoldComplete@dummy_[ops___], {extra___}] := (Message[Assert::asrtfr,
HeldInputForm@test, HeldInputForm@op[ops], formatExtra@extra];
call$AssertFunction[test, extra];)
AssertSub[False,
test_, {extra___}] := (Message[Assert::asrtf, HeldInputForm@test,
formatExtra@extra]; call$AssertFunction[test, extra];)
AssertSub[result_,
test_, _HoldComplete | PatternSequence[], _HoldComplete |
PatternSequence[], {extra___}] := (Message[Assert::asrttf,
HeldInputForm@test, HeldInputForm@result, formatExtra@extra];
call$AssertFunction[test, extra];)
Assert[test : logicalOperation_[operands__], extra___] :=
Module[{dummy}, With[
{(*evaluate parts in standard order: first the head*)
op = logicalOperation,
ops = dummy[
operands](*use inert dummy Head to not eliminate Nothing*)
},
{result = logicalOperation @@ ops(*finish evaluation*)},
(*HoldComplete op and ops:
they might evaluate again now that result is computed,
but that would not usually happen*)
AssertSub[result, test, HoldComplete@op, HoldComplete@ops, {extra}]
]];
Assert[test_, extra___] :=
With[{result = test}, AssertSub[result, test, {extra}]]
Protect@Assert;
(* -- End of Assert extension --*)
It just appends any extra arguments in a Row
, unlike the original assert which uses the "Assertion `1` in `2` failed."
message, as in
Assert[a, b]
Assert::asrttf: Assertion test a evaluated to a that is neither True nor False. Assert::asrtfe: Assertion a in Assert[a,b] failed.
Demos:
Assert[True, "Everything is ok."]
Assert[1 == 1, "1 equals itself."]
Assert[1 == 0, "There is something fishy."]
Assert[1 + 1 ==
"2", "This looked like it should be true with the old Assert."]
Assert[False, "This uses the base case above."]
f[] := False;
Assert[f[], "This uses the base case above."]
Assert[1 + 1 == True, "This generates Assert::asrttf."]
f[] := Print@"f is evaluated";
Assert[f[] =!= Null, "f is only evaluated once."]
nothingFalse[Nothing] = False;
Assert[nothingFalse[Nothing], "This shows why we need a dummy head."]
I then usually set $AssertFunction = Abort[]&;
to support fail-early.
Use
$AssertFunction = Print["$AssertFunction: ", InputForm@#] &;
to see how it's called.
Note that the behaviour of $AssertFunction
changes a bit with this: All Assert
messages are generated prior to calling it, not just Assert::asrttf.
$AssertFunction == Automatic
has no special meaning anymore. Also, Off@Assert
is not implemented (how do we check whether a message is disabled currently?).
Answered by masterxilo on February 20, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP