UNPKG

@mdfriday/foundry

Version:

The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.

188 lines 8.16 kB
"use strict"; 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const path = __importStar(require("path")); const livereload_server_1 = require("./livereload-server"); describe('FoundryLiveReloadServer - 跨平台兼容性测试', () => { let server; let config; beforeEach(() => { config = { port: 8091, host: 'localhost', publicDir: process.platform === 'win32' ? 'C:\\test\\public' : '/test/public', enableLiveReload: true }; server = new livereload_server_1.FoundryLiveReloadServer(config); }); describe('路径解析测试', () => { const testCases = [ { name: '基本中文路径', url: '/preview/randomxxx/中文/中文.html', expectedPosix: '/test/public/preview/randomxxx/中文/中文.html', expectedWin32: 'C:\\test\\public\\preview\\randomxxx\\中文\\中文.html' }, { name: 'URL编码的中文路径', url: '/preview/randomxxx/%E4%B8%AD%E6%96%87/%E4%B8%AD%E6%96%87.html', expectedPosix: '/test/public/preview/randomxxx/中文/中文.html', expectedWin32: 'C:\\test\\public\\preview\\randomxxx\\中文\\中文.html' }, { name: '混合编码路径', url: '/preview/randomxxx/中文/%E4%B8%AD%E6%96%87.html', expectedPosix: '/test/public/preview/randomxxx/中文/中文.html', expectedWin32: 'C:\\test\\public\\preview\\randomxxx\\中文\\中文.html' }, { name: '带查询参数的路径', url: '/preview/randomxxx/中文/中文.html?t=123&v=456', expectedPosix: '/test/public/preview/randomxxx/中文/中文.html', expectedWin32: 'C:\\test\\public\\preview\\randomxxx\\中文\\中文.html' }, { name: '带锚点的路径', url: '/preview/randomxxx/中文/中文.html#section1', expectedPosix: '/test/public/preview/randomxxx/中文/中文.html', expectedWin32: 'C:\\test\\public\\preview\\randomxxx\\中文\\中文.html' } ]; testCases.forEach(testCase => { it(`应该正确解析${testCase.name}`, () => { // 使用反射访问私有方法进行测试 const resolvedPath = server.resolveFilePath(testCase.url); if (process.platform === 'win32') { expect(resolvedPath).toBe(testCase.expectedWin32); } else { expect(resolvedPath).toBe(testCase.expectedPosix); } // 验证路径包含中文字符 expect(/[\u4e00-\u9fa5]/.test(resolvedPath)).toBe(true); }); }); }); describe('安全性测试', () => { const maliciousUrls = [ '../../../etc/passwd', '..\\..\\..\\windows\\system32\\config\\sam', '/preview/../../../sensitive.txt', '/preview/..%2F..%2F..%2Fsensitive.txt', '/preview/%2e%2e%2f%2e%2e%2f%2e%2e%2fsensitive.txt' ]; maliciousUrls.forEach(url => { it(`应该防止目录遍历攻击: ${url}`, () => { const resolvedPath = server.resolveFilePath(url); // 确保解析后的路径仍在 publicDir 内 const normalizedPublic = path.normalize(config.publicDir); const normalizedResolved = path.normalize(resolvedPath); expect(normalizedResolved.startsWith(normalizedPublic)).toBe(true); }); }); }); describe('错误处理测试', () => { it('应该处理无效的URL编码', () => { const invalidUrls = [ '/preview/%XX/file.html', // 无效的十六进制 '/preview/%E4%B8%AD%E6%96%87%XX/file.html', // 部分无效编码 '/preview/%/file.html' // 不完整的编码 ]; invalidUrls.forEach(url => { expect(() => { server.resolveFilePath(url); }).not.toThrow(); }); }); }); describe('Windows特定测试', () => { // 这些测试只在Windows环境下运行,或者模拟Windows环境 const originalPlatform = process.platform; afterEach(() => { // 恢复原始平台设置 Object.defineProperty(process, 'platform', { value: originalPlatform }); }); it('应该检测Windows非法字符', () => { // 模拟Windows环境 Object.defineProperty(process, 'platform', { value: 'win32' }); const invalidChars = ['<', '>', ':', '"', '|', '?', '*']; invalidChars.forEach(char => { const url = `/preview/file${char}name.html`; // 这应该不会抛出异常,但会记录警告 expect(() => { server.resolveFilePath(url); }).not.toThrow(); }); }); it('应该检测Windows路径长度限制', () => { // 模拟Windows环境 Object.defineProperty(process, 'platform', { value: 'win32' }); // 创建一个超长路径 const longPath = '/preview/' + 'a'.repeat(300) + '/file.html'; expect(() => { server.resolveFilePath(longPath); }).not.toThrow(); }); }); describe('MIME类型测试', () => { const mimeTestCases = [ { file: '中文.html', expected: 'text/html; charset=utf-8' }, { file: '测试.css', expected: 'text/css; charset=utf-8' }, { file: '脚本.js', expected: 'application/javascript; charset=utf-8' }, { file: '图片.png', expected: 'image/png' }, { file: '文档.pdf', expected: 'application/octet-stream' } ]; mimeTestCases.forEach(testCase => { it(`应该为${testCase.file}返回正确的MIME类型`, () => { const contentType = server.getContentType(`/path/to/${testCase.file}`); expect(contentType).toBe(testCase.expected); }); }); }); }); // 辅助函数:创建跨平台路径测试 function createCrossPlatformPathTest(description, testFn) { describe(description, () => { it('在POSIX系统上', () => testFn(path.posix)); it('在Windows系统上', () => testFn(path.win32)); }); } //# sourceMappingURL=livereload-server.test.js.map