Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/inlineCompletions/test/browser/graph.test.ts
4798 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
8
import { DirectedGraph } from '../../browser/model/graph.js';
9
10
suite('DirectedGraph', () => {
11
ensureNoDisposablesAreLeakedInTestSuite();
12
13
test('from - creates empty graph', () => {
14
const graph = DirectedGraph.from<string>([], () => []);
15
assert.deepStrictEqual(graph.getOutgoing('a'), []);
16
});
17
18
test('from - creates graph with single node', () => {
19
const graph = DirectedGraph.from(['a'], () => []);
20
assert.deepStrictEqual(graph.getOutgoing('a'), []);
21
});
22
23
test('from - creates graph with nodes and edges', () => {
24
const nodes = ['a', 'b', 'c'];
25
const getOutgoing = (node: string) => {
26
switch (node) {
27
case 'a':
28
return ['b', 'c'];
29
case 'b':
30
return ['c'];
31
case 'c':
32
return [];
33
default:
34
return [];
35
}
36
};
37
38
const graph = DirectedGraph.from(nodes, getOutgoing);
39
40
assert.deepStrictEqual([...graph.getOutgoing('a')].sort(), ['b', 'c']);
41
assert.deepStrictEqual(graph.getOutgoing('b'), ['c']);
42
assert.deepStrictEqual(graph.getOutgoing('c'), []);
43
});
44
45
test('from - handles duplicate edges', () => {
46
const nodes = ['a', 'b'];
47
const getOutgoing = (node: string) => {
48
switch (node) {
49
case 'a':
50
return ['b', 'b']; // Duplicate edge
51
case 'b':
52
return [];
53
default:
54
return [];
55
}
56
};
57
58
const graph = DirectedGraph.from(nodes, getOutgoing);
59
60
assert.deepStrictEqual(graph.getOutgoing('a'), ['b']);
61
assert.deepStrictEqual(graph.getOutgoing('b'), []);
62
});
63
64
test('removeCycles - no cycles', () => {
65
const nodes = ['a', 'b', 'c'];
66
const getOutgoing = (node: string) => {
67
switch (node) {
68
case 'a':
69
return ['b'];
70
case 'b':
71
return ['c'];
72
case 'c':
73
return [];
74
default:
75
return [];
76
}
77
};
78
79
const graph = DirectedGraph.from(nodes, getOutgoing);
80
const result = graph.removeCycles();
81
82
assert.deepStrictEqual(result.foundCycles, []);
83
assert.deepStrictEqual(graph.getOutgoing('a'), ['b']);
84
assert.deepStrictEqual(graph.getOutgoing('b'), ['c']);
85
assert.deepStrictEqual(graph.getOutgoing('c'), []);
86
});
87
88
test('removeCycles - simple cycle', () => {
89
const nodes = ['a', 'b'];
90
const getOutgoing = (node: string) => {
91
switch (node) {
92
case 'a':
93
return ['b'];
94
case 'b':
95
return ['a']; // Creates cycle
96
default:
97
return [];
98
}
99
};
100
101
const graph = DirectedGraph.from(nodes, getOutgoing);
102
const result = graph.removeCycles();
103
104
assert.strictEqual(result.foundCycles.length, 1);
105
assert.ok(
106
result.foundCycles.includes('a') || result.foundCycles.includes('b')
107
);
108
109
// After removing cycles, one of the edges should be removed
110
const aOutgoing = graph.getOutgoing('a');
111
const bOutgoing = graph.getOutgoing('b');
112
assert.ok(
113
(aOutgoing.length === 0 && bOutgoing.length === 1) ||
114
(aOutgoing.length === 1 && bOutgoing.length === 0)
115
);
116
});
117
118
test('removeCycles - self loop', () => {
119
const nodes = ['a'];
120
const getOutgoing = (node: string) => {
121
switch (node) {
122
case 'a':
123
return ['a']; // Self loop
124
default:
125
return [];
126
}
127
};
128
129
const graph = DirectedGraph.from(nodes, getOutgoing);
130
const result = graph.removeCycles();
131
132
assert.deepStrictEqual(result.foundCycles, ['a']);
133
assert.deepStrictEqual(graph.getOutgoing('a'), []);
134
});
135
136
test('removeCycles - complex cycle', () => {
137
const nodes = ['a', 'b', 'c', 'd'];
138
const getOutgoing = (node: string) => {
139
switch (node) {
140
case 'a':
141
return ['b'];
142
case 'b':
143
return ['c'];
144
case 'c':
145
return ['d', 'a']; // Creates cycle back to 'a'
146
case 'd':
147
return [];
148
default:
149
return [];
150
}
151
};
152
153
const graph = DirectedGraph.from(nodes, getOutgoing);
154
const result = graph.removeCycles();
155
156
assert.ok(result.foundCycles.length >= 1);
157
158
// After removing cycles, there should be no path back to 'a' from 'c'
159
const cOutgoing = graph.getOutgoing('c');
160
assert.ok(!cOutgoing.includes('a'));
161
});
162
163
test('removeCycles - multiple disconnected cycles', () => {
164
const nodes = ['a', 'b', 'c', 'd'];
165
const getOutgoing = (node: string) => {
166
switch (node) {
167
case 'a':
168
return ['b'];
169
case 'b':
170
return ['a']; // Cycle 1: a <-> b
171
case 'c':
172
return ['d'];
173
case 'd':
174
return ['c']; // Cycle 2: c <-> d
175
default:
176
return [];
177
}
178
};
179
180
const graph = DirectedGraph.from(nodes, getOutgoing);
181
const result = graph.removeCycles();
182
183
assert.ok(result.foundCycles.length >= 2);
184
185
// After removing cycles, each pair should have only one direction
186
const aOutgoing = graph.getOutgoing('a');
187
const bOutgoing = graph.getOutgoing('b');
188
const cOutgoing = graph.getOutgoing('c');
189
const dOutgoing = graph.getOutgoing('d');
190
191
assert.ok(
192
(aOutgoing.length === 0 && bOutgoing.length === 1) ||
193
(aOutgoing.length === 1 && bOutgoing.length === 0)
194
);
195
assert.ok(
196
(cOutgoing.length === 0 && dOutgoing.length === 1) ||
197
(cOutgoing.length === 1 && dOutgoing.length === 0)
198
);
199
});
200
201
test('getOutgoing - non-existent node', () => {
202
const graph = DirectedGraph.from(['a'], () => []);
203
assert.deepStrictEqual(graph.getOutgoing('b'), []);
204
});
205
206
test('with number nodes', () => {
207
const nodes = [1, 2, 3];
208
const getOutgoing = (node: number) => {
209
switch (node) {
210
case 1:
211
return [2, 3];
212
case 2:
213
return [3];
214
case 3:
215
return [];
216
default:
217
return [];
218
}
219
};
220
221
const graph = DirectedGraph.from(nodes, getOutgoing);
222
223
assert.deepStrictEqual([...graph.getOutgoing(1)].sort(), [2, 3]);
224
assert.deepStrictEqual(graph.getOutgoing(2), [3]);
225
assert.deepStrictEqual(graph.getOutgoing(3), []);
226
});
227
});
228
229