Examples block
Solomon E via Digitalmars-d
digitalmars-d at puremagic.com
Sun Aug 21 02:22:54 PDT 2016
On Sunday, 21 August 2016 at 09:02:09 UTC, Solomon E wrote:
> On Saturday, 20 August 2016 at 20:39:13 UTC, Engine Machine
> wrote:
>> We have a unittest, what about an examples?
....
>
> It seems like there could be a library function that
> compile-time-reflects to make a collection of all the functions
> in a module that have names starting with "maintest" and calls
> each of them in a try block, with a catch block that just
> prints the error messages to stderr and incorrect return codes
> and counts the total fails and finally counts the number of
> tests run to return the success ratio.
>
[replying to my own post]
So here's what I wrote on the idea in D, as it cooled down this
evening. It was an interesting exercise in D style. I kept
getting blocked by suggested features not being available (static
foreach, enum string[], etc.) So I decided to cut it down to
something a little simpler than I was going for, no imports or
string mixins or traits or underscores, just the core D language.
I think it shows there are enough features in D to get something
done like building a test framework that allows multiplying the
number of tests that can be run, at a small overhead in verbosity
(i.e. where I had to repeat the function refs and function names.)
module patterntester;
struct PatternTestResults(returnT)
{
ResultsArray!(returnT)[string] funCases;
int failures;
int successes;
int exceptions;
int tries;
int funs;
ulong cases;
}
struct ResultsArray(returnT)
{
PatternTestResult!returnT[int] res;
}
enum SingleTestStatus { UNTESTED = 0, SUCCESS, FAILURE, EXCEPTION
};
struct PatternTestResult(returnT)
{
returnT returned;
Exception exception;
SingleTestStatus status;
}
struct TestIO(argsT, returnT)
{
argsT arguments;
returnT expect;
this(argsT args, returnT ret)
{
arguments = args;
expect = ret;
}
}
immutable(Match!(argsT, returnT))[] FunctionGetter(string
pattern, argsT,
returnT)()
{
Match!(argsT, returnT)[] matches;
foreach(num, fun; maintests.contents)
{
string sym = maintests.names[num];
if (pattern == sym[0 .. pattern.length])
{
matches ~= Match!(argsT, returnT)(sym, fun);
}
}
return matches.idup;
}
struct Match(argsT, returnT)
{
string funName;
returnT function(argsT) funRef;
this(string funStr, returnT function(argsT) funRefer)
{
funName = funStr;
funRef = funRefer;
}
}
PatternTestResults!returnT PatternTest(string pattern, argsT,
returnT)
(TestIO!(argsT, returnT)[int] tests)
{
enum Match!(argsT, returnT)[] matches
= FunctionGetter!(pattern, argsT, returnT)();
PatternTestResults!returnT results;
alias STS = SingleTestStatus;
foreach(match; matches)
{
string funStr = match.funName;
returnT function(argsT) funref = match.funRef;
results.funCases[funStr] = ResultsArray!returnT();
foreach(tnum, testPair; tests)
{
argsT args = testPair.arguments;
returnT expect = testPair.expect;
auto singleResult = PatternTestResult!returnT();
try
{
auto exitcode = funref(args);
if (exitcode != expect)
{
++results.failures;
singleResult.status = STS.FAILURE;
}
else
{
++results.successes;
singleResult.status = STS.SUCCESS;
}
singleResult.returned = exitcode;
}
catch (Exception ex)
{
++results.failures;
++results.exceptions;
singleResult.exception = ex;
singleResult.status = STS.EXCEPTION;
}
finally
{
++results.tries;
}
results.funCases[funStr].res[tnum] = singleResult;
}
++results.funs;
}
results.cases = tests.length;
assert(results.cases * results.funs == results.tries);
return results;
}
struct Flist(argsT, returnT)
{
alias funt = returnT function(argsT);
funt[] contents;
string[] names;
}
enum maintests = Flist!(string[], int)([&maintestA, &maintestB,
&maintestC,
&maintestD],
["maintestA", "maintestB",
"maintestC",
"maintestD"]);
int maintestA(string[] args)
{
return 0;
}
int maintestB(string[] args)
{
return 1;
}
int maintestC(string[] args)
{
throw new Exception("meant throw");
return 0;
}
int maintestD(string[] args)
{
return 3 * (args[$ - 1] == "-A");
}
unittest
{
string df = "./a.out";
alias fntype = TestIO!(string[], int);
// first test set: one success
auto aresult = PatternTest!("maintestA", string[], int)
([1: fntype([df,"a","b"], 0)]);
assert(aresult.failures == 0);
assert(aresult.tries == 1);
assert(aresult.exceptions == 0);
assert(aresult.successes == 1);
assert(aresult.funCases["maintestA"].res[1].returned == 0);
assert(aresult.funCases["maintestA"].res[1].exception is
null);
alias STS = SingleTestStatus;
assert(aresult.funCases["maintestA"].res[1].status ==
STS.SUCCESS);
// second test set: one failure
auto bresult = PatternTest!("maintestB", string[], int)
([1: fntype([df,"a","b"], 0)]);
assert(bresult.failures == 1);
assert(bresult.tries == 1);
assert(bresult.exceptions == 0);
assert(bresult.successes == 0);
assert(bresult.funCases["maintestB"].res[1].returned == 1);
assert(bresult.funCases["maintestB"].res[1].exception is
null);
// third test set: one exception
auto cresult = PatternTest!("maintestC", string[], int)
([1: fntype([df,"a","b"], 0)]);
assert(cresult.failures == 1);
assert(cresult.tries == 1);
assert(cresult.exceptions == 1);
assert(cresult.successes == 0);
assert(cresult.funCases["maintestC"].res[1].returned ==
int.init);
assert(cresult.funCases["maintestC"].res[1].exception !is
null);
assert(cresult.funCases["maintestC"].res[1].exception.msg ==
"meant throw");
// fourth test set: multiplied tests
auto dresult = PatternTest!("maintest", string[], int)
([1: fntype([df,"a","b"], 0),
2: fntype([df,"c","d"], 0),
3: fntype([df,"-x","-A"], 3)]);
assert(dresult.failures == 7);
assert(dresult.tries == 12);
assert(dresult.exceptions == 3);
assert(dresult.successes == 5);
}
void main(string[] args)
{
assert(args[0] == "./d.out");
}
More information about the Digitalmars-d
mailing list