UNPKG

@mdfriday/foundry

Version:

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

363 lines 16.2 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 osfs_1 = require("../vo/osfs"); const fs = __importStar(require("fs/promises")); // Mock fs/promises jest.mock('fs/promises'); jest.mock('@pkg/log'); const mockFs = fs; describe('OS Filesystem Value Objects', () => { afterEach(() => { jest.clearAllMocks(); }); describe('OsFileInfo', () => { let mockStats; let osFileInfo; beforeEach(() => { mockStats = { size: 1024, mode: 0o644, mtime: new Date('2023-01-01'), isDirectory: jest.fn().mockReturnValue(false), }; osFileInfo = new osfs_1.OsFileInfo(mockStats, 'test.txt'); }); it('should return correct name', () => { expect(osFileInfo.name()).toBe('test.txt'); }); it('should return correct size', () => { expect(osFileInfo.size()).toBe(1024); }); it('should return correct mode', () => { expect(osFileInfo.mode()).toBe(0o644); }); it('should return correct modification time', () => { expect(osFileInfo.modTime()).toEqual(new Date('2023-01-01')); }); it('should return correct isDir status', () => { expect(osFileInfo.isDir()).toBe(false); expect(mockStats.isDirectory).toHaveBeenCalledTimes(1); }); it('should return stats as sys info', () => { expect(osFileInfo.sys()).toBe(mockStats); }); it('should handle directory stats', () => { mockStats.isDirectory.mockReturnValue(true); expect(osFileInfo.isDir()).toBe(true); }); }); describe('OsFile', () => { let osFile; let mockHandle; beforeEach(() => { mockHandle = { close: jest.fn(), read: jest.fn(), write: jest.fn(), stat: jest.fn(), sync: jest.fn(), truncate: jest.fn(), }; mockFs.open.mockResolvedValue(mockHandle); osFile = new osfs_1.OsFile('/test/file.txt', 'r'); }); describe('constructor', () => { it('should initialize with file path and flags', () => { expect(osFile.name()).toBe('/test/file.txt'); }); }); describe('ensureOpen', () => { it('should open file handle when not already open', async () => { await osFile.ensureOpen(); expect(mockFs.open).toHaveBeenCalledWith('/test/file.txt', 'r'); }); it('should not open file handle when already open', async () => { await osFile.ensureOpen(); await osFile.ensureOpen(); expect(mockFs.open).toHaveBeenCalledTimes(1); }); it('should not open file handle when closed', async () => { await osFile.close(); await osFile.ensureOpen(); expect(mockFs.open).not.toHaveBeenCalled(); }); }); describe('close', () => { it('should close file handle when open', async () => { await osFile.ensureOpen(); await osFile.close(); expect(mockHandle.close).toHaveBeenCalledTimes(1); }); it('should handle close when handle is null', async () => { await osFile.close(); expect(mockHandle.close).not.toHaveBeenCalled(); }); it('should set closed flag', async () => { await osFile.close(); await expect(osFile.read(new Uint8Array(10))).rejects.toThrow('File is closed'); }); }); describe('read', () => { it('should read data from file', async () => { const buffer = new Uint8Array(10); mockHandle.read.mockResolvedValue({ bytesRead: 5 }); const result = await osFile.read(buffer); expect(mockHandle.read).toHaveBeenCalledWith(buffer, 0, 10, 0); expect(result.bytesRead).toBe(5); expect(result.buffer).toBe(buffer); }); it('should update position after read', async () => { const buffer = new Uint8Array(10); mockHandle.read.mockResolvedValue({ bytesRead: 5 }); await osFile.read(buffer); await osFile.read(buffer); expect(mockHandle.read).toHaveBeenNthCalledWith(1, buffer, 0, 10, 0); expect(mockHandle.read).toHaveBeenNthCalledWith(2, buffer, 0, 10, 5); }); it('should throw error when file is closed', async () => { await osFile.close(); await expect(osFile.read(new Uint8Array(10))).rejects.toThrow('File is closed'); }); }); describe('readAt', () => { it('should read data at specific offset', async () => { const buffer = new Uint8Array(10); mockHandle.read.mockResolvedValue({ bytesRead: 5 }); const result = await osFile.readAt(buffer, 100); expect(mockHandle.read).toHaveBeenCalledWith(buffer, 0, 10, 100); expect(result.bytesRead).toBe(5); }); }); describe('seek', () => { it('should seek from beginning (SEEK_SET)', async () => { const position = await osFile.seek(100, 0); expect(position).toBe(100); }); it('should seek from current position (SEEK_CUR)', async () => { await osFile.seek(50, 0); // Set to 50 const position = await osFile.seek(25, 1); // Add 25 expect(position).toBe(75); }); it('should seek from end (SEEK_END)', async () => { mockHandle.stat.mockResolvedValue({ size: 1000 }); const position = await osFile.seek(-10, 2); expect(position).toBe(990); expect(mockHandle.stat).toHaveBeenCalledTimes(1); }); }); describe('write', () => { it('should write data to file', async () => { const buffer = new Uint8Array([1, 2, 3]); mockHandle.write.mockResolvedValue({ bytesWritten: 3 }); const result = await osFile.write(buffer); expect(mockHandle.write).toHaveBeenCalledWith(buffer, 0, 3, 0); expect(result.bytesWritten).toBe(3); expect(result.buffer).toBe(buffer); }); it('should update position after write', async () => { const buffer = new Uint8Array([1, 2, 3]); mockHandle.write.mockResolvedValue({ bytesWritten: 3 }); await osFile.write(buffer); await osFile.write(buffer); expect(mockHandle.write).toHaveBeenNthCalledWith(1, buffer, 0, 3, 0); expect(mockHandle.write).toHaveBeenNthCalledWith(2, buffer, 0, 3, 3); }); }); describe('writeString', () => { it('should write string to file', async () => { const testString = 'Hello World'; mockHandle.write.mockResolvedValue({ bytesWritten: 11 }); const result = await osFile.writeString(testString); expect(result.bytesWritten).toBe(11); expect(mockHandle.write).toHaveBeenCalledWith(Buffer.from(testString, 'utf8'), 0, 11, 0); }); }); describe('readdir', () => { it('should read directory entries', async () => { const mockDirents = [ { name: 'file1.txt' }, { name: 'file2.txt' }, ]; const mockStats = { size: 100, mode: 0o644, mtime: new Date() }; mockFs.readdir.mockResolvedValue(mockDirents); mockFs.stat.mockResolvedValue(mockStats); const result = await osFile.readdir(0); expect(mockFs.readdir).toHaveBeenCalledWith('/test/file.txt', { withFileTypes: true }); expect(result).toHaveLength(2); expect(result[0].name()).toBe('file1.txt'); expect(result[1].name()).toBe('file2.txt'); }); it('should limit results when count is specified', async () => { const mockDirents = [ { name: 'file1.txt' }, { name: 'file2.txt' }, { name: 'file3.txt' }, ]; const mockStats = { size: 100, mode: 0o644, mtime: new Date() }; mockFs.readdir.mockResolvedValue(mockDirents); mockFs.stat.mockResolvedValue(mockStats); const result = await osFile.readdir(2); expect(result).toHaveLength(2); }); }); describe('truncate', () => { it('should truncate file to specified size', async () => { await osFile.truncate(100); expect(mockHandle.truncate).toHaveBeenCalledWith(100); }); it('should reset position when truncated below current position', async () => { await osFile.seek(200, 0); await osFile.truncate(100); const position = await osFile.seek(0, 1); // Get current position expect(position).toBe(100); }); }); }); describe('OsFs', () => { let osFs; beforeEach(() => { osFs = new osfs_1.OsFs(); }); describe('create', () => { it('should create new file', async () => { const result = await osFs.create('/test/newfile.txt'); expect(mockFs.writeFile).toHaveBeenCalledWith('/test/newfile.txt', ''); expect(result).toBeInstanceOf(osfs_1.OsFile); expect(result.name()).toBe('/test/newfile.txt'); }); }); describe('mkdir', () => { it('should create directory', async () => { await osFs.mkdir('/test/newdir', 0o755); expect(mockFs.mkdir).toHaveBeenCalledWith('/test/newdir', { mode: 0o755 }); }); }); describe('mkdirAll', () => { it('should create directory recursively', async () => { await osFs.mkdirAll('/test/deep/dir', 0o755); expect(mockFs.mkdir).toHaveBeenCalledWith('/test/deep/dir', { mode: 0o755, recursive: true }); }); }); describe('open', () => { it('should open existing file', async () => { const mockStats = { isDirectory: () => false }; mockFs.stat.mockResolvedValue(mockStats); mockFs.access.mockResolvedValue(); const result = await osFs.open('/test/file.txt'); expect(mockFs.access).toHaveBeenCalledWith('/test/file.txt'); expect(mockFs.stat).toHaveBeenCalledWith('/test/file.txt'); expect(result).toBeInstanceOf(osfs_1.OsFile); }); it('should open directory', async () => { const mockStats = { isDirectory: () => true }; mockFs.stat.mockResolvedValue(mockStats); mockFs.access.mockResolvedValue(); const result = await osFs.open('/test/dir'); expect(result).toBeInstanceOf(osfs_1.OsFile); }); }); describe('remove', () => { it('should remove file', async () => { const mockStats = { isDirectory: () => false }; mockFs.stat.mockResolvedValue(mockStats); await osFs.remove('/test/file.txt'); expect(mockFs.unlink).toHaveBeenCalledWith('/test/file.txt'); }); it('should remove directory', async () => { const mockStats = { isDirectory: () => true }; mockFs.stat.mockResolvedValue(mockStats); await osFs.remove('/test/dir'); expect(mockFs.rmdir).toHaveBeenCalledWith('/test/dir'); }); }); describe('removeAll', () => { it('should remove directory recursively', async () => { await osFs.removeAll('/test/dir'); expect(mockFs.rm).toHaveBeenCalledWith('/test/dir', { recursive: true, force: true }); }); }); describe('rename', () => { it('should rename file', async () => { await osFs.rename('/test/old.txt', '/test/new.txt'); expect(mockFs.rename).toHaveBeenCalledWith('/test/old.txt', '/test/new.txt'); }); }); describe('stat', () => { it('should return file stats', async () => { const mockStats = { size: 100, mode: 0o644, mtime: new Date() }; mockFs.stat.mockResolvedValue(mockStats); const result = await osFs.stat('/test/file.txt'); expect(mockFs.stat).toHaveBeenCalledWith('/test/file.txt'); expect(result).toBeInstanceOf(osfs_1.OsFileInfo); expect(result.name()).toBe('file.txt'); }); }); describe('name', () => { it('should return filesystem name', () => { expect(osFs.name()).toBe('OsFs'); }); }); describe('permission methods', () => { it('should change file mode', async () => { await osFs.chmod('/test/file.txt', 0o644); expect(mockFs.chmod).toHaveBeenCalledWith('/test/file.txt', 0o644); }); it('should change file ownership', async () => { await osFs.chown('/test/file.txt', 1000, 1000); expect(mockFs.chown).toHaveBeenCalledWith('/test/file.txt', 1000, 1000); }); it('should change file times', async () => { const atime = new Date('2023-01-01'); const mtime = new Date('2023-01-02'); await osFs.chtimes('/test/file.txt', atime, mtime); expect(mockFs.utimes).toHaveBeenCalledWith('/test/file.txt', atime, mtime); }); }); }); describe('newOsFs factory function', () => { it('should create new OsFs instance', () => { const result = (0, osfs_1.newOsFs)(); expect(result).toBeInstanceOf(osfs_1.OsFs); }); }); }); //# sourceMappingURL=vo-osfs.test.js.map