@codingame/monaco-vscode-testing-service-override 1.83.16

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.
Files changed (33) hide show
  1. package/external/rollup-plugin-styles/dist/runtime/inject-css.js +3 -0
  2. package/external/tslib/tslib.es6.js +11 -0
  3. package/index.d.ts +1 -0
  4. package/index.js +1 -0
  5. package/package.json +30 -0
  6. package/testing.d.ts +5 -0
  7. package/testing.js +28 -0
  8. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/display.js +3 -0
  9. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/index.js +76 -0
  10. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/listProjection.js +186 -0
  11. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/testItemContextOverlay.js +18 -0
  12. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/testingObjectTree.js +46 -0
  13. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/testingViewState.js +17 -0
  14. package/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/treeProjection.js +220 -0
  15. package/vscode/src/vs/workbench/contrib/testing/browser/icons.js +149 -0
  16. package/vscode/src/vs/workbench/contrib/testing/browser/media/testing.css.js +6 -0
  17. package/vscode/src/vs/workbench/contrib/testing/browser/testExplorerActions.js +1427 -0
  18. package/vscode/src/vs/workbench/contrib/testing/browser/testing.contribution.js +178 -0
  19. package/vscode/src/vs/workbench/contrib/testing/browser/testingDecorations.js +879 -0
  20. package/vscode/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.js +237 -0
  21. package/vscode/src/vs/workbench/contrib/testing/browser/testingExplorerView.js +1225 -0
  22. package/vscode/src/vs/workbench/contrib/testing/browser/testingOutputPeek.css.js +6 -0
  23. package/vscode/src/vs/workbench/contrib/testing/browser/testingOutputPeek.js +1991 -0
  24. package/vscode/src/vs/workbench/contrib/testing/browser/testingProgressUiService.js +142 -0
  25. package/vscode/src/vs/workbench/contrib/testing/browser/testingViewPaneContainer.js +47 -0
  26. package/vscode/src/vs/workbench/contrib/testing/browser/theme.js +130 -0
  27. package/vscode/src/vs/workbench/contrib/testing/common/configuration.js +213 -0
  28. package/vscode/src/vs/workbench/contrib/testing/common/constants.js +59 -0
  29. package/vscode/src/vs/workbench/contrib/testing/common/mainThreadTestCollection.js +129 -0
  30. package/vscode/src/vs/workbench/contrib/testing/common/testExclusions.js +48 -0
  31. package/vscode/src/vs/workbench/contrib/testing/common/testServiceImpl.js +293 -0
  32. package/vscode/src/vs/workbench/contrib/testing/common/testingContentProvider.js +125 -0
  33. package/vscode/src/vs/workbench/contrib/testing/common/testingUri.js +67 -0
