Skip to content

Commit 52ddf6b

Browse files
andravinclaude
andcommitted
test(testing): add tests for exclude filtering in test execution
Add unit tests for isTestItemExcluded, expandExcludeSet, and getTestCaseNodes with exclude/visited parameters. Verifies ancestor chain checking, descendant expansion, and correct node skipping. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fc38e1b commit 52ddf6b

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import * as assert from 'assert';
2+
import { TestItem } from 'vscode';
3+
import {
4+
isTestItemExcluded,
5+
expandExcludeSet,
6+
getTestCaseNodes,
7+
RunTestTag,
8+
DebugTestTag,
9+
} from '../../../client/testing/testController/common/testItemUtilities';
10+
11+
function createMockTestItem(id: string, canResolveChildren: boolean, children: TestItem[] = []): TestItem {
12+
const item = {
13+
id,
14+
canResolveChildren,
15+
tags: [RunTestTag, DebugTestTag],
16+
children: {
17+
forEach: (callback: (item: TestItem) => void) => {
18+
children.forEach(callback);
19+
},
20+
size: children.length,
21+
},
22+
parent: undefined as TestItem | undefined,
23+
} as any;
24+
// Set parent references on children
25+
children.forEach((child) => {
26+
(child as any).parent = item;
27+
});
28+
return item;
29+
}
30+
31+
suite('isTestItemExcluded', () => {
32+
test('should return false when excludeSet is undefined', () => {
33+
const item = createMockTestItem('item1', false);
34+
assert.strictEqual(isTestItemExcluded(item, undefined), false);
35+
});
36+
37+
test('should return false when excludeSet is empty', () => {
38+
const item = createMockTestItem('item1', false);
39+
assert.strictEqual(isTestItemExcluded(item, new Set()), false);
40+
});
41+
42+
test('should return true when item is directly in excludeSet', () => {
43+
const item = createMockTestItem('item1', false);
44+
const excludeSet = new Set([item]);
45+
assert.strictEqual(isTestItemExcluded(item, excludeSet), true);
46+
});
47+
48+
test('should return true when ancestor is in excludeSet', () => {
49+
const child = createMockTestItem('child', false);
50+
const parent = createMockTestItem('parent', true, [child]);
51+
const excludeSet = new Set([parent]);
52+
assert.strictEqual(isTestItemExcluded(child, excludeSet), true);
53+
});
54+
55+
test('should return false when unrelated item is in excludeSet', () => {
56+
const child = createMockTestItem('child', false);
57+
createMockTestItem('parent', true, [child]);
58+
const other = createMockTestItem('other', false);
59+
const excludeSet = new Set([other]);
60+
assert.strictEqual(isTestItemExcluded(child, excludeSet), false);
61+
});
62+
63+
test('should walk multiple levels of ancestor chain', () => {
64+
const grandchild = createMockTestItem('grandchild', false);
65+
const child = createMockTestItem('child', true, [grandchild]);
66+
const root = createMockTestItem('root', true, [child]);
67+
const excludeSet = new Set([root]);
68+
assert.strictEqual(isTestItemExcluded(grandchild, excludeSet), true);
69+
});
70+
});
71+
72+
suite('expandExcludeSet', () => {
73+
test('should return undefined when excludeSet is undefined', () => {
74+
assert.strictEqual(expandExcludeSet(undefined), undefined);
75+
});
76+
77+
test('should return empty set when excludeSet is empty', () => {
78+
const result = expandExcludeSet(new Set());
79+
assert.ok(result);
80+
assert.strictEqual(result!.size, 0);
81+
});
82+
83+
test('should include the excluded item itself', () => {
84+
const item = createMockTestItem('leaf', false);
85+
const result = expandExcludeSet(new Set([item]));
86+
assert.ok(result);
87+
assert.ok(result!.has(item));
88+
});
89+
90+
test('should include all descendants of excluded items', () => {
91+
const child1 = createMockTestItem('child1', false);
92+
const child2 = createMockTestItem('child2', false);
93+
const parent = createMockTestItem('parent', true, [child1, child2]);
94+
const result = expandExcludeSet(new Set([parent]));
95+
assert.ok(result);
96+
assert.strictEqual(result!.size, 3);
97+
assert.ok(result!.has(parent));
98+
assert.ok(result!.has(child1));
99+
assert.ok(result!.has(child2));
100+
});
101+
102+
test('should include deeply nested descendants', () => {
103+
const grandchild = createMockTestItem('grandchild', false);
104+
const child = createMockTestItem('child', true, [grandchild]);
105+
const root = createMockTestItem('root', true, [child]);
106+
const result = expandExcludeSet(new Set([root]));
107+
assert.ok(result);
108+
assert.strictEqual(result!.size, 3);
109+
assert.ok(result!.has(root));
110+
assert.ok(result!.has(child));
111+
assert.ok(result!.has(grandchild));
112+
});
113+
});
114+
115+
suite('getTestCaseNodes with exclude and visited', () => {
116+
test('should collect leaf test nodes', () => {
117+
const leaf1 = createMockTestItem('leaf1', false);
118+
const leaf2 = createMockTestItem('leaf2', false);
119+
const parent = createMockTestItem('parent', true, [leaf1, leaf2]);
120+
const result = getTestCaseNodes(parent);
121+
assert.strictEqual(result.length, 2);
122+
assert.ok(result.includes(leaf1));
123+
assert.ok(result.includes(leaf2));
124+
});
125+
126+
test('should skip nodes in excludeSet', () => {
127+
const leaf1 = createMockTestItem('leaf1', false);
128+
const leaf2 = createMockTestItem('leaf2', false);
129+
const parent = createMockTestItem('parent', true, [leaf1, leaf2]);
130+
const excludeSet = new Set([leaf1]);
131+
const result = getTestCaseNodes(parent, [], new Set(), excludeSet);
132+
assert.strictEqual(result.length, 1);
133+
assert.ok(result.includes(leaf2));
134+
});
135+
136+
test('should skip entire subtree when parent is in excludeSet', () => {
137+
const leaf = createMockTestItem('leaf', false);
138+
const folder = createMockTestItem('folder', true, [leaf]);
139+
const root = createMockTestItem('root', true, [folder]);
140+
// Pre-expanded excludeSet (as expandExcludeSet would produce)
141+
const excludeSet = new Set([folder, leaf]);
142+
const result = getTestCaseNodes(root, [], new Set(), excludeSet);
143+
assert.strictEqual(result.length, 0);
144+
});
145+
146+
test('should not visit same node twice when visited set is used', () => {
147+
const leaf = createMockTestItem('leaf', false);
148+
const parent = createMockTestItem('parent', true, [leaf]);
149+
const visited = new Set<TestItem>();
150+
const collection: TestItem[] = [];
151+
getTestCaseNodes(parent, collection, visited);
152+
getTestCaseNodes(parent, collection, visited);
153+
assert.strictEqual(collection.length, 1);
154+
});
155+
156+
test('should work without optional visited and excludeSet parameters', () => {
157+
const leaf = createMockTestItem('leaf', false);
158+
const parent = createMockTestItem('parent', true, [leaf]);
159+
const result = getTestCaseNodes(parent);
160+
assert.strictEqual(result.length, 1);
161+
assert.ok(result.includes(leaf));
162+
});
163+
164+
test('should skip excluded root node entirely', () => {
165+
const leaf = createMockTestItem('leaf', false);
166+
const root = createMockTestItem('root', true, [leaf]);
167+
const excludeSet = new Set([root, leaf]);
168+
const result = getTestCaseNodes(root, [], new Set(), excludeSet);
169+
assert.strictEqual(result.length, 0);
170+
});
171+
});

0 commit comments

Comments
 (0)