From 033413cf3e9116078601efc56a649d07da319666 Mon Sep 17 00:00:00 2001 From: Avinal Kumar Date: Fri, 5 Jun 2026 15:05:16 +0530 Subject: [PATCH] Add 18 tests for relative dates and tag inheritance Relative date tests (12): - next week, in N days, next monday/friday parsing - Cleaned text verification (metadata stripped) - Future date assertions, exact day-count checks Tag inheritance tests (3): - Task-level tag overrides memo tags - No task tag inherits memo tags - Empty memo tags = empty lists Parser doctor tests (4): - No false positives for next monday, next week, in N days - Reminder with relative date valid 162 tests passing. Signed-off-by: Avinal Kumar Co-Authored-By: Claude Opus 4.6 (1M context) --- .../com/avinal/memos/ParserDoctorTest.kt | 19 +++++- .../kotlin/com/avinal/memos/TaskParserTest.kt | 67 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/composeApp/src/commonTest/kotlin/com/avinal/memos/ParserDoctorTest.kt b/composeApp/src/commonTest/kotlin/com/avinal/memos/ParserDoctorTest.kt index 99df913..3133a80 100644 --- a/composeApp/src/commonTest/kotlin/com/avinal/memos/ParserDoctorTest.kt +++ b/composeApp/src/commonTest/kotlin/com/avinal/memos/ParserDoctorTest.kt @@ -116,8 +116,25 @@ class ParserDoctorTest { } @Test fun singleTaskNoDateNotWarned() { - // Only 1 task without date should not trigger the combined warning val w = TaskParser.validateContent("- [ ] Single task") assertTrue(w.none { it.issue.contains("tasks have no due date") }) } + + // --- Relative dates no false positives --- + + @Test fun noWarningNextMonday() { + assertTrue(TaskParser.validateContent("- [ ] Call next monday 5pm").isEmpty()) + } + + @Test fun noWarningNextWeek() { + assertTrue(TaskParser.validateContent("- [ ] Plan next week").isEmpty()) + } + + @Test fun noWarningInDays() { + assertTrue(TaskParser.validateContent("- [ ] Follow up in 3 days").isEmpty()) + } + + @Test fun reminderWithNextFriday() { + assertTrue(TaskParser.validateContent("- [ ] Deploy next friday !1hr").isEmpty()) + } } diff --git a/composeApp/src/commonTest/kotlin/com/avinal/memos/TaskParserTest.kt b/composeApp/src/commonTest/kotlin/com/avinal/memos/TaskParserTest.kt index ae644bf..cdfb72d 100644 --- a/composeApp/src/commonTest/kotlin/com/avinal/memos/TaskParserTest.kt +++ b/composeApp/src/commonTest/kotlin/com/avinal/memos/TaskParserTest.kt @@ -2,6 +2,8 @@ package com.avinal.memos import com.avinal.memos.domain.ReminderUnit import com.avinal.memos.parser.TaskParser +import kotlinx.datetime.daysUntil +import kotlinx.datetime.todayIn import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -184,4 +186,69 @@ class TaskParserTest { assertNotNull(t.dueDate); assertEquals(15, t.dueTime!!.hour) assertEquals(15, t.reminder!!.value); assertEquals(ReminderUnit.MIN, t.reminder!!.unit) } + + // --- Relative dates --- + + @Test fun parsesNextWeek() { + val t = TaskParser.extractTasks("m1", "- [ ] Plan next week")[0] + assertNotNull(t.dueDate) + } + @Test fun parsesInDays() { + val t = TaskParser.extractTasks("m1", "- [ ] Follow up in 3 days")[0] + assertNotNull(t.dueDate) + } + @Test fun parsesIn1Day() { + val t = TaskParser.extractTasks("m1", "- [ ] Check in 1 day")[0] + assertNotNull(t.dueDate) + } + @Test fun parsesNextMonday() { + val t = TaskParser.extractTasks("m1", "- [ ] Standup next monday")[0] + assertNotNull(t.dueDate) + } + @Test fun parsesNextFriday() { + val t = TaskParser.extractTasks("m1", "- [ ] Deploy next friday")[0] + assertNotNull(t.dueDate) + } + @Test fun nextMondayCleaned() { + val t = TaskParser.extractTasks("m1", "- [ ] Standup next monday")[0] + assertEquals("Standup", t.text) + } + @Test fun inDaysCleaned() { + val t = TaskParser.extractTasks("m1", "- [ ] Follow up in 3 days")[0] + assertEquals("Follow up", t.text) + } + @Test fun nextWeekCleaned() { + val t = TaskParser.extractTasks("m1", "- [ ] Plan next week")[0] + assertEquals("Plan", t.text) + } + @Test fun nextDayIsFuture() { + val today = kotlin.time.Clock.System.todayIn(kotlinx.datetime.TimeZone.currentSystemDefault()) + val t = TaskParser.extractTasks("m1", "- [ ] Do next monday")[0] + assertTrue(t.dueDate!! > today) + } + @Test fun nextWeekIs7DaysAhead() { + val today = kotlin.time.Clock.System.todayIn(kotlinx.datetime.TimeZone.currentSystemDefault()) + val t = TaskParser.extractTasks("m1", "- [ ] Plan next week")[0] + assertEquals(7, today.daysUntil(t.dueDate!!)) + } + @Test fun in5DaysIs5Ahead() { + val today = kotlin.time.Clock.System.todayIn(kotlinx.datetime.TimeZone.currentSystemDefault()) + val t = TaskParser.extractTasks("m1", "- [ ] Review in 5 days")[0] + assertEquals(5, today.daysUntil(t.dueDate!!)) + } + + // --- Tag inheritance --- + + @Test fun taskLevelTagOverridesMemoTag() { + val t = TaskParser.extractTasks("m1", "- [ ] Fix bug #devops", listOf("work"))[0] + assertEquals(listOf("devops"), t.lists) + } + @Test fun noTaskTagInheritsMemoTags() { + val t = TaskParser.extractTasks("m1", "- [ ] Fix bug", listOf("work", "urgent"))[0] + assertEquals(listOf("work", "urgent"), t.lists) + } + @Test fun emptyMemoTagsNoInheritance() { + val t = TaskParser.extractTasks("m1", "- [ ] Fix bug")[0] + assertTrue(t.lists.isEmpty()) + } }