testlib.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. #ifndef _TESTLIB_H_
  2. #define _TESTLIB_H_
  3. /*
  4. *
  5. * Copyright (c) 2005-2009
  6. */
  7. #define VERSION "0.5.2"
  8. /*
  9. * Mike Mirzayanov
  10. *
  11. * This material is provided "as is", with absolutely no warranty expressed
  12. * or implied. Any use is at your own risk.
  13. *
  14. * Permission to use or copy this software for any purpose is hereby granted
  15. * without fee, provided the above notices are retained on all copies.
  16. * Permission to modify the code and to distribute modified code is granted,
  17. * provided the above notices are retained, and a notice that the code was
  18. * modified is included with the above copyright notice.
  19. *
  20. */
  21. /* NOTE: This file contains testlib library for C++.
  22. *
  23. * Program, using testlib running format:
  24. * check.exe <Input_File> <Output_File> <Answer_File> [<Result_File> [-appes]],
  25. *
  26. * If result file is specified it will contain results.
  27. */
  28. const char* latestFeatures[] = {
  29. "Added InStream::readLong() and removed InStream::readLongint()",
  30. "Now no footer added to each report by default (use directive FOOTER to switch on)",
  31. "Now every checker has a name, use setName(const char* format, ...) to set it",
  32. "Now it is compatible with TTS (by Kittens Computing)",
  33. "Added \'ensure(condition, message = \"\")\' feature, it works like assert()",
  34. "Fixed compatibility with MS C++ 7.1",
  35. "Added footer with exit code information",
  36. "Added compatibility with EJUDGE (compile with EJUDGE directive)"
  37. };
  38. #ifdef _MSC_VER
  39. #define _CRT_SECURE_NO_DEPRECATE
  40. #endif
  41. #include <cstdio>
  42. #include <cctype>
  43. #include <string>
  44. #include <string.h>
  45. #include <stdarg.h>
  46. #include <cstdlib>
  47. #if ( _WIN32 || __WIN32__ )
  48. #include <windows.h>
  49. #else
  50. #define WORD unsigned short
  51. #endif
  52. #define ABS(f) ((f) < 0 ? -(f) : (f))
  53. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  54. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  55. #define OUTPUT_BUFFER_SIZE (2097152)
  56. #define LF (char)10
  57. #define CR (char)13
  58. #define TAB (char)9
  59. #define SPACE (char)' '
  60. #define EOFCHAR (EOF)
  61. #define EOFREMAP SPACE
  62. #define NUMBERBEFORE LF, CR, SPACE, TAB, EOFCHAR
  63. #define NUMBERAFTER LF, CR, TAB, EOFCHAR
  64. #define LINEAFTER LF, CR, EOFCHAR
  65. #define BLANKS LF, CR, SPACE, TAB
  66. #define EOLNCHAR LF, CR, EOFCHAR
  67. #ifndef EJUDGE
  68. #define OK_EXIT_CODE 0
  69. #define WA_EXIT_CODE 1
  70. #define PE_EXIT_CODE 2
  71. #define FAIL_EXIT_CODE 3
  72. #define DIRT_EXIT_CODE 4
  73. #else
  74. #define OK_EXIT_CODE 0
  75. #define WA_EXIT_CODE 5
  76. #define PE_EXIT_CODE 4
  77. #define FAIL_EXIT_CODE 6
  78. #define DIRT_EXIT_CODE 6
  79. #endif
  80. inline bool isEofChar(char c)
  81. {
  82. return (c == EOFCHAR);
  83. }
  84. inline bool isEofRemap(char c)
  85. {
  86. return (c == EOFREMAP);
  87. }
  88. inline bool isNumberBefore(char c)
  89. {
  90. return (c == LF || c == CR || c == SPACE || c == TAB);
  91. }
  92. inline bool isNumberAfter(char c)
  93. {
  94. return (c == LF || c == CR || c == SPACE || c == TAB || c == EOFCHAR || c == (char)26);
  95. }
  96. inline bool isLineAfter(char c)
  97. {
  98. return (c == LF || c == CR || c == EOFCHAR || c == (char)26);
  99. }
  100. inline bool isBlanks(char c)
  101. {
  102. return (c == LF || c == CR || c == SPACE || c == TAB);
  103. }
  104. inline bool isEolnChar(char c)
  105. {
  106. return (c == LF || c == CR || c == EOFCHAR || c == (char)26);
  107. }
  108. struct TCharSet
  109. {
  110. unsigned int data[64];
  111. void insert(char c)
  112. {
  113. int pc = (int)c;
  114. data[pc >> 3] |= (1 << (pc & 7));
  115. }
  116. bool count(char c)
  117. {
  118. unsigned int pc = (unsigned char)c;
  119. return (data[pc >> 3] & (1 << (pc & 7))) != 0;
  120. }
  121. void clear()
  122. {
  123. memset(data, 0, sizeof(data));
  124. }
  125. TCharSet()
  126. {
  127. clear();
  128. }
  129. TCharSet(char c0)
  130. {
  131. clear();
  132. insert(c0);
  133. }
  134. TCharSet(char c0, char c1)
  135. {
  136. clear();
  137. insert(c0); insert(c1);
  138. }
  139. TCharSet(char c0, char c1, char c2)
  140. {
  141. clear();
  142. insert(c0); insert(c1); insert(c2);
  143. }
  144. TCharSet(char c0, char c1, char c2, char c3)
  145. {
  146. clear();
  147. insert(c0); insert(c1); insert(c2); insert(c3);
  148. }
  149. TCharSet(char c0, char c1, char c2, char c3, char c4)
  150. {
  151. clear();
  152. insert(c0); insert(c1); insert(c2); insert(c3); insert(c4);
  153. }
  154. };
  155. enum TMode
  156. {
  157. _input, _output, _answer
  158. };
  159. enum TResult
  160. {
  161. _ok, _wa, _pe, _fail, _dirt
  162. };
  163. const std::string outcomes[] =
  164. {"accepted", "wrong-answer", "presentation-error", "fail", "fail"};
  165. struct InStream
  166. {
  167. InStream();
  168. std::FILE * file;
  169. std::string name;
  170. TMode mode;
  171. bool opened;
  172. void init(std::string fileName, TMode mode);
  173. char curChar();
  174. void skipChar();
  175. char nextChar();
  176. void reset();
  177. bool eof();
  178. bool seekEof();
  179. bool eoln();
  180. bool seekEoln();
  181. void nextLine();
  182. void skip(TCharSet setof);
  183. std::string readWord(TCharSet before, TCharSet after);
  184. std::string readWord();
  185. long long readLong();
  186. int readInteger();
  187. int readInt();
  188. double readReal();
  189. double readDouble();
  190. std::string readString();
  191. void quit(TResult result, const char * msg);
  192. void quits(TResult result, std::string msg);
  193. void close();
  194. const static WORD LightGray = 0x07;
  195. const static WORD LightRed = 0x0c;
  196. const static WORD LightCyan = 0x0b;
  197. const static WORD LightGreen = 0x0a;
  198. static void textColor(WORD color);
  199. static void quitscr(WORD color, const char * msg);
  200. static void quitscrS(WORD color, std::string msg);
  201. void xmlSafeWrite(std::FILE * file, const char * msg);
  202. };
  203. InStream inf;
  204. InStream ouf;
  205. InStream ans;
  206. bool appesMode;
  207. std::string resultName;
  208. std::string checkerName = "untitled checker";
  209. /* implementation
  210. */
  211. InStream::InStream()
  212. {
  213. file = NULL;
  214. name = "";
  215. mode = _input;
  216. }
  217. int resultExitCode(TResult r)
  218. {
  219. if (r == _ok)
  220. return OK_EXIT_CODE;
  221. if (r == _wa)
  222. return WA_EXIT_CODE;
  223. if (r == _pe)
  224. return PE_EXIT_CODE;
  225. if (r == _fail)
  226. return FAIL_EXIT_CODE;
  227. if (r == _dirt)
  228. return DIRT_EXIT_CODE;
  229. return FAIL_EXIT_CODE;
  230. }
  231. void InStream::textColor(WORD color)
  232. {
  233. #if ( _WIN32 || __WIN32__ )
  234. HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
  235. SetConsoleTextAttribute(handle, color);
  236. #endif
  237. }
  238. void halt(int exitCode)
  239. {
  240. #ifdef FOOTER
  241. InStream::textColor(InStream::LightGray);
  242. std::printf("Checker: \"%s\"\n", checkerName.c_str());
  243. std::printf("Exit code: %d\n", exitCode);
  244. InStream::textColor(InStream::LightGray);
  245. #endif
  246. std::exit(exitCode);
  247. }
  248. void InStream::quit(TResult result, const char * msg)
  249. {
  250. if (mode != _output && result != _fail)
  251. quits(_fail, std::string(msg) + " (" + name + ")");
  252. std::FILE * resultFile;
  253. std::string errorName;
  254. if (result == _ok)
  255. {
  256. if (!ouf.seekEof())
  257. quit(_dirt, "Extra information in the output file");
  258. }
  259. switch (result)
  260. {
  261. case _fail:
  262. errorName = "FAIL ";
  263. quitscrS(LightRed, errorName);
  264. break;
  265. case _dirt:
  266. errorName = "wrong output format ";
  267. quitscrS(LightCyan, errorName);
  268. result = _pe;
  269. break;
  270. case _pe:
  271. errorName = "wrong output format ";
  272. quitscrS(LightRed, errorName);
  273. break;
  274. case _ok:
  275. errorName = "ok ";
  276. quitscrS(LightGreen, errorName);
  277. break;
  278. case _wa:
  279. errorName = "wrong answer ";
  280. quitscrS(LightRed, errorName);
  281. break;
  282. default:
  283. quit(_fail, "What is the code ??? ");
  284. }
  285. if (resultName != "")
  286. {
  287. resultFile = std::fopen(resultName.c_str(), "w");
  288. if (resultFile == NULL)
  289. quit(_fail, "Can not write to Result file");
  290. if (appesMode)
  291. {
  292. fprintf(resultFile, "<?xml version=\"1.0\" encoding=\"windows-1251\"?>");
  293. fprintf(resultFile, "<result outcome = \"%s\">", outcomes[(int)result].c_str());
  294. xmlSafeWrite(resultFile, msg);
  295. fprintf(resultFile, "</result>\n");
  296. }
  297. else
  298. {
  299. /** old-style format
  300. * fprintf(resultFile, ".Testlib Result Number = %d\n", (int)result);
  301. * fprintf(resultFile, ".Result name (optional) = %s\n", errorName.c_str());
  302. * fprintf(resultFile, ".Check Comments = %s\n", msg);
  303. */
  304. fprintf(resultFile, "%s", msg);
  305. }
  306. if (NULL == resultFile || fclose(resultFile) != 0)
  307. quit(_fail, "Can not write to Result file");
  308. }
  309. quitscr(LightGray, msg);
  310. std::printf("\n");
  311. if (inf.file)
  312. fclose(inf.file);
  313. if (ouf.file)
  314. fclose(ouf.file);
  315. if (ans.file)
  316. fclose(ans.file);
  317. textColor(LightGray);
  318. if (resultName != "")
  319. std::printf("See file to check exit message\n");
  320. halt(resultExitCode(result));
  321. }
  322. void InStream::quits(TResult result, std::string msg)
  323. {
  324. InStream::quit(result, msg.c_str());
  325. }
  326. void InStream::xmlSafeWrite(std::FILE * file, const char * msg)
  327. {
  328. size_t lmsg = strlen(msg);
  329. for (size_t i = 0; i < lmsg; i++)
  330. {
  331. if (msg[i] == '&')
  332. {
  333. fprintf(file, "%s", "&amp;");
  334. continue;
  335. }
  336. if (msg[i] == '<')
  337. {
  338. fprintf(file, "%s", "&lt;");
  339. continue;
  340. }
  341. if (msg[i] == '>')
  342. {
  343. fprintf(file, "%s", "&gt;");
  344. continue;
  345. }
  346. if (msg[i] == '"')
  347. {
  348. fprintf(file, "%s", "&quot;");
  349. continue;
  350. }
  351. if (0 <= msg[i] && msg[i] <= 31)
  352. {
  353. fprintf(file, "%c", '.');
  354. continue;
  355. }
  356. fprintf(file, "%c", msg[i]);
  357. }
  358. }
  359. void InStream::quitscrS(WORD color, std::string msg)
  360. {
  361. quitscr(color, msg.c_str());
  362. }
  363. void InStream::quitscr(WORD color, const char * msg)
  364. {
  365. if (resultName == "")
  366. {
  367. textColor(color);
  368. std::printf("%s", msg);
  369. textColor(LightGray);
  370. }
  371. }
  372. void InStream::reset()
  373. {
  374. if (opened)
  375. close();
  376. if (NULL == (file = std::fopen(name.c_str(), "r")))
  377. {
  378. if (mode == _output)
  379. quits(_pe, std::string("File not found: \"") + name + "\"");
  380. }
  381. opened = true;
  382. }
  383. void InStream::init(std::string fileName, TMode mode)
  384. {
  385. opened = false;
  386. name = fileName;
  387. this->mode = mode;
  388. reset();
  389. }
  390. char InStream::curChar()
  391. {
  392. char c = (char)getc(file);
  393. ungetc(c, file);
  394. return c;
  395. }
  396. char InStream::nextChar()
  397. {
  398. return (char)getc(file);
  399. }
  400. void InStream::skipChar()
  401. {
  402. getc(file);
  403. }
  404. std::string InStream::readWord(TCharSet before, TCharSet after)
  405. {
  406. char cur;
  407. while (before.count(cur = (char)getc(file)) == 1);
  408. if (cur == EOFCHAR && !after.count(cur))
  409. {
  410. quit(_pe, "Unexpected end of file");
  411. }
  412. std::string result = "";
  413. while (!(after.count(cur) || cur == EOFCHAR))
  414. {
  415. result += cur;
  416. cur = (char)getc(file);
  417. }
  418. ungetc(cur, file);
  419. return result;
  420. }
  421. std::string InStream::readWord()
  422. {
  423. return readWord(TCharSet(BLANKS), TCharSet(BLANKS));
  424. }
  425. int InStream::readInteger()
  426. {
  427. char cur;
  428. while (isNumberBefore(cur = (char)getc(file)));
  429. if (cur == EOFCHAR)
  430. quit(_pe, "Unexpected end of file - integer expected");
  431. ungetc(cur, file);
  432. int retval;
  433. if (fscanf(file, "%d", &retval) != 1)
  434. // todo: show insted-of
  435. quit(_pe, "Expected integer");
  436. return retval;
  437. }
  438. static bool equals(long long integer, const char* s)
  439. {
  440. if (integer == -9223372036854775808LL)
  441. return strcmp(s, "-9223372036854775808") == 0;
  442. if (integer == 0LL)
  443. return strcmp(s, "0") == 0;
  444. size_t length = strlen(s);
  445. if (length == 0)
  446. return false;
  447. if (integer < 0 && s[0] != '-')
  448. return false;
  449. if (integer < 0)
  450. s++, length--, integer = -integer;
  451. if (length == 0)
  452. return false;
  453. while (integer > 0)
  454. {
  455. int digit = integer % 10;
  456. if (s[length - 1] != '0' + digit)
  457. return false;
  458. length--;
  459. integer /= 10;
  460. }
  461. return length == 0;
  462. }
  463. long long InStream::readLong()
  464. {
  465. char cur;
  466. while (isNumberBefore(cur = (char)getc(file)));
  467. if (cur == EOFCHAR)
  468. quit(_pe, "Unexpected end of file - long expected");
  469. ungetc(cur, file);
  470. long long retval = 0;
  471. char buffer[32] = {0};
  472. if (fscanf(file, "%s", buffer) != 1)
  473. quit(_pe, "Expected int64");
  474. else
  475. {
  476. if (strcmp(buffer, "-9223372036854775808") == 0)
  477. return -9223372036854775808LL;
  478. bool minus = false;
  479. size_t length = strlen(buffer);
  480. if (length > 1 && buffer[0] == '-')
  481. minus = true;
  482. if (length > 20)
  483. quit(_pe, ("Expected int64, but \"" + (std::string)buffer + "\" found").c_str());
  484. for (size_t i = (minus ? 1 : 0); i < length; i++)
  485. {
  486. if (buffer[i] < '0' || buffer[i] > '9')
  487. quit(_pe, ("Expected int64, but \"" + (std::string)buffer + "\" found").c_str());
  488. retval = retval * 10 + (buffer[i] - '0');
  489. }
  490. if (retval < 0)
  491. quit(_pe, ("Expected int64, but \"" + (std::string)buffer + "\" found").c_str());
  492. retval = (minus ? -retval : +retval);
  493. if (length < 19)
  494. return retval;
  495. if (equals(retval, buffer))
  496. return retval;
  497. else
  498. quit(_pe, ("Expected int64, but \"" + (std::string)buffer + "\" found").c_str());
  499. }
  500. throw "it should not be executed";
  501. }
  502. int InStream::readInt()
  503. {
  504. return readInteger();
  505. }
  506. double InStream::readReal()
  507. {
  508. if (seekEof())
  509. quit(_pe, "Unexpected end of file - double expected");
  510. double retval;
  511. if (fscanf(file, "%lf", &retval) != 1)
  512. // todo: show insted-of
  513. quit(_pe, "Expected double");
  514. return retval;
  515. }
  516. double InStream::readDouble()
  517. {
  518. return readReal();
  519. }
  520. void InStream::skip(TCharSet setof)
  521. {
  522. char cur;
  523. while (setof.count(cur = (char)getc(file)) == 1);
  524. ungetc(cur, file);
  525. }
  526. bool InStream::eof()
  527. {
  528. return (NULL == file || feof(file) != 0);
  529. }
  530. bool InStream::seekEof()
  531. {
  532. if (NULL == file)
  533. return true;
  534. char cur;
  535. while (isBlanks(cur = (char)getc(file)));
  536. ungetc(cur, file);
  537. return (NULL == file || feof(file) != 0 || cur == EOF);
  538. }
  539. bool InStream::eoln()
  540. {
  541. if (NULL == file)
  542. return true;
  543. char c = curChar();
  544. return isEolnChar(c);
  545. }
  546. bool InStream::seekEoln()
  547. {
  548. if (NULL == file)
  549. return true;
  550. char cur;
  551. do
  552. {
  553. cur = (char)getc(file);
  554. }
  555. while (cur == SPACE || cur == TAB);
  556. ungetc(cur, file);
  557. return isEolnChar(cur);
  558. }
  559. void InStream::nextLine()
  560. {
  561. if (NULL == file)
  562. return;
  563. char cur;
  564. while (!isEolnChar(cur = (char)getc(file)));
  565. if (cur == CR)
  566. {
  567. cur = (char)getc(file);
  568. if (cur != LF)
  569. ungetc(cur, file);
  570. }
  571. else
  572. {
  573. if (cur != LF)
  574. ungetc(cur, file);
  575. }
  576. }
  577. std::string InStream::readString()
  578. {
  579. if (NULL == file)
  580. quit(_pe, "Expected line");
  581. std::string retval = "";
  582. char cur;
  583. while (!isEolnChar(cur = (char)getc(file)))
  584. retval += cur;
  585. if (cur == CR)
  586. {
  587. cur = (char)getc(file);
  588. if (cur != LF)
  589. ungetc(cur, file);
  590. }
  591. else
  592. {
  593. if (cur != LF)
  594. ungetc(cur, file);
  595. }
  596. return retval;
  597. }
  598. void InStream::close()
  599. {
  600. if (opened)
  601. fclose(file);
  602. opened = false;
  603. }
  604. void quit(TResult result, const std::string& msg)
  605. {
  606. ouf.quit(result, msg.c_str());
  607. }
  608. void quit(TResult result, const char * msg)
  609. {
  610. ouf.quit(result, msg);
  611. }
  612. void quitf(TResult result, const char * format, ...)
  613. {
  614. char * buffer = new char [OUTPUT_BUFFER_SIZE];
  615. va_list ap;
  616. va_start(ap, format);
  617. std::vsprintf(buffer, format, ap);
  618. va_end(ap);
  619. std::string output(buffer);
  620. delete[] buffer;
  621. quit(result, output);
  622. }
  623. void registerTestlibCmd(int argc, char * argv[])
  624. {
  625. if (argc > 1 && !strcmp("--help", argv[1]))
  626. {
  627. InStream::textColor(InStream::LightCyan);
  628. std::printf("TESTLIB %s ", VERSION);
  629. std::printf("by Mike Mirzayanov, copyright(c) 2005-2009\n");
  630. std::printf("Checker name: \"%s\"\n", checkerName.c_str());
  631. InStream::textColor(InStream::LightGray);
  632. std::printf("\n");
  633. std::printf("Latest features: \n");
  634. for (size_t i = 0; i < sizeof(latestFeatures) / sizeof(char*); i++)
  635. {
  636. std::printf("*) %s\n", latestFeatures[i]);
  637. }
  638. std::printf("\n");
  639. std::printf("Program must be run with the following arguments: \n");
  640. std::printf(" <input-file> <output-file> <answer-file> [<report-file> [<-appes>]]\n\n");
  641. std::exit(0);
  642. }
  643. if (sizeof(int) != 4)
  644. quit(_fail, "'testlib' unit assumes 'sizeof(int) = 4'");
  645. if (sizeof(long long) != 8)
  646. quit(_fail, "'testlib' unit assumes 'sizeof(long long) = 8'");
  647. if (argc < 4 || argc > 6)
  648. {
  649. quit(_fail, std::string("Program must be run with the following arguments: ") +
  650. std::string("<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]") +
  651. "\nUse \"--help\" to get help information");
  652. }
  653. if (argc == 4)
  654. {
  655. resultName = "";
  656. appesMode = false;
  657. }
  658. if (argc == 5)
  659. {
  660. resultName = argv[4];
  661. appesMode = false;
  662. }
  663. if (argc == 6)
  664. {
  665. if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5]))
  666. {
  667. quit(_fail, std::string("Program must be run with the following arguments: ") +
  668. "<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");
  669. }
  670. else
  671. {
  672. resultName = argv[4];
  673. appesMode = true;
  674. }
  675. }
  676. inf.init(argv[1], _input);
  677. ouf.init(argv[2], _output);
  678. ans.init(argv[3], _answer);
  679. }
  680. void registerTestlib(int argc, ...)
  681. {
  682. if (argc < 3 || argc > 5)
  683. quit(_fail, std::string("Program must be run with the following arguments: ") +
  684. "<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");
  685. char ** argv = new char*[argc + 1];
  686. va_list ap;
  687. va_start(ap, argc);
  688. argv[0] = NULL;
  689. for (int i = 0; i < argc; i++)
  690. {
  691. argv[i + 1] = va_arg(ap, char *);
  692. }
  693. va_end(ap);
  694. registerTestlibCmd(argc + 1, argv);
  695. delete[] argv;
  696. }
  697. inline bool isNaN(double r)
  698. {
  699. return ((r != r) == true) && ((r == r) == false) && ((1.0 > r) == false) && ((1.0 < r) == false);
  700. }
  701. inline bool isInfinite(double r)
  702. {
  703. return (r > 1E100 || r < -1E100);
  704. }
  705. bool doubleCompare(double expected, double result, double MAX_DOUBLE_ERROR)
  706. {
  707. if(isNaN(expected))
  708. {
  709. return isNaN(result);
  710. }
  711. else
  712. if(isInfinite(expected))
  713. {
  714. if(expected > 0)
  715. {
  716. return result > 0 && isInfinite(result);
  717. }
  718. else
  719. {
  720. return result < 0 && isInfinite(result);
  721. }
  722. }
  723. else
  724. if(isNaN(result) || isInfinite(result))
  725. {
  726. return false;
  727. }
  728. else
  729. if(ABS(result - expected) < MAX_DOUBLE_ERROR)
  730. {
  731. return true;
  732. }
  733. else
  734. {
  735. double minv = MIN(expected * (1.0 - MAX_DOUBLE_ERROR),
  736. expected * (1.0 + MAX_DOUBLE_ERROR));
  737. double maxv = MAX(expected * (1.0 - MAX_DOUBLE_ERROR),
  738. expected * (1.0 + MAX_DOUBLE_ERROR));
  739. return result > minv && result < maxv;
  740. }
  741. }
  742. double doubleDelta(double expected, double result)
  743. {
  744. double absolute = ABS(result - expected);
  745. if (ABS(expected) > 1E-9)
  746. {
  747. double relative = ABS(absolute / expected);
  748. return MIN(absolute, relative);
  749. }
  750. else
  751. return absolute;
  752. }
  753. void ensure(bool cond, const std::string msg = "")
  754. {
  755. if (!cond)
  756. {
  757. quitf(_fail, msg.c_str());
  758. }
  759. }
  760. void setName(const char* format, ...)
  761. {
  762. char * buffer = new char [OUTPUT_BUFFER_SIZE];
  763. va_list ap;
  764. va_start(ap, format);
  765. std::vsprintf(buffer, format, ap);
  766. va_end(ap);
  767. std::string name(buffer);
  768. delete[] buffer;
  769. checkerName = name;
  770. }
  771. #endif