chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { describe, expect, it } from 'vitest';
import {
DRIVE_FILE_COLLECTION,
DRIVE_FOLDER_COLLECTION,
driveFileLexicon,
driveFolderLexicon,
folderAncestry,
folderPath,
isValidName,
MAX_NAME_LENGTH,
normalizeFolderKey,
} from '../src/lexicon.js';
/** @param {Array<[string, string, string]>} rows - rkey, name, parent */
function treeOf(rows) {
return new Map(rows.map(([rkey, name, parent]) => [rkey, { name, parent }]));
}
describe('the lexicons', () => {
it('describe the collections they are named for', () => {
expect(driveFileLexicon.id).toBe(DRIVE_FILE_COLLECTION);
expect(driveFolderLexicon.id).toBe(DRIVE_FOLDER_COLLECTION);
expect(driveFileLexicon.defs.main.record.required).toContain('parts');
expect(driveFolderLexicon.defs.main.record.required).toContain('name');
});
it('key a file to its folder by record key, not by path', () => {
const folder = driveFileLexicon.defs.main.record.properties.folder;
expect(folder.description).toMatch(/[Rr]ecord key/);
});
});
describe('isValidName', () => {
it('accepts an ordinary name', () => {
expect(isValidName('notes.txt')).toBe(true);
expect(isValidName('a name with spaces.pdf')).toBe(true);
expect(isValidName('résumé.pdf')).toBe(true);
});
it('rejects a name that is not one path segment', () => {
expect(isValidName('a/b')).toBe(false);
expect(isValidName('a\\b')).toBe(false);
expect(isValidName('.')).toBe(false);
expect(isValidName('..')).toBe(false);
});
it('rejects an empty, over-long, or non-string name', () => {
expect(isValidName('')).toBe(false);
expect(isValidName('x'.repeat(MAX_NAME_LENGTH + 1))).toBe(false);
expect(isValidName(undefined)).toBe(false);
expect(isValidName(42)).toBe(false);
});
it('rejects a control character, which would display as a shorter name', () => {
expect(isValidName(`safe${String.fromCharCode(0)}.txt`)).toBe(false);
expect(isValidName(`safe${String.fromCharCode(0x1f)}.txt`)).toBe(false);
expect(isValidName(`safe${String.fromCharCode(0x7f)}.txt`)).toBe(false);
expect(isValidName(`safe${String.fromCharCode(0x0a)}.txt`)).toBe(false);
});
});
describe('normalizeFolderKey', () => {
it('reads the top level from every empty form', () => {
expect(normalizeFolderKey('')).toBe('');
expect(normalizeFolderKey(undefined)).toBe('');
expect(normalizeFolderKey(null)).toBe('');
});
it('keeps a record key as it is', () => {
expect(normalizeFolderKey('3lfoldertid')).toBe('3lfoldertid');
});
it('refuses anything that is not one key', () => {
expect(normalizeFolderKey('photos/2026')).toBe(null);
expect(normalizeFolderKey('..')).toBe(null);
expect(normalizeFolderKey(7)).toBe(null);
});
});
describe('folderAncestry', () => {
const tree = treeOf([
['a', 'photos', ''],
['b', '2026', 'a'],
['c', 'june', 'b'],
]);
it('gives nothing for the top level', () => {
expect(folderAncestry('', tree)).toEqual([]);
});
it('walks from the top level down to the folder', () => {
expect(folderAncestry('c', tree)).toEqual([
{ rkey: 'a', name: 'photos' },
{ rkey: 'b', name: '2026' },
{ rkey: 'c', name: 'june' },
]);
});
it('reports a chain that does not resolve', () => {
expect(folderAncestry('missing', tree)).toBe(null);
});
it('refuses to follow a loop rather than hanging', () => {
const looped = treeOf([
['x', 'one', 'y'],
['y', 'two', 'x'],
]);
expect(folderAncestry('x', looped)).toBe(null);
});
});
describe('folderPath', () => {
const tree = treeOf([
['a', 'photos', ''],
['b', '2026', 'a'],
]);
it('joins the chain for display', () => {
expect(folderPath('b', tree)).toBe('photos/2026');
expect(folderPath('', tree)).toBe('');
});
it('reports a broken chain as no path', () => {
expect(folderPath('nope', tree)).toBe(null);
});
});