@julesl23/s5js
Version:
Enhanced TypeScript SDK for S5 decentralized storage with path-based API, media processing, and directory utilities
180 lines • 7.92 kB
JavaScript
import { describe, it, expect, beforeEach } from 'vitest';
import { DirectoryWalker } from '../../../src/fs/utils/walker.js';
// Create a mock FS5 that simulates a directory structure
class MockFS5 {
structure = new Map();
constructor() {
// Initialize with test data
this.structure.set('home/test', {
files: new Map([
['file1.txt', { hash: new Uint8Array(32), size: 8 }],
['file2.txt', { hash: new Uint8Array(32), size: 8 }]
]),
dirs: new Map([
['dir1', { link: { type: 'fixed_hash_blake3', hash: new Uint8Array(32) } }],
['dir2', { link: { type: 'fixed_hash_blake3', hash: new Uint8Array(32) } }],
['empty', { link: { type: 'fixed_hash_blake3', hash: new Uint8Array(32) } }]
])
});
this.structure.set('home/test/dir1', {
files: new Map([
['file3.txt', { hash: new Uint8Array(32), size: 8 }],
['file4.txt', { hash: new Uint8Array(32), size: 8 }]
]),
dirs: new Map([
['subdir', { link: { type: 'fixed_hash_blake3', hash: new Uint8Array(32) } }]
])
});
this.structure.set('home/test/dir1/subdir', {
files: new Map([
['file5.txt', { hash: new Uint8Array(32), size: 8 }]
]),
dirs: new Map()
});
this.structure.set('home/test/dir2', {
files: new Map([
['file6.txt', { hash: new Uint8Array(32), size: 8 }]
]),
dirs: new Map()
});
this.structure.set('home/test/empty', {
files: new Map([
['.gitkeep', { hash: new Uint8Array(32), size: 0 }]
]),
dirs: new Map()
});
}
async *list(path, options) {
const dir = this.structure.get(path);
if (!dir) {
throw new Error(`Directory ${path} not found`);
}
let allEntries = [];
// Add files
for (const [name, file] of dir.files.entries()) {
allEntries.push([name, file]);
}
// Add directories
for (const [name, dirRef] of dir.dirs.entries()) {
allEntries.push([name, dirRef]);
}
// Sort for consistent ordering
allEntries.sort((a, b) => a[0].localeCompare(b[0]));
// Apply cursor if provided
let startIndex = 0;
if (options?.cursor) {
// Simple cursor implementation - just store index
startIndex = parseInt(options.cursor) + 1;
}
// Yield entries
for (let i = startIndex; i < allEntries.length; i++) {
const [name, value] = allEntries[i];
yield {
name,
value,
cursor: new TextEncoder().encode(i.toString())
};
}
}
}
describe('DirectoryWalker Simple Tests', () => {
let fs;
beforeEach(() => {
fs = new MockFS5();
});
describe('walk async iterator', () => {
it('should walk all files and directories recursively by default', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const results = [];
for await (const item of walker.walk()) {
results.push(item);
}
// Should include all files and directories
expect(results.length).toBeGreaterThanOrEqual(9); // At least 6 files + 3 directories
// Check for specific items
const paths = results.map(r => r.path);
expect(paths).toContain('home/test/file1.txt');
expect(paths).toContain('home/test/dir1/file3.txt');
expect(paths).toContain('home/test/dir1/subdir/file5.txt');
expect(paths).toContain('home/test/dir1');
expect(paths).toContain('home/test/dir1/subdir');
});
it('should respect includeFiles option', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const results = [];
for await (const item of walker.walk({ includeFiles: false })) {
results.push(item);
}
// Should only include directories
expect(results.every(r => r.type === 'directory')).toBe(true);
expect(results.length).toBeGreaterThanOrEqual(3); // dir1, dir1/subdir, dir2
});
it('should respect includeDirectories option', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const results = [];
for await (const item of walker.walk({ includeDirectories: false })) {
results.push(item);
}
// Should only include files
expect(results.every(r => r.type === 'file')).toBe(true);
expect(results.length).toBe(7); // All files including .gitkeep
});
it('should respect maxDepth option', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const results = [];
for await (const item of walker.walk({ maxDepth: 2 })) {
results.push(item);
}
// Should not include deeply nested items (depth 2+)
const paths = results.map(r => r.path);
expect(paths).not.toContain('home/test/dir1/subdir/file5.txt');
// Should include depth 0 and 1 items
expect(paths).toContain('home/test/file1.txt');
expect(paths).toContain('home/test/dir1');
expect(paths).toContain('home/test/dir1/file3.txt');
expect(paths).toContain('home/test/dir1/subdir'); // depth 1
});
it('should handle non-recursive walking', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const results = [];
for await (const item of walker.walk({ recursive: false })) {
results.push(item);
}
// Should only include direct children
const paths = results.map(r => r.path);
expect(paths).toContain('home/test/file1.txt');
expect(paths).toContain('home/test/file2.txt');
expect(paths).toContain('home/test/dir1');
expect(paths).toContain('home/test/dir2');
// Should not include nested items
expect(paths).not.toContain('home/test/dir1/file3.txt');
expect(paths).not.toContain('home/test/dir1/subdir');
});
});
describe('count method', () => {
it('should count all files and directories with total size', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const stats = await walker.count();
expect(stats.files).toBe(7);
expect(stats.directories).toBeGreaterThanOrEqual(3);
expect(stats.totalSize).toBe(48); // 6 files * 8 bytes + 1 empty file
});
it('should count with filter applied', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const filter = (name, type) => {
return type === 'directory' || name.endsWith('.txt');
};
const stats = await walker.count({ filter });
expect(stats.files).toBe(6); // Should not count .gitkeep
expect(stats.directories).toBeGreaterThanOrEqual(3);
});
it('should count non-recursively', async () => {
const walker = new DirectoryWalker(fs, 'home/test');
const stats = await walker.count({ recursive: false });
expect(stats.files).toBe(2); // file1.txt, file2.txt
expect(stats.directories).toBe(3); // dir1, dir2, empty
expect(stats.totalSize).toBe(16); // 2 files * 8 bytes
});
});
});
//# sourceMappingURL=walker-simple.test.js.map