~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
75 lines · 2.3 KB Raw History
import { describe, expect, it } from 'vitest';
import {
  parseDictionary,
  SfToken,
  serializeBare,
  serializeDictionary,
  serializeInnerList,
} from '../src/structured-fields.js';

describe('parseDictionary', () => {
  it('parses items, inner lists and parameters', () => {
    const dict = parseDictionary(
      'a="x\\"y", b=12, c=:AQI=:, d=?1, e, f=tok/en;p=1, g=("h" "i";q);tag="t"',
    );
    expect(dict.get('a')).toMatchObject({ kind: 'item', value: 'x"y' });
    expect(dict.get('b')).toMatchObject({ kind: 'item', value: 12 });
    const c = dict.get('c');
    expect(c?.kind === 'item' && c.value).toEqual(new Uint8Array([1, 2]));
    expect(dict.get('d')).toMatchObject({ value: true });
    expect(dict.get('e')).toMatchObject({ value: true });
    const f = dict.get('f');
    expect(f?.kind === 'item' && f.value).toBeInstanceOf(SfToken);
    expect(f?.params.get('p')).toBe(1);
    const g = dict.get('g');
    if (g?.kind !== 'innerList') throw new Error('expected an inner list');
    expect(g.items.map((i) => i.value)).toEqual(['h', 'i']);
    expect(g.items[1].params.get('q')).toBe(true);
    expect(g.params.get('tag')).toBe('t');
  });

  it('parses an empty field', () => {
    expect(parseDictionary('').size).toBe(0);
  });

  it('refuses malformed input', () => {
    for (const bad of [
      'A=1',
      'a=1,',
      'a=1 b=2',
      'a="unterminated',
      'a="bad\\escape"',
      'a=:AQI',
      'a=:!!:',
      'a=?2',
      'a=("x"y)',
      'a=@',
      'a="é"',
    ]) {
      expect(() => parseDictionary(bad), bad).toThrow();
    }
  });
});

describe('serialize', () => {
  it('writes canonical members', () => {
    expect(
      serializeDictionary([
        ['type', 'atproto-space-repo'],
        ['ver', 1],
        ['mac', new Uint8Array([1, 2])],
        ['flag', true],
        ['off', false],
      ]),
    ).toBe('type="atproto-space-repo", ver=1, mac=:AQI=:, flag, off=?0');
    expect(serializeBare('a"b\\c')).toBe('"a\\"b\\\\c"');
    expect(serializeBare(new SfToken('tok'))).toBe('tok');
  });

  it('round-trips an inner list', () => {
    const input = '("authorization" "atproto-space-audience";x);tag="t";flag';
    const g = parseDictionary(`s=${input}`).get('s');
    if (g?.kind !== 'innerList') throw new Error('expected an inner list');
    expect(serializeInnerList(g.items, g.params)).toBe(input);
  });
});