"use strict";
/**
 * Project Caffeine
 * 单元测试: promptService.ts
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
// 1. 全局 Mock fs/promises 模块
jest.mock('fs/promises');
// 2. 全局 Mock personas.json，提供测试专用的角色系统提示词
jest.mock('../../models/personas/personas.json', () => [
    { id: 'test_advisor', name: '测试顾问', systemPrompt: '这是一条测试专用的系统提示词' }
], { virtual: true });
describe('promptService', () => {
    // 使用 any 替代 typeof import，避免部分环境中未深度配置 ts-jest 导致的 Babel 解析报错
    let promptService;
    // 用于承载每次重置后的全新 fs mock 实例
    let fsMock;
    beforeEach(async () => {
        jest.clearAllMocks(); // 清理 mock 的调用统计
        jest.resetModules(); // 核心：重置模块注册表，清空 promptService 内部的 frameworksCache 状态
        // 【关键修复】在 resetModules 之后，必须重新 require mock 的 fs 模块！
        // 否则 promptService 内部引用的 fs 和这里外部的 fs 不是同一个实例，导致 mock 返回值失效并引发 TypeError。
        fsMock = require('fs/promises');
        promptService = await Promise.resolve().then(() => __importStar(require('../promptService')));
    });
    // 用于测试的伪造思维框架 JSON 数据
    const mockFrameworkJson = {
        name: "test_framework",
        description: "用于测试的伪造框架",
        parameters: [{ name: "topic", description: "测试主题", required: true }],
        template: "请分析这个主题：{{topic}}",
        persona: "test_advisor",
        examples: [
            {
                input: { topic: "人工智能" },
                output: "人工智能的分析结果"
            }
        ]
    };
    describe('listFrameworks', () => {
        it('应当成功读取并返回框架的元数据（且必须剔除 template 等内部字段）', async () => {
            // Given: 使用重新获取的 fsMock 模拟文件系统的返回
            fsMock.readdir.mockResolvedValueOnce(['test_framework.json']);
            fsMock.readFile.mockResolvedValueOnce(JSON.stringify(mockFrameworkJson));
            // When: 调用服务
            const result = await promptService.listFrameworks();
            // Then: 断言文件系统调用次数及返回值格式
            expect(fsMock.readdir).toHaveBeenCalledTimes(1);
            expect(fsMock.readFile).toHaveBeenCalledTimes(1);
            expect(result).toHaveLength(1);
            // 验证返回的元数据对象是否符合预期
            expect(result[0]).toEqual({
                name: "test_framework",
                description: "用于测试的伪造框架",
                parameters: [{ name: "topic", description: "测试主题", required: true }]
            });
            // 断言安全红线：不应该将模板内容暴露在 list 接口中
            expect(result[0].template).toBeUndefined();
        });
        it('异常流：当框架目录读取失败时，应当安全捕获错误并返回空数组', async () => {
            // 【新增优化】拦截并静音 console.error，避免预期的错误日志污染终端测试面板
            const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
            // 模拟磁盘异常
            fsMock.readdir.mockRejectedValueOnce(new Error('目录不存在或无权限'));
            const result = await promptService.listFrameworks();
            // 验证业务逻辑：服务不会崩溃，而是返回容错的空数组
            expect(result).toEqual([]);
            // 验证系统确实捕获并打印了预期的错误
            expect(consoleSpy).toHaveBeenCalledWith('[PromptService] 加载框架失败:', expect.any(Error));
            // 测试完毕后恢复 console.error 的正常行为
            consoleSpy.mockRestore();
        });
    });
    describe('getFramework', () => {
        beforeEach(() => {
            // 为 getFramework 的测试统一挂载成功的 Mock 返回
            fsMock.readdir.mockResolvedValue(['test_framework.json']);
            fsMock.readFile.mockResolvedValue(JSON.stringify(mockFrameworkJson));
        });
        it('异常流：当请求不存在的框架名称时，应当抛出明确的错误', async () => {
            await expect(promptService.getFramework('unknown_framework', {}))
                .rejects.toThrow('框架 "unknown_framework" 不存在');
        });
        it('核心逻辑：应当正确解析角色，并组装 System、Few-Shot 及 Current User 消息序列', async () => {
            // When: 请求框架，并传入动态参数
            const result = await promptService.getFramework('test_framework', { topic: '云计算' });
            const messages = result.messages;
            // Then: 应当精确包含 4 条消息 
            // (1x System, 1x Example User, 1x Example Assistant, 1x Current User)
            expect(messages).toHaveLength(4);
            // 1. 验证 System 提示词 (是否成功匹配并读取到了 Mock 的 persona 数据)
            expect(messages[0].role).toBe('system');
            expect(messages[0].content.text).toBe('这是一条测试专用的系统提示词');
            // 2. 验证 Few-Shot 示例中的 User 消息 (模板占位符是否被示例 input 正确替换)
            expect(messages[1].role).toBe('user');
            expect(messages[1].content.text).toBe('请分析这个主题：人工智能');
            // 3. 验证 Few-Shot 示例中的 Assistant 消息
            expect(messages[2].role).toBe('assistant');
            expect(messages[2].content.text).toBe('人工智能的分析结果');
            // 4. 验证当前用户请求 ({{topic}} 占位符是否被传入的 '云计算' 正确替换)
            expect(messages[3].role).toBe('user');
            expect(messages[3].content.text).toBe('请分析这个主题：云计算');
        });
        it('边界情况：如果多次调用 getFramework，验证内部框架缓存 (frameworksCache) 是否生效', async () => {
            // 第一次调用，会触发读盘
            await promptService.getFramework('test_framework', { topic: '测试1' });
            // 第二次调用，应该直接命中内部的 frameworksCache 缓存
            await promptService.getFramework('test_framework', { topic: '测试2' });
            // 断言：整个生命周期中，读盘操作应只有 1 次
            expect(fsMock.readdir).toHaveBeenCalledTimes(1);
            expect(fsMock.readFile).toHaveBeenCalledTimes(1);
        });
    });
});
//# sourceMappingURL=promptService.test.js.map