Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/notebook/test/node/notebookService.spec.ts
13405 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, describe, it, suite } from 'vitest';
7
import type * as vscode from 'vscode';
8
import { _hasSupportedNotebooks, EditorAssociation, INotebookEditorContribution, RegisteredEditorPriority } from '../../../../util/common/notebooks';
9
import { ExtHostNotebookDocumentData } from '../../../../util/common/test/shims/notebookDocument';
10
import { URI } from '../../../../util/vs/base/common/uri';
11
import { NotebookData } from '../../../../vscodeTypes';
12
13
describe('NotebookService', () => {
14
suite('hasSupportedNotebooks', () => {
15
// all real providers pulled from package.json of various extensions
16
const jupyterNotebookProvider: INotebookEditorContribution = {
17
type: 'jupyter-notebook',
18
displayName: 'Jupyter Notebook',
19
priority: RegisteredEditorPriority.default,
20
selector: [{ filenamePattern: '*.ipynb' }]
21
};
22
const kustoNotebookProvider: INotebookEditorContribution = {
23
type: 'kusto-notebook',
24
displayName: 'Kusto Notebook',
25
selector: [{ filenamePattern: '*.knb' }]
26
};
27
const kustoNotebookProvider2: INotebookEditorContribution = {
28
type: 'kusto-notebook-kql',
29
displayName: 'Kusto Notebook',
30
priority: RegisteredEditorPriority.option,
31
selector: [{ filenamePattern: '*.kql' }, { filenamePattern: '*.csl' }]
32
};
33
const ghinbNotebookProvider: INotebookEditorContribution = {
34
type: 'github-issues',
35
displayName: 'GitHub Issues Notebook',
36
selector: [{ filenamePattern: '*.github-issues' }]
37
};
38
39
suite('mock tests', () => {
40
it('should return false when no providers are registered', async () => {
41
const notebookDocument = ExtHostNotebookDocumentData.fromNotebookData(
42
URI.file('one.ipynb'),
43
new NotebookData([]),
44
'jupyter-notebook'
45
).document;
46
47
assert.isFalse(
48
_hasSupportedNotebooks(notebookDocument.uri, [], [], []),
49
'Notebook with .ipynb extension should not be supported when there are no providers registered.'
50
);
51
});
52
53
it('should support untitled notebooks with matching provider', async () => {
54
const untitledUri: vscode.Uri = URI.from({
55
scheme: 'untitled',
56
authority: '',
57
path: 'Untitled-1.ipynb',
58
query: 'jupyter-notebook',
59
fragment: '',
60
});
61
const untitledNotebook = ExtHostNotebookDocumentData.fromNotebookData(
62
untitledUri,
63
new NotebookData([]),
64
'jupyter-notebook'
65
).document;
66
const provider: INotebookEditorContribution = {
67
type: 'test-provider',
68
displayName: 'Test Provider',
69
priority: RegisteredEditorPriority.default,
70
selector: ['*.ipynb']
71
};
72
assert.isTrue(
73
_hasSupportedNotebooks(untitledNotebook.uri, [untitledNotebook], [provider], []),
74
'Untitled notebook with .ipynb extension should be supported by a provider with a matching selector.'
75
);
76
});
77
78
it('should support notebooks with basic string selector', async () => {
79
const provider: INotebookEditorContribution = {
80
type: 'test-provider',
81
displayName: 'Test Provider',
82
priority: RegisteredEditorPriority.default,
83
selector: ['*.ipynb']
84
};
85
const notebookDocument = ExtHostNotebookDocumentData.fromNotebookData(
86
URI.file('one.ipynb'),
87
new NotebookData([]),
88
'jupyter-notebook'
89
).document;
90
assert.isTrue(
91
_hasSupportedNotebooks(notebookDocument.uri, [], [provider], []),
92
'Notebook with .ipynb extension should be supported by a provider with a basic string selector.'
93
);
94
});
95
96
it('should support case-insensitive selector matching for file extensions', async () => {
97
const provider: INotebookEditorContribution = {
98
type: 'test-provider',
99
displayName: 'Test Provider',
100
priority: RegisteredEditorPriority.default,
101
selector: ['*.ipynb']
102
};
103
const notebookDocument = ExtHostNotebookDocumentData.fromNotebookData(
104
URI.file('one.IPYNB'),
105
new NotebookData([]),
106
'jupyter-notebook'
107
).document;
108
assert.isTrue(
109
_hasSupportedNotebooks(notebookDocument.uri, [], [provider], []),
110
'Notebook with .IPYNB extension should be supported by a provider due to case-insensitive selectors.'
111
);
112
});
113
114
it('should respect include and exclude patterns in provider selector', async () => {
115
const provider: INotebookEditorContribution = {
116
type: 'test-provider',
117
displayName: 'Test Provider',
118
priority: RegisteredEditorPriority.default,
119
selector: [{
120
include: '*.ipynb',
121
exclude: 'test.*'
122
}]
123
};
124
125
// Test file that matches include but not exclude
126
const valid = ExtHostNotebookDocumentData.fromNotebookData(
127
URI.file('one.ipynb'),
128
new NotebookData([]),
129
'jupyter-notebook'
130
).document;
131
assert.isTrue(
132
_hasSupportedNotebooks(valid.uri, [], [provider], []),
133
'Notebook matching only the include pattern should be supported.'
134
);
135
136
// Test file that matches both include and exclude
137
const excluded = ExtHostNotebookDocumentData.fromNotebookData(
138
URI.file('test.ipynb'),
139
new NotebookData([]),
140
'jupyter-notebook'
141
).document;
142
assert.isFalse(
143
_hasSupportedNotebooks(excluded.uri, [], [provider], []),
144
'Notebook matching both include and exclude patterns should not be supported.'
145
);
146
147
// Test file that doesn't match either pattern
148
const nonMatching = ExtHostNotebookDocumentData.fromNotebookData(
149
URI.file('one.txt'),
150
new NotebookData([]),
151
'jupyter-notebook'
152
).document;
153
assert.isFalse(
154
_hasSupportedNotebooks(nonMatching.uri, [], [provider], []),
155
'Notebook matching neither include nor exclude pattern should not be supported.'
156
);
157
158
// Test file in a subdirectory
159
const subDirValid = ExtHostNotebookDocumentData.fromNotebookData(
160
URI.file('subdir/one.ipynb'),
161
new NotebookData([]),
162
'jupyter-notebook'
163
).document;
164
assert.isTrue(
165
_hasSupportedNotebooks(subDirValid.uri, [], [provider], []),
166
'Notebook in subdirectory matching include pattern should be supported.'
167
);
168
169
// Test remote URI
170
const remoteValid = ExtHostNotebookDocumentData.fromNotebookData(
171
URI.parse('vscode-remote://ssh-remote+test/one.ipynb'),
172
new NotebookData([]),
173
'jupyter-notebook'
174
).document;
175
assert.isTrue(
176
_hasSupportedNotebooks(remoteValid.uri, [], [provider], []),
177
'Notebook with remote URI matching include pattern should be supported.'
178
);
179
});
180
181
it('should respect filenamePattern and excludeFileNamePattern in provider selector', async () => {
182
const provider: INotebookEditorContribution = {
183
type: 'test-provider',
184
displayName: 'Test Provider',
185
priority: RegisteredEditorPriority.default,
186
selector: [{
187
filenamePattern: '*.ipynb',
188
excludeFileNamePattern: 'test.*'
189
}]
190
};
191
192
// Test file that matches include but not exclude
193
const valid = ExtHostNotebookDocumentData.fromNotebookData(
194
URI.file('one.ipynb'),
195
new NotebookData([]),
196
'jupyter-notebook'
197
).document;
198
assert.isTrue(
199
_hasSupportedNotebooks(valid.uri, [], [provider], []),
200
'Notebook matching filenamePattern but not excludeFileNamePattern should be supported.'
201
);
202
203
// Test file that matches both include and exclude
204
const excluded = ExtHostNotebookDocumentData.fromNotebookData(
205
URI.file('test.ipynb'),
206
new NotebookData([]),
207
'jupyter-notebook'
208
).document;
209
assert.isFalse(
210
_hasSupportedNotebooks(excluded.uri, [], [provider], []),
211
'Notebook matching both filenamePattern and excludeFileNamePattern should not be supported.'
212
);
213
});
214
215
it('should return false when only providers with valid selector have non-default priority', async () => {
216
const testNotebook = ExtHostNotebookDocumentData.fromNotebookData(
217
URI.file('test.ipynb'),
218
new NotebookData([]),
219
'jupyter-notebook'
220
).document;
221
222
const providers = [
223
{
224
type: 'provider1',
225
displayName: 'Provider 1',
226
priority: RegisteredEditorPriority.option,
227
selector: ['*.ipynb']
228
},
229
{
230
type: 'provider2',
231
displayName: 'Provider 2',
232
priority: RegisteredEditorPriority.default,
233
selector: ['*.other']
234
}
235
];
236
assert.isFalse(
237
_hasSupportedNotebooks(testNotebook.uri, [], providers, []),
238
'Notebook with .ipynb extension should not be supported when only non-default priority providers match.'
239
);
240
});
241
242
it('should return true when a provider with valid selector has default priority', async () => {
243
const testNotebook = ExtHostNotebookDocumentData.fromNotebookData(
244
URI.file('test.ipynb'),
245
new NotebookData([]),
246
'jupyter-notebook'
247
).document;
248
249
const providers = [
250
{
251
type: 'provider1',
252
displayName: 'Provider 1',
253
priority: RegisteredEditorPriority.default,
254
selector: ['*.ipynb']
255
},
256
{
257
type: 'provider2',
258
displayName: 'Provider 2',
259
priority: RegisteredEditorPriority.default,
260
selector: ['*.other']
261
}
262
];
263
assert.isTrue(
264
_hasSupportedNotebooks(testNotebook.uri, [], providers, []),
265
'Notebook with .ipynb extension should be supported when a provider with default priority matches.'
266
);
267
});
268
269
it('should return true when only option-priority providers match but there is a matching editor association', async () => {
270
const testNotebook = ExtHostNotebookDocumentData.fromNotebookData(
271
URI.file('test.ipynb'),
272
new NotebookData([]),
273
'jupyter-notebook'
274
).document;
275
276
const associations = [{ viewType: 'option-provider', filenamePattern: '*.ipynb' }];
277
const providers = [{
278
type: 'option-provider',
279
displayName: 'Option Provider',
280
priority: RegisteredEditorPriority.option,
281
selector: ['*.ipynb']
282
}];
283
assert.isTrue(
284
_hasSupportedNotebooks(testNotebook.uri, [], providers, associations),
285
'Notebook with .ipynb extension should be supported when an option-priority provider matches and there is a matching editor association.'
286
);
287
});
288
});
289
290
suite('real extension tests', () => {
291
it('should return true for providers with no set priority, due to default fallback', async () => {
292
const ghinbUri: vscode.Uri = URI.from({
293
scheme: 'file',
294
authority: '',
295
path: '_endgame.github-issues',
296
query: '',
297
fragment: '',
298
});
299
assert.isTrue(
300
_hasSupportedNotebooks(ghinbUri, [], [ghinbNotebookProvider], []),
301
'Notebook with .github-issues extension should be supported even when there is no valid editor association.'
302
);
303
});
304
305
it('should return true for github issues notebook provider with *.github-issues uri and a valid association', async () => {
306
const ghinbUri: vscode.Uri = URI.from({
307
scheme: 'file',
308
authority: '',
309
path: '_endgame.github-issues',
310
query: '',
311
fragment: '',
312
});
313
const ghinbAssociation: EditorAssociation = { viewType: 'github-issues', filenamePattern: '*.github-issues' };
314
assert.isTrue(
315
_hasSupportedNotebooks(ghinbUri, [], [ghinbNotebookProvider], [ghinbAssociation]),
316
'Notebook with .github-issues extension should be supported when there is a valid editor association.'
317
);
318
});
319
320
it('should return true for various notebook files with multiple providers and all valid associations', async () => {
321
const providers = [ghinbNotebookProvider, jupyterNotebookProvider, kustoNotebookProvider, kustoNotebookProvider2];
322
const associations = [
323
{ viewType: 'jupyter-notebook', filenamePattern: '*.ipynb' },
324
{ viewType: 'kusto-notebook', filenamePattern: '*.knb' },
325
{ viewType: 'kusto-notebook-kql', filenamePattern: '*.kql' },
326
{ viewType: 'kusto-notebook-kql', filenamePattern: '*.csl' },
327
{ viewType: 'github-issues', filenamePattern: '*.github-issues' }
328
];
329
const testFiles = [
330
URI.file('test.ipynb'),
331
URI.file('test.knb'),
332
URI.file('test.kql'),
333
URI.file('test.csl'),
334
URI.file('test.github-issues'),
335
];
336
337
for (const testFile of testFiles) {
338
assert.isTrue(
339
_hasSupportedNotebooks(testFile, [], providers, associations),
340
`Notebook with extension matching a provider and association should be supported: ${testFile.toString()}`
341
);
342
}
343
});
344
});
345
});
346
347
348
});
349
350