@theia/api-tests 1.34.2 → 1.34.3

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.
@@ -1,697 +1,697 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2019 TypeFox and others.
3
- //
4
- // This program and the accompanying materials are made available under the
5
- // terms of the Eclipse Public License v. 2.0 which is available at
6
- // http://www.eclipse.org/legal/epl-2.0.
7
- //
8
- // This Source Code may also be made available under the following Secondary
9
- // Licenses when the conditions for such availability set forth in the Eclipse
10
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- // with the GNU Classpath Exception which is available at
12
- // https://www.gnu.org/software/classpath/license.html.
13
- //
14
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
- // *****************************************************************************
16
-
17
- // @ts-check
18
- /* @typescript-eslint/no-explicit-any */
19
-
20
- /**
21
- * @typedef {'.vscode' | '.theia' | ['.theia', '.vscode']} ConfigMode
22
- */
23
-
24
- /**
25
- * Expectations should be tested and aligned against VS Code.
26
- * See https://github.com/akosyakov/vscode-launch/blob/master/src/test/extension.test.ts
27
- */
28
- describe('Launch Preferences', function () {
29
- this.timeout(10_000);
30
-
31
- const { assert } = chai;
32
-
33
- const { PreferenceProvider } = require('@theia/core/lib/browser');
34
- const { PreferenceService, PreferenceScope } = require('@theia/core/lib/browser/preferences/preference-service');
35
- const { WorkspaceService } = require('@theia/workspace/lib/browser/workspace-service');
36
- const { FileService } = require('@theia/filesystem/lib/browser/file-service');
37
- const { FileResourceResolver } = require('@theia/filesystem/lib/browser/file-resource');
38
- const { AbstractResourcePreferenceProvider } = require('@theia/preferences/lib/browser/abstract-resource-preference-provider');
39
- const { waitForEvent } = require('@theia/core/lib/common/promise-util');
40
-
41
- const container = window.theia.container;
42
- /** @type {import('@theia/core/lib/browser/preferences/preference-service').PreferenceService} */
43
- const preferences = container.get(PreferenceService);
44
- /** @type {import('@theia/preferences/lib/browser/user-configs-preference-provider').UserConfigsPreferenceProvider} */
45
- const userPreferences = container.getNamed(PreferenceProvider, PreferenceScope.User);
46
- /** @type {import('@theia/preferences/lib/browser/workspace-preference-provider').WorkspacePreferenceProvider} */
47
- const workspacePreferences = container.getNamed(PreferenceProvider, PreferenceScope.Workspace);
48
- /** @type {import('@theia/preferences/lib/browser/folders-preferences-provider').FoldersPreferencesProvider} */
49
- const folderPreferences = container.getNamed(PreferenceProvider, PreferenceScope.Folder);
50
- const workspaceService = container.get(WorkspaceService);
51
- const fileService = container.get(FileService);
52
- const fileResourceResolver = container.get(FileResourceResolver);
53
-
54
- const defaultLaunch = {
55
- 'configurations': [],
56
- 'compounds': []
57
- };
58
-
59
- const validConfiguration = {
60
- 'name': 'Launch Program',
61
- 'program': '${file}',
62
- 'request': 'launch',
63
- 'type': 'node',
64
- };
65
-
66
- const validConfiguration2 = {
67
- 'name': 'Launch Program 2',
68
- 'program': '${file}',
69
- 'request': 'launch',
70
- 'type': 'node',
71
- };
72
-
73
- const bogusConfiguration = {};
74
-
75
- const validCompound = {
76
- 'name': 'Compound',
77
- 'configurations': [
78
- 'Launch Program',
79
- 'Launch Program 2'
80
- ]
81
- };
82
-
83
- const bogusCompound = {};
84
-
85
- const bogusCompound2 = {
86
- 'name': 'Compound 2',
87
- 'configurations': [
88
- 'Foo',
89
- 'Launch Program 2'
90
- ]
91
- };
92
-
93
- const validLaunch = {
94
- configurations: [validConfiguration, validConfiguration2],
95
- compounds: [validCompound]
96
- };
97
-
98
- testSuite({
99
- name: 'No Preferences',
100
- expectation: defaultLaunch
101
- });
102
-
103
- testLaunchAndSettingsSuite({
104
- name: 'Empty With Version',
105
- launch: {
106
- 'version': '0.2.0'
107
- },
108
- expectation: {
109
- 'version': '0.2.0',
110
- 'configurations': [],
111
- 'compounds': []
112
- }
113
- });
114
-
115
- testLaunchAndSettingsSuite({
116
- name: 'Empty With Version And Configurations',
117
- launch: {
118
- 'version': '0.2.0',
119
- 'configurations': [],
120
- },
121
- expectation: {
122
- 'version': '0.2.0',
123
- 'configurations': [],
124
- 'compounds': []
125
- }
126
- });
127
-
128
- testLaunchAndSettingsSuite({
129
- name: 'Empty With Version And Compounds',
130
- launch: {
131
- 'version': '0.2.0',
132
- 'compounds': []
133
- },
134
- expectation: {
135
- 'version': '0.2.0',
136
- 'configurations': [],
137
- 'compounds': []
138
- }
139
- });
140
-
141
- testLaunchAndSettingsSuite({
142
- name: 'Valid Conf',
143
- launch: {
144
- 'version': '0.2.0',
145
- 'configurations': [validConfiguration]
146
- },
147
- expectation: {
148
- 'version': '0.2.0',
149
- 'configurations': [validConfiguration],
150
- 'compounds': []
151
- }
152
- });
153
-
154
- testLaunchAndSettingsSuite({
155
- name: 'Bogus Conf',
156
- launch: {
157
- 'version': '0.2.0',
158
- 'configurations': [validConfiguration, bogusConfiguration]
159
- },
160
- expectation: {
161
- 'version': '0.2.0',
162
- 'configurations': [validConfiguration, bogusConfiguration],
163
- 'compounds': []
164
- }
165
- });
166
-
167
- testLaunchAndSettingsSuite({
168
- name: 'Completely Bogus Conf',
169
- launch: {
170
- 'version': '0.2.0',
171
- 'configurations': { 'valid': validConfiguration, 'bogus': bogusConfiguration }
172
- },
173
- expectation: {
174
- 'version': '0.2.0',
175
- 'configurations': { 'valid': validConfiguration, 'bogus': bogusConfiguration },
176
- 'compounds': []
177
- }
178
- });
179
-
180
- const arrayBogusLaunch = [
181
- 'version', '0.2.0',
182
- 'configurations', { 'valid': validConfiguration, 'bogus': bogusConfiguration }
183
- ];
184
- testSuite({
185
- name: 'Array Bogus Launch Configuration',
186
- launch: arrayBogusLaunch,
187
- expectation: {
188
- '0': 'version',
189
- '1': '0.2.0',
190
- '2': 'configurations',
191
- '3': { 'valid': validConfiguration, 'bogus': bogusConfiguration },
192
- 'compounds': [],
193
- 'configurations': []
194
- },
195
- inspectExpectation: {
196
- preferenceName: 'launch',
197
- defaultValue: defaultLaunch,
198
- workspaceValue: {
199
- '0': 'version',
200
- '1': '0.2.0',
201
- '2': 'configurations',
202
- '3': { 'valid': validConfiguration, 'bogus': bogusConfiguration }
203
- }
204
- }
205
- });
206
- testSuite({
207
- name: 'Array Bogus Settings Configuration',
208
- settings: {
209
- launch: arrayBogusLaunch
210
- },
211
- expectation: {
212
- '0': 'version',
213
- '1': '0.2.0',
214
- '2': 'configurations',
215
- '3': { 'valid': validConfiguration, 'bogus': bogusConfiguration },
216
- 'compounds': [],
217
- 'configurations': []
218
- },
219
- inspectExpectation: {
220
- preferenceName: 'launch',
221
- defaultValue: defaultLaunch,
222
- workspaceValue: arrayBogusLaunch
223
- }
224
- });
225
-
226
- testSuite({
227
- name: 'Null Bogus Launch Configuration',
228
- // eslint-disable-next-line no-null/no-null
229
- launch: null,
230
- expectation: {
231
- 'compounds': [],
232
- 'configurations': []
233
- }
234
- });
235
- testSuite({
236
- name: 'Null Bogus Settings Configuration',
237
- settings: {
238
- // eslint-disable-next-line no-null/no-null
239
- 'launch': null
240
- },
241
- expectation: {}
242
- });
243
-
244
- testLaunchAndSettingsSuite({
245
- name: 'Valid Compound',
246
- launch: {
247
- 'version': '0.2.0',
248
- 'configurations': [validConfiguration, validConfiguration2],
249
- 'compounds': [validCompound]
250
- },
251
- expectation: {
252
- 'version': '0.2.0',
253
- 'configurations': [validConfiguration, validConfiguration2],
254
- 'compounds': [validCompound]
255
- }
256
- });
257
-
258
- testLaunchAndSettingsSuite({
259
- name: 'Valid And Bogus',
260
- launch: {
261
- 'version': '0.2.0',
262
- 'configurations': [validConfiguration, validConfiguration2, bogusConfiguration],
263
- 'compounds': [validCompound, bogusCompound, bogusCompound2]
264
- },
265
- expectation: {
266
- 'version': '0.2.0',
267
- 'configurations': [validConfiguration, validConfiguration2, bogusConfiguration],
268
- 'compounds': [validCompound, bogusCompound, bogusCompound2]
269
- }
270
- });
271
-
272
- testSuite({
273
- name: 'Mixed',
274
- launch: {
275
- 'version': '0.2.0',
276
- 'configurations': [validConfiguration, bogusConfiguration],
277
- 'compounds': [bogusCompound, bogusCompound2]
278
- },
279
- settings: {
280
- launch: {
281
- 'version': '0.2.0',
282
- 'configurations': [validConfiguration2],
283
- 'compounds': [validCompound]
284
- }
285
- },
286
- expectation: {
287
- 'version': '0.2.0',
288
- 'configurations': [validConfiguration, bogusConfiguration],
289
- 'compounds': [bogusCompound, bogusCompound2]
290
- }
291
- });
292
-
293
- testSuite({
294
- name: 'Mixed Launch Without Configurations',
295
- launch: {
296
- 'version': '0.2.0',
297
- 'compounds': [bogusCompound, bogusCompound2]
298
- },
299
- settings: {
300
- launch: {
301
- 'version': '0.2.0',
302
- 'configurations': [validConfiguration2],
303
- 'compounds': [validCompound]
304
- }
305
- },
306
- expectation: {
307
- 'version': '0.2.0',
308
- 'configurations': [validConfiguration2],
309
- 'compounds': [bogusCompound, bogusCompound2]
310
- },
311
- inspectExpectation: {
312
- preferenceName: 'launch',
313
- defaultValue: defaultLaunch,
314
- workspaceValue: {
315
- 'version': '0.2.0',
316
- 'configurations': [validConfiguration2],
317
- 'compounds': [bogusCompound, bogusCompound2]
318
- }
319
- }
320
- });
321
-
322
- /**
323
- * @typedef {Object} LaunchAndSettingsSuiteOptions
324
- * @property {string} name
325
- * @property {any} expectation
326
- * @property {any} [launch]
327
- * @property {boolean} [only]
328
- * @property {ConfigMode} [configMode]
329
- */
330
- /**
331
- * @type {(options: LaunchAndSettingsSuiteOptions) => void}
332
- */
333
- function testLaunchAndSettingsSuite({
334
- name, expectation, launch, only, configMode
335
- }) {
336
- testSuite({
337
- name: name + ' Launch Configuration',
338
- launch,
339
- expectation,
340
- only,
341
- configMode
342
- });
343
- testSuite({
344
- name: name + ' Settings Configuration',
345
- settings: {
346
- 'launch': launch
347
- },
348
- expectation,
349
- only,
350
- configMode
351
- });
352
- }
353
-
354
- /**
355
- * @typedef {Partial<import('@theia/core/src/browser/preferences/preference-service').PreferenceInspection<any>>} PreferenceInspection
356
- */
357
-
358
- /**
359
- * @typedef {Object} SuiteOptions
360
- * @property {string} name
361
- * @property {any} expectation
362
- * @property {PreferenceInspection} [inspectExpectation]
363
- * @property {any} [launch]
364
- * @property {any} [settings]
365
- * @property {boolean} [only]
366
- * @property {ConfigMode} [configMode]
367
- */
368
- /**
369
- * @type {(options: SuiteOptions) => void}
370
- */
371
- function testSuite(options) {
372
- describe(options.name, () => {
373
-
374
- if (options.configMode) {
375
- testConfigSuite(options);
376
- } else {
377
-
378
- testConfigSuite({
379
- ...options,
380
- configMode: '.theia'
381
- });
382
-
383
- if (options.settings || options.launch) {
384
- testConfigSuite({
385
- ...options,
386
- configMode: '.vscode'
387
- });
388
-
389
- testConfigSuite({
390
- ...options,
391
- configMode: ['.theia', '.vscode']
392
- });
393
- }
394
- }
395
-
396
- });
397
-
398
- }
399
-
400
- const rootUri = workspaceService.tryGetRoots()[0].resource;
401
-
402
- /**
403
- * @param uri the URI of the file to modify
404
- * @returns {AbstractResourcePreferenceProvider | undefined} The preference provider matching the provided URI.
405
- */
406
- function findProvider(uri) {
407
- /**
408
- * @param {PreferenceProvider} provider
409
- * @returns {boolean} whether the provider matches the desired URI.
410
- */
411
- const isMatch = (provider) => {
412
- const configUri = provider.getConfigUri();
413
- return configUri && uri.isEqual(configUri);
414
- };
415
- for (const provider of userPreferences['providers'].values()) {
416
- if (isMatch(provider) && provider instanceof AbstractResourcePreferenceProvider) {
417
- return provider;
418
- }
419
- }
420
- for (const provider of folderPreferences['providers'].values()) {
421
- if (isMatch(provider) && provider instanceof AbstractResourcePreferenceProvider) {
422
- return provider;
423
- }
424
- }
425
- /** @type {PreferenceProvider} */
426
- const workspaceDelegate = workspacePreferences['delegate'];
427
- if (workspaceDelegate !== folderPreferences) {
428
- if (isMatch(workspaceDelegate) && workspaceDelegate instanceof AbstractResourcePreferenceProvider) {
429
- return workspaceDelegate;
430
- }
431
- }
432
- }
433
-
434
- function deleteWorkspacePreferences() {
435
- const promises = [];
436
- for (const configPath of ['.theia', '.vscode']) {
437
- for (const name of ['settings', 'launch']) {
438
- promises.push((async () => {
439
- const uri = rootUri.resolve(configPath + '/' + name + '.json');
440
- const provider = findProvider(uri);
441
- try {
442
- if (provider) {
443
- if (provider.valid) {
444
- await waitForEvent(provider.onDidChangeValidity, 5000);
445
- }
446
- await provider['readPreferencesFromFile']();
447
- await provider['fireDidPreferencesChanged']();
448
- } else {
449
- console.log('Unable to find provider for', uri.path.toString());
450
- }
451
- } catch (e) {
452
- console.error(e);
453
- }
454
- })());
455
- }
456
- }
457
- return Promise.all([
458
- ...promises,
459
- fileService.delete(rootUri.resolve('.theia'), { fromUserGesture: false, recursive: true }).catch(() => { }),
460
- fileService.delete(rootUri.resolve('.vscode'), { fromUserGesture: false, recursive: true }).catch(() => { })
461
- ]);
462
- }
463
-
464
- const originalShouldOverwrite = fileResourceResolver['shouldOverwrite'];
465
-
466
- before(async () => {
467
- // fail tests if out of async happens
468
- fileResourceResolver['shouldOverwrite'] = async () => (assert.fail('should be in sync'), false);
469
- await deleteWorkspacePreferences();
470
- });
471
-
472
- after(() => {
473
- fileResourceResolver['shouldOverwrite'] = originalShouldOverwrite;
474
- });
475
-
476
- /**
477
- * @typedef {Object} ConfigSuiteOptions
478
- * @property {any} expectation
479
- * @property {any} [inspectExpectation]
480
- * @property {any} [launch]
481
- * @property {any} [settings]
482
- * @property {boolean} [only]
483
- * @property {ConfigMode} [configMode]
484
- */
485
- /**
486
- * @type {(options: ConfigSuiteOptions) => void}
487
- */
488
- function testConfigSuite({
489
- configMode, expectation, inspectExpectation, settings, launch, only
490
- }) {
491
-
492
- describe(JSON.stringify(configMode, undefined, 2), () => {
493
- const configPaths = Array.isArray(configMode) ? configMode : [configMode];
494
-
495
- /** @typedef {import('@theia/monaco-editor-core/esm/vs/base/common/lifecycle').IReference<import('@theia/monaco/lib/browser/monaco-editor-model').MonacoEditorModel>} ConfigModelReference */
496
- /** @type {ConfigModelReference[]} */
497
- beforeEach(async () => {
498
- /** @type {Promise<void>[]} */
499
- const promises = [];
500
- /**
501
- * @param {string} name
502
- * @param {Record<string, unknown>} value
503
- */
504
- const ensureConfigModel = (name, value) => {
505
- for (const configPath of configPaths) {
506
- promises.push((async () => {
507
- try {
508
- const uri = rootUri.resolve(configPath + '/' + name + '.json');
509
- const provider = findProvider(uri);
510
- if (provider) {
511
- await provider['doSetPreference']('', [], value);
512
- } else {
513
- console.log('Unable to find provider for', uri.path.toString());
514
- }
515
- } catch (e) {
516
- console.error(e);
517
- }
518
- })());
519
- }
520
- };
521
- if (settings) {
522
- ensureConfigModel('settings', settings);
523
- }
524
- if (launch) {
525
- ensureConfigModel('launch', launch);
526
- }
527
- await Promise.all(promises);
528
- });
529
-
530
- after(() => deleteWorkspacePreferences());
531
-
532
- const testItOnly = !!only ? it.only : it;
533
- const testIt = testItOnly;
534
-
535
- const settingsLaunch = settings ? settings['launch'] : undefined;
536
-
537
- testIt('get from default', () => {
538
- const config = preferences.get('launch');
539
- assert.deepStrictEqual(JSON.parse(JSON.stringify(config)), expectation);
540
- });
541
-
542
- testIt('get from undefined', () => {
543
- /** @type {any} */
544
- const config = preferences.get('launch', undefined, undefined);
545
- assert.deepStrictEqual(JSON.parse(JSON.stringify(config)), expectation);
546
- });
547
-
548
- testIt('get from rootUri', () => {
549
- /** @type {any} */
550
- const config = preferences.get('launch', undefined, rootUri.toString());
551
- assert.deepStrictEqual(JSON.parse(JSON.stringify(config)), expectation);
552
- });
553
-
554
- testIt('inspect in undefined', () => {
555
- const inspect = preferences.inspect('launch');
556
- /** @type {PreferenceInspection} */
557
- let expected = inspectExpectation;
558
- if (!expected) {
559
- expected = {
560
- preferenceName: 'launch',
561
- defaultValue: defaultLaunch
562
- };
563
- const workspaceValue = launch || settingsLaunch;
564
- if (workspaceValue !== undefined) {
565
- Object.assign(expected, { workspaceValue });
566
- }
567
- }
568
- const expectedValue = expected.workspaceFolderValue || expected.workspaceValue || expected.globalValue || expected.defaultValue;
569
- assert.deepStrictEqual(JSON.parse(JSON.stringify(inspect)), { ...expected, value: expectedValue });
570
- });
571
-
572
- testIt('inspect in rootUri', () => {
573
- const inspect = preferences.inspect('launch', rootUri.toString());
574
- /** @type {PreferenceInspection} */
575
- const expected = {
576
- preferenceName: 'launch',
577
- defaultValue: defaultLaunch
578
- };
579
- if (inspectExpectation) {
580
- Object.assign(expected, {
581
- workspaceValue: inspectExpectation.workspaceValue,
582
- workspaceFolderValue: inspectExpectation.workspaceValue
583
- });
584
- } else {
585
- const value = launch || settingsLaunch;
586
- if (value !== undefined) {
587
- Object.assign(expected, {
588
- workspaceValue: value,
589
- workspaceFolderValue: value
590
- });
591
- }
592
- }
593
- const expectedValue = expected.workspaceFolderValue || expected.workspaceValue || expected.globalValue || expected.defaultValue;
594
- assert.deepStrictEqual(JSON.parse(JSON.stringify(inspect)), { ...expected, value: expectedValue });
595
- });
596
-
597
- testIt('update launch', async () => {
598
- await preferences.set('launch', validLaunch);
599
-
600
- const inspect = preferences.inspect('launch');
601
- const actual = inspect && inspect.workspaceValue;
602
- const expected = settingsLaunch && !Array.isArray(settingsLaunch) ? { ...settingsLaunch, ...validLaunch } : validLaunch;
603
- assert.deepStrictEqual(actual, expected);
604
- });
605
-
606
- testIt('update launch Workspace', async () => {
607
- await preferences.set('launch', validLaunch, PreferenceScope.Workspace);
608
-
609
- const inspect = preferences.inspect('launch');
610
- const actual = inspect && inspect.workspaceValue;
611
- const expected = settingsLaunch && !Array.isArray(settingsLaunch) ? { ...settingsLaunch, ...validLaunch } : validLaunch;
612
- assert.deepStrictEqual(actual, expected);
613
- });
614
-
615
- testIt('update launch WorkspaceFolder', async () => {
616
- try {
617
- await preferences.set('launch', validLaunch, PreferenceScope.Folder);
618
- assert.fail('should not be possible to update Workspace Folder Without resource');
619
- } catch (e) {
620
- assert.deepStrictEqual(e.message, 'Unable to write to Folder Settings because no resource is provided.');
621
- }
622
- });
623
-
624
- testIt('update launch WorkspaceFolder with resource', async () => {
625
- await preferences.set('launch', validLaunch, PreferenceScope.Folder, rootUri.toString());
626
-
627
- const inspect = preferences.inspect('launch');
628
- const actual = inspect && inspect.workspaceValue;
629
- const expected = settingsLaunch && !Array.isArray(settingsLaunch) ? { ...settingsLaunch, ...validLaunch } : validLaunch;
630
- assert.deepStrictEqual(actual, expected);
631
- });
632
-
633
- if ((launch && !Array.isArray(launch)) || (settingsLaunch && !Array.isArray(settingsLaunch))) {
634
- testIt('update launch.configurations', async () => {
635
- await preferences.set('launch.configurations', [validConfiguration, validConfiguration2]);
636
-
637
- const inspect = preferences.inspect('launch');
638
- const actual = inspect && inspect.workspaceValue && inspect.workspaceValue.configurations;
639
- assert.deepStrictEqual(actual, [validConfiguration, validConfiguration2]);
640
- });
641
- }
642
-
643
- testIt('delete launch', async () => {
644
- await preferences.set('launch', undefined);
645
- const actual = preferences.inspect('launch');
646
-
647
- let expected = undefined;
648
- if (configPaths[1]) {
649
- expected = launch;
650
- if (Array.isArray(expected)) {
651
- expected = { ...expected };
652
- }
653
- if (expected && !expected.configurations && settingsLaunch && settingsLaunch.configurations !== undefined) {
654
- expected.configurations = settingsLaunch.configurations;
655
- }
656
- }
657
- expected = expected || settingsLaunch;
658
- assert.deepStrictEqual(actual && actual.workspaceValue, expected);
659
- });
660
-
661
- if ((launch && !Array.isArray(launch)) || (settingsLaunch && !Array.isArray(settingsLaunch))) {
662
- testIt('delete launch.configurations', async () => {
663
- await preferences.set('launch.configurations', undefined);
664
-
665
- const actual = preferences.inspect('launch');
666
- const actualWorkspaceValue = actual && actual.workspaceValue;
667
-
668
- let expected = undefined;
669
- if (launch) {
670
- expected = { ...launch };
671
- delete expected['configurations'];
672
- }
673
- if (settings) {
674
- let _settingsLaunch = undefined;
675
- if (typeof settingsLaunch === 'object' && !Array.isArray(settings['launch']) && settings['launch'] !== null) {
676
- _settingsLaunch = settingsLaunch;
677
- } else {
678
- _settingsLaunch = expectation;
679
- }
680
- if (expected) {
681
- if (_settingsLaunch.configurations !== undefined) {
682
- expected.configurations = _settingsLaunch.configurations;
683
- }
684
- } else {
685
- expected = _settingsLaunch;
686
- }
687
- }
688
-
689
- assert.deepStrictEqual(actualWorkspaceValue, expected);
690
- });
691
- }
692
-
693
- });
694
-
695
- }
696
-
697
- });
1
+ // *****************************************************************************
2
+ // Copyright (C) 2019 TypeFox and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ // @ts-check
18
+ /* @typescript-eslint/no-explicit-any */
19
+
20
+ /**
21
+ * @typedef {'.vscode' | '.theia' | ['.theia', '.vscode']} ConfigMode
22
+ */
23
+
24
+ /**
25
+ * Expectations should be tested and aligned against VS Code.
26
+ * See https://github.com/akosyakov/vscode-launch/blob/master/src/test/extension.test.ts
27
+ */
28
+ describe('Launch Preferences', function () {
29
+ this.timeout(10_000);
30
+
31
+ const { assert } = chai;
32
+
33
+ const { PreferenceProvider } = require('@theia/core/lib/browser');
34
+ const { PreferenceService, PreferenceScope } = require('@theia/core/lib/browser/preferences/preference-service');
35
+ const { WorkspaceService } = require('@theia/workspace/lib/browser/workspace-service');
36
+ const { FileService } = require('@theia/filesystem/lib/browser/file-service');
37
+ const { FileResourceResolver } = require('@theia/filesystem/lib/browser/file-resource');
38
+ const { AbstractResourcePreferenceProvider } = require('@theia/preferences/lib/browser/abstract-resource-preference-provider');
39
+ const { waitForEvent } = require('@theia/core/lib/common/promise-util');
40
+
41
+ const container = window.theia.container;
42
+ /** @type {import('@theia/core/lib/browser/preferences/preference-service').PreferenceService} */
43
+ const preferences = container.get(PreferenceService);
44
+ /** @type {import('@theia/preferences/lib/browser/user-configs-preference-provider').UserConfigsPreferenceProvider} */
45
+ const userPreferences = container.getNamed(PreferenceProvider, PreferenceScope.User);
46
+ /** @type {import('@theia/preferences/lib/browser/workspace-preference-provider').WorkspacePreferenceProvider} */
47
+ const workspacePreferences = container.getNamed(PreferenceProvider, PreferenceScope.Workspace);
48
+ /** @type {import('@theia/preferences/lib/browser/folders-preferences-provider').FoldersPreferencesProvider} */
49
+ const folderPreferences = container.getNamed(PreferenceProvider, PreferenceScope.Folder);
50
+ const workspaceService = container.get(WorkspaceService);
51
+ const fileService = container.get(FileService);
52
+ const fileResourceResolver = container.get(FileResourceResolver);
53
+
54
+ const defaultLaunch = {
55
+ 'configurations': [],
56
+ 'compounds': []
57
+ };
58
+
59
+ const validConfiguration = {
60
+ 'name': 'Launch Program',
61
+ 'program': '${file}',
62
+ 'request': 'launch',
63
+ 'type': 'node',
64
+ };
65
+
66
+ const validConfiguration2 = {
67
+ 'name': 'Launch Program 2',
68
+ 'program': '${file}',
69
+ 'request': 'launch',
70
+ 'type': 'node',
71
+ };
72
+
73
+ const bogusConfiguration = {};
74
+
75
+ const validCompound = {
76
+ 'name': 'Compound',
77
+ 'configurations': [
78
+ 'Launch Program',
79
+ 'Launch Program 2'
80
+ ]
81
+ };
82
+
83
+ const bogusCompound = {};
84
+
85
+ const bogusCompound2 = {
86
+ 'name': 'Compound 2',
87
+ 'configurations': [
88
+ 'Foo',
89
+ 'Launch Program 2'
90
+ ]
91
+ };
92
+
93
+ const validLaunch = {
94
+ configurations: [validConfiguration, validConfiguration2],
95
+ compounds: [validCompound]
96
+ };
97
+
98
+ testSuite({
99
+ name: 'No Preferences',
100
+ expectation: defaultLaunch
101
+ });
102
+
103
+ testLaunchAndSettingsSuite({
104
+ name: 'Empty With Version',
105
+ launch: {
106
+ 'version': '0.2.0'
107
+ },
108
+ expectation: {
109
+ 'version': '0.2.0',
110
+ 'configurations': [],
111
+ 'compounds': []
112
+ }
113
+ });
114
+
115
+ testLaunchAndSettingsSuite({
116
+ name: 'Empty With Version And Configurations',
117
+ launch: {
118
+ 'version': '0.2.0',
119
+ 'configurations': [],
120
+ },
121
+ expectation: {
122
+ 'version': '0.2.0',
123
+ 'configurations': [],
124
+ 'compounds': []
125
+ }
126
+ });
127
+
128
+ testLaunchAndSettingsSuite({
129
+ name: 'Empty With Version And Compounds',
130
+ launch: {
131
+ 'version': '0.2.0',
132
+ 'compounds': []
133
+ },
134
+ expectation: {
135
+ 'version': '0.2.0',
136
+ 'configurations': [],
137
+ 'compounds': []
138
+ }
139
+ });
140
+
141
+ testLaunchAndSettingsSuite({
142
+ name: 'Valid Conf',
143
+ launch: {
144
+ 'version': '0.2.0',
145
+ 'configurations': [validConfiguration]
146
+ },
147
+ expectation: {
148
+ 'version': '0.2.0',
149
+ 'configurations': [validConfiguration],
150
+ 'compounds': []
151
+ }
152
+ });
153
+
154
+ testLaunchAndSettingsSuite({
155
+ name: 'Bogus Conf',
156
+ launch: {
157
+ 'version': '0.2.0',
158
+ 'configurations': [validConfiguration, bogusConfiguration]
159
+ },
160
+ expectation: {
161
+ 'version': '0.2.0',
162
+ 'configurations': [validConfiguration, bogusConfiguration],
163
+ 'compounds': []
164
+ }
165
+ });
166
+
167
+ testLaunchAndSettingsSuite({
168
+ name: 'Completely Bogus Conf',
169
+ launch: {
170
+ 'version': '0.2.0',
171
+ 'configurations': { 'valid': validConfiguration, 'bogus': bogusConfiguration }
172
+ },
173
+ expectation: {
174
+ 'version': '0.2.0',
175
+ 'configurations': { 'valid': validConfiguration, 'bogus': bogusConfiguration },
176
+ 'compounds': []
177
+ }
178
+ });
179
+
180
+ const arrayBogusLaunch = [
181
+ 'version', '0.2.0',
182
+ 'configurations', { 'valid': validConfiguration, 'bogus': bogusConfiguration }
183
+ ];
184
+ testSuite({
185
+ name: 'Array Bogus Launch Configuration',
186
+ launch: arrayBogusLaunch,
187
+ expectation: {
188
+ '0': 'version',
189
+ '1': '0.2.0',
190
+ '2': 'configurations',
191
+ '3': { 'valid': validConfiguration, 'bogus': bogusConfiguration },
192
+ 'compounds': [],
193
+ 'configurations': []
194
+ },
195
+ inspectExpectation: {
196
+ preferenceName: 'launch',
197
+ defaultValue: defaultLaunch,
198
+ workspaceValue: {
199
+ '0': 'version',
200
+ '1': '0.2.0',
201
+ '2': 'configurations',
202
+ '3': { 'valid': validConfiguration, 'bogus': bogusConfiguration }
203
+ }
204
+ }
205
+ });
206
+ testSuite({
207
+ name: 'Array Bogus Settings Configuration',
208
+ settings: {
209
+ launch: arrayBogusLaunch
210
+ },
211
+ expectation: {
212
+ '0': 'version',
213
+ '1': '0.2.0',
214
+ '2': 'configurations',
215
+ '3': { 'valid': validConfiguration, 'bogus': bogusConfiguration },
216
+ 'compounds': [],
217
+ 'configurations': []
218
+ },
219
+ inspectExpectation: {
220
+ preferenceName: 'launch',
221
+ defaultValue: defaultLaunch,
222
+ workspaceValue: arrayBogusLaunch
223
+ }
224
+ });
225
+
226
+ testSuite({
227
+ name: 'Null Bogus Launch Configuration',
228
+ // eslint-disable-next-line no-null/no-null
229
+ launch: null,
230
+ expectation: {
231
+ 'compounds': [],
232
+ 'configurations': []
233
+ }
234
+ });
235
+ testSuite({
236
+ name: 'Null Bogus Settings Configuration',
237
+ settings: {
238
+ // eslint-disable-next-line no-null/no-null
239
+ 'launch': null
240
+ },
241
+ expectation: {}
242
+ });
243
+
244
+ testLaunchAndSettingsSuite({
245
+ name: 'Valid Compound',
246
+ launch: {
247
+ 'version': '0.2.0',
248
+ 'configurations': [validConfiguration, validConfiguration2],
249
+ 'compounds': [validCompound]
250
+ },
251
+ expectation: {
252
+ 'version': '0.2.0',
253
+ 'configurations': [validConfiguration, validConfiguration2],
254
+ 'compounds': [validCompound]
255
+ }
256
+ });
257
+
258
+ testLaunchAndSettingsSuite({
259
+ name: 'Valid And Bogus',
260
+ launch: {
261
+ 'version': '0.2.0',
262
+ 'configurations': [validConfiguration, validConfiguration2, bogusConfiguration],
263
+ 'compounds': [validCompound, bogusCompound, bogusCompound2]
264
+ },
265
+ expectation: {
266
+ 'version': '0.2.0',
267
+ 'configurations': [validConfiguration, validConfiguration2, bogusConfiguration],
268
+ 'compounds': [validCompound, bogusCompound, bogusCompound2]
269
+ }
270
+ });
271
+
272
+ testSuite({
273
+ name: 'Mixed',
274
+ launch: {
275
+ 'version': '0.2.0',
276
+ 'configurations': [validConfiguration, bogusConfiguration],
277
+ 'compounds': [bogusCompound, bogusCompound2]
278
+ },
279
+ settings: {
280
+ launch: {
281
+ 'version': '0.2.0',
282
+ 'configurations': [validConfiguration2],
283
+ 'compounds': [validCompound]
284
+ }
285
+ },
286
+ expectation: {
287
+ 'version': '0.2.0',
288
+ 'configurations': [validConfiguration, bogusConfiguration],
289
+ 'compounds': [bogusCompound, bogusCompound2]
290
+ }
291
+ });
292
+
293
+ testSuite({
294
+ name: 'Mixed Launch Without Configurations',
295
+ launch: {
296
+ 'version': '0.2.0',
297
+ 'compounds': [bogusCompound, bogusCompound2]
298
+ },
299
+ settings: {
300
+ launch: {
301
+ 'version': '0.2.0',
302
+ 'configurations': [validConfiguration2],
303
+ 'compounds': [validCompound]
304
+ }
305
+ },
306
+ expectation: {
307
+ 'version': '0.2.0',
308
+ 'configurations': [validConfiguration2],
309
+ 'compounds': [bogusCompound, bogusCompound2]
310
+ },
311
+ inspectExpectation: {
312
+ preferenceName: 'launch',
313
+ defaultValue: defaultLaunch,
314
+ workspaceValue: {
315
+ 'version': '0.2.0',
316
+ 'configurations': [validConfiguration2],
317
+ 'compounds': [bogusCompound, bogusCompound2]
318
+ }
319
+ }
320
+ });
321
+
322
+ /**
323
+ * @typedef {Object} LaunchAndSettingsSuiteOptions
324
+ * @property {string} name
325
+ * @property {any} expectation
326
+ * @property {any} [launch]
327
+ * @property {boolean} [only]
328
+ * @property {ConfigMode} [configMode]
329
+ */
330
+ /**
331
+ * @type {(options: LaunchAndSettingsSuiteOptions) => void}
332
+ */
333
+ function testLaunchAndSettingsSuite({
334
+ name, expectation, launch, only, configMode
335
+ }) {
336
+ testSuite({
337
+ name: name + ' Launch Configuration',
338
+ launch,
339
+ expectation,
340
+ only,
341
+ configMode
342
+ });
343
+ testSuite({
344
+ name: name + ' Settings Configuration',
345
+ settings: {
346
+ 'launch': launch
347
+ },
348
+ expectation,
349
+ only,
350
+ configMode
351
+ });
352
+ }
353
+
354
+ /**
355
+ * @typedef {Partial<import('@theia/core/src/browser/preferences/preference-service').PreferenceInspection<any>>} PreferenceInspection
356
+ */
357
+
358
+ /**
359
+ * @typedef {Object} SuiteOptions
360
+ * @property {string} name
361
+ * @property {any} expectation
362
+ * @property {PreferenceInspection} [inspectExpectation]
363
+ * @property {any} [launch]
364
+ * @property {any} [settings]
365
+ * @property {boolean} [only]
366
+ * @property {ConfigMode} [configMode]
367
+ */
368
+ /**
369
+ * @type {(options: SuiteOptions) => void}
370
+ */
371
+ function testSuite(options) {
372
+ describe(options.name, () => {
373
+
374
+ if (options.configMode) {
375
+ testConfigSuite(options);
376
+ } else {
377
+
378
+ testConfigSuite({
379
+ ...options,
380
+ configMode: '.theia'
381
+ });
382
+
383
+ if (options.settings || options.launch) {
384
+ testConfigSuite({
385
+ ...options,
386
+ configMode: '.vscode'
387
+ });
388
+
389
+ testConfigSuite({
390
+ ...options,
391
+ configMode: ['.theia', '.vscode']
392
+ });
393
+ }
394
+ }
395
+
396
+ });
397
+
398
+ }
399
+
400
+ const rootUri = workspaceService.tryGetRoots()[0].resource;
401
+
402
+ /**
403
+ * @param uri the URI of the file to modify
404
+ * @returns {AbstractResourcePreferenceProvider | undefined} The preference provider matching the provided URI.
405
+ */
406
+ function findProvider(uri) {
407
+ /**
408
+ * @param {PreferenceProvider} provider
409
+ * @returns {boolean} whether the provider matches the desired URI.
410
+ */
411
+ const isMatch = (provider) => {
412
+ const configUri = provider.getConfigUri();
413
+ return configUri && uri.isEqual(configUri);
414
+ };
415
+ for (const provider of userPreferences['providers'].values()) {
416
+ if (isMatch(provider) && provider instanceof AbstractResourcePreferenceProvider) {
417
+ return provider;
418
+ }
419
+ }
420
+ for (const provider of folderPreferences['providers'].values()) {
421
+ if (isMatch(provider) && provider instanceof AbstractResourcePreferenceProvider) {
422
+ return provider;
423
+ }
424
+ }
425
+ /** @type {PreferenceProvider} */
426
+ const workspaceDelegate = workspacePreferences['delegate'];
427
+ if (workspaceDelegate !== folderPreferences) {
428
+ if (isMatch(workspaceDelegate) && workspaceDelegate instanceof AbstractResourcePreferenceProvider) {
429
+ return workspaceDelegate;
430
+ }
431
+ }
432
+ }
433
+
434
+ function deleteWorkspacePreferences() {
435
+ const promises = [];
436
+ for (const configPath of ['.theia', '.vscode']) {
437
+ for (const name of ['settings', 'launch']) {
438
+ promises.push((async () => {
439
+ const uri = rootUri.resolve(configPath + '/' + name + '.json');
440
+ const provider = findProvider(uri);
441
+ try {
442
+ if (provider) {
443
+ if (provider.valid) {
444
+ await waitForEvent(provider.onDidChangeValidity, 5000);
445
+ }
446
+ await provider['readPreferencesFromFile']();
447
+ await provider['fireDidPreferencesChanged']();
448
+ } else {
449
+ console.log('Unable to find provider for', uri.path.toString());
450
+ }
451
+ } catch (e) {
452
+ console.error(e);
453
+ }
454
+ })());
455
+ }
456
+ }
457
+ return Promise.all([
458
+ ...promises,
459
+ fileService.delete(rootUri.resolve('.theia'), { fromUserGesture: false, recursive: true }).catch(() => { }),
460
+ fileService.delete(rootUri.resolve('.vscode'), { fromUserGesture: false, recursive: true }).catch(() => { })
461
+ ]);
462
+ }
463
+
464
+ const originalShouldOverwrite = fileResourceResolver['shouldOverwrite'];
465
+
466
+ before(async () => {
467
+ // fail tests if out of async happens
468
+ fileResourceResolver['shouldOverwrite'] = async () => (assert.fail('should be in sync'), false);
469
+ await deleteWorkspacePreferences();
470
+ });
471
+
472
+ after(() => {
473
+ fileResourceResolver['shouldOverwrite'] = originalShouldOverwrite;
474
+ });
475
+
476
+ /**
477
+ * @typedef {Object} ConfigSuiteOptions
478
+ * @property {any} expectation
479
+ * @property {any} [inspectExpectation]
480
+ * @property {any} [launch]
481
+ * @property {any} [settings]
482
+ * @property {boolean} [only]
483
+ * @property {ConfigMode} [configMode]
484
+ */
485
+ /**
486
+ * @type {(options: ConfigSuiteOptions) => void}
487
+ */
488
+ function testConfigSuite({
489
+ configMode, expectation, inspectExpectation, settings, launch, only
490
+ }) {
491
+
492
+ describe(JSON.stringify(configMode, undefined, 2), () => {
493
+ const configPaths = Array.isArray(configMode) ? configMode : [configMode];
494
+
495
+ /** @typedef {import('@theia/monaco-editor-core/esm/vs/base/common/lifecycle').IReference<import('@theia/monaco/lib/browser/monaco-editor-model').MonacoEditorModel>} ConfigModelReference */
496
+ /** @type {ConfigModelReference[]} */
497
+ beforeEach(async () => {
498
+ /** @type {Promise<void>[]} */
499
+ const promises = [];
500
+ /**
501
+ * @param {string} name
502
+ * @param {Record<string, unknown>} value
503
+ */
504
+ const ensureConfigModel = (name, value) => {
505
+ for (const configPath of configPaths) {
506
+ promises.push((async () => {
507
+ try {
508
+ const uri = rootUri.resolve(configPath + '/' + name + '.json');
509
+ const provider = findProvider(uri);
510
+ if (provider) {
511
+ await provider['doSetPreference']('', [], value);
512
+ } else {
513
+ console.log('Unable to find provider for', uri.path.toString());
514
+ }
515
+ } catch (e) {
516
+ console.error(e);
517
+ }
518
+ })());
519
+ }
520
+ };
521
+ if (settings) {
522
+ ensureConfigModel('settings', settings);
523
+ }
524
+ if (launch) {
525
+ ensureConfigModel('launch', launch);
526
+ }
527
+ await Promise.all(promises);
528
+ });
529
+
530
+ after(() => deleteWorkspacePreferences());
531
+
532
+ const testItOnly = !!only ? it.only : it;
533
+ const testIt = testItOnly;
534
+
535
+ const settingsLaunch = settings ? settings['launch'] : undefined;
536
+
537
+ testIt('get from default', () => {
538
+ const config = preferences.get('launch');
539
+ assert.deepStrictEqual(JSON.parse(JSON.stringify(config)), expectation);
540
+ });
541
+
542
+ testIt('get from undefined', () => {
543
+ /** @type {any} */
544
+ const config = preferences.get('launch', undefined, undefined);
545
+ assert.deepStrictEqual(JSON.parse(JSON.stringify(config)), expectation);
546
+ });
547
+
548
+ testIt('get from rootUri', () => {
549
+ /** @type {any} */
550
+ const config = preferences.get('launch', undefined, rootUri.toString());
551
+ assert.deepStrictEqual(JSON.parse(JSON.stringify(config)), expectation);
552
+ });
553
+
554
+ testIt('inspect in undefined', () => {
555
+ const inspect = preferences.inspect('launch');
556
+ /** @type {PreferenceInspection} */
557
+ let expected = inspectExpectation;
558
+ if (!expected) {
559
+ expected = {
560
+ preferenceName: 'launch',
561
+ defaultValue: defaultLaunch
562
+ };
563
+ const workspaceValue = launch || settingsLaunch;
564
+ if (workspaceValue !== undefined) {
565
+ Object.assign(expected, { workspaceValue });
566
+ }
567
+ }
568
+ const expectedValue = expected.workspaceFolderValue || expected.workspaceValue || expected.globalValue || expected.defaultValue;
569
+ assert.deepStrictEqual(JSON.parse(JSON.stringify(inspect)), { ...expected, value: expectedValue });
570
+ });
571
+
572
+ testIt('inspect in rootUri', () => {
573
+ const inspect = preferences.inspect('launch', rootUri.toString());
574
+ /** @type {PreferenceInspection} */
575
+ const expected = {
576
+ preferenceName: 'launch',
577
+ defaultValue: defaultLaunch
578
+ };
579
+ if (inspectExpectation) {
580
+ Object.assign(expected, {
581
+ workspaceValue: inspectExpectation.workspaceValue,
582
+ workspaceFolderValue: inspectExpectation.workspaceValue
583
+ });
584
+ } else {
585
+ const value = launch || settingsLaunch;
586
+ if (value !== undefined) {
587
+ Object.assign(expected, {
588
+ workspaceValue: value,
589
+ workspaceFolderValue: value
590
+ });
591
+ }
592
+ }
593
+ const expectedValue = expected.workspaceFolderValue || expected.workspaceValue || expected.globalValue || expected.defaultValue;
594
+ assert.deepStrictEqual(JSON.parse(JSON.stringify(inspect)), { ...expected, value: expectedValue });
595
+ });
596
+
597
+ testIt('update launch', async () => {
598
+ await preferences.set('launch', validLaunch);
599
+
600
+ const inspect = preferences.inspect('launch');
601
+ const actual = inspect && inspect.workspaceValue;
602
+ const expected = settingsLaunch && !Array.isArray(settingsLaunch) ? { ...settingsLaunch, ...validLaunch } : validLaunch;
603
+ assert.deepStrictEqual(actual, expected);
604
+ });
605
+
606
+ testIt('update launch Workspace', async () => {
607
+ await preferences.set('launch', validLaunch, PreferenceScope.Workspace);
608
+
609
+ const inspect = preferences.inspect('launch');
610
+ const actual = inspect && inspect.workspaceValue;
611
+ const expected = settingsLaunch && !Array.isArray(settingsLaunch) ? { ...settingsLaunch, ...validLaunch } : validLaunch;
612
+ assert.deepStrictEqual(actual, expected);
613
+ });
614
+
615
+ testIt('update launch WorkspaceFolder', async () => {
616
+ try {
617
+ await preferences.set('launch', validLaunch, PreferenceScope.Folder);
618
+ assert.fail('should not be possible to update Workspace Folder Without resource');
619
+ } catch (e) {
620
+ assert.deepStrictEqual(e.message, 'Unable to write to Folder Settings because no resource is provided.');
621
+ }
622
+ });
623
+
624
+ testIt('update launch WorkspaceFolder with resource', async () => {
625
+ await preferences.set('launch', validLaunch, PreferenceScope.Folder, rootUri.toString());
626
+
627
+ const inspect = preferences.inspect('launch');
628
+ const actual = inspect && inspect.workspaceValue;
629
+ const expected = settingsLaunch && !Array.isArray(settingsLaunch) ? { ...settingsLaunch, ...validLaunch } : validLaunch;
630
+ assert.deepStrictEqual(actual, expected);
631
+ });
632
+
633
+ if ((launch && !Array.isArray(launch)) || (settingsLaunch && !Array.isArray(settingsLaunch))) {
634
+ testIt('update launch.configurations', async () => {
635
+ await preferences.set('launch.configurations', [validConfiguration, validConfiguration2]);
636
+
637
+ const inspect = preferences.inspect('launch');
638
+ const actual = inspect && inspect.workspaceValue && inspect.workspaceValue.configurations;
639
+ assert.deepStrictEqual(actual, [validConfiguration, validConfiguration2]);
640
+ });
641
+ }
642
+
643
+ testIt('delete launch', async () => {
644
+ await preferences.set('launch', undefined);
645
+ const actual = preferences.inspect('launch');
646
+
647
+ let expected = undefined;
648
+ if (configPaths[1]) {
649
+ expected = launch;
650
+ if (Array.isArray(expected)) {
651
+ expected = { ...expected };
652
+ }
653
+ if (expected && !expected.configurations && settingsLaunch && settingsLaunch.configurations !== undefined) {
654
+ expected.configurations = settingsLaunch.configurations;
655
+ }
656
+ }
657
+ expected = expected || settingsLaunch;
658
+ assert.deepStrictEqual(actual && actual.workspaceValue, expected);
659
+ });
660
+
661
+ if ((launch && !Array.isArray(launch)) || (settingsLaunch && !Array.isArray(settingsLaunch))) {
662
+ testIt('delete launch.configurations', async () => {
663
+ await preferences.set('launch.configurations', undefined);
664
+
665
+ const actual = preferences.inspect('launch');
666
+ const actualWorkspaceValue = actual && actual.workspaceValue;
667
+
668
+ let expected = undefined;
669
+ if (launch) {
670
+ expected = { ...launch };
671
+ delete expected['configurations'];
672
+ }
673
+ if (settings) {
674
+ let _settingsLaunch = undefined;
675
+ if (typeof settingsLaunch === 'object' && !Array.isArray(settings['launch']) && settings['launch'] !== null) {
676
+ _settingsLaunch = settingsLaunch;
677
+ } else {
678
+ _settingsLaunch = expectation;
679
+ }
680
+ if (expected) {
681
+ if (_settingsLaunch.configurations !== undefined) {
682
+ expected.configurations = _settingsLaunch.configurations;
683
+ }
684
+ } else {
685
+ expected = _settingsLaunch;
686
+ }
687
+ }
688
+
689
+ assert.deepStrictEqual(actualWorkspaceValue, expected);
690
+ });
691
+ }
692
+
693
+ });
694
+
695
+ }
696
+
697
+ });