@@ -0,0 +1,879 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import * as dom from 'monaco-editor/esm/vs/base/browser/dom.js';
3
+ import { renderStringAsPlaintext } from 'monaco-editor/esm/vs/base/browser/markdownRenderer.js';
4
+ import { Action, Separator, SubmenuAction } from 'monaco-editor/esm/vs/base/common/actions.js';
5
+ import { equals } from 'monaco-editor/esm/vs/base/common/arrays.js';
6
+ import { RunOnceScheduler } from 'monaco-editor/esm/vs/base/common/async.js';
7
+ import { Event, Emitter } from 'monaco-editor/esm/vs/base/common/event.js';
8
+ import { MarkdownString } from 'monaco-editor/esm/vs/base/common/htmlContent.js';
9
+ import { stripIcons } from 'monaco-editor/esm/vs/base/common/iconLabels.js';
10
+ import { Iterable } from 'monaco-editor/esm/vs/base/common/iterator.js';
11
+ import { Disposable, MutableDisposable, DisposableStore } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
12
+ import { ResourceMap } from 'monaco-editor/esm/vs/base/common/map.js';
13
+ import { isMacintosh } from 'monaco-editor/esm/vs/base/common/platform.js';
14
+ import { ThemeIcon } from 'monaco-editor/esm/vs/base/common/themables.js';
15
+ import { generateUuid } from 'monaco-editor/esm/vs/base/common/uuid.js';
16
+ import { ICodeEditorService } from 'monaco-editor/esm/vs/editor/browser/services/codeEditorService.js';
17
+ import { overviewRulerError, overviewRulerInfo } from 'monaco-editor/esm/vs/editor/common/core/editorColorRegistry.js';
18
+ import { OverviewRulerLane } from 'monaco-editor/esm/vs/editor/common/model.js';
19
+ import { IModelService } from 'monaco-editor/esm/vs/editor/common/services/model.js';
20
+ import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
21
+ import { createAndFillInContextMenuActions } from 'monaco-editor/esm/vs/platform/actions/browser/menuEntryActionViewItem.js';
22
+ import { MenuId, IMenuService } from 'monaco-editor/esm/vs/platform/actions/common/actions.js';
23
+ import { ICommandService } from 'monaco-editor/esm/vs/platform/commands/common/commands.js';
24
+ import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
25
+ import { IContextKeyService } from 'monaco-editor/esm/vs/platform/contextkey/common/contextkey.js';
26
+ import { IContextMenuService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextView.js';
27
+ import { IInstantiationService } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
28
+ import { themeColorFromId } from 'monaco-editor/esm/vs/platform/theme/common/themeService.js';
29
+ import { IUriIdentityService } from 'monaco-editor/esm/vs/platform/uriIdentity/common/uriIdentity.js';
30
+ import { GutterActionsRegistry, EditorLineNumberContextMenu } from 'vscode/vscode/vs/workbench/contrib/codeEditor/browser/editorLineNumberMenu';
31
+ import { getTestItemContextOverlay } from './explorerProjections/testItemContextOverlay.js';
32
+ import { testingRunAllIcon, testingRunIcon, testingStatesToIcons } from './icons.js';
33
+ import { getTestingConfiguration } from '../common/configuration.js';
34
+ import { labelForTestInState } from '../common/constants.js';
35
+ import { TestId } from 'vscode/vscode/vs/workbench/contrib/testing/common/testId';
36
+ import { ITestProfileService } from 'vscode/vscode/vs/workbench/contrib/testing/common/testProfileService';
37
+ import { LiveTestResult } from 'vscode/vscode/vs/workbench/contrib/testing/common/testResult';
38
+ import { ITestResultService } from 'vscode/vscode/vs/workbench/contrib/testing/common/testResultService';
39
+ import { testsInFile, ITestService, getContextForTestItem } from 'vscode/vscode/vs/workbench/contrib/testing/common/testService';
40
+ import { TestDecorations, ITestingDecorationsService } from 'vscode/vscode/vs/workbench/contrib/testing/common/testingDecorations';
41
+ import { ITestingPeekOpener } from 'vscode/vscode/vs/workbench/contrib/testing/common/testingPeekOpener';
42
+ import { isFailedState, maxPriority } from 'vscode/vscode/vs/workbench/contrib/testing/common/testingStates';
43
+ import { parseTestUri, buildTestUri } from '../common/testingUri.js';
44
+
45
+ var TestMessageDecoration_1;
46
+ const MAX_INLINE_MESSAGE_LENGTH = 128;
47
+ function isOriginalInDiffEditor(codeEditorService, codeEditor) {
48
+ const diffEditors = codeEditorService.listDiffEditors();
49
+ for (const diffEditor of diffEditors) {
50
+ if (diffEditor.getOriginalEditor() === codeEditor) {
51
+ return true;
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+ class CachedDecorations {
57
+ constructor() {
58
+ this.runByIdKey = ( new Map());
59
+ this.messages = ( new Map());
60
+ }
61
+ get size() {
62
+ return this.runByIdKey.size + this.messages.size;
63
+ }
64
+ getForExactTests(testIds) {
65
+ const key = testIds.sort().join('\0\0');
66
+ return this.runByIdKey.get(key);
67
+ }
68
+ getMessage(message) {
69
+ return this.messages.get(message);
70
+ }
71
+ removeMessage(message) {
72
+ this.messages.delete(message);
73
+ }
74
+ addMessage(d) {
75
+ this.messages.set(d.testMessage, d);
76
+ }
77
+ addTest(d) {
78
+ const key = d.testIds.sort().join('\0\0');
79
+ this.runByIdKey.set(key, d);
80
+ }
81
+ getById(decorationId) {
82
+ for (const d of ( this.runByIdKey.values())) {
83
+ if (d.id === decorationId) {
84
+ return d;
85
+ }
86
+ }
87
+ for (const d of ( this.messages.values())) {
88
+ if (d.id === decorationId) {
89
+ return d;
90
+ }
91
+ }
92
+ return undefined;
93
+ }
94
+ *[Symbol.iterator]() {
95
+ for (const d of ( this.runByIdKey.values())) {
96
+ yield d;
97
+ }
98
+ for (const d of ( this.messages.values())) {
99
+ yield d;
100
+ }
101
+ }
102
+ }
103
+ let TestingDecorationService = class TestingDecorationService extends Disposable {
104
+ constructor(codeEditorService, configurationService, testService, results, instantiationService, modelService) {
105
+ super();
106
+ this.configurationService = configurationService;
107
+ this.testService = testService;
108
+ this.results = results;
109
+ this.instantiationService = instantiationService;
110
+ this.modelService = modelService;
111
+ this.generation = 0;
112
+ this.changeEmitter = ( new Emitter());
113
+ this.decorationCache = ( new ResourceMap());
114
+ this.invalidatedMessages = ( new WeakSet());
115
+ this.onDidChange = this.changeEmitter.event;
116
+ codeEditorService.registerDecorationType('test-message-decoration', TestMessageDecoration.decorationId, {}, undefined);
117
+ modelService.onModelRemoved(e => this.decorationCache.delete(e.uri));
118
+ const debounceInvalidate = this._register(( new RunOnceScheduler(() => this.invalidate(), 100)));
119
+ this._register(this.testService.onWillProcessDiff(diff => {
120
+ for (const entry of diff) {
121
+ if (entry.op !== 2 ) {
122
+ continue;
123
+ }
124
+ const rec = this.decorationCache.get(entry.uri);
125
+ if (rec) {
126
+ rec.rangeUpdateVersionId = entry.docv;
127
+ }
128
+ }
129
+ if (!debounceInvalidate.isScheduled()) {
130
+ debounceInvalidate.schedule();
131
+ }
132
+ }));
133
+ this._register(Event.any(this.results.onResultsChanged, this.results.onTestChanged, this.testService.excluded.onTestExclusionsChanged, this.testService.showInlineOutput.onDidChange, Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration("testing.gutterEnabled" )))(() => {
134
+ if (!debounceInvalidate.isScheduled()) {
135
+ debounceInvalidate.schedule();
136
+ }
137
+ }));
138
+ this._register(GutterActionsRegistry.registerGutterActionsGenerator((context, result) => {
139
+ const model = context.editor.getModel();
140
+ const testingDecorations = TestingDecorations.get(context.editor);
141
+ if (!model || !testingDecorations?.currentUri) {
142
+ return;
143
+ }
144
+ const currentDecorations = this.syncDecorations(testingDecorations.currentUri);
145
+ if (!currentDecorations.size) {
146
+ return;
147
+ }
148
+ const modelDecorations = model.getLinesDecorations(context.lineNumber, context.lineNumber);
149
+ for (const { id } of modelDecorations) {
150
+ const decoration = currentDecorations.getById(id);
151
+ if (decoration) {
152
+ const { object: actions } = decoration.getContextMenuActions();
153
+ for (const action of actions) {
154
+ result.push(action, '1_testing');
155
+ }
156
+ }
157
+ }
158
+ }));
159
+ }
160
+ invalidateResultMessage(message) {
161
+ this.invalidatedMessages.add(message);
162
+ this.invalidate();
163
+ }
164
+ syncDecorations(resource) {
165
+ const model = this.modelService.getModel(resource);
166
+ if (!model) {
167
+ return ( new CachedDecorations());
168
+ }
169
+ const cached = this.decorationCache.get(resource);
170
+ if (cached && cached.generation === this.generation && (cached.rangeUpdateVersionId === undefined || cached.rangeUpdateVersionId !== model.getVersionId())) {
171
+ return cached.value;
172
+ }
173
+ return this.applyDecorations(model);
174
+ }
175
+ getDecoratedTestPosition(resource, testId) {
176
+ const model = this.modelService.getModel(resource);
177
+ if (!model) {
178
+ return undefined;
179
+ }
180
+ const decoration = Iterable.find(this.syncDecorations(resource), v => v instanceof RunTestDecoration && v.isForTest(testId));
181
+ if (!decoration) {
182
+ return undefined;
183
+ }
184
+ return model.getDecorationRange(decoration.id)?.getStartPosition();
185
+ }
186
+ invalidate() {
187
+ this.generation++;
188
+ this.changeEmitter.fire();
189
+ }
190
+ applyDecorations(model) {
191
+ const gutterEnabled = getTestingConfiguration(this.configurationService, "testing.gutterEnabled" );
192
+ const uriStr = ( model.uri.toString());
193
+ const cached = this.decorationCache.get(model.uri);
194
+ const testRangesUpdated = cached?.rangeUpdateVersionId === model.getVersionId();
195
+ const lastDecorations = cached?.value ?? ( new CachedDecorations());
196
+ const newDecorations = model.changeDecorations(accessor => {
197
+ const newDecorations = ( new CachedDecorations());
198
+ const runDecorations = ( new TestDecorations());
199
+ for (const test of this.testService.collection.getNodeByUrl(model.uri)) {
200
+ if (!test.item.range) {
201
+ continue;
202
+ }
203
+ const stateLookup = this.results.getStateById(test.item.extId);
204
+ const line = test.item.range.startLineNumber;
205
+ runDecorations.push({ line, id: '', test, resultItem: stateLookup?.[1] });
206
+ }
207
+ for (const [line, tests] of runDecorations.lines()) {
208
+ const multi = tests.length > 1;
209
+ let existing = lastDecorations.getForExactTests(( tests.map(t => t.test.item.extId)));
210
+ if (existing && testRangesUpdated && model.getDecorationRange(existing.id)?.startLineNumber !== line) {
211
+ existing = undefined;
212
+ }
213
+ if (existing) {
214
+ if (existing.replaceOptions(tests, gutterEnabled)) {
215
+ accessor.changeDecorationOptions(existing.id, existing.editorDecoration.options);
216
+ }
217
+ newDecorations.addTest(existing);
218
+ }
219
+ else {
220
+ newDecorations.addTest(multi
221
+ ? this.instantiationService.createInstance(MultiRunTestDecoration, tests, gutterEnabled, model)
222
+ : this.instantiationService.createInstance(RunSingleTestDecoration, tests[0].test, tests[0].resultItem, model, gutterEnabled));
223
+ }
224
+ }
225
+ const messageLines = ( new Set());
226
+ if (getTestingConfiguration(this.configurationService, "testing.showAllMessages" )) {
227
+ this.results.results.forEach(lastResult => this.applyDecorationsFromResult(lastResult, messageLines, uriStr, lastDecorations, model, newDecorations));
228
+ }
229
+ else {
230
+ this.applyDecorationsFromResult(this.results.results[0], messageLines, uriStr, lastDecorations, model, newDecorations);
231
+ }
232
+ const saveFromRemoval = ( new Set());
233
+ for (const decoration of newDecorations) {
234
+ if (decoration.id === '') {
235
+ decoration.id = accessor.addDecoration(decoration.editorDecoration.range, decoration.editorDecoration.options);
236
+ }
237
+ else {
238
+ saveFromRemoval.add(decoration.id);
239
+ }
240
+ }
241
+ for (const decoration of lastDecorations) {
242
+ if (!( saveFromRemoval.has(decoration.id))) {
243
+ accessor.removeDecoration(decoration.id);
244
+ }
245
+ }
246
+ this.decorationCache.set(model.uri, {
247
+ generation: this.generation,
248
+ rangeUpdateVersionId: cached?.rangeUpdateVersionId,
249
+ value: newDecorations,
250
+ });
251
+ return newDecorations;
252
+ });
253
+ return newDecorations || lastDecorations;
254
+ }
255
+ applyDecorationsFromResult(lastResult, messageLines, uriStr, lastDecorations, model, newDecorations) {
256
+ if (this.testService.showInlineOutput.value && lastResult instanceof LiveTestResult) {
257
+ for (const task of lastResult.tasks) {
258
+ for (const m of task.otherMessages) {
259
+ if (!( this.invalidatedMessages.has(m)) && m.location?.uri.toString() === uriStr) {
260
+ const decoration = lastDecorations.getMessage(m) || this.instantiationService.createInstance(TestMessageDecoration, m, undefined, model);
261
+ newDecorations.addMessage(decoration);
262
+ }
263
+ }
264
+ }
265
+ for (const test of lastResult.tests) {
266
+ for (let taskId = 0; taskId < test.tasks.length; taskId++) {
267
+ const state = test.tasks[taskId];
268
+ for (let i = 0; i < state.messages.length; i++) {
269
+ const m = state.messages[i];
270
+ if (( this.invalidatedMessages.has(m)) || m.location?.uri.toString() !== uriStr) {
271
+ continue;
272
+ }
273
+ const line = m.location.range.startLineNumber;
274
+ if (!( messageLines.has(line))) {
275
+ const decoration = lastDecorations.getMessage(m) || this.instantiationService.createInstance(TestMessageDecoration, m, buildTestUri({
276
+ type: 3 ,
277
+ messageIndex: i,
278
+ taskIndex: taskId,
279
+ resultId: lastResult.id,
280
+ testExtId: test.item.extId,
281
+ }), model);
282
+ newDecorations.addMessage(decoration);
283
+ messageLines.add(line);
284
+ }
285
+ }
286
+ }
287
+ }
288
+ }
289
+ }
290
+ };
291
+ TestingDecorationService = ( __decorate([
292
+ ( __param(0, ICodeEditorService)),
293
+ ( __param(1, IConfigurationService)),
294
+ ( __param(2, ITestService)),
295
+ ( __param(3, ITestResultService)),
296
+ ( __param(4, IInstantiationService)),
297
+ ( __param(5, IModelService))
298
+ ], TestingDecorationService));
299
+ let TestingDecorations = class TestingDecorations extends Disposable {
300
+ static get(editor) {
301
+ return editor.getContribution("editor.contrib.testingDecorations" );
302
+ }
303
+ get currentUri() { return this._currentUri; }
304
+ constructor(editor, codeEditorService, testService, decorations, uriIdentityService) {
305
+ super();
306
+ this.editor = editor;
307
+ this.codeEditorService = codeEditorService;
308
+ this.testService = testService;
309
+ this.decorations = decorations;
310
+ this.uriIdentityService = uriIdentityService;
311
+ this.expectedWidget = ( new MutableDisposable());
312
+ this.actualWidget = ( new MutableDisposable());
313
+ codeEditorService.registerDecorationType('test-message-decoration', TestMessageDecoration.decorationId, {}, undefined, editor);
314
+ this.attachModel(editor.getModel()?.uri);
315
+ this._register(decorations.onDidChange(() => {
316
+ if (this._currentUri) {
317
+ decorations.syncDecorations(this._currentUri);
318
+ }
319
+ }));
320
+ this._register(this.editor.onDidChangeModel(e => this.attachModel(e.newModelUrl || undefined)));
321
+ this._register(this.editor.onMouseDown(e => {
322
+ if (e.target.position && this.currentUri) {
323
+ const modelDecorations = editor.getModel()?.getLineDecorations(e.target.position.lineNumber) ?? [];
324
+ if (!modelDecorations.length) {
325
+ return;
326
+ }
327
+ const cache = decorations.syncDecorations(this.currentUri);
328
+ for (const { id } of modelDecorations) {
329
+ if (cache.getById(id)?.click(e)) {
330
+ e.event.stopPropagation();
331
+ return;
332
+ }
333
+ }
334
+ }
335
+ }));
336
+ this._register(Event.accumulate(this.editor.onDidChangeModelContent, 0, this._store)(evts => {
337
+ const model = editor.getModel();
338
+ if (!this._currentUri || !model) {
339
+ return;
340
+ }
341
+ const currentDecorations = decorations.syncDecorations(this._currentUri);
342
+ if (!currentDecorations.size) {
343
+ return;
344
+ }
345
+ for (const e of evts) {
346
+ for (const change of e.changes) {
347
+ const modelDecorations = model.getLinesDecorations(change.range.startLineNumber, change.range.endLineNumber);
348
+ for (const { id } of modelDecorations) {
349
+ const decoration = currentDecorations.getById(id);
350
+ if (decoration instanceof TestMessageDecoration) {
351
+ decorations.invalidateResultMessage(decoration.testMessage);
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }));
357
+ const updateFontFamilyVar = () => {
358
+ this.editor.getContainerDomNode().style.setProperty('--testMessageDecorationFontFamily', editor.getOption(49 ));
359
+ this.editor.getContainerDomNode().style.setProperty('--testMessageDecorationFontSize', `${editor.getOption(52 )}px`);
360
+ };
361
+ this._register(this.editor.onDidChangeConfiguration((e) => {
362
+ if (e.hasChanged(49 )) {
363
+ updateFontFamilyVar();
364
+ }
365
+ }));
366
+ updateFontFamilyVar();
367
+ }
368
+ attachModel(uri) {
369
+ switch (uri && parseTestUri(uri)?.type) {
370
+ case 4 :
371
+ this.expectedWidget.value = ( new ExpectedLensContentWidget(this.editor));
372
+ this.actualWidget.clear();
373
+ break;
374
+ case 3 :
375
+ this.expectedWidget.clear();
376
+ this.actualWidget.value = ( new ActualLensContentWidget(this.editor));
377
+ break;
378
+ default:
379
+ this.expectedWidget.clear();
380
+ this.actualWidget.clear();
381
+ }
382
+ if (isOriginalInDiffEditor(this.codeEditorService, this.editor)) {
383
+ uri = undefined;
384
+ }
385
+ this._currentUri = uri;
386
+ if (!uri) {
387
+ return;
388
+ }
389
+ this.decorations.syncDecorations(uri);
390
+ (async () => {
391
+ for await (const _test of testsInFile(this.testService, this.uriIdentityService, uri, false)) {
392
+ if (this._currentUri !== uri) {
393
+ break;
394
+ }
395
+ }
396
+ })();
397
+ }
398
+ };
399
+ TestingDecorations = ( __decorate([
400
+ ( __param(1, ICodeEditorService)),
401
+ ( __param(2, ITestService)),
402
+ ( __param(3, ITestingDecorationsService)),
403
+ ( __param(4, IUriIdentityService))
404
+ ], TestingDecorations));
405
+ const collapseRange = (originalRange) => ({
406
+ startLineNumber: originalRange.startLineNumber,
407
+ endLineNumber: originalRange.startLineNumber,
408
+ startColumn: originalRange.startColumn,
409
+ endColumn: originalRange.startColumn,
410
+ });
411
+ const createRunTestDecoration = (tests, states, visible) => {
412
+ const range = tests[0]?.item.range;
413
+ if (!range) {
414
+ throw new Error('Test decorations can only be created for tests with a range');
415
+ }
416
+ if (!visible) {
417
+ return { range: collapseRange(range), options: { isWholeLine: true, description: 'run-test-decoration' } };
418
+ }
419
+ let computedState = 0 ;
420
+ const hoverMessageParts = [];
421
+ let testIdWithMessages;
422
+ let retired = false;
423
+ for (let i = 0; i < tests.length; i++) {
424
+ const test = tests[i];
425
+ const resultItem = states[i];
426
+ const state = resultItem?.computedState ?? 0 ;
427
+ if (hoverMessageParts.length < 10) {
428
+ hoverMessageParts.push(labelForTestInState(test.item.label, state));
429
+ }
430
+ computedState = maxPriority(computedState, state);
431
+ retired = retired || !!resultItem?.retired;
432
+ if (!testIdWithMessages && resultItem?.tasks.some(t => t.messages.length)) {
433
+ testIdWithMessages = test.item.extId;
434
+ }
435
+ }
436
+ const hasMultipleTests = tests.length > 1 || tests[0].children.size > 0;
437
+ const icon = computedState === 0
438
+ ? (hasMultipleTests ? testingRunAllIcon : testingRunIcon)
439
+ : testingStatesToIcons.get(computedState);
440
+ let hoverMessage;
441
+ let glyphMarginClassName = ThemeIcon.asClassName(icon) + ' testing-run-glyph';
442
+ if (retired) {
443
+ glyphMarginClassName += ' retired';
444
+ }
445
+ return {
446
+ range: collapseRange(range),
447
+ options: {
448
+ description: 'run-test-decoration',
449
+ showIfCollapsed: true,
450
+ get hoverMessage() {
451
+ if (!hoverMessage) {
452
+ const building = hoverMessage = ( new MarkdownString('', true)).appendText(hoverMessageParts.join(', ') + '.');
453
+ if (testIdWithMessages) {
454
+ const args = encodeURIComponent(JSON.stringify([testIdWithMessages]));
455
+ building.appendMarkdown(` [${( localizeWithPath(
456
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
457
+ 'peekTestOutout',
458
+ 'Peek Test Output'
459
+ ))}](command:vscode.peekTestError?${args})`);
460
+ }
461
+ }
462
+ return hoverMessage;
463
+ },
464
+ glyphMarginClassName,
465
+ stickiness: 1 ,
466
+ zIndex: 10000,
467
+ }
468
+ };
469
+ };
470
+ class TitleLensContentWidget {
471
+ constructor(editor) {
472
+ this.editor = editor;
473
+ this.allowEditorOverflow = false;
474
+ this.suppressMouseDown = true;
475
+ this._domNode = dom.$('span');
476
+ queueMicrotask(() => {
477
+ this.applyStyling();
478
+ this.editor.addContentWidget(this);
479
+ });
480
+ }
481
+ applyStyling() {
482
+ let fontSize = this.editor.getOption(19 );
483
+ let height;
484
+ if (!fontSize || fontSize < 5) {
485
+ fontSize = (this.editor.getOption(52 ) * .9) | 0;
486
+ height = this.editor.getOption(66 );
487
+ }
488
+ else {
489
+ height = (fontSize * Math.max(1.3, this.editor.getOption(66 ) / this.editor.getOption(52 ))) | 0;
490
+ }
491
+ const editorFontInfo = this.editor.getOption(50 );
492
+ const node = this._domNode;
493
+ node.classList.add('testing-diff-lens-widget');
494
+ node.textContent = this.getText();
495
+ node.style.lineHeight = `${height}px`;
496
+ node.style.fontSize = `${fontSize}px`;
497
+ node.style.fontFamily = `var(--${"testingDiffLensFontFamily" })`;
498
+ node.style.fontFeatureSettings = `var(--${"testingDiffLensFontFeatures" })`;
499
+ const containerStyle = this.editor.getContainerDomNode().style;
500
+ containerStyle.setProperty("testingDiffLensFontFamily" , this.editor.getOption(18 ) ?? 'inherit');
501
+ containerStyle.setProperty("testingDiffLensFontFeatures" , editorFontInfo.fontFeatureSettings);
502
+ this.editor.changeViewZones(accessor => {
503
+ if (this.viewZoneId) {
504
+ accessor.removeZone(this.viewZoneId);
505
+ }
506
+ this.viewZoneId = accessor.addZone({
507
+ afterLineNumber: 0,
508
+ afterColumn: 1073741824 ,
509
+ domNode: document.createElement('div'),
510
+ heightInPx: 20,
511
+ });
512
+ });
513
+ }
514
+ getDomNode() {
515
+ return this._domNode;
516
+ }
517
+ dispose() {
518
+ this.editor.changeViewZones(accessor => {
519
+ if (this.viewZoneId) {
520
+ accessor.removeZone(this.viewZoneId);
521
+ }
522
+ });
523
+ this.editor.removeContentWidget(this);
524
+ }
525
+ getPosition() {
526
+ return {
527
+ position: { column: 0, lineNumber: 0 },
528
+ preference: [1 ],
529
+ };
530
+ }
531
+ }
532
+ class ExpectedLensContentWidget extends TitleLensContentWidget {
533
+ getId() {
534
+ return 'expectedTestingLens';
535
+ }
536
+ getText() {
537
+ return ( localizeWithPath(
538
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
539
+ 'expected.title',
540
+ 'Expected'
541
+ ));
542
+ }
543
+ }
544
+ class ActualLensContentWidget extends TitleLensContentWidget {
545
+ getId() {
546
+ return 'actualTestingLens';
547
+ }
548
+ getText() {
549
+ return ( localizeWithPath(
550
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
551
+ 'actual.title',
552
+ 'Actual'
553
+ ));
554
+ }
555
+ }
556
+ let RunTestDecoration = class RunTestDecoration {
557
+ get line() {
558
+ return this.editorDecoration.range.startLineNumber;
559
+ }
560
+ get testIds() {
561
+ return ( this.tests.map(t => t.test.item.extId));
562
+ }
563
+ constructor(tests, visible, model, codeEditorService, testService, contextMenuService, commandService, configurationService, testProfileService, contextKeyService, menuService) {
564
+ this.tests = tests;
565
+ this.visible = visible;
566
+ this.model = model;
567
+ this.codeEditorService = codeEditorService;
568
+ this.testService = testService;
569
+ this.contextMenuService = contextMenuService;
570
+ this.commandService = commandService;
571
+ this.configurationService = configurationService;
572
+ this.testProfileService = testProfileService;
573
+ this.contextKeyService = contextKeyService;
574
+ this.menuService = menuService;
575
+ this.id = '';
576
+ this.displayedStates = ( tests.map(t => t.resultItem?.computedState));
577
+ this.editorDecoration = createRunTestDecoration(( tests.map(t => t.test)), ( tests.map(t => t.resultItem)), visible);
578
+ this.editorDecoration.options.glyphMarginHoverMessage = ( new MarkdownString()).appendText(this.getGutterLabel());
579
+ }
580
+ click(e) {
581
+ if (e.target.type !== 2
582
+ || e.event.rightButton
583
+ || isMacintosh && e.event.leftButton && e.event.ctrlKey) {
584
+ return false;
585
+ }
586
+ switch (getTestingConfiguration(this.configurationService, "testing.defaultGutterClickAction" )) {
587
+ case "contextMenu" :
588
+ this.showContextMenu(e);
589
+ break;
590
+ case "debug" :
591
+ this.defaultDebug();
592
+ break;
593
+ case "run" :
594
+ default:
595
+ this.defaultRun();
596
+ break;
597
+ }
598
+ return true;
599
+ }
600
+ replaceOptions(newTests, visible) {
601
+ const displayedStates = ( newTests.map(t => t.resultItem?.computedState));
602
+ if (visible === this.visible && equals(this.displayedStates, displayedStates)) {
603
+ return false;
604
+ }
605
+ this.tests = newTests;
606
+ this.displayedStates = displayedStates;
607
+ this.visible = visible;
608
+ this.editorDecoration.options = createRunTestDecoration(( newTests.map(t => t.test)), ( newTests.map(t => t.resultItem)), visible).options;
609
+ this.editorDecoration.options.glyphMarginHoverMessage = ( new MarkdownString()).appendText(this.getGutterLabel());
610
+ return true;
611
+ }
612
+ isForTest(testId) {
613
+ return ( this.tests.some(t => t.test.item.extId === testId));
614
+ }
615
+ defaultRun() {
616
+ return this.testService.runTests({
617
+ tests: ( this.tests.map(({ test }) => test)),
618
+ group: 2 ,
619
+ });
620
+ }
621
+ defaultDebug() {
622
+ return this.testService.runTests({
623
+ tests: ( this.tests.map(({ test }) => test)),
624
+ group: 4 ,
625
+ });
626
+ }
627
+ showContextMenu(e) {
628
+ const editor = this.codeEditorService.listCodeEditors().find(e => e.getModel() === this.model);
629
+ editor?.getContribution(EditorLineNumberContextMenu.ID)?.show(e);
630
+ }
631
+ getGutterLabel() {
632
+ switch (getTestingConfiguration(this.configurationService, "testing.defaultGutterClickAction" )) {
633
+ case "contextMenu" :
634
+ return ( localizeWithPath(
635
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
636
+ 'testing.gutterMsg.contextMenu',
637
+ 'Click for test options'
638
+ ));
639
+ case "debug" :
640
+ return ( localizeWithPath(
641
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
642
+ 'testing.gutterMsg.debug',
643
+ 'Click to debug tests, right click for more options'
644
+ ));
645
+ case "run" :
646
+ default:
647
+ return ( localizeWithPath(
648
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
649
+ 'testing.gutterMsg.run',
650
+ 'Click to run tests, right click for more options'
651
+ ));
652
+ }
653
+ }
654
+ getTestContextMenuActions(test, resultItem) {
655
+ const testActions = [];
656
+ const capabilities = this.testProfileService.capabilitiesForTest(test);
657
+ if (capabilities & 2 ) {
658
+ testActions.push(( new Action('testing.gutter.run', ( localizeWithPath(
659
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
660
+ 'run test',
661
+ 'Run Test'
662
+ )), undefined, undefined, () => this.testService.runTests({
663
+ group: 2 ,
664
+ tests: [test],
665
+ }))));
666
+ }
667
+ if (capabilities & 4 ) {
668
+ testActions.push(( new Action('testing.gutter.debug', ( localizeWithPath(
669
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
670
+ 'debug test',
671
+ 'Debug Test'
672
+ )), undefined, undefined, () => this.testService.runTests({
673
+ group: 4 ,
674
+ tests: [test],
675
+ }))));
676
+ }
677
+ if (capabilities & 16 ) {
678
+ testActions.push(( new Action('testing.runUsing', ( localizeWithPath(
679
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
680
+ 'testing.runUsing',
681
+ 'Execute Using Profile...'
682
+ )), undefined, undefined, async () => {
683
+ const profile = await this.commandService.executeCommand('vscode.pickTestProfile', { onlyForTest: test });
684
+ if (!profile) {
685
+ return;
686
+ }
687
+ this.testService.runResolvedTests({
688
+ targets: [{
689
+ profileGroup: profile.group,
690
+ profileId: profile.profileId,
691
+ controllerId: profile.controllerId,
692
+ testIds: [test.item.extId]
693
+ }]
694
+ });
695
+ })));
696
+ }
697
+ if (resultItem && isFailedState(resultItem.computedState)) {
698
+ testActions.push(( new Action('testing.gutter.peekFailure', ( localizeWithPath(
699
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
700
+ 'peek failure',
701
+ 'Peek Error'
702
+ )), undefined, undefined, () => this.commandService.executeCommand('vscode.peekTestError', test.item.extId))));
703
+ }
704
+ testActions.push(( new Action('testing.gutter.reveal', ( localizeWithPath(
705
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
706
+ 'reveal test',
707
+ 'Reveal in Test Explorer'
708
+ )), undefined, undefined, () => this.commandService.executeCommand('_revealTestInExplorer', test.item.extId))));
709
+ const contributed = this.getContributedTestActions(test, capabilities);
710
+ return { object: Separator.join(testActions, contributed), dispose() { } };
711
+ }
712
+ getContributedTestActions(test, capabilities) {
713
+ const contextOverlay = this.contextKeyService.createOverlay(getTestItemContextOverlay(test, capabilities));
714
+ const menu = this.menuService.createMenu(MenuId.TestItemGutter, contextOverlay);
715
+ try {
716
+ const target = [];
717
+ const arg = getContextForTestItem(this.testService.collection, test.item.extId);
718
+ createAndFillInContextMenuActions(menu, { shouldForwardArgs: true, arg }, target);
719
+ return target;
720
+ }
721
+ finally {
722
+ menu.dispose();
723
+ }
724
+ }
725
+ };
726
+ RunTestDecoration = ( __decorate([
727
+ ( __param(3, ICodeEditorService)),
728
+ ( __param(4, ITestService)),
729
+ ( __param(5, IContextMenuService)),
730
+ ( __param(6, ICommandService)),
731
+ ( __param(7, IConfigurationService)),
732
+ ( __param(8, ITestProfileService)),
733
+ ( __param(9, IContextKeyService)),
734
+ ( __param(10, IMenuService))
735
+ ], RunTestDecoration));
736
+ class MultiRunTestDecoration extends RunTestDecoration {
737
+ getContextMenuActions() {
738
+ const allActions = [];
739
+ if (( this.tests.some(
740
+ ({ test }) => this.testProfileService.capabilitiesForTest(test) & 2
741
+ ))) {
742
+ allActions.push(( new Action('testing.gutter.runAll', ( localizeWithPath(
743
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
744
+ 'run all test',
745
+ 'Run All Tests'
746
+ )), undefined, undefined, () => this.defaultRun())));
747
+ }
748
+ if (( this.tests.some(
749
+ ({ test }) => this.testProfileService.capabilitiesForTest(test) & 4
750
+ ))) {
751
+ allActions.push(( new Action('testing.gutter.debugAll', ( localizeWithPath(
752
+ 'vs/workbench/contrib/testing/browser/testingDecorations',
753
+ 'debug all test',
754
+ 'Debug All Tests'
755
+ )), undefined, undefined, () => this.defaultDebug())));
756
+ }
757
+ const testItems = ( this.tests.map(testItem => ({
758
+ currentLabel: testItem.test.item.label,
759
+ testItem,
760
+ parent: TestId.fromString(testItem.test.item.extId).parentId,
761
+ })));
762
+ const getLabelConflicts = (tests) => {
763
+ const labelCount = ( new Map());
764
+ for (const test of tests) {
765
+ labelCount.set(test.currentLabel, (labelCount.get(test.currentLabel) || 0) + 1);
766
+ }
767
+ return tests.filter(e => labelCount.get(e.currentLabel) > 1);
768
+ };
769
+ let conflicts, hasParent = true;
770
+ while ((conflicts = getLabelConflicts(testItems)).length && hasParent) {
771
+ for (const conflict of conflicts) {
772
+ if (conflict.parent) {
773
+ const parent = this.testService.collection.getNodeById(( conflict.parent.toString()));
774
+ conflict.currentLabel = parent?.item.label + ' > ' + conflict.currentLabel;
775
+ conflict.parent = conflict.parent.parentId;
776
+ }
777
+ else {
778
+ hasParent = false;
779
+ }
780
+ }
781
+ }
782
+ const disposable = ( new DisposableStore());
783
+ const testSubmenus = ( testItems.map(({ currentLabel, testItem }) => {
784
+ const actions = this.getTestContextMenuActions(testItem.test, testItem.resultItem);
785
+ disposable.add(actions);
786
+ return ( new SubmenuAction(testItem.test.item.extId, stripIcons(currentLabel), actions.object));
787
+ }));
788
+ return { object: Separator.join(allActions, testSubmenus), dispose: () => disposable.dispose() };
789
+ }
790
+ }
791
+ let RunSingleTestDecoration = class RunSingleTestDecoration extends RunTestDecoration {
792
+ constructor(test, resultItem, model, visible, codeEditorService, testService, commandService, contextMenuService, configurationService, testProfiles, contextKeyService, menuService) {
793
+ super([{ test, resultItem }], visible, model, codeEditorService, testService, contextMenuService, commandService, configurationService, testProfiles, contextKeyService, menuService);
794
+ }
795
+ getContextMenuActions() {
796
+ return this.getTestContextMenuActions(this.tests[0].test, this.tests[0].resultItem);
797
+ }
798
+ };
799
+ RunSingleTestDecoration = ( __decorate([
800
+ ( __param(4, ICodeEditorService)),
801
+ ( __param(5, ITestService)),
802
+ ( __param(6, ICommandService)),
803
+ ( __param(7, IContextMenuService)),
804
+ ( __param(8, IConfigurationService)),
805
+ ( __param(9, ITestProfileService)),
806
+ ( __param(10, IContextKeyService)),
807
+ ( __param(11, IMenuService))
808
+ ], RunSingleTestDecoration));
809
+ const lineBreakRe = /\r?\n\s*/g;
810
+ let TestMessageDecoration = class TestMessageDecoration {
811
+ static { TestMessageDecoration_1 = this; }
812
+ static { this.inlineClassName = 'test-message-inline-content'; }
813
+ static { this.decorationId = `testmessage-${generateUuid()}`; }
814
+ constructor(testMessage, messageUri, textModel, peekOpener, editorService) {
815
+ this.testMessage = testMessage;
816
+ this.messageUri = messageUri;
817
+ this.peekOpener = peekOpener;
818
+ this.id = '';
819
+ this.contentIdClass = `test-message-inline-content-id${generateUuid()}`;
820
+ this.location = testMessage.location;
821
+ this.line = this.location.range.startLineNumber;
822
+ const severity = testMessage.type;
823
+ const message = testMessage.message;
824
+ const options = editorService.resolveDecorationOptions(TestMessageDecoration_1.decorationId, true);
825
+ options.hoverMessage = typeof message === 'string' ? ( new MarkdownString()).appendText(message) : message;
826
+ options.zIndex = 10;
827
+ options.className = `testing-inline-message-severity-${severity}`;
828
+ options.isWholeLine = true;
829
+ options.stickiness = 1 ;
830
+ options.collapseOnReplaceEdit = true;
831
+ let inlineText = renderStringAsPlaintext(message).replace(lineBreakRe, ' ');
832
+ if (inlineText.length > MAX_INLINE_MESSAGE_LENGTH) {
833
+ inlineText = inlineText.slice(0, MAX_INLINE_MESSAGE_LENGTH - 1) + '…';
834
+ }
835
+ options.after = {
836
+ content: ' '.repeat(4) + inlineText,
837
+ inlineClassName: `test-message-inline-content test-message-inline-content-s${severity} ${this.contentIdClass} ${messageUri ? 'test-message-inline-content-clickable' : ''}`
838
+ };
839
+ options.showIfCollapsed = true;
840
+ const rulerColor = severity === 0
841
+ ? overviewRulerError
842
+ : overviewRulerInfo;
843
+ if (rulerColor) {
844
+ options.overviewRuler = { color: themeColorFromId(rulerColor), position: OverviewRulerLane.Right };
845
+ }
846
+ const lineLength = textModel.getLineLength(this.location.range.startLineNumber);
847
+ const column = lineLength ? (lineLength + 1) : this.location.range.endColumn;
848
+ this.editorDecoration = {
849
+ options,
850
+ range: {
851
+ startLineNumber: this.location.range.startLineNumber,
852
+ startColumn: column,
853
+ endColumn: column,
854
+ endLineNumber: this.location.range.startLineNumber,
855
+ }
856
+ };
857
+ }
858
+ click(e) {
859
+ if (e.event.rightButton) {
860
+ return false;
861
+ }
862
+ if (!this.messageUri) {
863
+ return false;
864
+ }
865
+ if (e.target.element?.className.includes(this.contentIdClass)) {
866
+ this.peekOpener.peekUri(this.messageUri);
867
+ }
868
+ return false;
869
+ }
870
+ getContextMenuActions() {
871
+ return { object: [], dispose: () => { } };
872
+ }
873
+ };
874
+ TestMessageDecoration = TestMessageDecoration_1 = ( __decorate([
875
+ ( __param(3, ITestingPeekOpener)),
876
+ ( __param(4, ICodeEditorService))
877
+ ], TestMessageDecoration));
878
+
879
+ export { TestingDecorationService, TestingDecorations };