33. Testovací script (JS) a křížová kontrola

Ilustrační obrázek k článku: Testovací script (JS) a křížová kontrola
V minulém díle jsme postavili PHP část testovacího scriptu. Dnes doplníme JavaScriptovou část a dokončíme mechanismus pro křížové porovnávání výsledků – tedy páteř spolehlivosti CombiScriptu.

V minulém díle jsme vytvořili PHP část testovacího scriptu, která vygenerovala tabulku s výsledky testů na serveru. Dnes napíšeme JavaScriptovou část, která tytéž testy spustí v prohlížeči a porovná výsledky. To je klíčové pro ověření, že náš CombiScript opravdu vrací stejné hodnoty v obou jazycích.

Funkce tst_ToHTML v JavaScriptu

Začneme funkcí tst_ToHTML. Musíme ji napsat stejně jako v PHP, kde vypadala takto:

  1. function tst_ToHtml($x)
  2. {
  3. return nl2br(htmlspecialchars($x));
  4. }

JavaScript nemá vestavěnou funkci htmlspecialchars, takže si ji musíme naprogramovat sami. Když se podíváme do PHP manuálu, vidíme přesně, jaké znaky se konvertují. V JS použijeme několikanásobné nahrazení. Pořadí je důležité - ampersand musí být první, jinak bychom převáděli i ampersandy z již převedených entit.

Stejným způsobem nahradíme konce řádků za <br />. Carriage return považujeme za volitelný (proto regex \n\r?).

  1. function tst_ToHtml(x)
  2. {
  3. x = x.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
  4. x = x.replace(/\r?\n/g, '<br />\n');
  5. return x;
  6. }

Funkce Out bez statických proměnných

Dále vytvoříme JS variantu funkce Out. V PHP jsme využívali statickou proměnnou, ale JavaScript statické proměnné nemá. Musíme se tedy poradit jinak.

Řešení je překvapivě elegantní: každá JS funkce je objekt a může mít vlastnosti. Text si tedy schováme přímo do vlastnosti Out._buffer. To je užitečný trik, který se hodí i mimo CombiScript - zapamatujte si ho.

PHP verze pro srovnání:

  1. // Definice jednoznačných instancí
  2. define('TST_OUT_RESET', new stdClass());
  3. define('TST_OUT_GET', new stdClass());
  4. function Out($x)
  5. {
  6. static $buffer = '';
  7. if ($x === TST_OUT_RESET) return $buffer = '';
  8. if ($x === TST_OUT_GET) return $buffer;
  9. if (is_string($x) || is_int($x) || is_float($x) || is_bool($x) || is_null($x))
  10. {
  11. $buffer .= tst_ToHtml(json_encode($x, JSON_UNESCAPED_UNICODE));
  12. return;
  13. }
  14. if ($x instanceof Exception)
  15. {
  16. $s = ($x instanceof cs_Error) ? '#Err:' : '?Err:';
  17. $s .= $x->getMessage();
  18. if ($x instanceof cs_Error)
  19. {
  20. $data = $x->getData();
  21. if ($data && is_array($data) && count($data))
  22. {
  23. $s .= ' ' . json_encode($data, JSON_UNESCAPED_UNICODE);
  24. }
  25. }
  26. $buffer .= $s;
  27. return;
  28. }
  29. $buffer .= 'Out-UnknownType';
  30. }

A nyní JS implementace využívající vlastnosti funkce:

  1. const TST_OUT_RESET = {};
  2. const TST_OUT_GET = {};
  3. function Out(x)
  4. {
  5. if (Out._buffer === undefined) Out._buffer = '';
  6. if (x === TST_OUT_RESET) return Out._buffer = '';
  7. if (x === TST_OUT_GET) return Out._buffer;
  8. if (typeof x === "string" || typeof x === "number" || typeof x === "boolean" || x === null)
  9. {
  10. Out._buffer += JSON.stringify(x);
  11. return;
  12. }
  13. if (x instanceof Error)
  14. {
  15. let s = (x instanceof cs_Error) ? '#Err:' : '?Err:';
  16. s += x.message;
  17. const data = x.getData();
  18. if (Array.isArray(data) && data.length > 0)
  19. {
  20. s += ' ' + JSON.stringify(data);
  21. }
  22. Out._buffer += s
  23. return;
  24. }
  25. Out._buffer += 'Out-UnknownType';
  26. }

