api-tests-coverage 1.0.13 → 1.0.15

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 (100) hide show
  1. package/dist/src/pipeline/confidence.d.ts +70 -0
  2. package/dist/src/pipeline/confidence.d.ts.map +1 -0
  3. package/dist/src/pipeline/confidence.js +198 -0
  4. package/dist/src/pipeline/graph.d.ts +58 -0
  5. package/dist/src/pipeline/graph.d.ts.map +1 -0
  6. package/dist/src/pipeline/graph.js +199 -0
  7. package/dist/src/pipeline/index.d.ts +24 -0
  8. package/dist/src/pipeline/index.d.ts.map +1 -0
  9. package/dist/src/pipeline/index.js +41 -0
  10. package/dist/src/pipeline/orchestrator.d.ts +42 -0
  11. package/dist/src/pipeline/orchestrator.d.ts.map +1 -0
  12. package/dist/src/pipeline/orchestrator.js +115 -0
  13. package/dist/src/pipeline/stageInterface.d.ts +45 -0
  14. package/dist/src/pipeline/stageInterface.d.ts.map +1 -0
  15. package/dist/src/pipeline/stageInterface.js +17 -0
  16. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts +38 -0
  17. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts.map +1 -0
  18. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.js +203 -0
  19. package/dist/src/pipeline/stages/ast/astStage.d.ts +19 -0
  20. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -0
  21. package/dist/src/pipeline/stages/ast/astStage.js +238 -0
  22. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts +23 -0
  23. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts.map +1 -0
  24. package/dist/src/pipeline/stages/ast/crossFileResolver.js +183 -0
  25. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts +15 -0
  26. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -0
  27. package/dist/src/pipeline/stages/ast/graphBuilder.js +268 -0
  28. package/dist/src/pipeline/stages/ast/importResolver.d.ts +22 -0
  29. package/dist/src/pipeline/stages/ast/importResolver.d.ts.map +1 -0
  30. package/dist/src/pipeline/stages/ast/importResolver.js +186 -0
  31. package/dist/src/pipeline/stages/ast/types.d.ts +85 -0
  32. package/dist/src/pipeline/stages/ast/types.d.ts.map +1 -0
  33. package/dist/src/pipeline/stages/ast/types.js +5 -0
  34. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts +25 -0
  35. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts.map +1 -0
  36. package/dist/src/pipeline/stages/dast/conflictEmitter.js +90 -0
  37. package/dist/src/pipeline/stages/dast/dastStage.d.ts +17 -0
  38. package/dist/src/pipeline/stages/dast/dastStage.d.ts.map +1 -0
  39. package/dist/src/pipeline/stages/dast/dastStage.js +203 -0
  40. package/dist/src/pipeline/stages/dast/types.d.ts +49 -0
  41. package/dist/src/pipeline/stages/dast/types.d.ts.map +1 -0
  42. package/dist/src/pipeline/stages/dast/types.js +9 -0
  43. package/dist/src/pipeline/stages/iast/iastStage.d.ts +17 -0
  44. package/dist/src/pipeline/stages/iast/iastStage.d.ts.map +1 -0
  45. package/dist/src/pipeline/stages/iast/iastStage.js +191 -0
  46. package/dist/src/pipeline/stages/iast/types.d.ts +48 -0
  47. package/dist/src/pipeline/stages/iast/types.d.ts.map +1 -0
  48. package/dist/src/pipeline/stages/iast/types.js +8 -0
  49. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +17 -0
  50. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -0
  51. package/dist/src/pipeline/stages/merge/conflictDetector.js +60 -0
  52. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts +15 -0
  53. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -0
  54. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +141 -0
  55. package/dist/src/pipeline/stages/merge/mergeRules.d.ts +39 -0
  56. package/dist/src/pipeline/stages/merge/mergeRules.d.ts.map +1 -0
  57. package/dist/src/pipeline/stages/merge/mergeRules.js +90 -0
  58. package/dist/src/pipeline/stages/merge/mergeStage.d.ts +20 -0
  59. package/dist/src/pipeline/stages/merge/mergeStage.d.ts.map +1 -0
  60. package/dist/src/pipeline/stages/merge/mergeStage.js +145 -0
  61. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts +11 -0
  62. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts.map +1 -0
  63. package/dist/src/pipeline/stages/merge/summaryComputer.js +46 -0
  64. package/dist/src/pipeline/stages/sca/ciDetector.d.ts +15 -0
  65. package/dist/src/pipeline/stages/sca/ciDetector.d.ts.map +1 -0
  66. package/dist/src/pipeline/stages/sca/ciDetector.js +87 -0
  67. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts +31 -0
  68. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts.map +1 -0
  69. package/dist/src/pipeline/stages/sca/dependencyClassification.js +296 -0
  70. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts +25 -0
  71. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts.map +1 -0
  72. package/dist/src/pipeline/stages/sca/dependencyDetector.js +416 -0
  73. package/dist/src/pipeline/stages/sca/scaStage.d.ts +21 -0
  74. package/dist/src/pipeline/stages/sca/scaStage.d.ts.map +1 -0
  75. package/dist/src/pipeline/stages/sca/scaStage.js +208 -0
  76. package/dist/src/pipeline/stages/sca/types.d.ts +61 -0
  77. package/dist/src/pipeline/stages/sca/types.d.ts.map +1 -0
  78. package/dist/src/pipeline/stages/sca/types.js +9 -0
  79. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts +19 -0
  80. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -0
  81. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +118 -0
  82. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts +20 -0
  83. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts.map +1 -0
  84. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +238 -0
  85. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts +22 -0
  86. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts.map +1 -0
  87. package/dist/src/pipeline/stages/tia/testEndpointMapper.js +134 -0
  88. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts +16 -0
  89. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -0
  90. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +191 -0
  91. package/dist/src/pipeline/stages/tia/tiaStage.d.ts +20 -0
  92. package/dist/src/pipeline/stages/tia/tiaStage.d.ts.map +1 -0
  93. package/dist/src/pipeline/stages/tia/tiaStage.js +215 -0
  94. package/dist/src/pipeline/stages/tia/types.d.ts +52 -0
  95. package/dist/src/pipeline/stages/tia/types.d.ts.map +1 -0
  96. package/dist/src/pipeline/stages/tia/types.js +5 -0
  97. package/dist/src/pipeline/types.d.ts +128 -0
  98. package/dist/src/pipeline/types.d.ts.map +1 -0
  99. package/dist/src/pipeline/types.js +9 -0
  100. package/package.json +1 -1
