import { test, describe, beforeEach, afterEach } from 'node:test';
import { strict as assert } from 'node:assert';
import fs from 'fs-extra';
import path from 'path';
import { fileURLToPath } from 'url';
import { v4 as uuidv4 } from 'uuid';
// Create a simple MatrixFileSystem implementation for testing
class MatrixFileSystem {
constructor(basePath = process.cwd()) {
this.basePath = basePath;
this.matrixRoot = path.join(basePath, '.matrix_pattern');
this.matrixDir = path.join(this.matrixRoot, 'matrix');
this.metadataDir = path.join(this.matrixRoot, 'metadata');
this.horizontalsDir = path.join(this.metadataDir, 'horizontals');
this.syncReportsDir = path.join(this.metadataDir, 'sync-reports');
this.verticalsFile = path.join(this.metadataDir, 'verticals.json');
}
async initialize() {
try {
await fs.mkdir(this.matrixRoot, { recursive: true });
await fs.mkdir(this.matrixDir, { recursive: true });
await fs.mkdir(this.metadataDir, { recursive: true });
await fs.mkdir(this.horizontalsDir, { recursive: true });
await fs.mkdir(this.syncReportsDir, { recursive: true });
try {
await fs.access(this.verticalsFile);
} catch (error) {
if (error.code === 'ENOENT') {
await fs.writeFile(this.verticalsFile, JSON.stringify([], null, 2));
}
}
} catch (error) {
throw new Error(`Failed to initialize matrix structure: ${error.message}`);
}
}
async createCell(vertical, horizontal, content) {
// Check if cell already exists (forward-only constraint)
if (await this.cellExists(vertical, horizontal)) {
throw new Error(`Cell ${vertical}:${horizontal} already exists. Matrix Pattern System enforces forward-only constraint.`);
}
const verticalDir = path.join(this.matrixDir, vertical);
const cellFile = path.join(verticalDir, `${horizontal}.md`);
try {
await fs.mkdir(verticalDir, { recursive: true });
await fs.writeFile(cellFile, content, 'utf8');
await this.registerVertical(vertical);
} catch (error) {
throw new Error(`Failed to create cell [${vertical}, ${horizontal}]: ${error.message}`);
}
}
async createEmptyCell(vertical, horizontal, reason = '') {
const verticalDir = path.join(this.matrixDir, vertical);
const emptyFile = path.join(verticalDir, `${horizontal}.empty`);
try {
await fs.mkdir(verticalDir, { recursive: true });
await fs.writeFile(emptyFile, reason, 'utf8');
await this.registerVertical(vertical);
} catch (error) {
throw new Error(`Failed to create empty cell [${vertical}, ${horizontal}]: ${error.message}`);
}
}
async readCell(vertical, horizontal) {
const verticalDir = path.join(this.matrixDir, vertical);
const cellFile = path.join(verticalDir, `${horizontal}.md`);
const emptyFile = path.join(verticalDir, `${horizontal}.empty`);
try {
try {
const content = await fs.readFile(cellFile, 'utf8');
return { content, isEmpty: false, reason: null };
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
try {
const reason = await fs.readFile(emptyFile, 'utf8');
return { content: null, isEmpty: true, reason };
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
return { content: null, isEmpty: false, reason: null };
} catch (error) {
throw new Error(`Failed to read cell [${vertical}, ${horizontal}]: ${error.message}`);
}
}
async cellExists(vertical, horizontal) {
const verticalDir = path.join(this.matrixDir, vertical);
const cellFile = path.join(verticalDir, `${horizontal}.md`);
const emptyFile = path.join(verticalDir, `${horizontal}.empty`);
try {
await fs.access(cellFile);
return true;
} catch (error) {
if (error.code !== 'ENOENT') {
throw new Error(`Failed to check cell existence: ${error.message}`);
}
}
try {
await fs.access(emptyFile);
return true;
} catch (error) {
if (error.code !== 'ENOENT') {
throw new Error(`Failed to check empty cell existence: ${error.message}`);
}
}
return false;
}
async listVerticals() {
try {
const content = await fs.readFile(this.verticalsFile, 'utf8');
return JSON.parse(content);
} catch (error) {
if (error.code === 'ENOENT') return [];
throw new Error(`Failed to read verticals list: ${error.message}`);
}
}
async listHorizontals() {
try {
const verticals = await this.listVerticals();
const horizontalsSet = new Set();
for (const vertical of verticals) {
const verticalDir = path.join(this.matrixDir, vertical);
try {
const files = await fs.readdir(verticalDir);
for (const file of files) {
if (file.endsWith('.md')) {
horizontalsSet.add(file.slice(0, -3));
} else if (file.endsWith('.empty')) {
horizontalsSet.add(file.slice(0, -6));
}
}
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
}
return Array.from(horizontalsSet).sort();
} catch (error) {
throw new Error(`Failed to list horizontals: ${error.message}`);
}
}
async registerVertical(vertical) {
try {
let verticals = [];
// Try to read existing verticals, create empty array if file doesn't exist or empty
try {
const content = await fs.readFile(this.verticalsFile, 'utf8');
const trimmedContent = content.trim();
if (trimmedContent) {
try {
verticals = JSON.parse(trimmedContent);
if (!Array.isArray(verticals)) {
verticals = [];
}
} catch (parseError) {
// Invalid JSON, start with empty array
verticals = [];
}
}
} catch (error) {
if (error.code === 'ENOENT') {
// File doesn't exist, start with empty array
verticals = [];
} else {
throw error;
}
}
if (!verticals.includes(vertical)) {
verticals.push(vertical);
verticals.sort();
await fs.writeFile(this.verticalsFile, JSON.stringify(verticals, null, 2));
}
} catch (error) {
throw new Error(`Failed to register vertical '${vertical}': ${error.message}`);
}
}
async readHorizontalInstructions(horizontal) {
const instructionsFile = path.join(this.horizontalsDir, horizontal, 'instructions.md');
try {
return await fs.readFile(instructionsFile, 'utf8');
} catch (error) {
if (error.code === 'ENOENT') return null;
throw new Error(`Failed to read horizontal instructions for '${horizontal}': ${error.message}`);
}
}
async writeHorizontalInstructions(horizontal, content) {
const horizontalDir = path.join(this.horizontalsDir, horizontal);
const instructionsFile = path.join(horizontalDir, 'instructions.md');
try {
await fs.mkdir(horizontalDir, { recursive: true });
await fs.writeFile(instructionsFile, content, 'utf8');
} catch (error) {
throw new Error(`Failed to write horizontal instructions for '${horizontal}': ${error.message}`);
}
}
async getCellsForHorizontal(horizontal) {
try {
const verticals = await this.listVerticals();
const cells = [];
for (const vertical of verticals) {
const cellData = await this.readCell(vertical, horizontal);
if (cellData.content !== null || cellData.isEmpty) {
cells.push({
vertical,
horizontal,
content: cellData.content,
isEmpty: cellData.isEmpty,
reason: cellData.reason
});
}
}
return cells;
} catch (error) {
throw new Error(`Failed to get cells for horizontal '${horizontal}': ${error.message}`);
}
}
async getCellsForVertical(vertical) {
try {
const verticalDir = path.join(this.matrixDir, vertical);
const cells = [];
try {
const files = await fs.readdir(verticalDir);
for (const file of files) {
let horizontal;
if (file.endsWith('.md')) {
horizontal = file.slice(0, -3);
} else if (file.endsWith('.empty')) {
horizontal = file.slice(0, -6);
} else {
continue;
}
const cellData = await this.readCell(vertical, horizontal);
cells.push({
vertical,
horizontal,
content: cellData.content,
isEmpty: cellData.isEmpty,
reason: cellData.reason
});
}
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
return cells.sort((a, b) => a.horizontal.localeCompare(b.horizontal));
} catch (error) {
throw new Error(`Failed to get cells for vertical '${vertical}': ${error.message}`);
}
}
async deleteCell(vertical, horizontal) {
const verticalDir = path.join(this.matrixDir, vertical);
const cellFile = path.join(verticalDir, `${horizontal}.md`);
const emptyFile = path.join(verticalDir, `${horizontal}.empty`);
try {
try {
await fs.unlink(cellFile);
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
try {
await fs.unlink(emptyFile);
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
} catch (error) {
throw new Error(`Failed to delete cell [${vertical}, ${horizontal}]: ${error.message}`);
}
}
async getMatrixStats() {
try {
const verticals = await this.listVerticals();
const horizontals = await this.listHorizontals();
let totalCells = 0;
let filledCells = 0;
let emptyCells = 0;
for (const vertical of verticals) {
for (const horizontal of horizontals) {
if (await this.cellExists(vertical, horizontal)) {
totalCells++;
const cellData = await this.readCell(vertical, horizontal);
if (cellData.isEmpty) {
emptyCells++;
} else {
filledCells++;
}
}
}
}
return {
totalVerticals: verticals.length,
totalHorizontals: horizontals.length,
totalPossibleCells: verticals.length * horizontals.length,
totalExistingCells: totalCells,
filledCells,
emptyCells,
completionRate: verticals.length * horizontals.length > 0 ?
(totalCells / (verticals.length * horizontals.length) * 100).toFixed(2) + '%' : '0%'
};
} catch (error) {
throw new Error(`Failed to get matrix statistics: ${error.message}`);
}
}
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
describe('Matrix MCP Server Tests', () => {
let testDir;
let matrixFs;
let originalCwd;
beforeEach(async () => {
// Create temporary test directory
testDir = path.join(__dirname, '../../test-temp', uuidv4());
await fs.ensureDir(testDir);
// Save original working directory and change to test directory
originalCwd = process.cwd();
process.chdir(testDir);
// Initialize matrix file system
matrixFs = new MatrixFileSystem(testDir);
await matrixFs.initialize();
});
afterEach(async () => {
// Restore original working directory
process.chdir(originalCwd);
// Clean up test directory
try {
await fs.remove(testDir);
} catch (error) {
// Ignore cleanup errors
}
});
describe('MatrixFileSystem Operations', () => {
test('should initialize directory structure correctly', async () => {
const expectedDirs = [
'.matrix_pattern',
'.matrix_pattern/matrix',
'.matrix_pattern/metadata',
'.matrix_pattern/metadata/horizontals',
'.matrix_pattern/metadata/sync-reports'
];
for (const dir of expectedDirs) {
const dirPath = path.join(testDir, dir);
const exists = await fs.pathExists(dirPath);
assert.ok(exists, `Directory ${dir} should exist`);
}
// Check that verticals.json is initialized
const verticalsFile = path.join(testDir, '.matrix_pattern/metadata/verticals.json');
const exists = await fs.pathExists(verticalsFile);
assert.ok(exists, 'verticals.json should be created');
const content = await fs.readFile(verticalsFile, 'utf8');
const verticals = JSON.parse(content);
assert.ok(Array.isArray(verticals), 'verticals.json should contain an array');
assert.strictEqual(verticals.length, 0, 'Initial verticals array should be empty');
});
test('should create and read markdown cells', async () => {
const vertical = 'test-vertical';
const horizontal = 'test-horizontal';
const content = '# Test Cell\n\nThis is test content.';
// Create cell
await matrixFs.createCell(vertical, horizontal, content);
// Verify cell file exists
const cellPath = path.join(testDir, '.matrix_pattern/matrix', vertical, `${horizontal}.md`);
const exists = await fs.pathExists(cellPath);
assert.ok(exists, 'Cell file should be created');
// Read cell content
const cellData = await matrixFs.readCell(vertical, horizontal);
assert.strictEqual(cellData.content, content, 'Cell content should match');
assert.strictEqual(cellData.isEmpty, false, 'Cell should not be empty');
assert.strictEqual(cellData.reason, null, 'Cell should not have empty reason');
});
test('should create and read empty cells', async () => {
const vertical = 'test-vertical';
const horizontal = 'empty-horizontal';
const reason = 'Not applicable for this vertical';
// Create empty cell
await matrixFs.createEmptyCell(vertical, horizontal, reason);
// Verify empty cell file exists
const emptyPath = path.join(testDir, '.matrix_pattern/matrix', vertical, `${horizontal}.empty`);
const exists = await fs.pathExists(emptyPath);
assert.ok(exists, 'Empty cell file should be created');
// Read empty cell
const cellData = await matrixFs.readCell(vertical, horizontal);
assert.strictEqual(cellData.content, null, 'Empty cell content should be null');
assert.strictEqual(cellData.isEmpty, true, 'Cell should be marked as empty');
assert.strictEqual(cellData.reason, reason, 'Empty reason should match');
});
test('should detect cell existence correctly', async () => {
const vertical = 'existence-test';
const horizontal1 = 'markdown-cell';
const horizontal2 = 'empty-cell';
const horizontal3 = 'nonexistent-cell';
// Create markdown cell
await matrixFs.createCell(vertical, horizontal1, 'Content');
// Create empty cell
await matrixFs.createEmptyCell(vertical, horizontal2, 'Empty');
// Test existence
const exists1 = await matrixFs.cellExists(vertical, horizontal1);
const exists2 = await matrixFs.cellExists(vertical, horizontal2);
const exists3 = await matrixFs.cellExists(vertical, horizontal3);
assert.ok(exists1, 'Markdown cell should exist');
assert.ok(exists2, 'Empty cell should exist');
assert.ok(!exists3, 'Nonexistent cell should not exist');
});
test('should register and list verticals', async () => {
const verticals = ['vertical1', 'vertical2', 'vertical3'];
// Create cells to trigger vertical registration
for (const vertical of verticals) {
await matrixFs.createCell(vertical, 'test', 'content');
}
// List verticals
const listedVerticals = await matrixFs.listVerticals();
assert.strictEqual(listedVerticals.length, verticals.length, 'Should list all verticals');
verticals.forEach(v => {
assert.ok(listedVerticals.includes(v), `Should include vertical ${v}`);
});
});
test('should list horizontals correctly', async () => {
const verticals = ['v1', 'v2'];
const horizontals = ['h1', 'h2', 'h3'];
// Create matrix of cells
for (const vertical of verticals) {
for (const horizontal of horizontals) {
await matrixFs.createCell(vertical, horizontal, `Content for ${vertical}:${horizontal}`);
}
}
const listedHorizontals = await matrixFs.listHorizontals();
assert.strictEqual(listedHorizontals.length, horizontals.length, 'Should list all horizontals');
horizontals.forEach(h => {
assert.ok(listedHorizontals.includes(h), `Should include horizontal ${h}`);
});
});
test('should handle horizontal instructions', async () => {
const horizontal = 'test-horizontal';
const instructions = '# Instructions\n\nThese are test instructions for horizontal synchronization.';
// Write instructions
await matrixFs.writeHorizontalInstructions(horizontal, instructions);
// Verify file exists
const instructionsPath = path.join(testDir, '.matrix_pattern/metadata/horizontals', horizontal, 'instructions.md');
const exists = await fs.pathExists(instructionsPath);
assert.ok(exists, 'Instructions file should be created');
// Read instructions
const readInstructions = await matrixFs.readHorizontalInstructions(horizontal);
assert.strictEqual(readInstructions, instructions, 'Instructions content should match');
});
test('should get cells for horizontal', async () => {
const horizontal = 'shared-horizontal';
const verticals = ['v1', 'v2', 'v3'];
// Create cells for horizontal
await matrixFs.createCell(verticals[0], horizontal, 'Content 1');
await matrixFs.createCell(verticals[1], horizontal, 'Content 2');
await matrixFs.createEmptyCell(verticals[2], horizontal, 'Empty reason');
const cells = await matrixFs.getCellsForHorizontal(horizontal);
assert.strictEqual(cells.length, 3, 'Should return all cells for horizontal');
const cell1 = cells.find(c => c.vertical === verticals[0]);
const cell2 = cells.find(c => c.vertical === verticals[1]);
const cell3 = cells.find(c => c.vertical === verticals[2]);
assert.ok(cell1 && !cell1.isEmpty, 'First cell should exist and not be empty');
assert.ok(cell2 && !cell2.isEmpty, 'Second cell should exist and not be empty');
assert.ok(cell3 && cell3.isEmpty, 'Third cell should exist and be empty');
});
test('should get cells for vertical', async () => {
const vertical = 'test-vertical';
const horizontals = ['h1', 'h2', 'h3'];
// Create cells for vertical
await matrixFs.createCell(vertical, horizontals[0], 'Content 1');
await matrixFs.createCell(vertical, horizontals[1], 'Content 2');
await matrixFs.createEmptyCell(vertical, horizontals[2], 'Empty reason');
const cells = await matrixFs.getCellsForVertical(vertical);
assert.strictEqual(cells.length, 3, 'Should return all cells for vertical');
// Verify cells are sorted by horizontal
const sortedHorizontals = cells.map(c => c.horizontal).sort();
const expectedSorted = horizontals.sort();
assert.deepStrictEqual(cells.map(c => c.horizontal), expectedSorted, 'Cells should be sorted by horizontal');
});
test('should delete cells correctly', async () => {
const vertical = 'deletion-test';
const horizontal = 'test-cell';
// Create and verify cell exists
await matrixFs.createCell(vertical, horizontal, 'Content to delete');
assert.ok(await matrixFs.cellExists(vertical, horizontal), 'Cell should exist before deletion');
// Delete cell
await matrixFs.deleteCell(vertical, horizontal);
// Verify cell is deleted
assert.ok(!await matrixFs.cellExists(vertical, horizontal), 'Cell should not exist after deletion');
});
test('should generate matrix statistics', async () => {
const verticals = ['v1', 'v2'];
const horizontals = ['h1', 'h2', 'h3'];
// Create some cells to establish all horizontals
await matrixFs.createCell(verticals[0], horizontals[0], 'Content');
await matrixFs.createCell(verticals[0], horizontals[1], 'Content');
await matrixFs.createCell(verticals[0], horizontals[2], 'Content'); // Add h3
await matrixFs.createEmptyCell(verticals[1], horizontals[0], 'Empty');
const stats = await matrixFs.getMatrixStats();
assert.strictEqual(stats.totalVerticals, 2, 'Should count verticals correctly');
assert.strictEqual(stats.totalHorizontals, 3, 'Should count horizontals correctly');
assert.strictEqual(stats.totalPossibleCells, 6, 'Should calculate total possible cells');
assert.strictEqual(stats.totalExistingCells, 4, 'Should count existing cells'); // Now 4 cells
assert.strictEqual(stats.filledCells, 3, 'Should count filled cells'); // Now 3 filled
assert.strictEqual(stats.emptyCells, 1, 'Should count empty cells');
assert.ok(stats.completionRate.includes('%'), 'Should include percentage in completion rate');
});
});
describe('Forward-Only Constraint', () => {
test('should enforce forward-only constraint for cell creation', async () => {
const vertical = 'constraint-test';
const horizontal = 'duplicate-test';
const content = 'Original content';
// Create initial cell
await matrixFs.createCell(vertical, horizontal, content);
// Attempt to create duplicate should fail
await assert.rejects(
async () => {
await matrixFs.createCell(vertical, horizontal, 'Duplicate content');
},
/already exists/,
'Should throw error when trying to create duplicate cell'
);
});
test('should maintain cell integrity after failed duplicate creation', async () => {
const vertical = 'integrity-test';
const horizontal = 'test-cell';
const originalContent = 'Original content';
// Create initial cell
await matrixFs.createCell(vertical, horizontal, originalContent);
// Attempt duplicate creation
try {
await matrixFs.createCell(vertical, horizontal, 'Modified content');
} catch (error) {
// Expected to fail
}
// Verify original content is preserved
const cellData = await matrixFs.readCell(vertical, horizontal);
assert.strictEqual(cellData.content, originalContent, 'Original content should be preserved');
});
});
describe('Error Handling', () => {
test('should handle reading nonexistent cells gracefully', async () => {
const cellData = await matrixFs.readCell('nonexistent-vertical', 'nonexistent-horizontal');
assert.strictEqual(cellData.content, null, 'Nonexistent cell content should be null');
assert.strictEqual(cellData.isEmpty, false, 'Nonexistent cell should not be marked as empty');
assert.strictEqual(cellData.reason, null, 'Nonexistent cell should not have empty reason');
});
test('should handle reading nonexistent horizontal instructions', async () => {
const instructions = await matrixFs.readHorizontalInstructions('nonexistent-horizontal');
assert.strictEqual(instructions, null, 'Nonexistent instructions should return null');
});
test('should handle empty vertical directories gracefully', async () => {
const cells = await matrixFs.getCellsForVertical('nonexistent-vertical');
assert.ok(Array.isArray(cells), 'Should return array for nonexistent vertical');
assert.strictEqual(cells.length, 0, 'Should return empty array for nonexistent vertical');
});
test('should handle file system errors during initialization', async () => {
// Create a MatrixFileSystem pointing to invalid path
const invalidFs = new MatrixFileSystem('/invalid/path/that/should/not/exist');
// Should not throw during construction
assert.ok(invalidFs, 'MatrixFileSystem should be created even with invalid path');
// Should handle initialization errors gracefully (depending on implementation)
// Note: This test depends on the specific error handling in the MatrixFileSystem
});
});
describe('File System Consistency', () => {
test('should maintain directory structure consistency', async () => {
const vertical = 'consistency-test';
const horizontal = 'test-cell';
// Create cell
await matrixFs.createCell(vertical, horizontal, 'Test content');
// Verify directory structure
const verticalDir = path.join(testDir, '.matrix_pattern/matrix', vertical);
const exists = await fs.pathExists(verticalDir);
assert.ok(exists, 'Vertical directory should be created');
const dirStats = await fs.stat(verticalDir);
assert.ok(dirStats.isDirectory(), 'Vertical path should be a directory');
});
test('should handle concurrent operations safely', async () => {
const vertical = 'concurrent-test';
const horizontals = ['h1', 'h2', 'h3', 'h4', 'h5'];
// Create multiple cells concurrently
const promises = horizontals.map(h =>
matrixFs.createCell(vertical, h, `Content for ${h}`)
);
await Promise.all(promises);
// Verify all cells were created
for (const horizontal of horizontals) {
const exists = await matrixFs.cellExists(vertical, horizontal);
assert.ok(exists, `Cell ${vertical}:${horizontal} should exist`);
}
// Verify verticals list is updated correctly
const verticals = await matrixFs.listVerticals();
assert.ok(verticals.includes(vertical), 'Vertical should be registered');
});
});
});