From 247afd2867878ff67ea38634dc00a9be90810fa0 Mon Sep 17 00:00:00 2001 From: Artur Stepniewski <33253113+uniumuniu@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:17:39 +0200 Subject: [PATCH] Adjust codestyle (#6) --- build.gradle.kts | 9 + codestyle/codestyle.md | 231 +++++++++++++++++ codestyle/codestyles.xml | 154 ++++++++++++ codestyle/unitTestsStyle.md | 233 ++++++++++++++++++ .../kotlin/com/featurevisor/sdk/Conditions.kt | 6 +- .../com/featurevisor/sdk/MurmurHash3.kt | 20 +- .../kotlin/com/featurevisor/types/Types.kt | 68 ++--- .../kotlin/com/featurevisor/sdk/BucketTest.kt | 16 +- .../com/featurevisor/sdk/ConditionsTest.kt | 100 ++++---- .../com/featurevisor/sdk/LibraryTest.kt | 3 +- 10 files changed, 736 insertions(+), 104 deletions(-) create mode 100644 codestyle/codestyle.md create mode 100644 codestyle/codestyles.xml create mode 100644 codestyle/unitTestsStyle.md diff --git a/build.gradle.kts b/build.gradle.kts index 56aabf3..9f4da93 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,9 @@ * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.2.1/userguide/building_java_projects.html in the Gradle documentation. */ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent + plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. id("org.jetbrains.kotlin.jvm") version "1.8.20" @@ -66,4 +69,10 @@ java { tasks.named("test") { // Use JUnit Platform for unit tests. useJUnitPlatform() + // Log useful information when running tests. + testLogging { + exceptionFormat = TestExceptionFormat.FULL + events = setOf(TestLogEvent.SKIPPED, TestLogEvent.PASSED, TestLogEvent.FAILED) + showStandardStreams = true + } } diff --git a/codestyle/codestyle.md b/codestyle/codestyle.md new file mode 100644 index 0000000..dc3f690 --- /dev/null +++ b/codestyle/codestyle.md @@ -0,0 +1,231 @@ +# Code style + +Before writing your first line of code, please import `codestyles.xml` into your IDE settings from `docs/codestyles/codestyles.xml` + +--- + +## Add trailing comma when possible and makes sense + +**Note:** That makes Git history easier to traverse, adding comma to line before is not overriding this line Git history + +```kotlin +val someMap = mapOf( + "a" to "b", + "c" to "d", +) + +class GreatClass( + val fieldA: String, + val fieldB: String, +) +``` + +--- + +## Don't explicitly define a type when it's not required + +```kotlin +// 🔴 don't +val someVariable: String = "asd" + +// 🟢 do +val someVariable = "asd" +``` + +**Note:** If you are still missing explicit type definition, consider enabling `Type Hints` in Android Studio, IDE will add them automatically. + +--- + +## Empty statements or lambdas + +We want to make sure that empty or blank statements are not left there by accident, that's why you need to use `doNothing()` function from `com.dazn.extensions` for marking it as intentionally empty. + +```kotlin +when (x) { + VALUE_1 -> println("1") + VALUE_2 -> println("2") + else -> doNothing() +} +``` + +```kotlin +executeMethodWithCallbacks( + success = { view.showSomething() }, + error = { doNothing() } +) +``` + +--- + +## Functions and its parameters + +### When function only returns something, remove it's body + +```kotlin +// 🔴 don't +fun returnNumber(): Int { + return 2137 +} + +// 🟢 do +fun returnNumber() = 2137 +``` + +### When function only returns something and it has a long call inside, break it with new lines + +```kotlin +// 🔴 don't +fun returnSomething() = thisIsVeryImportantVariableNameBecauseItsNameIsLong.andThisIsVeryImportantMethodName(thisLooksLikeAnImportantParameter) + +// 🟢 do +fun returnSomething() = + thisIsVeryImportantVariableNameBecauseItsNameIsLong.andThisIsVeryImportantMethodName(thisLooksLikeAnImportantParameter) + +// 🟢 do +fun returnSomething() = + thisIsVeryImportantVariableNameBecauseItsNameIsLong.andThisIsVeryImportantMethodName( + thisLooksLikeAnImportantParameter, + ohNoThisMethodHasAnotherParameter, + ) +``` + +### Underscore unused parameters + +```kotlin +// 🔴 don't +val function: (Int, Long, Double) -> Unit = { someInt, someLong, someDouble -> println("") } + +// 🟢 do +val function: (Int, Long, Double) -> Unit = { _, _, _ -> println("") } +``` + +### When function definition is starting to be unreadable, put parameters in separate lines + +```kotlin +// 🔴 don't +fun someFunction(parameterA: ParameterOfTypeA, parameterB: ParameterOfTypeB, parameterC: ParameterOfTypeC, parameterD: ParameterOfTypeD) + +// 🟢 do +fun someFunction( + parameterA: ParameterOfTypeA, + parameterB: ParameterOfTypeB, + parameterC: ParameterOfTypeC, + parameterD: ParameterOfTypeD, +) +``` + +### When function contains a large mix of string and non standard classes, consider adding explicit param names + +```kotlin +// 🔴 don't +someFunction( + "a", + CustomObject(), + "b", + "c" +) + +// 🟢 do +someFunction( + parameterA = "a", + customObject = CustomObject(), + parameterB = "b", + parameterC = "c", +) +``` + +### When there is need to use line separator, use system provided one + +```kotlin +// 🔴 don't +listOf("hello", "world").joinToString(separator = "\n") + +// 🟢 do +listOf("hello", "world").joinToString(separator = System.lineSeparator()) +``` + +--- + +## Enums + +### Short enums + +```kotlin +enum class ShortEnum { + VALUE_1, + VALUE_2, + VALUE_3, +} +``` + +### Enums with value + +```kotlin +enum class EnumWithValue(val value: String) { + VALUE_1("value1"), + VALUE_2("value2"), + VALUE_3("value3"), +} +``` + +### Enums with value and method + +**Note:** Semicolon in new line, between enum entries and body + +```kotlin +enum class EnumWithValueAndMethod(val value: String) { + VALUE_1("value1"), + VALUE_2("value2"), + VALUE_3("value3"), + ; + + companion object { + fun fromString(string: String) = values().firstOrNull { it.value == string } + } +} +``` + +--- + +## Annotations + +### For parameters keep annotations in the same line + +```kotlin +data class SomeClass( + @SerializedName("field1") val field1: String, + @SerializedName("field2") val field2: String?, +) +``` + +### For methods, fields and classes keep them in new line + +```kotlin +@AnnotationForClass +class SomeClass constructor( + @FieldAnnotation private val field1 +) { + + @FieldAnnotation + val field2: String + + @AnnotationForMethod + fun annotatedMethod() { + doNothing() + } +} +``` + +### In other cases refer to Official Kotlin Style Guide + +[Google Kotlin Style Guide](https://android.github.io/kotlin-guides/style.html) + +### Don't use Hungarian notation, if it's still on your mind for some reason + +[Just Say mNo to Hungarian Notation (Jake Wharton)](http://jakewharton.com/just-say-no-to-hungarian-notation/) + +### RxJava/Stream chains + +Those can get pretty ugly sometimes. + +If possible, avoid deep nesting in RxJava/Stream chains. Instead, try to refactor operator arguments into separate methods. A good rule of thumb for clean and readable chains: **one line = one operator**. \ No newline at end of file diff --git a/codestyle/codestyles.xml b/codestyle/codestyles.xml new file mode 100644 index 0000000..bb569ec --- /dev/null +++ b/codestyle/codestyles.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/codestyle/unitTestsStyle.md b/codestyle/unitTestsStyle.md new file mode 100644 index 0000000..83e2a05 --- /dev/null +++ b/codestyle/unitTestsStyle.md @@ -0,0 +1,233 @@ +# Unit tests + +### Naming convention + +```kotlin +val systemUnderTest = ClassToTest() +``` + +### Assertions + +Always use AssertJ framework for assertions, always import it on class level. + +```kotlin +import org.assertj.core.api.Assertions.assertThat +``` + +```kotlin +// 🔴 don't +Assertions.assertThat(value).isEqualTo("expected") + +// 🟢 do +assertThat(value).isEqualTo("expected") +``` + +### Instance mocking + +```kotlin +private val mockDependency: Dependecy = mock { + on { shouldShowSomethingElse() } doReturn false +} + +private val mockView: View = mock() +private val spyInstance = spy(ObjectInstance()) + +//optional newline for better readability +private val mockSecondDependency: SecondDependecy = mock() +``` + +**Note:** Don't use `mock()`, define type explicitly for variable + +### Before/After + +```kotlin +@Before +fun setUp() { + systemUnderTest.attachView(mockView) +} +``` + +**Note:** Use `@Before` when needed + +**Note:** Keep method name autogenerated (Android Studio creates `setUp()` method), because we are lazy + +### Test methods naming + +Contain test method in backticks for improved readability. + +```kotlin +@Test +fun `show dialog on error`() { + systemUnderTest.showError() + + verify(mockView).showError() +} + +``` + +**Note:** Use plural form instead of singular (in this case use `show` instead of `shows`) + +### Visual given/when/then separation + +```kotlin +@Test +fun `show dialog on error`() { + systemUnderTest.attachView(mockView) + + systemUnderTest.showError() + + verify(mockView).showError() +} +``` + +### Preferred verification methods + +From most preferred to least preferred + +```kotlin +@Test +fun `show dialog on error`() { + val expectedValue = "text here" + + systemUnderTest.showError() + + verify(mockView).showErrorText(expectedValue) + verify(mockView).showErrorText(eq(expectedValue), any()) + verify(mockView).showErrorText(eq(expectedValue), argThat(it.hasSomeValue)) + argumentCaptor().apply { + verify(mockView).showErrorText(eq(expectedValue), capture()) + firstValue.invoke() + + //some assertion depending on the firstValue.invoke() call + } +} +``` + +### Verify other possible interactions + +```kotlin +@Test +fun `don't show error`() { + whenever(mockDependency.shouldShowError()).thenReturn(false) + + systemUnderTest.showError() + + verifyNoInteractions() //if makes sense, but be cautious + verify(mockView, never()).showError() + verifyNoMoreInteractions() //if makes sense +} +``` + +### Verify repeated interactions + +```kotlin +@Test +fun `show error two times`() { + systemUnderTest.showError() + systemUnderTest.showError() + + verify(mockView, times(2)).showError() +} +``` + +### Nice asserts for rx observables + +```kotlin +@Test +fun `token is set multiple times`() { + val observable = systemUnderTest.getLoginData().test() + + observable + .assertValue { it.token == expectedData.token } + .assertValueAt(2) { it.token == "token1" } + .assertValueAt(3) { it.token == "token2" } + .assertValueAt(4) { it.token == "token3" } +} +``` + +### Locale sensitive unit tests + +It's not guaranteed that on developer machines the same locale is set. Because of that we need to enforce specific locale to be sure that expected string values are matching. + +```kotlin +@get:Rule +val defaultLocaleRule = SetLocaleRule(Locale.ENGLISH) +``` + +### Mocking Android SDK classes + +If subject of the unit test requires or uses inside some native Android SDK classes, annotate test with following annotation: + +```kotlin +@RunWith(AndroidJUnit4::class) +@Config(manifest = Config.NONE, application = TestApplication::class) +class SomeClassTest { +``` + +### Use parameterized test when it makes sense + +```kotlin +@RunWith(Parameterized::class) +class ConvertBytesToMegaBytesTest( + private val bytes: Long, + private val expectedMegabytes: Int, +) { + + val systemUnderTest = Object() + + companion object { + @JvmStatic + @Parameterized.Parameters + fun data(): List> = + listOf( + arrayOf(1024000, 1), + arrayOf(2048000, 2), + arrayOf(4096000, 4), + arrayOf(8192000, 8) + ) + } + + @Test + fun `check if conversion works as expected`() { + val outputFormat = systemUnderTest.convertBytesToMegaBytes(bytes) + + assertThat(outputFormat).isEqualTo(expectedMegabytes) + } +} +``` + +**Note:** Consider wrapping test variables into something more readable, especially when there is a lot of them + +```kotlin +@RunWith(Parameterized::class) +class FollowParameterizedServiceTest( + private val parameters: Parameters, +) { + + companion object { + @JvmStatic + @Parameterized.Parameters(name = "{0}") + fun data(): Collection> = listOf( + Parameters(signedUpDaysAgo = NOW.minusDays(0L), daysDelayVariable = 0L, hasSeenOnboardingBefore = true, isOnboardingVisible = false).build(), + Parameters(signedUpDaysAgo = NOW.minusDays(1L), daysDelayVariable = 0L, hasSeenOnboardingBefore = true, isOnboardingVisible = false).build(), + //a lot more + ) + } + + val systemUnderTest = Object() + + @Test + fun `verify`() { + //assert + } + + data class Parameters( + val signedUpDaysAgo: LocalDateTime?, + val daysDelayVariable: Long, + val hasSeenOnboardingBefore: Boolean, + val isOnboardingVisible: Boolean, + ) { + fun build() = arrayOf(this) + } +} +``` diff --git a/src/main/kotlin/com/featurevisor/sdk/Conditions.kt b/src/main/kotlin/com/featurevisor/sdk/Conditions.kt index 5a0f9a5..5c1b507 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Conditions.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Conditions.kt @@ -22,9 +22,11 @@ object Conditions { Operator.notEquals -> return contextValue.value != conditionValue.value Operator.contains -> return contextValue.value.contains(conditionValue.value) Operator.notContains -> - return !contextValue.value.contains(conditionValue.value) + return !contextValue.value.contains(conditionValue.value) + Operator.startsWith -> - return contextValue.value.startsWith(conditionValue.value) + return contextValue.value.startsWith(conditionValue.value) + Operator.endsWith -> return contextValue.value.endsWith(conditionValue.value) else -> return false } diff --git a/src/main/kotlin/com/featurevisor/sdk/MurmurHash3.kt b/src/main/kotlin/com/featurevisor/sdk/MurmurHash3.kt index 443fac2..cf7c2cf 100644 --- a/src/main/kotlin/com/featurevisor/sdk/MurmurHash3.kt +++ b/src/main/kotlin/com/featurevisor/sdk/MurmurHash3.kt @@ -63,20 +63,20 @@ public class MurmurHash3(private val seed: UInt = 1.toUInt()) { private fun ByteArray.getLittleEndianUInt(index: Int): UInt { return this.getUInt(index) or - (this.getUInt(index + 1) shl 8) or - (this.getUInt(index + 2) shl 16) or - (this.getUInt(index + 3) shl 24) + (this.getUInt(index + 1) shl 8) or + (this.getUInt(index + 2) shl 16) or + (this.getUInt(index + 3) shl 24) } private fun ByteArray.getLittleEndianLong(index: Int): ULong { return this.getULong(index) or - (this.getULong(index + 1) shl 8) or - (this.getULong(index + 2) shl 16) or - (this.getULong(index + 3) shl 24) or - (this.getULong(index + 4) shl 32) or - (this.getULong(index + 5) shl 40) or - (this.getULong(index + 6) shl 48) or - (this.getULong(index + 7) shl 56) + (this.getULong(index + 1) shl 8) or + (this.getULong(index + 2) shl 16) or + (this.getULong(index + 3) shl 24) or + (this.getULong(index + 4) shl 32) or + (this.getULong(index + 5) shl 40) or + (this.getULong(index + 6) shl 48) or + (this.getULong(index + 7) shl 56) } private fun UInt.mix(r: Int, c1: UInt, c2: UInt): UInt { diff --git a/src/main/kotlin/com/featurevisor/types/Types.kt b/src/main/kotlin/com/featurevisor/types/Types.kt index 8707a6a..c641b51 100644 --- a/src/main/kotlin/com/featurevisor/types/Types.kt +++ b/src/main/kotlin/com/featurevisor/types/Types.kt @@ -7,6 +7,7 @@ sealed class AttributeValue { data class IntValue(val value: Int) : AttributeValue() data class DoubleValue(val value: Double) : AttributeValue() data class BooleanValue(val value: Boolean) : AttributeValue() + // @TODO: implement Date object NullValue : AttributeValue() } @@ -17,7 +18,7 @@ data class Attribute( val key: AttributeKey, val type: String, val archived: Boolean?, - val capture: Boolean? + val capture: Boolean?, ) enum class Operator(val value: String) { @@ -59,6 +60,7 @@ sealed class ConditionValue { data class DoubleValue(val value: Double) : ConditionValue() data class BooleanValue(val value: Boolean) : ConditionValue() data class ArrayValue(val values: Array) : ConditionValue() + // @TODO: implement Date object NullValue : ConditionValue() } @@ -66,19 +68,19 @@ sealed class ConditionValue { data class PlainCondition( val attribute: AttributeKey, val operator: Operator, - val value: ConditionValue + val value: ConditionValue, ) data class AndCondition( - val and: Array + val and: Array, ) data class OrCondition( - val or: Array + val or: Array, ) data class NotCondition( - val not: Array + val not: Array, ) sealed class Condition { @@ -95,21 +97,21 @@ typealias SegmentKey = String data class Segment( val archived: Boolean?, val key: SegmentKey, - val conditions: Condition + val conditions: Condition, ) typealias PlainGroupSegment = SegmentKey data class AndGroupSegment( - val and: Array + val and: Array, ) data class OrGroupSegment( - val or: Array + val or: Array, ) data class NotGroupSegment( - val not: Array + val not: Array, ) sealed class GroupSegment { @@ -152,13 +154,13 @@ data class VariableOverride( // one of the below must be present in YAML val conditions: Condition?, - val segments: GroupSegment? + val segments: GroupSegment?, ) data class Variable( val key: VariableKey, val value: VariableValue, - val overrides: Array? + val overrides: Array?, ) data class Variation( @@ -170,13 +172,13 @@ data class Variation( // 0 to 100 (available from parsed YAML, but not in datafile) val weight: Double?, - val variables: Array? + val variables: Array?, ) data class VariableSchema( val key: VariableKey, val type: VariableType, - val defaultValue: VariableValue + val defaultValue: VariableValue, ) typealias FeatureKey = String @@ -190,7 +192,7 @@ data class Force( val enabled: Boolean?, val variation: VariationValue?, - val variables: VariableValues? + val variables: VariableValues?, ) data class Slot( @@ -198,13 +200,13 @@ data class Slot( val feature: FeatureKey?, // 0 to 100 - val percentage: Weight + val percentage: Weight, ) data class Group( val key: String, val description: String, - val slots: Array + val slots: Array, ) typealias BucketKey = String @@ -220,12 +222,12 @@ typealias Percentage = Int data class Range( val start: Percentage, - val end: Percentage + val end: Percentage, ) data class Allocation( val variation: VariationValue, - val range: Range + val range: Range, ) data class Traffic( @@ -237,7 +239,7 @@ data class Traffic( val variation: VariationValue?, val variables: VariableValues?, - val allocation: Array + val allocation: Array, ) typealias PlainBucketBy = String @@ -245,7 +247,7 @@ typealias PlainBucketBy = String typealias AndBucketBy = Array data class OrBucketBy( - val or: Array + val or: Array, ) sealed class BucketBy { @@ -256,7 +258,7 @@ sealed class BucketBy { data class RequiredWithVariation( val key: FeatureKey, - val variation: VariationValue + val variation: VariationValue, ) sealed class Required { @@ -275,7 +277,7 @@ data class Feature( val force: Array?, // if in a Group (mutex), these are available slot ranges - val ranges: Array? + val ranges: Array?, ) data class DatafileContent( @@ -283,13 +285,13 @@ data class DatafileContent( val revision: String, val attributes: Array, val segments: Array, - val features: Array + val features: Array, ) data class OverrideFeature( val enabled: Boolean, val variation: VariationValue?, - val variables: VariableValues? + val variables: VariableValues?, ) typealias StickyFeatures = Map @@ -313,13 +315,13 @@ data class Rule( val enabled: Boolean?, val variation: VariationValue?, - val variables: VariableValues? + val variables: VariableValues?, ) data class Environment( val expose: Boolean?, val rules: Array, - val force: Array? + val force: Array?, ) typealias Environments = Map @@ -340,7 +342,7 @@ data class ParsedFeature( val variablesSchema: Array?, val variations: Array?, - val environments: Environments + val environments: Environments, ) /** @@ -353,23 +355,23 @@ data class FeatureAssertion( val context: Context, val expectedToBeEnabled: Boolean, val expectedVariation: VariationValue?, - val expectedVariables: VariableValues? + val expectedVariables: VariableValues?, ) data class TestFeature( val key: FeatureKey, - val assertions: Array + val assertions: Array, ) data class SegmentAssertion( val description: String?, val context: Context, - val expectedToMatch: Boolean + val expectedToMatch: Boolean, ) data class TestSegment( val key: SegmentKey, - val assertions: Array + val assertions: Array, ) data class Test( @@ -381,9 +383,9 @@ data class Test( val features: Array?, // needed for segment testing - val segments: Array? + val segments: Array?, ) data class Spec( - val tests: Array + val tests: Array, ) diff --git a/src/test/kotlin/com/featurevisor/sdk/BucketTest.kt b/src/test/kotlin/com/featurevisor/sdk/BucketTest.kt index 7b5d10f..4c89378 100644 --- a/src/test/kotlin/com/featurevisor/sdk/BucketTest.kt +++ b/src/test/kotlin/com/featurevisor/sdk/BucketTest.kt @@ -8,14 +8,14 @@ class BucketTest { fun getBucketedNumberReturnsExpectedValues() { val expectedResults = - mapOf( - "foo" to 20602, - "bar" to 89144, - "123.foo" to 3151, - "123.bar" to 9710, - "123.456.foo" to 14432, - "123.456.bar" to 1982 - ) + mapOf( + "foo" to 20602, + "bar" to 89144, + "123.foo" to 3151, + "123.bar" to 9710, + "123.456.foo" to 14432, + "123.456.bar" to 1982 + ) for ((key, value) in expectedResults) { val result = Bucket.getBucketedNumber(key) diff --git a/src/test/kotlin/com/featurevisor/sdk/ConditionsTest.kt b/src/test/kotlin/com/featurevisor/sdk/ConditionsTest.kt index 12e452a..0d50adc 100644 --- a/src/test/kotlin/com/featurevisor/sdk/ConditionsTest.kt +++ b/src/test/kotlin/com/featurevisor/sdk/ConditionsTest.kt @@ -11,56 +11,56 @@ class ConditionsTest { @Test fun testEqualsOperatorForStrings() { val condition = - PlainCondition( - "browser_type", - Operator.equals, - ConditionValue.StringValue("chrome") - ) + PlainCondition( + "browser_type", + Operator.equals, + ConditionValue.StringValue("chrome") + ) // match assertEquals( - true, - Conditions.conditionIsMatched( - condition, - mapOf("browser_type" to AttributeValue.StringValue("chrome")) - ) + true, + Conditions.conditionIsMatched( + condition, + mapOf("browser_type" to AttributeValue.StringValue("chrome")) + ) ) // not match assertEquals( - false, - Conditions.conditionIsMatched( - condition, - mapOf("browser_type" to AttributeValue.StringValue("firefox")) - ) + false, + Conditions.conditionIsMatched( + condition, + mapOf("browser_type" to AttributeValue.StringValue("firefox")) + ) ) } @Test fun testNotEqualsOperatorForStrings() { val condition = - PlainCondition( - "browser_type", - Operator.notEquals, - ConditionValue.StringValue("chrome") - ) + PlainCondition( + "browser_type", + Operator.notEquals, + ConditionValue.StringValue("chrome") + ) // match assertEquals( - true, - Conditions.conditionIsMatched( - condition, - mapOf("browser_type" to AttributeValue.StringValue("firefox")) - ) + true, + Conditions.conditionIsMatched( + condition, + mapOf("browser_type" to AttributeValue.StringValue("firefox")) + ) ) // not match assertEquals( - false, - Conditions.conditionIsMatched( - condition, - mapOf("browser_type" to AttributeValue.StringValue("chrome")) - ) + false, + Conditions.conditionIsMatched( + condition, + mapOf("browser_type" to AttributeValue.StringValue("chrome")) + ) ) } @@ -70,20 +70,20 @@ class ConditionsTest { // match assertEquals( - true, - Conditions.conditionIsMatched( - condition, - mapOf("age" to AttributeValue.IntValue(19)) - ) + true, + Conditions.conditionIsMatched( + condition, + mapOf("age" to AttributeValue.IntValue(19)) + ) ) // not match assertEquals( - false, - Conditions.conditionIsMatched( - condition, - mapOf("age" to AttributeValue.IntValue(17)) - ) + false, + Conditions.conditionIsMatched( + condition, + mapOf("age" to AttributeValue.IntValue(17)) + ) ) } @@ -93,20 +93,20 @@ class ConditionsTest { // match assertEquals( - true, - Conditions.conditionIsMatched( - condition, - mapOf("age" to AttributeValue.IntValue(17)) - ) + true, + Conditions.conditionIsMatched( + condition, + mapOf("age" to AttributeValue.IntValue(17)) + ) ) // not match assertEquals( - false, - Conditions.conditionIsMatched( - condition, - mapOf("age" to AttributeValue.IntValue(19)) - ) + false, + Conditions.conditionIsMatched( + condition, + mapOf("age" to AttributeValue.IntValue(19)) + ) ) } } diff --git a/src/test/kotlin/com/featurevisor/sdk/LibraryTest.kt b/src/test/kotlin/com/featurevisor/sdk/LibraryTest.kt index 6353133..1424f81 100644 --- a/src/test/kotlin/com/featurevisor/sdk/LibraryTest.kt +++ b/src/test/kotlin/com/featurevisor/sdk/LibraryTest.kt @@ -7,7 +7,8 @@ import kotlin.test.Test import kotlin.test.assertTrue class LibraryTest { - @Test fun someLibraryMethodReturnsTrue() { + @Test + fun someLibraryMethodReturnsTrue() { val classUnderTest = Library() assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'") }