import { describe, expect, it } from 'vitest' import fc from 'fast-check' import { escapeSegment, joinPath, pathKeys, splitPath, succ, toSegment, unescapeSegment, validateSeparator } from '../../src/core/path.js' import { InvalidKeyError } from '../../src/errors.js' const separators = fc.constantFrom('/', ':', '.', '|', '#', '\\', '!') describe('escapeSegment', () => { it('escapes %, the separator and a leading ~', () => { expect(escapeSegment('a/b')).toBe('a%2Fb') expect(escapeSegment('50%')).toBe('50%25') expect(escapeSegment('~x')).toBe('%7Ex') expect(escapeSegment('x~')).toBe('x~') expect(escapeSegment('a:b', ':')).toBe('a%3Ab') expect(escapeSegment('a/b', ':')).toBe('a/b') expect(escapeSegment('plain')).toBe('plain') }) it('round-trips (property)', () => { fc.assert( fc.property(fc.string({ unit: 'binary' }), separators, (s, sep) => { expect(unescapeSegment(escapeSegment(s, sep))).toBe(s) }), ) }) it('never emits a raw separator or a leading ~ (property)', () => { fc.assert( fc.property(fc.string({ unit: 'binary' }), separators, (s, sep) => { const e = escapeSegment(s, sep) expect(e.includes(sep)).toBe(false) expect(e.startsWith('~')).toBe(false) }), ) }) it('joins and splits paths (property)', () => { fc.assert( fc.property(fc.array(fc.string({ minLength: 1 }), { maxLength: 6 }), separators, (path, sep) => { expect(splitPath(joinPath(path, sep), sep)).toEqual(path) }), ) }) }) describe('pathKeys', () => { it('precomputes selfKey, prefix and subtree end', () => { expect(pathKeys(['users', '123'], '/')).toMatchObject({ selfKey: 'users/123', prefix: 'users/123/', end: 'users/1230' }) expect(pathKeys([], '/')).toMatchObject({ selfKey: '', prefix: '', end: undefined }) expect(pathKeys(['a/b'], '/').selfKey).toBe('a%2Fb') }) }) describe('misc', () => { it('succ returns the next char', () => { expect(succ('/')).toBe('0') }) it('toSegment rejects undefined, null, empty and non-finite', () => { expect(() => toSegment(undefined)).toThrow(InvalidKeyError) expect(() => toSegment(null)).toThrow(TypeError) expect(() => toSegment('')).toThrow(InvalidKeyError) expect(() => toSegment(NaN)).toThrow(InvalidKeyError) expect(toSegment(12)).toBe('12') }) it('validates separators', () => { expect(() => validateSeparator('//')).toThrow() expect(() => validateSeparator('%')).toThrow() expect(() => validateSeparator('~')).toThrow() expect(() => validateSeparator(':')).not.toThrow() }) })