AT Mot — a bilingual (EN/FR) daily word game native to the AT Protocol.
1import { describe, it, expect } from 'vitest';
2import { encodeAnswers, decodeAnswers } from '../src/engine/obfuscate.js';
3
4describe('answer-list obfuscation', () => {
5 const sample = ['DRAMA', 'SMITH', 'LACEY', 'KOALA', 'FLEAU'];
6
7 it('round-trips a list of words back to byte-identical strings', () => {
8 expect(decodeAnswers(encodeAnswers(sample))).toEqual(sample);
9 });
10
11 it('is deterministic — same input always encodes to the same blob', () => {
12 expect(encodeAnswers(sample)).toBe(encodeAnswers(sample));
13 });
14
15 it('round-trips an empty list back to an empty list (not [""])', () => {
16 expect(decodeAnswers(encodeAnswers([]))).toEqual([]);
17 });
18
19 it('produces an ASCII base64 string (safe to embed in JSON / a JS bundle)', () => {
20 const blob = encodeAnswers(sample);
21 expect(typeof blob).toBe('string');
22 expect(/^[A-Za-z0-9+/]+=*$/.test(blob)).toBe(true);
23 });
24
25 it('does not leak the plaintext words (not greppable)', () => {
26 const blob = encodeAnswers(sample);
27 for (const word of sample) {
28 expect(blob).not.toContain(word);
29 }
30 });
31
32 it('round-trips a large realistic list', () => {
33 const words = Array.from({ length: 2500 }, (_, i) =>
34 // deterministic pseudo-words, all 5 uppercase A–Z letters
35 String.fromCharCode(
36 65 + (i % 26),
37 65 + ((i * 7) % 26),
38 65 + ((i * 13) % 26),
39 65 + ((i * 17) % 26),
40 65 + ((i * 23) % 26),
41 ),
42 );
43 expect(decodeAnswers(encodeAnswers(words))).toEqual(words);
44 });
45});