Skip to content

Commit 4e4725a

Browse files
committed
test: add coverage for NAG import symbols, semicolon comments, RAVs, and onWarning forwarding in stream()
1 parent 216840e commit 4e4725a

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

src/__tests__/san.spec.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,103 @@ describe('PAWN_PUSH', () => {
338338
});
339339
});
340340

341+
// ─── NAG (nag_import) ────────────────────────────────────────────────────────
342+
343+
describe('NAG nag_import', () => {
344+
it('parses ! as annotation', () => {
345+
expect(white('e4!')).toMatchObject({
346+
annotations: ['!'],
347+
piece: 'P',
348+
to: 'e4',
349+
});
350+
});
351+
352+
it('parses ?? as annotation', () => {
353+
expect(white('e4??')).toMatchObject({
354+
annotations: ['??'],
355+
piece: 'P',
356+
to: 'e4',
357+
});
358+
});
359+
360+
it('parses ± (U+00B1) as annotation', () => {
361+
expect(white('e4\u00B1')).toMatchObject({
362+
annotations: ['\u00B1'],
363+
piece: 'P',
364+
to: 'e4',
365+
});
366+
});
367+
368+
it('parses multiple NAGs on one move', () => {
369+
expect(white('e4!$14')).toMatchObject({
370+
annotations: ['!', '14'],
371+
piece: 'P',
372+
to: 'e4',
373+
});
374+
});
375+
});
376+
377+
// ─── COMMENT ─────────────────────────────────────────────────────────────────
378+
379+
describe('COMMENT', () => {
380+
it('parses a semicolon comment_line', () => {
381+
const games = parse(
382+
'[Event "T"]\n[Result "1-0"]\n\n1. e4 ; this is a comment\n1-0',
383+
);
384+
expect(games[0]?.moves[0]?.[1]).toMatchObject({
385+
comment: 'this is a comment',
386+
piece: 'P',
387+
to: 'e4',
388+
});
389+
});
390+
391+
it('joins multiple comment blocks on one move', () => {
392+
const games = parse(
393+
'[Event "T"]\n[Result "1-0"]\n\n1. e4 { first } { second } 1-0',
394+
);
395+
expect(games[0]?.moves[0]?.[1]).toMatchObject({
396+
comment: 'first second',
397+
piece: 'P',
398+
to: 'e4',
399+
});
400+
});
401+
});
402+
403+
// ─── RAV ─────────────────────────────────────────────────────────────────────
404+
405+
describe('RAV', () => {
406+
it('parses a single variation on a move', () => {
407+
const games = parse(
408+
'[Event "T"]\n[Result "1-0"]\n\n1. e4 (1. d4 d5) e5 1-0',
409+
);
410+
const variants = games[0]?.moves[0]?.[1]?.variants;
411+
expect(variants).toHaveLength(1);
412+
expect(variants?.[0]?.[0]?.[1]).toMatchObject({ piece: 'P', to: 'd4' });
413+
});
414+
415+
it('parses a nested RAV (RAV inside a RAV)', () => {
416+
const games = parse(
417+
'[Event "T"]\n[Result "1-0"]\n\n1. e4 (1. d4 (1. c4 c5) d5) e5 1-0',
418+
);
419+
const outer = games[0]?.moves[0]?.[1]?.variants?.[0];
420+
const inner = outer?.[0]?.[1]?.variants;
421+
expect(inner).toHaveLength(1);
422+
expect(inner?.[0]?.[0]?.[1]).toMatchObject({ piece: 'P', to: 'c4' });
423+
});
424+
425+
it('parses a comment inside a RAV', () => {
426+
const games = parse(
427+
'[Event "T"]\n[Result "1-0"]\n\n1. e4 (1. d4 { good move } d5) e5 1-0',
428+
);
429+
const ravMove = games[0]?.moves[0]?.[1]?.variants?.[0]?.[0]?.[1];
430+
expect(ravMove).toMatchObject({
431+
comment: 'good move',
432+
piece: 'P',
433+
to: 'd4',
434+
});
435+
});
436+
});
437+
341438
// ─── PAWN_CAPTURE ────────────────────────────────────────────────────────────
342439

343440
describe('PAWN_CAPTURE', () => {

src/__tests__/stream.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,17 @@ describe('stream()', () => {
229229
expect(games).toHaveLength(1);
230230
expect(games[0]?.meta['Event']).toBe('B');
231231
});
232+
233+
it('forwards onWarning to parse() for each game', async () => {
234+
const warnings: string[] = [];
235+
// Missing Black tag triggers an STR warning
236+
const pgn = '[Event "T"]\n[Result "1-0"]\n\n1. e4 1-0';
237+
const games = await collect(
238+
stream(fromArray([pgn]), {
239+
onWarning: (w) => warnings.push(w.message),
240+
}),
241+
);
242+
expect(games).toHaveLength(1);
243+
expect(warnings.some((w) => w.includes('Black'))).toBe(true);
244+
});
232245
});

0 commit comments

Comments
 (0)