apex-mutation-testing 1.1.0 → 1.2.0-dev-53.17212276159-1

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.
Files changed (65) hide show
  1. package/README.md +3 -2
  2. package/lib/adapter/apexClassRepository.d.ts +5 -1
  3. package/lib/adapter/apexClassRepository.js +23 -1
  4. package/lib/adapter/apexClassRepository.js.map +1 -1
  5. package/lib/adapter/apexTestRunner.d.ts +7 -2
  6. package/lib/adapter/apexTestRunner.js +28 -7
  7. package/lib/adapter/apexTestRunner.js.map +1 -1
  8. package/lib/mutator/arithmeticOperatorMutator.d.ts +9 -0
  9. package/lib/mutator/arithmeticOperatorMutator.js +36 -0
  10. package/lib/mutator/arithmeticOperatorMutator.js.map +1 -0
  11. package/lib/mutator/baseListener.d.ts +5 -0
  12. package/lib/mutator/baseListener.js +21 -0
  13. package/lib/mutator/baseListener.js.map +1 -1
  14. package/lib/mutator/boundaryConditionMutator.d.ts +3 -3
  15. package/lib/mutator/boundaryConditionMutator.js +21 -19
  16. package/lib/mutator/boundaryConditionMutator.js.map +1 -1
  17. package/lib/mutator/emptyReturnMutator.d.ts +7 -0
  18. package/lib/mutator/emptyReturnMutator.js +94 -0
  19. package/lib/mutator/emptyReturnMutator.js.map +1 -0
  20. package/lib/mutator/equalityConditionMutator.d.ts +6 -0
  21. package/lib/mutator/equalityConditionMutator.js +25 -0
  22. package/lib/mutator/equalityConditionMutator.js.map +1 -0
  23. package/lib/mutator/falseReturnMutator.d.ts +5 -0
  24. package/lib/mutator/falseReturnMutator.js +29 -0
  25. package/lib/mutator/falseReturnMutator.js.map +1 -0
  26. package/lib/mutator/incrementMutator.d.ts +1 -1
  27. package/lib/mutator/incrementMutator.js +6 -10
  28. package/lib/mutator/incrementMutator.js.map +1 -1
  29. package/lib/mutator/methodTypeListener.d.ts +12 -0
  30. package/lib/mutator/methodTypeListener.js +114 -0
  31. package/lib/mutator/methodTypeListener.js.map +1 -0
  32. package/lib/mutator/mutationListener.d.ts +4 -2
  33. package/lib/mutator/mutationListener.js +11 -1
  34. package/lib/mutator/mutationListener.js.map +1 -1
  35. package/lib/mutator/nullReturnMutator.d.ts +5 -0
  36. package/lib/mutator/nullReturnMutator.js +26 -0
  37. package/lib/mutator/nullReturnMutator.js.map +1 -0
  38. package/lib/mutator/returnTypeAwareBaseListener.d.ts +12 -0
  39. package/lib/mutator/returnTypeAwareBaseListener.js +24 -0
  40. package/lib/mutator/returnTypeAwareBaseListener.js.map +1 -0
  41. package/lib/mutator/trueReturnMutator.d.ts +5 -0
  42. package/lib/mutator/trueReturnMutator.js +29 -0
  43. package/lib/mutator/trueReturnMutator.js.map +1 -0
  44. package/lib/reporter/HTMLReporter.js +1 -1
  45. package/lib/reporter/HTMLReporter.js.map +1 -1
  46. package/lib/service/apexTypeResolver.d.ts +9 -0
  47. package/lib/service/apexTypeResolver.js +18 -0
  48. package/lib/service/apexTypeResolver.js.map +1 -0
  49. package/lib/service/mutantGenerator.d.ts +4 -1
  50. package/lib/service/mutantGenerator.js +30 -6
  51. package/lib/service/mutantGenerator.js.map +1 -1
  52. package/lib/service/mutationTestingService.d.ts +4 -0
  53. package/lib/service/mutationTestingService.js +105 -26
  54. package/lib/service/mutationTestingService.js.map +1 -1
  55. package/lib/type/ApexMethod.d.ts +29 -0
  56. package/lib/type/ApexMethod.js +24 -0
  57. package/lib/type/ApexMethod.js.map +1 -0
  58. package/lib/type/ApexMutation.d.ts +7 -2
  59. package/lib/type/MetadataComponentDependency.d.ts +6 -0
  60. package/lib/type/MetadataComponentDependency.js +2 -0
  61. package/lib/type/MetadataComponentDependency.js.map +1 -0
  62. package/messages/apex.mutation.test.run.md +1 -1
  63. package/npm-shrinkwrap.json +3992 -3112
  64. package/oclif.manifest.json +2 -2
  65. package/package.json +22 -21
package/README.md CHANGED
@@ -16,7 +16,7 @@ sf plugins install apex-mutation-testing
16
16
  ```
17
17
 
18
18
  ```sh
19
- sf apex mutation test run --class-file MyClass --test-file MyClassTest
19
+ sf apex mutation test run --apex-class MyClass --test-class MyClassTest
20
20
  ```
21
21
 
22
22
  ## What is it mutation testing ?
@@ -104,7 +104,7 @@ DESCRIPTION
104
104
  EXAMPLES
105
105
  Run mutation testing on a class with its test file:
106
106
 
107
- $ sf apex mutation test run --class-file MyClass --test-file MyClassTest
107
+ $ sf apex mutation test run --apex-class MyClass --test-class MyClassTest
108
108
  ```
