UNPKG

dpml-prompt

Version:

DPML-powered AI prompt framework - Revolutionary AI-First CLI system based on Deepractice Prompt Markup Language. Build sophisticated AI agents with structured prompts, memory systems, and execution frameworks.

361 lines (299 loc) 12.9 kB
const PackageProtocol = require('../../../../lib/core/resource/protocols/PackageProtocol') const { QueryParams } = require('../../../../lib/core/resource/types') const path = require('path') const fs = require('fs').promises describe('PackageProtocol', () => { let packageProtocol const originalEnv = process.env const projectRoot = process.cwd() // PromptX项目根目录 beforeEach(() => { packageProtocol = new PackageProtocol() // 重置环境变量 process.env = { ...originalEnv } }) afterEach(() => { packageProtocol.clearCache() process.env = originalEnv }) describe('基础功能', () => { test('应该正确初始化协议', () => { expect(packageProtocol.name).toBe('package') expect(packageProtocol.installModeCache).toBeInstanceOf(Map) }) test('应该提供协议信息', () => { const info = packageProtocol.getProtocolInfo() expect(info.name).toBe('package') expect(info.description).toContain('包协议') expect(info.examples).toContain('@package://package.json') expect(info.examples).toContain('@package://src/index.js') expect(info.installModes).toContain('development') }) test('应该支持缓存', () => { expect(packageProtocol.enableCache).toBe(true) expect(packageProtocol.cache).toBeInstanceOf(Map) expect(packageProtocol.installModeCache).toBeInstanceOf(Map) }) }) describe('安装模式检测', () => { test('应该检测开发模式', () => { // 设置开发环境 process.env.NODE_ENV = 'development' packageProtocol.clearCache() const mode = packageProtocol.detectInstallMode() expect(mode).toBe('development') }) test('应该检测npx执行模式', () => { // 模拟npx环境 process.env.npm_execpath = '/usr/local/bin/npx' packageProtocol.clearCache() const mode = packageProtocol.detectInstallMode() expect(mode).toBe('npx') }) test('应该缓存检测结果', () => { const mode1 = packageProtocol.detectInstallMode() const mode2 = packageProtocol.detectInstallMode() expect(mode1).toBe(mode2) expect(packageProtocol.installModeCache.size).toBe(1) }) test('检测结果应该是有效的安装模式', () => { const mode = packageProtocol.detectInstallMode() const validModes = ['development', 'local', 'global', 'npx', 'monorepo', 'link'] expect(validModes).toContain(mode) }) }) describe('NPX执行检测', () => { test('应该通过npm_execpath检测npx', () => { process.env.npm_execpath = '/path/to/npx' expect(packageProtocol._isNpxExecution()).toBe(true) }) test('应该通过npm_config_cache检测npx', () => { process.env.npm_config_cache = '/tmp/_npx/cache' expect(packageProtocol._isNpxExecution()).toBe(true) }) test('正常情况下应该返回false', () => { delete process.env.npm_execpath delete process.env.npm_config_cache expect(packageProtocol._isNpxExecution()).toBe(false) }) }) describe('全局安装检测', () => { test('应该检测常见的全局路径', () => { // 这个测试在实际环境中可能会失败,因为我们无法轻易改变__dirname const result = packageProtocol._isGlobalInstall() expect(typeof result).toBe('boolean') }) }) describe('开发模式检测', () => { test('应该通过NODE_ENV检测开发模式', () => { process.env.NODE_ENV = 'development' expect(packageProtocol._isDevelopmentMode()).toBe(true) }) test('应该检测非node_modules目录', () => { // 当前测试环境应该不在node_modules中 const result = packageProtocol._isDevelopmentMode() expect(typeof result).toBe('boolean') }) }) describe('包查找功能', () => { test('应该能找到package.json', () => { const packageJsonPath = packageProtocol.findPackageJson() expect(packageJsonPath).toBeTruthy() expect(packageJsonPath).toMatch(/package\.json$/) }) test('应该能找到根package.json', () => { const rootPackageJsonPath = packageProtocol.findRootPackageJson() expect(rootPackageJsonPath).toBeTruthy() expect(rootPackageJsonPath).toMatch(/package\.json$/) }) test('查找不存在的package.json应该返回null', () => { const result = packageProtocol.findPackageJson('/nonexistent/path') expect(result).toBeNull() }) }) describe('包根目录获取', () => { test('应该能获取包根目录', async () => { const packageRoot = await packageProtocol.getPackageRoot() expect(packageRoot).toBeTruthy() expect(typeof packageRoot).toBe('string') expect(path.isAbsolute(packageRoot)).toBe(true) }) test('项目根目录查找应该工作正常', () => { const root = packageProtocol._findProjectRoot() expect(root).toBeTruthy() expect(path.isAbsolute(root)).toBe(true) }) }) describe('路径解析', () => { test('应该解析package.json路径', async () => { const resolved = await packageProtocol.resolvePath('package.json') expect(resolved).toMatch(/package\.json$/) expect(path.isAbsolute(resolved)).toBe(true) }) test('应该解析src目录路径', async () => { const resolved = await packageProtocol.resolvePath('src/index.js') expect(resolved).toContain('src') expect(resolved).toMatch(/index\.js$/) }) test('应该解析prompt目录路径', async () => { const resolved = await packageProtocol.resolvePath('prompt/core/thought.md') expect(resolved).toContain('prompt') expect(resolved).toContain('core') expect(resolved).toMatch(/thought\.md$/) }) test('空路径应该返回包根目录', async () => { const resolved = await packageProtocol.resolvePath('') expect(path.isAbsolute(resolved)).toBe(true) expect(resolved).toBeTruthy() }) test('只有空格的路径应该返回包根目录', async () => { const resolved = await packageProtocol.resolvePath(' ') expect(path.isAbsolute(resolved)).toBe(true) expect(resolved).toBeTruthy() }) test('应该使用缓存', async () => { const path1 = await packageProtocol.resolvePath('package.json') const path2 = await packageProtocol.resolvePath('package.json') expect(path1).toBe(path2) expect(packageProtocol.cache.size).toBeGreaterThan(0) }) }) describe('路径安全检查', () => { test('应该阻止目录遍历攻击', async () => { await expect( packageProtocol.resolvePath('../../../etc/passwd') ).rejects.toThrow('路径安全检查失败') }) test('正常的相对路径应该被允许', async () => { const resolved = await packageProtocol.resolvePath('src/lib/utils.js') expect(resolved).toContain('src') expect(resolved).toContain('lib') expect(resolved).toMatch(/utils\.js$/) }) }) describe('资源存在性检查', () => { test('存在的文件应该返回true', async () => { const exists = await packageProtocol.exists('package.json') expect(exists).toBe(true) }) test('不存在的文件应该返回false', async () => { const exists = await packageProtocol.exists('nonexistent.txt') expect(exists).toBe(false) }) }) describe('内容加载', () => { test('应该能加载package.json内容', async () => { const resolvedPath = await packageProtocol.resolvePath('package.json') const result = await packageProtocol.loadContent(resolvedPath) expect(result).toHaveProperty('content') expect(result).toHaveProperty('path') expect(result).toHaveProperty('protocol', 'package') expect(result).toHaveProperty('installMode') expect(result).toHaveProperty('metadata') expect(result.metadata).toHaveProperty('size') expect(result.metadata).toHaveProperty('lastModified') expect(result.metadata).toHaveProperty('absolutePath') expect(result.metadata).toHaveProperty('relativePath') // 验证内容是有效的JSON expect(() => JSON.parse(result.content)).not.toThrow() }) test('加载不存在的文件应该抛出错误', async () => { const resolvedPath = await packageProtocol.resolvePath('nonexistent.txt') await expect( packageProtocol.loadContent(resolvedPath) ).rejects.toThrow('包资源不存在') }) test('返回的metadata应该包含正确信息', async () => { const resolvedPath = await packageProtocol.resolvePath('package.json') const result = await packageProtocol.loadContent(resolvedPath) expect(result.metadata.size).toBe(result.content.length) expect(result.metadata.lastModified.constructor.name).toBe('Date') expect(path.isAbsolute(result.metadata.absolutePath)).toBe(true) expect(result.metadata.relativePath).toBe('package.json') }) }) describe('查询参数支持', () => { test('应该支持查询参数', async () => { const queryParams = new QueryParams() queryParams.set('encoding', 'utf8') const resolved = await packageProtocol.resolvePath('package.json', queryParams) expect(resolved).toMatch(/package\.json$/) }) test('相同路径但不同查询参数应该有不同的缓存', async () => { const queryParams1 = new QueryParams() queryParams1.set('test', 'value1') const queryParams2 = new QueryParams() queryParams2.set('test', 'value2') await packageProtocol.resolvePath('package.json', queryParams1) await packageProtocol.resolvePath('package.json', queryParams2) expect(packageProtocol.cache.size).toBeGreaterThan(1) }) }) describe('调试信息', () => { test('应该提供完整的调试信息', () => { const debugInfo = packageProtocol.getDebugInfo() expect(debugInfo).toHaveProperty('protocol', 'package') expect(debugInfo).toHaveProperty('installMode') expect(debugInfo).toHaveProperty('packageRoot') expect(debugInfo).toHaveProperty('currentWorkingDirectory') expect(debugInfo).toHaveProperty('moduleDirectory') expect(debugInfo).toHaveProperty('environment') expect(debugInfo).toHaveProperty('cacheSize') expect(debugInfo.environment).toHaveProperty('NODE_ENV') expect(debugInfo.environment).toHaveProperty('npm_execpath') expect(debugInfo.environment).toHaveProperty('npm_config_cache') }) }) describe('缓存管理', () => { test('应该能清理所有缓存', async () => { // 生成一些缓存 await packageProtocol.resolvePath('package.json') packageProtocol.detectInstallMode() expect(packageProtocol.cache.size).toBeGreaterThan(0) expect(packageProtocol.installModeCache.size).toBeGreaterThan(0) packageProtocol.clearCache() expect(packageProtocol.cache.size).toBe(0) expect(packageProtocol.installModeCache.size).toBe(0) }) }) describe('错误处理', () => { test('文件系统错误应该被正确处理', async () => { // 尝试访问一个权限不足的路径(如果存在的话) const result = await packageProtocol.exists('../../../root/.ssh/id_rsa') expect(typeof result).toBe('boolean') }) test('路径解析错误应该包含有用信息', async () => { try { await packageProtocol.resolvePath('../../../etc/passwd') } catch (error) { expect(error.message).toContain('路径安全检查失败') } }) }) describe('边界情况', () => { test('深层嵌套路径应该正确处理', async () => { const resolved = await packageProtocol.resolvePath('src/lib/core/resource/protocols/test.js') expect(resolved).toContain('src') expect(resolved).toContain('lib') expect(resolved).toContain('core') expect(resolved).toContain('resource') expect(resolved).toContain('protocols') expect(resolved).toMatch(/test\.js$/) }) test('特殊字符路径应该被正确处理', async () => { const resolved = await packageProtocol.resolvePath('assets/images/logo-2024.png') expect(resolved).toContain('assets') expect(resolved).toContain('images') expect(resolved).toMatch(/logo-2024\.png$/) }) test('带有空格的路径应该被正确处理', async () => { const resolved = await packageProtocol.resolvePath('docs/user guide.md') expect(resolved).toContain('docs') expect(resolved).toMatch(/user guide\.md$/) }) test('中文路径应该被正确处理', async () => { const resolved = await packageProtocol.resolvePath('文档/说明.md') expect(resolved).toContain('文档') expect(resolved).toMatch(/说明\.md$/) }) }) })