Skip to content

Commit

Permalink
Add value validation using lambdas
Browse files Browse the repository at this point in the history
  • Loading branch information
kevincianfarini committed Aug 6, 2019
1 parent 5d1a442 commit 7569159
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 1 deletion.
32 changes: 32 additions & 0 deletions krate/src/androidTest/java/hu/autsoft/krate/DefaultTests.kt
@@ -0,0 +1,32 @@
package hu.autsoft.krate

import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class DefaultTests {

private lateinit var testKrate: TestKrate

@Before
fun setup() {
val appContext = InstrumentationRegistry.getTargetContext()
testKrate = TestKrate(appContext)
}

@Test
fun testValidatedDefaultFloatDelegate() {
testKrate.defaultValidatedFloat = .67f

assertEquals(.67f, testKrate.defaultValidatedFloat)
}

@Test(expected = IllegalArgumentException::class)
fun testValidatedDefaultFloatDelegateThrowsException() {
testKrate.defaultValidatedFloat = 5.0f
}
}
14 changes: 14 additions & 0 deletions krate/src/androidTest/java/hu/autsoft/krate/OptionalTests.kt
Expand Up @@ -103,4 +103,18 @@ class OptionalTests {
assertEquals(null, testKrate.optionalStringSet)
}

@Test(expected = IllegalArgumentException::class)
fun testOptionalStringValidatedPrefFailsValidation() {
assertEquals(null, testKrate.optionalValidatedString)

testKrate.optionalValidatedString = "Lorem ipsum dolor sit amet"
}

@Test
fun testOptionalStringValidatedPassesValidation() {
assertEquals(null, testKrate.optionalValidatedString)

testKrate.optionalValidatedString = "Lorem"
}

}
6 changes: 6 additions & 0 deletions krate/src/androidTest/java/hu/autsoft/krate/TestKrate.kt
Expand Up @@ -14,5 +14,11 @@ class TestKrate(context: Context) : SimpleKrate(context) {
var optionalLong by longPref("optionalLong")
var optionalString by stringPref("optionalString")
var optionalStringSet by stringSetPref("optionalStringSet")
var optionalValidatedString by stringPref("validatedString") {
it?.length ?: 5 == 5
}
var defaultValidatedFloat by floatPref("defaultFloat", 0.0f) {
it > 0.0f && it < 1.0f
}

}
6 changes: 5 additions & 1 deletion krate/src/main/kotlin/hu/autsoft/krate/Functions.kt
Expand Up @@ -46,6 +46,10 @@ public fun Krate.longPref(key: String): ReadWriteProperty<Krate, Long?> {

/**
* Creates an optional preference of type String with the given [key] in this [Krate] instance.
*
* @param [key] the key to identify this value in SharedPreferences
*
* @return [StringDelegate]
*/
public fun Krate.stringPref(key: String): ReadWriteProperty<Krate, String?> {
return StringDelegate(key)
Expand Down Expand Up @@ -99,4 +103,4 @@ public fun Krate.stringPref(key: String, defaultValue: String): ReadWritePropert
*/
public fun Krate.stringSetPref(key: String, defaultValue: Set<String>): ReadWriteProperty<Krate, Set<String>> {
return StringSetDelegateWithDefault(key, defaultValue)
}
}
116 changes: 116 additions & 0 deletions krate/src/main/kotlin/hu/autsoft/krate/ValidatedFunctions.kt
@@ -0,0 +1,116 @@
@file:Suppress("RedundantVisibilityModifier")

package hu.autsoft.krate

import hu.autsoft.krate.validated.ValidatedPreferenceDelegate
import hu.autsoft.krate.default.FloatDelegateWithDefault
import hu.autsoft.krate.default.IntDelegateWithDefault
import hu.autsoft.krate.default.LongDelegateWithDefault
import hu.autsoft.krate.default.StringDelegateWithDefault
import hu.autsoft.krate.default.StringSetDelegateWithDefault
import hu.autsoft.krate.optional.FloatDelegate
import hu.autsoft.krate.optional.IntDelegate
import hu.autsoft.krate.optional.LongDelegate
import hu.autsoft.krate.optional.StringDelegate
import hu.autsoft.krate.optional.StringSetDelegate
import kotlin.properties.ReadWriteProperty

/**
* Creates a validated, optional preference of type [Float] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.floatPref(key: String, isValid: (Float?) -> Boolean): ReadWriteProperty<Krate, Float?> {
return ValidatedPreferenceDelegate(FloatDelegate(key), isValid)
}

/**
* Creates a validated, non-optional preference of type [Float] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.floatPref(key: String, default: Float, isValid: (Float) -> Boolean): ReadWriteProperty<Krate, Float> {
return ValidatedPreferenceDelegate(FloatDelegateWithDefault(key, default), isValid)
}

/**
* Creates a validated, optional preference of type [Int] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.intPref(key: String, isValid: (Int?) -> Boolean): ReadWriteProperty<Krate, Int?> {
return ValidatedPreferenceDelegate(IntDelegate(key), isValid)
}

/**
* Creates a validated, non-optional preference of type [Int] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.intPref(key: String, default: Int, isValid: (Int) -> Boolean): ReadWriteProperty<Krate, Int> {
return ValidatedPreferenceDelegate(IntDelegateWithDefault(key, default), isValid)
}

/**
* Creates a validated, optional preference of type [Long] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.longPref(key: String, isValid: (Long?) -> Boolean): ReadWriteProperty<Krate, Long?> {
return ValidatedPreferenceDelegate(LongDelegate(key), isValid)
}

/**
* Creates a validated, non-optional preference of type [Long] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.longPref(key: String, defaultValue: Long, isValid: (Long) -> Boolean): ReadWriteProperty<Krate, Long> {
return ValidatedPreferenceDelegate(LongDelegateWithDefault(key, defaultValue), isValid)
}

/**
* Creates a validated, optional preference of type [String] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.stringPref(key: String, isValid: (String?) -> Boolean): ReadWriteProperty<Krate, String?> {
return ValidatedPreferenceDelegate(StringDelegate(key), isValid)
}

/**
* Creates a validated, non-optional preference of type [String] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.stringPref(key: String, default: String, isValid: (String) -> Boolean): ReadWriteProperty<Krate, String> {
return ValidatedPreferenceDelegate(StringDelegateWithDefault(key, default), isValid)
}

/**
* Creates a validated, optional preference of type [Set] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.stringSetPref(key: String, isValid: (Set<String>?) -> Boolean): ReadWriteProperty<Krate, Set<String>?> {
return ValidatedPreferenceDelegate(StringSetDelegate(key), isValid)
}

/**
* Creates a validated, non-optional preference of type [Set] with the given [key].
*
* If a value being set to this preference returns `false` when checked by [isValid],
* an [IllegalArgumentException] will be thrown.
*/
public fun Krate.stringSetPref(key: String, defaultValue: Set<String>, isValid: (Set<String>) -> Boolean): ReadWriteProperty<Krate, Set<String>> {
return ValidatedPreferenceDelegate(StringSetDelegateWithDefault(key, defaultValue), isValid)
}
@@ -0,0 +1,27 @@
package hu.autsoft.krate.validated

import hu.autsoft.krate.Krate
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
* [ValidatedPreferenceDelegate] is a generic [ReadWriteProperty] that can be used to
* validate values that are being set.
*
* @param [delegate] the [ReadWriteProperty] implementation that is used for delegation
* @param [isValid] the lambda used to validate property values on [setValue]
*/
internal class ValidatedPreferenceDelegate<T>(
private val delegate: ReadWriteProperty<Krate, T>,
private val isValid: (T) -> Boolean
) : ReadWriteProperty<Krate, T> by delegate {

override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: T) {
if (!isValid(value)) {
throw IllegalArgumentException("$value is not valid for ${property.name}.")
}

delegate.setValue(thisRef, property, value)
}

}

0 comments on commit 7569159

Please sign in to comment.