jest-test-lineage-reporter 2.0.1 → 2.1.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 +252 -0
- package/bin/jest-lineage.js +20 -0
- package/package.json +14 -5
- package/src/MutationTester.js +1154 -0
- package/src/__tests__/assertion-test.test.ts +59 -0
- package/src/__tests__/calculator.test.ts +30 -0
- package/src/__tests__/depth-example.test.ts +237 -0
- package/src/__tests__/gc-pressure-example.test.ts +169 -0
- package/src/__tests__/performance-example.test.ts +83 -0
- package/src/__tests__/quality-example.test.ts +122 -0
- package/src/__tests__/survived-mutations-example.test.ts +32 -0
- package/src/__tests__/truly-weak-example.test.ts +90 -0
- package/src/__tests__/weak-test-example.test.ts +222 -0
- package/src/babel-plugin-mutation-tester.js +402 -0
- package/src/calculator.ts +12 -0
- package/src/cli/commands/analyze.js +91 -0
- package/src/cli/commands/mutate.js +89 -0
- package/src/cli/commands/query.js +107 -0
- package/src/cli/commands/report.js +65 -0
- package/src/cli/commands/test.js +56 -0
- package/src/cli/index.js +89 -0
- package/src/cli/utils/config-loader.js +114 -0
- package/src/cli/utils/data-loader.js +118 -0
- package/src/cli/utils/jest-runner.js +105 -0
- package/src/cli/utils/output-formatter.js +126 -0
- package/src/depth-example.ts +66 -0
- package/src/gc-pressure-example.ts +158 -0
- package/src/global.d.ts +7 -0
- package/src/mcp/server.js +469 -0
- package/src/performance-example.ts +82 -0
- package/src/quality-example.ts +79 -0
- package/src/survived-mutations-example.ts +19 -0
- package/src/truly-weak-example.ts +37 -0
- package/src/weak-test-example.ts +91 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { directFunction } from '../depth-example';
|
|
2
|
+
|
|
3
|
+
describe('Assertion Counting Test', () => {
|
|
4
|
+
test('should count multiple expect statements correctly', () => {
|
|
5
|
+
// This test has many expect statements to test assertion counting
|
|
6
|
+
|
|
7
|
+
const result1 = directFunction(5);
|
|
8
|
+
expect(result1).toBe(10);
|
|
9
|
+
expect(result1).toBeGreaterThan(5);
|
|
10
|
+
expect(result1).toBeLessThan(20);
|
|
11
|
+
|
|
12
|
+
const result2 = directFunction(0);
|
|
13
|
+
expect(result2).toBe(0);
|
|
14
|
+
expect(result2).toEqual(0);
|
|
15
|
+
expect(result2).not.toBe(1);
|
|
16
|
+
|
|
17
|
+
const result3 = directFunction(-5);
|
|
18
|
+
expect(result3).toBe(-10);
|
|
19
|
+
expect(result3).toBeLessThan(0);
|
|
20
|
+
expect(result3).toBeGreaterThan(-20);
|
|
21
|
+
|
|
22
|
+
// Test arrays and objects
|
|
23
|
+
const results = [result1, result2, result3];
|
|
24
|
+
expect(results).toHaveLength(3);
|
|
25
|
+
expect(results).toContain(10);
|
|
26
|
+
expect(results).toContain(0);
|
|
27
|
+
expect(results).toContain(-10);
|
|
28
|
+
|
|
29
|
+
// Test properties
|
|
30
|
+
const obj = { value: result1 };
|
|
31
|
+
expect(obj).toHaveProperty('value');
|
|
32
|
+
expect(obj).toHaveProperty('value', 10);
|
|
33
|
+
|
|
34
|
+
// Test null/undefined
|
|
35
|
+
expect(result1).toBeDefined();
|
|
36
|
+
expect(result1).not.toBeNull();
|
|
37
|
+
expect(result1).not.toBeUndefined();
|
|
38
|
+
|
|
39
|
+
// Test truthiness
|
|
40
|
+
expect(result1).toBeTruthy();
|
|
41
|
+
expect(result2).toBeFalsy();
|
|
42
|
+
|
|
43
|
+
// Test error handling
|
|
44
|
+
expect(() => {
|
|
45
|
+
if (result1 < 0) {
|
|
46
|
+
throw new Error('Should not be negative');
|
|
47
|
+
}
|
|
48
|
+
}).not.toThrow();
|
|
49
|
+
|
|
50
|
+
// This test should show:
|
|
51
|
+
// - 22+ expect statements (high assertion count)
|
|
52
|
+
// - Error handling with expect().not.toThrow()
|
|
53
|
+
// - Property testing with toHaveProperty()
|
|
54
|
+
// - Array testing with toContain() and toHaveLength()
|
|
55
|
+
// - Boundary testing with toBeGreaterThan/toBeLessThan
|
|
56
|
+
// - Null/undefined testing
|
|
57
|
+
// - Truthiness testing
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { add, subtract, multiply } from '../calculator';
|
|
2
|
+
|
|
3
|
+
describe('Calculator', () => {
|
|
4
|
+
it('should correctly add two numbers', () => {
|
|
5
|
+
expect(add(1, 2)).toBe(3);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should subtract a smaller number from a larger one', () => {
|
|
9
|
+
expect(subtract(5, 2)).toBe(3); // This will hit line 9
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should subtract a larger number from a smaller one and return a positive result', () => {
|
|
13
|
+
expect(subtract(2, 5)).toBe(3); // This will hit line 7
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// This test covers the same line as the first subtraction test, which our report will show.
|
|
17
|
+
it('should handle zero correctly in subtraction', () => {
|
|
18
|
+
expect(subtract(10, 0)).toBe(10); // This will also hit line 9
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// This test ONLY calls multiply, so it will show different coverage
|
|
22
|
+
it('should multiply two numbers correctly', () => {
|
|
23
|
+
expect(multiply(3, 4)).toBe(12); // This will ONLY hit line 13 (multiply function)
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// This test ONLY calls add, so it will show different coverage
|
|
27
|
+
it('should add negative numbers', () => {
|
|
28
|
+
expect(add(-5, -3)).toBe(-8); // This will ONLY hit lines 2-3 (add function)
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import {
|
|
2
|
+
directFunction,
|
|
3
|
+
oneLevel,
|
|
4
|
+
twoLevels,
|
|
5
|
+
threeLevels,
|
|
6
|
+
complexFunction,
|
|
7
|
+
recursiveFunction,
|
|
8
|
+
memoryLeakFunction,
|
|
9
|
+
clearMemoryLeaks,
|
|
10
|
+
getMemoryLeakCount
|
|
11
|
+
} from '../depth-example';
|
|
12
|
+
|
|
13
|
+
describe('Call Depth Tracking Examples', () => {
|
|
14
|
+
test('should call directFunction directly (depth 1)', () => {
|
|
15
|
+
const result = directFunction(5);
|
|
16
|
+
expect(result).toBe(10);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('should call directFunction through oneLevel (depth 2)', () => {
|
|
20
|
+
const result = oneLevel(5);
|
|
21
|
+
expect(result).toBe(11);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should call directFunction through twoLevels (depth 3)', () => {
|
|
25
|
+
const result = twoLevels(5);
|
|
26
|
+
expect(result).toBe(12);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('should call directFunction through threeLevels (depth 4)', () => {
|
|
30
|
+
const result = threeLevels(5);
|
|
31
|
+
expect(result).toBe(13);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should call directFunction at multiple depths in complexFunction', () => {
|
|
35
|
+
const result = complexFunction(5);
|
|
36
|
+
expect(result).toBe(33); // 10 + 11 + 12 = 33
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should call directFunction through recursive calls (very deep)', () => {
|
|
40
|
+
const result = recursiveFunction(5);
|
|
41
|
+
expect(result).toBe(13); // 10 + 1 + 1 + 1 = 13
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should demonstrate memory leak detection with large allocations', () => {
|
|
45
|
+
// This test intentionally creates memory leaks to demonstrate tracking
|
|
46
|
+
const largeArrays = [];
|
|
47
|
+
|
|
48
|
+
// Create multiple large arrays (each >1MB) to trigger memory leak detection
|
|
49
|
+
for (let i = 0; i < 3; i++) {
|
|
50
|
+
// Allocate ~2MB array (will trigger 🚨LEAK alert)
|
|
51
|
+
const largeArray = new Array(500000).fill(0).map((_, index) => ({
|
|
52
|
+
id: index,
|
|
53
|
+
data: `Large data string for item ${index} with extra padding to increase memory usage`,
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
metadata: {
|
|
56
|
+
created: new Date(),
|
|
57
|
+
processed: false,
|
|
58
|
+
tags: ['memory', 'test', 'large', 'allocation']
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
largeArrays.push(largeArray);
|
|
63
|
+
|
|
64
|
+
// Call our function to track memory usage at different call depths
|
|
65
|
+
const result = directFunction(i);
|
|
66
|
+
expect(result).toBe(i * 2);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Verify we created the expected number of arrays
|
|
70
|
+
expect(largeArrays).toHaveLength(3);
|
|
71
|
+
expect(largeArrays[0]).toHaveLength(500000);
|
|
72
|
+
|
|
73
|
+
// Test edge cases with memory allocation
|
|
74
|
+
expect(largeArrays[0][0]).toHaveProperty('id', 0);
|
|
75
|
+
expect(largeArrays[0][0]).toHaveProperty('data');
|
|
76
|
+
expect(largeArrays[0][0].metadata).toHaveProperty('tags');
|
|
77
|
+
expect(largeArrays[0][0].metadata.tags).toContain('memory');
|
|
78
|
+
|
|
79
|
+
// Test error conditions
|
|
80
|
+
expect(() => {
|
|
81
|
+
if (largeArrays.length === 0) {
|
|
82
|
+
throw new Error('No arrays created');
|
|
83
|
+
}
|
|
84
|
+
}).not.toThrow();
|
|
85
|
+
|
|
86
|
+
// Test boundary conditions
|
|
87
|
+
expect(largeArrays[2][499999]).toHaveProperty('id', 499999);
|
|
88
|
+
|
|
89
|
+
// This should show high memory usage, multiple assertions, and good error handling
|
|
90
|
+
// Expected quality metrics:
|
|
91
|
+
// - High assertion count (8+ expect statements)
|
|
92
|
+
// - Error handling (try/catch equivalent with expect().not.toThrow())
|
|
93
|
+
// - Edge case testing (boundary values, null checks)
|
|
94
|
+
// - Memory leak detection (large allocations)
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should demonstrate GC pressure with many small allocations', () => {
|
|
98
|
+
const smallObjects = [];
|
|
99
|
+
|
|
100
|
+
// Create many small objects to trigger GC pressure detection
|
|
101
|
+
for (let i = 0; i < 1000; i++) {
|
|
102
|
+
// Small allocations (<1KB each) to trigger 🗑️GC alert
|
|
103
|
+
const smallObj = {
|
|
104
|
+
id: i,
|
|
105
|
+
value: Math.random(),
|
|
106
|
+
processed: false
|
|
107
|
+
};
|
|
108
|
+
smallObjects.push(smallObj);
|
|
109
|
+
|
|
110
|
+
// Call function at different depths to test performance impact
|
|
111
|
+
if (i % 100 === 0) {
|
|
112
|
+
const result = oneLevel(i);
|
|
113
|
+
expect(result).toBeGreaterThan(i);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
expect(smallObjects).toHaveLength(1000);
|
|
118
|
+
expect(smallObjects[999]).toHaveProperty('id', 999);
|
|
119
|
+
|
|
120
|
+
// This should show GC pressure but smaller memory footprint
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should demonstrate slow execution patterns', () => {
|
|
124
|
+
const results = [];
|
|
125
|
+
|
|
126
|
+
// Create intentionally variable performance to trigger slow execution detection
|
|
127
|
+
for (let i = 0; i < 5; i++) {
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
|
|
130
|
+
// Sometimes do heavy work, sometimes light work (creates performance variance)
|
|
131
|
+
if (i % 2 === 0) {
|
|
132
|
+
// Heavy work - should be slower
|
|
133
|
+
let heavyResult = 0;
|
|
134
|
+
for (let j = 0; j < 10000; j++) {
|
|
135
|
+
heavyResult += Math.sin(j) * Math.cos(j);
|
|
136
|
+
}
|
|
137
|
+
results.push(heavyResult);
|
|
138
|
+
} else {
|
|
139
|
+
// Light work - should be faster
|
|
140
|
+
results.push(i * 2);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const result = directFunction(i);
|
|
144
|
+
expect(result).toBe(i * 2);
|
|
145
|
+
|
|
146
|
+
const endTime = Date.now();
|
|
147
|
+
expect(endTime).toBeGreaterThanOrEqual(startTime);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
expect(results).toHaveLength(5);
|
|
151
|
+
|
|
152
|
+
// This should show performance variance and trigger 🐌SLOW alert
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('should create actual memory leaks with large objects', () => {
|
|
156
|
+
// Clear any existing leaks first
|
|
157
|
+
const initialCount = getMemoryLeakCount();
|
|
158
|
+
expect(initialCount).toBeGreaterThanOrEqual(0);
|
|
159
|
+
|
|
160
|
+
// Create multiple memory leaks with large objects
|
|
161
|
+
for (let i = 0; i < 3; i++) {
|
|
162
|
+
// Each call creates ~1MB of leaked memory (1000 items * 1KB each)
|
|
163
|
+
const result = memoryLeakFunction(1000);
|
|
164
|
+
expect(result).toBe(1000 * 2); // directFunction returns x * 2
|
|
165
|
+
|
|
166
|
+
// Verify memory leak count is increasing
|
|
167
|
+
const currentCount = getMemoryLeakCount();
|
|
168
|
+
expect(currentCount).toBe(initialCount + i + 1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Verify we have created 3 memory leaks
|
|
172
|
+
const finalCount = getMemoryLeakCount();
|
|
173
|
+
expect(finalCount).toBe(initialCount + 3);
|
|
174
|
+
|
|
175
|
+
// This test should show:
|
|
176
|
+
// - High memory usage (3MB+ leaked)
|
|
177
|
+
// - 🚨LEAK alerts in console
|
|
178
|
+
// - Multiple expect() statements (good assertion count)
|
|
179
|
+
// - Error handling with expect().toBe() validations
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('should create massive memory leak for testing', () => {
|
|
183
|
+
// Create a very large memory leak to ensure detection
|
|
184
|
+
const initialMemoryCount = getMemoryLeakCount();
|
|
185
|
+
|
|
186
|
+
// Create 5 large objects (each ~2MB)
|
|
187
|
+
for (let i = 0; i < 5; i++) {
|
|
188
|
+
const result = memoryLeakFunction(2000); // 2000 items * ~1KB each = ~2MB
|
|
189
|
+
expect(result).toBe(2000 * 2);
|
|
190
|
+
|
|
191
|
+
// Verify the leak is growing
|
|
192
|
+
expect(getMemoryLeakCount()).toBeGreaterThan(initialMemoryCount + i);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Verify total memory leaks
|
|
196
|
+
const totalLeaks = getMemoryLeakCount();
|
|
197
|
+
expect(totalLeaks).toBeGreaterThanOrEqual(initialMemoryCount + 5);
|
|
198
|
+
|
|
199
|
+
// Test edge cases
|
|
200
|
+
expect(() => memoryLeakFunction(0)).not.toThrow();
|
|
201
|
+
expect(memoryLeakFunction(0)).toBe(0);
|
|
202
|
+
|
|
203
|
+
// Test error conditions
|
|
204
|
+
expect(() => {
|
|
205
|
+
if (totalLeaks < 0) {
|
|
206
|
+
throw new Error('Invalid leak count');
|
|
207
|
+
}
|
|
208
|
+
}).not.toThrow();
|
|
209
|
+
|
|
210
|
+
// This should create ~10MB of leaked memory and trigger multiple 🚨LEAK alerts
|
|
211
|
+
// Quality metrics should show:
|
|
212
|
+
// - High assertion count (8+ expect statements)
|
|
213
|
+
// - Good error handling (expect().not.toThrow())
|
|
214
|
+
// - Edge case testing (zero values, negative checks)
|
|
215
|
+
// - Boundary testing (memory thresholds)
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('should demonstrate memory cleanup', () => {
|
|
219
|
+
// Create some leaks first
|
|
220
|
+
const result1 = memoryLeakFunction(500);
|
|
221
|
+
const result2 = memoryLeakFunction(500);
|
|
222
|
+
|
|
223
|
+
expect(result1).toBe(1000);
|
|
224
|
+
expect(result2).toBe(1000);
|
|
225
|
+
expect(getMemoryLeakCount()).toBeGreaterThanOrEqual(2);
|
|
226
|
+
|
|
227
|
+
// Clear all memory leaks
|
|
228
|
+
const clearedCount = clearMemoryLeaks();
|
|
229
|
+
expect(clearedCount).toBeGreaterThanOrEqual(2);
|
|
230
|
+
expect(getMemoryLeakCount()).toBe(0);
|
|
231
|
+
|
|
232
|
+
// Verify cleanup worked
|
|
233
|
+
expect(getMemoryLeakCount()).toBe(0);
|
|
234
|
+
|
|
235
|
+
// This test shows proper cleanup and should have fewer memory issues
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {
|
|
2
|
+
badGCPressureFunction,
|
|
3
|
+
goodGCPressureFunction,
|
|
4
|
+
badStringConcatenation,
|
|
5
|
+
goodStringConcatenation,
|
|
6
|
+
badArrayOperations,
|
|
7
|
+
goodArrayOperations,
|
|
8
|
+
objectPoolExample
|
|
9
|
+
} from '../gc-pressure-example';
|
|
10
|
+
|
|
11
|
+
describe.skip('GC Pressure Examples', () => {
|
|
12
|
+
test.skip('should demonstrate BAD GC pressure with many small objects', () => {
|
|
13
|
+
// This test creates many small objects and should trigger 🗑️GC alerts
|
|
14
|
+
|
|
15
|
+
const result1 = badGCPressureFunction(1000); // Creates 2000+ small objects
|
|
16
|
+
expect(result1).toBeGreaterThan(0);
|
|
17
|
+
expect(typeof result1).toBe('number');
|
|
18
|
+
|
|
19
|
+
const result2 = badGCPressureFunction(500); // Creates 1000+ small objects
|
|
20
|
+
expect(result2).toBeGreaterThan(0);
|
|
21
|
+
expect(result2).toBeLessThan(result1);
|
|
22
|
+
|
|
23
|
+
// Test edge cases
|
|
24
|
+
expect(badGCPressureFunction(0)).toBe(0);
|
|
25
|
+
expect(badGCPressureFunction(1)).toBeGreaterThan(0);
|
|
26
|
+
|
|
27
|
+
// This should show:
|
|
28
|
+
// - 🗑️GC alerts due to many small object allocations
|
|
29
|
+
// - High memory churn but relatively small total memory
|
|
30
|
+
// - Multiple expect statements for good test quality
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should demonstrate GOOD GC behavior with object reuse', () => {
|
|
34
|
+
// This test reuses objects and should have minimal GC pressure
|
|
35
|
+
|
|
36
|
+
const result1 = goodGCPressureFunction(1000); // Reuses same objects
|
|
37
|
+
expect(result1).toBeGreaterThan(0);
|
|
38
|
+
expect(typeof result1).toBe('number');
|
|
39
|
+
|
|
40
|
+
const result2 = goodGCPressureFunction(500);
|
|
41
|
+
expect(result2).toBeGreaterThan(0);
|
|
42
|
+
expect(result2).toBeLessThan(result1);
|
|
43
|
+
|
|
44
|
+
// Test edge cases
|
|
45
|
+
expect(goodGCPressureFunction(0)).toBe(0);
|
|
46
|
+
expect(goodGCPressureFunction(1)).toBeGreaterThan(0);
|
|
47
|
+
|
|
48
|
+
// This should show:
|
|
49
|
+
// - Minimal or no 🗑️GC alerts
|
|
50
|
+
// - Lower memory usage than the bad example
|
|
51
|
+
// - Better performance consistency
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('should demonstrate BAD string concatenation GC pressure', () => {
|
|
55
|
+
// String concatenation in loops creates many temporary strings
|
|
56
|
+
|
|
57
|
+
const items = Array.from({ length: 1000 }, (_, i) => `item${i}`);
|
|
58
|
+
|
|
59
|
+
const result = badStringConcatenation(items);
|
|
60
|
+
expect(result).toContain('item0');
|
|
61
|
+
expect(result).toContain('item999');
|
|
62
|
+
expect(result.split(', ')).toHaveLength(1001); // 1000 items + empty string at end
|
|
63
|
+
|
|
64
|
+
// Test with smaller arrays
|
|
65
|
+
const smallItems = ['a', 'b', 'c'];
|
|
66
|
+
const smallResult = badStringConcatenation(smallItems);
|
|
67
|
+
expect(smallResult).toBe('a, b, c, ');
|
|
68
|
+
|
|
69
|
+
// This should trigger 🗑️GC due to many temporary string objects
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('should demonstrate GOOD string concatenation', () => {
|
|
73
|
+
// Array.join() creates only one final string
|
|
74
|
+
|
|
75
|
+
const items = Array.from({ length: 1000 }, (_, i) => `item${i}`);
|
|
76
|
+
|
|
77
|
+
const result = goodStringConcatenation(items);
|
|
78
|
+
expect(result).toContain('item0');
|
|
79
|
+
expect(result).toContain('item999');
|
|
80
|
+
expect(result.split(', ')).toHaveLength(1000);
|
|
81
|
+
|
|
82
|
+
// Test with smaller arrays
|
|
83
|
+
const smallItems = ['a', 'b', 'c'];
|
|
84
|
+
const smallResult = goodStringConcatenation(smallItems);
|
|
85
|
+
expect(smallResult).toBe('a, b, c');
|
|
86
|
+
|
|
87
|
+
// This should have minimal GC pressure
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should demonstrate BAD array operations with multiple allocations', () => {
|
|
91
|
+
// Chained array operations create many intermediate arrays
|
|
92
|
+
|
|
93
|
+
const numbers = Array.from({ length: 1000 }, (_, i) => i);
|
|
94
|
+
|
|
95
|
+
const result = badArrayOperations(numbers);
|
|
96
|
+
expect(Array.isArray(result)).toBe(true);
|
|
97
|
+
expect(result.length).toBeGreaterThan(0);
|
|
98
|
+
expect(result.every(x => x % 2 === 0)).toBe(true);
|
|
99
|
+
expect(result.every(x => x > 10)).toBe(true);
|
|
100
|
+
|
|
101
|
+
// Test edge cases
|
|
102
|
+
expect(badArrayOperations([])).toEqual([]);
|
|
103
|
+
expect(badArrayOperations([1, 2, 3])).toEqual([]);
|
|
104
|
+
expect(badArrayOperations([10, 20, 30])).toEqual([22, 42, 62]);
|
|
105
|
+
|
|
106
|
+
// This should trigger 🗑️GC due to multiple intermediate arrays
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('should demonstrate GOOD array operations with single allocation', () => {
|
|
110
|
+
// Single reduce operation creates only one final array
|
|
111
|
+
|
|
112
|
+
const numbers = Array.from({ length: 1000 }, (_, i) => i);
|
|
113
|
+
|
|
114
|
+
const result = goodArrayOperations(numbers);
|
|
115
|
+
expect(Array.isArray(result)).toBe(true);
|
|
116
|
+
expect(result.length).toBeGreaterThan(0);
|
|
117
|
+
expect(result.every(x => x % 2 === 0)).toBe(true);
|
|
118
|
+
expect(result.every(x => x > 10)).toBe(true);
|
|
119
|
+
|
|
120
|
+
// Test edge cases
|
|
121
|
+
expect(goodArrayOperations([])).toEqual([]);
|
|
122
|
+
expect(goodArrayOperations([1, 2, 3])).toEqual([]);
|
|
123
|
+
expect(goodArrayOperations([10, 20, 30])).toEqual([22, 42, 62]);
|
|
124
|
+
|
|
125
|
+
// This should have minimal GC pressure
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('should demonstrate object pooling for optimal GC behavior', () => {
|
|
129
|
+
// Object pooling reuses pre-allocated objects
|
|
130
|
+
|
|
131
|
+
const result1 = objectPoolExample(1000);
|
|
132
|
+
expect(result1).toBeGreaterThan(0);
|
|
133
|
+
expect(typeof result1).toBe('number');
|
|
134
|
+
|
|
135
|
+
const result2 = objectPoolExample(500);
|
|
136
|
+
expect(result2).toBeGreaterThan(0);
|
|
137
|
+
expect(result2).toBeLessThan(result1);
|
|
138
|
+
|
|
139
|
+
// Test edge cases
|
|
140
|
+
expect(objectPoolExample(0)).toBe(0);
|
|
141
|
+
expect(objectPoolExample(1)).toBeGreaterThan(0);
|
|
142
|
+
|
|
143
|
+
// This should have the best GC behavior - minimal allocations
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('should compare all GC pressure patterns', () => {
|
|
147
|
+
// Compare all patterns to show the difference
|
|
148
|
+
|
|
149
|
+
const testSize = 100;
|
|
150
|
+
|
|
151
|
+
const badResult = badGCPressureFunction(testSize);
|
|
152
|
+
const goodResult = goodGCPressureFunction(testSize);
|
|
153
|
+
const poolResult = objectPoolExample(testSize);
|
|
154
|
+
|
|
155
|
+
// All should produce similar numerical results
|
|
156
|
+
expect(badResult).toBeGreaterThan(0);
|
|
157
|
+
expect(goodResult).toBeGreaterThan(0);
|
|
158
|
+
expect(poolResult).toBeGreaterThan(0);
|
|
159
|
+
|
|
160
|
+
// But GC behavior should be very different:
|
|
161
|
+
// - badResult: High 🗑️GC pressure
|
|
162
|
+
// - goodResult: Medium 🗑️GC pressure
|
|
163
|
+
// - poolResult: Minimal 🗑️GC pressure
|
|
164
|
+
|
|
165
|
+
expect(typeof badResult).toBe('number');
|
|
166
|
+
expect(typeof goodResult).toBe('number');
|
|
167
|
+
expect(typeof poolResult).toBe('number');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lightweightFunction,
|
|
3
|
+
mediumFunction,
|
|
4
|
+
heavyFunction,
|
|
5
|
+
memoryIntensiveFunction,
|
|
6
|
+
recursiveFunction,
|
|
7
|
+
nestedCallsFunction,
|
|
8
|
+
mixedPerformanceFunction,
|
|
9
|
+
performanceVariableFunction
|
|
10
|
+
} from '../performance-example';
|
|
11
|
+
|
|
12
|
+
describe.skip('Performance Tracking Examples', () => {
|
|
13
|
+
test('should track lightweight function performance', () => {
|
|
14
|
+
// This should show minimal CPU cycles
|
|
15
|
+
const result = lightweightFunction(5);
|
|
16
|
+
expect(result).toBe(6);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('should track medium function performance', () => {
|
|
20
|
+
// This should show moderate CPU cycles
|
|
21
|
+
const result = mediumFunction(4);
|
|
22
|
+
expect(result).toBeGreaterThan(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should track heavy function performance', () => {
|
|
26
|
+
// This should show high CPU cycles
|
|
27
|
+
const result = heavyFunction(2);
|
|
28
|
+
expect(result).toBeGreaterThan(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should track memory intensive function', () => {
|
|
32
|
+
// This should show memory allocation patterns
|
|
33
|
+
const result = memoryIntensiveFunction(1000);
|
|
34
|
+
expect(result).toHaveLength(1000);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should track recursive function with exponential complexity', () => {
|
|
38
|
+
// This should show very high CPU cycles due to recursion
|
|
39
|
+
const result = recursiveFunction(5);
|
|
40
|
+
expect(result).toBeGreaterThan(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should track nested calls with different depths', () => {
|
|
44
|
+
// This should show performance at different call depths
|
|
45
|
+
const result = nestedCallsFunction(10);
|
|
46
|
+
expect(result).toBeGreaterThan(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should track mixed performance patterns', () => {
|
|
50
|
+
// This should show variable performance within one test
|
|
51
|
+
const result = mixedPerformanceFunction(10);
|
|
52
|
+
expect(result).toBeGreaterThan(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('should track fast mode performance', () => {
|
|
56
|
+
// Fast execution path
|
|
57
|
+
const result = performanceVariableFunction('fast');
|
|
58
|
+
expect(result).toBe(43);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('should track medium mode performance', () => {
|
|
62
|
+
// Medium execution path
|
|
63
|
+
const result = performanceVariableFunction('medium');
|
|
64
|
+
expect(result).toBeGreaterThan(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('should track slow mode performance', () => {
|
|
68
|
+
// Slow execution path
|
|
69
|
+
const result = performanceVariableFunction('slow');
|
|
70
|
+
expect(result).toBeGreaterThan(0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should demonstrate performance hotspot', () => {
|
|
74
|
+
// Call heavy function multiple times to create hotspot
|
|
75
|
+
let total = 0;
|
|
76
|
+
let i = 0;
|
|
77
|
+
while (i < 3) {
|
|
78
|
+
total += heavyFunction(i);
|
|
79
|
+
i++;
|
|
80
|
+
}
|
|
81
|
+
expect(total).toBeGreaterThan(0);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
simpleFunction,
|
|
3
|
+
complexFunction,
|
|
4
|
+
asyncFunction,
|
|
5
|
+
errorProneFunction,
|
|
6
|
+
wellTestedFunction,
|
|
7
|
+
Calculator
|
|
8
|
+
} from '../quality-example';
|
|
9
|
+
|
|
10
|
+
describe('Test Quality Examples', () => {
|
|
11
|
+
// High quality test - good assertions, error handling, edge cases
|
|
12
|
+
test('wellTestedFunction should handle all edge cases properly', async () => {
|
|
13
|
+
// Test normal cases
|
|
14
|
+
expect(wellTestedFunction(5, 3)).toBe(8);
|
|
15
|
+
expect(wellTestedFunction(0, 0)).toBe(0);
|
|
16
|
+
expect(wellTestedFunction(1.5, 2.5)).toBe(4);
|
|
17
|
+
|
|
18
|
+
// Test error cases
|
|
19
|
+
expect(() => wellTestedFunction(null as any, 5)).toThrow('Parameter a is required');
|
|
20
|
+
expect(() => wellTestedFunction(5, undefined as any)).toThrow('Parameter b is required');
|
|
21
|
+
expect(() => wellTestedFunction('5' as any, 3)).toThrow('Both parameters must be numbers');
|
|
22
|
+
expect(() => wellTestedFunction(-1, 5)).toThrow('Parameters must be non-negative');
|
|
23
|
+
expect(() => wellTestedFunction(5, -1)).toThrow('Parameters must be non-negative');
|
|
24
|
+
|
|
25
|
+
// Test boundary cases
|
|
26
|
+
expect(wellTestedFunction(Number.MAX_SAFE_INTEGER, 0)).toBe(Number.MAX_SAFE_INTEGER);
|
|
27
|
+
expect(wellTestedFunction(0.1, 0.2)).toBeCloseTo(0.3);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Medium quality test - some assertions, basic testing
|
|
31
|
+
test('complexFunction should handle different data types', () => {
|
|
32
|
+
expect(complexFunction('hello')).toBe('HELLO');
|
|
33
|
+
expect(complexFunction(5)).toBe(25);
|
|
34
|
+
expect(complexFunction(-3)).toBe(3);
|
|
35
|
+
expect(complexFunction(0)).toBe(1);
|
|
36
|
+
expect(complexFunction([1, 2, 3])).toEqual([2, 4, 6]);
|
|
37
|
+
expect(complexFunction({ key: 'value' })).toBe('{"key":"value"}');
|
|
38
|
+
|
|
39
|
+
// Test error cases
|
|
40
|
+
expect(() => complexFunction(null)).toThrow('Data is required');
|
|
41
|
+
expect(() => complexFunction(undefined)).toThrow('Data is required');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Low quality test - minimal assertions, no error handling
|
|
45
|
+
test('simpleFunction basic test', () => {
|
|
46
|
+
expect(simpleFunction(5)).toBe(10);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Async test with proper error handling
|
|
50
|
+
test('asyncFunction should handle async operations correctly', async () => {
|
|
51
|
+
const result = await asyncFunction(10);
|
|
52
|
+
expect(result).toBe('Completed after 10ms');
|
|
53
|
+
|
|
54
|
+
// Test error case
|
|
55
|
+
await expect(asyncFunction(-1)).rejects.toThrow('Delay cannot be negative');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Poor quality test - no error handling for error-prone function
|
|
59
|
+
test('errorProneFunction test', () => {
|
|
60
|
+
expect(errorProneFunction('hello')).toBe('HELLO');
|
|
61
|
+
expect(errorProneFunction(123)).toBe('123');
|
|
62
|
+
// Missing: null/undefined tests that would reveal bugs
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Test with mocking (affects isolation score)
|
|
66
|
+
test('Calculator with mocking', () => {
|
|
67
|
+
const calculator = new Calculator();
|
|
68
|
+
const spy = jest.spyOn(calculator, 'add');
|
|
69
|
+
|
|
70
|
+
calculator.add(2, 3);
|
|
71
|
+
expect(spy).toHaveBeenCalledWith(2, 3);
|
|
72
|
+
expect(calculator.getHistory()).toEqual([5]);
|
|
73
|
+
|
|
74
|
+
spy.mockRestore();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Long test (test smell)
|
|
78
|
+
test('long test with many assertions', () => {
|
|
79
|
+
const calc = new Calculator();
|
|
80
|
+
|
|
81
|
+
// Too many assertions in one test
|
|
82
|
+
expect(calc.add(1, 1)).toBe(2);
|
|
83
|
+
expect(calc.add(2, 2)).toBe(4);
|
|
84
|
+
expect(calc.add(3, 3)).toBe(6);
|
|
85
|
+
expect(calc.add(4, 4)).toBe(8);
|
|
86
|
+
expect(calc.add(5, 5)).toBe(10);
|
|
87
|
+
expect(calc.add(6, 6)).toBe(12);
|
|
88
|
+
expect(calc.add(7, 7)).toBe(14);
|
|
89
|
+
expect(calc.add(8, 8)).toBe(16);
|
|
90
|
+
expect(calc.add(9, 9)).toBe(18);
|
|
91
|
+
expect(calc.add(10, 10)).toBe(20);
|
|
92
|
+
expect(calc.add(11, 11)).toBe(22);
|
|
93
|
+
expect(calc.add(12, 12)).toBe(24);
|
|
94
|
+
|
|
95
|
+
expect(calc.getHistory()).toHaveLength(12);
|
|
96
|
+
calc.clearHistory();
|
|
97
|
+
expect(calc.getHistory()).toHaveLength(0);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Test with complex control flow (high complexity)
|
|
101
|
+
test('complex control flow test', () => {
|
|
102
|
+
let result = 0;
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < 10; i++) {
|
|
105
|
+
if (i % 2 === 0) {
|
|
106
|
+
if (i % 4 === 0) {
|
|
107
|
+
result += complexFunction(i);
|
|
108
|
+
} else {
|
|
109
|
+
result += simpleFunction(i);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
if (i > 5) {
|
|
113
|
+
result -= i;
|
|
114
|
+
} else {
|
|
115
|
+
result += i;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
expect(result).toBeGreaterThan(0);
|
|
121
|
+
});
|
|
122
|
+
});
|