From c76ca1798e9387009f694a275aaa70322648760c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 6 Nov 2024 08:46:10 +0600 Subject: [PATCH] fixes in parsing of ktontab templates --- CHANGELOG.md | 2 + src/commonMain/kotlin/internal/Parser.kt | 95 +++++++++++++++--------- src/commonTest/kotlin/StringParseTest.kt | 72 +++++++----------- 3 files changed, 91 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7026809..d26f1e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## 2.6.1 +* Fixes in parsing of string parts + ## 2.6.0 * Fix of `doOnceTz` behaviour: now it will use local time as utc time to get next waking up time diff --git a/src/commonMain/kotlin/internal/Parser.kt b/src/commonMain/kotlin/internal/Parser.kt index caaad9b..d724826 100644 --- a/src/commonMain/kotlin/internal/Parser.kt +++ b/src/commonMain/kotlin/internal/Parser.kt @@ -41,53 +41,80 @@ private fun createSimpleScheduler(from: String, dataRange: IntRange, dataCon * FSM for parsing of incoming data. If at the end of parsing it have non-null state and string is not empty, data passed check * * 1. - * * \\d -> 1 - * * \\* -> 2 - * * \\- -> 5 - * * , -> 1 - * * m -> 6 - * * o -> 7 - * * w -> 7 + * * "\\d" -> 2 + * * "\\*" -> 4 + * * "f" -> 7 + * * "l" -> 7 + * * "/" -> 6 * 2. - * * / -> 3 + * * "\\d" -> 2 + * * "/" -> 6 + * * "," -> 1 + * * "-" -> 3 + * * "m" -> 9 + * * "o" -> 10 + * * "w" -> 10 * 3. - * * \\d -> 3 - * * \\* -> 4 + * * "l" -> 7 + * * "\\d" -> 8 * 4. - * * , -> 1 + * * "/" -> 6 + * * "," -> 1 * 5. - * * \\d -> 5 - * * , -> 1 + * * "/" -> 6 * 6. - * * s -> 7 - * 7. Empty, end of parse + * * "\\d" -> 8 + * * "\\*" -> 7 + * 7. + * * "," -> 1 + * 8. + * * "\\d" -> 8 + * * "," -> 1 + * 9. + * * "s" -> 10 // end of ms + * 10. Empty, end of parse */ private val checkIncomingPartTransitionsMap = listOf( - listOf( - Regex("\\d") to 0, - Regex("\\*") to 1, - Regex("-") to 4, - Regex(",") to 0, - Regex("m") to 5, - Regex("o") to 6, - Regex("w") to 6, - ), - listOf( - Regex("/") to 2, - ), - listOf( - Regex("\\d") to 2, + listOf( // 0 + Regex("\\d") to 1, Regex("\\*") to 3, + Regex("f") to 6, + Regex("l") to 6, + Regex("/") to 5, ), - listOf( + listOf( // 1 + Regex("\\d") to 1, + Regex("/") to 5, + Regex(",") to 0, + Regex("-") to 2, + Regex("m") to 8, + Regex("o") to 9, + Regex("w") to 9, + ), + listOf( // 2 + Regex("l") to 6, + Regex("\\d") to 7, + ), + listOf( // 3 + Regex("/") to 5, Regex(",") to 0, ), - listOf( - Regex("\\d") to 4, + listOf( // 4 + Regex("/") to 5, + ), + listOf( // 5 + Regex("\\d") to 7, + Regex("\\*") to 6, + ), + listOf( // 6 Regex(",") to 0, ), - listOf( - Regex("s") to 6, // end of ms + listOf( // 7 + Regex("\\d") to 7, + Regex(",") to 0, + ), + listOf( // 8 + Regex("s") to 9, // end of ms ), listOf(), // empty state, end of parsing ) diff --git a/src/commonTest/kotlin/StringParseTest.kt b/src/commonTest/kotlin/StringParseTest.kt index 0e44c94..5cc7d07 100644 --- a/src/commonTest/kotlin/StringParseTest.kt +++ b/src/commonTest/kotlin/StringParseTest.kt @@ -2,6 +2,7 @@ package dev.inmo.krontab.utils import korlibs.time.* import dev.inmo.krontab.KronSchedulerTz +import dev.inmo.krontab.KrontabTemplate import dev.inmo.krontab.buildSchedule import kotlinx.coroutines.* import kotlinx.coroutines.flow.takeWhile @@ -11,73 +12,51 @@ import kotlin.test.* @ExperimentalCoroutinesApi @FlowPreview class StringParseTest { - @Test - fun testThatFlowIsCorrectlyWorkEverySecondBuiltOnString() { - val kronScheduler = buildSchedule("*/1 * * * *") + private fun makeSimpleEverySecondTest(template: KrontabTemplate) { + val kronScheduler = buildSchedule(template) val flow = kronScheduler.asFlowWithoutDelays() runTest { val mustBeCollected = 10 var collected = 0 + var previousTime: DateTime? = null flow.takeWhile { collected < mustBeCollected }.collect { + previousTime ?.let { previousTime -> + assertEquals(previousTime + 1.seconds, it) + } + previousTime = it collected++ } assertEquals(mustBeCollected, collected) } } + + @Test + fun testThatFlowIsCorrectlyWorkEverySecondBuiltOnString() { + makeSimpleEverySecondTest("*/1 * * * *") + } @Test fun testThatFlowIsCorrectlyWorkEverySecondBuiltOnStringWithWrongAmountOfSpaces() { - val kronScheduler = buildSchedule("*/1 * * * * ") - - val flow = kronScheduler.asFlowWithoutDelays() - - runTest { - val mustBeCollected = 10 - var collected = 0 - flow.takeWhile { - collected < mustBeCollected - }.collect { - collected++ - } - assertEquals(mustBeCollected, collected) + val templatesFirstReplacers = listOf( + "*/1", + "*", + "/1", + "f,/1", + ) + templatesFirstReplacers.forEach { replacer -> + makeSimpleEverySecondTest("$replacer * * * * ") } } @Test fun testThatFlowIsCorrectlyWorkEverySecondBuiltOnStringWithGarbageInTemplate() { - val kronScheduler = buildSchedule(" sdf */1 * * * oo * ") - - val flow = kronScheduler.asFlowWithoutDelays() - - runTest { - val mustBeCollected = 10 - var collected = 0 - flow.takeWhile { - collected < mustBeCollected - }.collect { - collected++ - } - assertEquals(mustBeCollected, collected) - } + makeSimpleEverySecondTest(" sdf */1 * * * oo * ") } @Test fun testThatFlowIsCorrectlyWorkEverySecondBuiltOnStringWithInsufficientArgsInTemplate() { - val kronScheduler = buildSchedule(" sdf */1 ") - - val flow = kronScheduler.asFlowWithoutDelays() - - runTest { - val mustBeCollected = 10 - var collected = 0 - flow.takeWhile { - collected < mustBeCollected - }.collect { - collected++ - } - assertEquals(mustBeCollected, collected) - } + makeSimpleEverySecondTest(" sdf */1 ") } @Test fun testThatFlowIsCorrectlyWorkEverySecondWhenMillisIsHalfOfSecondBuiltOnString() { @@ -88,9 +67,14 @@ class StringParseTest { runTest { val mustBeCollected = 10 var collected = 0 + var previousTime: DateTime? = null flow.takeWhile { collected < mustBeCollected }.collect { + previousTime ?.let { previousTime -> + assertEquals(previousTime.copy(milliseconds = 500) + 1.seconds, it) + } + previousTime = it collected++ } assertEquals(mustBeCollected, collected)