Spuštění jednotlivých testů

Nakonec vytvoříme funkci tst_RunTest, která spustí jednu anonymní testovací funkci. V PHP vypadá takto:

  1. function tst_RunTest($test)
  2. {
  3. Out(TST_OUT_RESET);
  4. try
  5. {
  6. $test();
  7. }
  8. catch (Exception $e)
  9. {
  10. Out($e);
  11. }
  12. return Out(TST_OUT_GET);
  13. }

Přepis do JavaScriptu je přímočarý - jen změníme způsob zachytávání výjimek:

  1. function tst_RunTest($test)
  2. {
  3. Out(TST_OUT_RESET);
  4. try
  5. {
  6. $test();
  7. }
  8. catch (error)
  9. {
  10. Out(error)
  11. }
  12. return Out(TST_OUT_GET);
  13. }

Automatické spuštění všech testů

A zcela na závěr vytvoříme kód, který po načtení stránky automaticky spustí všechny testy v JavaScriptu. Logika je následující:

  1. Projdeme všechny testovací soubory, funkce a jednotlivé testy
  2. Pro každý test najdeme odpovídající řádek tabulky (vygenerovaný v PHP)
  3. Spustíme test a výsledek zapíšeme do buňky s indexem 3
  4. Porovnáme výsledek PHP (buňka 2) s výsledkem JS (buňka 3)
  5. Do buňky 4 zapíšeme "OK" nebo "Err" a obarvíme podle očekávání
  1. window.onload = function()
  2. {
  3. for (var $File in $Tests)
  4. for (var $Func in $Tests[$File])
  5. for (var $TestId=0; $TestId<$Tests[$File][$Func].length; $TestId++)
  6. {
  7. var $TestArr = $Tests[$File][$Func][$TestId];
  8. var trEl = document.getElementById($File+'-'+$Func+'-'+$TestId);
  9. if (!trEl) continue;
  10. trEl.cells[3].innerHTML = tst_ToHtml(tst_RunTest($TestArr[1]));
  11. trEl.cells[4].innerHTML = (trEl.cells[2].innerHTML===trEl.cells[3].innerHTML) ? 'OK' : 'Err';
  12. if ($TestArr[0]===1)
  13. {
  14. trEl.cells[4].style.color = (trEl.cells[4].innerText==='OK') ? 'green' : 'red';
  15. }
  16. }
  17. }

Kompletní testovací framework

