This commit is contained in:
InsanusMokrassar 2024-11-03 12:54:51 +06:00
parent ca5794726f
commit e4b3a5059a
4 changed files with 91 additions and 18 deletions

View File

@ -9,6 +9,8 @@
## 2.5.0 ## 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`: * `Version`:
* `Kotlin`: `2.0.20` * `Kotlin`: `2.0.20`
* `AndroidXWork`: `2.10.0` * `AndroidXWork`: `2.10.0`

View File

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

View File

@ -37,6 +37,10 @@ private fun <T> createSimpleScheduler(from: String, dataRange: IntRange, dataCon
return results.map(dataConverter) 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 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 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() } internal fun parseYears(from: String?) = from ?.let { createSimpleScheduler(from, yearRange, intToIntConverter) ?.toTypedArray() }

View File

@ -29,6 +29,57 @@ class StringParseTest {
} }
} }
@Test @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() { fun testThatFlowIsCorrectlyWorkEverySecondWhenMillisIsHalfOfSecondBuiltOnString() {
val kronScheduler = buildSchedule("*/1 * * * * 500ms") val kronScheduler = buildSchedule("*/1 * * * * 500ms")