apex-mutation-testing 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -3
- package/lib/commands/apex/mutation/test/run.d.ts +1 -0
- package/lib/commands/apex/mutation/test/run.js +4 -0
- package/lib/commands/apex/mutation/test/run.js.map +1 -1
- package/lib/service/configReader.js +1 -0
- package/lib/service/configReader.js.map +1 -1
- package/lib/service/exactColoring.d.ts +25 -0
- package/lib/service/exactColoring.js +143 -0
- package/lib/service/exactColoring.js.map +1 -0
- package/lib/service/groupExecutor.d.ts +29 -0
- package/lib/service/groupExecutor.js +194 -0
- package/lib/service/groupExecutor.js.map +1 -0
- package/lib/service/mutantGenerator.d.ts +2 -0
- package/lib/service/mutantGenerator.js +26 -1
- package/lib/service/mutantGenerator.js.map +1 -1
- package/lib/service/mutationGrouper.d.ts +22 -0
- package/lib/service/mutationGrouper.js +130 -0
- package/lib/service/mutationGrouper.js.map +1 -0
- package/lib/service/mutationLocation.d.ts +12 -0
- package/lib/service/mutationLocation.js +54 -0
- package/lib/service/mutationLocation.js.map +1 -0
- package/lib/service/mutationTestingService.d.ts +3 -6
- package/lib/service/mutationTestingService.js +71 -177
- package/lib/service/mutationTestingService.js.map +1 -1
- package/lib/service/timeUtils.d.ts +1 -0
- package/lib/service/timeUtils.js +8 -0
- package/lib/service/timeUtils.js.map +1 -1
- package/lib/type/ApexMutationParameter.d.ts +1 -0
- package/messages/apex.mutation.test.run.md +13 -1
- package/npm-shrinkwrap.json +553 -378
- package/oclif.manifest.json +7 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutantGenerator.js","sourceRoot":"","sources":["../../src/service/mutantGenerator.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mutantGenerator.js","sourceRoot":"","sources":["../../src/service/mutantGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,mBAAmB,EAAE,MAAM,UAAU,CAAA;AACjE,OAAO,EACL,SAAS,EACT,UAAU,EAEV,0BAA0B,EAC1B,iBAAiB,EACjB,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;AACrF,OAAO,EAAE,iCAAiC,EAAE,MAAM,iDAAiD,CAAA;AACnG,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AAEnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,8BAA8B,EAAE,MAAM,8CAA8C,CAAA;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAA;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AACnF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAA;AAC3F,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAK3E,MAAM,YAAY,GAAG;IACnB,oBAAoB,EAAE,qBAAqB;IAC3C,mBAAmB,EAAE,oBAAoB;IACzC,4BAA4B,EAAE,4BAA4B;IAC1D,gBAAgB,EAAE,iBAAiB;IACnC,kBAAkB,EAAE,mBAAmB;IACvC,gBAAgB,EAAE,iBAAiB;IACnC,YAAY,EAAE,aAAa;IAC3B,kBAAkB,EAAE,mBAAmB;IACvC,mBAAmB,EAAE,oBAAoB;IACzC,YAAY,EAAE,aAAa;IAC3B,SAAS,EAAE,WAAW;IACtB,eAAe,EAAE,gBAAgB;IACjC,gBAAgB,EAAE,iBAAiB;IACnC,gBAAgB,EAAE,iBAAiB;IACnC,yBAAyB,EAAE,yBAAyB;IACpD,eAAe,EAAE,gBAAgB;IACjC,cAAc,EAAE,eAAe;IAC/B,QAAQ,EAAE,UAAU;IACpB,oBAAoB,EAAE,mBAAmB;IACzC,WAAW,EAAE,YAAY;IACzB,mBAAmB,EAAE,oBAAoB;IACzC,iBAAiB,EAAE,kBAAkB;IACrC,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,YAAY;IACzB,wBAAwB,EAAE,wBAAwB;IAClD,gBAAgB,EAAE,gBAAgB;CAC1B,CAAA;AASV,MAAM,gBAAgB,GAA2B;IAC/C;QACE,IAAI,EAAE,YAAY,CAAC,oBAAoB;QACvC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,0BAA0B,CAAC,EAAE,CAAC;KACjD;IACD;QACE,IAAI,EAAE,YAAY,CAAC,mBAAmB;QACtC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,yBAAyB,CAAC,EAAE,CAAC;KAChD;IACD;QACE,IAAI,EAAE,YAAY,CAAC,4BAA4B;QAC/C,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,iCAAiC,CAAC,EAAE,CAAC;KACxD;IACD;QACE,IAAI,EAAE,YAAY,CAAC,gBAAgB;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,sBAAsB,EAAE;KAC3C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,kBAAkB;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,wBAAwB,EAAE;KAC7C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,gBAAgB;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,sBAAsB,EAAE;KAC3C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,YAAY;QAC/B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC;KACzC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,kBAAkB;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,wBAAwB,EAAE;KAC7C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,mBAAmB;QACtC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,yBAAyB,EAAE;KAC9C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,YAAY;QAC/B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC;KACzC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,SAAS;QAC5B,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,gBAAgB,EAAE;KACrC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,eAAe;QAClC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,qBAAqB,CAAC,EAAE,CAAC;KAC5C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,gBAAgB;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,sBAAsB,EAAE;KAC3C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,gBAAgB;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,sBAAsB,EAAE;KAC3C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,yBAAyB;QAC5C,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,8BAA8B,EAAE;KACnD;IACD;QACE,IAAI,EAAE,YAAY,CAAC,eAAe;QAClC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;KAC1C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,cAAc;QACjC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,oBAAoB,CAAC,EAAE,CAAC;KAC3C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,QAAQ;QAC3B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,eAAe,CAAC,EAAE,CAAC;KACtC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,oBAAoB;QACvC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,wBAAwB,CAAC,EAAE,CAAC;KAC/C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,WAAW;QAC9B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,iBAAiB,CAAC,EAAE,CAAC;KACxC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,mBAAmB;QACtC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,yBAAyB,EAAE;KAC9C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,iBAAiB;QACpC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,uBAAuB,EAAE;KAC5C;IACD;QACE,IAAI,EAAE,YAAY,CAAC,MAAM;QACzB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE;KAClC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,WAAW;QAC9B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,iBAAiB,CAAC,EAAE,CAAC;KACxC;IACD;QACE,IAAI,EAAE,YAAY,CAAC,wBAAwB;QAC3C,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,6BAA6B,CAAC,EAAE,CAAC;KACpD;IACD;QACE,IAAI,EAAE,YAAY,CAAC,gBAAgB;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;KAC1C;CACF,CAAA;AAYD,MAAM,OAAO,eAAe;IACnB,OAAO,CACZ,YAAoB,EACpB,YAAyB,EACzB,YAA2B,EAC3B,aAA0D,EAC1D,eAA8B,EAAE,EAChC,YAA0B,EAC1B,SAA0B;QAE1B,IAAI,IAAuB,CAAA;QAC3B,IAAI,WAA8B,CAAA;QAClC,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,GAAG,SAAS,CAAC,IAAI,CAAA;YACrB,WAAW,GAAG,SAAS,CAAC,WAAW,CAAA;QACrC,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,IAAI,SAAS,CACzB,IAAI,0BAA0B,CAAC,OAAO,EAAE,YAAY,CAAC,CACtD,CAAA;YACD,WAAW,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAA;YAC1C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAA;YAC1C,IAAI,GAAG,MAAM,CAAC,eAAe,EAAuB,CAAA;QACtD,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAA;QAE3D,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;QAC1E,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAE5C,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CACnC,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,CACZ,CAAA;QAED,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,QAA8B,EAAE,IAAI,CAAC,CAAA;QAElE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,YAAY,EAAE,EAAE,WAAW,EAAE,CAAA;IAC5D,CAAC;IAEM,MAAM,CACX,QAAsB,EACtB,WAA8B;QAE9B,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAA;IACjD,CAAC;IAED,wEAAwE;IACxE,6EAA6E;IAC7E,6CAA6C;IAC7C,EAAE;IACF,0EAA0E;IAC1E,2EAA2E;IAC3E,uEAAuE;IAChE,UAAU,CACf,SAAsC,EACtC,WAA8B;QAE9B,IAAI,CAAC,0BAA0B,CAAC,SAAS,CAAC,CAAA;QAC1C,MAAM,QAAQ,GAAG,IAAI,mBAAmB,CAAC,WAAW,CAAC,CAAA;QACrD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,QAAQ,CAAC,OAAO,CACd,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EACrC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EACnC,QAAQ,CAAC,WAAW,CACrB,CAAA;QACH,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAA;IAC3B,CAAC;IAEO,0BAA0B,CAChC,SAAsC;QAEtC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,OAAM;QAChC,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAC1E,CAAA;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAA;YACxD,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAA;YACxD,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACb,+CAA+C,SAAS,MAAM,OAAO,GAAG,CACzE,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,aAGtB;QACC,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,gBAAgB,CAAA;QACzB,CAAC;QAED,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,OAAO,IAAI,EAAE,CAAA;QAClE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QACxD,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAA;QACzB,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAA;QAEjC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QAChD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;YACnD,OAAO,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QACnC,CAAC,CAAC,CAAA;QAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;QACrE,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,mBAAmB,CAAC,cAA2B;QACrD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QAC3E,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,WAAW,CAAC,0BAA0B,IAAI,cAAc,CAAC,CAAA;YACnE,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ApexMutation } from '../type/ApexMutation.js';
|
|
2
|
+
export interface MutationGroup {
|
|
3
|
+
mutations: ApexMutation[];
|
|
4
|
+
testMethods: Set<string>;
|
|
5
|
+
}
|
|
6
|
+
export interface GroupingResult {
|
|
7
|
+
groups: MutationGroup[];
|
|
8
|
+
lowerBound: number;
|
|
9
|
+
}
|
|
10
|
+
interface GroupingInternals {
|
|
11
|
+
adjacency: number[][];
|
|
12
|
+
witness: number[];
|
|
13
|
+
coloring: number[];
|
|
14
|
+
tests: ReadonlyArray<Set<string>>;
|
|
15
|
+
}
|
|
16
|
+
type GroupingResultWithInternals = GroupingResult & {
|
|
17
|
+
internals: GroupingInternals;
|
|
18
|
+
};
|
|
19
|
+
export declare const groupMutations: (mutations: ReadonlyArray<ApexMutation>, testMethodsPerLine: Map<number, Set<string>>) => GroupingResult;
|
|
20
|
+
export declare const groupMutationsWithInternals: (mutations: ReadonlyArray<ApexMutation>, testMethodsPerLine: Map<number, Set<string>>) => GroupingResultWithInternals;
|
|
21
|
+
export declare const assembleGroups: (mutations: ReadonlyArray<ApexMutation>, tests: ReadonlyArray<Set<string>>, color: ReadonlyArray<number>) => MutationGroup[];
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { buildAdjacency } from './exactColoring.js';
|
|
2
|
+
// Partition mutations into the smallest number of conflict-free groups using
|
|
3
|
+
// DSATUR (Brélaz, 1979): the strongest polynomial-time graph-coloring
|
|
4
|
+
// heuristic. At each step, color the uncolored vertex whose **saturation**
|
|
5
|
+
// (count of distinct colors already used by its colored neighbors) is highest;
|
|
6
|
+
// tiebreak on raw degree, then input order. Provably optimal on bipartite
|
|
7
|
+
// graphs and several other structured classes; near-optimal on the rest.
|
|
8
|
+
//
|
|
9
|
+
// Each color = one batched deployment + one batched test run. Two mutations
|
|
10
|
+
// share a color iff their covering tests are pairwise disjoint, so test
|
|
11
|
+
// outcomes can be reverse-mapped per mutation without ambiguity.
|
|
12
|
+
//
|
|
13
|
+
// The conflict graph is the intersection graph of per-mutation test sets:
|
|
14
|
+
// every test method T induces a clique among the mutations it covers. The
|
|
15
|
+
// largest such test-induced set is a free lower bound on the chromatic
|
|
16
|
+
// number; pre-coloring it before DSATUR runs both gives the heuristic a
|
|
17
|
+
// maximally-constrained start and surfaces an optimality certificate
|
|
18
|
+
// (groups.length === lowerBound implies provably optimal).
|
|
19
|
+
export const groupMutations = (mutations, testMethodsPerLine) => {
|
|
20
|
+
const { groups, lowerBound } = groupMutationsWithInternals(mutations, testMethodsPerLine);
|
|
21
|
+
return { groups, lowerBound };
|
|
22
|
+
};
|
|
23
|
+
// Like `groupMutations` but additionally exposes the conflict graph, witness
|
|
24
|
+
// clique, DSATUR coloring, and per-mutation test sets. Used by the optional
|
|
25
|
+
// SAT-based exact-coloring path so it can re-use the work without rebuilding
|
|
26
|
+
// the graph.
|
|
27
|
+
export const groupMutationsWithInternals = (mutations, testMethodsPerLine) => {
|
|
28
|
+
const n = mutations.length;
|
|
29
|
+
if (n === 0) {
|
|
30
|
+
return {
|
|
31
|
+
groups: [],
|
|
32
|
+
lowerBound: 0,
|
|
33
|
+
internals: { adjacency: [], witness: [], coloring: [], tests: [] },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const tests = mutations.map(m => testMethodsPerLine.get(m.target.startToken.line) ?? new Set());
|
|
37
|
+
const adjacency = buildAdjacency(tests);
|
|
38
|
+
const degree = adjacency.map(neighbors => neighbors.length);
|
|
39
|
+
const witness = computeLowerBoundClique(tests);
|
|
40
|
+
const color = new Array(n).fill(-1);
|
|
41
|
+
const saturation = new Array(n).fill(0);
|
|
42
|
+
const neighborColors = Array.from({ length: n }, () => new Set());
|
|
43
|
+
for (let k = 0; k < witness.length; ++k) {
|
|
44
|
+
const v = witness[k];
|
|
45
|
+
color[v] = k;
|
|
46
|
+
propagate(v, k, adjacency, color, neighborColors, saturation);
|
|
47
|
+
}
|
|
48
|
+
for (let step = 0; step < n - witness.length; ++step) {
|
|
49
|
+
const pick = pickNextVertex(color, saturation, degree);
|
|
50
|
+
const chosenColor = pickSmallestAvailableColor(neighborColors[pick]);
|
|
51
|
+
color[pick] = chosenColor;
|
|
52
|
+
propagate(pick, chosenColor, adjacency, color, neighborColors, saturation);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
groups: assembleGroups(mutations, tests, color),
|
|
56
|
+
lowerBound: witness.length,
|
|
57
|
+
internals: { adjacency, witness, coloring: color, tests },
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
// Returns the indices of the largest test-induced clique. Each test method T
|
|
61
|
+
// induces a clique among {m : T ∈ tests(m)}; we pick the largest such bucket.
|
|
62
|
+
// O(n · k) where k = avg tests per mutation. Indexes by mutation (not by
|
|
63
|
+
// line) so two mutations sharing the same Set reference still produce two
|
|
64
|
+
// distinct witness entries.
|
|
65
|
+
const computeLowerBoundClique = (tests) => {
|
|
66
|
+
const testToMutations = new Map();
|
|
67
|
+
for (let i = 0; i < tests.length; ++i) {
|
|
68
|
+
for (const t of tests[i]) {
|
|
69
|
+
const bucket = testToMutations.get(t);
|
|
70
|
+
if (bucket === undefined)
|
|
71
|
+
testToMutations.set(t, [i]);
|
|
72
|
+
else
|
|
73
|
+
bucket.push(i);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
let best = [];
|
|
77
|
+
for (const indices of testToMutations.values()) {
|
|
78
|
+
if (indices.length > best.length)
|
|
79
|
+
best = indices;
|
|
80
|
+
}
|
|
81
|
+
// Stable canonical order: ascending by mutation index. Combined with the
|
|
82
|
+
// strict-`>` tiebreak in pickNextVertex, makes the entire pipeline
|
|
83
|
+
// deterministic for fixed input.
|
|
84
|
+
return best.slice().sort((a, b) => a - b);
|
|
85
|
+
};
|
|
86
|
+
const propagate = (v, c, adjacency, color, neighborColors, saturation) => {
|
|
87
|
+
for (const neighbor of adjacency[v]) {
|
|
88
|
+
if (color[neighbor] === -1 && !neighborColors[neighbor].has(c)) {
|
|
89
|
+
neighborColors[neighbor].add(c);
|
|
90
|
+
++saturation[neighbor];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
// Strict `>` comparisons mean equal-key candidates retain the first-encountered
|
|
95
|
+
// pick — which is the lowest unprocessed index. Switching to `>=` would
|
|
96
|
+
// silently invert determinism on every tied pair; keep the contract.
|
|
97
|
+
const pickNextVertex = (color, saturation, degree) => {
|
|
98
|
+
let pick = -1;
|
|
99
|
+
for (let i = 0; i < color.length; ++i) {
|
|
100
|
+
if (color[i] !== -1)
|
|
101
|
+
continue;
|
|
102
|
+
if (pick === -1 ||
|
|
103
|
+
saturation[i] > saturation[pick] ||
|
|
104
|
+
(saturation[i] === saturation[pick] && degree[i] > degree[pick])) {
|
|
105
|
+
pick = i;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return pick;
|
|
109
|
+
};
|
|
110
|
+
const pickSmallestAvailableColor = (neighborColors) => {
|
|
111
|
+
let candidate = 0;
|
|
112
|
+
while (neighborColors.has(candidate)) {
|
|
113
|
+
++candidate;
|
|
114
|
+
}
|
|
115
|
+
return candidate;
|
|
116
|
+
};
|
|
117
|
+
export const assembleGroups = (mutations, tests, color) => {
|
|
118
|
+
const groups = [];
|
|
119
|
+
for (let i = 0; i < mutations.length; ++i) {
|
|
120
|
+
const c = color[i];
|
|
121
|
+
while (groups.length <= c) {
|
|
122
|
+
groups.push({ mutations: [], testMethods: new Set() });
|
|
123
|
+
}
|
|
124
|
+
groups[c].mutations.push(mutations[i]);
|
|
125
|
+
for (const t of tests[i])
|
|
126
|
+
groups[c].testMethods.add(t);
|
|
127
|
+
}
|
|
128
|
+
return groups;
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=mutationGrouper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutationGrouper.js","sourceRoot":"","sources":["../../src/service/mutationGrouper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ApexMutation } from '../type/ApexMutation.js';
|
|
2
|
+
export declare const calculateMutationPosition: (mutation: ApexMutation) => {
|
|
3
|
+
start: {
|
|
4
|
+
line: number;
|
|
5
|
+
column: number;
|
|
6
|
+
};
|
|
7
|
+
end: {
|
|
8
|
+
line: number;
|
|
9
|
+
column: number;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare const extractMutationOriginalText: (mutation: ApexMutation, sourceContent: string) => string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Advance a 1-indexed (line, column) cursor through `text`, returning the
|
|
2
|
+
// position immediately AFTER the last character. Handles tokens whose text
|
|
3
|
+
// spans newlines (multi-line string literals, block comments).
|
|
4
|
+
//
|
|
5
|
+
// Used to compute the Stryker `end` position for a mutation: ANTLR tokens
|
|
6
|
+
// expose `line` and `charPositionInLine` for the START of the token but not
|
|
7
|
+
// past the end; walking `endToken.text` closes that gap without needing a
|
|
8
|
+
// separate line-offset index over the whole source.
|
|
9
|
+
const advancePosition = (text, startLine, startColumn) => {
|
|
10
|
+
let line = startLine;
|
|
11
|
+
let column = startColumn;
|
|
12
|
+
for (let i = 0; i < text.length; i++) {
|
|
13
|
+
if (text.charCodeAt(i) === 10 /* \n */) {
|
|
14
|
+
line++;
|
|
15
|
+
column = 1;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
column++;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { line, column };
|
|
22
|
+
};
|
|
23
|
+
export const calculateMutationPosition = (mutation) => {
|
|
24
|
+
const start = mutation.target.startToken;
|
|
25
|
+
const end = mutation.target.endToken;
|
|
26
|
+
if (start.startIndex === undefined ||
|
|
27
|
+
end.stopIndex === undefined ||
|
|
28
|
+
end.text === undefined) {
|
|
29
|
+
throw new Error(`Failed to calculate position for mutation: ${mutation.mutationName}`);
|
|
30
|
+
}
|
|
31
|
+
// ANTLR tokens expose the position of the FIRST character directly.
|
|
32
|
+
// The Stryker `end` position is exclusive (one past the last char), so
|
|
33
|
+
// we walk endToken.text to advance from the end token's own start.
|
|
34
|
+
// This correctly handles tokens that span newlines (multi-line string
|
|
35
|
+
// literals, block comments).
|
|
36
|
+
return {
|
|
37
|
+
start: {
|
|
38
|
+
line: start.line,
|
|
39
|
+
column: start.charPositionInLine + 1,
|
|
40
|
+
},
|
|
41
|
+
end: advancePosition(end.text, end.line, end.charPositionInLine + 1),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export const extractMutationOriginalText = (mutation, sourceContent) => {
|
|
45
|
+
const start = mutation.target.startToken;
|
|
46
|
+
const end = mutation.target.endToken;
|
|
47
|
+
if (start.startIndex !== undefined &&
|
|
48
|
+
end.stopIndex !== undefined &&
|
|
49
|
+
sourceContent) {
|
|
50
|
+
return sourceContent.substring(start.startIndex, end.stopIndex + 1);
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`Failed to extract original text for mutation: ${mutation.mutationName}`);
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=mutationLocation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutationLocation.js","sourceRoot":"","sources":["../../src/service/mutationLocation.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,2EAA2E;AAC3E,+DAA+D;AAC/D,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,0EAA0E;AAC1E,oDAAoD;AACpD,MAAM,eAAe,GAAG,CACtB,IAAY,EACZ,SAAiB,EACjB,WAAmB,EACe,EAAE;IACpC,IAAI,IAAI,GAAG,SAAS,CAAA;IACpB,IAAI,MAAM,GAAG,WAAW,CAAA;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,EAAE,CAAA;YACN,MAAM,GAAG,CAAC,CAAA;QACZ,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,CAAA;QACV,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,QAAsB,EAItB,EAAE;IACF,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAA;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAA;IAEpC,IACE,KAAK,CAAC,UAAU,KAAK,SAAS;QAC9B,GAAG,CAAC,SAAS,KAAK,SAAS;QAC3B,GAAG,CAAC,IAAI,KAAK,SAAS,EACtB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,8CAA8C,QAAQ,CAAC,YAAY,EAAE,CACtE,CAAA;IACH,CAAC;IAED,oEAAoE;IACpE,uEAAuE;IACvE,mEAAmE;IACnE,sEAAsE;IACtE,6BAA6B;IAC7B,OAAO;QACL,KAAK,EAAE;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,kBAAkB,GAAG,CAAC;SACrC;QACD,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,kBAAkB,GAAG,CAAC,CAAC;KACrE,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,QAAsB,EACtB,aAAqB,EACb,EAAE;IACV,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAA;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAA;IAEpC,IACE,KAAK,CAAC,UAAU,KAAK,SAAS;QAC9B,GAAG,CAAC,SAAS,KAAK,SAAS;QAC3B,aAAa,EACb,CAAC;QACD,OAAO,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;IACrE,CAAC;IAED,MAAM,IAAI,KAAK,CACb,iDAAiD,QAAQ,CAAC,YAAY,EAAE,CACzE,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -16,12 +16,12 @@ export declare class MutationTestingService {
|
|
|
16
16
|
protected readonly excludeTestMethods: string[] | undefined;
|
|
17
17
|
private readonly skipPatterns;
|
|
18
18
|
private readonly allowedLines;
|
|
19
|
+
private readonly mutationGroupingEnabled;
|
|
19
20
|
private apexClassContent;
|
|
20
|
-
constructor(progress: Progress, spinner: Spinner, connection: Connection, { apexClassName, apexTestClassName, dryRun, includeMutators, excludeMutators, includeTestMethods, excludeTestMethods, skipPatterns, lines, }: ApexMutationParameter, messages: Messages<string>);
|
|
21
|
+
constructor(progress: Progress, spinner: Spinner, connection: Connection, { apexClassName, apexTestClassName, dryRun, includeMutators, excludeMutators, includeTestMethods, excludeTestMethods, skipPatterns, lines, mutationGrouping, }: ApexMutationParameter, messages: Messages<string>);
|
|
21
22
|
process(): Promise<ApexMutationTestResult>;
|
|
23
|
+
private planGroups;
|
|
22
24
|
calculateScore(mutationResult: ApexMutationTestResult): number;
|
|
23
|
-
private buildMutantResult;
|
|
24
|
-
private calculateMutationPosition;
|
|
25
25
|
private filterTestMethods;
|
|
26
26
|
private createAdapters;
|
|
27
27
|
private fetchApexClass;
|
|
@@ -35,8 +35,5 @@ export declare class MutationTestingService {
|
|
|
35
35
|
private displayTimeEstimate;
|
|
36
36
|
private buildDryRunResult;
|
|
37
37
|
private executeMutationLoop;
|
|
38
|
-
private evaluateMutation;
|
|
39
|
-
private formatRemainingTime;
|
|
40
38
|
private rollback;
|
|
41
|
-
private extractMutationOriginalText;
|
|
42
39
|
}
|
|
@@ -2,59 +2,14 @@ import { ApexClassRepository } from '../adapter/apexClassRepository.js';
|
|
|
2
2
|
import { ApexTestRunner } from '../adapter/apexTestRunner.js';
|
|
3
3
|
import { SObjectDescribeRepository } from '../adapter/sObjectDescribeRepository.js';
|
|
4
4
|
import { ConfigReader } from './configReader.js';
|
|
5
|
+
import { decideExactOutcome, solveColoring } from './exactColoring.js';
|
|
6
|
+
import { GroupExecutor } from './groupExecutor.js';
|
|
5
7
|
import { MutantGenerator } from './mutantGenerator.js';
|
|
8
|
+
import { assembleGroups, groupMutationsWithInternals, } from './mutationGrouper.js';
|
|
9
|
+
import { calculateMutationPosition, extractMutationOriginalText, } from './mutationLocation.js';
|
|
6
10
|
import { formatDuration, timeExecution } from './timeUtils.js';
|
|
7
11
|
import { TypeDiscoverer } from './typeDiscoverer.js';
|
|
8
12
|
import { ApexClassTypeMatcher, SObjectTypeMatcher } from './typeMatcher.js';
|
|
9
|
-
/**
|
|
10
|
-
* Advance a 1-indexed (line, column) cursor through `text`, returning the
|
|
11
|
-
* position immediately AFTER the last character. Handles tokens whose text
|
|
12
|
-
* spans newlines (multi-line string literals, block comments).
|
|
13
|
-
*
|
|
14
|
-
* Used to compute the Stryker `end` position for a mutation: ANTLR tokens
|
|
15
|
-
* expose `line` and `charPositionInLine` for the START of the token but not
|
|
16
|
-
* past the end; walking `endToken.text` closes that gap without needing a
|
|
17
|
-
* separate line-offset index over the whole source.
|
|
18
|
-
*/
|
|
19
|
-
function advancePosition(text, startLine, startColumn) {
|
|
20
|
-
let line = startLine;
|
|
21
|
-
let column = startColumn;
|
|
22
|
-
for (let i = 0; i < text.length; i++) {
|
|
23
|
-
if (text.charCodeAt(i) === 10 /* \n */) {
|
|
24
|
-
line++;
|
|
25
|
-
column = 1;
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
column++;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return { line, column };
|
|
32
|
-
}
|
|
33
|
-
const errorStrategies = [
|
|
34
|
-
{
|
|
35
|
-
matches: msg => msg.startsWith('Deployment failed:'),
|
|
36
|
-
classify: (msg, targetInfo) => ({
|
|
37
|
-
status: 'CompileError',
|
|
38
|
-
statusReason: msg,
|
|
39
|
-
progressMessage: `Mutation result: compile error at line ${targetInfo.line}`,
|
|
40
|
-
}),
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
matches: msg => msg.includes('LIMIT_USAGE_FOR_NS'),
|
|
44
|
-
classify: msg => ({
|
|
45
|
-
status: 'Killed',
|
|
46
|
-
progressMessage: `Mutation result: mutant killed (${msg})`,
|
|
47
|
-
}),
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
matches: () => true,
|
|
51
|
-
classify: msg => ({
|
|
52
|
-
status: 'RuntimeError',
|
|
53
|
-
statusReason: msg,
|
|
54
|
-
progressMessage: `Mutation result: runtime error (${msg})`,
|
|
55
|
-
}),
|
|
56
|
-
},
|
|
57
|
-
];
|
|
58
13
|
export class MutationTestingService {
|
|
59
14
|
progress;
|
|
60
15
|
spinner;
|
|
@@ -69,8 +24,9 @@ export class MutationTestingService {
|
|
|
69
24
|
excludeTestMethods;
|
|
70
25
|
skipPatterns;
|
|
71
26
|
allowedLines;
|
|
27
|
+
mutationGroupingEnabled;
|
|
72
28
|
apexClassContent = '';
|
|
73
|
-
constructor(progress, spinner, connection, { apexClassName, apexTestClassName, dryRun, includeMutators, excludeMutators, includeTestMethods, excludeTestMethods, skipPatterns, lines, }, messages) {
|
|
29
|
+
constructor(progress, spinner, connection, { apexClassName, apexTestClassName, dryRun, includeMutators, excludeMutators, includeTestMethods, excludeTestMethods, skipPatterns, lines, mutationGrouping, }, messages) {
|
|
74
30
|
this.progress = progress;
|
|
75
31
|
this.spinner = spinner;
|
|
76
32
|
this.connection = connection;
|
|
@@ -84,6 +40,7 @@ export class MutationTestingService {
|
|
|
84
40
|
this.excludeTestMethods = excludeTestMethods;
|
|
85
41
|
this.skipPatterns = ConfigReader.compileSkipPatterns(skipPatterns);
|
|
86
42
|
this.allowedLines = ConfigReader.parseLineRanges(lines);
|
|
43
|
+
this.mutationGroupingEnabled = mutationGrouping ?? false;
|
|
87
44
|
}
|
|
88
45
|
async process() {
|
|
89
46
|
const { apexClassRepository, apexTestRunner } = this.createAdapters();
|
|
@@ -94,14 +51,55 @@ export class MutationTestingService {
|
|
|
94
51
|
const { testMethodsPerLine, testTime } = await this.runBaselineTests(apexTestRunner);
|
|
95
52
|
const coveredLines = this.extractCoveredLines(testMethodsPerLine);
|
|
96
53
|
const { mutations, mutantGenerator, tokenStream } = this.generateMutations(apexClass, coveredLines, typeAnalysis);
|
|
97
|
-
this.displayTimeEstimate(deployTime, testTime, mutations.length);
|
|
98
54
|
if (this.dryRun) {
|
|
55
|
+
this.displayTimeEstimate(deployTime, testTime, mutations.length, mutations.length);
|
|
99
56
|
return this.buildDryRunResult(apexClass, mutations);
|
|
100
57
|
}
|
|
101
|
-
const
|
|
58
|
+
const groups = await this.planGroups(mutations, testMethodsPerLine);
|
|
59
|
+
this.displayTimeEstimate(deployTime, testTime, mutations.length, groups.length);
|
|
60
|
+
const result = await this.executeMutationLoop(apexClass, mutations, groups, mutantGenerator, tokenStream, testMethodsPerLine, apexTestRunner, apexClassRepository);
|
|
102
61
|
await this.rollback(apexClass, apexClassRepository);
|
|
103
62
|
return result;
|
|
104
63
|
}
|
|
64
|
+
async planGroups(mutations, testMethodsPerLine) {
|
|
65
|
+
if (!this.mutationGroupingEnabled) {
|
|
66
|
+
// No grouping: one mutation per group. Inlined here rather than going
|
|
67
|
+
// through groupMutations to avoid building the conflict graph for the
|
|
68
|
+
// common (default-off) case.
|
|
69
|
+
return mutations.map(m => ({
|
|
70
|
+
mutations: [m],
|
|
71
|
+
// extractCoveredLines guarantees the line is in the map.
|
|
72
|
+
testMethods: testMethodsPerLine.get(m.target.startToken.line),
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
this.spinner.start(`Grouping ${mutations.length} mutations to minimize deployments`, undefined, { stdout: true });
|
|
76
|
+
const { groups: dsaturGroups, lowerBound, internals, } = groupMutationsWithInternals(mutations, testMethodsPerLine);
|
|
77
|
+
let groups = dsaturGroups;
|
|
78
|
+
const exact = solveColoring({
|
|
79
|
+
adjacency: internals.adjacency,
|
|
80
|
+
n: mutations.length,
|
|
81
|
+
lowerBound,
|
|
82
|
+
dsaturColors: dsaturGroups.length,
|
|
83
|
+
witness: internals.witness,
|
|
84
|
+
dsaturColoring: internals.coloring,
|
|
85
|
+
});
|
|
86
|
+
const decision = decideExactOutcome(exact, dsaturGroups.length);
|
|
87
|
+
const exactSuffix = decision.suffix;
|
|
88
|
+
if (decision.useGroups === 'exact') {
|
|
89
|
+
groups = assembleGroups(mutations, internals.tests, exact.coloring);
|
|
90
|
+
}
|
|
91
|
+
// Division is safe: generateMutations throws when mutations is empty,
|
|
92
|
+
// so planGroups is never reached with mutations.length === 0.
|
|
93
|
+
const savingsPct = Math.round((1 - groups.length / mutations.length) * 100);
|
|
94
|
+
this.spinner.stop(this.messages.getMessage('info.groupingPlan', [
|
|
95
|
+
String(mutations.length),
|
|
96
|
+
String(groups.length),
|
|
97
|
+
String(savingsPct),
|
|
98
|
+
String(lowerBound),
|
|
99
|
+
exactSuffix,
|
|
100
|
+
]));
|
|
101
|
+
return groups;
|
|
102
|
+
}
|
|
105
103
|
calculateScore(mutationResult) {
|
|
106
104
|
const validMutants = mutationResult.mutants.filter(mutant => mutant.status !== 'CompileError');
|
|
107
105
|
if (validMutants.length === 0) {
|
|
@@ -112,42 +110,6 @@ export class MutationTestingService {
|
|
|
112
110
|
validMutants.length) *
|
|
113
111
|
100);
|
|
114
112
|
}
|
|
115
|
-
buildMutantResult(mutation, testResult, targetInfo) {
|
|
116
|
-
const mutationStatus = testResult.summary.outcome === 'Passed' ? 'Survived' : 'Killed';
|
|
117
|
-
const location = this.calculateMutationPosition(mutation);
|
|
118
|
-
const originalText = this.extractMutationOriginalText(mutation);
|
|
119
|
-
return {
|
|
120
|
-
id: `${this.apexClassName}-${targetInfo.line}-${targetInfo.column}-${targetInfo.tokenIndex}-${Date.now()}`,
|
|
121
|
-
mutatorName: mutation.mutationName,
|
|
122
|
-
status: mutationStatus,
|
|
123
|
-
location,
|
|
124
|
-
replacement: mutation.replacement,
|
|
125
|
-
original: originalText,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
calculateMutationPosition(mutation) {
|
|
129
|
-
const start = mutation.target.startToken;
|
|
130
|
-
const end = mutation.target.endToken;
|
|
131
|
-
if (start.startIndex === undefined ||
|
|
132
|
-
end.stopIndex === undefined ||
|
|
133
|
-
end.text === undefined) {
|
|
134
|
-
throw new Error(`Failed to calculate position for mutation: ${mutation.mutationName}`);
|
|
135
|
-
}
|
|
136
|
-
// ANTLR tokens expose the position of the FIRST character directly.
|
|
137
|
-
// The Stryker `end` position is exclusive (one past the last char), so
|
|
138
|
-
// we walk endToken.text to advance from the end token's own start.
|
|
139
|
-
// This correctly handles tokens that span newlines (multi-line string
|
|
140
|
-
// literals, block comments).
|
|
141
|
-
return {
|
|
142
|
-
start: {
|
|
143
|
-
line: start.line,
|
|
144
|
-
column: start.charPositionInLine + 1,
|
|
145
|
-
},
|
|
146
|
-
// ANTLR tokens always expose `text`; treat an undefined text as a
|
|
147
|
-
// programmer error rather than silently swallowing with an empty default.
|
|
148
|
-
end: advancePosition(end.text, end.line, end.charPositionInLine + 1),
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
113
|
filterTestMethods(testMethodsPerLine) {
|
|
152
114
|
const filterSet = this.includeTestMethods
|
|
153
115
|
? new Set(this.includeTestMethods)
|
|
@@ -288,8 +250,8 @@ export class MutationTestingService {
|
|
|
288
250
|
return { exclude: this.excludeMutators };
|
|
289
251
|
return undefined;
|
|
290
252
|
}
|
|
291
|
-
displayTimeEstimate(deployTime, testTime, mutationCount) {
|
|
292
|
-
const totalEstimateMs = (deployTime + testTime) *
|
|
253
|
+
displayTimeEstimate(deployTime, testTime, mutationCount, groupCount) {
|
|
254
|
+
const totalEstimateMs = (deployTime + testTime) * groupCount;
|
|
293
255
|
this.spinner.start(this.messages.getMessage('info.timeEstimate', [
|
|
294
256
|
formatDuration(totalEstimateMs),
|
|
295
257
|
]), undefined, { stdout: true });
|
|
@@ -297,6 +259,7 @@ export class MutationTestingService {
|
|
|
297
259
|
formatDuration(deployTime),
|
|
298
260
|
formatDuration(testTime),
|
|
299
261
|
String(mutationCount),
|
|
262
|
+
String(groupCount),
|
|
300
263
|
]));
|
|
301
264
|
}
|
|
302
265
|
buildDryRunResult(apexClass, mutations) {
|
|
@@ -308,96 +271,37 @@ export class MutationTestingService {
|
|
|
308
271
|
id: `${this.apexClassName}-${mutation.target.startToken.line}-${mutation.target.startToken.charPositionInLine}-${mutation.target.startToken.tokenIndex}-${Date.now()}`,
|
|
309
272
|
mutatorName: mutation.mutationName,
|
|
310
273
|
status: 'Pending',
|
|
311
|
-
location:
|
|
274
|
+
location: calculateMutationPosition(mutation),
|
|
312
275
|
replacement: mutation.replacement,
|
|
313
|
-
original:
|
|
276
|
+
original: extractMutationOriginalText(mutation, this.apexClassContent),
|
|
314
277
|
})),
|
|
315
278
|
};
|
|
316
279
|
}
|
|
317
|
-
async executeMutationLoop(apexClass, mutations, mutantGenerator, tokenStream, testMethodsPerLine, apexTestRunner, apexClassRepository) {
|
|
318
|
-
const mutationResults = {
|
|
319
|
-
sourceFile: this.apexClassName,
|
|
320
|
-
sourceFileContent: apexClass.Body,
|
|
321
|
-
testFile: this.apexTestClassName,
|
|
322
|
-
mutants: [],
|
|
323
|
-
};
|
|
280
|
+
async executeMutationLoop(apexClass, mutations, groups, mutantGenerator, tokenStream, testMethodsPerLine, apexTestRunner, apexClassRepository) {
|
|
324
281
|
this.progress.start(mutations.length, { info: 'Starting mutation testing' }, {
|
|
325
282
|
title: 'MUTATION TESTING PROGRESS',
|
|
326
283
|
format: '%s | {bar} | {value}/{total} {info}',
|
|
327
284
|
});
|
|
328
|
-
|
|
285
|
+
const executor = new GroupExecutor(apexClass, this.apexClassName, this.apexTestClassName, this.apexClassContent, tokenStream, testMethodsPerLine, mutantGenerator, apexTestRunner, apexClassRepository, this.progress, this.messages);
|
|
286
|
+
const indexByMutation = new Map(mutations.map((m, i) => [m, i]));
|
|
287
|
+
const orderedResults = new Array(mutations.length).fill(null);
|
|
288
|
+
let completed = 0;
|
|
329
289
|
const loopStartTime = performance.now();
|
|
330
|
-
for (const
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const testMethods = testMethodsPerLine.get(mutation.target.startToken.line);
|
|
336
|
-
if (testMethods) {
|
|
337
|
-
this.progress.update(mutationCount, {
|
|
338
|
-
info: `${remainingText}Running ${testMethods.size} tests methods for "${mutation.replacement}" mutation at line ${mutation.target.startToken.line}`,
|
|
339
|
-
});
|
|
290
|
+
for (const group of groups) {
|
|
291
|
+
const mutantResults = await executor.evaluate(group, completed, loopStartTime, mutations.length);
|
|
292
|
+
for (let i = 0; i < group.mutations.length; ++i) {
|
|
293
|
+
const idx = indexByMutation.get(group.mutations[i]);
|
|
294
|
+
orderedResults[idx] = mutantResults[i];
|
|
340
295
|
}
|
|
341
|
-
|
|
342
|
-
mutationResults.mutants.push(mutantResult);
|
|
343
|
-
++mutationCount;
|
|
344
|
-
const updatedRemainingText = this.formatRemainingTime(loopStartTime, mutationCount, mutations.length);
|
|
345
|
-
this.progress.update(mutationCount, {
|
|
346
|
-
info: `${updatedRemainingText}${progressMessage}`,
|
|
347
|
-
});
|
|
296
|
+
completed += group.mutations.length;
|
|
348
297
|
}
|
|
349
298
|
this.progress.finish({ info: 'All mutations evaluated' });
|
|
350
|
-
return
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
line: mutation.target.startToken.line,
|
|
356
|
-
column: mutation.target.startToken.charPositionInLine,
|
|
357
|
-
tokenIndex: mutation.target.startToken.tokenIndex,
|
|
358
|
-
text: mutation.target.text,
|
|
299
|
+
return {
|
|
300
|
+
sourceFile: this.apexClassName,
|
|
301
|
+
sourceFileContent: apexClass.Body,
|
|
302
|
+
testFile: this.apexTestClassName,
|
|
303
|
+
mutants: orderedResults.filter((r) => r !== null),
|
|
359
304
|
};
|
|
360
|
-
try {
|
|
361
|
-
await apexClassRepository.update({
|
|
362
|
-
Id: apexClass.Id,
|
|
363
|
-
Body: mutatedVersion,
|
|
364
|
-
});
|
|
365
|
-
const testMethods = testMethodsPerLine.get(targetInfo.line);
|
|
366
|
-
const testResult = await apexTestRunner.runTestMethods(this.apexTestClassName, testMethods);
|
|
367
|
-
return {
|
|
368
|
-
mutantResult: this.buildMutantResult(mutation, testResult, targetInfo),
|
|
369
|
-
progressMessage: `Mutation result: ${testResult.summary.outcome === 'Passed' ? 'zombie' : 'mutant killed'}`,
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
374
|
-
const location = this.calculateMutationPosition(mutation);
|
|
375
|
-
const originalText = this.extractMutationOriginalText(mutation);
|
|
376
|
-
const strategy = errorStrategies.find(s => s.matches(errorMessage));
|
|
377
|
-
const classification = strategy.classify(errorMessage, targetInfo);
|
|
378
|
-
return {
|
|
379
|
-
mutantResult: {
|
|
380
|
-
id: `${this.apexClassName}-${targetInfo.line}-${targetInfo.column}-${targetInfo.tokenIndex}-${Date.now()}`,
|
|
381
|
-
mutatorName: mutation.mutationName,
|
|
382
|
-
status: classification.status,
|
|
383
|
-
...(classification.statusReason && {
|
|
384
|
-
statusReason: classification.statusReason,
|
|
385
|
-
}),
|
|
386
|
-
location,
|
|
387
|
-
replacement: mutation.replacement,
|
|
388
|
-
original: originalText,
|
|
389
|
-
},
|
|
390
|
-
progressMessage: classification.progressMessage,
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
formatRemainingTime(loopStartTime, completedCount, totalCount) {
|
|
395
|
-
if (completedCount === 0)
|
|
396
|
-
return '';
|
|
397
|
-
const elapsed = performance.now() - loopStartTime;
|
|
398
|
-
const avgPerMutant = elapsed / completedCount;
|
|
399
|
-
const remainingMs = avgPerMutant * (totalCount - completedCount);
|
|
400
|
-
return `Remaining: ${formatDuration(remainingMs)} | `;
|
|
401
305
|
}
|
|
402
306
|
async rollback(apexClass, apexClassRepository) {
|
|
403
307
|
this.spinner.start(`Rolling back "${this.apexClassName}" ApexClass to its original state`, undefined, { stdout: true });
|
|
@@ -411,15 +315,5 @@ export class MutationTestingService {
|
|
|
411
315
|
throw new Error(`Rollback of '${this.apexClassName}' failed. The class on the target org is still in a mutated state. Redeploy manually. Underlying cause: ${cause}`);
|
|
412
316
|
}
|
|
413
317
|
}
|
|
414
|
-
extractMutationOriginalText(mutation) {
|
|
415
|
-
const start = mutation.target.startToken;
|
|
416
|
-
const end = mutation.target.endToken;
|
|
417
|
-
if (start.startIndex !== undefined &&
|
|
418
|
-
end.stopIndex !== undefined &&
|
|
419
|
-
this.apexClassContent) {
|
|
420
|
-
return this.apexClassContent.substring(start.startIndex, end.stopIndex + 1);
|
|
421
|
-
}
|
|
422
|
-
throw new Error(`Failed to extract original text for mutation: ${mutation.mutationName}`);
|
|
423
|
-
}
|
|
424
318
|
}
|
|
425
319
|
//# sourceMappingURL=mutationTestingService.js.map
|