mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-15 00:21:09 -07:00
157 lines
4.1 KiB
TypeScript
157 lines
4.1 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/// <reference types="vitest/globals" />
|
|
|
|
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
|
import * as fs from 'node:fs';
|
|
|
|
const mockCoreEvents = vi.hoisted(() => ({
|
|
emitFeedback: vi.fn(),
|
|
emitConsoleLog: vi.fn(),
|
|
emitOutput: vi.fn(),
|
|
emitModelChanged: vi.fn(),
|
|
drainBacklogs: vi.fn(),
|
|
}));
|
|
|
|
const mockIsWorkspaceTrusted = vi.hoisted(() =>
|
|
vi.fn().mockReturnValue({ isTrusted: true, source: 'file' }),
|
|
);
|
|
|
|
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
|
const actual =
|
|
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
|
return {
|
|
...actual,
|
|
coreEvents: mockCoreEvents,
|
|
Storage: class extends actual.Storage {
|
|
static override getGlobalSettingsPath = () =>
|
|
'/mock/home/user/.gemini/settings.json';
|
|
override getWorkspaceSettingsPath = () =>
|
|
'/mock/workspace/.gemini/settings.json';
|
|
static override getGlobalGeminiDir = () => '/mock/home/user/.gemini';
|
|
},
|
|
};
|
|
});
|
|
|
|
vi.mock('./trustedFolders.js', () => ({
|
|
isWorkspaceTrusted: mockIsWorkspaceTrusted,
|
|
loadTrustedFolders: vi.fn().mockReturnValue({
|
|
isPathTrusted: vi.fn().mockReturnValue(true),
|
|
user: { config: {} },
|
|
errors: [],
|
|
}),
|
|
isFolderTrustEnabled: vi.fn().mockReturnValue(false),
|
|
TrustLevel: {
|
|
TRUST_FOLDER: 'TRUST_FOLDER',
|
|
TRUST_PARENT: 'TRUST_PARENT',
|
|
DO_NOT_TRUST: 'DO_NOT_TRUST',
|
|
},
|
|
}));
|
|
|
|
vi.mock('os', () => ({
|
|
homedir: () => '/mock/home/user',
|
|
platform: () => 'linux',
|
|
totalmem: () => 16 * 1024 * 1024 * 1024,
|
|
}));
|
|
|
|
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(),
|
|
renameSync: vi.fn(),
|
|
realpathSync: (p: string) => p,
|
|
};
|
|
});
|
|
|
|
// Import loadSettings after all mocks are defined
|
|
import {
|
|
loadSettings,
|
|
USER_SETTINGS_PATH,
|
|
type LoadedSettings,
|
|
} from './settings.js';
|
|
|
|
const MOCK_WORKSPACE_DIR = '/mock/workspace';
|
|
|
|
describe('Settings Validation Warning', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
(fs.readFileSync as Mock).mockReturnValue('{}');
|
|
(fs.existsSync as Mock).mockReturnValue(false);
|
|
});
|
|
|
|
it('should emit a warning and NOT throw when settings are invalid', () => {
|
|
(fs.existsSync as Mock).mockImplementation(
|
|
(p: string) => p === USER_SETTINGS_PATH,
|
|
);
|
|
|
|
const invalidSettingsContent = {
|
|
ui: {
|
|
customThemes: {
|
|
terafox: {
|
|
name: 'terafox',
|
|
type: 'custom',
|
|
DiffModified: '#ffffff', // Invalid key
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
(fs.readFileSync as Mock).mockImplementation((p: string) => {
|
|
if (p === USER_SETTINGS_PATH)
|
|
return JSON.stringify(invalidSettingsContent);
|
|
return '{}';
|
|
});
|
|
|
|
// Should NOT throw
|
|
let settings: LoadedSettings | undefined;
|
|
expect(() => {
|
|
settings = loadSettings(MOCK_WORKSPACE_DIR);
|
|
}).not.toThrow();
|
|
|
|
// Should have recorded a warning in the settings object
|
|
expect(
|
|
settings?.errors.some((e) =>
|
|
e.message.includes("Unrecognized key(s) in object: 'DiffModified'"),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it('should throw a fatal error when settings file is not a valid JSON object', () => {
|
|
(fs.existsSync as Mock).mockImplementation(
|
|
(p: string) => p === USER_SETTINGS_PATH,
|
|
);
|
|
|
|
(fs.readFileSync as Mock).mockImplementation((p: string) => {
|
|
if (p === USER_SETTINGS_PATH) return '[]';
|
|
return '{}';
|
|
});
|
|
|
|
expect(() => {
|
|
loadSettings(MOCK_WORKSPACE_DIR);
|
|
}).toThrow();
|
|
});
|
|
|
|
it('should throw a fatal error when settings file contains invalid JSON', () => {
|
|
(fs.existsSync as Mock).mockImplementation(
|
|
(p: string) => p === USER_SETTINGS_PATH,
|
|
);
|
|
|
|
(fs.readFileSync as Mock).mockImplementation((p: string) => {
|
|
if (p === USER_SETTINGS_PATH) return '{ "invalid": "json", }'; // Trailing comma is invalid in standard JSON
|
|
return '{}';
|
|
});
|
|
|
|
expect(() => {
|
|
loadSettings(MOCK_WORKSPACE_DIR);
|
|
}).toThrow();
|
|
});
|
|
});
|