From 1bd6eee88390a8eaf85545b60aa9834b9756b3d5 Mon Sep 17 00:00:00 2001 From: Kevin Buffardi Date: Wed, 16 Sep 2026 13:32:44 -0700 Subject: [PATCH] fix(cpp): parse CxxTest output mismatches Populate expected and received values for quoted CxxTest inequality diagnostics while preserving raw multi-failure output.\n\nRefs codewit-us/codewit.us#186\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- executor.js | 16 ++++++++++-- test/cpp-result.test.js | 55 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/executor.js b/executor.js index 058634c..47ba5ca 100644 --- a/executor.js +++ b/executor.js @@ -285,6 +285,16 @@ async function handleTestSetup(language, uniqueDir, className, testCode) { } } +function extractCppOutputMismatch(message) { + const match = message.match( + /found\s*\(\s*"((?:\\.|[^"\\])*)"\s*!=\s*"((?:\\.|[^"\\])*)"\s*\)/ + ); + + return match + ? { expected: match[1], received: match[2] } + : { expected: '', received: '' }; +} + function parseCppTestOutput(output, stdout = '', stderr = '') { output = output.toString(); let total_tests = 0; @@ -307,10 +317,12 @@ function parseCppTestOutput(output, stdout = '', stderr = '') { const diagnosticBlocks = extractCppDiagnosticBlocks(output); diagnosticBlocks.forEach((message, index) => { + const { expected, received } = extractCppOutputMismatch(message); + failures.push({ test_case: `Test ${index + 1}`, - expected: '', - received: '', + expected, + received, error_message: message, rawout: `${stdout}\n${stderr}`, stderr, diff --git a/test/cpp-result.test.js b/test/cpp-result.test.js index 45dcbc7..ab4cfcf 100644 --- a/test/cpp-result.test.js +++ b/test/cpp-result.test.js @@ -18,6 +18,23 @@ test_program.h:15: Error: Assertion failed: first student-facing message test_program.h:16: Error: Assertion failed: second student-facing message Failed 1 and Skipped 0 of 2 tests`; +const outputMismatchFailures = `Running cxxtest tests (3 tests) +In codewit_test::testSuccessfulLogin: +test_program.h:38: Error: Expected (removeWhitespace(expected) == removeWhitespace(actual)), found ("EnterauserEnterapasswordLoginsuccessful!juan" != "EnterauserEnterapasswordLoginsuccessful!") +In codewit_test::testWrongPassword: +test_program.h:67: Error: Expected (removeWhitespace(expected) == removeWhitespace(actual)), found ("EnterauserEnterapasswordOneofthethingsyouenteredisincorrect.Loginfailed" != "EnterauserEnterapasswordOneofthethingsenteredisincorrectLoginfailed") +. +Failed 2 and Skipped 0 of 3 tests +Success rate: 33%`; + +const escapedOutputMismatch = `Running cxxtest tests (1 test) +test_program.h:15: Error: Expected (expected == actual), found ("say \\"hello\\"\\\\n" != "") +Failed 1 and Skipped 0 of 1 test`; + +const malformedOutputMismatch = `Running cxxtest tests (1 test) +test_program.h:15: Error: Expected (expected == actual), found ("expected" != actual) +Failed 1 and Skipped 0 of 1 test`; + for (const [name, output, total] of [ ['singular failure summary', oneTestFailure, 1], ['plural failure summary', pluralFailure, 2], @@ -47,6 +64,44 @@ assert.deepStrictEqual( ] ); +const outputMismatchResult = parseCppTestOutput(outputMismatchFailures, outputMismatchFailures, ''); +assert.strictEqual(outputMismatchResult.tests_run, 3); +assert.strictEqual(outputMismatchResult.passed, 1); +assert.strictEqual(outputMismatchResult.failed, 2); +assert.strictEqual(outputMismatchResult.failure_details.length, 2); +assert.deepStrictEqual( + outputMismatchResult.failure_details.map(({ expected, received }) => ({ expected, received })), + [ + { + expected: 'EnterauserEnterapasswordLoginsuccessful!juan', + received: 'EnterauserEnterapasswordLoginsuccessful!', + }, + { + expected: 'EnterauserEnterapasswordOneofthethingsyouenteredisincorrect.Loginfailed', + received: 'EnterauserEnterapasswordOneofthethingsenteredisincorrectLoginfailed', + }, + ] +); +assert.match(outputMismatchResult.failure_details[0].rawout, /testSuccessfulLogin/); +assert.match(outputMismatchResult.failure_details[0].rawout, /testWrongPassword/); +assert.match(outputMismatchResult.failure_details[0].rawout, /Failed 2 and Skipped 0 of 3 tests/); + +const escapedOutputMismatchResult = parseCppTestOutput( + escapedOutputMismatch, + escapedOutputMismatch, + '' +); +assert.strictEqual(escapedOutputMismatchResult.failure_details[0].expected, 'say \\"hello\\"\\\\n'); +assert.strictEqual(escapedOutputMismatchResult.failure_details[0].received, ''); + +const malformedOutputMismatchResult = parseCppTestOutput( + malformedOutputMismatch, + malformedOutputMismatch, + '' +); +assert.strictEqual(malformedOutputMismatchResult.failure_details[0].expected, ''); +assert.strictEqual(malformedOutputMismatchResult.failure_details[0].received, ''); + const assertionResponse = buildCppTestResponse( { state: 'failed', runtime_error: 'Execution failed with code 1', failure_details: [] }, { stdout: oneTestFailure, stderr: '', exitCode: 1 }