Skip to content

Commit

Permalink
Feature/versions (#18)
Browse files Browse the repository at this point in the history
* Switch Builder Test on Kotest

* Switch Parser Tests on Kotest

* Add Versions support

* Cover versions by tests

* Increase Version

* Update README

* Fix code smells
  • Loading branch information
Scogun authored Nov 22, 2023
1 parent 1dad733 commit 0d65376
Show file tree
Hide file tree
Showing 23 changed files with 377 additions and 167 deletions.
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# KCron Common
Cron realization for Kotlin Multiplatform

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Scogun_kcron-common&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Scogun_kcron-common) ![GitHub](https://img.shields.io/github/license/Scogun/kcron-common?color=blue) ![Publish workflow](https://github.com/Scogun/kcron-common/actions/workflows/publish.yml/badge.svg) [![Maven Central with version prefix filter](https://img.shields.io/maven-central/v/com.ucasoft.kcron/kcron-common/0.7.3?color=blue)](https://search.maven.org/artifact/com.ucasoft.kcron/kcron-common/0.7.3/jar)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Scogun_kcron-common&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Scogun_kcron-common) ![GitHub](https://img.shields.io/github/license/Scogun/kcron-common?color=blue) ![Publish workflow](https://github.com/Scogun/kcron-common/actions/workflows/publish.yml/badge.svg) [![Maven Central with version prefix filter](https://img.shields.io/maven-central/v/com.ucasoft.kcron/kcron-common/0.8.0?color=blue)](https://search.maven.org/artifact/com.ucasoft.kcron/kcron-common/0.8.0/jar)

### Features
* Kotlin Multiplatform library
Expand Down Expand Up @@ -38,7 +38,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'com.ucasoft.kcron:kcron-common:0.7.3'
implementation 'com.ucasoft.kcron:kcron-common:0.8.0'
}
}
}
Expand All @@ -57,9 +57,12 @@ builder
.years(2050)
println(builder.expression) // 0/10 5-25 5,12 ? * 7#5 2050
```
***Parse Cron expression***
***Parse as Classic as well as Modern Cron expressions***
```kotlin
val builder = KCron.parseAndBuild("0/10 5-25 5,12 ? * 7#5 2050", WeekDays.Sunday)
// Auto detect
val builder = KCron.parseAndBuild("0/10 5-25 5,12 ? * 7#5 2050") {
it.firstDayOfWeek = WeekDays.Sunday
}
println(builder.nextRunList()) // 10 is a default list size
/* Result:
[
Expand All @@ -74,7 +77,15 @@ println(builder.nextRunList()) // 10 is a default list size
2050-01-29T05:06:20,
2050-01-29T05:06:30
]
*/
*/
// OR Force to parse only Classic expressions
try {
val builder = KCron.parseAndBuild("0/10 5-25 5,12 ? * 7#5 2050") {
it.version = Version.Classic
}
} catch(e: WrongCronExpression) {
println(e.message) // Expression 0/10 5-25 5,12 ? * 7#5 2050 is not Classic Cron one!
}
```
***Days of week and months can be defined in a parsed expression as numbers as well as short names***
```kotlin
Expand All @@ -91,6 +102,6 @@ builder.years(2021..2025)
println(builder.expression) // 0/10 5-25 5,12 ? * SUN#5 2021-2025
```
### Current status
This library is on beta version `0.7.3`.
This library is on beta version `0.8.0`.
However, it will be a part of another cool library.
Check the news!
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group = "com.ucasoft.kcron"
version = "0.7.3"
version = "0.8.0"

repositories {
mavenCentral()
Expand Down Expand Up @@ -36,6 +36,7 @@ kotlin {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
implementation("io.kotest:kotest-assertions-core:5.8.0")
}
}
val jsTest by getting {
Expand Down
9 changes: 6 additions & 3 deletions src/commonMain/kotlin/com/ucasoft/kcron/KCron.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package com.ucasoft.kcron
import com.ucasoft.kcron.builders.Builder
import com.ucasoft.kcron.common.WeekDays
import com.ucasoft.kcron.parsers.Parser
import com.ucasoft.kcron.settings.Settings

class KCron {

companion object {

fun parseAndBuild(expression: String, firstDayOfWeek: WeekDays = WeekDays.Monday) : Builder {
val parseResult = Parser().parse(expression)
return Builder(firstDayOfWeek).build(parseResult.parts)
fun parseAndBuild(expression: String, block: (Settings) -> Unit = {}) : Builder {
val settings = Settings()
block.invoke(settings)
val parseResult = Parser().parse(expression, settings.version)
return Builder(settings.firstDayOfWeek).build(parseResult.parts)
}

fun builder(firstDayOfWeek: WeekDays = WeekDays.Monday): Builder {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package com.ucasoft.kcron.exceptions

class WrongCronExpression(expression: String) : Throwable("Expression $expression is not Cron one!")
import com.ucasoft.kcron.settings.Version

class WrongCronExpression(expression: String, version: Version) : Throwable("Expression $expression is not ${if (version != Version.Auto) "$version " else ""}Cron one!")
21 changes: 15 additions & 6 deletions src/commonMain/kotlin/com/ucasoft/kcron/parsers/Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.ucasoft.kcron.parsers

import com.ucasoft.kcron.common.*
import com.ucasoft.kcron.exceptions.*
import com.ucasoft.kcron.settings.Version

class Parser {

Expand All @@ -28,19 +29,27 @@ class Parser {
CombinationRule(CronPart.DaysOfWeek, DayOfWeekGroups.OfMonth, listOf(CombinationRule(CronPart.Days, DayGroups.Any)))
)

fun parse(expression: String): ParseResult {
val expressionParts = splitExpression(expression)
fun parse(expression: String, version: Version = Version.Auto): ParseResult {
val expressionParts = splitExpression(expression, version)
val parseResult = parsePartsAndEnsureValid(expressionParts)
ensureCombinationRules(parseResult.parts)
return parseResult
}

private fun splitExpression(expression: String): List<String> {
private fun splitExpression(expression: String, version: Version): List<String> {
val expressionParts = expression.split(' ')
if (expressionParts.size != 7) {
throw WrongCronExpression(expression)
if (expressionParts.size == 5 && (version == Version.Auto || version == Version.Classic)) {
return expressionParts.toMutableList().also {
it.add(0, "0")
it.add("*")
}
}

if (expressionParts.size == 7 && (version == Version.Auto || version == Version.Modern)) {
return expressionParts
}
return expressionParts

throw WrongCronExpression(expression, version)
}

private fun parsePartsAndEnsureValid(expressionParts: List<String>): ParseResult {
Expand Down
5 changes: 5 additions & 0 deletions src/commonMain/kotlin/com/ucasoft/kcron/settings/Settings.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.ucasoft.kcron.settings

import com.ucasoft.kcron.common.WeekDays

data class Settings(var firstDayOfWeek: WeekDays = WeekDays.Monday, var version: Version = Version.Auto)
10 changes: 10 additions & 0 deletions src/commonMain/kotlin/com/ucasoft/kcron/settings/Version.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ucasoft.kcron.settings

enum class Version {

Auto,

Classic,

Modern
}
70 changes: 70 additions & 0 deletions src/commonTest/kotlin/com/ucasoft/kcron/BuildAndParseTests.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.ucasoft.kcron

import com.ucasoft.kcron.exceptions.WrongCronExpression
import com.ucasoft.kcron.settings.Version
import io.kotest.assertions.throwables.shouldThrowWithMessage
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import kotlin.test.BeforeTest
import kotlin.test.Test

class BuildAndParseTests {

private var currentYear : Int = 2023

private val modernCronExpression = "30 * * ? * * 2050"

@BeforeTest
fun setupOnce() {
currentYear = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).year
}

@Test
fun parseAndBuildAuto() {
var builder = KCron.parseAndBuild("* 12 ? * *")
builder.expression.shouldBe("0 * 12 ? * * *")
builder.nextRun.shouldNotBeNull()
.year.shouldBe(currentYear)
builder = KCron.parseAndBuild(modernCronExpression)
builder.expression.shouldBe(modernCronExpression)
builder.nextRun.shouldNotBeNull()
.year.shouldBe(2050)
shouldThrowWithMessage<WrongCronExpression>("Expression * * * ? * * is not Cron one!") {
KCron.parseAndBuild("* * * ? * *")
}
}

@Test
fun parseAndBuildClassic() {
val builder = KCron.parseAndBuild("* 12 ? * *") {
it.version = Version.Classic
}
builder.expression.shouldBe("0 * 12 ? * * *")
builder.nextRun.shouldNotBeNull()
.year.shouldBe(currentYear)
shouldThrowWithMessage<WrongCronExpression>("Expression * * * ? * * * is not Classic Cron one!") {
KCron.parseAndBuild("* * * ? * * *") {
it.version = Version.Classic
}
}
}

@Test
fun parseAndBuildModern() {
val builder = KCron.parseAndBuild(modernCronExpression) {
it.version = Version.Modern
}
builder.expression.shouldBe(modernCronExpression)
builder.nextRun.shouldNotBeNull()
.year.shouldBe(2050)
shouldThrowWithMessage<WrongCronExpression>("Expression * * ? * * is not Modern Cron one!") {
KCron.parseAndBuild("* * ? * *") {
it.version = Version.Modern
}
}
}

}
Loading

0 comments on commit 0d65376

Please sign in to comment.