Skip to content

Commit

Permalink
fix ValueValidator not returning isValid for empty rule sets.
Browse files Browse the repository at this point in the history
fix outcome() not returning SUCCESS for empty rule sets
  • Loading branch information
chrisjenx committed Oct 9, 2024
1 parent f3170b8 commit 4b26783
Show file tree
Hide file tree
Showing 18 changed files with 288 additions and 36 deletions.
3 changes: 1 addition & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]

kotlin = "2.0.21-RC"
kotlin = "2.0.20"
compose = "1.7.0-rc01"
agp = "8.7.0"
androidx-activityCompose = "1.9.2"
Expand All @@ -10,7 +10,6 @@ libphonenumberJvm = "8.13.47"
libphonenumberAndroid = "8.13.35"
coreKtx = "1.13.1"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.6"
composeBom = "2024.09.03"
Expand Down
11 changes: 7 additions & 4 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.compose)
//alias(libs.plugins.cocoapods)
// alias(libs.plugins.cocoapods)
alias(libs.plugins.maven.publish)
}

Expand All @@ -28,9 +28,9 @@ kotlin {
// homepage = "https://github.com/chrisjenx/yakcov"
// ios.deploymentTarget = "14.1"
// framework {
// baseName = "shared"
// isStatic = true
// pod("libPhoneNumber-iOS")
// baseName = "yakcov"
//// isStatic = true
//// pod("libPhoneNumber-iOS")
//// @OptIn(ExperimentalKotlinGradlePluginApi::class)
//// transitiveExport = true
// }
Expand Down Expand Up @@ -118,6 +118,9 @@ kotlin {
implementation(compose.desktop.currentOs)
implementation(libs.libphonenumber.jvm)
}
jvmTest.dependencies {
implementation(compose.desktop.currentOs)
}

jsMain.dependencies {
implementation(compose.html.core)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.chrisjenx.yakcov

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class IOSIgnore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class AndroidJUnitIgnore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class JSIgnore()

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.chrisjenx.yakcov

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class IOSIgnore

actual typealias AndroidJUnitIgnore = org.junit.Ignore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class JSIgnore()
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ abstract class ValueValidator<V, R>(
*/
val isValid: Boolean by derivedStateOf {
if (internalState !is InternalState.Validating) return@derivedStateOf false
// If no rules set then we are always valid
val severity = validationResults.map { it.outcome() }.maxOfOrNull { it.severity }
?: return@derivedStateOf false
?: return@derivedStateOf true
severity < Outcome.ERROR.severity
}

Expand Down Expand Up @@ -95,7 +96,7 @@ abstract class ValueValidator<V, R>(
*/
fun isError(): Boolean = validationResults
.takeIf { (internalState as? InternalState.Validating)?.shouldShowError == true }
?.maxOfOrNull { it.outcome().severity >= Outcome.ERROR.severity }
?.any { it.outcome().severity >= Outcome.ERROR.severity }
?: false

/**
Expand All @@ -106,7 +107,11 @@ abstract class ValueValidator<V, R>(
*/
fun outcome(): Outcome? = validationResults
.takeIf { internalState is InternalState.Validating }
?.maxByOrNull { it.outcome().severity }?.outcome()
.let { results ->
if (results == null) return@let null // Not validating yet
// Return the result with the highest severity, or if no rules return success
results.maxByOrNull { it.outcome().severity }?.outcome() ?: Outcome.SUCCESS
}

/**
* @return the error message of [ValueValidatorRule] with [Outcome.ERROR], null otherwise.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.chrisjenx.yakcov

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
expect annotation class IOSIgnore()

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
expect annotation class AndroidJUnitIgnore()

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
expect annotation class JSIgnore()
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package com.chrisjenx.yakcov

import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.runComposeUiTest
import com.chrisjenx.yakcov.strings.Required
import org.jetbrains.compose.resources.stringResource
import yakcov.library.generated.resources.Res
import yakcov.library.generated.resources.ruleRequired
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue

@OptIn(ExperimentalTestApi::class)
class ValueValidatorTest {

private val noRulesValueValidator = object : ValueValidator<String, String>(
state = mutableStateOf(""),
rules = emptyList(),
validateMapper = { validate(it) }
) {}

private val ruleValueValidator = object : ValueValidator<String, String>(
state = mutableStateOf(""),
rules = listOf(Required),
validateMapper = { validate(it) }
) {}


@Test
fun noRulesValueValidator() {
assertEquals(
expected = ValueValidator.InternalState.Validating(),
noRulesValueValidator.internalState,
"internalState should be Validating"
)
assertTrue(noRulesValueValidator.isValid, "isValid should be true")
assertEquals(
expected = 0, noRulesValueValidator.validationResults.size,
"Should have no validation results"
)
assertFalse(
noRulesValueValidator.isError(),
"isError should be false"
)
assertEquals(
expected = ValidationResult.Outcome.SUCCESS,
noRulesValueValidator.outcome(),
"outcome should be SUCCESS"
)
}

@Test
@AndroidJUnitIgnore
@JSIgnore
fun noRulesValueValidatorCompose() = runComposeUiTest {
setContent {
assertEquals(
expected = null, noRulesValueValidator.getValidationResultString(),
"format should be null"
)
assertEquals(
expected = null, noRulesValueValidator.supportingText(),
"supportingText should be null"
)
}
}

@Test
fun rulesValueValidator_notValidating() {
assertEquals(
expected = ValueValidator.InternalState.Initial,
ruleValueValidator.internalState,
"internalState should be Initial"
)
assertFalse(
ruleValueValidator.isValid,
"isValid should be false"
)
assertEquals(
expected = 1, ruleValueValidator.validationResults.size,
"Should have 1 validation results"
)
assertFalse(
ruleValueValidator.isError(),
"isError should be false"
)
assertNull(
ruleValueValidator.outcome(),
"outcome should be null"
)
}

@Test
fun rulesValueValidator_validating() {
ruleValueValidator.validate(value = null) // Start validating
assertEquals(
expected = ValueValidator.InternalState.Validating(),
ruleValueValidator.internalState,
"internalState should be Validating"
)
assertFalse(
ruleValueValidator.isValid,
"isValid should be false"
)
assertEquals(
expected = 1, ruleValueValidator.validationResults.size,
"Should have 1 validation results"
)
assertTrue(
ruleValueValidator.isError(),
"isError should be true"
)
assertEquals(
expected = ValidationResult.Outcome.ERROR,
ruleValueValidator.outcome(),
"outcome should be ERROR"
)
}

@Test
fun rulesValueValidator_valid() {
ruleValueValidator.validate(value = "Value") // Start validating
assertEquals(
expected = ValueValidator.InternalState.Validating(),
ruleValueValidator.internalState,
"internalState should be Validating"
)
assertTrue(
ruleValueValidator.isValid,
"isValid should be true"
)
assertEquals(
expected = 1, ruleValueValidator.validationResults.size,
"Should have 1 validation results"
)
assertFalse(
ruleValueValidator.isError(),
"isError should be false"
)
assertEquals(
expected = ValidationResult.Outcome.SUCCESS,
ruleValueValidator.outcome(),
"outcome should be SUCCESS"
)
}

@Test
@AndroidJUnitIgnore
@JSIgnore
fun rulesValueValidatorCompose_notValidating() = runComposeUiTest {
setContent {
assertEquals(
expected = stringResource(Res.string.ruleRequired),
ruleValueValidator.getValidationResultString(),
"getValidationResultString should be Required"
)
assertEquals(
expected = null, ruleValueValidator.supportingText(),
"supportingText should be null"
)
}
}

@Test
@AndroidJUnitIgnore
@JSIgnore
fun rulesValueValidatorCompose_validating() = runComposeUiTest {
ruleValueValidator.validate(value = null) // Start validating
setContent {
assertEquals(
expected = stringResource(Res.string.ruleRequired),
ruleValueValidator.getValidationResultString(),
"getValidationResultString should be Required"
)
assertNotNull(
ruleValueValidator.supportingText(),
"supportingText should not be null"
)
}
}

@Test
@AndroidJUnitIgnore
@JSIgnore
fun rulesValueValidatorCompose_success() = runComposeUiTest {
// Note, these might change as we want to support, alwaysShowRules, which means SUCCESS will
// need to return the rule message.
ruleValueValidator.validate(value = "Value") // Start validating
setContent {
assertNull(
ruleValueValidator.getValidationResultString(),
"getValidationResultString should be Required"
)
assertNull(
ruleValueValidator.supportingText(),
"supportingText should be null"
)
}
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.chrisjenx.yakcov

actual typealias IOSIgnore = kotlin.test.Ignore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class AndroidJUnitIgnore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class JSIgnore()

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.chrisjenx.yakcov

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class IOSIgnore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class AndroidJUnitIgnore

actual typealias JSIgnore = kotlin.test.Ignore

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.chrisjenx.yakcov

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class IOSIgnore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class AndroidJUnitIgnore

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class JSIgnore actual constructor()

This file was deleted.

Loading

0 comments on commit 4b26783

Please sign in to comment.