| 1 |
/++ |
|---|
| 2 |
copyright: Copyright (c) 2007 Darryl Bleau. All rights reserved. |
|---|
| 3 |
license: BSD style. |
|---|
| 4 |
version: Oct 2007 |
|---|
| 5 |
author: Darryl B |
|---|
| 6 |
|
|---|
| 7 |
Test is a highly configurable module that allows for detailed code test output for specified TestCases. Output may be customized on a |
|---|
| 8 |
per-Test basis, or disabled entirely. Test results may be stepped through after run for output that isn't provided. The Test is also |
|---|
| 9 |
fairly customizable with regards to language output. Examples of some possible Test output. |
|---|
| 10 |
|
|---|
| 11 |
Example: |
|---|
| 12 |
--- |
|---|
| 13 |
Test of Test |
|---|
| 14 |
-Test of Failure |
|---|
| 15 |
1 :: Warning [1.0041s] |
|---|
| 16 |
2 :: Failure [1.0039s] |
|---|
| 17 |
3 :: Failure [1.0042s] |
|---|
| 18 |
-Test of Exception :: Exception [0.0001s] |
|---|
| 19 |
-Test of Warning :: Warning [1.0036s] |
|---|
| 20 |
-Test of Success :: Success [1.0039s] |
|---|
| 21 |
[5.0196 Seconds] |
|---|
| 22 |
--- |
|---|
| 23 |
|
|---|
| 24 |
Example: |
|---|
| 25 |
--- |
|---|
| 26 |
Test of Test (5.0196 Seconds) |
|---|
| 27 |
[Warning] (1.0041 Seconds) :: Test of Failure [1] (Uh Oh!) |
|---|
| 28 |
[Failure] (1.0039 Seconds) :: Test of Failure [2] (Yikes!) |
|---|
| 29 |
[Failure] (1.0042 Seconds) :: Test of Failure [3] (Oops!, Eeek!, Yikes!) |
|---|
| 30 |
[Warning] (1.0036 Seconds) :: Test of Warning (Erm..., Um...) |
|---|
| 31 |
[Success] (1.0039 Seconds) :: Test of Success (Yay!) |
|---|
| 32 |
[Exception] (0.0001 Seconds) :: Test of Exception (exception) |
|---|
| 33 |
--- |
|---|
| 34 |
|
|---|
| 35 |
The basic use of Test is to create functions (or delegates) which perform the code test, tell Test about them, and then tell it to run. |
|---|
| 36 |
The test functions must return a Test.Status and accept as a parameter a string array to which the test function can append |
|---|
| 37 |
any messages that it may want to have included in the report. |
|---|
| 38 |
|
|---|
| 39 |
Example: |
|---|
| 40 |
--- |
|---|
| 41 |
Test.Status myTestFunction(char[][] messages) { return Test.Success; } |
|---|
| 42 |
auto myTest = new Test("Test Name"); |
|---|
| 43 |
myTest["My Test Case"] = &myTestFunction; |
|---|
| 44 |
myTest.run; |
|---|
| 45 |
--- |
|---|
| 46 |
|
|---|
| 47 |
The Test can be configured to alter it's output via the config struct. |
|---|
| 48 |
Example: |
|---|
| 49 |
--- |
|---|
| 50 |
myTest.config.incremental = false; |
|---|
| 51 |
myTest.config.summary = true; |
|---|
| 52 |
myTest.config.testName = false; |
|---|
| 53 |
myTest.config.timing.precision = 6; |
|---|
| 54 |
myTest.config.timing.postfix = " Seconds"; |
|---|
| 55 |
myTest.config.status.output[Test.Status.Success] = false; |
|---|
| 56 |
myTest.config.status.test[Test.Status.Failure] = "FAILED!!!"; |
|---|
| 57 |
--- |
|---|
| 58 |
This would tell the Test not to output during run (incremental), to output a summary, and not to output the name of the test. |
|---|
| 59 |
The Test will also output all timings at 6 decimal precision, and postfix times with "Seconds". |
|---|
| 60 |
Additionally, the Test will not output any TestCases which were successful, and will output "FAILED!!!" for any TestCases which were failures. |
|---|
| 61 |
+/ |
|---|
| 62 |
|
|---|
| 63 |
module tango.scrapple.util.Test; |
|---|
| 64 |
|
|---|
| 65 |
private import tango.io.Stdout; |
|---|
| 66 |
private import tango.text.Util; |
|---|
| 67 |
private import tango.time.StopWatch; |
|---|
| 68 |
private import tango.core.Array; |
|---|
| 69 |
private import Float = tango.text.convert.Float; |
|---|
| 70 |
private import tango.text.Ascii; |
|---|
| 71 |
private import tango.core.Memory; |
|---|
| 72 |
|
|---|
| 73 |
/++ |
|---|
| 74 |
Provides the Test functionality. A Test may contain multiple TestCases. A TestCase may be added as a function via index: |
|---|
| 75 |
--- |
|---|
| 76 |
myTest["My Test Case"] = &myTestFunction; |
|---|
| 77 |
--- |
|---|
| 78 |
Where the index represents the name of the TestCase. A TestCase may then be retrieved from the same index: |
|---|
| 79 |
--- |
|---|
| 80 |
TestCase myTestCase = myTest["My Test Case"]; |
|---|
| 81 |
--- |
|---|
| 82 |
Delegates may be added to a Test in the same fashion: |
|---|
| 83 |
--- |
|---|
| 84 |
myTest["My Test Case 2"] = &myClass.myFunction; |
|---|
| 85 |
--- |
|---|
| 86 |
TestCase iterations may also be specified by using .add (in this case, each running of the Test will run this test function 4 times): |
|---|
| 87 |
--- |
|---|
| 88 |
myTest.add(&myFunction, "My Test", 4); |
|---|
| 89 |
--- |
|---|
| 90 |
Alternatively, a TestCase may be created and then added to a Test in the same way: |
|---|
| 91 |
--- |
|---|
| 92 |
TestCase myTestCase = new TestCase(&myFunction); |
|---|
| 93 |
myTest["My TestCase"] = myTestCase; |
|---|
| 94 |
--- |
|---|
| 95 |
TestCases may also be added via .add: |
|---|
| 96 |
--- |
|---|
| 97 |
myTest.add(myTestCase, "My TestCase"); |
|---|
| 98 |
--- |
|---|
| 99 |
+/ |
|---|
| 100 |
public class Test |
|---|
| 101 |
{ |
|---|
| 102 |
/// Test status indicators |
|---|
| 103 |
enum Status |
|---|
| 104 |
{ |
|---|
| 105 |
Untested, /// Test has not yet been run. |
|---|
| 106 |
Success, /// Test indicates success. |
|---|
| 107 |
Warning, /// Test did not fail, but has a warning. |
|---|
| 108 |
Exception, /// Test threw an exception. |
|---|
| 109 |
Failure /// Test indicates failure. |
|---|
| 110 |
} |
|---|
| 111 |
|
|---|
| 112 |
/// Provides output-related configuration for the Test |
|---|
| 113 |
struct Config |
|---|
| 114 |
{ |
|---|
| 115 |
bool message = true; /// Output all TestCase messages. |
|---|
| 116 |
bool testTime = false; /// Output timing result for the entire Test. |
|---|
| 117 |
bool caseTime = false; /// Output timing results for each TestCase. |
|---|
| 118 |
bool testName = true; /// Output Test name. |
|---|
| 119 |
bool caseName = true; /// Output each TestCase name. |
|---|
| 120 |
bool incremental = true; /// Output Test results during run. |
|---|
| 121 |
bool summary = false; /// Output Test results summary after run. |
|---|
| 122 |
bool sortName = true; /// Sorts output according to TestCase name. Takes precedence over sortTime. |
|---|
| 123 |
bool sortTime = false; /// Sorts output according to TestCase time. Takes precedence over sortStatus. For multiple iteration tests, the first time is used. |
|---|
| 124 |
bool sortStatus = false; /// Sorts output according to TestCase status. For multiple iteration tests, the first Status is used. |
|---|
| 125 |
/// Status related configuration. |
|---|
| 126 |
struct Status |
|---|
| 127 |
{ |
|---|
| 128 |
bool[] output = |
|---|
| 129 |
[ Test.Status.Untested : true, |
|---|
| 130 |
Test.Status.Success : true, |
|---|
| 131 |
Test.Status.Warning : true, |
|---|
| 132 |
Test.Status.Exception : true, |
|---|
| 133 |
Test.Status.Failure : true ]; /// Boolean array indexed by Test.Status indicating whether TestCases with that status should be output. |
|---|
| 134 |
char[][] text = |
|---|
| 135 |
[ Test.Status.Untested : "Untested", |
|---|
| 136 |
Test.Status.Success : "Success", |
|---|
| 137 |
Test.Status.Warning : "Warning", |
|---|
| 138 |
Test.Status.Exception : "Exception", |
|---|
| 139 |
Test.Status.Failure : "Failure" ]; /// Char array indexed by Test.Status containing the text to be output for that Test.Status. |
|---|
| 140 |
} |
|---|
| 141 |
/// provides status. |
|---|
| 142 |
Status status; |
|---|
| 143 |
/// Timing related configuration. |
|---|
| 144 |
struct Timing |
|---|
| 145 |
{ |
|---|
| 146 |
int precision = 3; /// Decimal precision of timing output. |
|---|
| 147 |
char[] postfix = "s"; /// String to append to timing output. |
|---|
| 148 |
} |
|---|
| 149 |
/// provides timing. |
|---|
| 150 |
Timing timing; |
|---|
| 151 |
} |
|---|
| 152 |
/// provides config. |
|---|
| 153 |
Config config; |
|---|
| 154 |
|
|---|
| 155 |
private TestCase[char[]] _tests; |
|---|
| 156 |
private char[] _name; |
|---|
| 157 |
char[] name() { return _name; } |
|---|
| 158 |
|
|---|
| 159 |
void opIndexAssign(testFunction tf, char[] name) { _tests[name] = new TestCase(tf); } |
|---|
| 160 |
void opIndexAssign(testDelegate td, char[] name) { _tests[name] = new TestCase(td); } |
|---|
| 161 |
void opIndexAssign(TestCase tc, char[] name) { _tests[name] = tc; } |
|---|
| 162 |
void opIndexAssign(int priority, char[] name) |
|---|
| 163 |
{ |
|---|
| 164 |
TestCase tc = _tests[name]; |
|---|
| 165 |
if (tc !is null) |
|---|
| 166 |
tc.priority = priority; |
|---|
| 167 |
} |
|---|
| 168 |
void add(testFunction tf, char[] name, int iterations = 1) { _tests[name] = new TestCase(tf, iterations); } |
|---|
| 169 |
void add(testDelegate td, char[] name, int iterations = 1) { _tests[name] = new TestCase(td, iterations); } |
|---|
| 170 |
void add(TestCase tc, char[] name) { _tests[name] = tc; } |
|---|
| 171 |
TestCase opIndex(char[] name) { return _tests[name]; } |
|---|
| 172 |
|
|---|
| 173 |
int opApply(int delegate(inout TestCase tc, inout char[] name) dg) |
|---|
| 174 |
{ |
|---|
| 175 |
int result; |
|---|
| 176 |
foreach (char[] name, TestCase tc; _tests) |
|---|
| 177 |
if ((result = dg(tc, name)) != 0) |
|---|
| 178 |
break; |
|---|
| 179 |
return result; |
|---|
| 180 |
} |
|---|
| 181 |
|
|---|
| 182 |
int opApply(int delegate(inout TestCase tc) dg) |
|---|
| 183 |
{ |
|---|
| 184 |
int result; |
|---|
| 185 |
foreach (TestCase tc; _tests) |
|---|
| 186 |
if ((result = dg(tc)) != 0) |
|---|
| 187 |
break; |
|---|
| 188 |
return result; |
|---|
| 189 |
} |
|---|
| 190 |
|
|---|
| 191 |
private void _outputLevel(int level) |
|---|
| 192 |
{ |
|---|
| 193 |
for (int i=0; i < level; i++) |
|---|
| 194 |
Stdout(" "); |
|---|
| 195 |
} |
|---|
| 196 |
|
|---|
| 197 |
/// Performs the Test, outputting results as per Test.config, and tracks all TestCase results. |
|---|
| 198 |
void run() |
|---|
| 199 |
{ |
|---|
| 200 |
int outLevel = 0; |
|---|
| 201 |
float totalTime = 0; |
|---|
| 202 |
StopWatch timer; |
|---|
| 203 |
if (config.incremental && config.testName) |
|---|
| 204 |
{ |
|---|
| 205 |
Stdout.format("{}", this._name).newline; |
|---|
| 206 |
outLevel++; |
|---|
| 207 |
} |
|---|
| 208 |
char[][] tcSort; |
|---|
| 209 |
foreach(char[] name, TestCase tc; _tests) |
|---|
| 210 |
tcSort ~= name; |
|---|
| 211 |
tcSort.sort((char[] lhs, char[] rhs) { return (_tests[lhs]._priority < _tests[rhs]._priority); }); |
|---|
| 212 |
|
|---|
| 213 |
foreach (char[] name; tcSort) |
|---|
| 214 |
{ |
|---|
| 215 |
TestCase tc = _tests[name]; |
|---|
| 216 |
if (config.incremental && config.caseName) |
|---|
| 217 |
{ |
|---|
| 218 |
_outputLevel(outLevel); |
|---|
| 219 |
Stdout.format("-{}", name); |
|---|
| 220 |
if (tc._iterations > 1) |
|---|
| 221 |
{ |
|---|
| 222 |
outLevel++; |
|---|
| 223 |
Stdout.newline; |
|---|
| 224 |
} |
|---|
| 225 |
} |
|---|
| 226 |
float totalCaseTime = 0; |
|---|
| 227 |
for (int i = 0; i < tc._iterations; i++) |
|---|
| 228 |
{ |
|---|
| 229 |
if (config.incremental) |
|---|
| 230 |
{ |
|---|
| 231 |
if (config.caseName && (tc._iterations > 1)) |
|---|
| 232 |
{ |
|---|
| 233 |
_outputLevel(outLevel); |
|---|
| 234 |
Stdout.format("{}", i+1); |
|---|
| 235 |
} |
|---|
| 236 |
Stdout("... ").flush; |
|---|
| 237 |
} |
|---|
| 238 |
|
|---|
| 239 |
GC.disable; |
|---|
| 240 |
timer.start; |
|---|
| 241 |
try |
|---|
| 242 |
{ |
|---|
| 243 |
if (tc._testFunction !is null) |
|---|
| 244 |
tc._status[i] = tc._testFunction(tc._messages[i]); |
|---|
| 245 |
else |
|---|
| 246 |
tc._status[i] = tc._testDelegate(tc._messages[i]); |
|---|
| 247 |
} |
|---|
| 248 |
catch (Exception ex) |
|---|
| 249 |
{ |
|---|
| 250 |
tc._status[i] = Status.Exception; |
|---|
| 251 |
tc._messages[i] ~= ex.msg; |
|---|
| 252 |
} |
|---|
| 253 |
totalTime += tc._time[i] = timer.stop; |
|---|
| 254 |
totalCaseTime += tc._time[i]; |
|---|
| 255 |
GC.enable; |
|---|
| 256 |
GC.collect; |
|---|
| 257 |
|
|---|
| 258 |
if (config.incremental) |
|---|
| 259 |
{ |
|---|
| 260 |
Stdout("\b\b\b\b"); |
|---|
| 261 |
if (config.caseName) |
|---|
| 262 |
Stdout(" ::"); |
|---|
| 263 |
if (config.status.output[tc._status[i]]) |
|---|
| 264 |
Stdout.format(" {}", config.status.text[tc._status[i]]); |
|---|
| 265 |
if (config.message && (tc._messages[i] !is null)) |
|---|
| 266 |
Stdout.format(" ({})", join(tc._messages[i], ", ")); |
|---|
| 267 |
if (config.caseTime) |
|---|
| 268 |
Stdout.format(" [{}{}]", Float.toString(tc._time[i], config.timing.precision), config.timing.postfix); |
|---|
| 269 |
Stdout.newline; |
|---|
| 270 |
} |
|---|
| 271 |
} |
|---|
| 272 |
if (config.incremental && config.caseName && (tc._iterations > 1)) |
|---|
| 273 |
{ |
|---|
| 274 |
if (config.caseTime) |
|---|
| 275 |
{ |
|---|
| 276 |
_outputLevel(outLevel); |
|---|
| 277 |
Stdout.format("-Avg: [{}{}], Total: [{}{}]", Float.toString((totalCaseTime / tc._iterations), config.timing.precision), config.timing.postfix, Float.toString(totalCaseTime, config.timing.precision), config.timing.postfix).newline; |
|---|
| 278 |
} |
|---|
| 279 |
outLevel--; |
|---|
| 280 |
} |
|---|
| 281 |
} |
|---|
| 282 |
if (config.incremental && config.testTime) |
|---|
| 283 |
Stdout.format("[{}{}]", Float.toString(totalTime, config.timing.precision), config.timing.postfix).newline; |
|---|
| 284 |
if (config.incremental) |
|---|
| 285 |
Stdout.newline; |
|---|
| 286 |
if (config.summary) |
|---|
| 287 |
this.output; |
|---|
| 288 |
} |
|---|
| 289 |
|
|---|
| 290 |
/// Outputs the results of the Test via Stdout as per the Test.config. |
|---|
| 291 |
void output() |
|---|
| 292 |
{ |
|---|
| 293 |
char[][] tcSort; |
|---|
| 294 |
float totalTime = 0; |
|---|
| 295 |
foreach(char[] name, TestCase tc; _tests) |
|---|
| 296 |
{ |
|---|
| 297 |
tcSort ~= name; |
|---|
| 298 |
for (int i = 0; i < tc._iterations; i++) |
|---|
| 299 |
totalTime += tc._time[i]; |
|---|
| 300 |
} |
|---|
| 301 |
|
|---|
| 302 |
if (config.testName) |
|---|
| 303 |
Stdout.format("{}", this._name); |
|---|
| 304 |
if (config.testTime) |
|---|
| 305 |
Stdout.format(" ({}{})", Float.toString(totalTime, config.timing.precision), config.timing.postfix); |
|---|
| 306 |
if (config.testName || config.testTime) |
|---|
| 307 |
Stdout.newline; |
|---|
| 308 |
|
|---|
| 309 |
if (config.sortName) |
|---|
| 310 |
tcSort.sort; |
|---|
| 311 |
else if (config.sortTime) |
|---|
| 312 |
tcSort.sort((char[] lhs, char[] rhs) { return (_tests[lhs]._time[0] < _tests[rhs]._time[0]); }); |
|---|
| 313 |
else if (config.sortStatus) |
|---|
| 314 |
tcSort.sort((char[] lhs, char[] rhs) { return (_tests[lhs]._status[0] < _tests[rhs]._status[0]); }); |
|---|
| 315 |
foreach(char[] name; tcSort) |
|---|
| 316 |
{ |
|---|
| 317 |
TestCase tc = _tests[name]; |
|---|
| 318 |
for (int i = 0; i < tc._iterations; i++) |
|---|
| 319 |
{ |
|---|
| 320 |
if (config.status.output[tc._status[i]]) |
|---|
| 321 |
Stdout.format(" [{}]", config.status.text[tc._status[i]]); |
|---|
| 322 |
if (config.caseTime) |
|---|
| 323 |
Stdout.format(" ({}{})", Float.toString(tc._time[i], config.timing.precision), config.timing.postfix); |
|---|
| 324 |
if (config.caseName) |
|---|
| 325 |
{ |
|---|
| 326 |
Stdout.format(" :: {}", name); |
|---|
| 327 |
if (tc._iterations > 1) |
|---|
| 328 |
Stdout.format(" [{}]", i+1); |
|---|
| 329 |
} |
|---|
| 330 |
if (config.message) |
|---|
| 331 |
if (tc._messages[i] !is null) |
|---|
| 332 |
Stdout.format(" ({})", join(tc._messages[i], ", ")); |
|---|
| 333 |
Stdout.newline; |
|---|
| 334 |
} |
|---|
| 335 |
} |
|---|
| 336 |
Stdout.newline; |
|---|
| 337 |
} |
|---|
| 338 |
|
|---|
| 339 |
this(char[] name) |
|---|
| 340 |
{ |
|---|
| 341 |
this._name = name; |
|---|
| 342 |
} |
|---|
| 343 |
} |
|---|
| 344 |
|
|---|
| 345 |
alias Test.Status function(inout char[][] messages) testFunction; |
|---|
| 346 |
alias Test.Status delegate(inout char[][] messages) testDelegate; |
|---|
| 347 |
|
|---|
| 348 |
/// An individual TestCase. These may be used for iterating through Test results (for customized output, perhaps). |
|---|
| 349 |
public class TestCase |
|---|
| 350 |
{ |
|---|
| 351 |
private Test.Status[] _status; |
|---|
| 352 |
private char[][][] _messages; |
|---|
| 353 |
private float[] _time; |
|---|
| 354 |
private testFunction _testFunction; |
|---|
| 355 |
private testDelegate _testDelegate; |
|---|
| 356 |
private int _iterations; |
|---|
| 357 |
private int _priority; |
|---|
| 358 |
|
|---|
| 359 |
/// Status result for this TestCase. An index may be specified to retrieve the result for a particular iteration. |
|---|
| 360 |
Test.Status status(int index = 0) { return _status[index]; } |
|---|
| 361 |
/// Messaages relating to this TestCase. An index may be specified to retrieve the messages for a particular iteration. |
|---|
| 362 |
char[][] messages(int index = 0) { return _messages[index]; } |
|---|
| 363 |
/// Timing results for this TestCase. An index may be specified to retrieve the timing for a particular iteration. |
|---|
| 364 |
float time(int index = 0) { return _time[index]; } |
|---|
| 365 |
/// The number of iterations specified for this TestCase. |
|---|
| 366 |
int iterations() { return _iterations; } |
|---|
| 367 |
/// The processing priority for this TestCase, 0 is default, lower numbers are higher priority (run first). |
|---|
| 368 |
int priority() { return _priority; } |
|---|
| 369 |
void priority(int priority) { this._priority = priority; } |
|---|
| 370 |
|
|---|
| 371 |
private void _init(int iterations) |
|---|
| 372 |
{ |
|---|
| 373 |
this._iterations = iterations; |
|---|
| 374 |
_status = new Test.Status[iterations]; |
|---|
| 375 |
_messages = new char[][][iterations]; |
|---|
| 376 |
_time = new float[iterations]; |
|---|
| 377 |
} |
|---|
| 378 |
|
|---|
| 379 |
this(testFunction tf, int iterations = 1) |
|---|
| 380 |
{ |
|---|
| 381 |
this._testFunction = tf; |
|---|
| 382 |
_init(iterations); |
|---|
| 383 |
} |
|---|
| 384 |
|
|---|
| 385 |
this(testDelegate td, int iterations = 1) |
|---|
| 386 |
{ |
|---|
| 387 |
this._testDelegate = td; |
|---|
| 388 |
_init(iterations); |
|---|
| 389 |
} |
|---|
| 390 |
} |
|---|
| 391 |
|
|---|
| 392 |
debug(Test) |
|---|
| 393 |
{ |
|---|
| 394 |
private import tango.core.Thread; |
|---|
| 395 |
|
|---|
| 396 |
Test.Status successFunction(inout char[][] messages) |
|---|
| 397 |
{ |
|---|
| 398 |
Thread.sleep(1); |
|---|
| 399 |
messages ~= "Yay!"; |
|---|
| 400 |
return Test.Status.Success; |
|---|
| 401 |
} |
|---|
| 402 |
|
|---|
| 403 |
class Warning |
|---|
| 404 |
{ |
|---|
| 405 |
Test.Status warningFunction(inout char[][] messages) |
|---|
| 406 |
{ |
|---|
| 407 |
Thread.sleep(1); |
|---|
| 408 |
messages ~= "Erm..."; |
|---|
| 409 |
messages ~= "Um..."; |
|---|
| 410 |
return Test.Status.Warning; |
|---|
| 411 |
} |
|---|
| 412 |
} |
|---|
| 413 |
|
|---|
| 414 |
class Failure |
|---|
| 415 |
{ |
|---|
| 416 |
bool warn = true; |
|---|
| 417 |
bool moreMessages = false; |
|---|
| 418 |
Test.Status failureFunction(inout char[][] messages) |
|---|
| 419 |
{ |
|---|
| 420 |
Thread.sleep(1); |
|---|
| 421 |
if (warn) |
|---|
| 422 |
{ |
|---|
| 423 |
messages ~= "Uh Oh!"; |
|---|
| 424 |
warn = false; |
|---|
| 425 |
return Test.Status.Warning; |
|---|
| 426 |
} |
|---|
| 427 |
if (moreMessages) |
|---|
| 428 |
{ |
|---|
| 429 |
messages ~= "Oops!"; |
|---|
| 430 |
messages ~= "Eeek!"; |
|---|
| 431 |
} |
|---|
| 432 |
else |
|---|
| 433 |
moreMessages = true; |
|---|
| 434 |
messages ~= "Yikes!"; |
|---|
| 435 |
return Test.Status.Failure; |
|---|
| 436 |
} |
|---|
| 437 |
} |
|---|
| 438 |
|
|---|
| 439 |
Test.Status exceptionFunction(inout char[][] messages) |
|---|
| 440 |
{ |
|---|
| 441 |
throw new Exception("exception"); |
|---|
| 442 |
} |
|---|
| 443 |
|
|---|
| 444 |
void main() |
|---|
| 445 |
{ |
|---|
| 446 |
auto myWarning = new Warning; |
|---|
| 447 |
auto myFailure = new Failure; |
|---|
| 448 |
auto myTest = new Test("Test of Test"); |
|---|
| 449 |
myTest.config.timing.postfix = " Seconds"; |
|---|
| 450 |
myTest.config.timing.precision = 4; |
|---|
| 451 |
myTest.config.summary = true; |
|---|
| 452 |
myTest.config.caseTime = true; |
|---|
| 453 |
myTest.config.testTime = true; |
|---|
| 454 |
myTest.config.testName = true; |
|---|
| 455 |
myTest.config.caseName = true; |
|---|
| 456 |
myTest.config.message = true; |
|---|
| 457 |
myTest.config.incremental = true; |
|---|
| 458 |
myTest.config.status.output[Test.Status.Success] = true; |
|---|
| 459 |
myTest.config.status.output[Test.Status.Warning] = true; |
|---|
| 460 |
myTest.config.status.output[Test.Status.Failure] = true; |
|---|
| 461 |
myTest.config.status.text[Test.Status.Failure] = "Failure"; |
|---|
| 462 |
myTest.config.sortName = false; |
|---|
| 463 |
myTest.config.sortTime = true; |
|---|
| 464 |
myTest.config.sortStatus = false; |
|---|
| 465 |
TestCase failureCase = new TestCase(&myFailure.failureFunction, 3); |
|---|
| 466 |
myTest["Test of Success"] = &successFunction; |
|---|
| 467 |
myTest["Test of Warning"] = &myWarning.warningFunction; |
|---|
| 468 |
myTest["Test of Failure"] = failureCase; |
|---|
| 469 |
myTest["Test of Exception"] = &exceptionFunction; |
|---|
| 470 |
myTest.run; |
|---|
| 471 |
} |
|---|
| 472 |
} |
|---|