Filesystem MCP Server
by bsmi021
import { promises as fs } from 'fs';
import path from 'path';
import * as directory from '../../operations/directory.js';
import {
TEST_DIR,
createTestFile,
createTestDir,
testFileExists
} from '../setup.js';
describe('Directory Operations', () => {
describe('listDirectoryContents', () => {
it('should list directory contents non-recursively', async () => {
await createTestFile('file1.txt');
await createTestFile('file2.txt');
await createTestDir('subdir');
const contents = await directory.listDirectoryContents(TEST_DIR, false);
expect(contents).toHaveLength(3);
expect(contents.map(c => c.name).sort()).toEqual(['file1.txt', 'file2.txt', 'subdir'].sort());
expect(contents.find(c => c.name === 'subdir')?.isDirectory).toBe(true);
});
it('should list directory contents recursively', async () => {
await createTestFile('file1.txt');
await createTestDir('subdir');
await createTestFile(path.join('subdir', 'file2.txt'));
const contents = await directory.listDirectoryContents(TEST_DIR, true);
expect(contents).toHaveLength(2);
const subdir = contents.find(c => c.name === 'subdir');
expect(subdir?.isDirectory).toBe(true);
expect(subdir?.contents).toHaveLength(1);
expect(subdir?.contents?.[0].name).toBe('file2.txt');
});
});
describe('makeDirectory', () => {
it('should create directory', async () => {
const dirPath = path.join(TEST_DIR, 'newdir');
await directory.makeDirectory(dirPath);
const stats = await fs.stat(dirPath);
expect(stats.isDirectory()).toBe(true);
});
it('should create nested directories when recursive is true', async () => {
const dirPath = path.join(TEST_DIR, 'nested', 'deep', 'dir');
await directory.makeDirectory(dirPath, true);
const stats = await fs.stat(dirPath);
expect(stats.isDirectory()).toBe(true);
});
it('should throw error for nested directories when recursive is false', async () => {
const dirPath = path.join(TEST_DIR, 'nested', 'deep', 'dir');
await expect(directory.makeDirectory(dirPath, false))
.rejects
.toThrow();
});
});
describe('removeDirectory', () => {
it('should remove empty directory', async () => {
const dirPath = await createTestDir('emptydir');
await directory.removeDirectory(dirPath);
const exists = await testFileExists('emptydir');
expect(exists).toBe(false);
});
it('should throw error for non-empty directory when recursive is false', async () => {
const dirPath = await createTestDir('nonempty');
await createTestFile(path.join('nonempty', 'file.txt'));
await expect(directory.removeDirectory(dirPath, false))
.rejects
.toThrow();
});
it('should remove directory and contents when recursive is true', async () => {
const dirPath = await createTestDir('nonempty');
await createTestFile(path.join('nonempty', 'file.txt'));
await directory.removeDirectory(dirPath, true);
const exists = await testFileExists('nonempty');
expect(exists).toBe(false);
});
});
describe('copyDirectory', () => {
it('should copy directory and contents', async () => {
const sourceDir = await createTestDir('source');
await createTestFile(path.join('source', 'file1.txt'), 'content1');
await createTestDir(path.join('source', 'subdir'));
await createTestFile(path.join('source', 'subdir', 'file2.txt'), 'content2');
const destPath = path.join(TEST_DIR, 'dest');
await directory.copyDirectory(sourceDir, destPath);
// Check directory structure
const destStats = await fs.stat(destPath);
expect(destStats.isDirectory()).toBe(true);
const file1Path = path.join(destPath, 'file1.txt');
const file1Content = await fs.readFile(file1Path, 'utf8');
expect(file1Content).toBe('content1');
const subdirPath = path.join(destPath, 'subdir');
const subdirStats = await fs.stat(subdirPath);
expect(subdirStats.isDirectory()).toBe(true);
const file2Path = path.join(subdirPath, 'file2.txt');
const file2Content = await fs.readFile(file2Path, 'utf8');
expect(file2Content).toBe('content2');
});
it('should throw error when source is not a directory', async () => {
const sourcePath = await createTestFile('source.txt');
const destPath = path.join(TEST_DIR, 'dest');
await expect(directory.copyDirectory(sourcePath, destPath))
.rejects
.toThrow('Source is not a directory');
});
it('should throw error when destination exists and overwrite is false', async () => {
const sourceDir = await createTestDir('source');
const destDir = await createTestDir('dest');
await expect(directory.copyDirectory(sourceDir, destDir, false))
.rejects
.toThrow('Destination directory already exists');
});
it('should overwrite destination when overwrite is true', async () => {
const sourceDir = await createTestDir('source');
await createTestFile(path.join('source', 'file.txt'), 'new content');
const destDir = await createTestDir('dest');
await createTestFile(path.join('dest', 'old.txt'), 'old content');
await directory.copyDirectory(sourceDir, destDir, true);
const oldExists = await testFileExists(path.join('dest', 'old.txt'));
expect(oldExists).toBe(false);
const newContent = await fs.readFile(path.join(destDir, 'file.txt'), 'utf8');
expect(newContent).toBe('new content');
});
});
});