jest-test-lineage-reporter 2.0.2 → 2.1.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.
- package/README.md +281 -0
- package/bin/jest-lineage.js +20 -0
- package/package.json +14 -7
- 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/calculator.ts +12 -0
- package/src/cli/commands/analyze.js +91 -0
- package/src/cli/commands/init.js +214 -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 +99 -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,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
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { demonstrateSurvivedMutations, anotherWeakFunction } from '../survived-mutations-example';
|
|
2
|
+
|
|
3
|
+
describe('Survived Mutations Example', () => {
|
|
4
|
+
// This test is intentionally terrible to demonstrate survived mutations
|
|
5
|
+
|
|
6
|
+
describe('demonstrateSurvivedMutations', () => {
|
|
7
|
+
it('should just call the function', () => {
|
|
8
|
+
// This test literally does NOTHING except call the function
|
|
9
|
+
// No assertions whatsoever!
|
|
10
|
+
|
|
11
|
+
demonstrateSurvivedMutations(42); // Covers input === 42, return 100
|
|
12
|
+
demonstrateSurvivedMutations(60); // Covers input > 50, return input * 2
|
|
13
|
+
demonstrateSurvivedMutations(5); // Covers default case, return input + 10
|
|
14
|
+
|
|
15
|
+
// NO EXPECTATIONS AT ALL!
|
|
16
|
+
// This means ALL mutations will survive because we don't check anything
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('anotherWeakFunction', () => {
|
|
21
|
+
it('should execute the function', () => {
|
|
22
|
+
// This test calls the function but makes NO assertions!
|
|
23
|
+
|
|
24
|
+
anotherWeakFunction(10, 5); // Covers x > y, return true
|
|
25
|
+
anotherWeakFunction(3, 8); // Covers x <= y, return false
|
|
26
|
+
|
|
27
|
+
// NO EXPECTATIONS AT ALL!
|
|
28
|
+
// return true -> return false: SURVIVES
|
|
29
|
+
// return false -> return true: SURVIVES
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { definitelyWillSurvive, anotherSurvivor, booleanSurvivor, guaranteedSurvivor } from '../truly-weak-example';
|
|
2
|
+
|
|
3
|
+
describe('Truly Weak Example - Guaranteed Survived Mutations', () => {
|
|
4
|
+
|
|
5
|
+
describe('definitelyWillSurvive', () => {
|
|
6
|
+
it('should just execute', () => {
|
|
7
|
+
// This test literally does NOTHING except call the function
|
|
8
|
+
// It covers all branches but validates NOTHING
|
|
9
|
+
|
|
10
|
+
definitelyWillSurvive(5); // Covers x === 5, return 42
|
|
11
|
+
definitelyWillSurvive(15); // Covers x > 10, return x + 100
|
|
12
|
+
definitelyWillSurvive(3); // Covers default case, return x * 2
|
|
13
|
+
|
|
14
|
+
// NO ASSERTIONS WHATSOEVER!
|
|
15
|
+
// ALL mutations will survive:
|
|
16
|
+
// return 42 -> return 0: SURVIVES
|
|
17
|
+
// return 42 -> return 1: SURVIVES
|
|
18
|
+
// x + 100 -> x - 100: SURVIVES
|
|
19
|
+
// x + 100 -> x * 100: SURVIVES
|
|
20
|
+
// x * 2 -> x + 2: SURVIVES
|
|
21
|
+
// x * 2 -> x - 2: SURVIVES
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('anotherSurvivor', () => {
|
|
26
|
+
it('should execute without any validation', () => {
|
|
27
|
+
// This test covers all lines but checks NOTHING
|
|
28
|
+
|
|
29
|
+
anotherSurvivor(30, 25); // Covers sum > 50, return sum - 10
|
|
30
|
+
anotherSurvivor(10, 5); // Covers sum <= 50, return sum / 2
|
|
31
|
+
|
|
32
|
+
// NO EXPECTATIONS!
|
|
33
|
+
// Mutations that will survive:
|
|
34
|
+
// a + b -> a - b: SURVIVES
|
|
35
|
+
// a + b -> a * b: SURVIVES
|
|
36
|
+
// sum > 50 -> sum < 50: SURVIVES
|
|
37
|
+
// sum - 10 -> sum + 10: SURVIVES
|
|
38
|
+
// sum / 2 -> sum * 2: SURVIVES
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('booleanSurvivor', () => {
|
|
43
|
+
it('should call the function', () => {
|
|
44
|
+
// This test calls the function but ignores the result completely
|
|
45
|
+
|
|
46
|
+
booleanSurvivor(5); // Covers x > 0, return true
|
|
47
|
+
booleanSurvivor(-3); // Covers x <= 0, return false
|
|
48
|
+
|
|
49
|
+
// NO VALIDATION OF BOOLEAN RESULTS!
|
|
50
|
+
// Mutations that will survive:
|
|
51
|
+
// x > 0 -> x < 0: SURVIVES
|
|
52
|
+
// x > 0 -> x >= 0: SURVIVES
|
|
53
|
+
// return true -> return false: SURVIVES
|
|
54
|
+
// return false -> return true: SURVIVES
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('guaranteedSurvivor', () => {
|
|
59
|
+
it('should execute without any validation whatsoever', () => {
|
|
60
|
+
// This test is designed to be completely useless
|
|
61
|
+
// It catches ALL exceptions and validates NOTHING
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
guaranteedSurvivor(10); // Should return 100, but we don't check
|
|
65
|
+
guaranteedSurvivor(20); // Should return 200, but we don't check
|
|
66
|
+
guaranteedSurvivor(5); // Should return 10, but we don't check
|
|
67
|
+
guaranteedSurvivor(-1); // Should return 4, but we don't check
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// Even if mutations cause errors, we ignore them!
|
|
70
|
+
// This ensures mutations that change behavior but don't crash will survive
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// NO ASSERTIONS AT ALL!
|
|
74
|
+
// ALL mutations will survive because:
|
|
75
|
+
// 1. We don't check return values
|
|
76
|
+
// 2. We catch all exceptions
|
|
77
|
+
// 3. We have no expectations
|
|
78
|
+
//
|
|
79
|
+
// Expected survived mutations:
|
|
80
|
+
// input === 10 -> input !== 10: SURVIVES
|
|
81
|
+
// input === 10 -> input > 10: SURVIVES
|
|
82
|
+
// result = 100 -> result = 0: SURVIVES
|
|
83
|
+
// result = 100 -> result = 1: SURVIVES
|
|
84
|
+
// input === 20 -> input !== 20: SURVIVES
|
|
85
|
+
// result = 200 -> result = 0: SURVIVES
|
|
86
|
+
// input + 5 -> input - 5: SURVIVES
|
|
87
|
+
// input + 5 -> input * 5: SURVIVES
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|