@@ -0,0 +1,61 @@
1
+ /**
2
+ * SCA (Software Composition Analysis) stage output types.
3
+ *
4
+ * The SCA stage is the first stage in the pipeline. It formalizes the existing
5
+ * discovery engine output and adds dependency classification, version extraction,
6
+ * and CI platform detection.
7
+ */
8
+ /**
9
+ * Category for a classified dependency.
10
+ */
11
+ export type DependencyCategory = 'httpClient' | 'testFramework' | 'assertionLibrary' | 'mockingLibrary' | 'securityLibrary' | 'performanceTool' | 'e2eFramework' | 'framework' | 'database' | 'logging' | 'utility' | 'unknown';
12
+ /**
13
+ * CI platform detected from project structure.
14
+ */
15
+ export type CiPlatform = 'github-actions' | 'gitlab-ci' | 'jenkins' | 'azure-devops' | 'circleci' | 'travis-ci' | 'none';
16
+ /**
17
+ * Output produced by the SCA stage.
18
+ * Downstream stages (especially AST and TIA) reference this to select
19
+ * correct analysis heuristics.
20
+ */
21
+ export interface ScaOutput {
22
+ /** Detected programming languages (e.g. ["java", "typescript"]) */
23
+ languages: string[];
24
+ /** Detected frameworks (e.g. ["spring-boot", "express", "nestjs"]) */
25
+ frameworks: string[];
26
+ /** Detected HTTP client libraries (e.g. ["axios", "retrofit", "okhttp"]) */
27
+ httpClients: string[];
28
+ /** Detected test frameworks (e.g. ["jest", "junit5", "pytest"]) */
29
+ testFrameworks: string[];
30
+ /** Detected assertion libraries (e.g. ["assertj", "chai", "hamcrest"]) */
31
+ assertionLibraries: string[];
32
+ /** Detected security libraries (e.g. ["spring-security", "passport"]) */
33
+ securityLibraries: string[];
34
+ /** Detected performance testing tools (e.g. ["k6", "gatling", "locust"]) */
35
+ performanceTools: string[];
36
+ /** Detected mocking libraries (e.g. ["mockito", "mockk", "jest.mock", "sinon"]) */
37
+ mockingLibraries: string[];
38
+ /** Detected E2E testing frameworks (e.g. ["cypress", "playwright", "selenium"]) */
39
+ e2eFrameworks: string[];
40
+ /** All detected dependency names → version strings */
41
+ dependencyVersions: Record<string, string>;
42
+ /** Detected CI platform */
43
+ ciPlatform: CiPlatform;
44
+ }
45
+ /**
46
+ * A single parsed dependency entry from a manifest file.
47
+ */
48
+ export interface ParsedDependency {
49
+ name: string;
50
+ version: string;
51
+ scope: 'production' | 'development' | 'test' | 'build' | 'unknown';
52
+ sourceFile: string;
53
+ }
54
+ /**
55
+ * Result of parsing all manifest files in a project.
56
+ */
57
+ export interface DependencyParseResult {
58
+ dependencies: ParsedDependency[];
59
+ manifestFiles: string[];
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/sca/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,YAAY,GACZ,eAAe,GACf,kBAAkB,GAClB,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,UAAU,GACV,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,cAAc,GACd,UAAU,GACV,WAAW,GACX,MAAM,CAAC;AAEX;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,mEAAmE;IACnE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,sEAAsE;IACtE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mEAAmE;IACnE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0EAA0E;IAC1E,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,yEAAyE;IACzE,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mFAAmF;IACnF,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,sDAAsD;IACtD,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,2BAA2B;IAC3B,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,YAAY,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACnE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * SCA (Software Composition Analysis) stage output types.
4
+ *
5
+ * The SCA stage is the first stage in the pipeline. It formalizes the existing
6
+ * discovery engine output and adds dependency classification, version extraction,
7
+ * and CI platform detection.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Mock boundary detector — detects mock patterns across all languages
3
+ * and creates mock boundary records.
4
+ *
5
+ * Detects patterns from spec §17:
6
+ * - Java: @Mock, @Spy, @MockBean, @SpyBean, Mockito.mock(), mockk<>(), every{}
7
+ * - JS/TS: jest.mock(), jest.fn(), jest.spyOn(), sinon.stub(), sinon.mock(), nock()
8
+ * - Python: @patch(), @patch.object(), Mock(), MagicMock(), AsyncMock(), mocker.patch()
9
+ */
10
+ import type { DetectedMockBoundary } from './types';
11
+ /**
12
+ * Detect mock boundaries in a test file.
13
+ *
14
+ * @param filePath - The test file path
15
+ * @param content - The file content
16
+ * @param language - The detected language
17
+ */
18
+ export declare function detectMockBoundaries(filePath: string, content: string, language: string): DetectedMockBoundary[];
19
+ //# sourceMappingURL=mockBoundaryDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockBoundaryDetector.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/tia/mockBoundaryDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAmEpD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,oBAAoB,EAAE,CA8CxB"}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ /**
3
+ * Mock boundary detector — detects mock patterns across all languages
4
+ * and creates mock boundary records.
5
+ *
6
+ * Detects patterns from spec §17:
7
+ * - Java: @Mock, @Spy, @MockBean, @SpyBean, Mockito.mock(), mockk<>(), every{}
8
+ * - JS/TS: jest.mock(), jest.fn(), jest.spyOn(), sinon.stub(), sinon.mock(), nock()
9
+ * - Python: @patch(), @patch.object(), Mock(), MagicMock(), AsyncMock(), mocker.patch()
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.detectMockBoundaries = detectMockBoundaries;
13
+ const JAVA_KOTLIN_PATTERNS = [
14
+ { regex: /@Mock\b/, library: 'mockito', mockType: 'return-value' },
15
+ { regex: /@Spy\b/, library: 'mockito', mockType: 'spy' },
16
+ { regex: /@MockBean\b/, library: 'spring-test', mockType: 'return-value' },
17
+ { regex: /@SpyBean\b/, library: 'spring-test', mockType: 'spy' },
18
+ { regex: /Mockito\.mock\(/, library: 'mockito', mockType: 'return-value' },
19
+ { regex: /Mockito\.spy\(/, library: 'mockito', mockType: 'spy' },
20
+ { regex: /when\(.*\)\.thenReturn\(/, library: 'mockito', mockType: 'return-value' },
21
+ { regex: /when\(.*\)\.thenThrow\(/, library: 'mockito', mockType: 'exception' },
22
+ { regex: /doReturn\(.*\)\.when\(/, library: 'mockito', mockType: 'return-value' },
23
+ { regex: /doThrow\(.*\)\.when\(/, library: 'mockito', mockType: 'exception' },
24
+ { regex: /mockk</, library: 'mockk', mockType: 'return-value' },
25
+ { regex: /spyk\(/, library: 'mockk', mockType: 'spy' },
26
+ { regex: /every\s*\{/, library: 'mockk', mockType: 'return-value' },
27
+ { regex: /coEvery\s*\{/, library: 'mockk', mockType: 'return-value' },
28
+ { regex: /verify\s*\{/, library: 'mockk', mockType: 'spy' },
29
+ ];
30
+ const JS_TS_PATTERNS = [
31
+ { regex: /jest\.mock\(/, library: 'jest', mockType: 'return-value' },
32
+ { regex: /jest\.fn\(/, library: 'jest', mockType: 'return-value' },
33
+ { regex: /jest\.spyOn\(/, library: 'jest', mockType: 'spy' },
34
+ { regex: /\.mockReturnValue\(/, library: 'jest', mockType: 'return-value' },
35
+ { regex: /\.mockResolvedValue\(/, library: 'jest', mockType: 'return-value' },
36
+ { regex: /\.mockRejectedValue\(/, library: 'jest', mockType: 'exception' },
37
+ { regex: /\.mockImplementation\(/, library: 'jest', mockType: 'return-value' },
38
+ { regex: /sinon\.stub\(/, library: 'sinon', mockType: 'return-value' },
39
+ { regex: /sinon\.mock\(/, library: 'sinon', mockType: 'return-value' },
40
+ { regex: /sinon\.spy\(/, library: 'sinon', mockType: 'spy' },
41
+ { regex: /\.returns\(/, library: 'sinon', mockType: 'return-value' },
42
+ { regex: /\.throws\(/, library: 'sinon', mockType: 'exception' },
43
+ { regex: /nock\(/, library: 'nock', mockType: 'return-value' },
44
+ { regex: /\.useFakeTimers\(/, library: 'jest', mockType: 'timer' },
45
+ { regex: /sinon\.useFakeTimers\(/, library: 'sinon', mockType: 'timer' },
46
+ ];
47
+ const PYTHON_PATTERNS = [
48
+ { regex: /@patch\(/, library: 'unittest.mock', mockType: 'return-value' },
49
+ { regex: /@patch\.object\(/, library: 'unittest.mock', mockType: 'return-value' },
50
+ { regex: /Mock\(\)/, library: 'unittest.mock', mockType: 'return-value' },
51
+ { regex: /MagicMock\(\)/, library: 'unittest.mock', mockType: 'return-value' },
52
+ { regex: /AsyncMock\(\)/, library: 'unittest.mock', mockType: 'return-value' },
53
+ { regex: /mocker\.patch\(/, library: 'pytest-mock', mockType: 'return-value' },
54
+ { regex: /mocker\.spy\(/, library: 'pytest-mock', mockType: 'spy' },
55
+ { regex: /\.return_value\s*=/, library: 'unittest.mock', mockType: 'return-value' },
56
+ { regex: /\.side_effect\s*=/, library: 'unittest.mock', mockType: 'exception' },
57
+ { regex: /responses\.add\(/, library: 'responses', mockType: 'return-value' },
58
+ { regex: /requests_mock\./, library: 'requests-mock', mockType: 'return-value' },
59
+ { regex: /freezegun|freeze_time/, library: 'freezegun', mockType: 'timer' },
60
+ ];
61
+ const RUBY_PATTERNS = [
62
+ { regex: /allow\(.*\)\.to\s+receive\(/, library: 'rspec-mocks', mockType: 'return-value' },
63
+ { regex: /expect\(.*\)\.to\s+receive\(/, library: 'rspec-mocks', mockType: 'spy' },
64
+ { regex: /double\(/, library: 'rspec-mocks', mockType: 'return-value' },
65
+ { regex: /instance_double\(/, library: 'rspec-mocks', mockType: 'return-value' },
66
+ { regex: /stub_request\(/, library: 'webmock', mockType: 'return-value' },
67
+ ];
68
+ /**
69
+ * Detect mock boundaries in a test file.
70
+ *
71
+ * @param filePath - The test file path
72
+ * @param content - The file content
73
+ * @param language - The detected language
74
+ */
75
+ function detectMockBoundaries(filePath, content, language) {
76
+ var _a;
77
+ const boundaries = [];
78
+ const lines = content.split('\n');
79
+ let patterns;
80
+ switch (language) {
81
+ case 'java':
82
+ case 'kotlin':
83
+ patterns = JAVA_KOTLIN_PATTERNS;
84
+ break;
85
+ case 'javascript':
86
+ case 'typescript':
87
+ patterns = JS_TS_PATTERNS;
88
+ break;
89
+ case 'python':
90
+ patterns = PYTHON_PATTERNS;
91
+ break;
92
+ case 'ruby':
93
+ patterns = RUBY_PATTERNS;
94
+ break;
95
+ default:
96
+ // Try all patterns
97
+ patterns = [...JS_TS_PATTERNS, ...JAVA_KOTLIN_PATTERNS, ...PYTHON_PATTERNS, ...RUBY_PATTERNS];
98
+ }
99
+ for (let i = 0; i < lines.length; i++) {
100
+ const line = lines[i];
101
+ for (const pattern of patterns) {
102
+ if (pattern.regex.test(line)) {
103
+ // Extract mocked target (heuristic: argument in parentheses)
104
+ const targetMatch = /[\(][\s]*['"`]?([a-zA-Z0-9_./@]+)['"`]?/.exec(line);
105
+ const mockedTarget = (_a = targetMatch === null || targetMatch === void 0 ? void 0 : targetMatch[1]) !== null && _a !== void 0 ? _a : 'unknown';
106
+ boundaries.push({
107
+ testFilePath: filePath,
108
+ mockingLibrary: pattern.library,
109
+ mockType: pattern.mockType,
110
+ mockedTarget,
111
+ line: i + 1,
112
+ });
113
+ break; // One detection per line
114
+ }
115
+ }
116
+ }
117
+ return boundaries;
118
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Parameterized test expander — detects parameterized test patterns and
3
+ * calculates variant counts.
4
+ *
5
+ * Supports:
6
+ * - JUnit: @ParameterizedTest + @ValueSource, @CsvSource, @MethodSource, @EnumSource
7
+ * - Jest: test.each(table), describe.each(table), it.each
8
+ * - pytest: @pytest.mark.parametrize()
9
+ * - Kotest: data-driven tests
10
+ */
11
+ import type { ExpandedParameterizedTest } from './types';
12
+ /**
13
+ * Detect and expand parameterized tests in a file.
14
+ *
15
+ * @param filePath - The test file path
16
+ * @param content - The file content
17
+ * @param language - The detected language
18
+ */
19
+ export declare function expandParameterizedTests(filePath: string, content: string, language: string): ExpandedParameterizedTest[];
20
+ //# sourceMappingURL=parameterizedTestExpander.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parameterizedTestExpander.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/tia/parameterizedTestExpander.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,yBAAyB,EAAE,CAa7B"}
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ /**
3
+ * Parameterized test expander — detects parameterized test patterns and
4
+ * calculates variant counts.
5
+ *
6
+ * Supports:
7
+ * - JUnit: @ParameterizedTest + @ValueSource, @CsvSource, @MethodSource, @EnumSource
8
+ * - Jest: test.each(table), describe.each(table), it.each
9
+ * - pytest: @pytest.mark.parametrize()
10
+ * - Kotest: data-driven tests
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.expandParameterizedTests = expandParameterizedTests;
14
+ /**
15
+ * Detect and expand parameterized tests in a file.
16
+ *
17
+ * @param filePath - The test file path
18
+ * @param content - The file content
19
+ * @param language - The detected language
20
+ */
21
+ function expandParameterizedTests(filePath, content, language) {
22
+ switch (language) {
23
+ case 'java':
24
+ case 'kotlin':
25
+ return expandJavaKotlinParameterized(filePath, content);
26
+ case 'javascript':
27
+ case 'typescript':
28
+ return expandJestParameterized(filePath, content);
29
+ case 'python':
30
+ return expandPytestParameterized(filePath, content);
31
+ default:
32
+ return [];
33
+ }
34
+ }
35
+ // ─── JUnit Parameterized ────────────────────────────────────────────────────
36
+ function expandJavaKotlinParameterized(filePath, content) {
37
+ const results = [];
38
+ const lines = content.split('\n');
39
+ for (let i = 0; i < lines.length; i++) {
40
+ const line = lines[i].trim();
41
+ // @ParameterizedTest must precede the data source annotation
42
+ if (!line.includes('@ParameterizedTest'))
43
+ continue;
44
+ // Look ahead for data source annotations
45
+ let testName = 'unknown';
46
+ let variantCount = 'unresolvable';
47
+ let pattern = '@ParameterizedTest';
48
+ for (let j = i + 1; j < Math.min(i + 10, lines.length); j++) {
49
+ const nextLine = lines[j].trim();
50
+ // Extract test method name
51
+ const methodMatch = /(?:void|fun)\s+(\w+)\s*\(/.exec(nextLine);
52
+ if (methodMatch) {
53
+ testName = methodMatch[1];
54
+ break;
55
+ }
56
+ // @ValueSource(strings = {"a", "b", "c"})
57
+ const valueSourceMatch = /@ValueSource\(\s*\w+\s*=\s*\{([^}]+)\}/.exec(nextLine);
58
+ if (valueSourceMatch) {
59
+ variantCount = valueSourceMatch[1].split(',').length;
60
+ pattern = '@ValueSource';
61
+ continue;
62
+ }
63
+ // @CsvSource({"a,1", "b,2", "c,3"})
64
+ const csvSourceMatch = /@CsvSource\(\s*(?:value\s*=\s*)?\{([^}]+)\}/.exec(nextLine);
65
+ if (csvSourceMatch) {
66
+ variantCount = csvSourceMatch[1].split(/",\s*"/).length;
67
+ pattern = '@CsvSource';
68
+ continue;
69
+ }
70
+ // @MethodSource("methodName")
71
+ const methodSourceMatch = /@MethodSource\(\s*"(\w+)"/.exec(nextLine);
72
+ if (methodSourceMatch) {
73
+ pattern = `@MethodSource(${methodSourceMatch[1]})`;
74
+ // Try to find the method and count Stream.of() arguments
75
+ const sourceMethodRegex = new RegExp(`(?:static\\s+)?(?:Stream|List|Collection|Set).*?\\s+${methodSourceMatch[1]}\\s*\\([^)]*\\)\\s*\\{([\\s\\S]*?)\\}`, 'm');
76
+ const sourceMethodMatch = sourceMethodRegex.exec(content);
77
+ if (sourceMethodMatch) {
78
+ const body = sourceMethodMatch[1];
79
+ const argsMatch = body.match(/(?:Arguments\.of|of)\s*\(/g);
80
+ if (argsMatch) {
81
+ variantCount = argsMatch.length;
82
+ }
83
+ }
84
+ continue;
85
+ }
86
+ // @EnumSource(MyEnum.class)
87
+ if (nextLine.includes('@EnumSource')) {
88
+ pattern = '@EnumSource';
89
+ variantCount = 'unresolvable'; // Would need to find enum declaration
90
+ continue;
91
+ }
92
+ }
93
+ results.push({
94
+ testFilePath: filePath,
95
+ testName,
96
+ variantCount,
97
+ pattern,
98
+ line: i + 1,
99
+ });
100
+ }
101
+ return results;
102
+ }
103
+ // ─── Jest Parameterized ─────────────────────────────────────────────────────
104
+ function expandJestParameterized(filePath, content) {
105
+ var _a;
106
+ const results = [];
107
+ const lines = content.split('\n');
108
+ for (let i = 0; i < lines.length; i++) {
109
+ const line = lines[i];
110
+ // test.each([...])('name', ...)
111
+ // it.each([...])('name', ...)
112
+ // describe.each([...])('name', ...)
113
+ const eachMatch = /(?:test|it|describe)\.each\s*\(\s*\[/.exec(line);
114
+ if (eachMatch) {
115
+ // Try to extract the array and count items
116
+ const arrayContent = extractBalancedBrackets(content, content.indexOf(eachMatch[0], i > 0 ? content.indexOf(lines[i]) : 0));
117
+ const variantCount = arrayContent ? countArrayElements(arrayContent) : 'unresolvable';
118
+ // Extract test name from the next argument
119
+ const nameMatch = /\)\s*\(\s*['"`]([^'"`]+)['"`]/.exec(content.substring(content.indexOf(eachMatch[0])));
120
+ const testName = (_a = nameMatch === null || nameMatch === void 0 ? void 0 : nameMatch[1]) !== null && _a !== void 0 ? _a : 'parameterized test';
121
+ results.push({
122
+ testFilePath: filePath,
123
+ testName,
124
+ variantCount,
125
+ pattern: 'test.each',
126
+ line: i + 1,
127
+ });
128
+ }
129
+ // test.each`template`('name', ...) — tagged template form
130
+ const templateMatch = /(?:test|it|describe)\.each\s*`/.exec(line);
131
+ if (templateMatch && !eachMatch) {
132
+ // Count rows in tagged template (lines between backticks, minus header)
133
+ let rowCount = 0;
134
+ for (let j = i + 1; j < lines.length; j++) {
135
+ if (lines[j].includes('`'))
136
+ break;
137
+ if (lines[j].trim())
138
+ rowCount++;
139
+ }
140
+ const variantCount = rowCount > 0 ? rowCount : 'unresolvable';
141
+ results.push({
142
+ testFilePath: filePath,
143
+ testName: 'parameterized test',
144
+ variantCount,
145
+ pattern: 'test.each (template)',
146
+ line: i + 1,
147
+ });
148
+ }
149
+ }
150
+ return results;
151
+ }
152
+ // ─── Pytest Parameterized ───────────────────────────────────────────────────
153
+ function expandPytestParameterized(filePath, content) {
154
+ const results = [];
155
+ const lines = content.split('\n');
156
+ for (let i = 0; i < lines.length; i++) {
157
+ const line = lines[i].trim();
158
+ // @pytest.mark.parametrize("name", [...])
159
+ const paramMatch = /@pytest\.mark\.parametrize\s*\(/.exec(line);
160
+ if (paramMatch) {
161
+ // Try to extract array content and count elements
162
+ let variantCount = 'unresolvable';
163
+ // Look for the bracket content
164
+ const fullContent = lines.slice(i, Math.min(i + 20, lines.length)).join('\n');
165
+ const bracketContent = extractBalancedBrackets(fullContent, fullContent.indexOf('['));
166
+ if (bracketContent) {
167
+ variantCount = countPytestParams(bracketContent);
168
+ }
169
+ // Extract test name from following def line
170
+ let testName = 'unknown';
171
+ for (let j = i + 1; j < Math.min(i + 10, lines.length); j++) {
172
+ const defMatch = /def\s+(\w+)\s*\(/.exec(lines[j]);
173
+ if (defMatch) {
174
+ testName = defMatch[1];
175
+ break;
176
+ }
177
+ }
178
+ results.push({
179
+ testFilePath: filePath,
180
+ testName,
181
+ variantCount,
182
+ pattern: '@pytest.mark.parametrize',
183
+ line: i + 1,
184
+ });
185
+ }
186
+ }
187
+ return results;
188
+ }
189
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
190
+ function extractBalancedBrackets(content, startIndex) {
191
+ if (startIndex < 0 || startIndex >= content.length || content[startIndex] !== '[') {
192
+ return undefined;
193
+ }
194
+ let depth = 0;
195
+ let i = startIndex;
196
+ while (i < content.length) {
197
+ if (content[i] === '[')
198
+ depth++;
199
+ else if (content[i] === ']') {
200
+ depth--;
201
+ if (depth === 0) {
202
+ return content.substring(startIndex + 1, i);
203
+ }
204
+ }
205
+ i++;
206
+ }
207
+ return undefined;
208
+ }
209
+ function countArrayElements(arrayContent) {
210
+ // Count top-level elements (not nested)
211
+ let depth = 0;
212
+ let count = 1;
213
+ for (const char of arrayContent) {
214
+ if (char === '[' || char === '(' || char === '{')
215
+ depth++;
216
+ else if (char === ']' || char === ')' || char === '}')
217
+ depth--;
218
+ else if (char === ',' && depth === 0)
219
+ count++;
220
+ }
221
+ // If only whitespace, return 0
222
+ if (arrayContent.trim().length === 0)
223
+ return 0;
224
+ return count;
225
+ }
226
+ function countPytestParams(bracketContent) {
227
+ // Each top-level tuple/value is a test case
228
+ const trimmed = bracketContent.trim();
229
+ if (!trimmed)
230
+ return 0;
231
+ // Count top-level commas for simple values
232
+ // For tuples, count each (...) group
233
+ const tupleMatches = trimmed.match(/\([^)]*\)/g);
234
+ if (tupleMatches)
235
+ return tupleMatches.length;
236
+ // Otherwise count comma-separated values
237
+ return countArrayElements(trimmed);
238
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Test-to-endpoint mapper — maps test files to endpoints using multiple evidence sources.
3
+ *
4
+ * Evidence types:
5
+ * 1. Explicit URL: Direct URL string in test file
6
+ * 2. Resolved constant: URL from resolved constant/variable
7
+ * 3. Import graph: Linked via import chain
8
+ * 4. Naming convention: Test file name matches endpoint handler
9
+ * 5. Framework metadata: Framework annotations link test to endpoint
10
+ * 6. Helper traversal: URL resolved through helper function chain
11
+ * 7. Page object: URL resolved through page object pattern
12
+ */
13
+ import type { TestEndpointMapping } from './types';
14
+ import type { CoverageKnowledgeGraph } from '../../graph';
15
+ /**
16
+ * Map test files to endpoints using available evidence in the graph.
17
+ *
18
+ * @param graph - The coverage knowledge graph (from AST stage)
19
+ * @param testFiles - List of test file paths
20
+ */
21
+ export declare function mapTestsToEndpoints(graph: CoverageKnowledgeGraph, testFiles: string[]): TestEndpointMapping[];
22
+ //# sourceMappingURL=testEndpointMapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testEndpointMapper.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/tia/testEndpointMapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAG1D;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,MAAM,EAAE,GAClB,mBAAmB,EAAE,CAqFvB"}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ /**
3
+ * Test-to-endpoint mapper — maps test files to endpoints using multiple evidence sources.
4
+ *
5
+ * Evidence types:
6
+ * 1. Explicit URL: Direct URL string in test file
7
+ * 2. Resolved constant: URL from resolved constant/variable
8
+ * 3. Import graph: Linked via import chain
9
+ * 4. Naming convention: Test file name matches endpoint handler
10
+ * 5. Framework metadata: Framework annotations link test to endpoint
11
+ * 6. Helper traversal: URL resolved through helper function chain
12
+ * 7. Page object: URL resolved through page object pattern
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.mapTestsToEndpoints = mapTestsToEndpoints;
49
+ const path = __importStar(require("path"));
50
+ /**
51
+ * Map test files to endpoints using available evidence in the graph.
52
+ *
53
+ * @param graph - The coverage knowledge graph (from AST stage)
54
+ * @param testFiles - List of test file paths
55
+ */
56
+ function mapTestsToEndpoints(graph, testFiles) {
57
+ var _a, _b;
58
+ const mappings = [];
59
+ // Get all endpoint nodes
60
+ const endpointNodes = graph.getNodesByType('endpoint');
61
+ if (endpointNodes.length === 0)
62
+ return mappings;
63
+ for (const testFile of testFiles) {
64
+ const fileNodeId = `file:${testFile}`;
65
+ // 1. Check for existing 'tests' edges from AST stage
66
+ if (graph.hasNode(fileNodeId)) {
67
+ const testEdges = graph.getEdgesFrom(fileNodeId).filter((e) => e.type === 'tests');
68
+ for (const edge of testEdges) {
69
+ mappings.push({
70
+ testFilePath: testFile,
71
+ endpointId: edge.targetNodeId,
72
+ evidenceType: 'explicit-url',
73
+ confidence: 'high',
74
+ });
75
+ }
76
+ }
77
+ // 2. Check for 'asserts' edges (higher confidence than just 'tests')
78
+ if (graph.hasNode(fileNodeId)) {
79
+ const assertEdges = graph.getEdgesFrom(fileNodeId).filter((e) => e.type === 'asserts');
80
+ for (const edge of assertEdges) {
81
+ // Don't duplicate if already mapped via 'tests'
82
+ if (!mappings.some((m) => m.testFilePath === testFile && m.endpointId === edge.targetNodeId)) {
83
+ mappings.push({
84
+ testFilePath: testFile,
85
+ endpointId: edge.targetNodeId,
86
+ evidenceType: 'explicit-url',
87
+ confidence: 'high',
88
+ });
89
+ }
90
+ }
91
+ }
92
+ // 3. Naming convention matching
93
+ const testBasename = path.basename(testFile, path.extname(testFile))
94
+ .replace(/\.(test|spec|Test|Tests|Spec|IT)$/, '')
95
+ .replace(/^test_|_test$/, '')
96
+ .replace(/^Test|Test$/, '');
97
+ for (const endpoint of endpointNodes) {
98
+ const handlerName = (_b = (_a = endpoint.metadata) === null || _a === void 0 ? void 0 : _a.handlerFunction) !== null && _b !== void 0 ? _b : '';
99
+ const endpointLabel = endpoint.label.toLowerCase();
100
+ // Match test file name to handler/controller name
101
+ if (testBasename.toLowerCase().includes(handlerName.toLowerCase()) && handlerName.length > 3) {
102
+ if (!mappings.some((m) => m.testFilePath === testFile && m.endpointId === endpoint.id)) {
103
+ mappings.push({
104
+ testFilePath: testFile,
105
+ endpointId: endpoint.id,
106
+ evidenceType: 'naming-convention',
107
+ confidence: 'low',
108
+ });
109
+ }
110
+ }
111
+ }
112
+ // 4. Import graph traversal: follow imports from test file to find endpoint connections
113
+ if (graph.hasNode(fileNodeId)) {
114
+ const importEdges = graph.getEdgesFrom(fileNodeId).filter((e) => e.type === 'imports-helper');
115
+ for (const importEdge of importEdges) {
116
+ // Check if the imported file defines any endpoints
117
+ const importedFileEdges = graph.getEdgesFrom(importEdge.targetNodeId);
118
+ for (const fileEdge of importedFileEdges) {
119
+ if (fileEdge.type === 'tests' || fileEdge.type === 'defines') {
120
+ if (!mappings.some((m) => m.testFilePath === testFile && m.endpointId === fileEdge.targetNodeId)) {
121
+ mappings.push({
122
+ testFilePath: testFile,
123
+ endpointId: fileEdge.targetNodeId,
124
+ evidenceType: 'import-graph',
125
+ confidence: 'medium',
126
+ });
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+ return mappings;
134
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Test layer classifier — classifies test files into 7 layers:
3
+ * unit, component, integration, api, e2e, performance, security.
4
+ *
5
+ * Uses multiple signals: directory patterns, naming patterns,
6
+ * framework annotations, and import analysis.
7
+ */
8
+ import type { TestClassification } from './types';
9
+ /**
10
+ * Classify a test file into a layer.
11
+ *
12
+ * @param filePath - The test file path
13
+ * @param content - Optional file content for content-based classification
14
+ */
15
+ export declare function classifyTestLayer(filePath: string, content?: string): TestClassification;
16
+ //# sourceMappingURL=testLayerClassifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testLayerClassifier.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/tia/testLayerClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAyGlD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,kBAAkB,CA0DpB"}