Path: blob/main/extensions/copilot/src/extension/chatSessions/claude/node/test/skillConfigLocations.spec.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { afterEach, beforeEach, describe, expect, it } from 'vitest';6import { IConfigurationService } from '../../../../../platform/configuration/common/configurationService';7import { InMemoryConfigurationService } from '../../../../../platform/configuration/test/common/inMemoryConfigurationService';8import { SKILLS_LOCATION_KEY } from '../../../../../platform/customInstructions/common/promptTypes';9import { INativeEnvService } from '../../../../../platform/env/common/envService';10import { NullNativeEnvService } from '../../../../../platform/env/common/nullEnvService';11import { IWorkspaceService } from '../../../../../platform/workspace/common/workspaceService';12import { Event } from '../../../../../util/vs/base/common/event';13import { DisposableStore } from '../../../../../util/vs/base/common/lifecycle';14import { URI } from '../../../../../util/vs/base/common/uri';15import { createExtensionUnitTestingServices } from '../../../../test/node/services';16import { resolveSkillConfigLocations } from '../../../common/skillConfigLocations';1718function createWorkspaceService(folders: URI[] = [URI.file('/workspace')]): IWorkspaceService {19return {20_serviceBrand: undefined,21onDidChangeWorkspaceFolders: Event.None,22getWorkspaceFolders: () => folders,23} as unknown as IWorkspaceService;24}2526describe('resolveSkillConfigLocations', () => {27const disposables = new DisposableStore();28let baseConfigurationService: IConfigurationService;2930beforeEach(() => {31const services = disposables.add(createExtensionUnitTestingServices());32const accessor = services.createTestingAccessor();33baseConfigurationService = accessor.get(IConfigurationService);34});3536afterEach(() => {37disposables.clear();38});3940function resolve(options?: {41configLocations?: Record<string, boolean>;42workspaceFolders?: URI[];43userHome?: URI;44}): URI[] {45const configService = new InMemoryConfigurationService(baseConfigurationService);46if (options?.configLocations) {47configService.setNonExtensionConfig(SKILLS_LOCATION_KEY, options.configLocations);48}4950const envService: INativeEnvService = options?.userHome51? new class extends NullNativeEnvService { override get userHome() { return options.userHome!; } }()52: new NullNativeEnvService();5354const workspaceService = createWorkspaceService(options?.workspaceFolders);5556return resolveSkillConfigLocations(configService, envService, workspaceService);57}5859it('returns empty array when no config is set', () => {60expect(resolve()).toEqual([]);61});6263it('returns empty array when config is not an object', () => {64const configService = new InMemoryConfigurationService(baseConfigurationService);65configService.setNonExtensionConfig(SKILLS_LOCATION_KEY, 'not-an-object');66const result = resolveSkillConfigLocations(67configService,68new NullNativeEnvService(),69createWorkspaceService(),70);71expect(result).toEqual([]);72});7374it('expands tilde-prefixed paths using user home directory', () => {75const result = resolve({76configLocations: { '~/my-skills': true },77userHome: URI.file('/home/user'),78});79expect(result).toHaveLength(1);80expect(result[0].path).toBe('/home/user/my-skills');81});8283it('handles absolute paths', () => {84const result = resolve({85configLocations: { '/absolute/skills/path': true },86});87expect(result).toHaveLength(1);88expect(result[0].path).toBe('/absolute/skills/path');89});9091it('joins relative paths to each workspace folder', () => {92const result = resolve({93configLocations: { 'relative/skills': true },94workspaceFolders: [URI.file('/workspace1'), URI.file('/workspace2')],95});96expect(result).toHaveLength(2);97expect(result[0].path).toBe('/workspace1/relative/skills');98expect(result[1].path).toBe('/workspace2/relative/skills');99});100101it('ignores config entries with value !== true', () => {102const result = resolve({103configLocations: {104'/included': true,105'/excluded': false,106},107});108expect(result).toHaveLength(1);109expect(result[0].path).toBe('/included');110});111112it('handles mixed path types', () => {113const result = resolve({114configLocations: {115'~/home-skills': true,116'/absolute-skills': true,117'relative-skills': true,118},119userHome: URI.file('/home/user'),120workspaceFolders: [URI.file('/workspace')],121});122expect(result).toHaveLength(3);123expect(result[0].path).toBe('/home/user/home-skills');124expect(result[1].path).toBe('/absolute-skills');125expect(result[2].path).toBe('/workspace/relative-skills');126});127128it('trims whitespace from location keys', () => {129const result = resolve({130configLocations: { ' /trimmed ': true },131});132expect(result).toHaveLength(1);133expect(result[0].path).toBe('/trimmed');134});135});136137138