From 44f10b71d21de7db1811ec73e95731a171e92ef1 Mon Sep 17 00:00:00 2001 From: tbali0524 Date: Sat, 24 Feb 2024 11:47:54 +0100 Subject: [PATCH] v1.12.0 --- .cgtest.full.php | 2 +- .cgtest.php | 2 +- CHANGELOG.md | 18 +++++- cgtest.php | 126 +++++++++++++++++++++++-------------- cgtest_screenshot_base.png | Bin 10926 -> 13071 bytes test.sh | 2 +- 6 files changed, 99 insertions(+), 51 deletions(-) diff --git a/.cgtest.full.php b/.cgtest.full.php index 5fe2e3a4..7be5903a 100644 --- a/.cgtest.full.php +++ b/.cgtest.full.php @@ -1,7 +1,7 @@ 0, 'countSkippedLanguages' => 0, @@ -30,6 +30,7 @@ 'countRunOnlyFiles' => 0, 'countFailedFiles' => 0, 'countSkippedFiles' => 0, + 'countLines' => 0, 'countTests' => 0, 'countRunOnlyTests' => 0, 'countPassedTests' => 0, @@ -62,10 +63,12 @@ $ansiGreenInv = $useAnsi ? "\e[1;37;42m" : ''; $ansiYellowInv = $useAnsi ? "\e[1;37;43m" : ''; $ansiGreen = $useAnsi ? "\e[32m" : ''; -$ansiBlue = $useAnsi ? "\e[34m" : ''; -$ansiVersion = $ansiGreen; -$ansiInfo = $ansiBlue; +$ansiYellow = $useAnsi ? "\e[33m" : ''; +$ansiLightCyan = $useAnsi ? "\e[96m" : ''; $ansiReset = $useAnsi ? "\e[0m" : ''; +$ansiVersion = $ansiGreen; +$ansiInfo = $ansiLightCyan; +$ansiWarn = $ansiYellow; $errorTag = $ansiRedInv . '[ERROR]' . $ansiReset . ' '; $warnTag = $ansiYellowInv . '[WARN]' . $ansiReset . ' '; $passTag = $ansiGreenInv . '[PASS]' . $ansiReset . ' '; @@ -82,7 +85,7 @@ const MIN_PHP_VERSION = '7.3.0'; if (version_compare(phpversion(), MIN_PHP_VERSION, '<')) { echo $errorTag . 'Minimum required PHP version is ' . $ansiVersion . MIN_PHP_VERSION . $ansiReset - . '; you are on ' . $ansiInfo . phpversion() . $ansiReset . PHP_EOL . PHP_EOL; + . '; you are on ' . $ansiWarn . phpversion() . $ansiReset . PHP_EOL . PHP_EOL; // OS exit codes: 0 = OK, 1 = some tests failed, 2 = error (wrong CLI arguments, etc) exit(2); } @@ -533,7 +536,7 @@ } foreach ($langs as $lang) { if (array_search($lang, $reservedConfigKeys, true) !== false) { - echo $errorTag . 'Invalid language name: ' . $ansiInfo . $lang . $ansiReset . PHP_EOL . PHP_EOL; + echo $errorTag . 'Invalid language name: ' . $ansiWarn . $lang . $ansiReset . PHP_EOL . PHP_EOL; exit(2); } if (array_search($lang, $argumentConfig['languages'], true) === false) { @@ -567,7 +570,7 @@ continue; } if ($arg[0] == '-') { - echo $errorTag . 'Invalid argument: ' . $ansiInfo . $arg . $ansiReset . PHP_EOL . PHP_EOL; + echo $errorTag . 'Invalid argument: ' . $ansiWarn . $arg . $ansiReset . PHP_EOL . PHP_EOL; exit(2); } if (!isset($argumentConfig['puzzles'])) { @@ -583,7 +586,7 @@ } $puzzle = substr($argv[$i], $j + 1); if ($puzzle == '') { - echo $errorTag . 'Invalid puzzle name: ' . $ansiInfo . $argv[$i] . $ansiReset . PHP_EOL . PHP_EOL; + echo $errorTag . 'Invalid puzzle name: ' . $ansiWarn . $argv[$i] . $ansiReset . PHP_EOL . PHP_EOL; exit(2); } if (!isset($argumentConfig['puzzles'][$path])) { @@ -596,7 +599,7 @@ $configFromFile = []; if ($argConfigFileName != '') { if (!file_exists($argConfigFileName)) { - echo $errorTag . 'Cannot open config file: ' . $ansiInfo . $argConfigFileName . $ansiReset . PHP_EOL . PHP_EOL; + echo $errorTag . 'Cannot open config file: ' . $ansiWarn . $argConfigFileName . $ansiReset . PHP_EOL . PHP_EOL; exit(2); } echo $infoTag . 'Using configuration file: ' . $ansiInfo . $argConfigFileName . $ansiReset . PHP_EOL; @@ -648,9 +651,11 @@ $ansiGreenInv = $useAnsi ? "\e[1;37;42m" : ''; $ansiYellowInv = $useAnsi ? "\e[1;37;43m" : ''; $ansiGreen = $useAnsi ? "\e[32m" : ''; -$ansiBlue = $useAnsi ? "\e[34m" : ''; +$ansiYellow = $useAnsi ? "\e[33m" : ''; +$ansiLightCyan = $useAnsi ? "\e[96m" : ''; $ansiVersion = $ansiGreen; -$ansiInfo = $ansiBlue; +$ansiInfo = $ansiLightCyan; +$ansiWarn = $ansiYellow; $ansiReset = $useAnsi ? "\e[0m" : ''; $errorTag = $ansiRedInv . '[ERROR]' . $ansiReset . ' '; $warnTag = $ansiYellowInv . '[WARN]' . $ansiReset . ' '; @@ -785,7 +790,7 @@ } $inputFile = fopen($inputFullFileName, 'w'); if ($inputFile === false) { - echo $errorTag . 'Cannot create file: ' . $ansiInfo . $inputFullFileName . $ansiReset + echo $errorTag . 'Cannot create file: ' . $ansiWarn . $inputFullFileName . $ansiReset . PHP_EOL . PHP_EOL; exit(2); } @@ -814,7 +819,7 @@ if ($config['clean']) { if (!$unlinkResult) { ++$totalUnsuccessfulDeleteFiles; - echo $warnTag . 'Could not delete file: ' . $ansiInfo . $config['debugLog'] . $ansiReset . PHP_EOL; + echo $warnTag . 'Could not delete file: ' . $ansiWarn . $config['debugLog'] . $ansiReset . PHP_EOL; } else { ++$languageStats['totals']['countDeletedFiles']; if ($config['verbose']) { @@ -828,7 +833,7 @@ if ($config['clean']) { if (!$unlinkResult) { ++$totalUnsuccessfulDeleteFiles; - echo $warnTag . 'Could not delete file: ' . $ansiInfo . $config['buildLog'] . $ansiReset . PHP_EOL; + echo $warnTag . 'Could not delete file: ' . $ansiWarn . $config['buildLog'] . $ansiReset . PHP_EOL; } else { ++$languageStats['totals']['countDeletedFiles']; if ($config['verbose']) { @@ -863,12 +868,12 @@ // check for configuration errors in per-language settings $isLanguageOk = true; if ((trim($language) == '') or (array_search($language, $reservedConfigKeys, true) !== false)) { - echo $warnTag . 'Invalid language name: ' . $ansiInfo . $language . $ansiReset . PHP_EOL . PHP_EOL; + echo $warnTag . 'Invalid language name: ' . $ansiWarn . $language . $ansiReset . PHP_EOL . PHP_EOL; ++$languageStats[$language]['countSkippedLanguages']; continue; } if (!isset($config[$language]) or !is_array($config[$language])) { - echo $warnTag . 'No configuration available for language: ' . $ansiInfo . $language . $ansiReset . PHP_EOL; + echo $warnTag . 'No configuration available for language: ' . $ansiWarn . $language . $ansiReset . PHP_EOL; ++$languageStats[$language]['countSkippedLanguages']; continue; } @@ -878,7 +883,7 @@ or !is_string($config[$language][$configKey]) or ($config[$language][$configKey] == '') ) { - echo $warnTag . 'Invalid configuration for language ' . $ansiInfo . $language . $ansiReset + echo $warnTag . 'Invalid configuration for language ' . $ansiWarn . $language . $ansiReset . ': required setting must be a non-empty string value: ' . $configKey . PHP_EOL; $isLanguageOk = false; } @@ -889,7 +894,7 @@ continue; } if (!is_string($config[$language][$configKey])) { - echo $warnTag . 'Invalid configuration for language ' . $ansiInfo . $language . $ansiReset + echo $warnTag . 'Invalid configuration for language ' . $ansiWarn . $language . $ansiReset . ': setting must be a string value: ' . $configKey . PHP_EOL; $isLanguageOk = false; } @@ -900,13 +905,13 @@ continue; } if (!is_array($config[$language][$configKey])) { - echo $warnTag . 'Invalid configuration for language ' . $ansiInfo . $language . $ansiReset + echo $warnTag . 'Invalid configuration for language ' . $ansiWarn . $language . $ansiReset . ': setting must be an array: ' . $configKey . PHP_EOL; $isLanguageOk = false; } } if ($config['lang-versions'] and ($config[$language]['versionCommand'] == '')) { - echo $warnTag . 'Invalid configuration: missing version command for language: ' . $ansiInfo . $language + echo $warnTag . 'Invalid configuration: missing version command for language: ' . $ansiWarn . $language . $ansiReset . PHP_EOL; $isLanguageOk = false; } @@ -1071,7 +1076,8 @@ ++$languageStats[$language]['countFiles']; if (!file_exists($sourceFullFileName)) { if (!$config['clean']) { - echo $warnTag . 'Cannot find sourcefile: ' . $ansiInfo . $sourceFullFileName . $ansiReset . PHP_EOL; + echo $warnTag . 'Cannot find sourcefile: ' . $ansiWarn . $sourceFullFileName . $ansiReset + . PHP_EOL; } ++$languageStats[$language]['countSkippedFiles']; if (!isset($puzzleStats[$puzzleName])) { @@ -1100,7 +1106,7 @@ $unlinkResult = unlink($tempFileName); if (!$unlinkResult) { ++$totalUnsuccessfulDeleteFiles; - echo $warnTag . 'Could not delete file: ' . $ansiInfo . $tempFileName . $ansiReset + echo $warnTag . 'Could not delete file: ' . $ansiWarn . $tempFileName . $ansiReset . PHP_EOL; } else { ++$languageStats[$language]['countDeletedFiles']; @@ -1136,7 +1142,7 @@ if ($config['clean']) { if (!$unlinkResult) { ++$totalUnsuccessfulDeleteFiles; - echo $warnTag . 'Could not delete file: ' . $ansiInfo . $csprojFilename + echo $warnTag . 'Could not delete file: ' . $ansiWarn . $csprojFilename . $ansiReset . PHP_EOL; } else { ++$languageStats[$language]['countDeletedFiles']; @@ -1200,11 +1206,28 @@ $execResult = exec($buildCommand, $execOutput, $execResultCode); if (($execResult === false) or ($execResultCode != 0)) { $buildSuccessful = false; - echo $warnTag . 'Build unsuccessful for source: ' . $ansiInfo . $sourceFullFileName + echo $warnTag . 'Build unsuccessful for source: ' . $ansiWarn . $sourceFullFileName . $ansiReset . PHP_EOL; } } // -------------------------------------------------------------------- + // count source lines + if (!$config['clean']) { + $sourceFileContents = fopen($sourceFullFileName, 'r'); + if ($sourceFileContents === false) { + echo $errorTag . 'Cannot open source file: ' . $ansiWarn . $sourceFullFileName . $ansiReset + . PHP_EOL; + } else { + $countLines = 0; + while (!feof($sourceFileContents)) { + fgets($sourceFileContents); + ++$countLines; + } + fclose($sourceFileContents); + $languageStats[$language]['countLines'] += $countLines; + } + } + // -------------------------------------------------------------------- // preparation common for all tests $baseRunCommand = str_replace( ['%l', '%p', '%o', '%b', '%s'], @@ -1258,7 +1281,7 @@ if (!file_exists($expectedFullFileName)) { ++$languageStats[$language]['countSkippedTests']; ++$countSkippedTestsForFile; - echo $warnTag . 'Cannot read expected test output file: ' . $ansiInfo . $expectedFullFileName + echo $warnTag . 'Cannot read expected test output file: ' . $ansiWarn . $expectedFullFileName . $ansiReset . PHP_EOL; continue; } @@ -1270,7 +1293,7 @@ ); if (!$runOnlyCurrentPuzzle and ($expectedFullFileName === $outputFullFileName)) { echo $errorTag . 'Invalid configuration: expected and real test output filenames ' - . 'must not be the same: ' . $ansiInfo . $expectedFullFileName . $ansiReset + . 'must not be the same: ' . $ansiWarn . $expectedFullFileName . $ansiReset . PHP_EOL . PHP_EOL; exit(2); } @@ -1281,7 +1304,7 @@ $unlinkResult = unlink($outputFullFileName); if (!$unlinkResult) { ++$totalUnsuccessfulDeleteFiles; - echo $warnTag . 'Could not delete file: ' . $ansiInfo . $outputFullFileName . $ansiReset + echo $warnTag . 'Could not delete file: ' . $ansiWarn . $outputFullFileName . $ansiReset . PHP_EOL; } else { ++$languageStats[$language]['countDeletedFiles']; @@ -1303,7 +1326,7 @@ if ($expectedFileContents === false) { ++$languageStats[$language]['countSkippedTests']; ++$countSkippedTestsForFile; - echo $warnTag . 'Cannot read expected test output file: ' . $ansiInfo . $expectedFullFileName + echo $warnTag . 'Cannot read expected test output file: ' . $ansiWarn . $expectedFullFileName . $ansiReset . PHP_EOL; continue; } @@ -1374,13 +1397,13 @@ // -------------------------------------------------------------------- // read and process test output (replace CRLF with LF, remove trailing LF) if (!file_exists($outputFullFileName)) { - echo $errorTag . 'Cannot read test output file: ' . $ansiInfo . $outputFullFileName + echo $errorTag . 'Cannot read test output file: ' . $ansiWarn . $outputFullFileName . $ansiReset . PHP_EOL; continue; } $outputFileContents = file_get_contents($outputFullFileName); if ($outputFileContents === false) { - echo $warnTag . 'Cannot read test output file: ' . $ansiInfo . $outputFullFileName + echo $warnTag . 'Cannot read test output file: ' . $ansiWarn . $outputFullFileName . $ansiReset . PHP_EOL; continue; } @@ -1406,7 +1429,7 @@ continue; } if ($countTestsForFile == 0) { - echo $warnTag . 'No test input found for source: ' . $ansiInfo . $sourceFullFileName . $ansiReset + echo $warnTag . 'No test input found for source: ' . $ansiWarn . $sourceFullFileName . $ansiReset . PHP_EOL; } if (isset($puzzleStats[$puzzleName])) { @@ -1515,19 +1538,19 @@ $cleanHeader3 = ' files |'; } $emptyTag = str_repeat(' ', 7); - $separator = '-------+------------+------+------+------+------+------+------+------+------+------+-------+' + $separator = '-------+------------+------+------+------+------+------+------+------+------+------+------+-------+' . $cleanHeader1; echo $separator . PHP_EOL; - echo ' | |Direc-| Puzzles (source files) | Test cases | |' + echo ' | |Direc-| Puzzle solutions (source files) | Test cases | |' . $cleanHeader2 . PHP_EOL; - echo ' | Language |tories| Total|NoEval| Fail | Skip | Total|NoEval| Fail | Skip | Time |' + echo ' | Language |tories| Total|NoEval| Fail | Skip | Lines| Total|NoEval| Fail | Skip | Time |' . $cleanHeader3 . PHP_EOL; echo $separator . PHP_EOL; foreach ($languageStats as $language => $stat) { if (($language == 'totals') or ($language == 'unique')) { continue; } - if ($config['dry-run'] or $config['clean']) { + if ($config['dry-run'] or $config['clean'] or $config['lang-versions']) { $status = $emptyTag; } else { $status = $passTag; @@ -1537,6 +1560,7 @@ $msgCountRunOnlyFiles = str_pad(substr(strval($stat['countRunOnlyFiles']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountFailedFiles = str_pad(substr(strval($stat['countFailedFiles']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountSkippedFiles = str_pad(substr(strval($stat['countSkippedFiles']), 0, 6), 6, ' ', STR_PAD_LEFT); + $msgCountLines = str_pad(substr(strval($stat['countLines']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountTests = str_pad(substr(strval($stat['countTests']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountRunOnlyTests = str_pad(substr(strval($stat['countRunOnlyTests']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountFailedTests = str_pad(substr(strval($stat['countFailedTests']), 0, 6), 6, ' ', STR_PAD_LEFT); @@ -1546,12 +1570,12 @@ $msgLanguageSkipped = ''; if ($stat['countSkippedLanguages'] > 0) { $status = $warnTag; - $msgLanguageSkipped = ' language skipped.'; + $msgLanguageSkipped = $ansiYellow . ' skipped.' . $ansiReset; } if ($config['clean']) { $msgCountDeletedFiles = str_pad(strval($stat['countDeletedFiles']), 7, ' ', STR_PAD_LEFT) . '|'; } else { - if ($stat['countFiles'] == 0) { + if (($stat['countFiles'] == 0) and !$config['lang-versions']) { $msgCountFiles = $ansiYellowInv . $msgCountFiles . $ansiReset; $status = $warnTag; } @@ -1559,7 +1583,7 @@ $msgCountSkippedFiles = $ansiYellowInv . $msgCountSkippedFiles . $ansiReset; $status = $warnTag; } - if ($stat['countTests'] == 0) { + if (($stat['countTests'] == 0) and !$config['lang-versions']) { $msgCountTests = $ansiYellowInv . $msgCountTests . $ansiReset; $status = $warnTag; } @@ -1583,6 +1607,7 @@ . '|' . $msgCountRunOnlyFiles . '|' . $msgCountFailedFiles . '|' . $msgCountSkippedFiles + . '|' . $msgCountLines . '|' . $msgCountTests . '|' . $msgCountRunOnlyTests . '|' . $msgCountFailedTests @@ -1602,6 +1627,7 @@ $msgCountRunOnlyFiles = str_pad(substr(strval($stat['countRunOnlyFiles']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountFailedFiles = str_pad(substr(strval($stat['countFailedFiles']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountSkippedFiles = str_pad(substr(strval($stat['countSkippedFiles']), 0, 6), 6, ' ', STR_PAD_LEFT); + $msgCountLines = str_pad(substr(strval($stat['countLines']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountTests = str_pad(substr(strval($stat['countTests']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountRunOnlyTests = str_pad(substr(strval($stat['countRunOnlyTests']), 0, 6), 6, ' ', STR_PAD_LEFT); $msgCountFailedTests = str_pad(substr(strval($stat['countFailedTests']), 0, 6), 6, ' ', STR_PAD_LEFT); @@ -1619,6 +1645,7 @@ . '|' . $msgCountRunOnlyFiles . '|' . $msgCountFailedFiles . '|' . $msgCountSkippedFiles + . '|' . $msgCountLines . '|' . $msgCountTests . '|' . $msgCountRunOnlyTests . '|' . $msgCountFailedTests @@ -1648,6 +1675,7 @@ . '|' . $msgCountRunOnlyFiles . '|' . $msgCountFailedFiles . '|' . $msgCountSkippedFiles + . '| ' . '|' . $msgCountTests . '|' . $msgCountRunOnlyTests . '|' . $msgCountFailedTests @@ -1722,17 +1750,21 @@ echo $ansiYellowInv . str_pad(' [WARN] There was nothing to test.', $statusWidth) . $ansiReset . PHP_EOL . PHP_EOL; exit(1); } -$msg = ''; -if ($languageStats['unique']['countFiles'] != $languageStats['totals']['countFiles']) { - $msg = ' for ' . $ansiInfo . $languageStats['unique']['countFiles'] . $ansiReset - . ' unique puzzle' . ($languageStats['unique']['countFiles'] > 1 ? 's' : ''); +if ($languageStats['totals']['countLanguages'] > 1) { + $msgUniquePuzzles = ' (' . $ansiInfo . $languageStats['unique']['countFiles'] . $ansiReset . ' unique)'; + $msgUniqueTests = ' (' . $ansiInfo . $languageStats['unique']['countTests'] . $ansiReset . ' unique)'; +} else { + $msgUniquePuzzles = ''; + $msgUniqueTests = ''; } -echo $infoTag . 'Total: ' . $ansiInfo . $languageStats['totals']['countPassedTests'] . $ansiReset . ' / ' +echo $infoTag . 'Total: ' . $ansiInfo . $languageStats['totals']['countPassedTests'] . $ansiReset + . ' test' . ($languageStats['totals']['countPassedTests'] > 1 ? 's' : '') . ' passed out of ' . $ansiInfo . $languageStats['totals']['countTests'] . $ansiReset - . ' test' . ($languageStats['totals']['countTests'] > 1 ? 's' : '') . ' passed while testing ' - . $ansiInfo . $languageStats['totals']['countFiles'] . $ansiReset + . $msgUniqueTests . '.' . PHP_EOL; +echo $infoTag . 'Total: ' . $ansiInfo . $languageStats['totals']['countFiles'] . $ansiReset . ' solution' . ($languageStats['totals']['countFiles'] > 1 ? 's' : '') - . $msg . ' in ' + . $msgUniquePuzzles + . ' with ' . $ansiInfo . $languageStats['totals']['countLines'] . $ansiReset . ' total source lines in ' . $ansiInfo . $languageStats['totals']['countLanguages'] . $ansiReset . ' programming language' . ($languageStats['totals']['countLanguages'] > 1 ? 's' : '') . '.' . PHP_EOL; if ((($config['slowThreshold'] ?? 0) > 0) and (count($slowTests) > 0)) { diff --git a/cgtest_screenshot_base.png b/cgtest_screenshot_base.png index 299cdd6c4e738a7f87ecf6138a114e1d2ee4e6d6..bb2687dddf5ad256606f5ae3253a9abbde77c58e 100644 GIT binary patch literal 13071 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 literal 10926 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