require('spec.helpers') local config = require('pending.config') describe('parse', function() before_each(function() vim.g.pending = nil config.reset() end) after_each(function() vim.g.pending = nil config.reset() end) local parse = require('pending.parse') describe('body', function() it('returns plain description when no metadata', function() local desc, meta = parse.body('Buy groceries') assert.are.equal('Buy groceries', desc) assert.are.same({}, meta) end) it('extracts due date', function() local desc, meta = parse.body('Buy groceries due:2026-03-15') assert.are.equal('Buy groceries', desc) assert.are.equal('2026-03-15', meta.due) end) it('extracts category', function() local desc, meta = parse.body('Buy groceries cat:Errands') assert.are.equal('Buy groceries', desc) assert.are.equal('Errands', meta.cat) end) it('extracts both due and cat', function() local desc, meta = parse.body('Buy milk due:2026-03-15 cat:Errands') assert.are.equal('Buy milk', desc) assert.are.equal('2026-03-15', meta.due) assert.are.equal('Errands', meta.cat) end) it('extracts metadata in any order', function() local desc, meta = parse.body('Buy milk cat:Errands due:2026-03-15') assert.are.equal('Buy milk', desc) assert.are.equal('2026-03-15', meta.due) assert.are.equal('Errands', meta.cat) end) it('stops at duplicate key', function() local desc, meta = parse.body('Buy milk due:2026-03-15 due:2026-04-01') assert.are.equal('Buy milk due:2026-03-15', desc) assert.are.equal('2026-04-01', meta.due) end) it('stops at non-meta token', function() local desc, meta = parse.body('Buy milk for breakfast due:2026-03-15') assert.are.equal('Buy milk for breakfast', desc) assert.are.equal('2026-03-15', meta.due) end) it('rejects invalid dates', function() local desc, meta = parse.body('Buy milk due:2026-13-15') assert.are.equal('Buy milk due:2026-13-15', desc) assert.is_nil(meta.due) end) it('preserves colons in description', function() local desc, meta = parse.body('Meeting at 3:00pm') assert.are.equal('Meeting at 3:00pm', desc) assert.are.same({}, meta) end) it('uses configurable date syntax', function() vim.g.pending = { date_syntax = 'by' } config.reset() local desc, meta = parse.body('Buy milk by:2026-03-15') assert.are.equal('Buy milk', desc) assert.are.equal('2026-03-15', meta.due) end) it('ignores old syntax when date_syntax is changed', function() vim.g.pending = { date_syntax = 'by' } config.reset() local desc, meta = parse.body('Buy milk due:2026-03-15') assert.are.equal('Buy milk due:2026-03-15', desc) assert.is_nil(meta.due) end) end) describe('command_add', function() it('parses simple text', function() local desc, meta = parse.command_add('Buy milk') assert.are.equal('Buy milk', desc) assert.are.same({}, meta) end) it('detects category prefix', function() local desc, meta = parse.command_add('School: Do homework') assert.are.equal('Do homework', desc) assert.are.equal('School', meta.cat) end) it('ignores lowercase prefix', function() local desc, _ = parse.command_add('hello: world') assert.are.equal('hello: world', desc) end) it('combines category prefix with inline metadata', function() local desc, meta = parse.command_add('School: Do homework due:2026-03-15') assert.are.equal('Do homework', desc) assert.are.equal('School', meta.cat) assert.are.equal('2026-03-15', meta.due) end) end) end)