From a598218cf2579776afd30a2a46a11fd2fb40e403 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Fri, 21 Jun 2024 19:54:15 +0200 Subject: [PATCH] Add tests --- composeApp/build.gradle.kts | 12 +- .../src/commonMain/kotlin/domain/clues.kt | 8 +- .../src/commonTest/kotlin/domain/ClueTest.kt | 25 ++++ .../kotlin/domain/NeighbourClueTest.kt | 108 ++++++++++++++---- .../commonTest/kotlin/domain/OrderClueTest.kt | 28 +++++ .../kotlin/domain/TripletClueTest.kt | 46 ++++++++ gradle/libs.versions.toml | 3 +- 7 files changed, 194 insertions(+), 36 deletions(-) create mode 100644 composeApp/src/commonTest/kotlin/domain/ClueTest.kt create mode 100644 composeApp/src/commonTest/kotlin/domain/OrderClueTest.kt create mode 100644 composeApp/src/commonTest/kotlin/domain/TripletClueTest.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 45bb8ec..dc45c00 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -3,7 +3,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { - alias(libs.plugins.jetbrainsKotlinJvm) alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidApplication) alias(libs.plugins.jetbrainsCompose) @@ -20,6 +19,7 @@ kotlin { androidTarget() jvm("desktop") + @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) sourceSets { val androidUnitTest by getting val desktopMain by getting @@ -42,18 +42,16 @@ kotlin { implementation(compose.desktop.currentOs) } androidUnitTest.dependencies { - implementation(kotlin("test")) + implementation(libs.kotlin.test) + implementation(compose.uiTest) implementation(libs.atrium) } commonTest.dependencies { - implementation(kotlin("test")) + implementation(libs.kotlin.test) implementation(libs.atrium) - - @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) - implementation(compose.uiTest) } desktopTest.dependencies { - implementation(kotlin("test")) + implementation(libs.kotlin.test) implementation(libs.atrium) implementation(compose.desktop.uiTestJUnit4) implementation(compose.desktop.currentOs) diff --git a/composeApp/src/commonMain/kotlin/domain/clues.kt b/composeApp/src/commonMain/kotlin/domain/clues.kt index dadcabb..bed6e28 100644 --- a/composeApp/src/commonMain/kotlin/domain/clues.kt +++ b/composeApp/src/commonMain/kotlin/domain/clues.kt @@ -56,14 +56,16 @@ class TripletClue>(val a: Item, val b: Item, val c: Item< val ib = grid.indexOf(bType) val ic = grid.indexOf(cType) + if (ib == 0 || ib == grid.size) { + return true + } + if (ia == -1 && ic == -1) { return false } if (ia != -1 && ic != -1) { - if (ia + 2 == ic || ia == ic + 2) { - return true - } + return !(ia + 2 == ic || ia == ic + 2) } if (isNeighbourRuleViolated(ia, ib) || isNeighbourRuleViolated(ib, ic)) { diff --git a/composeApp/src/commonTest/kotlin/domain/ClueTest.kt b/composeApp/src/commonTest/kotlin/domain/ClueTest.kt new file mode 100644 index 0000000..253c520 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/domain/ClueTest.kt @@ -0,0 +1,25 @@ +package domain + +abstract class ClueTest { + protected val size = 6 + + protected fun createGrid(selection: (Item>) -> Item>? = { it }) = Grid( + ItemClass.randomClasses(size) + .map { + it.randomItems(size).map { item -> Item(item) } + } + .map { row -> + GameRow( + category = row.first().itemType.companion, + options = row, + cells = row.map { + GameCell( + selection = selection(it), + solution = it, + options = mutableListOf() + ) + } + ) + } + ) +} \ No newline at end of file diff --git a/composeApp/src/commonTest/kotlin/domain/NeighbourClueTest.kt b/composeApp/src/commonTest/kotlin/domain/NeighbourClueTest.kt index c06010f..10b3893 100644 --- a/composeApp/src/commonTest/kotlin/domain/NeighbourClueTest.kt +++ b/composeApp/src/commonTest/kotlin/domain/NeighbourClueTest.kt @@ -1,36 +1,94 @@ package domain -import ch.tutteli.atrium.api.fluent.en_GB.feature -import ch.tutteli.atrium.api.fluent.en_GB.size -import ch.tutteli.atrium.api.fluent.en_GB.toBeLessThan import ch.tutteli.atrium.api.fluent.en_GB.toEqual -import ch.tutteli.atrium.api.fluent.en_GB.toHaveSize import ch.tutteli.atrium.api.verbs.expect -import domain.Item import kotlin.test.Test -class NeighbourClueTest { +class NeighbourClueTest : ClueTest() { + @Test fun `ensure actual neighbours are valid`() { - val size = 5 - val grid = ItemClass.randomClasses(size) - .map { - it.randomItems(size).map { item -> Item(item) } - } - .map { row -> - GameRow( - category = row.first().itemType.companion, - options = row, - cells = row.map { - GameCell( - selection = it, - solution = it, - options = mutableListOf() - ) - } - ) - } + val grid = createGrid() + for (ia in 0 until size) { + for (ib in 0 until size) { + for (j in 1 until size) { + val a = grid[ia][j - 1] + val b = grid[ib][j] - NeighbourClue(Item(Animals.ANT), Item(Profession.ASTRONAUT)) + expect(NeighbourClue(a.solution, b.solution).isRuleViolated(grid)) + .toEqual(false) + expect(NeighbourClue(b.solution, a.solution).isRuleViolated(grid)) + .toEqual(false) + } + } + } } + + @Test + fun `ensure non-neighbours are invalid`() { + val grid = createGrid() + for (ia in 0 until size) { + for (ib in 0 until size) { + for (ja in 0 until size) { + for (jb in 0 until size) { + if (ja == jb + 1 || ja == jb - 1) { + continue + } + val a = grid[ia][ja] + val b = grid[ib][jb] + + expect(NeighbourClue(a.solution, b.solution).isRuleViolated(grid)) + .toEqual(true) + expect(NeighbourClue(b.solution, a.solution).isRuleViolated(grid)) + .toEqual(true) + } + } + } + } + } + + @Test + fun `ensure grid with one neighbour not set is considered valid`() { + val grid = createGrid() + for (ia in 0 until size) { + for (ib in 0 until size) { + for (j in 1 until size) { + val a = grid[ia][j - 1] + val b = grid[ib][j] + + a.selection = null + b.selection = b.solution + + expect(NeighbourClue(a.solution, b.solution).isRuleViolated(grid)) + .toEqual(false) + expect(NeighbourClue(b.solution, a.solution).isRuleViolated(grid)) + .toEqual(false) + + a.selection = a.solution + b.selection = null + + expect(NeighbourClue(a.solution, b.solution).isRuleViolated(grid)) + .toEqual(false) + expect(NeighbourClue(b.solution, a.solution).isRuleViolated(grid)) + .toEqual(false) + } + } + } + } + + @Test + fun `ensure grid with a and c more than one cell between is not considered valid`() { + val grid = createGrid { null } + val a = grid[2][1] + val b = grid[0][2] + + a.selection = a.solution + grid[0][3].selection = b.solution + + expect(NeighbourClue(a.solution, b.solution).isRuleViolated(grid)) + .toEqual(true) + expect(NeighbourClue(b.solution, a.solution).isRuleViolated(grid)) + .toEqual(true) + } + } \ No newline at end of file diff --git a/composeApp/src/commonTest/kotlin/domain/OrderClueTest.kt b/composeApp/src/commonTest/kotlin/domain/OrderClueTest.kt new file mode 100644 index 0000000..be919a7 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/domain/OrderClueTest.kt @@ -0,0 +1,28 @@ +package domain + +import ch.tutteli.atrium.api.fluent.en_GB.toEqual +import ch.tutteli.atrium.api.verbs.expect +import kotlin.test.Test + +class OrderClueTest : ClueTest() { + @Test + fun `ensure items in correct order are valid`() { + val grid = createGrid() + for (ia in 0 until size) { + for (ib in 0 until size) { + for (ic in 0 until size) { + for (ja in 0 until size - 1) { + for (jb in ja + 1 until size) { + val a = grid[ia][ja] + val b = grid[ib][jb] + + expect(OrderClue(a.solution, b.solution).isRuleViolated(grid)) + .toEqual(false) + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/composeApp/src/commonTest/kotlin/domain/TripletClueTest.kt b/composeApp/src/commonTest/kotlin/domain/TripletClueTest.kt new file mode 100644 index 0000000..765e0cc --- /dev/null +++ b/composeApp/src/commonTest/kotlin/domain/TripletClueTest.kt @@ -0,0 +1,46 @@ +package domain + +import ch.tutteli.atrium.api.fluent.en_GB.toEqual +import ch.tutteli.atrium.api.verbs.expect +import kotlin.test.Test + +class TripletClueTest : ClueTest() { + + @Test + fun `ensure actual triplets are valid`() { + val grid = createGrid() + for (ia in 0 until size) { + for (ib in 0 until size) { + for (ic in 0 until size) { + for (j in 2 until size) { + val a = grid[ia][j - 2] + val b = grid[ib][j - 1] + val c = grid[ic][j] + + expect(TripletClue(a.solution, b.solution, c.solution).isRuleViolated(grid)) + .toEqual(false) + expect(TripletClue(a.solution, b.solution, c.solution).isRuleViolated(grid)) + .toEqual(false) + } + } + } + } + } + + @Test + fun `ensure grid with a and c more than one cell between is not considered valid`() { + val grid = createGrid { null } + val a = grid[2][1] + val b = grid[0][2] + val c = grid[1][3] + + a.selection = a.solution + grid[1][4].selection = c.solution + + expect(TripletClue(a.solution, b.solution, c.solution).isRuleViolated(grid)) + .toEqual(true) + expect(TripletClue(a.solution, b.solution, c.solution).isRuleViolated(grid)) + .toEqual(true) + } + +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7e9f1dd..b8bd4f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,11 +9,12 @@ compose-plugin = "1.6.11" kotlin = "2.0.0" [libraries] -atrium = { module = "ch.tutteli.atrium:atrium-fluent", version = "1.2.0" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" } compose-ui-text-googlefonts = { module = "androidx.compose.ui:ui-text-google-fonts", version.ref = "compose" } +kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } +atrium = { module = "ch.tutteli.atrium:atrium-fluent", version = "1.2.0" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }