@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
JavaScript
;
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