109
109
  <!-- commandsstop -->
110
110
 
@@ -128,6 +128,7 @@ Versioning follows [SemVer](http://semver.org/) specification.
128
128
  ## Authors
129
129
 
130
130
  - **Sebastien Colladon** - Developer - [scolladon](https://github.com/scolladon)
131
+ - **Saman Attar** - Developer - [saman](https://github.com/SamanAttar)
131
132
 
132
133
  Special thanks to **Sara Sali** for her [presentation at Dreamforce](https://www.youtube.com/watch?v=8PjzrTaNNns) about apex mutation testing
133
134
  This repository is basically a port of her idea / repo to a sf plugin.
@@ -1,10 +1,14 @@
1
1
  import { Connection } from '@salesforce/core';
2
2
  import { ApexClass } from '../type/ApexClass.js';
3
+ import { MetadataComponentDependency } from '../type/MetadataComponentDependency.js';
3
4
  export declare class ApexClassRepository {
4
5
  protected readonly connection: Connection;
5
6
  constructor(connection: Connection);
6
7
  read(name: string): Promise<{
7
8
  [name: string]: import("@jsforce/jsforce-node").SObjectFieldType | null;
8
9
  } & import("@jsforce/jsforce-node").Record>;
9
- update(apexClass: ApexClass): Promise<import("@jsforce/jsforce-node").SaveResult>;
10
+ getApexClassDependencies(classId: string): Promise<MetadataComponentDependency[]>;
11
+ update(apexClass: ApexClass): Promise<{
12
+ [name: string]: import("@jsforce/jsforce-node").SObjectFieldType | null;
13
+ } & import("@jsforce/jsforce-node").Record>;
10
14
  }
@@ -9,6 +9,12 @@ export class ApexClassRepository {
9
9
  .find({ Name: name })
10
10
  .execute())[0];
11
11
  }
12
+ async getApexClassDependencies(classId) {
13
+ return (await this.connection.tooling
14
+ .sobject('MetadataComponentDependency')
15
+ .find({ MetadataComponentId: classId })
16
+ .execute());
17
+ }
12
18
  async update(apexClass) {
13
19
  const container = await this.connection.tooling
14
20
  .sobject('MetadataContainer')
@@ -22,13 +28,29 @@ export class ApexClassRepository {
22
28
  Body: apexClass.Body,
23
29
  });
24
30
  // Create ContainerAsyncRequest to deploy
25
- return await this.connection.tooling
31
+ const asyncRequest = await this.connection.tooling
26
32
  .sobject('ContainerAsyncRequest')
27
33
  .create({
28
34
  IsCheckOnly: false,
29
35
  MetadataContainerId: container.id,
30
36
  IsRunTests: true,
31
37
  });
38
+ if (!asyncRequest.id) {
39
+ throw new Error('ContainerAsyncRequest did not return an ID');
40
+ }
41
+ const result = await this.connection.tooling
42
+ .sobject('ContainerAsyncRequest')
43
+ .retrieve(asyncRequest.id);
44
+ if (result['State'] === 'Failed') {
45
+ const messages = result['DeployDetails']?.['allComponentMessages'];
46
+ const formattedErrors = Array.isArray(messages)
47
+ ? messages
48
+ .map(m => `[${m.fileName}:${m.lineNumber}:${m.columnNumber}] ${m.problem}`)
49
+ .join('\n')
50
+ : result['ErrorMsg'] || 'Unknown error';
51
+ throw new Error(`Deployment failed:\n${formattedErrors}`);
52
+ }
53
+ return result;
32
54
  }
33
55
  }
34
56
  //# sourceMappingURL=apexClassRepository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apexClassRepository.js","sourceRoot":"","sources":["../../src/adapter/apexClassRepository.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,mBAAmB;IACC;IAA/B,YAA+B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAElD,KAAK,CAAC,IAAI,CAAC,IAAY;QAC5B,OAAO,CACL,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aAC1B,OAAO,CAAC,WAAW,CAAC;aACpB,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;aACpB,OAAO,EAAE,CACb,CAAC,CAAC,CAAC,CAAA;IACN,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,SAAoB;QACtC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aAC5C,OAAO,CAAC,mBAAmB,CAAC;aAC5B,MAAM,CAAC;YACN,IAAI,EAAE,gBAAgB,IAAI,CAAC,GAAG,EAAE,EAAE;SACnC,CAAC,CAAA;QAEJ,iDAAiD;QACjD,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;YAC9D,mBAAmB,EAAE,SAAS,CAAC,EAAE;YACjC,eAAe,EAAE,SAAS,CAAC,EAAE;YAC7B,IAAI,EAAE,SAAS,CAAC,IAAI;SACrB,CAAC,CAAA;QAEF,yCAAyC;QACzC,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aACjC,OAAO,CAAC,uBAAuB,CAAC;aAChC,MAAM,CAAC;YACN,WAAW,EAAE,KAAK;YAClB,mBAAmB,EAAE,SAAS,CAAC,EAAE;YACjC,UAAU,EAAE,IAAI;SACjB,CAAC,CAAA;IACN,CAAC;CACF"}
1
+ {"version":3,"file":"apexClassRepository.js","sourceRoot":"","sources":["../../src/adapter/apexClassRepository.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,mBAAmB;IACC;IAA/B,YAA+B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAElD,KAAK,CAAC,IAAI,CAAC,IAAY;QAC5B,OAAO,CACL,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aAC1B,OAAO,CAAC,WAAW,CAAC;aACpB,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;aACpB,OAAO,EAAE,CACb,CAAC,CAAC,CAAC,CAAA;IACN,CAAC;IAEM,KAAK,CAAC,wBAAwB,CACnC,OAAe;QAEf,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aAClC,OAAO,CAAC,6BAA6B,CAAC;aACtC,IAAI,CAAC,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC;aACtC,OAAO,EAAE,CAAkC,CAAA;IAChD,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,SAAoB;QACtC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aAC5C,OAAO,CAAC,mBAAmB,CAAC;aAC5B,MAAM,CAAC;YACN,IAAI,EAAE,gBAAgB,IAAI,CAAC,GAAG,EAAE,EAAE;SACnC,CAAC,CAAA;QAEJ,iDAAiD;QACjD,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;YAC9D,mBAAmB,EAAE,SAAS,CAAC,EAAE;YACjC,eAAe,EAAE,SAAS,CAAC,EAAE;YAC7B,IAAI,EAAE,SAAS,CAAC,IAAI;SACrB,CAAC,CAAA;QAEF,yCAAyC;QACzC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aAC/C,OAAO,CAAC,uBAAuB,CAAC;aAChC,MAAM,CAAC;YACN,WAAW,EAAE,KAAK;YAClB,mBAAmB,EAAE,SAAS,CAAC,EAAE;YACjC,UAAU,EAAE,IAAI;SACjB,CAAC,CAAA;QAEJ,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;aACzC,OAAO,CAAC,uBAAuB,CAAC;aAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QAE5B,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAA;YAClE,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC7C,CAAC,CAAC,QAAQ;qBACL,GAAG,CACF,CAAC,CAAC,EAAE,CACF,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,OAAO,EAAE,CACnE;qBACA,IAAI,CAAC,IAAI,CAAC;gBACf,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,eAAe,CAAA;YAEzC,MAAM,IAAI,KAAK,CAAC,uBAAuB,eAAe,EAAE,CAAC,CAAA;QAC3D,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
@@ -3,7 +3,12 @@ import { Connection } from '@salesforce/core';
3
3
  export declare class ApexTestRunner {
4
4
  protected readonly testService: TestService;
5
5
  constructor(connection: Connection);
6
- getCoveredLines(testClassName: string): Promise<Set<number>>;
7
- run(testClassName: string): Promise<TestResult>;
6
+ getTestMethodsPerLines(className: string): Promise<{
7
+ outcome: string;
8
+ testsRan: number;
9
+ failing: number;
10
+ testMethodsPerLine: Map<number, Set<string>>;
11
+ }>;
12
+ runTestMethods(className: string, testMethods?: Set<string>): Promise<TestResult>;
8
13
  private runTestAsynchronous;
9
14
  }
@@ -4,16 +4,37 @@ export class ApexTestRunner {
4
4
  constructor(connection) {
5
5
  this.testService = new TestService(connection);
6
6
  }
7
- async getCoveredLines(testClassName) {
8
- const testResult = await this.runTestAsynchronous(testClassName, false);
9
- return new Set(testResult.codecoverage?.flatMap(coverage => coverage.coveredLines));
7
+ async getTestMethodsPerLines(className) {
8
+ const testResult = await this.runTestAsynchronous({ className }, false);
9
+ const testMethodsPerLine = new Map();
10
+ testResult.tests?.forEach(test => {
11
+ test.perClassCoverage?.forEach(testMethodExecutionResult => {
12
+ testMethodExecutionResult.coverage?.coveredLines?.forEach(line => {
13
+ if (!testMethodsPerLine.has(line)) {
14
+ testMethodsPerLine.set(line, new Set());
15
+ }
16
+ testMethodsPerLine
17
+ .get(line)
18
+ .add(testMethodExecutionResult.apexTestMethodName);
19
+ });
20
+ });
21
+ });
22
+ return {
23
+ outcome: testResult.summary.outcome,
24
+ testsRan: testResult.summary.testsRan,
25
+ failing: testResult.summary.failing,
26
+ testMethodsPerLine,
27
+ };
10
28
  }
11
- async run(testClassName) {
12
- return await this.runTestAsynchronous(testClassName);
29
+ async runTestMethods(className, testMethods = new Set()) {
30
+ return await this.runTestAsynchronous({
31
+ className,
32
+ testMethods: Array.from(testMethods),
33
+ });
13
34
  }
14
- async runTestAsynchronous(testClassName, skipCodeCoverage = true) {
35
+ async runTestAsynchronous(testPerimeter, skipCodeCoverage = true) {
15
36
  return (await this.testService.runTestAsynchronous({
16
- tests: [{ className: testClassName }],
37
+ tests: [testPerimeter],
17
38
  testLevel: "RunSpecifiedTests" /* TestLevel.RunSpecifiedTests */,
18
39
  skipCodeCoverage,
19
40
  maxFailedTests: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"apexTestRunner.js","sourceRoot":"","sources":["../../src/adapter/apexTestRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAG1E,MAAM,OAAO,cAAc;IACN,WAAW,CAAa;IAC3C,YAAY,UAAsB;QAChC,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,aAAqB;QAChD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QACvE,OAAO,IAAI,GAAG,CACZ,UAAU,CAAC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CACpE,CAAA;IACH,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,aAAqB;QACpC,OAAO,MAAM,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAA;IACtD,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAC/B,aAAqB,EACrB,mBAA4B,IAAI;QAEhC,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAChD;YACE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;YACrC,SAAS,uDAA6B;YACtC,gBAAgB;YAChB,cAAc,EAAE,CAAC;SAClB,EACD,CAAC,gBAAgB,CAClB,CAAe,CAAA;IAClB,CAAC;CACF"}
1
+ {"version":3,"file":"apexTestRunner.js","sourceRoot":"","sources":["../../src/adapter/apexTestRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAG1E,MAAM,OAAO,cAAc;IACN,WAAW,CAAa;IAC3C,YAAY,UAAsB;QAChC,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC;IAEM,KAAK,CAAC,sBAAsB,CAAC,SAAiB;QACnD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,CAAA;QAEvE,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAuB,CAAA;QAEzD,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;YAC/B,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,yBAAyB,CAAC,EAAE;gBACzD,yBAAyB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;oBAC/D,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBAClC,kBAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAU,CAAC,CAAA;oBACjD,CAAC;oBACD,kBAAkB;yBACf,GAAG,CAAC,IAAI,CAAE;yBACV,GAAG,CAAC,yBAAyB,CAAC,kBAAkB,CAAC,CAAA;gBACtD,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,OAAO;YACL,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO;YACnC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,QAAQ;YACrC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO;YACnC,kBAAkB;SACnB,CAAA;IACH,CAAC;IAEM,KAAK,CAAC,cAAc,CACzB,SAAiB,EACjB,cAA2B,IAAI,GAAG,EAAU;QAE5C,OAAO,MAAM,IAAI,CAAC,mBAAmB,CAAC;YACpC,SAAS;YACT,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;SACrC,CAAC,CAAA;IACJ,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAC/B,aAA4D,EAC5D,mBAA4B,IAAI;QAEhC,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAChD;YACE,KAAK,EAAE,CAAC,aAAa,CAAC;YACtB,SAAS,uDAA6B;YACtC,gBAAgB;YAChB,cAAc,EAAE,CAAC;SAClB,EACD,CAAC,gBAAgB,CAClB,CAAe,CAAA;IAClB,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { BaseListener } from './baseListener.js';
3
+ export declare class ArithmeticOperatorMutator extends BaseListener {
4
+ private readonly REPLACEMENT_MAP;
5
+ enterArth1Expression(ctx: ParserRuleContext): void;
6
+ enterArth2Expression(ctx: ParserRuleContext): void;
7
+ enterAssignExpression(_ctx: ParserRuleContext): void;
8
+ private processArithmeticOperation;
9
+ }
@@ -0,0 +1,36 @@
1
+ import { TerminalNode } from 'antlr4ts/tree/index.js';
2
+ import { BaseListener } from './baseListener.js';
3
+ export class ArithmeticOperatorMutator extends BaseListener {
4
+ REPLACEMENT_MAP = {
5
+ '+': ['-', '*', '/'],
6
+ '-': ['+', '*', '/'],
7
+ '*': ['+', '-', '/'],
8
+ '/': ['+', '-', '*'],
9
+ };
10
+ // Handle MUL, DIV, and MOD operations (*, /, %)
11
+ enterArth1Expression(ctx) {
12
+ this.processArithmeticOperation(ctx);
13
+ }
14
+ // Handle ADD and SUB operations (+, -)
15
+ enterArth2Expression(ctx) {
16
+ this.processArithmeticOperation(ctx);
17
+ }
18
+ enterAssignExpression(_ctx) {
19
+ // Method intentionally left empty - enables traversal into children
20
+ }
21
+ processArithmeticOperation(ctx) {
22
+ if (ctx.childCount === 3) {
23
+ const operatorNode = ctx.getChild(1);
24
+ if (operatorNode instanceof TerminalNode) {
25
+ const operatorText = operatorNode.text;
26
+ const replacements = this.REPLACEMENT_MAP[operatorText];
27
+ if (replacements) {
28
+ for (const replacement of replacements) {
29
+ this.createMutationFromTerminalNode(operatorNode, replacement);
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ //# sourceMappingURL=arithmeticOperatorMutator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arithmeticOperatorMutator.js","sourceRoot":"","sources":["../../src/mutator/arithmeticOperatorMutator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,OAAO,yBAA0B,SAAQ,YAAY;IACxC,eAAe,GAA6B;QAC3D,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QACpB,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QACpB,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QACpB,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;KACrB,CAAA;IAED,gDAAgD;IAChD,oBAAoB,CAAC,GAAsB;QACzC,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,CAAA;IACtC,CAAC;IAED,uCAAuC;IACvC,oBAAoB,CAAC,GAAsB;QACzC,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,CAAA;IACtC,CAAC;IAED,qBAAqB,CAAC,IAAuB;QAC3C,oEAAoE;IACtE,CAAC;IAEO,0BAA0B,CAAC,GAAsB;QACvD,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAEpC,IAAI,YAAY,YAAY,YAAY,EAAE,CAAC;gBACzC,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAA;gBACtC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAA;gBAEvD,IAAI,YAAY,EAAE,CAAC;oBACjB,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;wBACvC,IAAI,CAAC,8BAA8B,CAAC,YAAY,EAAE,WAAW,CAAC,CAAA;oBAChE,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -1,5 +1,10 @@
1
+ import { ParserRuleContext, Token } from 'antlr4ts';
2
+ import { TerminalNode } from 'antlr4ts/tree/index.js';
1
3
  import { ApexParserListener } from 'apex-parser';
2
4
  import { ApexMutation } from '../type/ApexMutation.js';
3
5
  export declare class BaseListener implements ApexParserListener {
4
6
  _mutations: ApexMutation[];
7
+ protected createMutation(startToken: Token, endToken: Token, originalText: string, replacement: string): void;
8
+ protected createMutationFromParserRuleContext(ctx: ParserRuleContext, replacement: string): void;
9
+ protected createMutationFromTerminalNode(node: TerminalNode, replacement: string): void;
5
10
  }
@@ -1,5 +1,26 @@
1
1
  // @ts-ignore: Base type with just a common _mutations property
2
2
  export class BaseListener {
3
3
  _mutations = [];
4
+ createMutation(startToken, endToken, originalText, replacement) {
5
+ this._mutations.push({
6
+ mutationName: this.constructor.name,
7
+ target: {
8
+ startToken,
9
+ endToken,
10
+ text: originalText,
11
+ },
12
+ replacement,
13
+ });
14
+ }
15
+ createMutationFromParserRuleContext(ctx, replacement) {
16
+ if (ctx.start && ctx.stop) {
17
+ this.createMutation(ctx.start, ctx.stop, ctx.text, replacement);
18
+ }
19
+ }
20
+ createMutationFromTerminalNode(node, replacement) {
21
+ if (node.symbol) {
22
+ this.createMutation(node.symbol, node.symbol, node.text, replacement);
23
+ }
24
+ }
4
25
  }
5
26
  //# sourceMappingURL=baseListener.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"baseListener.js","sourceRoot":"","sources":["../../src/mutator/baseListener.ts"],"names":[],"mappings":"AAGA,+DAA+D;AAC/D,MAAM,OAAO,YAAY;IACvB,UAAU,GAAmB,EAAE,CAAA;CAChC"}
1
+ {"version":3,"file":"baseListener.js","sourceRoot":"","sources":["../../src/mutator/baseListener.ts"],"names":[],"mappings":"AAKA,+DAA+D;AAC/D,MAAM,OAAO,YAAY;IACvB,UAAU,GAAmB,EAAE,CAAA;IAErB,cAAc,CACtB,UAAiB,EACjB,QAAe,EACf,YAAoB,EACpB,WAAmB;QAEnB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACnB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YACnC,MAAM,EAAE;gBACN,UAAU;gBACV,QAAQ;gBACR,IAAI,EAAE,YAAY;aACnB;YACD,WAAW;SACZ,CAAC,CAAA;IACJ,CAAC;IAES,mCAAmC,CAC3C,GAAsB,EACtB,WAAmB;QAEnB,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IAES,8BAA8B,CACtC,IAAkB,EAClB,WAAmB;QAEnB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;QACvE,CAAC;IACH,CAAC;CACF"}
@@ -1,6 +1,6 @@
1
- import { BaseListener } from './baseListener.js';
2
1
  import { ParserRuleContext } from 'antlr4ts';
2
+ import { BaseListener } from './baseListener.js';
3
3
  export declare class BoundaryConditionMutator extends BaseListener {
4
- private REPLACEMENT_MAP;
5
- enterParExpression(ctx: ParserRuleContext): void;
4
+ private readonly REPLACEMENT_MAP;
5
+ enterCmpExpression(ctx: ParserRuleContext): void;
6
6
  }
@@ -1,33 +1,35 @@
1
- import { BaseListener } from './baseListener.js';
2
1
  import { TerminalNode } from 'antlr4ts/tree/index.js';
2
+ import { BaseListener } from './baseListener.js';
3
3
  export class BoundaryConditionMutator extends BaseListener {
4
4
  REPLACEMENT_MAP = {
5
- '!=': '==',
6
- '==': '!=',
7
5
  '<': '<=',
8
6
  '<=': '<',
9
7
  '>': '>=',
10
8
  '>=': '>',
11
- '===': '!==',
12
- '!==': '===',
13
9
  };
14
- // Target rule
15
- // expression: expression ('<=' | '>=' | '>' | '<') expression
16
- enterParExpression(ctx) {
17
- if (ctx.childCount === 3) {
18
- const symbol = ctx.getChild(1).getChild(1);
19
- if (symbol instanceof TerminalNode) {
20
- const symbolText = symbol.text;
21
- const replacement = this.REPLACEMENT_MAP[symbolText];
22
- if (replacement) {
23
- this._mutations.push({
24
- mutationName: this.constructor.name,
25
- token: symbol,
26
- replacement,
27
- });
10
+ enterCmpExpression(ctx) {
11
+ if (ctx.childCount < 3)
12
+ return;
13
+ let operatorText = '';
14
+ const operatorTokens = [];
15
+ for (let i = 0; i < ctx.childCount; i++) {
16
+ const child = ctx.getChild(i);
17
+ if (child instanceof TerminalNode) {
18
+ const text = child.text;
19
+ if (['>', '<', '=', '!'].includes(text)) {
20
+ operatorText += text;
21
+ if (child.symbol !== null) {
22
+ operatorTokens.push({ node: child, token: child.symbol });
23
+ }
28
24
  }
29
25
  }
30
26
  }
27
+ const replacement = this.REPLACEMENT_MAP[operatorText];
28
+ if (replacement && operatorTokens.length > 0) {
29
+ const startToken = operatorTokens[0].token;
30
+ const endToken = operatorTokens[operatorTokens.length - 1].token;
31
+ this.createMutation(startToken, endToken, operatorText, replacement);
32
+ }
31
33
  }
32
34
  }
33
35
  //# sourceMappingURL=boundaryConditionMutator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"boundaryConditionMutator.js","sourceRoot":"","sources":["../../src/mutator/boundaryConditionMutator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD,MAAM,OAAO,wBAAyB,SAAQ,YAAY;IAChD,eAAe,GAA2B;QAChD,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,IAAI;QACV,GAAG,EAAE,IAAI;QACT,IAAI,EAAE,GAAG;QACT,GAAG,EAAE,IAAI;QACT,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,KAAK;KACb,CAAA;IAED,cAAc;IACd,8DAA8D;IAC9D,kBAAkB,CAAC,GAAsB;QACvC,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAC1C,IAAI,MAAM,YAAY,YAAY,EAAE,CAAC;gBACnC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAA;gBAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;gBACpD,IAAI,WAAW,EAAE,CAAC;oBAChB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;wBACnB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;wBACnC,KAAK,EAAE,MAAM;wBACb,WAAW;qBACZ,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"boundaryConditionMutator.js","sourceRoot":"","sources":["../../src/mutator/boundaryConditionMutator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,OAAO,wBAAyB,SAAQ,YAAY;IACvC,eAAe,GAA2B;QACzD,GAAG,EAAE,IAAI;QACT,IAAI,EAAE,GAAG;QACT,GAAG,EAAE,IAAI;QACT,IAAI,EAAE,GAAG;KACV,CAAA;IAED,kBAAkB,CAAC,GAAsB;QACvC,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC;YAAE,OAAM;QAE9B,IAAI,YAAY,GAAG,EAAE,CAAA;QACrB,MAAM,cAAc,GAA2C,EAAE,CAAA;QAEjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAC7B,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;gBAEvB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxC,YAAY,IAAI,IAAI,CAAA;oBACpB,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;wBAC1B,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;oBAC3D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAA;QAEtD,IAAI,WAAW,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;YAC1C,MAAM,QAAQ,GAAG,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAA;YAChE,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { ReturnTypeAwareBaseListener } from './returnTypeAwareBaseListener.js';
3
+ export declare class EmptyReturnMutator extends ReturnTypeAwareBaseListener {
4
+ enterReturnStatement(ctx: ParserRuleContext): void;
5
+ private generateEmptyValue;
6
+ isEmptyValue(type: string, expressionText: string): boolean;
7
+ }
@@ -0,0 +1,94 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { ApexType } from '../type/ApexMethod.js';
3
+ import { ReturnTypeAwareBaseListener } from './returnTypeAwareBaseListener.js';
4
+ export class EmptyReturnMutator extends ReturnTypeAwareBaseListener {
5
+ enterReturnStatement(ctx) {
6
+ if (!this.isCurrentMethodTypeKnown()) {
7
+ return;
8
+ }
9
+ const typeInfo = this.getCurrentMethodReturnTypeInfo();
10
+ if (!typeInfo) {
11
+ return;
12
+ }
13
+ // Skip types that can't be replaced
14
+ if ([
15
+ ApexType.VOID,
16
+ ApexType.BOOLEAN,
17
+ ApexType.SOBJECT,
18
+ ApexType.OBJECT,
19
+ ApexType.APEX_CLASS,
20
+ ApexType.DATE,
21
+ ApexType.DATETIME,
22
+ ApexType.TIME,
23
+ ].includes(typeInfo.type)) {
24
+ return;
25
+ }
26
+ if (!ctx.children || ctx.children.length < 2) {
27
+ return;
28
+ }
29
+ const expressionNode = ctx.children[1];
30
+ if (!(expressionNode instanceof ParserRuleContext)) {
31
+ return;
32
+ }
33
+ if (this.isEmptyValue(typeInfo.returnType, expressionNode.text)) {
34
+ return;
35
+ }
36
+ const emptyValue = this.generateEmptyValue(typeInfo);
37
+ if (emptyValue) {
38
+ this.createMutationFromParserRuleContext(expressionNode, emptyValue);
39
+ }
40
+ }
41
+ generateEmptyValue(typeInfo) {
42
+ switch (typeInfo.type) {
43
+ case ApexType.STRING:
44
+ case ApexType.ID:
45
+ return "''";
46
+ case ApexType.INTEGER:
47
+ return '0';
48
+ case ApexType.LONG:
49
+ return '0L';
50
+ case ApexType.DOUBLE:
51
+ case ApexType.DECIMAL:
52
+ return '0.0';
53
+ case ApexType.BLOB:
54
+ return "Blob.valueOf('')";
55
+ case ApexType.LIST:
56
+ case ApexType.SET:
57
+ case ApexType.MAP:
58
+ case ApexType.CUSTOM_OBJECT:
59
+ case ApexType.STANDARD_ENTITY:
60
+ return `new ${typeInfo.returnType}()`;
61
+ default:
62
+ return null;
63
+ }
64
+ }
65
+ isEmptyValue(type, expressionText) {
66
+ const lowerType = type.toLowerCase();
67
+ const emptyValuePatterns = {
68
+ string: expr => expr === "''",
69
+ integer: expr => expr === '0',
70
+ double: expr => expr === '0' || expr === '0.0' || !!expr.match(/^0\.0+$/),
71
+ decimal: expr => expr === '0' || expr === '0.0' || !!expr.match(/^0\.0+$/),
72
+ long: expr => expr === '0' || expr === '0L',
73
+ };
74
+ if (lowerType.startsWith('list<') || lowerType.endsWith('[]')) {
75
+ return (!!expressionText.match(/new\s+List<[^>]*>\s*\(\s*\)/i) ||
76
+ !!expressionText.match(/new\s+[^[\]]+\[\s*\]\s*\{\s*\}/));
77
+ }
78
+ if (lowerType.startsWith('set<')) {
79
+ return !!expressionText.match(/new\s+Set<[^>]*>\s*\(\s*\)/i);
80
+ }
81
+ if (lowerType.startsWith('map<')) {
82
+ return !!expressionText.match(/new\s+Map<[^>]*>\s*\(\s*\)/i);
83
+ }
84
+ if (expressionText === 'null') {
85
+ return true;
86
+ }
87
+ const checkPattern = emptyValuePatterns[lowerType];
88
+ if (checkPattern) {
89
+ return checkPattern(expressionText);
90
+ }
91
+ return false;
92
+ }
93
+ }
94
+ //# sourceMappingURL=emptyReturnMutator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emptyReturnMutator.js","sourceRoot":"","sources":["../../src/mutator/emptyReturnMutator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { BaseListener } from './baseListener.js';
3
+ export declare class EqualityConditionMutator extends BaseListener {
4
+ private readonly REPLACEMENT_MAP;
5
+ enterEqualityExpression(ctx: ParserRuleContext): void;
6
+ }
@@ -0,0 +1,25 @@
1
+ import { TerminalNode } from 'antlr4ts/tree/index.js';
2
+ import { BaseListener } from './baseListener.js';
3
+ export class EqualityConditionMutator extends BaseListener {
4
+ REPLACEMENT_MAP = {
5
+ '==': '!=',
6
+ '!=': '==',
7
+ '===': '!==',
8
+ '!==': '===',
9
+ };
10
+ enterEqualityExpression(ctx) {
11
+ if (!ctx || ctx.childCount < 3)
12
+ return;
13
+ for (let i = 0; i < ctx.childCount; i++) {
14
+ const child = ctx.getChild(i);
15
+ if (child instanceof TerminalNode) {
16
+ const operatorText = child.text;
17
+ const replacement = this.REPLACEMENT_MAP[operatorText];
18
+ if (replacement) {
19
+ this.createMutationFromTerminalNode(child, replacement);
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=equalityConditionMutator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"equalityConditionMutator.js","sourceRoot":"","sources":["../../src/mutator/equalityConditionMutator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,OAAO,wBAAyB,SAAQ,YAAY;IACvC,eAAe,GAA2B;QACzD,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,KAAK;KACb,CAAA;IAED,uBAAuB,CAAC,GAAsB;QAC5C,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC;YAAE,OAAM;QAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAE7B,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;gBAClC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAA;gBAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAA;gBACtD,IAAI,WAAW,EAAE,CAAC;oBAChB,IAAI,CAAC,8BAA8B,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;gBACzD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { ReturnTypeAwareBaseListener } from './returnTypeAwareBaseListener.js';
3
+ export declare class FalseReturnMutator extends ReturnTypeAwareBaseListener {
4
+ enterReturnStatement(ctx: ParserRuleContext): void;
5
+ }
@@ -0,0 +1,29 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { ApexType } from '../type/ApexMethod.js';
3
+ import { ReturnTypeAwareBaseListener } from './returnTypeAwareBaseListener.js';
4
+ export class FalseReturnMutator extends ReturnTypeAwareBaseListener {
5
+ enterReturnStatement(ctx) {
6
+ if (!this.isCurrentMethodTypeKnown()) {
7
+ return;
8
+ }
9
+ const typeInfo = this.getCurrentMethodReturnTypeInfo();
10
+ if (!typeInfo) {
11
+ return;
12
+ }
13
+ if (typeInfo.type !== ApexType.BOOLEAN) {
14
+ return;
15
+ }
16
+ if (!ctx.children || ctx.children.length < 2) {
17
+ return;
18
+ }
19
+ const expressionNode = ctx.children[1];
20
+ if (!(expressionNode instanceof ParserRuleContext)) {
21
+ return;
22
+ }
23
+ if (expressionNode.text.trim().toLowerCase() === 'false') {
24
+ return;
25
+ }
26
+ this.createMutationFromParserRuleContext(expressionNode, 'false');
27
+ }
28
+ }
29
+ //# sourceMappingURL=falseReturnMutator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"falseReturnMutator.js","sourceRoot":"","sources":["../../src/mutator/falseReturnMutator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAA;AAE9E,MAAM,OAAO,kBAAmB,SAAQ,2BAA2B;IACjE,oBAAoB,CAAC,GAAsB;QACzC,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;YACrC,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,8BAA8B,EAAE,CAAA;QACtD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAM;QACR,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC;YACvC,OAAM;QACR,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,OAAM;QACR,CAAC;QAED,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QACtC,IAAI,CAAC,CAAC,cAAc,YAAY,iBAAiB,CAAC,EAAE,CAAC;YACnD,OAAM;QACR,CAAC;QAED,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,EAAE,CAAC;YACzD,OAAM;QACR,CAAC;QAED,IAAI,CAAC,mCAAmC,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;IACnE,CAAC;CACF"}
@@ -1,5 +1,5 @@
1
- import { BaseListener } from './baseListener.js';
2
1
  import { ParserRuleContext } from 'antlr4ts';
2
+ import { BaseListener } from './baseListener.js';
3
3
  export declare class IncrementMutator extends BaseListener {
4
4
  private REPLACEMENT_MAP;
5
5
  enterPostOpExpression(ctx: ParserRuleContext): void;
@@ -1,5 +1,5 @@
1
- import { BaseListener } from './baseListener.js';
2
1
  import { TerminalNode } from 'antlr4ts/tree/index.js';
2
+ import { BaseListener } from './baseListener.js';
3
3
  export class IncrementMutator extends BaseListener {
4
4
  REPLACEMENT_MAP = {
5
5
  '++': '--',
@@ -17,19 +17,15 @@ export class IncrementMutator extends BaseListener {
17
17
  }
18
18
  processOperation(ctx) {
19
19
  if (ctx.childCount === 2) {
20
- let symbol = null;
20
+ let operatorNode = null;
21
21
  if (ctx.getChild(0) instanceof TerminalNode) {
22
- symbol = ctx.getChild(0);
22
+ operatorNode = ctx.getChild(0);
23
23
  }
24
24
  else if (ctx.getChild(1) instanceof TerminalNode) {
25
- symbol = ctx.getChild(1);
25
+ operatorNode = ctx.getChild(1);
26
26
  }
27
- if (symbol !== null && symbol.text in this.REPLACEMENT_MAP) {
28
- this._mutations.push({
29
- mutationName: this.constructor.name,
30
- token: symbol,
31
- replacement: this.REPLACEMENT_MAP[symbol.text],
32
- });
27
+ if (operatorNode !== null && operatorNode.text in this.REPLACEMENT_MAP) {
28
+ this.createMutationFromTerminalNode(operatorNode, this.REPLACEMENT_MAP[operatorNode.text]);
33
29
  }
34
30
  }
35
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"incrementMutator.js","sourceRoot":"","sources":["../../src/mutator/incrementMutator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IACxC,eAAe,GAA2B;QAChD,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,IAAI;KACX,CAAA;IAED,cAAc;IACd,eAAe;IACf,8BAA8B;IAC9B,0CAA0C;IAC1C,qBAAqB,CAAC,GAAsB;QAC1C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED,oBAAoB,CAAC,GAAsB;QACzC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAEO,gBAAgB,CAAC,GAAsB;QAC7C,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,MAAM,GAAwB,IAAI,CAAA;YACtC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,YAAY,EAAE,CAAC;gBAC5C,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAiB,CAAA;YAC1C,CAAC;iBAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,YAAY,EAAE,CAAC;gBACnD,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAiB,CAAA;YAC1C,CAAC;YAED,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC3D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;oBACnB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;oBACnC,KAAK,EAAE,MAAM;oBACb,WAAW,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC;iBAC/C,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"incrementMutator.js","sourceRoot":"","sources":["../../src/mutator/incrementMutator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IACxC,eAAe,GAA2B;QAChD,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,IAAI;KACX,CAAA;IAED,cAAc;IACd,eAAe;IACf,8BAA8B;IAC9B,0CAA0C;IAC1C,qBAAqB,CAAC,GAAsB;QAC1C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED,oBAAoB,CAAC,GAAsB;QACzC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAEO,gBAAgB,CAAC,GAAsB;QAC7C,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,YAAY,GAAwB,IAAI,CAAA;YAC5C,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,YAAY,EAAE,CAAC;gBAC5C,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAiB,CAAA;YAChD,CAAC;iBAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,YAAY,EAAE,CAAC;gBACnD,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAiB,CAAA;YAChD,CAAC;YAED,IAAI,YAAY,KAAK,IAAI,IAAI,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBACvE,IAAI,CAAC,8BAA8B,CACjC,YAAY,EACZ,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,CACxC,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { ApexParserListener } from 'apex-parser';
3
+ import { ApexMethod } from '../type/ApexMethod.js';
4
+ export declare class MethodTypeListener implements ApexParserListener {
5
+ private _apexClassTypes;
6
+ private _standardEntityTypes;
7
+ private _customObjectTypes;
8
+ private _methodTypeTable;
9
+ constructor(_apexClassTypes: Set<string>, _standardEntityTypes: Set<string>, _customObjectTypes: Set<string>);
10
+ getMethodTypeTable(): Map<string, ApexMethod>;
11
+ enterMethodDeclaration(ctx: ParserRuleContext): void;
12
+ }