Skip to content

Commit

Permalink
fix of #126
Browse files Browse the repository at this point in the history
  • Loading branch information
InsanusMokrassar committed Nov 3, 2024
1 parent ca57947 commit e4b3a50
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

## 2.5.0

* Add cleaning up of incoming template, which must remove all malformed parts from string template (fix of [#126](https://github.com/InsanusMokrassar/krontab/issues/126))
* Add support of insufficient amount of arguments (fix of [#126](https://github.com/InsanusMokrassar/krontab/issues/126))
* `Version`:
* `Kotlin`: `2.0.20`
* `AndroidXWork`: `2.10.0`
Expand Down
52 changes: 34 additions & 18 deletions src/commonMain/kotlin/KrontabConfig.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.inmo.krontab

import dev.inmo.krontab.internal.*
import dev.inmo.krontab.internal.CronDateTimeScheduler
import dev.inmo.krontab.internal.CronDateTimeSchedulerTz
import dev.inmo.krontab.internal.createKronScheduler
Expand Down Expand Up @@ -94,27 +95,37 @@ value class KrontabConfig(
var dayOfWeekParsed: Array<Byte>? = null
var yearParsed: Array<Int>? = null
var millisecondsParsed: Array<Short>? = null
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = template.split(" ").also {
listOfNotNull(
it.getOrNull(5),
it.getOrNull(6),
it.getOrNull(7),
it.getOrNull(8)
).forEach {
val offsetFromString = parseOffset(it)
val dayOfWeekFromString = parseWeekDay(it)
val millisecondsFromString = parseMilliseconds(it)
offsetParsed = offsetParsed ?: offsetFromString
dayOfWeekParsed = dayOfWeekParsed ?: dayOfWeekFromString
millisecondsParsed = millisecondsParsed ?: millisecondsFromString
when {
dayOfWeekFromString != null || offsetFromString != null || millisecondsFromString != null -> return@forEach
yearParsed == null -> {
yearParsed = parseYears(it)
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = template
.split(Regex("\\s"))
.filter { it.matches(KrontabConfigPartRegex) } // filter garbage from string
.let {
if (it.size < 5) { // reconstruction in case of insufficient arguments; 5 is amount of required arguments out of latest also code
it + (it.size until 5).map { "*" }
} else {
it
}
}
.also {
listOfNotNull(
it.getOrNull(5),
it.getOrNull(6),
it.getOrNull(7),
it.getOrNull(8)
).forEach {
val offsetFromString = parseOffset(it)
val dayOfWeekFromString = parseWeekDay(it)
val millisecondsFromString = parseMilliseconds(it)
offsetParsed = offsetParsed ?: offsetFromString
dayOfWeekParsed = dayOfWeekParsed ?: dayOfWeekFromString
millisecondsParsed = millisecondsParsed ?: millisecondsFromString
when {
dayOfWeekFromString != null || offsetFromString != null || millisecondsFromString != null -> return@forEach
yearParsed == null -> {
yearParsed = parseYears(it)
}
}
}
}
}

val secondsParsed = parseSeconds(secondsSource)
val minutesParsed = parseMinutes(minutesSource)
Expand Down Expand Up @@ -162,4 +173,9 @@ value class KrontabConfig(
)
}
}

companion object {
val spacesRegex = Regex("\\s")
val numberRegex = Regex("\\d+")
}
}
4 changes: 4 additions & 0 deletions src/commonMain/kotlin/internal/Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ private fun <T> createSimpleScheduler(from: String, dataRange: IntRange, dataCon
return results.map(dataConverter)
}

internal val KrontabPartNumberRegexString = "((\\d+\\-\\d+)|([\\d\\*]+(/[\\d\\*]+)?))"
internal val KrontabPartsNumberRegexString = "$KrontabPartNumberRegexString(,$KrontabPartNumberRegexString)*"
internal val KrontabConfigPartRegex = Regex("(($KrontabPartsNumberRegexString+)|(\\d+o)|($KrontabPartsNumberRegexString+w)|($KrontabPartsNumberRegexString+ms))")

internal fun parseWeekDay(from: String?) = from ?.let { if (it.endsWith("w")) createSimpleScheduler(it.removeSuffix("w"), dayOfWeekRange, intToByteConverter) ?.toTypedArray() else null }
internal fun parseOffset(from: String?) = from ?.let { if (it.endsWith("o")) it.removeSuffix("o").toIntOrNull() else null }
internal fun parseYears(from: String?) = from ?.let { createSimpleScheduler(from, yearRange, intToIntConverter) ?.toTypedArray() }
Expand Down
51 changes: 51 additions & 0 deletions src/commonTest/kotlin/StringParseTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,57 @@ class StringParseTest {
}
}
@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)
}
}
@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)
}
}
@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)
}
}
@Test
fun testThatFlowIsCorrectlyWorkEverySecondWhenMillisIsHalfOfSecondBuiltOnString() {
val kronScheduler = buildSchedule("*/1 * * * * 500ms")

Expand Down

0 comments on commit e4b3a50

Please sign in to comment.