1 |
sf-pippijn |
1.1 |
#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC |
2 |
|
|
#include "jsontest.h" |
3 |
|
|
#include <stdio.h> |
4 |
|
|
#include <string> |
5 |
|
|
|
6 |
|
|
#if defined(_MSC_VER) |
7 |
|
|
// Used to install a report hook that prevent dialog on assertion and error. |
8 |
|
|
# include <crtdbg.h> |
9 |
|
|
#endif // if defined(_MSC_VER) |
10 |
|
|
|
11 |
|
|
#if defined(_WIN32) |
12 |
|
|
// Used to prevent dialog on memory fault. |
13 |
|
|
// Limits headers included by Windows.h |
14 |
|
|
# define WIN32_LEAN_AND_MEAN |
15 |
|
|
# define NOSERVICE |
16 |
|
|
# define NOMCX |
17 |
|
|
# define NOIME |
18 |
|
|
# define NOSOUND |
19 |
|
|
# define NOCOMM |
20 |
|
|
# define NORPC |
21 |
|
|
# define NOGDI |
22 |
|
|
# define NOUSER |
23 |
|
|
# define NODRIVERS |
24 |
|
|
# define NOLOGERROR |
25 |
|
|
# define NOPROFILER |
26 |
|
|
# define NOMEMMGR |
27 |
|
|
# define NOLFILEIO |
28 |
|
|
# define NOOPENFILE |
29 |
|
|
# define NORESOURCE |
30 |
|
|
# define NOATOM |
31 |
|
|
# define NOLANGUAGE |
32 |
|
|
# define NOLSTRING |
33 |
|
|
# define NODBCS |
34 |
|
|
# define NOKEYBOARDINFO |
35 |
|
|
# define NOGDICAPMASKS |
36 |
|
|
# define NOCOLOR |
37 |
|
|
# define NOGDIOBJ |
38 |
|
|
# define NODRAWTEXT |
39 |
|
|
# define NOTEXTMETRIC |
40 |
|
|
# define NOSCALABLEFONT |
41 |
|
|
# define NOBITMAP |
42 |
|
|
# define NORASTEROPS |
43 |
|
|
# define NOMETAFILE |
44 |
|
|
# define NOSYSMETRICS |
45 |
|
|
# define NOSYSTEMPARAMSINFO |
46 |
|
|
# define NOMSG |
47 |
|
|
# define NOWINSTYLES |
48 |
|
|
# define NOWINOFFSETS |
49 |
|
|
# define NOSHOWWINDOW |
50 |
|
|
# define NODEFERWINDOWPOS |
51 |
|
|
# define NOVIRTUALKEYCODES |
52 |
|
|
# define NOKEYSTATES |
53 |
|
|
# define NOWH |
54 |
|
|
# define NOMENUS |
55 |
|
|
# define NOSCROLL |
56 |
|
|
# define NOCLIPBOARD |
57 |
|
|
# define NOICONS |
58 |
|
|
# define NOMB |
59 |
|
|
# define NOSYSCOMMANDS |
60 |
|
|
# define NOMDI |
61 |
|
|
# define NOCTLMGR |
62 |
|
|
# define NOWINMESSAGES |
63 |
|
|
# include <windows.h> |
64 |
|
|
#endif // if defined(_WIN32) |
65 |
|
|
|
66 |
|
|
namespace JsonTest |
67 |
|
|
{ |
68 |
|
|
/* |
69 |
|
|
* class TestResult |
70 |
|
|
* ////////////////////////////////////////////////////////////////// |
71 |
|
|
*/ |
72 |
|
|
|
73 |
|
|
TestResult::TestResult () |
74 |
|
|
: predicateId_ (1) |
75 |
|
|
, lastUsedPredicateId_ (0) |
76 |
|
|
, messageTarget_ (0) |
77 |
|
|
{ |
78 |
|
|
/* The root predicate has id 0 */ |
79 |
|
|
rootPredicateNode_.id_ = 0; |
80 |
|
|
rootPredicateNode_.next_ = 0; |
81 |
|
|
predicateStackTail_ = &rootPredicateNode_; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
void |
85 |
|
|
TestResult::setTestName (const std::string &name) |
86 |
|
|
{ |
87 |
|
|
name_ = name; |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
TestResult & |
91 |
|
|
TestResult::addFailure (const char *file, unsigned int line, const char *expr) |
92 |
|
|
{ |
93 |
|
|
/* / Walks the PredicateContext stack adding them to failures_ if not already added. */ |
94 |
|
|
unsigned int nestingLevel = 0; |
95 |
|
|
PredicateContext *lastNode = rootPredicateNode_.next_; |
96 |
|
|
|
97 |
|
|
for (; lastNode != 0; lastNode = lastNode->next_) |
98 |
|
|
{ |
99 |
|
|
if (lastNode->id_ > lastUsedPredicateId_) /* new PredicateContext */ |
100 |
|
|
{ |
101 |
|
|
lastUsedPredicateId_ = lastNode->id_; |
102 |
|
|
addFailureInfo (lastNode->file_, lastNode->line_, lastNode->expr_, |
103 |
|
|
nestingLevel); |
104 |
|
|
/* |
105 |
|
|
* Link the PredicateContext to the failure for message target when |
106 |
|
|
* popping the PredicateContext. |
107 |
|
|
*/ |
108 |
|
|
lastNode->failure_ = &(failures_.back ()); |
109 |
|
|
} |
110 |
|
|
++nestingLevel; |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
/* Adds the failed assertion */ |
114 |
|
|
addFailureInfo (file, line, expr, nestingLevel); |
115 |
|
|
messageTarget_ = &(failures_.back ()); |
116 |
|
|
return *this; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
void |
120 |
|
|
TestResult::addFailureInfo (const char *file, unsigned int line, const char *expr, unsigned int nestingLevel) |
121 |
|
|
{ |
122 |
|
|
Failure failure; |
123 |
|
|
|
124 |
|
|
failure.file_ = file; |
125 |
|
|
failure.line_ = line; |
126 |
|
|
if (expr) |
127 |
|
|
failure.expr_ = expr; |
128 |
|
|
failure.nestingLevel_ = nestingLevel; |
129 |
|
|
failures_.push_back (failure); |
130 |
|
|
} |
131 |
|
|
|
132 |
|
|
TestResult & |
133 |
|
|
TestResult::popPredicateContext () |
134 |
|
|
{ |
135 |
|
|
PredicateContext *lastNode = &rootPredicateNode_; |
136 |
|
|
|
137 |
|
|
while (lastNode->next_ != 0 && lastNode->next_->next_ != 0) |
138 |
|
|
lastNode = lastNode->next_; |
139 |
|
|
/* Set message target to popped failure */ |
140 |
|
|
PredicateContext *tail = lastNode->next_; |
141 |
|
|
if (tail != 0 && tail->failure_ != 0) |
142 |
|
|
messageTarget_ = tail->failure_; |
143 |
|
|
/* Remove tail from list */ |
144 |
|
|
predicateStackTail_ = lastNode; |
145 |
|
|
lastNode->next_ = 0; |
146 |
|
|
return *this; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
bool |
150 |
|
|
TestResult::failed () const |
151 |
|
|
{ |
152 |
|
|
return !failures_.empty (); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
unsigned int |
156 |
|
|
TestResult::getAssertionNestingLevel () const |
157 |
|
|
{ |
158 |
|
|
unsigned int level = 0; |
159 |
|
|
const PredicateContext *lastNode = &rootPredicateNode_; |
160 |
|
|
|
161 |
|
|
while (lastNode->next_ != 0) |
162 |
|
|
{ |
163 |
|
|
lastNode = lastNode->next_; |
164 |
|
|
++level; |
165 |
|
|
} |
166 |
|
|
return level; |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
void |
170 |
|
|
TestResult::printFailure (bool printTestName) const |
171 |
|
|
{ |
172 |
|
|
if (failures_.empty ()) |
173 |
|
|
return; |
174 |
|
|
|
175 |
|
|
if (printTestName) |
176 |
|
|
printf ("* Detail of %s test failure:\n", name_.c_str ()); |
177 |
|
|
|
178 |
|
|
/* Print in reverse to display the callstack in the right order */ |
179 |
|
|
Failures::const_iterator itEnd = failures_.end (); |
180 |
|
|
for (Failures::const_iterator it = failures_.begin (); it != itEnd; ++it) |
181 |
|
|
{ |
182 |
|
|
const Failure &failure = *it; |
183 |
|
|
std::string indent (failure.nestingLevel_ * 2, ' '); |
184 |
|
|
if (failure.file_) |
185 |
|
|
printf ("%s%s(%d): ", indent.c_str (), failure.file_, failure.line_); |
186 |
|
|
if (!failure.expr_.empty ()) |
187 |
|
|
printf ("%s\n", failure.expr_.c_str ()); |
188 |
|
|
else if (failure.file_) |
189 |
|
|
printf ("\n"); |
190 |
|
|
if (!failure.message_.empty ()) |
191 |
|
|
{ |
192 |
|
|
std::string reindented = indentText (failure.message_, indent + " "); |
193 |
|
|
printf ("%s\n", reindented.c_str ()); |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
std::string |
199 |
|
|
TestResult::indentText (const std::string &text, const std::string &indent) |
200 |
|
|
{ |
201 |
|
|
std::string reindented; |
202 |
|
|
std::string::size_type lastIndex = 0; |
203 |
|
|
|
204 |
|
|
while (lastIndex < text.size ()) |
205 |
|
|
{ |
206 |
|
|
std::string::size_type nextIndex = text.find ('\n', lastIndex); |
207 |
|
|
if (nextIndex == std::string::npos) |
208 |
|
|
nextIndex = text.size () - 1; |
209 |
|
|
reindented += indent; |
210 |
|
|
reindented += text.substr (lastIndex, nextIndex - lastIndex + 1); |
211 |
|
|
lastIndex = nextIndex + 1; |
212 |
|
|
} |
213 |
|
|
return reindented; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
TestResult & |
217 |
|
|
TestResult::addToLastFailure (const std::string &message) |
218 |
|
|
{ |
219 |
|
|
if (messageTarget_ != 0) |
220 |
|
|
messageTarget_->message_ += message; |
221 |
|
|
return *this; |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
TestResult & |
225 |
|
|
TestResult::operator << (bool value) |
226 |
|
|
{ |
227 |
|
|
return addToLastFailure (value ? "true" : "false"); |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
TestResult & |
231 |
|
|
TestResult::operator << (int value) |
232 |
|
|
{ |
233 |
|
|
char buffer[32]; |
234 |
|
|
|
235 |
|
|
sprintf (buffer, "%d", value); |
236 |
|
|
return addToLastFailure (buffer); |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
TestResult & |
240 |
|
|
TestResult::operator << (unsigned int value) |
241 |
|
|
{ |
242 |
|
|
char buffer[32]; |
243 |
|
|
|
244 |
|
|
sprintf (buffer, "%u", value); |
245 |
|
|
return addToLastFailure (buffer); |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
TestResult & |
249 |
|
|
TestResult::operator << (double value) |
250 |
|
|
{ |
251 |
|
|
char buffer[32]; |
252 |
|
|
|
253 |
|
|
sprintf (buffer, "%16g", value); |
254 |
|
|
return addToLastFailure (buffer); |
255 |
|
|
} |
256 |
|
|
|
257 |
|
|
TestResult & |
258 |
|
|
TestResult::operator << (const char *value) |
259 |
|
|
{ |
260 |
|
|
return addToLastFailure (value ? value |
261 |
|
|
: "<NULL>"); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
TestResult & |
265 |
|
|
TestResult::operator << (const std::string &value) |
266 |
|
|
{ |
267 |
|
|
return addToLastFailure (value); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
/* |
271 |
|
|
* class TestCase |
272 |
|
|
* ////////////////////////////////////////////////////////////////// |
273 |
|
|
*/ |
274 |
|
|
|
275 |
|
|
TestCase::TestCase () |
276 |
|
|
: result_ (0) |
277 |
|
|
{ |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
TestCase::~TestCase () |
281 |
|
|
{ |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
void |
285 |
|
|
TestCase::run (TestResult &result) |
286 |
|
|
{ |
287 |
|
|
result_ = &result; |
288 |
|
|
runTestCase (); |
289 |
|
|
} |
290 |
|
|
|
291 |
|
|
/* |
292 |
|
|
* class Runner |
293 |
|
|
* ////////////////////////////////////////////////////////////////// |
294 |
|
|
*/ |
295 |
|
|
|
296 |
|
|
Runner::Runner () |
297 |
|
|
{ |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
Runner & |
301 |
|
|
Runner::add (TestCaseFactory factory) |
302 |
|
|
{ |
303 |
|
|
tests_.push_back (factory); |
304 |
|
|
return *this; |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
unsigned int |
308 |
|
|
Runner::testCount () const |
309 |
|
|
{ |
310 |
|
|
return static_cast<unsigned int> (tests_.size ()); |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
std::string |
314 |
|
|
Runner::testNameAt (unsigned int index) const |
315 |
|
|
{ |
316 |
|
|
TestCase *test = tests_[index] (); |
317 |
|
|
std::string name = test->testName (); |
318 |
|
|
|
319 |
|
|
delete test; |
320 |
|
|
return name; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
void |
324 |
|
|
Runner::runTestAt (unsigned int index, TestResult &result) const |
325 |
|
|
{ |
326 |
|
|
TestCase *test = tests_[index] (); |
327 |
|
|
|
328 |
|
|
result.setTestName (test->testName ()); |
329 |
|
|
printf ("Testing %s: ", test->testName ()); |
330 |
|
|
fflush (stdout); |
331 |
|
|
#if JSON_USE_EXCEPTION |
332 |
|
|
try |
333 |
|
|
{ |
334 |
|
|
#endif /* if JSON_USE_EXCEPTION */ |
335 |
|
|
test->run (result); |
336 |
|
|
#if JSON_USE_EXCEPTION |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
catch (const std::exception &e) |
340 |
|
|
{ |
341 |
|
|
result.addFailure (__FILE__, __LINE__, |
342 |
|
|
"Unexpected exception caugth:") << e.what (); |
343 |
|
|
} |
344 |
|
|
#endif /* if JSON_USE_EXCEPTION */ |
345 |
|
|
delete test; |
346 |
|
|
const char *status = result.failed () ? "FAILED" |
347 |
|
|
: "OK"; |
348 |
|
|
printf ("%s\n", status); |
349 |
|
|
fflush (stdout); |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
|
353 |
|
|
bool |
354 |
|
|
Runner::runAllTest (bool printSummary) const |
355 |
|
|
{ |
356 |
|
|
unsigned int count = testCount (); |
357 |
|
|
|
358 |
|
|
std::deque<TestResult> failures; |
359 |
|
|
for (unsigned int index = 0; index < count; ++index) |
360 |
|
|
{ |
361 |
|
|
TestResult result; |
362 |
|
|
runTestAt (index, result); |
363 |
|
|
if (result.failed ()) |
364 |
|
|
failures.push_back (result); |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
if (failures.empty ()) |
368 |
|
|
{ |
369 |
|
|
if (printSummary) |
370 |
|
|
printf ("All %d tests passed\n", count); |
371 |
|
|
return true; |
372 |
|
|
} |
373 |
|
|
else |
374 |
|
|
{ |
375 |
|
|
for (unsigned int index = 0; index < failures.size (); ++index) |
376 |
|
|
{ |
377 |
|
|
TestResult &result = failures[index]; |
378 |
|
|
result.printFailure (count > 1); |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
if (printSummary) |
382 |
|
|
{ |
383 |
|
|
unsigned int failedCount = static_cast<unsigned int> (failures.size ()); |
384 |
|
|
unsigned int passedCount = count - failedCount; |
385 |
|
|
printf ("%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount); |
386 |
|
|
} |
387 |
|
|
return false; |
388 |
|
|
} |
389 |
|
|
} |
390 |
|
|
|
391 |
|
|
bool |
392 |
|
|
Runner::testIndex (const std::string &testName, unsigned int &indexOut) const |
393 |
|
|
{ |
394 |
|
|
unsigned int count = testCount (); |
395 |
|
|
|
396 |
|
|
for (unsigned int index = 0; index < count; ++index) |
397 |
|
|
if (testNameAt (index) == testName) |
398 |
|
|
{ |
399 |
|
|
indexOut = index; |
400 |
|
|
return true; |
401 |
|
|
} |
402 |
|
|
return false; |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
void |
406 |
|
|
Runner::listTests () const |
407 |
|
|
{ |
408 |
|
|
unsigned int count = testCount (); |
409 |
|
|
|
410 |
|
|
for (unsigned int index = 0; index < count; ++index) |
411 |
|
|
printf ("%s\n", testNameAt (index).c_str ()); |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
int |
415 |
|
|
Runner::runCommandLine (int argc, const char *argv[]) const |
416 |
|
|
{ |
417 |
|
|
typedef std::deque<std::string> TestNames; |
418 |
|
|
Runner subrunner; |
419 |
|
|
for (int index = 1; index < argc; ++index) |
420 |
|
|
{ |
421 |
|
|
std::string opt = argv[index]; |
422 |
|
|
if (opt == "--list-tests") |
423 |
|
|
{ |
424 |
|
|
listTests (); |
425 |
|
|
return 0; |
426 |
|
|
} |
427 |
|
|
else if (opt == "--test-auto") |
428 |
|
|
preventDialogOnCrash (); |
429 |
|
|
else if (opt == "--test") |
430 |
|
|
{ |
431 |
|
|
++index; |
432 |
|
|
if (index < argc) |
433 |
|
|
{ |
434 |
|
|
unsigned int testNameIndex; |
435 |
|
|
if (testIndex (argv[index], testNameIndex)) |
436 |
|
|
subrunner.add (tests_[testNameIndex]); |
437 |
|
|
else |
438 |
|
|
{ |
439 |
|
|
fprintf (stderr, "Test '%s' does not exist!\n", argv[index]); |
440 |
|
|
return 2; |
441 |
|
|
} |
442 |
|
|
} |
443 |
|
|
else |
444 |
|
|
{ |
445 |
|
|
printUsage (argv[0]); |
446 |
|
|
return 2; |
447 |
|
|
} |
448 |
|
|
} |
449 |
|
|
else |
450 |
|
|
{ |
451 |
|
|
printUsage (argv[0]); |
452 |
|
|
return 2; |
453 |
|
|
} |
454 |
|
|
} |
455 |
|
|
bool succeeded; |
456 |
|
|
if (subrunner.testCount () > 0) |
457 |
|
|
succeeded = subrunner.runAllTest (subrunner.testCount () > 1); |
458 |
|
|
else |
459 |
|
|
succeeded = runAllTest (true); |
460 |
|
|
return succeeded ? 0 |
461 |
|
|
: 1; |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
#if defined(_MSC_VER) |
465 |
|
|
/* Hook MSVCRT assertions to prevent dialog from appearing */ |
466 |
|
|
static int |
467 |
|
|
msvcrtSilentReportHook (int reportType, char *message, int *returnValue) |
468 |
|
|
{ |
469 |
|
|
/* |
470 |
|
|
* The default CRT handling of error and assertion is to display |
471 |
|
|
* an error dialog to the user. |
472 |
|
|
* Instead, when an error or an assertion occurs, we force the |
473 |
|
|
* application to terminate using abort() after display |
474 |
|
|
* the message on stderr. |
475 |
|
|
*/ |
476 |
|
|
if (reportType == _CRT_ERROR || |
477 |
|
|
reportType == _CRT_ASSERT) |
478 |
|
|
{ |
479 |
|
|
/* |
480 |
|
|
* calling abort() cause the ReportHook to be called |
481 |
|
|
* The following is used to detect this case and let's the |
482 |
|
|
* error handler fallback on its default behaviour ( |
483 |
|
|
* display a warning message) |
484 |
|
|
*/ |
485 |
|
|
static volatile bool isAborting = false; |
486 |
|
|
if (isAborting) |
487 |
|
|
return TRUE; |
488 |
|
|
isAborting = true; |
489 |
|
|
|
490 |
|
|
fprintf (stderr, "CRT Error/Assert:\n%s\n", message); |
491 |
|
|
fflush (stderr); |
492 |
|
|
abort (); |
493 |
|
|
} |
494 |
|
|
/* Let's other reportType (_CRT_WARNING) be handled as they would by default */ |
495 |
|
|
return FALSE; |
496 |
|
|
} |
497 |
|
|
#endif /* if defined(_MSC_VER) */ |
498 |
|
|
|
499 |
|
|
|
500 |
|
|
|
501 |
|
|
void |
502 |
|
|
Runner::preventDialogOnCrash () |
503 |
|
|
{ |
504 |
|
|
#if defined(_MSC_VER) |
505 |
|
|
/* |
506 |
|
|
* Install a hook to prevent MSVCRT error and assertion from |
507 |
|
|
* popping a dialog. |
508 |
|
|
*/ |
509 |
|
|
_CrtSetReportHook (&msvcrtSilentReportHook); |
510 |
|
|
#endif /* if defined(_MSC_VER) */ |
511 |
|
|
|
512 |
|
|
/* |
513 |
|
|
* @todo investiguate this handler (for buffer overflow) |
514 |
|
|
* _set_security_error_handler |
515 |
|
|
*/ |
516 |
|
|
|
517 |
|
|
#if defined(_WIN32) |
518 |
|
|
/* |
519 |
|
|
* Prevents the system from popping a dialog for debugging if the |
520 |
|
|
* application fails due to invalid memory access. |
521 |
|
|
*/ |
522 |
|
|
SetErrorMode (SEM_FAILCRITICALERRORS |
523 |
|
|
| SEM_NOGPFAULTERRORBOX |
524 |
|
|
| SEM_NOOPENFILEERRORBOX); |
525 |
|
|
#endif /* if defined(_WIN32) */ |
526 |
|
|
} |
527 |
|
|
|
528 |
|
|
void |
529 |
|
|
Runner::printUsage (const char *appName) |
530 |
|
|
{ |
531 |
|
|
printf ( |
532 |
|
|
"Usage: %s [options]\n" |
533 |
|
|
"\n" |
534 |
|
|
"If --test is not specified, then all the test cases be run.\n" |
535 |
|
|
"\n" |
536 |
|
|
"Valid options:\n" |
537 |
|
|
"--list-tests: print the name of all test cases on the standard\n" |
538 |
|
|
" output and exit.\n" |
539 |
|
|
"--test TESTNAME: executes the test case with the specified name.\n" |
540 |
|
|
" May be repeated.\n" |
541 |
|
|
"--test-auto: prevent dialog prompting for debugging on crash.\n" |
542 |
|
|
, appName); |
543 |
|
|
} |
544 |
|
|
|
545 |
|
|
/* |
546 |
|
|
* Assertion functions |
547 |
|
|
* ////////////////////////////////////////////////////////////////// |
548 |
|
|
*/ |
549 |
|
|
|
550 |
|
|
TestResult & |
551 |
|
|
checkStringEqual (TestResult &result, const std::string &expected, const std::string &actual, const char *file, unsigned int line, const char *expr) |
552 |
|
|
{ |
553 |
|
|
if (expected != actual) |
554 |
|
|
{ |
555 |
|
|
result.addFailure (file, line, expr); |
556 |
|
|
result << "Expected: '" << expected << "'\n"; |
557 |
|
|
result << "Actual : '" << actual << "'"; |
558 |
|
|
} |
559 |
|
|
return result; |
560 |
|
|
} |
561 |
|
|
} /* namespace JsonTest */ |