From 7745ff0ec130872676b2337004fe915836c6dfbc Mon Sep 17 00:00:00 2001 From: Shamus Taylor Date: Mon, 21 Apr 2025 15:19:16 -0500 Subject: [PATCH 1/3] Add Golang test parser --- __tests__/__outputs__/golang-json.md | 33 +++++ .../__snapshots__/golang-json.test.ts.snap | 108 +++++++++++++++++ __tests__/fixtures/golang-json.json | 46 +++++++ __tests__/golang-json.test.ts | 29 +++++ package.json | 2 + reports/go/calculator.go | 20 +++ reports/go/calculator_test.go | 77 ++++++++++++ reports/go/go.mod | 3 + src/parsers/golang-json/golang-json-parser.ts | 114 ++++++++++++++++++ src/parsers/golang-json/golang-json-types.ts | 19 +++ 10 files changed, 451 insertions(+) create mode 100644 __tests__/__outputs__/golang-json.md create mode 100644 __tests__/__snapshots__/golang-json.test.ts.snap create mode 100644 __tests__/fixtures/golang-json.json create mode 100644 __tests__/golang-json.test.ts create mode 100644 reports/go/calculator.go create mode 100644 reports/go/calculator_test.go create mode 100644 reports/go/go.mod create mode 100644 src/parsers/golang-json/golang-json-parser.ts create mode 100644 src/parsers/golang-json/golang-json-types.ts diff --git a/__tests__/__outputs__/golang-json.md b/__tests__/__outputs__/golang-json.md new file mode 100644 index 0000000..aaa36ea --- /dev/null +++ b/__tests__/__outputs__/golang-json.md @@ -0,0 +1,33 @@ +![Tests failed](https://img.shields.io/badge/tests-3%20passed%2C%205%20failed%2C%201%20skipped-critical) +|Report|Passed|Failed|Skipped|Time| +|:---|---:|---:|---:|---:| +|fixtures/golang-json.json|3 ✅|5 ❌|1 ⚪|4s| +## ❌ fixtures/golang-json.json +**9** tests were completed in **4s** with **3** passed, **5** failed and **1** skipped. +|Test suite|Passed|Failed|Skipped|Time| +|:---|---:|---:|---:|---:| +|[_/home/james_t/git/test-reporter/reports/go](#user-content-r0s0)|3 ✅|5 ❌|1 ⚪|4s| +### ❌ _/home/james_t/git/test-reporter/reports/go +``` +✅ TestPassing +❌ TestFailing + calculator_test.go:19: expected 1+1 = 3, got 2 + +❌ TestPanicInsideFunction + calculator_test.go:71: caught panic: runtime error: integer divide by zero + +❌ TestPanicInsideTest + calculator_test.go:71: caught panic: bad stuff + +⚪ TestSkipped + calculator_test.go:45: skipping test + +❌ TestCases + +TestCases + ✅ 1_+_2_=_3 + ✅ 4_+_7_=_11 + ❌ 2_+_3_=_4 + calculator_test.go:62: expected 2 + 3 = 4, got 5 + +``` \ No newline at end of file diff --git a/__tests__/__snapshots__/golang-json.test.ts.snap b/__tests__/__snapshots__/golang-json.test.ts.snap new file mode 100644 index 0000000..f2e4b04 --- /dev/null +++ b/__tests__/__snapshots__/golang-json.test.ts.snap @@ -0,0 +1,108 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`golang-json tests report from ./reports/dotnet test results matches snapshot 1`] = ` +TestRunResult { + "path": "fixtures/golang-json.json", + "suites": [ + TestSuiteResult { + "groups": [ + TestGroupResult { + "name": null, + "tests": [ + TestCaseResult { + "error": undefined, + "name": "TestPassing", + "result": "success", + "time": 90, + }, + TestCaseResult { + "error": { + "details": "calculator_test.go:19: expected 1+1 = 3, got 2 +", + "message": "calculator_test.go:19: expected 1+1 = 3, got 2 +", + }, + "name": "TestFailing", + "result": "failed", + "time": 760, + }, + TestCaseResult { + "error": { + "details": "calculator_test.go:71: caught panic: runtime error: integer divide by zero +", + "message": "calculator_test.go:71: caught panic: runtime error: integer divide by zero +", + }, + "name": "TestPanicInsideFunction", + "result": "failed", + "time": 0, + }, + TestCaseResult { + "error": { + "details": "calculator_test.go:71: caught panic: bad stuff +", + "message": "calculator_test.go:71: caught panic: bad stuff +", + }, + "name": "TestPanicInsideTest", + "result": "failed", + "time": 0, + }, + TestCaseResult { + "error": { + "details": "calculator_test.go:45: skipping test +", + "message": "calculator_test.go:45: skipping test +", + }, + "name": "TestSkipped", + "result": "skipped", + "time": 110, + }, + TestCaseResult { + "error": { + "details": "", + "message": "", + }, + "name": "TestCases", + "result": "failed", + "time": 1620, + }, + ], + }, + TestGroupResult { + "name": "TestCases", + "tests": [ + TestCaseResult { + "error": undefined, + "name": "1_+_2_=_3", + "result": "success", + "time": 540, + }, + TestCaseResult { + "error": undefined, + "name": "4_+_7_=_11", + "result": "success", + "time": 540, + }, + TestCaseResult { + "error": { + "details": "calculator_test.go:62: expected 2 + 3 = 4, got 5 +", + "message": "calculator_test.go:62: expected 2 + 3 = 4, got 5 +", + }, + "name": "2_+_3_=_4", + "result": "failed", + "time": 530, + }, + ], + }, + ], + "name": "_/home/james_t/git/test-reporter/reports/go", + "totalTime": undefined, + }, + ], + "totalTime": undefined, +} +`; diff --git a/__tests__/fixtures/golang-json.json b/__tests__/fixtures/golang-json.json new file mode 100644 index 0000000..c18d7ef --- /dev/null +++ b/__tests__/fixtures/golang-json.json @@ -0,0 +1,46 @@ +{"Time":"2025-04-21T14:45:43.899731191-05:00","Action":"start","Package":"_/home/james_t/git/test-reporter/reports/go"} +{"Time":"2025-04-21T14:45:43.907303273-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing"} +{"Time":"2025-04-21T14:45:43.907333465-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":"=== RUN TestPassing\n"} +{"Time":"2025-04-21T14:45:43.998551886-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":" calculator_test.go:11: pass!\n"} +{"Time":"2025-04-21T14:45:43.998572844-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":"--- PASS: TestPassing (0.09s)\n"} +{"Time":"2025-04-21T14:45:43.998576971-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Elapsed":0.09} +{"Time":"2025-04-21T14:45:43.998580617-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing"} +{"Time":"2025-04-21T14:45:43.998582298-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":"=== RUN TestFailing\n"} +{"Time":"2025-04-21T14:45:44.763532195-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":" calculator_test.go:19: expected 1+1 = 3, got 2\n"} +{"Time":"2025-04-21T14:45:44.763556975-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":"--- FAIL: TestFailing (0.76s)\n"} +{"Time":"2025-04-21T14:45:44.763560434-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Elapsed":0.76} +{"Time":"2025-04-21T14:45:44.763564534-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction"} +{"Time":"2025-04-21T14:45:44.763566339-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":"=== RUN TestPanicInsideFunction\n"} +{"Time":"2025-04-21T14:45:44.763568422-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":" calculator_test.go:71: caught panic: runtime error: integer divide by zero\n"} +{"Time":"2025-04-21T14:45:44.763571047-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":"--- FAIL: TestPanicInsideFunction (0.00s)\n"} +{"Time":"2025-04-21T14:45:44.763575434-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Elapsed":0} +{"Time":"2025-04-21T14:45:44.763577511-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest"} +{"Time":"2025-04-21T14:45:44.763579734-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":"=== RUN TestPanicInsideTest\n"} +{"Time":"2025-04-21T14:45:44.763584346-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":" calculator_test.go:71: caught panic: bad stuff\n"} +{"Time":"2025-04-21T14:45:44.763592493-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":"--- FAIL: TestPanicInsideTest (0.00s)\n"} +{"Time":"2025-04-21T14:45:44.763595682-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Elapsed":0} +{"Time":"2025-04-21T14:45:44.763598032-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped"} +{"Time":"2025-04-21T14:45:44.763600787-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":"=== RUN TestSkipped\n"} +{"Time":"2025-04-21T14:45:44.875085305-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":" calculator_test.go:45: skipping test\n"} +{"Time":"2025-04-21T14:45:44.875128112-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":"--- SKIP: TestSkipped (0.11s)\n"} +{"Time":"2025-04-21T14:45:44.875136234-05:00","Action":"skip","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Elapsed":0.11} +{"Time":"2025-04-21T14:45:44.87514445-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases"} +{"Time":"2025-04-21T14:45:44.87514908-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Output":"=== RUN TestCases\n"} +{"Time":"2025-04-21T14:45:44.875158116-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3"} +{"Time":"2025-04-21T14:45:44.875163067-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Output":"=== RUN TestCases/1_+_2_=_3\n"} +{"Time":"2025-04-21T14:45:45.413895814-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11"} +{"Time":"2025-04-21T14:45:45.413916191-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Output":"=== RUN TestCases/4_+_7_=_11\n"} +{"Time":"2025-04-21T14:45:45.957801848-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4"} +{"Time":"2025-04-21T14:45:45.957836789-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":"=== RUN TestCases/2_+_3_=_4\n"} +{"Time":"2025-04-21T14:45:46.492673381-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":" calculator_test.go:62: expected 2 + 3 = 4, got 5\n"} +{"Time":"2025-04-21T14:45:46.492759645-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Output":"--- FAIL: TestCases (1.62s)\n"} +{"Time":"2025-04-21T14:45:46.492779916-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Output":" --- PASS: TestCases/1_+_2_=_3 (0.54s)\n"} +{"Time":"2025-04-21T14:45:46.492787539-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Elapsed":0.54} +{"Time":"2025-04-21T14:45:46.492795891-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Output":" --- PASS: TestCases/4_+_7_=_11 (0.54s)\n"} +{"Time":"2025-04-21T14:45:46.492801851-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Elapsed":0.54} +{"Time":"2025-04-21T14:45:46.492806634-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":" --- FAIL: TestCases/2_+_3_=_4 (0.53s)\n"} +{"Time":"2025-04-21T14:45:46.492811453-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Elapsed":0.53} +{"Time":"2025-04-21T14:45:46.49281562-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Elapsed":1.62} +{"Time":"2025-04-21T14:45:46.492821605-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Output":"FAIL\n"} +{"Time":"2025-04-21T14:45:46.493310745-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Output":"FAIL\t_/home/james_t/git/test-reporter/reports/go\t2.593s\n"} +{"Time":"2025-04-21T14:45:46.493343801-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Elapsed":2.594} diff --git a/__tests__/golang-json.test.ts b/__tests__/golang-json.test.ts new file mode 100644 index 0000000..37d45b3 --- /dev/null +++ b/__tests__/golang-json.test.ts @@ -0,0 +1,29 @@ +import * as fs from 'fs' +import * as path from 'path' + +import { GolangJsonParser } from '../src/parsers/golang-json/golang-json-parser' +import { ParseOptions } from '../src/test-parser' +import { getReport } from '../src/report/get-report' +import { normalizeFilePath } from '../src/utils/path-utils' + +describe('golang-json tests', () => { + it('report from ./reports/dotnet test results matches snapshot', async () => { + const fixturePath = path.join(__dirname, 'fixtures', 'golang-json.json') + const outputPath = path.join(__dirname, '__outputs__', 'golang-json.md') + const filePath = normalizeFilePath(path.relative(__dirname, fixturePath)) + const fileContent = fs.readFileSync(fixturePath, { encoding: 'utf8' }) + + const opts: ParseOptions = { + parseErrors: true, + trackedFiles: ['calculator.go', 'calculator_test.go'] + } + + const parser = new GolangJsonParser(opts) + const result = await parser.parse(filePath, fileContent) + expect(result).toMatchSnapshot() + + const report = getReport([result]) + fs.mkdirSync(path.dirname(outputPath), { recursive: true }) + fs.writeFileSync(outputPath, report) + }) +}) diff --git a/package.json b/package.json index 96a951e..6c8cdc0 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "dart-fixture": "cd \"reports/dart\" && dart test --file-reporter=\"json:../../__tests__/fixtures/dart-json.json\"", "dotnet-fixture": "dotnet test reports/dotnet/DotnetTests.XUnitTests --logger \"trx;LogFileName=../../../../__tests__/fixtures/dotnet-trx.trx\"", "dotnet-nunit-fixture": "nunit.exe reports/dotnet/DotnetTests.NUnitV3Tests/bin/Debug/netcoreapp3.1/DotnetTests.NUnitV3Tests.dll --result=__tests__/fixtures/dotnet-nunit.xml", + "dotnet-nunit-legacy-fixture": "nunit-console.exe reports/dotnet-nunit-legacy/NUnitLegacy.sln --result=__tests__/fixtures/dotnet-nunit-legacy.xml", + "golang-json-fixture": "go test -v -json -timeout 5s ./reports/go | tee __tests__/fixtures/golang-json.json", "jest-fixture": "cd \"reports/jest\" && npm test", "mocha-fixture": "cd \"reports/mocha\" && npm test" }, diff --git a/reports/go/calculator.go b/reports/go/calculator.go new file mode 100644 index 0000000..c863ae0 --- /dev/null +++ b/reports/go/calculator.go @@ -0,0 +1,20 @@ +package main + +import "errors" + +func CalculatorSum(a, b int) int { + return a + b +} + +func CalculatorDivide(a, b int) int { + return a / b +} + +var ErrDivideByZero = errors.New("divide by zero") + +func CalculatorSafeDivide(a, b int) (int, error) { + if b == 0 { + return 0, ErrDivideByZero + } + return a / b, nil +} diff --git a/reports/go/calculator_test.go b/reports/go/calculator_test.go new file mode 100644 index 0000000..c0649fb --- /dev/null +++ b/reports/go/calculator_test.go @@ -0,0 +1,77 @@ +package main + +import ( + "math/rand" + "testing" + "time" +) + +func TestPassing(t *testing.T) { + randomSleep() + t.Log("pass!") +} + +func TestFailing(t *testing.T) { + randomSleep() + expected := 3 + actual := CalculatorSum(1, 1) + if actual != expected { + t.Fatalf("expected 1+1 = %d, got %d", expected, actual) + } +} + +func TestPanicInsideFunction(t *testing.T) { + defer catchPanics(t) + + expected := 0 + actual := CalculatorDivide(1, 0) + if actual != expected { + t.Fatalf("expected 1/1 = %d, got %d", expected, actual) + } +} + +func TestPanicInsideTest(t *testing.T) { + defer catchPanics(t) + panic("bad stuff") +} + +// Timeouts cause the entire test process to end - so we can't get good output for these +// func TestTimeout(t *testing.T) { +// time.Sleep(time.Second * 5) +// } + +func TestSkipped(t *testing.T) { + randomSleep() + t.Skipf("skipping test") +} + +func TestCases(t *testing.T) { + for _, tc := range []struct { + name string + a, b, c int + }{ + {"1 + 2 = 3", 1, 2, 3}, + {"4 + 7 = 11", 4, 7, 11}, + {"2 + 3 = 4", 2, 3, 4}, + } { + t.Run(tc.name, func(t *testing.T) { + randomSleep() + + c := CalculatorSum(tc.a, tc.b) + if c != tc.c { + t.Fatalf("expected %s, got %d", tc.name, c) + } + }) + } +} + +func catchPanics(t *testing.T) { + err := recover() + if err != nil { + t.Fatalf("caught panic: %v", err) + } +} + +func randomSleep() { + time.Sleep(time.Duration(rand.Int63n(int64(time.Second)))) +} diff --git a/reports/go/go.mod b/reports/go/go.mod new file mode 100644 index 0000000..4b3a577 --- /dev/null +++ b/reports/go/go.mod @@ -0,0 +1,3 @@ +module test_reporter_example + +go 1.24.2 diff --git a/src/parsers/golang-json/golang-json-parser.ts b/src/parsers/golang-json/golang-json-parser.ts new file mode 100644 index 0000000..b79e1f9 --- /dev/null +++ b/src/parsers/golang-json/golang-json-parser.ts @@ -0,0 +1,114 @@ +import { ParseOptions, TestParser } from '../../test-parser' + +import { GoTestEvent } from './golang-json-types' +import { getExceptionSource } from '../../utils/node-utils' +import { getBasePath, normalizeFilePath } from '../../utils/path-utils' + +import { + TestExecutionResult, + TestRunResult, + TestSuiteResult, + TestGroupResult, + TestCaseResult, + TestCaseError +} from '../../test-results' + +export class GolangJsonParser implements TestParser { + assumedWorkDir: string | undefined + + constructor(readonly options: ParseOptions) { } + + async parse(path: string, content: string): Promise { + const events = await this.getGolangTestEvents(path, content) + return this.getTestRunResult(path, events) + } + + private async getGolangTestEvents(path: string, content: string): Promise { + return content.trim().split('\n').map((line, index) => { + try { + return JSON.parse(line) as GoTestEvent + } catch (e) { + throw new Error(`Invalid JSON at ${path} line ${index + 1}\n\n${e}`) + } + }) + } + + private getTestRunResult(path: string, events: GoTestEvent[]): TestRunResult { + const eventGroups = new Map() + for (const event of events) { + if (!event.Test) { + continue + } + const k = `${event.Package}/${event.Test}` + let g = eventGroups.get(k) + if (!g) { + g = [] + eventGroups.set(k, g) + } + g.push(event) + } + + const suites: TestSuiteResult[] = [] + + for (const eventGroup of eventGroups.values()) { + const event = eventGroup[0] + + let suite = suites.find(s => s.name === event.Package) + if (!suite) { + suite = new TestSuiteResult(event.Package, []) + suites.push(suite) + } + + if (!event.Test) { + continue + } + + let groupName: string | null + let testName: string + [groupName, testName] = event.Test.split('/', 2) + if (!testName) { + testName = groupName + groupName = null + } + + let group = suite.groups.find(g => g.name === groupName) + if (!group) { + group = new TestGroupResult(groupName, []) + suite.groups.push(group) + } + + const lastEvent = eventGroup.at(-1)! + + const result: TestExecutionResult = lastEvent.Action === 'pass' ? 'success' + : lastEvent.Action === 'skip' ? 'skipped' + : 'failed' + if (lastEvent.Elapsed === undefined) { + throw new Error('missing elapsed on final test event') + } + const time: number = lastEvent.Elapsed * 1000 + + let error: TestCaseError | undefined = undefined + if (result !== 'success') { + const outputEvents = eventGroup + .filter(e => e.Action === 'output') + .map(e => e.Output ?? '') + // Go output prepends indentation to help group tests - remove it + .map(o => o.replace(/^ /, '')) + + // First and last lines will be generic "test started" and "test finished" lines - remove them + outputEvents.splice(0, 1) + outputEvents.splice(-1, 1) + + const details = outputEvents.join('') + error = { + message: details, + details: details + } + } + + group.tests.push(new TestCaseResult(testName, result, time, error)) + } + + return new TestRunResult(path, suites) + } +} diff --git a/src/parsers/golang-json/golang-json-types.ts b/src/parsers/golang-json/golang-json-types.ts new file mode 100644 index 0000000..f27fa86 --- /dev/null +++ b/src/parsers/golang-json/golang-json-types.ts @@ -0,0 +1,19 @@ +export type GoTestAction = 'start' + | 'run' + | 'pause' + | 'cont' + | 'pass' + | 'bench' + | 'fail' + | 'output' + | 'skip' + +export type GoTestEvent = { + Time: string + Action: GoTestAction + Package: string + Test?: string + Elapsed?: number + Output?: string + FailedBuild?: string +} From 34f1c566ff37c6839418102e3cc501d38efe2a6d Mon Sep 17 00:00:00 2001 From: Shamus Taylor Date: Mon, 21 Apr 2025 15:26:42 -0500 Subject: [PATCH 2/3] register parser and update readme --- README.md | 9 +++++++++ src/main.ts | 3 +++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index e5abd85..676d21e 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ This [Github Action](https://github.com/features/actions) displays test results - .NET / [dotnet test](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#examples) ( [xUnit](https://xunit.net/) / [NUnit](https://nunit.org/) / [MSTest](https://github.com/Microsoft/testfx-docs) ) - Dart / [test](https://pub.dev/packages/test) - Flutter / [test](https://pub.dev/packages/test) +- Go / [go test](https://pkg.go.dev/testing) - Java / [JUnit](https://junit.org/) - JavaScript / [JEST](https://jestjs.io/) / [Mocha](https://mochajs.org/) - Swift / xUnit @@ -140,6 +141,7 @@ jobs: # dotnet-nunit # dotnet-trx # flutter-json + # golang-json # java-junit # jest-junit # mocha-json @@ -278,6 +280,13 @@ For more information see: +
+ golang-json + +You must use the `-json` flag and output the results to a file (ex: `go test -json > testresults.json`) + +
+
java-junit (Experimental) diff --git a/src/main.ts b/src/main.ts index 109d75b..b018390 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,6 +13,7 @@ import {getReport} from './report/get-report' import {DartJsonParser} from './parsers/dart-json/dart-json-parser' import {DotnetNunitParser} from './parsers/dotnet-nunit/dotnet-nunit-parser' import {DotnetTrxParser} from './parsers/dotnet-trx/dotnet-trx-parser' +import {GolangJsonParser} from './parsers/golang-json/golang-json-parser' import {JavaJunitParser} from './parsers/java-junit/java-junit-parser' import {JestJunitParser} from './parsers/jest-junit/jest-junit-parser' import {MochaJsonParser} from './parsers/mocha-json/mocha-json-parser' @@ -248,6 +249,8 @@ class TestReporter { return new DotnetNunitParser(options) case 'dotnet-trx': return new DotnetTrxParser(options) + case 'golang-json': + return new GolangJsonParser(options) case 'flutter-json': return new DartJsonParser(options, 'flutter') case 'java-junit': From a0398fb7ddd193fcf3eb2a1fbb6c7bca62915932 Mon Sep 17 00:00:00 2001 From: Shamus Taylor Date: Tue, 22 Apr 2025 09:04:22 -0500 Subject: [PATCH 3/3] Correct behavior for test cases with slashes --- __tests__/__outputs__/golang-json.md | 19 ++-- .../__snapshots__/golang-json.test.ts.snap | 49 +++++--- __tests__/fixtures/golang-json.json | 105 ++++++++++-------- __tests__/golang-json.test.ts | 12 +- dist/index.js | 103 +++++++++++++++++ reports/go/calculator_test.go | 13 ++- src/parsers/golang-json/golang-json-parser.ts | 5 +- 7 files changed, 228 insertions(+), 78 deletions(-) diff --git a/__tests__/__outputs__/golang-json.md b/__tests__/__outputs__/golang-json.md index aaa36ea..b3640d8 100644 --- a/__tests__/__outputs__/golang-json.md +++ b/__tests__/__outputs__/golang-json.md @@ -1,12 +1,12 @@ -![Tests failed](https://img.shields.io/badge/tests-3%20passed%2C%205%20failed%2C%201%20skipped-critical) +![Tests failed](https://img.shields.io/badge/tests-5%20passed%2C%206%20failed%2C%201%20skipped-critical) |Report|Passed|Failed|Skipped|Time| |:---|---:|---:|---:|---:| -|fixtures/golang-json.json|3 ✅|5 ❌|1 ⚪|4s| +|fixtures/golang-json.json|5 ✅|6 ❌|1 ⚪|6s| ## ❌ fixtures/golang-json.json -**9** tests were completed in **4s** with **3** passed, **5** failed and **1** skipped. +**12** tests were completed in **6s** with **5** passed, **6** failed and **1** skipped. |Test suite|Passed|Failed|Skipped|Time| |:---|---:|---:|---:|---:| -|[_/home/james_t/git/test-reporter/reports/go](#user-content-r0s0)|3 ✅|5 ❌|1 ⚪|4s| +|[_/home/james_t/git/test-reporter/reports/go](#user-content-r0s0)|5 ✅|6 ❌|1 ⚪|6s| ### ❌ _/home/james_t/git/test-reporter/reports/go ``` ✅ TestPassing @@ -14,10 +14,10 @@ calculator_test.go:19: expected 1+1 = 3, got 2 ❌ TestPanicInsideFunction - calculator_test.go:71: caught panic: runtime error: integer divide by zero + calculator_test.go:76: caught panic: runtime error: integer divide by zero ❌ TestPanicInsideTest - calculator_test.go:71: caught panic: bad stuff + calculator_test.go:76: caught panic: bad stuff ⚪ TestSkipped calculator_test.go:45: skipping test @@ -28,6 +28,11 @@ TestCases ✅ 1_+_2_=_3 ✅ 4_+_7_=_11 ❌ 2_+_3_=_4 - calculator_test.go:62: expected 2 + 3 = 4, got 5 + calculator_test.go:67: expected 2 + 3 = 4, got 5 + ❌ 1_/_2_=_1 + calculator_test.go:67: expected 1 / 2 = 1, got 0 + + ✅ 9_/_3_=_3 + ✅ 14_/_7_=_2 ``` \ No newline at end of file diff --git a/__tests__/__snapshots__/golang-json.test.ts.snap b/__tests__/__snapshots__/golang-json.test.ts.snap index f2e4b04..75c6de1 100644 --- a/__tests__/__snapshots__/golang-json.test.ts.snap +++ b/__tests__/__snapshots__/golang-json.test.ts.snap @@ -13,7 +13,7 @@ TestRunResult { "error": undefined, "name": "TestPassing", "result": "success", - "time": 90, + "time": 60, }, TestCaseResult { "error": { @@ -24,13 +24,13 @@ TestRunResult { }, "name": "TestFailing", "result": "failed", - "time": 760, + "time": 890, }, TestCaseResult { "error": { - "details": "calculator_test.go:71: caught panic: runtime error: integer divide by zero + "details": "calculator_test.go:76: caught panic: runtime error: integer divide by zero ", - "message": "calculator_test.go:71: caught panic: runtime error: integer divide by zero + "message": "calculator_test.go:76: caught panic: runtime error: integer divide by zero ", }, "name": "TestPanicInsideFunction", @@ -39,9 +39,9 @@ TestRunResult { }, TestCaseResult { "error": { - "details": "calculator_test.go:71: caught panic: bad stuff + "details": "calculator_test.go:76: caught panic: bad stuff ", - "message": "calculator_test.go:71: caught panic: bad stuff + "message": "calculator_test.go:76: caught panic: bad stuff ", }, "name": "TestPanicInsideTest", @@ -57,7 +57,7 @@ TestRunResult { }, "name": "TestSkipped", "result": "skipped", - "time": 110, + "time": 940, }, TestCaseResult { "error": { @@ -66,7 +66,7 @@ TestRunResult { }, "name": "TestCases", "result": "failed", - "time": 1620, + "time": 2250, }, ], }, @@ -77,24 +77,47 @@ TestRunResult { "error": undefined, "name": "1_+_2_=_3", "result": "success", - "time": 540, + "time": 400, }, TestCaseResult { "error": undefined, "name": "4_+_7_=_11", "result": "success", - "time": 540, + "time": 460, }, TestCaseResult { "error": { - "details": "calculator_test.go:62: expected 2 + 3 = 4, got 5 + "details": "calculator_test.go:67: expected 2 + 3 = 4, got 5 ", - "message": "calculator_test.go:62: expected 2 + 3 = 4, got 5 + "message": "calculator_test.go:67: expected 2 + 3 = 4, got 5 ", }, "name": "2_+_3_=_4", "result": "failed", - "time": 530, + "time": 90, + }, + TestCaseResult { + "error": { + "details": "calculator_test.go:67: expected 1 / 2 = 1, got 0 +", + "message": "calculator_test.go:67: expected 1 / 2 = 1, got 0 +", + }, + "name": "1_/_2_=_1", + "result": "failed", + "time": 920, + }, + TestCaseResult { + "error": undefined, + "name": "9_/_3_=_3", + "result": "success", + "time": 340, + }, + TestCaseResult { + "error": undefined, + "name": "14_/_7_=_2", + "result": "success", + "time": 40, }, ], }, diff --git a/__tests__/fixtures/golang-json.json b/__tests__/fixtures/golang-json.json index c18d7ef..421a707 100644 --- a/__tests__/fixtures/golang-json.json +++ b/__tests__/fixtures/golang-json.json @@ -1,46 +1,59 @@ -{"Time":"2025-04-21T14:45:43.899731191-05:00","Action":"start","Package":"_/home/james_t/git/test-reporter/reports/go"} -{"Time":"2025-04-21T14:45:43.907303273-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing"} -{"Time":"2025-04-21T14:45:43.907333465-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":"=== RUN TestPassing\n"} -{"Time":"2025-04-21T14:45:43.998551886-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":" calculator_test.go:11: pass!\n"} -{"Time":"2025-04-21T14:45:43.998572844-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":"--- PASS: TestPassing (0.09s)\n"} -{"Time":"2025-04-21T14:45:43.998576971-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Elapsed":0.09} -{"Time":"2025-04-21T14:45:43.998580617-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing"} -{"Time":"2025-04-21T14:45:43.998582298-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":"=== RUN TestFailing\n"} -{"Time":"2025-04-21T14:45:44.763532195-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":" calculator_test.go:19: expected 1+1 = 3, got 2\n"} -{"Time":"2025-04-21T14:45:44.763556975-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":"--- FAIL: TestFailing (0.76s)\n"} -{"Time":"2025-04-21T14:45:44.763560434-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Elapsed":0.76} -{"Time":"2025-04-21T14:45:44.763564534-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction"} -{"Time":"2025-04-21T14:45:44.763566339-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":"=== RUN TestPanicInsideFunction\n"} -{"Time":"2025-04-21T14:45:44.763568422-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":" calculator_test.go:71: caught panic: runtime error: integer divide by zero\n"} -{"Time":"2025-04-21T14:45:44.763571047-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":"--- FAIL: TestPanicInsideFunction (0.00s)\n"} -{"Time":"2025-04-21T14:45:44.763575434-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Elapsed":0} -{"Time":"2025-04-21T14:45:44.763577511-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest"} -{"Time":"2025-04-21T14:45:44.763579734-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":"=== RUN TestPanicInsideTest\n"} -{"Time":"2025-04-21T14:45:44.763584346-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":" calculator_test.go:71: caught panic: bad stuff\n"} -{"Time":"2025-04-21T14:45:44.763592493-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":"--- FAIL: TestPanicInsideTest (0.00s)\n"} -{"Time":"2025-04-21T14:45:44.763595682-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Elapsed":0} -{"Time":"2025-04-21T14:45:44.763598032-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped"} -{"Time":"2025-04-21T14:45:44.763600787-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":"=== RUN TestSkipped\n"} -{"Time":"2025-04-21T14:45:44.875085305-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":" calculator_test.go:45: skipping test\n"} -{"Time":"2025-04-21T14:45:44.875128112-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":"--- SKIP: TestSkipped (0.11s)\n"} -{"Time":"2025-04-21T14:45:44.875136234-05:00","Action":"skip","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Elapsed":0.11} -{"Time":"2025-04-21T14:45:44.87514445-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases"} -{"Time":"2025-04-21T14:45:44.87514908-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Output":"=== RUN TestCases\n"} -{"Time":"2025-04-21T14:45:44.875158116-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3"} -{"Time":"2025-04-21T14:45:44.875163067-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Output":"=== RUN TestCases/1_+_2_=_3\n"} -{"Time":"2025-04-21T14:45:45.413895814-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11"} -{"Time":"2025-04-21T14:45:45.413916191-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Output":"=== RUN TestCases/4_+_7_=_11\n"} -{"Time":"2025-04-21T14:45:45.957801848-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4"} -{"Time":"2025-04-21T14:45:45.957836789-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":"=== RUN TestCases/2_+_3_=_4\n"} -{"Time":"2025-04-21T14:45:46.492673381-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":" calculator_test.go:62: expected 2 + 3 = 4, got 5\n"} -{"Time":"2025-04-21T14:45:46.492759645-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Output":"--- FAIL: TestCases (1.62s)\n"} -{"Time":"2025-04-21T14:45:46.492779916-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Output":" --- PASS: TestCases/1_+_2_=_3 (0.54s)\n"} -{"Time":"2025-04-21T14:45:46.492787539-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Elapsed":0.54} -{"Time":"2025-04-21T14:45:46.492795891-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Output":" --- PASS: TestCases/4_+_7_=_11 (0.54s)\n"} -{"Time":"2025-04-21T14:45:46.492801851-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Elapsed":0.54} -{"Time":"2025-04-21T14:45:46.492806634-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":" --- FAIL: TestCases/2_+_3_=_4 (0.53s)\n"} -{"Time":"2025-04-21T14:45:46.492811453-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Elapsed":0.53} -{"Time":"2025-04-21T14:45:46.49281562-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Elapsed":1.62} -{"Time":"2025-04-21T14:45:46.492821605-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Output":"FAIL\n"} -{"Time":"2025-04-21T14:45:46.493310745-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Output":"FAIL\t_/home/james_t/git/test-reporter/reports/go\t2.593s\n"} -{"Time":"2025-04-21T14:45:46.493343801-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Elapsed":2.594} +{"Time":"2025-04-22T08:59:55.364618802-05:00","Action":"start","Package":"_/home/james_t/git/test-reporter/reports/go"} +{"Time":"2025-04-22T08:59:55.371779289-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing"} +{"Time":"2025-04-22T08:59:55.371805677-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":"=== RUN TestPassing\n"} +{"Time":"2025-04-22T08:59:55.428201983-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":" calculator_test.go:11: pass!\n"} +{"Time":"2025-04-22T08:59:55.428265529-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Output":"--- PASS: TestPassing (0.06s)\n"} +{"Time":"2025-04-22T08:59:55.428285649-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPassing","Elapsed":0.06} +{"Time":"2025-04-22T08:59:55.428299886-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing"} +{"Time":"2025-04-22T08:59:55.428309029-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":"=== RUN TestFailing\n"} +{"Time":"2025-04-22T08:59:56.317425091-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":" calculator_test.go:19: expected 1+1 = 3, got 2\n"} +{"Time":"2025-04-22T08:59:56.31748077-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Output":"--- FAIL: TestFailing (0.89s)\n"} +{"Time":"2025-04-22T08:59:56.317493452-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestFailing","Elapsed":0.89} +{"Time":"2025-04-22T08:59:56.317506107-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction"} +{"Time":"2025-04-22T08:59:56.317514487-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":"=== RUN TestPanicInsideFunction\n"} +{"Time":"2025-04-22T08:59:56.317530448-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":" calculator_test.go:76: caught panic: runtime error: integer divide by zero\n"} +{"Time":"2025-04-22T08:59:56.317541866-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Output":"--- FAIL: TestPanicInsideFunction (0.00s)\n"} +{"Time":"2025-04-22T08:59:56.317552981-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideFunction","Elapsed":0} +{"Time":"2025-04-22T08:59:56.317561057-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest"} +{"Time":"2025-04-22T08:59:56.317568742-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":"=== RUN TestPanicInsideTest\n"} +{"Time":"2025-04-22T08:59:56.317584113-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":" calculator_test.go:76: caught panic: bad stuff\n"} +{"Time":"2025-04-22T08:59:56.317598524-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Output":"--- FAIL: TestPanicInsideTest (0.00s)\n"} +{"Time":"2025-04-22T08:59:56.317608268-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestPanicInsideTest","Elapsed":0} +{"Time":"2025-04-22T08:59:56.317615472-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped"} +{"Time":"2025-04-22T08:59:56.317623959-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":"=== RUN TestSkipped\n"} +{"Time":"2025-04-22T08:59:57.256475698-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":" calculator_test.go:45: skipping test\n"} +{"Time":"2025-04-22T08:59:57.256536372-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Output":"--- SKIP: TestSkipped (0.94s)\n"} +{"Time":"2025-04-22T08:59:57.256549142-05:00","Action":"skip","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestSkipped","Elapsed":0.94} +{"Time":"2025-04-22T08:59:57.256562053-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases"} +{"Time":"2025-04-22T08:59:57.256569388-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Output":"=== RUN TestCases\n"} +{"Time":"2025-04-22T08:59:57.256580104-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3"} +{"Time":"2025-04-22T08:59:57.256587408-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Output":"=== RUN TestCases/1_+_2_=_3\n"} +{"Time":"2025-04-22T08:59:57.653005399-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11"} +{"Time":"2025-04-22T08:59:57.653036336-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Output":"=== RUN TestCases/4_+_7_=_11\n"} +{"Time":"2025-04-22T08:59:58.112825221-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4"} +{"Time":"2025-04-22T08:59:58.112858016-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":"=== RUN TestCases/2_+_3_=_4\n"} +{"Time":"2025-04-22T08:59:58.201204209-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":" calculator_test.go:67: expected 2 + 3 = 4, got 5\n"} +{"Time":"2025-04-22T08:59:58.201245827-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_/_2_=_1"} +{"Time":"2025-04-22T08:59:58.201255566-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_/_2_=_1","Output":"=== RUN TestCases/1_/_2_=_1\n"} +{"Time":"2025-04-22T08:59:59.119852965-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_/_2_=_1","Output":" calculator_test.go:67: expected 1 / 2 = 1, got 0\n"} +{"Time":"2025-04-22T08:59:59.119877603-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/9_/_3_=_3"} +{"Time":"2025-04-22T08:59:59.119879955-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/9_/_3_=_3","Output":"=== RUN TestCases/9_/_3_=_3\n"} +{"Time":"2025-04-22T08:59:59.460576385-05:00","Action":"run","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/14_/_7_=_2"} +{"Time":"2025-04-22T08:59:59.460607599-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/14_/_7_=_2","Output":"=== RUN TestCases/14_/_7_=_2\n"} +{"Time":"2025-04-22T08:59:59.504952672-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Output":"--- FAIL: TestCases (2.25s)\n"} +{"Time":"2025-04-22T08:59:59.504995938-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Output":" --- PASS: TestCases/1_+_2_=_3 (0.40s)\n"} +{"Time":"2025-04-22T08:59:59.505006062-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_+_2_=_3","Elapsed":0.4} +{"Time":"2025-04-22T08:59:59.505017551-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Output":" --- PASS: TestCases/4_+_7_=_11 (0.46s)\n"} +{"Time":"2025-04-22T08:59:59.505026099-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/4_+_7_=_11","Elapsed":0.46} +{"Time":"2025-04-22T08:59:59.505033963-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Output":" --- FAIL: TestCases/2_+_3_=_4 (0.09s)\n"} +{"Time":"2025-04-22T08:59:59.505042238-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/2_+_3_=_4","Elapsed":0.09} +{"Time":"2025-04-22T08:59:59.505050917-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_/_2_=_1","Output":" --- FAIL: TestCases/1_/_2_=_1 (0.92s)\n"} +{"Time":"2025-04-22T08:59:59.505059901-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/1_/_2_=_1","Elapsed":0.92} +{"Time":"2025-04-22T08:59:59.505068125-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/9_/_3_=_3","Output":" --- PASS: TestCases/9_/_3_=_3 (0.34s)\n"} +{"Time":"2025-04-22T08:59:59.505076976-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/9_/_3_=_3","Elapsed":0.34} +{"Time":"2025-04-22T08:59:59.5050845-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/14_/_7_=_2","Output":" --- PASS: TestCases/14_/_7_=_2 (0.04s)\n"} +{"Time":"2025-04-22T08:59:59.505091554-05:00","Action":"pass","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases/14_/_7_=_2","Elapsed":0.04} +{"Time":"2025-04-22T08:59:59.505098998-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Test":"TestCases","Elapsed":2.25} +{"Time":"2025-04-22T08:59:59.505107502-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Output":"FAIL\n"} +{"Time":"2025-04-22T08:59:59.505552861-05:00","Action":"output","Package":"_/home/james_t/git/test-reporter/reports/go","Output":"FAIL\t_/home/james_t/git/test-reporter/reports/go\t4.141s\n"} +{"Time":"2025-04-22T08:59:59.505584529-05:00","Action":"fail","Package":"_/home/james_t/git/test-reporter/reports/go","Elapsed":4.141} diff --git a/__tests__/golang-json.test.ts b/__tests__/golang-json.test.ts index 37d45b3..0bfdd86 100644 --- a/__tests__/golang-json.test.ts +++ b/__tests__/golang-json.test.ts @@ -1,17 +1,17 @@ import * as fs from 'fs' import * as path from 'path' -import { GolangJsonParser } from '../src/parsers/golang-json/golang-json-parser' -import { ParseOptions } from '../src/test-parser' -import { getReport } from '../src/report/get-report' -import { normalizeFilePath } from '../src/utils/path-utils' +import {GolangJsonParser} from '../src/parsers/golang-json/golang-json-parser' +import {ParseOptions} from '../src/test-parser' +import {getReport} from '../src/report/get-report' +import {normalizeFilePath} from '../src/utils/path-utils' describe('golang-json tests', () => { it('report from ./reports/dotnet test results matches snapshot', async () => { const fixturePath = path.join(__dirname, 'fixtures', 'golang-json.json') const outputPath = path.join(__dirname, '__outputs__', 'golang-json.md') const filePath = normalizeFilePath(path.relative(__dirname, fixturePath)) - const fileContent = fs.readFileSync(fixturePath, { encoding: 'utf8' }) + const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'}) const opts: ParseOptions = { parseErrors: true, @@ -23,7 +23,7 @@ describe('golang-json tests', () => { expect(result).toMatchSnapshot() const report = getReport([result]) - fs.mkdirSync(path.dirname(outputPath), { recursive: true }) + fs.mkdirSync(path.dirname(outputPath), {recursive: true}) fs.writeFileSync(outputPath, report) }) }) diff --git a/dist/index.js b/dist/index.js index 26cc77d..94ba8b0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -273,6 +273,7 @@ const get_report_1 = __nccwpck_require__(7070); const dart_json_parser_1 = __nccwpck_require__(1254); const dotnet_nunit_parser_1 = __nccwpck_require__(6394); const dotnet_trx_parser_1 = __nccwpck_require__(1658); +const golang_json_parser_1 = __nccwpck_require__(5162); const java_junit_parser_1 = __nccwpck_require__(8342); const jest_junit_parser_1 = __nccwpck_require__(1042); const mocha_json_parser_1 = __nccwpck_require__(5402); @@ -475,6 +476,8 @@ class TestReporter { return new dotnet_nunit_parser_1.DotnetNunitParser(options); case 'dotnet-trx': return new dotnet_trx_parser_1.DotnetTrxParser(options); + case 'golang-json': + return new golang_json_parser_1.GolangJsonParser(options); case 'flutter-json': return new dart_json_parser_1.DartJsonParser(options, 'flutter'); case 'java-junit': @@ -1066,6 +1069,106 @@ class DotnetTrxParser { exports.DotnetTrxParser = DotnetTrxParser; +/***/ }), + +/***/ 5162: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.GolangJsonParser = void 0; +const test_results_1 = __nccwpck_require__(613); +class GolangJsonParser { + options; + assumedWorkDir; + constructor(options) { + this.options = options; + } + async parse(path, content) { + const events = await this.getGolangTestEvents(path, content); + return this.getTestRunResult(path, events); + } + async getGolangTestEvents(path, content) { + return content.trim().split('\n').map((line, index) => { + try { + return JSON.parse(line); + } + catch (e) { + throw new Error(`Invalid JSON at ${path} line ${index + 1}\n\n${e}`); + } + }); + } + getTestRunResult(path, events) { + const eventGroups = new Map(); + for (const event of events) { + if (!event.Test) { + continue; + } + const k = `${event.Package}/${event.Test}`; + let g = eventGroups.get(k); + if (!g) { + g = []; + eventGroups.set(k, g); + } + g.push(event); + } + const suites = []; + for (const eventGroup of eventGroups.values()) { + const event = eventGroup[0]; + let suite = suites.find(s => s.name === event.Package); + if (!suite) { + suite = new test_results_1.TestSuiteResult(event.Package, []); + suites.push(suite); + } + if (!event.Test) { + continue; + } + let groupName; + let rest; + [groupName, ...rest] = event.Test.split('/'); + let testName = rest.join('/'); + if (!testName) { + testName = groupName; + groupName = null; + } + let group = suite.groups.find(g => g.name === groupName); + if (!group) { + group = new test_results_1.TestGroupResult(groupName, []); + suite.groups.push(group); + } + const lastEvent = eventGroup.at(-1); + const result = lastEvent.Action === 'pass' ? 'success' + : lastEvent.Action === 'skip' ? 'skipped' + : 'failed'; + if (lastEvent.Elapsed === undefined) { + throw new Error('missing elapsed on final test event'); + } + const time = lastEvent.Elapsed * 1000; + let error = undefined; + if (result !== 'success') { + const outputEvents = eventGroup + .filter(e => e.Action === 'output') + .map(e => e.Output ?? '') + // Go output prepends indentation to help group tests - remove it + .map(o => o.replace(/^ /, '')); + // First and last lines will be generic "test started" and "test finished" lines - remove them + outputEvents.splice(0, 1); + outputEvents.splice(-1, 1); + const details = outputEvents.join(''); + error = { + message: details, + details: details + }; + } + group.tests.push(new test_results_1.TestCaseResult(testName, result, time, error)); + } + return new test_results_1.TestRunResult(path, suites); + } +} +exports.GolangJsonParser = GolangJsonParser; + + /***/ }), /***/ 8342: diff --git a/reports/go/calculator_test.go b/reports/go/calculator_test.go index c0649fb..d9f6128 100644 --- a/reports/go/calculator_test.go +++ b/reports/go/calculator_test.go @@ -48,16 +48,21 @@ func TestSkipped(t *testing.T) { func TestCases(t *testing.T) { for _, tc := range []struct { name string + fn func(int, int) int a, b, c int }{ - {"1 + 2 = 3", 1, 2, 3}, - {"4 + 7 = 11", 4, 7, 11}, - {"2 + 3 = 4", 2, 3, 4}, + {"1 + 2 = 3", CalculatorSum, 1, 2, 3}, + {"4 + 7 = 11", CalculatorSum, 4, 7, 11}, + {"2 + 3 = 4", CalculatorSum, 2, 3, 4}, + + {"1 / 2 = 1", CalculatorDivide, 1, 2, 1}, + {"9 / 3 = 3", CalculatorDivide, 9, 3, 3}, + {"14 / 7 = 2", CalculatorDivide, 14, 7, 2}, } { t.Run(tc.name, func(t *testing.T) { randomSleep() - c := CalculatorSum(tc.a, tc.b) + c := tc.fn(tc.a, tc.b) if c != tc.c { t.Fatalf("expected %s, got %d", tc.name, c) } diff --git a/src/parsers/golang-json/golang-json-parser.ts b/src/parsers/golang-json/golang-json-parser.ts index b79e1f9..bc20821 100644 --- a/src/parsers/golang-json/golang-json-parser.ts +++ b/src/parsers/golang-json/golang-json-parser.ts @@ -64,8 +64,9 @@ export class GolangJsonParser implements TestParser { } let groupName: string | null - let testName: string - [groupName, testName] = event.Test.split('/', 2) + let rest: string[] + [groupName, ...rest] = event.Test.split('/') + let testName = rest.join('/') if (!testName) { testName = groupName groupName = null