diff --git a/src/vs/workbench/contrib/testing/common/testProfileService.ts b/src/vs/workbench/contrib/testing/common/testProfileService.ts index ecdb9ffcd63..60d5972e130 100644 --- a/src/vs/workbench/contrib/testing/common/testProfileService.ts +++ b/src/vs/workbench/contrib/testing/common/testProfileService.ts @@ -241,11 +241,31 @@ export class TestProfileService implements ITestProfileService { /** @inheritdoc */ public setGroupDefaultProfiles(group: TestRunProfileBitset, profiles: ITestRunProfile[]) { - this.preferredDefaults.store({ + const next = { ...this.preferredDefaults.get(), [group]: profiles.map(c => ({ profileId: c.profileId, controllerId: c.controllerId })), - }); + }; + // When switching a run/debug profile, if the controller has a same-named + // profile in the other group, use that instead of anything else that was selected. + if (group === TestRunProfileBitset.Run || group === TestRunProfileBitset.Debug) { + const otherGroup = group === TestRunProfileBitset.Run ? TestRunProfileBitset.Debug : TestRunProfileBitset.Run; + + const previousDefaults = next[otherGroup] || []; + let newDefaults = previousDefaults.slice(); + for (const [ctrlId, { profiles: ctrlProfiles }] of this.controllerProfiles) { + const labels = new Set(profiles.filter(p => p.controllerId === ctrlId).map(p => p.label)); + const nextByLabels = ctrlProfiles.filter(p => labels.has(p.label) && p.group === otherGroup); + if (nextByLabels.length) { + newDefaults = newDefaults.filter(p => p.controllerId !== ctrlId); + newDefaults.push(...nextByLabels.map(p => ({ profileId: p.profileId, controllerId: p.controllerId }))); + } + } + + next[otherGroup] = newDefaults; + } + + this.preferredDefaults.store(next); this.changeEmitter.fire(); } diff --git a/src/vs/workbench/contrib/testing/test/common/testProfileService.test.ts b/src/vs/workbench/contrib/testing/test/common/testProfileService.test.ts new file mode 100644 index 00000000000..f12f301beae --- /dev/null +++ b/src/vs/workbench/contrib/testing/test/common/testProfileService.test.ts @@ -0,0 +1,117 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + + + +import * as assert from 'assert'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { TestProfileService } from 'vs/workbench/contrib/testing/common/testProfileService'; +import { ITestRunProfile, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; +import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; + +suite('Workbench - TestProfileService', () => { + let t: TestProfileService; + let idCounter = 0; + setup(() => { + idCounter = 0; + t = new TestProfileService( + new MockContextKeyService(), + new TestStorageService(), + ); + }); + + const addProfile = (profile: Partial) => { + const p: ITestRunProfile = { + controllerId: 'ctrlId', + group: TestRunProfileBitset.Run, + isDefault: true, + label: 'profile', + profileId: idCounter++, + hasConfigurationHandler: false, + tag: null, + ...profile, + }; + + t.addProfile(null as any, p); + return p; + }; + + const expectProfiles = (expected: ITestRunProfile[], actual: string[]) => { + const e = expected.map(e => e.label).sort(); + const a = actual.sort(); + assert.deepStrictEqual(e, a); + }; + + test('getGroupDefaultProfiles', () => { + addProfile({ isDefault: true, group: TestRunProfileBitset.Debug, label: 'a' }); + addProfile({ isDefault: false, group: TestRunProfileBitset.Debug, label: 'b' }); + addProfile({ isDefault: true, group: TestRunProfileBitset.Run, label: 'c' }); + addProfile({ isDefault: true, group: TestRunProfileBitset.Run, label: 'd', controllerId: '2' }); + addProfile({ isDefault: false, group: TestRunProfileBitset.Run, label: 'e', controllerId: '2' }); + expectProfiles(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), ['c', 'd']); + expectProfiles(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), ['a']); + }); + + suite('setGroupDefaultProfiles', () => { + test('applies simple changes', () => { + const p1 = addProfile({ isDefault: false, group: TestRunProfileBitset.Debug, label: 'a' }); + addProfile({ isDefault: false, group: TestRunProfileBitset.Debug, label: 'b' }); + const p3 = addProfile({ isDefault: false, group: TestRunProfileBitset.Run, label: 'c' }); + addProfile({ isDefault: false, group: TestRunProfileBitset.Run, label: 'd' }); + + t.setGroupDefaultProfiles(TestRunProfileBitset.Run, [p3]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p3]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p1]); + }); + + test('syncs labels if same', () => { + const p1 = addProfile({ isDefault: false, group: TestRunProfileBitset.Debug, label: 'a' }); + const p2 = addProfile({ isDefault: false, group: TestRunProfileBitset.Debug, label: 'b' }); + const p3 = addProfile({ isDefault: false, group: TestRunProfileBitset.Run, label: 'a' }); + const p4 = addProfile({ isDefault: false, group: TestRunProfileBitset.Run, label: 'b' }); + + t.setGroupDefaultProfiles(TestRunProfileBitset.Run, [p3]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p3]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p1]); + + t.setGroupDefaultProfiles(TestRunProfileBitset.Debug, [p2]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p4]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p2]); + }); + + test('does not mess up sync for multiple controllers', () => { + // ctrl a and b both of have their own labels. ctrl c does not and should be unaffected + const p1 = addProfile({ isDefault: false, controllerId: 'a', group: TestRunProfileBitset.Debug, label: 'a' }); + const p2 = addProfile({ isDefault: false, controllerId: 'b', group: TestRunProfileBitset.Debug, label: 'b1' }); + const p3 = addProfile({ isDefault: false, controllerId: 'b', group: TestRunProfileBitset.Debug, label: 'b2' }); + const p4 = addProfile({ isDefault: false, controllerId: 'c', group: TestRunProfileBitset.Debug, label: 'c1' }); + + const p5 = addProfile({ isDefault: false, controllerId: 'a', group: TestRunProfileBitset.Run, label: 'a' }); + const p6 = addProfile({ isDefault: false, controllerId: 'b', group: TestRunProfileBitset.Run, label: 'b1' }); + const p7 = addProfile({ isDefault: false, controllerId: 'b', group: TestRunProfileBitset.Run, label: 'b2' }); + const p8 = addProfile({ isDefault: false, controllerId: 'b', group: TestRunProfileBitset.Run, label: 'b3' }); + + // same profile on both + t.setGroupDefaultProfiles(TestRunProfileBitset.Debug, [p3]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p7]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p3]); + + // different profile, other should be unaffected + t.setGroupDefaultProfiles(TestRunProfileBitset.Run, [p8]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p8]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p3]); + + // multiple changes in one go, with unmatched c + t.setGroupDefaultProfiles(TestRunProfileBitset.Debug, [p1, p2, p4]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p5, p6]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p1, p2, p4]); + + // identity + t.setGroupDefaultProfiles(TestRunProfileBitset.Run, [p5, p8]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Run), [p5, p8]); + assert.deepStrictEqual(t.getGroupDefaultProfiles(TestRunProfileBitset.Debug), [p2, p4, p1]); + }); + }); +});