mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 01:07:46 +00:00
209 lines
6.3 KiB
TypeScript
209 lines
6.3 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
// Mock 'os' first.
|
|
import * as osActual from 'os';
|
|
vi.mock('os', async (importOriginal) => {
|
|
const actualOs = await importOriginal<typeof osActual>();
|
|
return {
|
|
...actualOs,
|
|
homedir: vi.fn(() => '/mock/home/user'),
|
|
platform: vi.fn(() => 'linux'),
|
|
};
|
|
});
|
|
|
|
import {
|
|
describe,
|
|
it,
|
|
expect,
|
|
vi,
|
|
beforeEach,
|
|
afterEach,
|
|
type Mocked,
|
|
type Mock,
|
|
} from 'vitest';
|
|
import * as fs from 'fs';
|
|
import stripJsonComments from 'strip-json-comments';
|
|
import * as path from 'path';
|
|
|
|
import {
|
|
loadTrustedFolders,
|
|
USER_TRUSTED_FOLDERS_PATH,
|
|
TrustLevel,
|
|
isWorkspaceTrusted,
|
|
} from './trustedFolders.js';
|
|
import { Settings } from './settings.js';
|
|
|
|
vi.mock('fs', async (importOriginal) => {
|
|
const actualFs = await importOriginal<typeof fs>();
|
|
return {
|
|
...actualFs,
|
|
existsSync: vi.fn(),
|
|
readFileSync: vi.fn(),
|
|
writeFileSync: vi.fn(),
|
|
mkdirSync: vi.fn(),
|
|
};
|
|
});
|
|
|
|
vi.mock('strip-json-comments', () => ({
|
|
default: vi.fn((content) => content),
|
|
}));
|
|
|
|
describe('Trusted Folders Loading', () => {
|
|
let mockFsExistsSync: Mocked<typeof fs.existsSync>;
|
|
let mockStripJsonComments: Mocked<typeof stripJsonComments>;
|
|
let mockFsWriteFileSync: Mocked<typeof fs.writeFileSync>;
|
|
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
mockFsExistsSync = vi.mocked(fs.existsSync);
|
|
mockStripJsonComments = vi.mocked(stripJsonComments);
|
|
mockFsWriteFileSync = vi.mocked(fs.writeFileSync);
|
|
vi.mocked(osActual.homedir).mockReturnValue('/mock/home/user');
|
|
(mockStripJsonComments as unknown as Mock).mockImplementation(
|
|
(jsonString: string) => jsonString,
|
|
);
|
|
(mockFsExistsSync as Mock).mockReturnValue(false);
|
|
(fs.readFileSync as Mock).mockReturnValue('{}');
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it('should load empty rules if no files exist', () => {
|
|
const { rules, errors } = loadTrustedFolders();
|
|
expect(rules).toEqual([]);
|
|
expect(errors).toEqual([]);
|
|
});
|
|
|
|
it('should load user rules if only user file exists', () => {
|
|
const userPath = USER_TRUSTED_FOLDERS_PATH;
|
|
(mockFsExistsSync as Mock).mockImplementation((p) => p === userPath);
|
|
const userContent = {
|
|
'/user/folder': TrustLevel.TRUST_FOLDER,
|
|
};
|
|
(fs.readFileSync as Mock).mockImplementation((p) => {
|
|
if (p === userPath) return JSON.stringify(userContent);
|
|
return '{}';
|
|
});
|
|
|
|
const { rules, errors } = loadTrustedFolders();
|
|
expect(rules).toEqual([
|
|
{ path: '/user/folder', trustLevel: TrustLevel.TRUST_FOLDER },
|
|
]);
|
|
expect(errors).toEqual([]);
|
|
});
|
|
|
|
it('should handle JSON parsing errors gracefully', () => {
|
|
const userPath = USER_TRUSTED_FOLDERS_PATH;
|
|
(mockFsExistsSync as Mock).mockImplementation((p) => p === userPath);
|
|
(fs.readFileSync as Mock).mockImplementation((p) => {
|
|
if (p === userPath) return 'invalid json';
|
|
return '{}';
|
|
});
|
|
|
|
const { rules, errors } = loadTrustedFolders();
|
|
expect(rules).toEqual([]);
|
|
expect(errors.length).toBe(1);
|
|
expect(errors[0].path).toBe(userPath);
|
|
expect(errors[0].message).toContain('Unexpected token');
|
|
});
|
|
|
|
it('setValue should update the user config and save it', () => {
|
|
const loadedFolders = loadTrustedFolders();
|
|
loadedFolders.setValue('/new/path', TrustLevel.TRUST_FOLDER);
|
|
|
|
expect(loadedFolders.user.config['/new/path']).toBe(
|
|
TrustLevel.TRUST_FOLDER,
|
|
);
|
|
expect(mockFsWriteFileSync).toHaveBeenCalledWith(
|
|
USER_TRUSTED_FOLDERS_PATH,
|
|
JSON.stringify({ '/new/path': TrustLevel.TRUST_FOLDER }, null, 2),
|
|
'utf-8',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('isWorkspaceTrusted', () => {
|
|
let mockCwd: string;
|
|
const mockRules: Record<string, TrustLevel> = {};
|
|
const mockSettings: Settings = {
|
|
folderTrustFeature: true,
|
|
folderTrust: true,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.spyOn(process, 'cwd').mockImplementation(() => mockCwd);
|
|
vi.spyOn(fs, 'readFileSync').mockImplementation((p) => {
|
|
if (p === USER_TRUSTED_FOLDERS_PATH) {
|
|
return JSON.stringify(mockRules);
|
|
}
|
|
return '{}';
|
|
});
|
|
vi.spyOn(fs, 'existsSync').mockImplementation(
|
|
(p) => p === USER_TRUSTED_FOLDERS_PATH,
|
|
);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
// Clear the object
|
|
Object.keys(mockRules).forEach((key) => delete mockRules[key]);
|
|
});
|
|
|
|
it('should return true for a directly trusted folder', () => {
|
|
mockCwd = '/home/user/projectA';
|
|
mockRules['/home/user/projectA'] = TrustLevel.TRUST_FOLDER;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBe(true);
|
|
});
|
|
|
|
it('should return true for a child of a trusted folder', () => {
|
|
mockCwd = '/home/user/projectA/src';
|
|
mockRules['/home/user/projectA'] = TrustLevel.TRUST_FOLDER;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBe(true);
|
|
});
|
|
|
|
it('should return true for a child of a trusted parent folder', () => {
|
|
mockCwd = '/home/user/projectB';
|
|
mockRules['/home/user/projectB/somefile.txt'] = TrustLevel.TRUST_PARENT;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBe(true);
|
|
});
|
|
|
|
it('should return false for a directly untrusted folder', () => {
|
|
mockCwd = '/home/user/untrusted';
|
|
mockRules['/home/user/untrusted'] = TrustLevel.DO_NOT_TRUST;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBe(false);
|
|
});
|
|
|
|
it('should return undefined for a child of an untrusted folder', () => {
|
|
mockCwd = '/home/user/untrusted/src';
|
|
mockRules['/home/user/untrusted'] = TrustLevel.DO_NOT_TRUST;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBeUndefined();
|
|
});
|
|
|
|
it('should return undefined when no rules match', () => {
|
|
mockCwd = '/home/user/other';
|
|
mockRules['/home/user/projectA'] = TrustLevel.TRUST_FOLDER;
|
|
mockRules['/home/user/untrusted'] = TrustLevel.DO_NOT_TRUST;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBeUndefined();
|
|
});
|
|
|
|
it('should prioritize trust over distrust', () => {
|
|
mockCwd = '/home/user/projectA/untrusted';
|
|
mockRules['/home/user/projectA'] = TrustLevel.TRUST_FOLDER;
|
|
mockRules['/home/user/projectA/untrusted'] = TrustLevel.DO_NOT_TRUST;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBe(true);
|
|
});
|
|
|
|
it('should handle path normalization', () => {
|
|
mockCwd = '/home/user/projectA';
|
|
mockRules[`/home/user/../user/${path.basename('/home/user/projectA')}`] =
|
|
TrustLevel.TRUST_FOLDER;
|
|
expect(isWorkspaceTrusted(mockSettings)).toBe(true);
|
|
});
|
|
});
|