|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +const fs = require('fs'); |
| 4 | +const path = require('path'); |
| 5 | +const { execSync } = require('child_process'); |
| 6 | + |
| 7 | +const IMPLEMENT_DIR = 'Sprint-3/1-implement-and-rewrite-tests/implement'; |
| 8 | +const JEST_DIR = 'Sprint-3/1-implement-and-rewrite-tests/rewrite-tests-with-jest'; |
| 9 | + |
| 10 | +const results = { |
| 11 | + passed: 0, |
| 12 | + failed: 0, |
| 13 | + total: 0, |
| 14 | + parityIssues: [] |
| 15 | +}; |
| 16 | + |
| 17 | +function runInlineTest(filePath) { |
| 18 | + const filename = path.basename(filePath); |
| 19 | + console.log(`\nTesting: ${filename}`); |
| 20 | + |
| 21 | + try { |
| 22 | + const output = execSync(`node "${filePath}"`, { |
| 23 | + encoding: 'utf-8', |
| 24 | + stdio: 'pipe' |
| 25 | + }); |
| 26 | + |
| 27 | + if (output.includes('Assertion failed')) { |
| 28 | + console.log('FAILED'); |
| 29 | + console.log(output); |
| 30 | + return { status: 'failed', filename }; |
| 31 | + } |
| 32 | + |
| 33 | + console.log('PASSED'); |
| 34 | + if (output.trim()) console.log(output); |
| 35 | + return { status: 'passed', filename }; |
| 36 | + |
| 37 | + } catch (error) { |
| 38 | + const output = error.stdout || error.stderr || error.message; |
| 39 | + console.log('FAILED'); |
| 40 | + console.log(output); |
| 41 | + return { status: 'failed', filename }; |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +function getJsFiles(dir) { |
| 46 | + if (!fs.existsSync(dir)) return []; |
| 47 | + return fs.readdirSync(dir) |
| 48 | + .filter(file => file.endsWith('.js')) |
| 49 | + .map(file => path.join(dir, file)); |
| 50 | +} |
| 51 | + |
| 52 | +function countAssertions(filePath, pattern) { |
| 53 | + try { |
| 54 | + const content = fs.readFileSync(filePath, 'utf-8'); |
| 55 | + const matches = content.match(new RegExp(pattern, 'g')); |
| 56 | + return matches ? matches.length : 0; |
| 57 | + } catch (error) { |
| 58 | + return 0; |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +function checkParity(implFile) { |
| 63 | + const filename = path.basename(implFile); |
| 64 | + const baseName = filename.replace('.js', ''); |
| 65 | + const jestFile = path.join(JEST_DIR, `${baseName}.test.js`); |
| 66 | + |
| 67 | + console.log(`\nComparing: ${filename}`); |
| 68 | + |
| 69 | + if (!fs.existsSync(jestFile)) { |
| 70 | + console.log('No corresponding Jest test file found'); |
| 71 | + return { filename, inlineCount: 0, jestCount: 0, hasMismatch: true }; |
| 72 | + } |
| 73 | + |
| 74 | + const inlineCount = countAssertions(implFile, 'assertEquals\\('); |
| 75 | + const jestCount = countAssertions(jestFile, 'expect\\('); |
| 76 | + |
| 77 | + console.log(`Inline: ${inlineCount}, Jest: ${jestCount}`); |
| 78 | + |
| 79 | + if (inlineCount === jestCount) { |
| 80 | + console.log('Counts match'); |
| 81 | + return { filename, inlineCount, jestCount, hasMismatch: false }; |
| 82 | + } |
| 83 | + |
| 84 | + const diff = Math.abs(inlineCount - jestCount); |
| 85 | + console.log(`Mismatch: ${diff} assertion(s) difference`); |
| 86 | + |
| 87 | + return { |
| 88 | + filename, |
| 89 | + inlineCount, |
| 90 | + jestCount, |
| 91 | + diff, |
| 92 | + hasMismatch: true |
| 93 | + }; |
| 94 | +} |
| 95 | + |
| 96 | +function writeGitHubSummary() { |
| 97 | + const summaryFile = process.env.GITHUB_STEP_SUMMARY; |
| 98 | + if (!summaryFile) return; |
| 99 | + |
| 100 | + let summary = '## Inline Assertion Tests\n\n'; |
| 101 | + summary += '| Metric | Count |\n|--------|-------|\n'; |
| 102 | + summary += `| Total | ${results.total} |\n`; |
| 103 | + summary += `| Passed | ${results.passed} |\n`; |
| 104 | + summary += `| Failed | ${results.failed} |\n\n`; |
| 105 | + |
| 106 | + summary += '## Test Parity Check\n\n'; |
| 107 | + summary += '| File | Inline | Jest | Match |\n|------|--------|------|-------|\n'; |
| 108 | + |
| 109 | + results.parityIssues.forEach(issue => { |
| 110 | + const match = issue.hasMismatch ? 'No' : 'Yes'; |
| 111 | + summary += `| ${issue.filename} | ${issue.inlineCount} | ${issue.jestCount} | ${match} |\n`; |
| 112 | + }); |
| 113 | + |
| 114 | + fs.appendFileSync(summaryFile, summary); |
| 115 | +} |
| 116 | + |
| 117 | +function main() { |
| 118 | + console.log('Running inline assertion tests...\n'); |
| 119 | + |
| 120 | + const testFiles = getJsFiles(IMPLEMENT_DIR); |
| 121 | + if (testFiles.length === 0) { |
| 122 | + console.log(`No test files found in ${IMPLEMENT_DIR}`); |
| 123 | + process.exit(1); |
| 124 | + } |
| 125 | + |
| 126 | + results.total = testFiles.length; |
| 127 | + |
| 128 | + testFiles.forEach(file => { |
| 129 | + const result = runInlineTest(file); |
| 130 | + if (result.status === 'passed') { |
| 131 | + results.passed++; |
| 132 | + } else { |
| 133 | + results.failed++; |
| 134 | + } |
| 135 | + }); |
| 136 | + |
| 137 | + console.log(`\n\nTest Summary: ${results.passed}/${results.total} passed`); |
| 138 | + |
| 139 | + console.log('\n\nChecking test parity...'); |
| 140 | + testFiles.forEach(file => { |
| 141 | + results.parityIssues.push(checkParity(file)); |
| 142 | + }); |
| 143 | + |
| 144 | + const hasParityIssues = results.parityIssues.some(issue => issue.hasMismatch); |
| 145 | + |
| 146 | + writeGitHubSummary(); |
| 147 | + |
| 148 | + console.log('\n'); |
| 149 | + if (results.failed > 0) { |
| 150 | + console.log(`${results.failed} test(s) failed`); |
| 151 | + process.exit(1); |
| 152 | + } |
| 153 | + |
| 154 | + if (hasParityIssues) { |
| 155 | + console.log('Parity issues detected - please review'); |
| 156 | + } else { |
| 157 | + console.log('All tests passed, parity verified'); |
| 158 | + } |
| 159 | + |
| 160 | + process.exit(0); |
| 161 | +} |
| 162 | + |
| 163 | +main(); |
0 commit comments