Nyní máme hotovo. Celý testovací script včetně obou částí (PHP i JS) vypadá takto:

    
  1. <!DOCTYPE html>
  2. <HTML lang="cs">
  3. <HEAD>
  4. <META charset="UTF-8"/>
  5. <META name="viewport" content="width=device-width, initial-scale=1.0">
  6. <LINK rel="shortcut icon" href="./favicon.ico"/>
  7. <TITLE>CombiScript Tests</TITLE>
  8. <STYLE>
  9. BODY {
  10. background-color:#EEE;
  11. font-family:sans-serif;
  12. }
  13. .Tests {
  14. border-collapse: collapse;
  15. width:100%;
  16. }
  17. .Tests TD, .Tests TH {
  18. border:1px solid black;
  19. position:relative;
  20. }
  21. .tst_Source {
  22. white-space:pre;
  23. font-family:monospace;
  24. }
  25. </STYLE>
  26. </HEAD>
  27. <BODY>
  28. <?php
  29. $Libs = ['cs_Util', 'nm_Util'];
  30. $TestLibs = ['nm_Util_Test'];
  31. foreach ($Libs AS $Nr => $Lib)
  32. include('./cs_src/'.$Lib.'.php.js');
  33. foreach ($TestLibs AS $Nr => $Lib)
  34. include('./cs_tests/'.$Lib.'.php.js');
  35. ?>
  36. </BODY>
  37. <?php
  38. foreach ($Libs AS $Nr => $Lib)
  39. echo '<SCRIPT src="./cs_src/'.$Lib.'.php.js?'.date('YmdHis').'"></SCRIPT>';
  40. foreach ($TestLibs AS $Nr => $Lib)
  41. echo '<SCRIPT src="./cs_tests/'.$Lib.'.php.js?'.date('YmdHis').'"></SCRIPT>';
  42. function tst_ToHtml($x)
  43. {
  44. return nl2br(htmlspecialchars($x));
  45. }
  46. // Definice jednoznačných instancí
  47. define('TST_OUT_RESET', new stdClass());
  48. define('TST_OUT_GET', new stdClass());
  49. function Out($x)
  50. {
  51. static $buffer = '';
  52. if ($x === TST_OUT_RESET) return $buffer = '';
  53. if ($x === TST_OUT_GET) return $buffer;
  54. if (is_string($x) || is_int($x) || is_float($x) || is_bool($x) || is_null($x))
  55. {
  56. $buffer .= json_encode($x, JSON_UNESCAPED_UNICODE);
  57. return;
  58. }
  59. if ($x instanceof Exception)
  60. {
  61. $s = ($x instanceof cs_Error) ? '#Err:' : '?Err:';
  62. $s .= $x->getMessage();
  63. if ($x instanceof cs_Error)
  64. {
  65. $data = $x->getData();
  66. if ($data && is_array($data) && count($data))
  67. {
  68. $s .= ' ' . json_encode($data, JSON_UNESCAPED_UNICODE);
  69. }
  70. }
  71. $buffer .= $s;
  72. return;
  73. }
  74. $buffer .= 'Out-UnknownType';
  75. }
  76. function tst_RunTest($test)
  77. {
  78. Out(TST_OUT_RESET);
  79. try
  80. {
  81. $test();
  82. }
  83. catch (Exception $e)
  84. {
  85. Out($e);
  86. }
  87. return Out(TST_OUT_GET);
  88. }
  89. function tst_GetClosureCode($func)
  90. {
  91. static $cache = [];
  92. $ref = new ReflectionFunction($func);
  93. if (!$ref->isUserDefined()) return null;
  94. $file = $ref->getFileName();
  95. if (!isset($cache[$file]))
  96. $cache[$file] = file($file);
  97. $start = $ref->getStartLine() - 1;
  98. $end = $ref->getEndLine();
  99. $ret = implode('', array_slice($cache[$file], $start, $end - $start)); //\n uz je soucasti kazdy line ziskane pomoci funkce file()
  100. if (preg_match('/function\s*\(/i', $ret, $matches, PREG_OFFSET_CAPTURE)) $Begin = $matches[0][1]; //Pocitam s tim ze je to prvni "function (" na radku kde zacina deklarace funkce
  101. $End = strrpos($ret, '}'); //Pocitam s tim ze je to posledni "}" na radku kde konci deklarace funkce
  102. $ret = substr($ret, $Begin, $End-$Begin+1);
  103. return $ret;
  104. }
  105. foreach ($Tests AS $File=>$FileArr)
  106. {
  107. foreach ($FileArr AS $Func=>$FuncArr)
  108. {
  109. echo '<H3>'.$Func.'</H3>';
  110. echo '<TABLE class=Tests><TR><TH>Popis</TH><TH>Zdroj</TH><TH>PHP</TH><TH>JS</TH><TH>Vysledek</TH></TR>';
  111. foreach ($FuncArr AS $TestId=>$TestArr)
  112. {
  113. echo '<TR id="'.$File.'-'.$Func.'-'.$TestId.'">';
  114. echo '<TD>'.tst_ToHtml($TestArr[2]).'</TD>';
  115. echo '<TD style="white-space:pre; font-family:monospace">'.htmlspecialchars(tst_GetClosureCode($TestArr[1])).'</TD>';
  116. echo '<TD>'.tst_ToHtml(tst_RunTest($TestArr[1])).'</TD>';
  117. echo '<TD></TD>';
  118. echo '<TD></TD>';
  119. echo '</TR>';
  120. }
  121. echo '</TABLE>';
  122. }
  123. }
  124. ?>
  125. </BODY>
  126. <SCRIPT>
  127. "use strict";
  128. var $Tests = {};
  129. </SCRIPT>
  130. <?php
  131. foreach ($Libs AS $Nr => $Lib)
  132. echo '<SCRIPT src="./cs_src/'.$Lib.'.php.js?'.date('YmdHis').'"></SCRIPT>';
  133. foreach ($TestLibs AS $Nr => $Lib)
  134. echo '<SCRIPT src="./cs_tests/'.$Lib.'.php.js?'.date('YmdHis').'"></SCRIPT>';
  135. ?>
  136. <SCRIPT>
  137. "use strict";
  138. function tst_ToHtml(x)
  139. {
  140. x = x.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
  141. x = x.replace(/\r?\n/g, '<br />\n');
  142. return x;
  143. }
  144. const TST_OUT_RESET = {};
  145. const TST_OUT_GET = {};
  146. function Out(x)
  147. {
  148. if (Out._buffer === undefined) Out._buffer = '';
  149. if (x === TST_OUT_RESET) return Out._buffer = '';
  150. if (x === TST_OUT_GET) return Out._buffer;
  151. if (typeof x === "string" || typeof x === "number" || typeof x === "boolean" || x === null)
  152. {
  153. Out._buffer += JSON.stringify(x);
  154. return;
  155. }
  156. if (x instanceof Error)
  157. {
  158. let s = (x instanceof cs_Error) ? '#Err:' : '?Err:';
  159. s += x.message;
  160. const data = x.getData();
  161. if (Array.isArray(data) && data.length > 0)
  162. {
  163. s += ' ' + JSON.stringify(data);
  164. }
  165. Out._buffer += s
  166. return;
  167. }
  168. Out._buffer += 'Out-UnknownType';
  169. }
  170. function tst_RunTest($test)
  171. {
  172. Out(TST_OUT_RESET);
  173. try
  174. {
  175. $test();
  176. }
  177. catch (error)
  178. {
  179. Out(error)
  180. }
  181. return Out(TST_OUT_GET);
  182. }
  183. window.onload = function()
  184. {
  185. for (var $File in $Tests)
  186. for (var $Func in $Tests[$File])
  187. for (var $TestId=0; $TestId<$Tests[$File][$Func].length; $TestId++)
  188. {
  189. var $TestArr = $Tests[$File][$Func][$TestId];
  190. var trEl = document.getElementById($File+'-'+$Func+'-'+$TestId);
  191. if (!trEl) continue;
  192. trEl.cells[3].innerHTML = tst_ToHtml(tst_RunTest($TestArr[1]));
  193. trEl.cells[4].innerHTML = (trEl.cells[2].innerHTML===trEl.cells[3].innerHTML) ? 'OK' : 'Err';
  194. if ($TestArr[0]===1)
  195. {
  196. trEl.cells[4].style.color = (trEl.cells[4].innerText==='OK') ? 'green' : 'red';
  197. }
  198. }
  199. }
  200. </SCRIPT>
  201. </HTML>
  1. <!-- --><?php /*
  2. "use strict";
  3. //*/
  4. function nm_IsNumber($num)
  5. {
  6. 0&&0<!--$_;/*
  7. return typeof $num === 'number'
  8. /*/
  9. return is_int($num) OR is_float($num);
  10. //*/
  11. }
  12. function nm_Abs($num)
  13. {
  14. if (!nm_IsNumber($num)) throw new cs_Error('nm_Abs-$num-NotNumber', [cs_Type($num)]);
  15. 0&&0<!--$_;/*
  16. return Math.abs($num);
  17. /*/
  18. return abs($num);
  19. //*/
  20. }
  21. function nm_Sign($num)
  22. {
  23. if (!nm_IsNumber($num)) throw new cs_Error('nm_Sign-$num-NotNumber', [cs_Type($num)]);
  24. 0&&0<!--$_;/*
  25. return Math.sign($num);
  26. /*/
  27. return ($num > 0) - ($num < 0);
  28. //*/
  29. }
  30. function nm_IsAsInt($num)
  31. {
  32. 0&&0<!--$_;/*
  33. return Number.isInteger($num);
  34. /*/
  35. if (is_int($num)) return true;
  36. return (is_float($num) && floor($num) === $num);
  37. //*/
  38. }
  39. function nm_Pi()
  40. {
  41. 0&&0<!--$_;/*
  42. return Math.PI;
  43. /*/
  44. return Pi();
  45. //*/
  46. }
  47. function nm_Rad2Deg($rad)
  48. {
  49. if (!nm_IsNumber($rad)) throw new cs_Error('nm_Rad2Deg-$rad-NotNumber', [cs_Type($rad)]);
  50. 0&&0<!--$_;/*
  51. return $rad * (180/Math.PI);
  52. /*/
  53. return rad2deg($rad);
  54. //*/
  55. }
  56. function nm_Deg2Rad($deg)
  57. {
  58. if (!nm_IsNumber($deg)) throw new cs_Error('nm_Deg2Rad-$deg-NotNumber', [cs_Type($deg)]);
  59. 0&&0<!--$_;/*
  60. return $deg/180*Math.PI;
  61. /*/
  62. return deg2rad($deg);
  63. //*/
  64. }
  65. function nm_Sin($rad)
  66. {
  67. if (!nm_IsNumber($rad)) throw new cs_Error('nm_Sin-$rad-NotNumber', [cs_Type($rad)]);
  68. 0&&0<!--$_;/*
  69. return Math.sin($rad);
  70. /*/
  71. return sin($rad);
  72. //*/
  73. }
  74. function nm_Cos($rad)
  75. {
  76. if (!nm_IsNumber($rad)) throw new cs_Error('nm_Cos-$rad-NotNumber', [cs_Type($rad)]);
  77. 0&&0<!--$_;/*
  78. return Math.cos($rad);
  79. /*/
  80. return cos($rad);
  81. //*/
  82. }
  83. function nm_Tan($rad)
  84. {
  85. if (!nm_IsNumber($rad)) throw new cs_Error('nm_Tan-$rad-NotNumber', [cs_Type($rad)]);
  86. 0&&0<!--$_;/*
  87. return Math.tan($rad);
  88. /*/
  89. return tan($rad);
  90. //*/
  91. }
  92. function nm_ASin($num)
  93. {
  94. if (!nm_IsNumber($num)) throw new cs_Error('nm_ASin-$num-NotNumber', [cs_Type($num)]);
  95. if ($num>1 || $num<-1) throw new cs_Error('nm_ASin-$num-OutOfRange');
  96. 0&&0<!--$_;/*
  97. return Math.asin($num);
  98. /*/
  99. return asin($num);
  100. //*/
  101. }
  102. function nm_ACos($num)
  103. {
  104. if (!nm_IsNumber($num)) throw new cs_Error('nm_ACos-$num-NotNumber', [cs_Type($num)]);
  105. if ($num>1 || $num<-1) throw new cs_Error('nm_ACos-$num-OutOfRange');
  106. 0&&0<!--$_;/*
  107. return Math.acos($num);
  108. /*/
  109. return acos($num);
  110. //*/
  111. }
  112. function nm_ATan($num)
  113. {
  114. if (!nm_IsNumber($num)) throw new cs_Error('nm_ATan-$num-NotNumber', [cs_Type($num)]);
  115. 0&&0<!--$_;/*
  116. return Math.atan($num);
  117. /*/
  118. return atan($num);
  119. //*/
  120. }
  121. function nm_ATan2($y, $x)
  122. {
  123. if (!nm_IsNumber($y)) throw new cs_Error('nm_ATan2-$y-NotNumber', [cs_Type($y)]);
  124. if (!nm_IsNumber($x)) throw new cs_Error('nm_ATan2-$x-NotNumber', [cs_Type($x)]);
  125. 0&&0<!--$_;/*
  126. return Math.atan2($y, $x);
  127. /*/
  128. return atan2($y, $x);
  129. //*/
  130. }
  1. <!-- --><?php /*
  2. "use strict";
  3. class cs_Error extends Error
  4. {
  5. constructor($message, $data=[])
  6. {
  7. super($message);
  8. if (Error.captureStackTrace) Error.captureStackTrace(this, cs_Error);
  9. this.data = $data;
  10. }
  11. getData()
  12. {
  13. return this.data;
  14. }
  15. }
  16. /*/
  17. class cs_Error extends Exception
  18. {
  19. private $_data = '';
  20. public function __construct($message, $data=[])
  21. {
  22. $this->_data = $data;
  23. parent::__construct($message);
  24. }
  25. public function getData()
  26. {
  27. return $this->_data;
  28. }
  29. }
  30. //*/
  31. function cs_Type($var)
  32. {
  33. if ($var === null) return 'Null';
  34. if (nm_IsNumber($var)) return 'Number';
  35. //if (bl_IsBoolean($var)) return 'Boolean'; //TODO next
  36. //if (st_IsString($var)) return 'String';
  37. //if (ar_IsArray($var)) return 'Array';
  38. return 'Unknown';
  39. }
  1. <!-- --><?php
  2. "use strict";
  3. $Tests['nm_Util'] = [];
  4. $Tests['nm_Util']['nm_IsNumber'] = [
  5. [1, function()
  6. {
  7. Out(nm_IsNumber(5));
  8. },
  9. 'Ověřuje, že kladné celé číslo je číslo'],
  10. [1, function()
  11. {
  12. Out(nm_IsNumber(-5));
  13. },
  14. 'Ověřuje, že záporné celé číslo je číslo'],
  15. [1, function()
  16. {
  17. Out(nm_IsNumber(0));
  18. },
  19. 'Ověřuje, že nula je číslo'],
  20. [1, function()
  21. {
  22. Out(nm_IsNumber(2.5));
  23. },
  24. 'Ověřuje, že kladné desetinné číslo je číslo'],
  25. [1, function()
  26. {
  27. Out(nm_IsNumber(-2.5));
  28. },
  29. 'Ověřuje, že záporné desetinné číslo je číslo'],
  30. [1, function()
  31. {
  32. Out(nm_IsNumber(.5));
  33. },
  34. 'Ověřuje, že desetinné číslo s vynechanou úvodní nulou je číslo'],
  35. [1, function()
  36. {
  37. Out(nm_IsNumber(-.5));
  38. },
  39. 'Ověřuje, že záporné desetinné číslo s vynechanou úvodní nulou je číslo'],
  40. [1, function()
  41. {
  42. Out(nm_IsNumber(3.21E4));
  43. },
  44. 'Ověřuje, že číslo v exponenciálním tvaru je číslo'],
  45. [1, function()
  46. {
  47. Out(nm_IsNumber(-3.21E4));
  48. },
  49. 'Ověřuje, že záporné číslo v exponenciálním tvaru je číslo'],
  50. [1, function()
  51. {
  52. Out(nm_IsNumber(3.21E-4));
  53. },
  54. 'Ověřuje, že číslo s negativním exponentem je číslo'],
  55. [1, function()
  56. {
  57. Out(nm_IsNumber(-3.21E-4));
  58. },
  59. 'Ověřuje, že záporné číslo s negativním exponentem je číslo'],
  60. [1, function()
  61. {
  62. Out(nm_IsNumber(-3.21e-4));
  63. },
  64. 'Ověřuje, že se akceptuje malé "e" v exponenciálním tvaru'],
  65. [1, function()
  66. {
  67. Out(nm_IsNumber("123"));
  68. },
  69. 'Ověřuje, že string obsahující číslo není číslo'],
  70. [1, function()
  71. {
  72. Out(nm_IsNumber([1]));
  73. },
  74. 'Ověřuje, že pole není číslo']
  75. ];
  76. $Tests['nm_Util']['nm_IsAsInt'] = [
  77. [1, function()
  78. {
  79. Out(nm_IsAsInt(5));
  80. },
  81. 'Ověřuje, že kladné celé číslo je celé číslo'],
  82. [1, function()
  83. {
  84. Out(nm_IsAsInt(-5));
  85. },
  86. 'Ověřuje, že záporné celé číslo je celé číslo'],
  87. [1, function()
  88. {
  89. Out(nm_IsAsInt(5.0));
  90. },
  91. 'Ověřuje, že celočíselný float je celé číslo'],
  92. [1, function()
  93. {
  94. Out(nm_IsAsInt(-5.0));
  95. },
  96. 'Ověřuje, že záporný celočíselný float je celé číslo'],
  97. [1, function()
  98. {
  99. Out(nm_IsAsInt(0));
  100. },
  101. 'Ověřuje, že nula je celé číslo'],
  102. [1, function()
  103. {
  104. Out(nm_IsAsInt(-0));
  105. },
  106. 'Ověřuje, že minus nula je celé číslo'],
  107. [1, function()
  108. {
  109. Out(nm_IsAsInt(2.5));
  110. },
  111. 'Ověřuje, že kladné desetinné číslo není celé číslo'],
  112. [1, function()
  113. {
  114. Out(nm_IsAsInt(-2.5));
  115. },
  116. 'Ověřuje, že záporné desetinné číslo není celé číslo'],
  117. [1, function()
  118. {
  119. Out(nm_IsAsInt("123"));
  120. },
  121. 'Ověřuje, že string obsahující číslo není celé číslo'],
  122. [1, function()
  123. {
  124. Out(nm_IsAsInt(9007199254740991.5));
  125. },
  126. 'Ověřuje, že velké číslo s desetinnou částí se stále jeví jako integer (rozložení na číselné ose je už tak hrubé)'],
  127. [1, function()
  128. {
  129. Out(nm_IsAsInt(4.9999999999999995));
  130. },
  131. 'Toto ještě není 5'],
  132. [1, function()
  133. {
  134. Out(nm_IsAsInt(4.9999999999999996));
  135. },
  136. 'Toto už je 5']
  137. ];
  138. $Tests['nm_Util']['nm_Abs'] = [
  139. [1, function()
  140. {
  141. Out(nm_Abs(2.5));
  142. },
  143. 'Ověřuje, že absolutní hodnota kladného čísla je to samé číslo'],
  144. [1, function()
  145. {
  146. Out(nm_Abs(-2.5));
  147. },
  148. 'Ověřuje, že absolutní hodnota záporného čísla změní znaménko na kladné'],
  149. [1, function()
  150. {
  151. Out(nm_Abs(0));
  152. },
  153. 'Ověřuje, že absolutní hodnota nuly je nula'],
  154. [1, function()
  155. {
  156. Out(nm_Abs("123"));
  157. },
  158. 'Ověřuje, že pro nečíselný parametr se vyhodí chyba'],
  159. ];
  160. $Tests['nm_Util']['nm_Sign'] = [
  161. [1, function()
  162. {
  163. Out(nm_Sign(2.5));
  164. },
  165. 'Ověřuje, že signum kladného čísla je +1'],
  166. [1, function()
  167. {
  168. Out(nm_Sign(-2.5));
  169. },
  170. 'Ověřuje, že signum záporného čísla je -1'],
  171. [1, function()
  172. {
  173. Out(nm_Sign(0));
  174. },
  175. 'Ověřuje, že signum nuly je 0'],
  176. [1, function()
  177. {
  178. Out(nm_Sign(-0));
  179. },
  180. 'Ověřuje, že signum záporné nuly je také 0'],
  181. [1, function()
  182. {
  183. Out(nm_Sign("0"));
  184. },
  185. 'Ověřuje, že pro nečíselný parametr se vyhodí chyba'],
  186. ];

V živé ukázce výše vidíte tabulku se "zelenými" výsledky - podle toho se PHP a JS v námi definovaných a otestovaných funkcích zatím chovají stejně. To je páteř naší důvěry v CombiScript: pokud testy procházejí zeleně, můžeme nanich klidně stavět složitější funkce - až po návrh celého CADu.

V příštím díle se vrátíme k rozšiřování knihovny nm_Util a podíváme se na další matematické funkce, které budeme potřebovat pro geometrické výpočty v našem CADu.

Předchozí