8

Seems to me that VerificationTests are a bit verbose:

TestReport[{VerificationTest[StringFreeQ["apple", "lp"], True], 
  VerificationTest[StringFreeQ["apple", "a" ~~ __ ~~ "e"], False], 
  VerificationTest[StringFreeQ["apple", "ap"], False], 
  VerificationTest[StringFreeQ["apple", "x"], True], 
  VerificationTest[StringFreeQ["", "asd"], True]}]

This was the first obvious thing that I tried:

args := {{"apple", "lp"}, {"apple", "a" ~~ __ ~~ "e"}, {"apple", "ap"}, {"apple", "x"}, {"", "asd"}};
results := {True, False, (Pause[2]; False), True, True};

tr = TestReport[
  VerificationTest @@@ Thread[{StringFreeQ @@@ args, results}], 
  TimeConstraint -> Quantity[1, "Seconds"]]

But this solution has many problems:

  • Timing specs and information aren't enforced and preserved
  • Evaluations may leak

What are some elegant ways to cut down the verbosity here without messing with evaluation mechanics of the arguments to VerificationTest?

M.R.
  • 31,425
  • 8
  • 90
  • 281

2 Answers2

11

You can make it look somewhat more pleasant by using simple expression parsers. For example, define an auxiliary head Tests, as follows:

ClearAll[transformTest];
SetAttributes[transformTest, {HoldAll, Listable}];
transformTest[lhs_ -> rhs_] := Hold[VerificationTest[lhs, rhs]];
transformTest[Tests[tests___]] := Thread[transformTest[{tests}], Hold];


ClearAll[Tests];
SetAttributes[Tests, HoldAll];
Tests /: TestReport[t_Tests, args___] :=
  Replace[
    transformTest[t],
    Hold[tests___] :> TestReport[tests, args]
  ];

And now you can use the following syntax:

TestReport @ Tests[
  StringFreeQ["apple", "lp"] -> True, 
  StringFreeQ["apple", "a" ~~ __ ~~ "e"] -> False,
  StringFreeQ["apple", "ap"] -> False, 
  StringFreeQ["apple", "x"] -> True,
  StringFreeQ["", "asd"] -> True
]

which looks a little nicer to me.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
3

You can make your own code work simply enough by controlling evaluating with e.g. Inactive

Inactive[TestReport][
  Inactive[VerificationTest] @@@ 
   Thread[{Inactive[StringFreeQ] @@@ args, results}]] // Activate

or Block:

Block[{StringFreeQ, VerificationTest, TestReport},
  TestReport[VerificationTest @@@ Thread[{StringFreeQ @@@ args, results}]]
]

If writing this myself I would probably use my own heldCases and this:

heldCases[
  Thread @ {args, results},
  {{a_, b_}, r_} :>
    VerificationTest[StringFreeQ[a, b], r]
] /. _[x__] :> TestReport[{x}]

I prefer Leonid's more general approach however.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371