From 95c880e0891736c4fdea7a958bcde731acd53433 Mon Sep 17 00:00:00 2001 From: Emilien Escalle Date: Fri, 5 Jun 2026 18:16:59 +0200 Subject: [PATCH] fix(actions/parse-ci-reports-path): auto-pattern detection and parser accepted paths conflict Signed-off-by: Emilien Escalle --- .../src/parsers/CheckStyleParser.test.js | 60 +++++++++++++++++++ .../src/parsers/CoberturaParser.test.js | 46 ++++++++++++++ .../src/parsers/ESLintParser.test.js | 51 ++++++++++++++++ .../src/parsers/LCOVParser.test.js | 43 +++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 actions/parse-ci-reports/src/parsers/CheckStyleParser.test.js create mode 100644 actions/parse-ci-reports/src/parsers/CoberturaParser.test.js create mode 100644 actions/parse-ci-reports/src/parsers/ESLintParser.test.js create mode 100644 actions/parse-ci-reports/src/parsers/LCOVParser.test.js diff --git a/actions/parse-ci-reports/src/parsers/CheckStyleParser.test.js b/actions/parse-ci-reports/src/parsers/CheckStyleParser.test.js new file mode 100644 index 0000000..60898ba --- /dev/null +++ b/actions/parse-ci-reports/src/parsers/CheckStyleParser.test.js @@ -0,0 +1,60 @@ +import { describe, it } from "node:test"; +import assert from "node:assert/strict"; +import { CheckStyleParser } from "./CheckStyleParser.js"; + +const EMPTY_CHECKSTYLE_XML = ` +`; + +const CHECKSTYLE_WITH_ISSUES_XML = ` + + + + +`; + +describe("CheckStyleParser", () => { + it("keeps auto-pattern path detection synchronized", () => { + const parser = new CheckStyleParser(); + const filePath = "application/humanize-checkstyle-result.xml"; + + assert.ok(parser.matchesAutoPatterns(filePath)); + assert.ok(parser.canParse(filePath, EMPTY_CHECKSTYLE_XML)); + }); + + it("identifies valid checkstyle XML reports without file entries", () => { + const parser = new CheckStyleParser(); + + assert.ok( + parser.canParse( + "application/humanize-report-checkstyle.xml", + EMPTY_CHECKSTYLE_XML, + ), + ); + }); + + it("parses empty checkstyle reports as zero lint issues", () => { + const parser = new CheckStyleParser(); + + const reportData = parser.parse( + EMPTY_CHECKSTYLE_XML, + "application/humanize-report-checkstyle.xml", + ); + assert.strictEqual(reportData.lintIssues.length, 0); + }); + + it("parses checkstyle issues from file entries", () => { + const parser = new CheckStyleParser(); + + const reportData = parser.parse( + CHECKSTYLE_WITH_ISSUES_XML, + "checkstyle-result.xml", + ); + + assert.strictEqual(reportData.lintIssues.length, 1); + assert.strictEqual(reportData.lintIssues[0].file, "src/index.js"); + assert.strictEqual(reportData.lintIssues[0].line, 5); + assert.strictEqual(reportData.lintIssues[0].column, 1); + assert.strictEqual(reportData.lintIssues[0].severity, "warning"); + assert.strictEqual(reportData.lintIssues[0].rule, "no-console"); + }); +}); diff --git a/actions/parse-ci-reports/src/parsers/CoberturaParser.test.js b/actions/parse-ci-reports/src/parsers/CoberturaParser.test.js new file mode 100644 index 0000000..fcc2e0a --- /dev/null +++ b/actions/parse-ci-reports/src/parsers/CoberturaParser.test.js @@ -0,0 +1,46 @@ +import { describe, it } from "node:test"; +import assert from "node:assert/strict"; +import { CoberturaParser } from "./CoberturaParser.js"; + +const SAMPLE_COBERTURA_XML = ` + + + + + + + + + + + + + +`; + +describe("CoberturaParser", () => { + it("keeps auto-pattern path detection synchronized", () => { + const parser = new CoberturaParser(); + const filePath = "coverage/humanize-coverage.xml"; + + assert.ok(parser.matchesAutoPatterns(filePath)); + assert.ok(parser.canParse(filePath, SAMPLE_COBERTURA_XML)); + }); + + it("identifies Cobertura XML reports", () => { + const parser = new CoberturaParser(); + + assert.ok(parser.canParse("coverage/coverage.xml", SAMPLE_COBERTURA_XML)); + assert.ok(!parser.canParse("reports/report.txt", SAMPLE_COBERTURA_XML)); + }); + + it("parses coverage totals", () => { + const parser = new CoberturaParser(); + const reportData = parser.parse(SAMPLE_COBERTURA_XML, "coverage.xml"); + + assert.ok(reportData.coverage); + assert.strictEqual(reportData.coverage.lines.total, 2); + assert.strictEqual(reportData.coverage.lines.covered, 1); + assert.strictEqual(reportData.coverage.lines.percentage, 50); + }); +}); diff --git a/actions/parse-ci-reports/src/parsers/ESLintParser.test.js b/actions/parse-ci-reports/src/parsers/ESLintParser.test.js new file mode 100644 index 0000000..35f9551 --- /dev/null +++ b/actions/parse-ci-reports/src/parsers/ESLintParser.test.js @@ -0,0 +1,51 @@ +import { describe, it } from "node:test"; +import assert from "node:assert/strict"; +import { ESLintParser } from "./ESLintParser.js"; + +const SAMPLE_ESLINT_JSON = JSON.stringify([ + { + filePath: "src/app.js", + messages: [ + { + ruleId: "no-console", + severity: 2, + message: "Unexpected console statement.", + line: 3, + column: 1, + }, + ], + }, +]); + +describe("ESLintParser", () => { + it("keeps auto-pattern path detection synchronized", () => { + const parser = new ESLintParser(); + const filePath = "reports/humanize-eslint-report.json"; + + assert.ok(parser.matchesAutoPatterns(filePath)); + assert.ok(parser.canParse(filePath, SAMPLE_ESLINT_JSON)); + }); + + it("identifies ESLint report format", () => { + const parser = new ESLintParser(); + + assert.ok(parser.canParse("eslint-report.json", SAMPLE_ESLINT_JSON)); + assert.ok(!parser.canParse("eslint-report.txt", SAMPLE_ESLINT_JSON)); + assert.ok(!parser.canParse("eslint-report.json", "{}")); + }); + + it("parses lint issues from ESLint JSON", () => { + const parser = new ESLintParser(); + const reportData = parser.parse(SAMPLE_ESLINT_JSON, "eslint-report.json"); + + assert.strictEqual(reportData.lintIssues.length, 1); + const [issue] = reportData.lintIssues; + + assert.strictEqual(issue.file, "src/app.js"); + assert.strictEqual(issue.line, 3); + assert.strictEqual(issue.column, 1); + assert.strictEqual(issue.severity, "error"); + assert.strictEqual(issue.rule, "no-console"); + assert.strictEqual(issue.message, "Unexpected console statement."); + }); +}); diff --git a/actions/parse-ci-reports/src/parsers/LCOVParser.test.js b/actions/parse-ci-reports/src/parsers/LCOVParser.test.js new file mode 100644 index 0000000..6fbaa19 --- /dev/null +++ b/actions/parse-ci-reports/src/parsers/LCOVParser.test.js @@ -0,0 +1,43 @@ +import { describe, it } from "node:test"; +import assert from "node:assert/strict"; +import { LCOVParser } from "./LCOVParser.js"; + +const SAMPLE_LCOV = `TN: +SF:src/app.js +DA:1,1 +DA:2,0 +FNDA:1,handler +BRDA:2,0,0,1 +BRDA:2,0,1,0 +end_of_record +`; + +describe("LCOVParser", () => { + it("keeps auto-pattern path detection synchronized", () => { + const parser = new LCOVParser(); + const filePath = "coverage/humanize-lcov.info"; + + assert.ok(parser.matchesAutoPatterns(filePath)); + assert.ok(parser.canParse(filePath, SAMPLE_LCOV)); + }); + + it("identifies LCOV reports", () => { + const parser = new LCOVParser(); + + assert.ok(parser.canParse("coverage/lcov.info", SAMPLE_LCOV)); + assert.ok(!parser.canParse("coverage/report.txt", SAMPLE_LCOV)); + }); + + it("parses line, function, and branch coverage", () => { + const parser = new LCOVParser(); + const reportData = parser.parse(SAMPLE_LCOV, "lcov.info"); + + assert.ok(reportData.coverage); + assert.strictEqual(reportData.coverage.lines.total, 2); + assert.strictEqual(reportData.coverage.lines.covered, 1); + assert.strictEqual(reportData.coverage.functions.total, 1); + assert.strictEqual(reportData.coverage.functions.covered, 1); + assert.strictEqual(reportData.coverage.branches.total, 2); + assert.strictEqual(reportData.coverage.branches.covered, 1); + }); +});