/* * Copyright (C) 2026 Fluxer Contributors * * This file is part of Fluxer. * * Fluxer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Fluxer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Fluxer. If not, see . */ import {describe, expect, test} from 'vitest'; import {Parser} from '../parser/parser'; import {EmojiKind, NodeType, ParserFlags, TimestampStyle} from '../types/enums'; describe('Fluxer Markdown Parser', () => { test('timestamp default', () => { const input = 'Current time: '; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ {type: NodeType.Text, content: 'Current time: '}, { type: NodeType.Timestamp, timestamp: 1618953630, style: TimestampStyle.ShortDateTime, }, ]); }); test('timestamp with style', () => { const input = ' is the date.'; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.Timestamp, timestamp: 1618953630, style: TimestampStyle.ShortDate, }, {type: NodeType.Text, content: ' is the date.'}, ]); }); test('timestamp with short date & short time style', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.Timestamp, timestamp: 1618953630, style: TimestampStyle.ShortDateShortTime, }, ]); }); test('timestamp with short date & medium time style', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.Timestamp, timestamp: 1618953630, style: TimestampStyle.ShortDateMediumTime, }, ]); }); test('timestamp invalid style', () => { const input = 'Check this time.'; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: 'Check this time.'}]); }); test('timestamp non numeric', () => { const input = 'Check time.'; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: 'Check time.'}]); }); test('timestamp with milliseconds should not parse', () => { const input = 'Time: '; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: 'Time: '}]); }); test('timestamp with partial milliseconds should not parse', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: ''}]); }); test('timestamp with excess millisecond precision should not parse', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: ''}]); }); test('timestamp with milliseconds and style should not parse', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: ''}]); }); test('timestamp in mixed content', () => { const input = 'Hello 🦶 <:smile:9876>'; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ {type: NodeType.Text, content: 'Hello '}, { type: NodeType.Emoji, kind: { kind: EmojiKind.Custom, name: 'wave', id: '12345', animated: true, }, }, {type: NodeType.Text, content: ' '}, { type: NodeType.Emoji, kind: { kind: EmojiKind.Standard, raw: '🦶', codepoints: '1f9b6', name: expect.any(String), }, }, {type: NodeType.Text, content: ' '}, { type: NodeType.Timestamp, timestamp: 1618953630, style: TimestampStyle.ShortDate, }, {type: NodeType.Text, content: ' '}, { type: NodeType.Emoji, kind: { kind: EmojiKind.Custom, name: 'smile', id: '9876', animated: false, }, }, ]); }); test('timestamp edge cases', () => { const inputs = ['', '', '', '', '']; for (const input of inputs) { const parser = new Parser(input, 0); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: input}]); } }); test('very large valid timestamp', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.Timestamp, timestamp: 9999999999, style: TimestampStyle.ShortDateTime, }, ]); }); test('timestamp with leading zeros', () => { const input = ''; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.Timestamp, timestamp: 1618953630, style: TimestampStyle.ShortDateTime, }, ]); }); test('timestamp in code block should not be parsed', () => { const input = '```\n\n```'; const flags = ParserFlags.ALLOW_CODE_BLOCKS; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.CodeBlock, language: undefined, content: '\n', }, ]); }); test('timestamp in inline code should not be parsed', () => { const input = '``'; const flags = 0; const parser = new Parser(input, flags); const {nodes: ast} = parser.parse(); expect(ast).toEqual([ { type: NodeType.InlineCode, content: '', }, ]); }); test('timestamp with non-digit characters should not parse', () => { const inputs = [ '', '', '', '', '', '', '', '', '', '', '', '', ]; for (const input of inputs) { const parser = new Parser(input, 0); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: input}]); } }); test('timestamp with valid integer formats', () => { const inputs = ['', '', '']; for (const input of inputs) { const parser = new Parser(input, 0); const {nodes: ast} = parser.parse(); expect(ast[0].type).toBe(NodeType.Timestamp); } }); test('timestamp with zero value should not parse', () => { const parser = new Parser('', 0); const {nodes: ast} = parser.parse(); expect(ast).toEqual([{type: NodeType.Text, content: ''}]); }); });