From da26f8cad1c43ed0fc135d1d2778dd0ccec8dac4 Mon Sep 17 00:00:00 2001 From: Sanjeev Penupala Date: Sat, 7 Mar 2026 12:01:08 -0600 Subject: [PATCH 1/2] improve mutation test coverage for line selection parsing Add 16 new test cases across checkLegacySyntax and parseLineSelector to kill 11 survived mutants. Covered mutation score rises from 93.42% to 98.25%. Remaining 4 survivors are equivalent mutants or dead code. --- plugin/src/checkLegacySyntax.test.ts | 37 +++++++++++++- plugin/src/parseLineSelector.test.ts | 75 ++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/plugin/src/checkLegacySyntax.test.ts b/plugin/src/checkLegacySyntax.test.ts index 3dda2d0..b1ea866 100644 --- a/plugin/src/checkLegacySyntax.test.ts +++ b/plugin/src/checkLegacySyntax.test.ts @@ -1,8 +1,43 @@ import { expect, test } from "vitest"; import { checkLegacySyntax } from "./checkLegacySyntax.js"; -test("it should parse tag without file path", () => { +test("it should throw on legacy colon syntax with line range", () => { expect(() => checkLegacySyntax("src/greet.example.ts:5-20")).toThrowError( "BREAKING CHANGE: The colon syntax 'src/greet.example.ts:5-20' is no longer supported in v3.0.0+. Please migrate to the new bracket syntax: 'src/greet.example.ts[5:20]'. See documentation for the new bracket syntax.", ); }); + +test("it should throw on legacy colon syntax with single line", () => { + expect(() => checkLegacySyntax("file.ts:15")).toThrowError("BREAKING CHANGE"); +}); + +test("it should throw on legacy colon syntax with spaces in selector", () => { + expect(() => checkLegacySyntax("file.ts:5 - 20")).toThrowError( + "BREAKING CHANGE", + ); +}); + +test("it should not throw when tag has no colon", () => { + expect(() => checkLegacySyntax("foo.example.ts")).not.toThrow(); +}); + +test("it should not throw when colon is followed by non-numeric text", () => { + expect(() => checkLegacySyntax("file.ts:notdigits")).not.toThrow(); +}); + +test("it should not throw when colon is followed by empty string", () => { + expect(() => checkLegacySyntax("file.ts:")).not.toThrow(); +}); + +test("it should not throw when colon is followed by only whitespace", () => { + expect(() => checkLegacySyntax("file.ts: ")).not.toThrow(); +}); + +test("it should throw on legacy syntax where colon is at index 1", () => { + expect(() => checkLegacySyntax("a:5")).toThrowError("BREAKING CHANGE"); +}); + +test("it should not throw when colon is followed by mixed alphanumeric", () => { + expect(() => checkLegacySyntax("file.ts:123abc")).not.toThrow(); + expect(() => checkLegacySyntax("file.ts:abc123")).not.toThrow(); +}); diff --git a/plugin/src/parseLineSelector.test.ts b/plugin/src/parseLineSelector.test.ts index b00aeeb..72abab2 100644 --- a/plugin/src/parseLineSelector.test.ts +++ b/plugin/src/parseLineSelector.test.ts @@ -251,6 +251,81 @@ test("Should handle colon-only selector", () => { expect(parseLineSelector(":")).toHaveLength(0); }); +test("Should handle whitespace-padded selector", () => { + const result = parseLineSelector(" 5 "); + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + type: "single", + isExclusion: false, + line: 5, + }); +}); + +test("Should handle spaces around comma-separated parts", () => { + const result = parseLineSelector("2:5, 10"); + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ + type: "range", + isExclusion: false, + start: 2, + end: 5, + }); + expect(result[1]).toEqual({ + type: "single", + isExclusion: false, + line: 10, + }); +}); + +test("Should skip empty parts from trailing comma", () => { + const result = parseLineSelector("2:5,"); + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + type: "range", + isExclusion: false, + start: 2, + end: 5, + }); +}); + +test("Should skip empty parts from double comma", () => { + const result = parseLineSelector("2:5,,10"); + expect(result).toHaveLength(2); + expect(result[1]).toEqual({ + type: "single", + isExclusion: false, + line: 10, + }); +}); + +test("Should detect old dash syntax with spaces around parts", () => { + expect(() => parseLineSelector("2-4 , 10")).toThrowError("BREAKING CHANGE"); +}); + +test("Should handle whitespace around exclusion part", () => { + const result = parseLineSelector("1:10, !5"); + expect(result).toHaveLength(2); + expect(result[1]).toEqual({ + type: "single", + isExclusion: true, + line: 5, + }); +}); + +test("Should handle negative number with trailing characters as old dash syntax", () => { + expect(() => parseLineSelector("-5-3")).toThrowError("BREAKING CHANGE"); +}); + +test("Should not flag negative number with leading space as old dash syntax", () => { + const result = parseLineSelector("1, -5"); + expect(result).toHaveLength(2); + expect(result[1]).toEqual({ + type: "single", + isExclusion: false, + line: -5, + }); +}); + test("Should resolve basic range", () => { const parsed = parseLineSelector("2:5"); const resolved = resolveLineSelections(parsed, 10); From f64c95d031dc79193d5b1ac0017ecf64e995b5c5 Mon Sep 17 00:00:00 2001 From: Sanjeev Penupala Date: Sat, 7 Mar 2026 12:25:03 -0600 Subject: [PATCH 2/2] update contributor GitHub username --- plugin/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/package.json b/plugin/package.json index dd6e60e..f5a4bef 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -21,7 +21,7 @@ "Jeremy Cherer (https://github.com/JavaLavaMT)", "Rocky Warren (https://github.com/therockstorm)", "Gerrit Birkeland (https://github.com/Gerrit0)", - "Sanjeev Penupala (https://github.com/spenpal)" + "Sanjeev Penupala (https://github.com/sanjeevpenupala)" ], "scripts": { "build": "tsc --noEmit && tsc --noEmit -p test.tsconfig.json && vitest run && biome ci && exportcase check src && stryker run && tsc",