diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/CraftDSimplePropertiesDiffCallbackTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/CraftDSimplePropertiesDiffCallbackTest.kt new file mode 100644 index 0000000..50dc913 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/CraftDSimplePropertiesDiffCallbackTest.kt @@ -0,0 +1,365 @@ +package com.github.codandotv.craftd.androidcore + +import androidx.recyclerview.widget.DiffUtil +import com.github.codandotv.craftd.androidcore.data.model.base.SimpleProperties +import io.mockk.mockk +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import java.util.AbstractMap +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class CraftDSimplePropertiesDiffCallbackTest { + + private lateinit var callback: DiffUtil.ItemCallback + + @Before + fun setup() { + callback = CraftDSimplePropertiesItemCallback + } + + inner class SimplePropertiesTests { + + @Test + fun `given SimpleProperties when created with all params then initializes correctly`() { + val key = "testKey" + val value = JsonPrimitive("testValue") + val properties = SimpleProperties(key = key, value = value) + + assertEquals(key, properties.key) + assertEquals(value, properties.value) + } + + @Test + fun `given SimpleProperties when created with null value then initializes correctly`() { + val key = "testKey" + val properties = SimpleProperties(key = key, value = null) + + assertEquals(key, properties.key) + assertEquals(null, properties.value) + } + + @Test + fun `given SimpleProperties when copy is called then returns new instance with updated fields`() { + val original = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val copied = original.copy(key = "key2", value = JsonPrimitive("value2")) + + assertEquals("key2", copied.key) + assertEquals(JsonPrimitive("value2"), copied.value) + assertEquals("key1", original.key) + } + + @Test + fun `given SimpleProperties when copy is called with partial params then preserves original fields`() { + val value = JsonPrimitive("original") + val original = SimpleProperties(key = "key1", value = value) + val copied = original.copy(key = "key2") + + assertEquals("key2", copied.key) + assertEquals(value, copied.value) + } + + @Test + fun `given two SimpleProperties with same key and value when equals is called then returns true`() { + val props1 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val props2 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + + assertTrue(props1 == props2) + } + + @Test + fun `given two SimpleProperties with different keys when equals is called then returns false`() { + val props1 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val props2 = SimpleProperties(key = "key2", value = JsonPrimitive("value1")) + + assertFalse(props1 == props2) + } + + @Test + fun `given two SimpleProperties with different values when equals is called then returns false`() { + val props1 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val props2 = SimpleProperties(key = "key1", value = JsonPrimitive("value2")) + + assertFalse(props1 == props2) + } + + @Test + fun `given SimpleProperties with null value when equals is called then handles null correctly`() { + val props1 = SimpleProperties(key = "key1", value = null) + val props2 = SimpleProperties(key = "key1", value = null) + + assertTrue(props1 == props2) + } + + @Test + fun `given SimpleProperties when hashCode is called then returns consistent value`() { + val props1 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val props2 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + + assertEquals(props1.hashCode(), props2.hashCode()) + } + + @Test + fun `given SimpleProperties when toString is called then returns string representation`() { + val props = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val stringRep = props.toString() + + assertTrue(stringRep.contains("key1")) + } + } + + inner class AreItemsTheSameTests { + + @Test + fun `given same key when areItemsTheSame then returns true`() { + val oldItem = SimpleProperties(key = "sameKey", value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = "sameKey", value = JsonPrimitive("value2")) + + assertTrue(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given different keys when areItemsTheSame then returns false`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive("value1")) + + assertFalse(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given null values when areItemsTheSame then returns true for same null key`() { + val oldItem = SimpleProperties(key = "key1", value = null) + val newItem = SimpleProperties(key = "key1", value = null) + + assertTrue(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given exception during comparison when areItemsTheSame then returns false`() { + val oldItem = mockk() + val newItem = mockk() + + io.mockk.every { oldItem.key } throws RuntimeException("Test exception") + + assertFalse(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given empty keys when areItemsTheSame then returns true for matching empty keys`() { + val oldItem = SimpleProperties(key = "", value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = "", value = JsonPrimitive("value2")) + + assertTrue(callback.areItemsTheSame(oldItem, newItem)) + } + } + + inner class AreContentsTheSameTests { + + @Test + fun `given same JsonPrimitive value when areContentsTheSame then returns true`() { + val value = JsonPrimitive("sameValue") + val oldItem = SimpleProperties(key = "key1", value = value) + val newItem = SimpleProperties(key = "key2", value = value) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given different JsonPrimitive values when areContentsTheSame then returns false`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = "key1", value = JsonPrimitive("value2")) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given same AbstractMap values when areContentsTheSame then returns true`() { + val map1 = linkedMapOf("key" to "value") + val map2 = linkedMapOf("key" to "value") + val oldItem = SimpleProperties(key = "key1", value = map1 as JsonElement) + val newItem = SimpleProperties(key = "key2", value = map2 as JsonElement) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given different AbstractMap values when areContentsTheSame then returns false`() { + val map1 = linkedMapOf("key" to "value1") + val map2 = linkedMapOf("key" to "value2") + val oldItem = SimpleProperties(key = "key1", value = map1 as JsonElement) + val newItem = SimpleProperties(key = "key2", value = map2 as JsonElement) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given null values when areContentsTheSame then returns true`() { + val oldItem = SimpleProperties(key = "key1", value = null) + val newItem = SimpleProperties(key = "key2", value = null) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given one null and one non-null value when areContentsTheSame then returns false`() { + val oldItem = SimpleProperties(key = "key1", value = null) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive("value")) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given JsonObject values when areContentsTheSame then returns true for identical objects`() { + val jsonObj1 = buildJsonObject { put("key", "value") } + val jsonObj2 = buildJsonObject { put("key", "value") } + val oldItem = SimpleProperties(key = "key1", value = jsonObj1) + val newItem = SimpleProperties(key = "key2", value = jsonObj2) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given JsonObject values when areContentsTheSame then returns false for different objects`() { + val jsonObj1 = buildJsonObject { put("key", "value1") } + val jsonObj2 = buildJsonObject { put("key", "value2") } + val oldItem = SimpleProperties(key = "key1", value = jsonObj1) + val newItem = SimpleProperties(key = "key2", value = jsonObj2) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given numeric JsonPrimitive values when areContentsTheSame then returns true for same number`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive(42)) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive(42)) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given numeric JsonPrimitive values when areContentsTheSame then returns false for different numbers`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive(42)) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive(43)) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given boolean JsonPrimitive values when areContentsTheSame then returns true for same boolean`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive(true)) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive(true)) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given boolean JsonPrimitive values when areContentsTheSame then returns false for different booleans`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive(true)) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive(false)) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given empty AbstractMap values when areContentsTheSame then returns true`() { + val map1 = linkedMapOf() + val map2 = linkedMapOf() + val oldItem = SimpleProperties(key = "key1", value = map1 as JsonElement) + val newItem = SimpleProperties(key = "key2", value = map2 as JsonElement) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given AbstractMap and JsonObject when areContentsTheSame then compares correctly`() { + val map = linkedMapOf("key" to "value") + val jsonObj = buildJsonObject { put("key", "value") } + val oldItem = SimpleProperties(key = "key1", value = map as JsonElement) + val newItem = SimpleProperties(key = "key2", value = jsonObj) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + } + + inner class CallbackObjectTests { + + @Test + fun `given CraftDSimplePropertiesItemCallback when accessed then is singleton instance`() { + val instance1 = CraftDSimplePropertiesItemCallback + val instance2 = CraftDSimplePropertiesItemCallback + + assertTrue(instance1 === instance2) + } + + @Test + fun `given CraftDSimplePropertiesItemCallback when cast to ItemCallback then implements interface correctly`() { + val callback: DiffUtil.ItemCallback = CraftDSimplePropertiesItemCallback + + assertTrue(callback is DiffUtil.ItemCallback<*>) + } + } + + inner class EdgeCaseTests { + + @Test + fun `given very long keys when areItemsTheSame then compares correctly`() { + val longKey = "k".repeat(10000) + val oldItem = SimpleProperties(key = longKey, value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = longKey, value = JsonPrimitive("value2")) + + assertTrue(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given special characters in key when areItemsTheSame then compares correctly`() { + val specialKey = "key!@#$%^&*()" + val oldItem = SimpleProperties(key = specialKey, value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = specialKey, value = JsonPrimitive("value2")) + + assertTrue(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given unicode characters in value when areContentsTheSame then compares correctly`() { + val oldItem = SimpleProperties(key = "key1", value = JsonPrimitive("值")) + val newItem = SimpleProperties(key = "key2", value = JsonPrimitive("値")) + + assertFalse(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given whitespace in key when areItemsTheSame then compares correctly`() { + val keyWithSpace = "key with spaces" + val oldItem = SimpleProperties(key = keyWithSpace, value = JsonPrimitive("value1")) + val newItem = SimpleProperties(key = keyWithSpace, value = JsonPrimitive("value2")) + + assertTrue(callback.areItemsTheSame(oldItem, newItem)) + } + + @Test + fun `given nested JsonObject when areContentsTheSame then compares correctly`() { + val nested1 = buildJsonObject { + put("outer", buildJsonObject { put("inner", "value") }) + } + val nested2 = buildJsonObject { + put("outer", buildJsonObject { put("inner", "value") }) + } + val oldItem = SimpleProperties(key = "key1", value = nested1) + val newItem = SimpleProperties(key = "key2", value = nested2) + + assertTrue(callback.areContentsTheSame(oldItem, newItem)) + } + + @Test + fun `given nested JsonObject with different inner values when areContentsTheSame then returns false`() { + val nested1 = buildJsonObject { + put("outer", buildJsonObject { put(" \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/ViewMapperTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/ViewMapperTest.kt new file mode 100644 index 0000000..1d02c63 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/ViewMapperTest.kt @@ -0,0 +1,197 @@ +package com.github.codandotv.craftd.androidcore.data + +import io.mockk.junit4.MockKRule +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import kotlinx.serialization.json.putJsonObject +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertNull +import com.github.codandotv.craftd.androidcore.data.model.base.SimpleProperties +import com.github.codandotv.craftd.androidcore.data.model.base.SimplePropertiesResponse + +@RunWith(JUnit4::class) +class ViewMapperTest { + @get:Rule + val mockkRule = MockKRule(this) + + data class TestSerializableClass( + val name: String, + val age: Int + ) + + @Test + fun `given null JsonElement when convertToElement then returns null`() { + val result: TestSerializableClass? = null.convertToElement() + assertNull(result) + } + + @Test + fun `given valid JsonElement when convertToElement then returns deserialized object`() { + val jsonElement = buildJsonObject { + put("name", "John") + put("age", 30) + } + val result: TestSerializableClass? = jsonElement.convertToElement() + assertEquals("John", result?.name) + assertEquals(30, result?.age) + } + + @Test + fun `given JsonElement with extra unknown keys when convertToElement then returns deserialized object ignoring unknown keys`() { + val jsonElement = buildJsonObject { + put("name", "Jane") + put("age", 25) + put("unknownKey", "unknownValue") + } + val result: TestSerializableClass? = jsonElement.convertToElement() + assertEquals("Jane", result?.name) + assertEquals(25, result?.age) + } + + @Test + fun `given malformed JsonElement when convertToElement then returns null`() { + val jsonElement = JsonPrimitive("invalid") + val result: TestSerializableClass? = jsonElement.convertToElement() + assertNull(result) + } + + @Test + fun `given JsonElement with wrong type when convertToElement then returns null`() { + val jsonElement = buildJsonObject { + put("name", "Test") + put("age", "notAnInt") + } + val result: TestSerializableClass? = jsonElement.convertToElement() + assertNull(result) + } + + @Test + fun `given JsonNull when convertToElement then returns null`() { + val result: TestSerializableClass? = JsonNull.convertToElement() + assertNull(result) + } + + @Test + fun `given empty list when toListSimpleProperties then returns empty list`() { + val input: List = emptyList() + val result = input.toListSimpleProperties() + assertEquals(0, result.size) + } + + @Test + fun `given list with single item when toListSimpleProperties then returns mapped list with one element`() { + val input = listOf( + SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + ) + val result = input.toListSimpleProperties() + assertEquals(1, result.size) + assertEquals("key1", result[0].key) + assertEquals(JsonPrimitive("value1"), result[0].value) + } + + @Test + fun `given list with multiple items when toListSimpleProperties then returns mapped list`() { + val input = listOf( + SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")), + SimplePropertiesResponse(key = "key2", value = JsonPrimitive("value2")), + SimplePropertiesResponse(key = "key3", value = JsonPrimitive("value3")) + ) + val result = input.toListSimpleProperties() + assertEquals(3, result.size) + assertEquals("key1", result[0].key) + assertEquals("key2", result[1].key) + assertEquals("key3", result[2].key) + } + + @Test + fun `given list with null values when toListSimpleProperties then returns mapped list with null values`() { + val input = listOf( + SimplePropertiesResponse(key = "key1", value = JsonNull), + SimplePropertiesResponse(key = "key2", value = JsonPrimitive("value2")) + ) + val result = input.toListSimpleProperties() + assertEquals(2, result.size) + assertEquals(JsonNull, result[0].value) + assertEquals(JsonPrimitive("value2"), result[1].value) + } + + @Test + fun `given SimplePropertiesResponse when toSimpleProperties then returns SimpleProperties with mapped values`() { + val input = SimplePropertiesResponse(key = "testKey", value = JsonPrimitive("testValue")) + val result = input.toSimpleProperties() + assertEquals("testKey", result.key) + assertEquals(JsonPrimitive("testValue"), result.value) + } + + @Test + fun `given SimplePropertiesResponse with JsonNull when toSimpleProperties then returns SimpleProperties with JsonNull`() { + val input = SimplePropertiesResponse(key = "testKey", value = JsonNull) + val result = input.toSimpleProperties() + assertEquals("testKey", result.key) + assertEquals(JsonNull, result.value) + } + + @Test + fun `given SimplePropertiesResponse with complex JsonElement when toSimpleProperties then returns SimpleProperties with same JsonElement`() { + val complexJson = buildJsonObject { + put("nested", "value") + putJsonObject("inner") { + put("deep", "data") + } + } + val input = SimplePropertiesResponse(key = "complexKey", value = complexJson) + val result = input.toSimpleProperties() + assertEquals("complexKey", result.key) + assertEquals(complexJson, result.value) + } + + @Test + fun `given SimplePropertiesResponse with empty string key when toSimpleProperties then returns SimpleProperties with empty key`() { + val input = SimplePropertiesResponse(key = "", value = JsonPrimitive("value")) + val result = input.toSimpleProperties() + assertEquals("", result.key) + assertEquals(JsonPrimitive("value"), result.value) + } + + @Test + fun `given JsonElement with numeric value when convertToElement then deserializes correctly`() { + val jsonElement = buildJsonObject { + put("name", "Test") + put("age", 42) + } + val result: TestSerializableClass? = jsonElement.convertToElement() + assertEquals("Test", result?.name) + assertEquals(42, result?.age) + } + + @Test + fun `given JsonElement with boolean value when convertToElement then deserializes correctly`() { + data class BooleanClass(val flag: Boolean) + val jsonElement = buildJsonObject { + put("flag", true) + } + val result: BooleanClass? = jsonElement.convertToElement() + assertEquals(true, result?.flag) + } + + @Test + fun `given list with duplicate keys when toListSimpleProperties then returns all items including duplicates`() { + val input = listOf( + SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")), + SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value2")) + ) + val result = input.toListSimpleProperties() + assertEquals(2, result.size) + assertEquals("key1", result[0].key) + assertEquals("key1", result[1].key) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/ViewMapperVoTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/ViewMapperVoTest.kt new file mode 100644 index 0000000..03777f5 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/ViewMapperVoTest.kt @@ -0,0 +1,298 @@ +```kotlin +package com.github.codandotv.craftd.androidcore.data + +import io.mockk.junit4.MockKRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNull + +@RunWith(JUnit4::class) +class ViewMapperVoTest { + + @get:Rule + val mockkRule = MockKRule(this) + + data class TestDataClass( + val id: String = "", + val name: String = "", + val value: Int = 0 + ) + + data class NestedTestDataClass( + val id: String, + val nested: TestDataClass, + val optional: String? = null + ) + + @Test + fun `given valid map when convertToVO then returns correctly deserialized object`() { + val input = mapOf( + "id" to "test-123", + "name" to "Test Name", + "value" to 42 + ) + + val result = input.convertToVO() + + assertEquals("test-123", result.id) + assertEquals("Test Name", result.name) + assertEquals(42, result.value) + } + + @Test + fun `given partial map with defaults when convertToVO then uses default values`() { + val input = mapOf( + "id" to "test-456" + ) + + val result = input.convertToVO() + + assertEquals("test-456", result.id) + assertEquals("", result.name) + assertEquals(0, result.value) + } + + @Test + fun `given nested map when convertToVO then returns correctly deserialized nested object`() { + val input = mapOf( + "id" to "parent-123", + "nested" to mapOf( + "id" to "child-456", + "name" to "Child Name", + "value" to 99 + ), + "optional" to "test-value" + ) + + val result = input.convertToVO() + + assertEquals("parent-123", result.id) + assertEquals("child-456", result.nested.id) + assertEquals("Child Name", result.nested.name) + assertEquals(99, result.nested.value) + assertEquals("test-value", result.optional) + } + + @Test + fun `given null input when convertToVO then throws exception`() { + val input: Any? = null + + assertFailsWith { + input.convertToVO() + } + } + + @Test + fun `given empty map when convertToVO then returns object with default values`() { + val input: Any = emptyMap() + + val result = input.convertToVO() + + assertEquals("", result.id) + assertEquals("", result.name) + assertEquals(0, result.value) + } + + @Test + fun `given map with extra fields when convertToVO then ignores extra fields`() { + val input = mapOf( + "id" to "test-789", + "name" to "Extra Test", + "value" to 55, + "extraField" to "should be ignored", + "anotherExtra" to 123 + ) + + val result = input.convertToVO() + + assertEquals("test-789", result.id) + assertEquals("Extra Test", result.name) + assertEquals(55, result.value) + } + + @Test + fun `given map with type coercion when convertToVO then coerces types correctly`() { + val input = mapOf( + "id" to "test-coerce", + "name" to "Coerce Test", + "value" to "100" + ) + + val result = input.convertToVO() + + assertEquals("test-coerce", result.id) + assertEquals("Coerce Test", result.name) + assertEquals(100, result.value) + } + + @Test + fun `given list of maps when convertToVO then returns correctly deserialized list object`() { + val input: Any = listOf( + mapOf("id" to "1", "name" to "First", "value" to 10), + mapOf("id" to "2", "name" to "Second", "value" to 20) + ) + + val result = input.convertToVO>() + + assertEquals(2, result.size) + assertEquals("1", result[0].id) + assertEquals("First", result[0].name) + assertEquals(10, result[0].value) + assertEquals("2", result[1].id) + assertEquals("Second", result[1].name) + assertEquals(20, result[1].value) + } + + @Test + fun `given string input when convertToVO then throws exception`() { + val input: Any = "not a valid object" + + assertFailsWith { + input.convertToVO() + } + } + + @Test + fun `given boolean input when convertToVO then throws exception`() { + val input: Any = true + + assertFailsWith { + input.convertToVO() + } + } + + @Test + fun `given integer input when convertToVO then throws exception`() { + val input: Any = 42 + + assertFailsWith { + input.convertToVO() + } + } + + @Test + fun `given map with null values when convertToVO then preserves null values in nullable fields`() { + val input = mapOf( + "id" to "test-null", + "nested" to mapOf( + "id" to "nested-id", + "name" to "Nested", + "value" to 5 + ), + "optional" to null + ) + + val result = input.convertToVO() + + assertEquals("test-null", result.id) + assertNull(result.optional) + } + + @Test + fun `given complex nested structure when convertToVO then handles deeply nested objects`() { + val input = mapOf( + "id" to "root", + "nested" to mapOf( + "id" to "child", + "name" to "Child Name", + "value" to 100 + ) + ) + + val result = input.convertToVO() + + assertEquals("root", result.id) + assertEquals("child", result.nested.id) + assertEquals("Child Name", result.nested.name) + assertEquals(100, result.nested.value) + } + + @Test + fun `given data class with copy when convertToVO then original object unaffected`() { + val original = TestDataClass(id = "orig", name = "Original", value = 1) + val copy = original.copy(name = "Modified", value = 2) + + assertEquals("Original", original.name) + assertEquals(1, original.value) + assertEquals("Modified", copy.name) + assertEquals(2, copy.value) + } + + @Test + fun `given two identical data classes when comparing then equals returns true`() { + val obj1 = TestDataClass(id = "same", name = "Same Name", value = 42) + val obj2 = TestDataClass(id = "same", name = "Same Name", value = 42) + + assertEquals(obj1, obj2) + assertEquals(obj1.hashCode(), obj2.hashCode()) + } + + @Test + fun `given two different data classes when comparing then equals returns false`() { + val obj1 = TestDataClass(id = "obj1", name = "Name1", value = 1) + val obj2 = TestDataClass(id = "obj2", name = "Name2", value = 2) + + assertEquals(false, obj1 == obj2) + } + + @Test + fun `given data class with default constructor when instantiating then all fields have default values`() { + val obj = TestDataClass() + + assertEquals("", obj.id) + assertEquals("", obj.name) + assertEquals(0, obj.value) + } + + @Test + fun `given map with missing required nested field when convertToVO then throws exception`() { + val input = mapOf( + "id" to "parent", + "nested" to mapOf( + "id" to "child" + ) + ) + + assertFailsWith { + input.convertToVO() + } + } + + @Test + fun `given empty list when convertToVO then returns empty list`() { + val input: Any = emptyList>() + + val result = input.convertToVO>() + + assertEquals(0, result.size) + } + + @Test + fun `given map with numeric string when convertToVO then coerces to numeric value`() { + val input = mapOf( + "id" to "numeric-test", + "name" to "Numeric", + "value" to "999" + ) + + val result = input.convertToVO() + + assertEquals(999, result.value) + } + + @Test + fun `given data class toString when called then returns formatted string`() { + val obj = TestDataClass(id = "test", name = "Test Name", value = 42) + val stringRepresentation = obj.toString() + + assertEquals(true, stringRepresentation.contains("TestDataClass")) + assertEquals(true, stringRepresentation.contains("test")) + assertEquals(true, stringRepresentation.contains("Test Name")) + assertEquals(true, stringRepresentation.contains("42")) + } +} +``` \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/action/AnalyticsPropertiesTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/action/AnalyticsPropertiesTest.kt new file mode 100644 index 0000000..8054f66 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/action/AnalyticsPropertiesTest.kt @@ -0,0 +1,407 @@ +package com.github.codandotv.craftd.androidcore.data.model.action + +import io.mockk.junit4.MockKRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class AnalyticsPropertiesTest { + + @get:Rule + val mockkRule = MockKRule(this) + + @Test + fun `given all null parameters when constructing AnalyticsProperties then all fields are null`() { + val analyticsProperties = AnalyticsProperties() + + assertNull(analyticsProperties.category) + assertNull(analyticsProperties.action) + assertNull(analyticsProperties.label) + assertNull(analyticsProperties.track) + } + + @Test + fun `given all parameters when constructing AnalyticsProperties then all fields are set correctly`() { + val analyticsProperties = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button_main", + track = "event_123" + ) + + assertEquals("purchase", analyticsProperties.category) + assertEquals("click", analyticsProperties.action) + assertEquals("button_main", analyticsProperties.label) + assertEquals("event_123", analyticsProperties.track) + } + + @Test + fun `given partial parameters when constructing AnalyticsProperties then specified fields are set and others are null`() { + val analyticsProperties = AnalyticsProperties( + category = "purchase", + action = "click" + ) + + assertEquals("purchase", analyticsProperties.category) + assertEquals("click", analyticsProperties.action) + assertNull(analyticsProperties.label) + assertNull(analyticsProperties.track) + } + + @Test + fun `given AnalyticsProperties with category when copying with new action then new instance has updated action and same category`() { + val original = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + val copied = original.copy(action = "submit") + + assertEquals("purchase", copied.category) + assertEquals("submit", copied.action) + assertEquals("button", copied.label) + assertEquals("event_1", copied.track) + } + + @Test + fun `given AnalyticsProperties when copying without parameters then returns equivalent instance`() { + val original = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + val copied = original.copy() + + assertEquals(original, copied) + } + + @Test + fun `given two AnalyticsProperties with same values when comparing equals then returns true`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + assertEquals(first, second) + } + + @Test + fun `given two AnalyticsProperties with different category when comparing equals then returns false`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "view", + action = "click", + label = "button", + track = "event_1" + ) + + assertNotEquals(first, second) + } + + @Test + fun `given two AnalyticsProperties with different action when comparing equals then returns false`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "purchase", + action = "submit", + label = "button", + track = "event_1" + ) + + assertNotEquals(first, second) + } + + @Test + fun `given two AnalyticsProperties with different label when comparing equals then returns false`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "purchase", + action = "click", + label = "link", + track = "event_1" + ) + + assertNotEquals(first, second) + } + + @Test + fun `given two AnalyticsProperties with different track when comparing equals then returns false`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_2" + ) + + assertNotEquals(first, second) + } + + @Test + fun `given two AnalyticsProperties with all null values when comparing equals then returns true`() { + val first = AnalyticsProperties() + val second = AnalyticsProperties() + + assertEquals(first, second) + } + + @Test + fun `given two AnalyticsProperties with same values when comparing hashCode then returns same hash`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + assertEquals(first.hashCode(), second.hashCode()) + } + + @Test + fun `given two AnalyticsProperties with different values when comparing hashCode then likely returns different hash`() { + val first = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "view", + action = "scroll", + label = "page", + track = "event_2" + ) + + assertNotEquals(first.hashCode(), second.hashCode()) + } + + @Test + fun `given AnalyticsProperties when calling toString then returns string representation`() { + val analyticsProperties = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + val result = analyticsProperties.toString() + + assertTrue(result.contains("category")) + assertTrue(result.contains("purchase")) + assertTrue(result.contains("action")) + assertTrue(result.contains("click")) + assertTrue(result.contains("label")) + assertTrue(result.contains("button")) + assertTrue(result.contains("track")) + assertTrue(result.contains("event_1")) + } + + @Test + fun `given AnalyticsProperties with null category when calling toString then includes null category`() { + val analyticsProperties = AnalyticsProperties( + category = null, + action = "click", + label = "button", + track = "event_1" + ) + + val result = analyticsProperties.toString() + + assertTrue(result.contains("category")) + assertTrue(result.contains("null") || result.contains("null")) + } + + @Test + fun `given AnalyticsProperties with empty string values when constructing then all empty strings are set`() { + val analyticsProperties = AnalyticsProperties( + category = "", + action = "", + label = "", + track = "" + ) + + assertEquals("", analyticsProperties.category) + assertEquals("", analyticsProperties.action) + assertEquals("", analyticsProperties.label) + assertEquals("", analyticsProperties.track) + } + + @Test + fun `given AnalyticsProperties with mixed null and empty string when comparing equals then returns false`() { + val first = AnalyticsProperties( + category = null, + action = "click", + label = "button", + track = "event_1" + ) + val second = AnalyticsProperties( + category = "", + action = "click", + label = "button", + track = "event_1" + ) + + assertNotEquals(first, second) + } + + @Test + fun `given AnalyticsProperties when copying all fields then returns new instance with same values`() { + val original = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + val copied = original.copy( + category = original.category, + action = original.action, + label = original.label, + track = original.track + ) + + assertEquals(original, copied) + assertTrue(original === original) + assertFalse(original === copied) + } + + @Test + fun `given AnalyticsProperties with special characters when constructing then special characters are preserved`() { + val analyticsProperties = AnalyticsProperties( + category = "purchase_event@2024", + action = "click-submit", + label = "btn[main]", + track = "event#123" + ) + + assertEquals("purchase_event@2024", analyticsProperties.category) + assertEquals("click-submit", analyticsProperties.action) + assertEquals("btn[main]", analyticsProperties.label) + assertEquals("event#123", analyticsProperties.track) + } + + @Test + fun `given AnalyticsProperties with unicode characters when constructing then unicode characters are preserved`() { + val analyticsProperties = AnalyticsProperties( + category = "购买", + action = "点击", + label = "按钮", + track = "事件" + ) + + assertEquals("购买", analyticsProperties.category) + assertEquals("点击", analyticsProperties.action) + assertEquals("按钮", analyticsProperties.label) + assertEquals("事件", analyticsProperties.track) + } + + @Test + fun `given AnalyticsProperties when copying with null values then all fields become null`() { + val original = AnalyticsProperties( + category = "purchase", + action = "click", + label = "button", + track = "event_1" + ) + + val copied = original.copy( + category = null, + action = null, + label = null, + track = null + ) + + assertNull(copied.category) + assertNull(copied.action) + assertNull(copied.label) + assertNull(copied.track) + } + + @Test + fun `given AnalyticsProperties with long strings when constructing then long strings are handled`() { + val longString = "a".repeat(1000) + val analyticsProperties = AnalyticsProperties( + category = longString, + action = longString, + label = longString, + track = longString + ) + + assertEquals(longString, analyticsProperties.category) + assertEquals(longString, analyticsProperties.action) + assertEquals(longString, analyticsProperties.label) + assertEquals(longString, analyticsProperties.track) + } + + @Test + fun `given AnalyticsProperties with whitespace when constructing then whitespace is preserved`() { + val analyticsProperties = AnalyticsProperties( + category = " purchase ", + action = " click ", + label = " button ", + track = " event " + ) + + assertEquals(" purchase ", analyticsProperties.category) + assertEquals(" click ", analyticsProperties.action) + assertEquals(" button ", analyticsProperties.label) + assertEquals(" event ", analyticsProperties.track) + } + + @Test + fun `given multiple AnalyticsProperties instances in collection when comparing then equals works correctly`() { + val properties = listOf( + AnalyticsProperties(category = "purchase", action = "click"), + AnalyticsProperties(category = "view", action = "scroll"), + AnalyticsProperties(category = "purchase", action = "click") + ) + + assertEquals(properties[0], properties[2]) + assertNotEquals(properties[0], properties[1]) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/base/SimplePropertiesResponseTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/base/SimplePropertiesResponseTest.kt new file mode 100644 index 0000000..efcabcf --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/base/SimplePropertiesResponseTest.kt @@ -0,0 +1,294 @@ +package com.github.codandotv.craftd.androidcore.data.model.base + +import io.mockk.junit4.MockKRule +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.jsonPrimitive +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class SimplePropertiesResponseTest { + + @get:Rule + val mockkRule = MockKRule(this) + + @Test + fun `given default params when SimplePropertiesResponse created then properties are empty string and null`() { + val response = SimplePropertiesResponse() + + assertEquals("", response.key) + assertNull(response.value) + } + + @Test + fun `given key and value when SimplePropertiesResponse created then properties are set correctly`() { + val testKey = "testKey" + val testValue: JsonElement = JsonPrimitive("testValue") + + val response = SimplePropertiesResponse(key = testKey, value = testValue) + + assertEquals(testKey, response.key) + assertEquals(testValue, response.value) + } + + @Test + fun `given only key when SimplePropertiesResponse created then value is null`() { + val testKey = "onlyKey" + + val response = SimplePropertiesResponse(key = testKey) + + assertEquals(testKey, response.key) + assertNull(response.value) + } + + @Test + fun `given only value when SimplePropertiesResponse created then key is empty string`() { + val testValue: JsonElement = JsonPrimitive(42) + + val response = SimplePropertiesResponse(value = testValue) + + assertEquals("", response.key) + assertEquals(testValue, response.value) + } + + @Test + fun `given two identical SimplePropertiesResponse when compared then equals returns true`() { + val response1 = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + val response2 = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + + assertEquals(response1, response2) + } + + @Test + fun `given two different SimplePropertiesResponse when compared then equals returns false`() { + val response1 = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + val response2 = SimplePropertiesResponse(key = "key2", value = JsonPrimitive("value2")) + + assertNotEquals(response1, response2) + } + + @Test + fun `given SimplePropertiesResponse with different keys when compared then equals returns false`() { + val response1 = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("same")) + val response2 = SimplePropertiesResponse(key = "key2", value = JsonPrimitive("same")) + + assertNotEquals(response1, response2) + } + + @Test + fun `given SimplePropertiesResponse with different values when compared then equals returns false`() { + val response1 = SimplePropertiesResponse(key = "same", value = JsonPrimitive("value1")) + val response2 = SimplePropertiesResponse(key = "same", value = JsonPrimitive("value2")) + + assertNotEquals(response1, response2) + } + + @Test + fun `given SimplePropertiesResponse when hashCode called then consistent hash is returned`() { + val response1 = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + val response2 = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + + assertEquals(response1.hashCode(), response2.hashCode()) + } + + @Test + fun `given SimplePropertiesResponse when copy called with new key then new object with updated key is returned`() { + val original = SimplePropertiesResponse(key = "original", value = JsonPrimitive("value")) + val copied = original.copy(key = "updated") + + assertEquals("updated", copied.key) + assertEquals(original.value, copied.value) + assertNotEquals(original, copied) + } + + @Test + fun `given SimplePropertiesResponse when copy called with new value then new object with updated value is returned`() { + val original = SimplePropertiesResponse(key = "key", value = JsonPrimitive("original")) + val newValue = JsonPrimitive("updated") + val copied = original.copy(value = newValue) + + assertEquals(original.key, copied.key) + assertEquals(newValue, copied.value) + assertNotEquals(original, copied) + } + + @Test + fun `given SimplePropertiesResponse when copy called with all new params then new object with all updated properties is returned`() { + val original = SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")) + val copied = original.copy(key = "key2", value = JsonPrimitive("value2")) + + assertEquals("key2", copied.key) + assertEquals(JsonPrimitive("value2"), copied.value) + assertNotEquals(original, copied) + } + + @Test + fun `given SimplePropertiesResponse when copy called without params then identical object is returned`() { + val original = SimplePropertiesResponse(key = "key", value = JsonPrimitive("value")) + val copied = original.copy() + + assertEquals(original, copied) + } + + @Test + fun `given default params when DataSimplePropertiesResponse created then data list is empty`() { + val response = DataSimplePropertiesResponse(data = emptyList()) + + assertTrue(response.data.isEmpty()) + } + + @Test + fun `given list of SimplePropertiesResponse when DataSimplePropertiesResponse created then data is set correctly`() { + val items = listOf( + SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")), + SimplePropertiesResponse(key = "key2", value = JsonPrimitive("value2")) + ) + + val response = DataSimplePropertiesResponse(data = items) + + assertEquals(items, response.data) + assertEquals(2, response.data.size) + } + + @Test + fun `given two identical DataSimplePropertiesResponse when compared then equals returns true`() { + val items = listOf(SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1"))) + val response1 = DataSimplePropertiesResponse(data = items) + val response2 = DataSimplePropertiesResponse(data = items) + + assertEquals(response1, response2) + } + + @Test + fun `given two DataSimplePropertiesResponse with different data when compared then equals returns false`() { + val response1 = DataSimplePropertiesResponse( + data = listOf(SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1"))) + ) + val response2 = DataSimplePropertiesResponse( + data = listOf(SimplePropertiesResponse(key = "key2", value = JsonPrimitive("value2"))) + ) + + assertNotEquals(response1, response2) + } + + @Test + fun `given DataSimplePropertiesResponse when copy called with new data then new object with updated data is returned`() { + val original = DataSimplePropertiesResponse( + data = listOf(SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1"))) + ) + val newData = listOf(SimplePropertiesResponse(key = "key2", value = JsonPrimitive("value2"))) + val copied = original.copy(data = newData) + + assertEquals(newData, copied.data) + assertNotEquals(original, copied) + } + + @Test + fun `given SimplePropertiesResponse with null value when created then value property is null`() { + val response = SimplePropertiesResponse(key = "testKey", value = null) + + assertEquals("testKey", response.key) + assertNull(response.value) + } + + @Test + fun `given SimplePropertiesResponse with JsonNull when created then value is JsonNull`() { + val response = SimplePropertiesResponse(key = "testKey", value = JsonNull) + + assertEquals("testKey", response.key) + assertEquals(JsonNull, response.value) + } + + @Test + fun `given SimplePropertiesResponse with complex JsonElement when created then value is preserved`() { + val complexJson = buildJsonObject { + put("nested", JsonPrimitive("value")) + } + val response = SimplePropertiesResponse(key = "complex", value = complexJson) + + assertEquals("complex", response.key) + assertEquals(complexJson, response.value) + } + + @Test + fun `given empty string key when SimplePropertiesResponse created then key is empty string`() { + val response = SimplePropertiesResponse(key = "", value = JsonPrimitive("value")) + + assertEquals("", response.key) + } + + @Test + fun `given DataSimplePropertiesResponse with single item when created then data size is one`() { + val item = SimplePropertiesResponse(key = "single", value = JsonPrimitive("item")) + val response = DataSimplePropertiesResponse(data = listOf(item)) + + assertEquals(1, response.data.size) + assertEquals(item, response.data[0]) + } + + @Test + fun `given DataSimplePropertiesResponse with multiple items when created then all items are accessible`() { + val items = listOf( + SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1")), + SimplePropertiesResponse(key = "key2", value = JsonPrimitive(123)), + SimplePropertiesResponse(key = "key3", value = JsonNull) + ) + val response = DataSimplePropertiesResponse(data = items) + + assertEquals(3, response.data.size) + assertEquals("key1", response.data[0].key) + assertEquals("key2", response.data[1].key) + assertEquals("key3", response.data[2].key) + } + + @Test + fun `given DataSimplePropertiesResponse when hashCode called then consistent hash is returned`() { + val items = listOf(SimplePropertiesResponse(key = "key1", value = JsonPrimitive("value1"))) + val response1 = DataSimplePropertiesResponse(data = items) + val response2 = DataSimplePropertiesResponse(data = items) + + assertEquals(response1.hashCode(), response2.hashCode()) + } + + @Test + fun `given SimplePropertiesResponse with numeric JsonElement when created then value is preserved`() { + val numericValue: JsonElement = JsonPrimitive(42) + val response = SimplePropertiesResponse(key = "numeric", value = numericValue) + + assertEquals(numericValue, response.value) + assertEquals(42, response.value?.jsonPrimitive?.content?.toIntOrNull()) + } + + @Test + fun `given SimplePropertiesResponse with boolean JsonElement when created then value is preserved`() { + val boolValue: JsonElement = JsonPrimitive(true) + val response = SimplePropertiesResponse(key = "bool", value = boolValue) + + assertEquals(boolValue, response.value) + } + + @Test + fun `given two SimplePropertiesResponse with same key but null values when compared then equals returns true`() { + val response1 = SimplePropertiesResponse(key = "key", value = null) + val response2 = SimplePropertiesResponse(key = "key", value = null) + + assertEquals(response1, response2) + } + + @Test + fun `given SimplePropertiesResponse with null and non-null values when compared then not equal`() { + val response1 = SimplePropertiesResponse(key = "key", value = null) + val response2 = SimplePropertiesResponse(key = "key", value = JsonPrimitive("value")) + + assertNotEquals(response1, response2) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/base/SimplePropertiesTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/base/SimplePropertiesTest.kt new file mode 100644 index 0000000..376ff9f --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/base/SimplePropertiesTest.kt @@ -0,0 +1,277 @@ +package com.github.codandotv.craftd.androidcore.data.model.base + +import io.mockk.junit4.MockKRule +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class SimplePropertiesTest { + + @get:Rule + val mockkRule = MockKRule(this) + + @Test + fun `given default constructor when creating SimpleProperties then key is empty string and value is null`() { + val properties = SimpleProperties() + + assertEquals("", properties.key) + assertNull(properties.value) + } + + @Test + fun `given key and value when creating SimpleProperties then properties are set correctly`() { + val testKey = "testKey" + val testValue = JsonPrimitive("testValue") + val properties = SimpleProperties(key = testKey, value = testValue) + + assertEquals(testKey, properties.key) + assertEquals(testValue, properties.value) + } + + @Test + fun `given only key when creating SimpleProperties then key is set and value is null`() { + val testKey = "onlyKey" + val properties = SimpleProperties(key = testKey) + + assertEquals(testKey, properties.key) + assertNull(properties.value) + } + + @Test + fun `given only value when creating SimpleProperties then value is set and key is empty string`() { + val testValue = JsonPrimitive(123) + val properties = SimpleProperties(value = testValue) + + assertEquals("", properties.key) + assertEquals(testValue, properties.value) + } + + @Test + fun `given SimpleProperties instance when calling copy with new key then new instance has updated key`() { + val original = SimpleProperties(key = "original", value = JsonPrimitive("value")) + val copied = original.copy(key = "modified") + + assertEquals("modified", copied.key) + assertEquals(original.value, copied.value) + assertNotEquals(original, copied) + } + + @Test + fun `given SimpleProperties instance when calling copy with new value then new instance has updated value`() { + val originalValue = JsonPrimitive("original") + val newValue = JsonPrimitive("modified") + val original = SimpleProperties(key = "key", value = originalValue) + val copied = original.copy(value = newValue) + + assertEquals(original.key, copied.key) + assertEquals(newValue, copied.value) + assertNotEquals(original, copied) + } + + @Test + fun `given SimpleProperties instance when calling copy with both parameters then new instance has both updated`() { + val original = SimpleProperties(key = "original", value = JsonPrimitive("value")) + val copied = original.copy(key = "newKey", value = JsonPrimitive("newValue")) + + assertEquals("newKey", copied.key) + assertEquals(JsonPrimitive("newValue"), copied.value) + assertNotEquals(original, copied) + } + + @Test + fun `given two SimpleProperties with same key and value when comparing then they are equal`() { + val properties1 = SimpleProperties(key = "sameKey", value = JsonPrimitive("sameValue")) + val properties2 = SimpleProperties(key = "sameKey", value = JsonPrimitive("sameValue")) + + assertEquals(properties1, properties2) + } + + @Test + fun `given two SimpleProperties with different keys when comparing then they are not equal`() { + val properties1 = SimpleProperties(key = "key1", value = JsonPrimitive("value")) + val properties2 = SimpleProperties(key = "key2", value = JsonPrimitive("value")) + + assertNotEquals(properties1, properties2) + } + + @Test + fun `given two SimpleProperties with different values when comparing then they are not equal`() { + val properties1 = SimpleProperties(key = "key", value = JsonPrimitive("value1")) + val properties2 = SimpleProperties(key = "key", value = JsonPrimitive("value2")) + + assertNotEquals(properties1, properties2) + } + + @Test + fun `given two SimpleProperties with null values when comparing then they are equal`() { + val properties1 = SimpleProperties(key = "key", value = null) + val properties2 = SimpleProperties(key = "key", value = null) + + assertEquals(properties1, properties2) + } + + @Test + fun `given SimpleProperties instance when calling hashCode with same properties then hash codes are equal`() { + val properties1 = SimpleProperties(key = "key", value = JsonPrimitive("value")) + val properties2 = SimpleProperties(key = "key", value = JsonPrimitive("value")) + + assertEquals(properties1.hashCode(), properties2.hashCode()) + } + + @Test + fun `given SimpleProperties instance when calling hashCode with different properties then hash codes may differ`() { + val properties1 = SimpleProperties(key = "key1", value = JsonPrimitive("value1")) + val properties2 = SimpleProperties(key = "key2", value = JsonPrimitive("value2")) + + assertNotEquals(properties1.hashCode(), properties2.hashCode()) + } + + @Test + fun `given SimpleProperties with JsonNull value when comparing then properties work correctly`() { + val properties1 = SimpleProperties(key = "key", value = JsonNull) + val properties2 = SimpleProperties(key = "key", value = JsonNull) + + assertEquals(properties1, properties2) + } + + @Test + fun `given SimpleProperties with complex JsonElement when constructing then value is stored correctly`() { + val jsonValue = JsonPrimitive(true) + val properties = SimpleProperties(key = "boolKey", value = jsonValue) + + assertEquals(jsonValue, properties.value) + assertTrue(properties.value?.jsonPrimitive?.boolean ?: false) + } + + @Test + fun `given SimpleProperties with numeric JsonElement when constructing then value is stored correctly`() { + val jsonValue = JsonPrimitive(42) + val properties = SimpleProperties(key = "numKey", value = jsonValue) + + assertEquals(jsonValue, properties.value) + assertEquals(42, properties.value?.jsonPrimitive?.int) + } + + @Test + fun `given empty key when creating SimpleProperties then key field is empty string`() { + val properties = SimpleProperties(key = "", value = JsonPrimitive("value")) + + assertEquals("", properties.key) + } + + @Test + fun `given null value when creating SimpleProperties then value field is null`() { + val properties = SimpleProperties(key = "key", value = null) + + assertNull(properties.value) + } + + @Test + fun `given SimpleProperties when toString is called then it contains key and value information`() { + val properties = SimpleProperties(key = "testKey", value = JsonPrimitive("testValue")) + val stringRepresentation = properties.toString() + + assertTrue(stringRepresentation.contains("testKey")) + assertTrue(stringRepresentation.contains("testValue")) + } + + @Test + fun `given default SimpleProperties when checking fields then key is empty and value is null`() { + val default = SimpleProperties() + + assertEquals("", default.key) + assertNull(default.value) + } + + @Test + fun `given two identical SimpleProperties when checking equality then equals returns true`() { + val props = SimpleProperties(key = "identical", value = JsonPrimitive("identical")) + + assertTrue(props == props) + } + + @Test + fun `given SimpleProperties with whitespace key when constructing then whitespace is preserved`() { + val keyWithSpace = "key with spaces" + val properties = SimpleProperties(key = keyWithSpace, value = JsonPrimitive("value")) + + assertEquals(keyWithSpace, properties.key) + } + + @Test + fun `given SimpleProperties copy without parameters when called then identical instance is created`() { + val original = SimpleProperties(key = "key", value = JsonPrimitive("value")) + val copied = original.copy() + + assertEquals(original, copied) + assertEquals(original.key, copied.key) + assertEquals(original.value, copied.value) + } + + @Test + fun `given SimpleProperties with special characters in key when constructing then key is preserved`() { + val specialKey = "key@#$%^&*()" + val properties = SimpleProperties(key = specialKey, value = JsonPrimitive("value")) + + assertEquals(specialKey, properties.key) + } + + @Test + fun `given two SimpleProperties instances when using them in a set then deduplication works`() { + val props1 = SimpleProperties(key = "key", value = JsonPrimitive("value")) + val props2 = SimpleProperties(key = "key", value = JsonPrimitive("value")) + val propSet = setOf(props1, props2) + + assertEquals(1, propSet.size) + } + + @Test + fun `given SimpleProperties with JsonPrimitive string when accessing value then string content is accessible`() { + val stringValue = "testString" + val properties = SimpleProperties(key = "stringKey", value = JsonPrimitive(stringValue)) + + assertEquals(stringValue, properties.value?.jsonPrimitive?.content) + } + + @Test + fun `given SimpleProperties with float JsonElement when constructing then float value is stored`() { + val floatValue = 3.14f + val properties = SimpleProperties(key = "floatKey", value = JsonPrimitive(floatValue)) + + assertEquals(floatValue, properties.value?.jsonPrimitive?.float) + } + + @Test + fun `given SimpleProperties when data class methods are available then they function correctly`() { + val properties = SimpleProperties(key = "key", value = JsonPrimitive("value")) + + assertTrue(properties.key.isNotEmpty()) + assertTrue(properties.value != null) + } + + @Test + fun `given SimpleProperties with null value when checking nullability then value is null`() { + val properties = SimpleProperties(key = "key", value = null) + + assertTrue(properties.value == null) + } + + @Test + fun `given two SimpleProperties with JsonNull value when comparing then they are equal`() { + val properties1 = SimpleProperties(key = "key", value = JsonNull) + val properties2 = SimpleProperties(key = "key", value = JsonNull) + + assertEquals(properties1, properties2) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/button/ButtonPropertiesTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/button/ButtonPropertiesTest.kt new file mode 100644 index 0000000..06dee62 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/button/ButtonPropertiesTest.kt @@ -0,0 +1,379 @@ +package com.github.codandotv.craftd.androidcore.data.model.button + +import io.mockk.mockk +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import com.github.codandotv.craftd.androidcore.data.model.action.ActionProperties +import com.github.codandotv.craftd.androidcore.domain.CraftDAlign + +@RunWith(JUnit4::class) +class ButtonPropertiesTest { + + @Test + fun `given default parameters when creating ButtonProperties then all fields have expected default values`() { + val buttonProperties = ButtonProperties() + + assertNull(buttonProperties.text) + assertNull(buttonProperties.textColorHex) + assertNull(buttonProperties.align) + assertNull(buttonProperties.textAlign) + assertNull(buttonProperties.textSize) + assertFalse(buttonProperties.textAllCaps!!) + assertFalse(buttonProperties.fillMaxSize!!) + assertNull(buttonProperties.backgroundHex) + assertNull(buttonProperties.actionProperties) + } + + @Test + fun `given all parameters when creating ButtonProperties then all fields are set correctly`() { + val action = mockk() + val buttonProperties = ButtonProperties( + text = "Click Me", + textColorHex = "#FFFFFF", + align = CraftDAlign.CENTER, + textAlign = CraftDAlign.CENTER, + textSize = "16sp", + textAllCaps = true, + fillMaxSize = true, + backgroundHex = "#000000", + actionProperties = action + ) + + assertEquals("Click Me", buttonProperties.text) + assertEquals("#FFFFFF", buttonProperties.textColorHex) + assertEquals(CraftDAlign.CENTER, buttonProperties.align) + assertEquals(CraftDAlign.CENTER, buttonProperties.textAlign) + assertEquals("16sp", buttonProperties.textSize) + assertTrue(buttonProperties.textAllCaps!!) + assertTrue(buttonProperties.fillMaxSize!!) + assertEquals("#000000", buttonProperties.backgroundHex) + assertEquals(action, buttonProperties.actionProperties) + } + + @Test + fun `given partial parameters when creating ButtonProperties then specified fields are set and others use defaults`() { + val buttonProperties = ButtonProperties( + text = "Submit", + textColorHex = "#FF0000", + textSize = "14sp" + ) + + assertEquals("Submit", buttonProperties.text) + assertEquals("#FF0000", buttonProperties.textColorHex) + assertNull(buttonProperties.align) + assertNull(buttonProperties.textAlign) + assertEquals("14sp", buttonProperties.textSize) + assertFalse(buttonProperties.textAllCaps!!) + assertFalse(buttonProperties.fillMaxSize!!) + assertNull(buttonProperties.backgroundHex) + assertNull(buttonProperties.actionProperties) + } + + @Test + fun `given ButtonProperties when calling copy with new text then returns new instance with updated text`() { + val original = ButtonProperties(text = "Original", textColorHex = "#FFFFFF") + val copied = original.copy(text = "Updated") + + assertEquals("Updated", copied.text) + assertEquals("#FFFFFF", copied.textColorHex) + assertNotEquals(original, copied) + } + + @Test + fun `given ButtonProperties when calling copy with all parameters then returns new instance with all fields updated`() { + val action = mockk() + val original = ButtonProperties(text = "Original") + val copied = original.copy( + text = "Updated", + textColorHex = "#000000", + align = CraftDAlign.START, + textAlign = CraftDAlign.END, + textSize = "18sp", + textAllCaps = true, + fillMaxSize = true, + backgroundHex = "#CCCCCC", + actionProperties = action + ) + + assertEquals("Updated", copied.text) + assertEquals("#000000", copied.textColorHex) + assertEquals(CraftDAlign.START, copied.align) + assertEquals(CraftDAlign.END, copied.textAlign) + assertEquals("18sp", copied.textSize) + assertTrue(copied.textAllCaps!!) + assertTrue(copied.fillMaxSize!!) + assertEquals("#CCCCCC", copied.backgroundHex) + assertEquals(action, copied.actionProperties) + } + + @Test + fun `given same ButtonProperties instances when comparing then equals returns true`() { + val button1 = ButtonProperties( + text = "Same", + textColorHex = "#FFFFFF", + textSize = "16sp" + ) + val button2 = ButtonProperties( + text = "Same", + textColorHex = "#FFFFFF", + textSize = "16sp" + ) + + assertEquals(button1, button2) + assertEquals(button1.hashCode(), button2.hashCode()) + } + + @Test + fun `given different ButtonProperties instances when comparing then equals returns false`() { + val button1 = ButtonProperties(text = "Button1") + val button2 = ButtonProperties(text = "Button2") + + assertNotEquals(button1, button2) + assertNotEquals(button1.hashCode(), button2.hashCode()) + } + + @Test + fun `given ButtonProperties with different text when comparing then equals returns false`() { + val button1 = ButtonProperties( + text = "Text1", + textColorHex = "#FFFFFF" + ) + val button2 = ButtonProperties( + text = "Text2", + textColorHex = "#FFFFFF" + ) + + assertNotEquals(button1, button2) + } + + @Test + fun `given ButtonProperties with different colors when comparing then equals returns false`() { + val button1 = ButtonProperties(text = "Same", textColorHex = "#FFFFFF") + val button2 = ButtonProperties(text = "Same", textColorHex = "#000000") + + assertNotEquals(button1, button2) + } + + @Test + fun `given ButtonProperties with different booleans when comparing then equals returns false`() { + val button1 = ButtonProperties(text = "Same", textAllCaps = true) + val button2 = ButtonProperties(text = "Same", textAllCaps = false) + + assertNotEquals(button1, button2) + } + + @Test + fun `given ButtonProperties with different ActionProperties when comparing then equals returns false`() { + val action1 = mockk() + val action2 = mockk() + val button1 = ButtonProperties(text = "Same", actionProperties = action1) + val button2 = ButtonProperties(text = "Same", actionProperties = action2) + + assertNotEquals(button1, button2) + } + + @Test + fun `given ButtonProperties when comparing with self then equals returns true`() { + val button = ButtonProperties(text = "Self") + assertEquals(button, button) + } + + @Test + fun `given ButtonProperties when comparing with null then equals returns false`() { + val button = ButtonProperties(text = "Button") + assertNotEquals(button, null) + } + + @Test + fun `given ButtonProperties with all null fields when comparing then equals based on boolean defaults`() { + val button1 = ButtonProperties( + text = null, + textColorHex = null, + textAllCaps = false, + fillMaxSize = false + ) + val button2 = ButtonProperties() + + assertEquals(button1, button2) + } + + @Test + fun `given ButtonProperties when calling hashCode multiple times then returns same value`() { + val button = ButtonProperties(text = "Consistent") + val hash1 = button.hashCode() + val hash2 = button.hashCode() + + assertEquals(hash1, hash2) + } + + @Test + fun `given CraftDAlign enum then START constant exists`() { + val align = enumValueOf("START") + assertEquals(CraftDAlign.START, align) + } + + @Test + fun `given CraftDAlign enum then END constant exists`() { + val align = enumValueOf("END") + assertEquals(CraftDAlign.END, align) + } + + @Test + fun `given CraftDAlign enum then CENTER constant exists`() { + val align = enumValueOf("CENTER") + assertEquals(CraftDAlign.CENTER, align) + } + + @Test + fun `given ButtonProperties with complex ActionProperties when creating then structure is maintained`() { + val complexAction = mockk(relaxed = true) + val button = ButtonProperties( + text = "Complex", + textColorHex = "#123456", + align = CraftDAlign.CENTER, + textAlign = CraftDAlign.START, + textSize = "20sp", + textAllCaps = true, + fillMaxSize = true, + backgroundHex = "#ABCDEF", + actionProperties = complexAction + ) + + assertEquals("Complex", button.text) + assertEquals("#123456", button.textColorHex) + assertEquals(CraftDAlign.CENTER, button.align) + assertEquals(CraftDAlign.START, button.textAlign) + assertEquals("20sp", button.textSize) + assertTrue(button.textAllCaps!!) + assertTrue(button.fillMaxSize!!) + assertEquals("#ABCDEF", button.backgroundHex) + assertEquals(complexAction, button.actionProperties) + } + + @Test + fun `given ButtonProperties when modifying actionProperties then changes are reflected`() { + val button = ButtonProperties(text = "Mutable") + val newAction = mockk() + button.actionProperties = newAction + + assertEquals(newAction, button.actionProperties) + } + + @Test + fun `given ButtonProperties with empty strings when creating then fields are set`() { + val button = ButtonProperties( + text = "", + textColorHex = "", + backgroundHex = "" + ) + + assertEquals("", button.text) + assertEquals("", button.textColorHex) + assertEquals("", button.backgroundHex) + } + + @Test + fun `given ButtonProperties when copy is called without parameters then returns equal instance`() { + val original = ButtonProperties( + text = "Original", + textColorHex = "#FFFFFF", + textSize = "16sp" + ) + val copied = original.copy() + + assertEquals(original, copied) + assertEquals(original.hashCode(), copied.hashCode()) + } + + @Test + fun `given multiple ButtonProperties with same data when comparing then all are equal`() { + val buttons = listOf( + ButtonProperties(text = "Same", textColorHex = "#FFFFFF"), + ButtonProperties(text = "Same", textColorHex = "#FFFFFF"), + ButtonProperties(text = "Same", textColorHex = "#FFFFFF") + ) + + buttons.forEach { button -> + assertEquals(buttons[0], button) + } + } + + @Test + fun `given ButtonProperties with all boolean flags true when creating then flags are correctly set`() { + val button = ButtonProperties( + text = "Flags", + textAllCaps = true, + fillMaxSize = true + ) + + assertTrue(button.textAllCaps!!) + assertTrue(button.fillMaxSize!!) + } + + @Test + fun `given ButtonProperties with all boolean flags false when creating then flags are correctly set`() { + val button = ButtonProperties( + text = "Flags", + textAllCaps = false, + fillMaxSize = false + ) + + assertFalse(button.textAllCaps!!) + assertFalse(button.fillMaxSize!!) + } + + @Test + fun `given ButtonProperties instances when comparing hashCodes of equal objects then codes are identical`() { + val button1 = ButtonProperties( + text = "Test", + textColorHex = "#AABBCC", + align = CraftDAlign.CENTER + ) + val button2 = ButtonProperties( + text = "Test", + textColorHex = "#AABBCC", + align = CraftDAlign.CENTER + ) + + assertEquals(button1.hashCode(), button2.hashCode()) + } + + @Test + fun `given ButtonProperties with special characters in text when creating then text is preserved`() { + val specialText = "Click! @#\$%^&*()" + val button = ButtonProperties(text = specialText) + + assertEquals(specialText, button.text) + } + + @Test + fun `given ButtonProperties with unicode text when creating then text is preserved`() { + val unicodeText = "クリック 点击 Нажмите" + val button = ButtonProperties(text = unicodeText) + + assertEquals(unicodeText, button.text) + } + + @Test + fun `given ButtonProperties with long hex color when creating then hex is preserved`() { + val longHex = "#AABBCCDDEE" + val button = ButtonProperties(textColorHex = longHex) + + assertEquals(longHex, button.textColorHex) + } + + @Test + fun `given ButtonProperties with various text sizes when creating then text sizes are preserved`() { + val sizes = listOf("10sp", "14dp", "18em", "2.5rem") + sizes.forEach { size -> + val button = ButtonProperties(textSize = size) + assertEquals(size, button.textSize) + } + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/checkbox/CheckBoxPropertiesTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/checkbox/CheckBoxPropertiesTest.kt new file mode 100644 index 0000000..4fde284 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/checkbox/CheckBoxPropertiesTest.kt @@ -0,0 +1,343 @@ +package com.github.codandotv.craftd.androidcore.data.model.checkbox + +import com.github.codandotv.craftd.androidcore.data.model.action.ActionProperties +import com.github.codandotv.craftd.androidcore.domain.CraftDAlign +import io.mockk.mockk +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class CheckBoxPropertiesTest { + + @Test + fun `given default parameters when creating CheckBoxProperties then all fields have default values`() { + val properties = CheckBoxProperties() + + assertNull(properties.text) + assertNull(properties.align) + assertNull(properties.textAlign) + assertFalse(properties.enable!!) + assertFalse(properties.hasItRightText!!) + assertNull(properties.actionProperties) + assertNull(properties.styleProperties) + } + + @Test + fun `given all parameters when creating CheckBoxProperties then all fields are set correctly`() { + val actionProps = mockk() + val styleProps = mockk() + val properties = CheckBoxProperties( + text = "Test CheckBox", + align = CraftDAlign.START, + textAlign = CraftDAlign.CENTER, + enable = true, + hasItRightText = true, + actionProperties = actionProps, + styleProperties = styleProps + ) + + assertEquals("Test CheckBox", properties.text) + assertEquals(CraftDAlign.START, properties.align) + assertEquals(CraftDAlign.CENTER, properties.textAlign) + assertTrue(properties.enable!!) + assertTrue(properties.hasItRightText!!) + assertEquals(actionProps, properties.actionProperties) + assertEquals(styleProps, properties.styleProperties) + } + + @Test + fun `given partial parameters when creating CheckBoxProperties then non-provided fields use defaults`() { + val properties = CheckBoxProperties( + text = "Partial", + enable = true + ) + + assertEquals("Partial", properties.text) + assertTrue(properties.enable!!) + assertNull(properties.align) + assertNull(properties.textAlign) + assertFalse(properties.hasItRightText!!) + assertNull(properties.actionProperties) + assertNull(properties.styleProperties) + } + + @Test + fun `given CheckBoxProperties when calling copy with new text then returns new instance with updated text`() { + val original = CheckBoxProperties(text = "Original") + val copied = original.copy(text = "Updated") + + assertEquals("Updated", copied.text) + assertNull(copied.align) + assertNotEquals(original.text, copied.text) + } + + @Test + fun `given CheckBoxProperties when calling copy with multiple parameters then returns new instance with all updates`() { + val original = CheckBoxProperties(text = "Original", enable = false) + val actionProps = mockk() + val copied = original.copy( + text = "New Text", + enable = true, + align = CraftDAlign.END, + actionProperties = actionProps + ) + + assertEquals("New Text", copied.text) + assertTrue(copied.enable!!) + assertEquals(CraftDAlign.END, copied.align) + assertEquals(actionProps, copied.actionProperties) + } + + @Test + fun `given identical CheckBoxProperties when comparing with equals then returns true`() { + val actionProps = mockk() + val props1 = CheckBoxProperties( + text = "Same", + align = CraftDAlign.START, + enable = true, + actionProperties = actionProps + ) + val props2 = CheckBoxProperties( + text = "Same", + align = CraftDAlign.START, + enable = true, + actionProperties = actionProps + ) + + assertEquals(props1, props2) + } + + @Test + fun `given different CheckBoxProperties when comparing with equals then returns false`() { + val props1 = CheckBoxProperties(text = "Text1", enable = true) + val props2 = CheckBoxProperties(text = "Text2", enable = false) + + assertNotEquals(props1, props2) + } + + @Test + fun `given CheckBoxProperties with different text when comparing then returns false`() { + val props1 = CheckBoxProperties(text = "Text A") + val props2 = CheckBoxProperties(text = "Text B") + + assertNotEquals(props1, props2) + } + + @Test + fun `given CheckBoxProperties with different align when comparing then returns false`() { + val props1 = CheckBoxProperties(align = CraftDAlign.START) + val props2 = CheckBoxProperties(align = CraftDAlign.CENTER) + + assertNotEquals(props1, props2) + } + + @Test + fun `given CheckBoxProperties with different enable when comparing then returns false`() { + val props1 = CheckBoxProperties(enable = true) + val props2 = CheckBoxProperties(enable = false) + + assertNotEquals(props1, props2) + } + + @Test + fun `given identical CheckBoxProperties when calling hashCode then returns same hash`() { + val actionProps = mockk() + val props1 = CheckBoxProperties( + text = "Same", + enable = true, + actionProperties = actionProps + ) + val props2 = CheckBoxProperties( + text = "Same", + enable = true, + actionProperties = actionProps + ) + + assertEquals(props1.hashCode(), props2.hashCode()) + } + + @Test + fun `given different CheckBoxProperties when calling hashCode then may return different hash`() { + val props1 = CheckBoxProperties(text = "Text1", enable = true) + val props2 = CheckBoxProperties(text = "Text2", enable = false) + + assertNotEquals(props1.hashCode(), props2.hashCode()) + } + + @Test + fun `given CheckBoxProperties when creating with null actionProperties then actionProperties is null`() { + val properties = CheckBoxProperties(actionProperties = null) + + assertNull(properties.actionProperties) + } + + @Test + fun `given CheckBoxProperties when creating with null styleProperties then styleProperties is null`() { + val properties = CheckBoxProperties(styleProperties = null) + + assertNull(properties.styleProperties) + } + + @Test + fun `given CheckBoxProperties when accessing all CraftDAlign variants then no exceptions thrown`() { + val alignValues = listOf( + CraftDAlign.START, + CraftDAlign.CENTER, + CraftDAlign.END + ) + + for (align in alignValues) { + val properties = CheckBoxProperties(align = align) + assertEquals(align, properties.align) + } + } + + @Test + fun `given CheckBoxProperties with boolean fields when toggling values then reflects correctly`() { + var properties = CheckBoxProperties(enable = true, hasItRightText = false) + assertEquals(true, properties.enable) + assertEquals(false, properties.hasItRightText) + + properties = properties.copy(enable = false, hasItRightText = true) + assertEquals(false, properties.enable) + assertEquals(true, properties.hasItRightText) + } + + @Test + fun `given CheckBoxProperties when modifying actionProperties var then reflects change`() { + val properties = CheckBoxProperties() + assertNull(properties.actionProperties) + + val newActionProps = mockk() + properties.actionProperties = newActionProps + assertEquals(newActionProps, properties.actionProperties) + } + + @Test + fun `given CheckBoxProperties when modifying styleProperties var then reflects change`() { + val properties = CheckBoxProperties() + assertNull(properties.styleProperties) + + val newStyleProps = mockk() + properties.styleProperties = newStyleProps + assertEquals(newStyleProps, properties.styleProperties) + } + + @Test + fun `given empty string text when creating CheckBoxProperties then text is preserved`() { + val properties = CheckBoxProperties(text = "") + + assertEquals("", properties.text) + } + + @Test + fun `given null text when creating CheckBoxProperties then text is null`() { + val properties = CheckBoxProperties(text = null) + + assertNull(properties.text) + } + + @Test + fun `given CheckBoxProperties with all null optional fields when comparing equality then considers content`() { + val props1 = CheckBoxProperties( + text = null, + align = null, + textAlign = null, + actionProperties = null, + styleProperties = null + ) + val props2 = CheckBoxProperties( + text = null, + align = null, + textAlign = null, + actionProperties = null, + styleProperties = null + ) + + assertEquals(props1, props2) + } + + @Test + fun `given CheckBoxProperties copy when not modifying actionProperties then retains original reference`() { + val actionProps = mockk() + val original = CheckBoxProperties( + text = "Original", + actionProperties = actionProps + ) + val copied = original.copy(text = "Updated") + + assertEquals(actionProps, copied.actionProperties) + assertEquals(original.actionProperties, copied.actionProperties) + } + + @Test + fun `given CheckBoxProperties copy when replacing actionProperties then has new reference`() { + val oldActionProps = mockk() + val newActionProps = mockk() + val original = CheckBoxProperties(actionProperties = oldActionProps) + val copied = original.copy(actionProperties = newActionProps) + + assertEquals(newActionProps, copied.actionProperties) + assertNotEquals(oldActionProps, copied.actionProperties) + } + + @Test + fun `given multiple CheckBoxProperties with different textAlign when comparing then reflects differences`() { + val props1 = CheckBoxProperties(textAlign = CraftDAlign.START) + val props2 = CheckBoxProperties(textAlign = CraftDAlign.CENTER) + val props3 = CheckBoxProperties(textAlign = CraftDAlign.END) + + assertNotEquals(props1, props2) + assertNotEquals(props2, props3) + assertNotEquals(props1, props3) + } + + @Test + fun `given CheckBoxProperties when accessing default enable value then returns false`() { + val properties = CheckBoxProperties() + + assertEquals(false, properties.enable) + } + + @Test + fun `given CheckBoxProperties when accessing default hasItRightText value then returns false`() { + val properties = CheckBoxProperties() + + assertEquals(false, properties.hasItRightText) + } + + @Test + fun `given CheckBoxProperties with all fields populated when converting to string then no exceptions thrown`() { + val actionProps = mockk() + val styleProps = mockk() + val properties = CheckBoxProperties( + text = "Test", + align = CraftDAlign.START, + textAlign = CraftDAlign.CENTER, + enable = true, + hasItRightText = true, + actionProperties = actionProps, + styleProperties = styleProps + ) + + val stringRepresentation = properties.toString() + assertTrue(stringRepresentation.isNotEmpty()) + } + + @Test + fun `given two CheckBoxProperties instances when one is modified then original remains unchanged`() { + val original = CheckBoxProperties(text = "Original", enable = false) + val modified = original.copy(text = "Modified", enable = true) + + assertEquals("Original", original.text) + assertEquals(false, original.enable) + assertEquals("Modified", modified.text) + assertEquals(true, modified.enable) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/checkbox/StylePropertiesTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/checkbox/StylePropertiesTest.kt new file mode 100644 index 0000000..b4e7add --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/checkbox/StylePropertiesTest.kt @@ -0,0 +1,326 @@ +package com.github.codandotv.craftd.androidcore.data.model.checkbox + +import io.mockk.junit4.MockKRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertNull + +@RunWith(JUnit4::class) +class StylePropertiesTest { + + @get:Rule + val mockkRule = MockKRule(this) + + @Test + fun `given all parameters when instantiating StyleProperties then all fields are set correctly`() { + val checkedColor = "#FF0000" + val uncheckedColor = "#00FF00" + + val styleProperties = StyleProperties( + checkedColor = checkedColor, + uncheckedColor = uncheckedColor + ) + + assertEquals(checkedColor, styleProperties.checkedColor) + assertEquals(uncheckedColor, styleProperties.uncheckedColor) + } + + @Test + fun `given null parameters when instantiating StyleProperties then fields default to null`() { + val styleProperties = StyleProperties( + checkedColor = null, + uncheckedColor = null + ) + + assertNull(styleProperties.checkedColor) + assertNull(styleProperties.uncheckedColor) + } + + @Test + fun `given no parameters when instantiating StyleProperties then all fields are null`() { + val styleProperties = StyleProperties() + + assertNull(styleProperties.checkedColor) + assertNull(styleProperties.uncheckedColor) + } + + @Test + fun `given partial parameters when instantiating StyleProperties then specified fields are set and others are null`() { + val checkedColor = "#AABBCC" + + val styleProperties = StyleProperties(checkedColor = checkedColor) + + assertEquals(checkedColor, styleProperties.checkedColor) + assertNull(styleProperties.uncheckedColor) + } + + @Test + fun `given StyleProperties with all fields when calling copy with new values then returns new instance with updated fields`() { + val original = StyleProperties( + checkedColor = "#111111", + uncheckedColor = "#222222" + ) + val newCheckedColor = "#333333" + val newUncheckedColor = "#444444" + + val copied = original.copy( + checkedColor = newCheckedColor, + uncheckedColor = newUncheckedColor + ) + + assertEquals(newCheckedColor, copied.checkedColor) + assertEquals(newUncheckedColor, copied.uncheckedColor) + assertEquals(original.checkedColor, original.checkedColor) + } + + @Test + fun `given StyleProperties when calling copy with no parameters then returns identical instance`() { + val original = StyleProperties( + checkedColor = "#FFFF00", + uncheckedColor = "#00FFFF" + ) + + val copied = original.copy() + + assertEquals(original, copied) + assertEquals(original.checkedColor, copied.checkedColor) + assertEquals(original.uncheckedColor, copied.uncheckedColor) + } + + @Test + fun `given StyleProperties when calling copy with partial parameters then only specified fields are updated`() { + val original = StyleProperties( + checkedColor = "#111111", + uncheckedColor = "#222222" + ) + val newCheckedColor = "#555555" + + val copied = original.copy(checkedColor = newCheckedColor) + + assertEquals(newCheckedColor, copied.checkedColor) + assertEquals(original.uncheckedColor, copied.uncheckedColor) + } + + @Test + fun `given two StyleProperties with same values when comparing with equals then returns true`() { + val styleProperties1 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + val styleProperties2 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + + assertEquals(styleProperties1, styleProperties2) + } + + @Test + fun `given two StyleProperties with different checked color when comparing with equals then returns false`() { + val styleProperties1 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + val styleProperties2 = StyleProperties( + checkedColor = "#111111", + uncheckedColor = "#DDEEFF" + ) + + assertNotEquals(styleProperties1, styleProperties2) + } + + @Test + fun `given two StyleProperties with different unchecked color when comparing with equals then returns false`() { + val styleProperties1 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + val styleProperties2 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#999999" + ) + + assertNotEquals(styleProperties1, styleProperties2) + } + + @Test + fun `given two StyleProperties with all null values when comparing with equals then returns true`() { + val styleProperties1 = StyleProperties() + val styleProperties2 = StyleProperties() + + assertEquals(styleProperties1, styleProperties2) + } + + @Test + fun `given StyleProperties with null checked color when comparing with one that has checked color then returns false`() { + val styleProperties1 = StyleProperties( + checkedColor = null, + uncheckedColor = "#DDEEFF" + ) + val styleProperties2 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + + assertNotEquals(styleProperties1, styleProperties2) + } + + @Test + fun `given two StyleProperties with same values when calling hashCode then returns same hash`() { + val styleProperties1 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + val styleProperties2 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + + assertEquals(styleProperties1.hashCode(), styleProperties2.hashCode()) + } + + @Test + fun `given two StyleProperties with different values when calling hashCode then likely returns different hash`() { + val styleProperties1 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + val styleProperties2 = StyleProperties( + checkedColor = "#111111", + uncheckedColor = "#999999" + ) + + assertNotEquals(styleProperties1.hashCode(), styleProperties2.hashCode()) + } + + @Test + fun `given StyleProperties with null values when calling hashCode then returns hash`() { + val styleProperties1 = StyleProperties() + val styleProperties2 = StyleProperties() + + assertEquals(styleProperties1.hashCode(), styleProperties2.hashCode()) + } + + @Test + fun `given StyleProperties when calling toString then returns string representation`() { + val styleProperties = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + + val result = styleProperties.toString() + + assert(result.contains("checkedColor")) + assert(result.contains("uncheckedColor")) + assert(result.contains("#AABBCC")) + assert(result.contains("#DDEEFF")) + } + + @Test + fun `given StyleProperties with null values when calling toString then returns string representation`() { + val styleProperties = StyleProperties() + + val result = styleProperties.toString() + + assert(result.contains("StyleProperties")) + } + + @Test + fun `given StyleProperties when accessing checked color field then returns correct value`() { + val checkedColor = "#FF5733" + val styleProperties = StyleProperties(checkedColor = checkedColor) + + assertEquals(checkedColor, styleProperties.checkedColor) + } + + @Test + fun `given StyleProperties when accessing unchecked color field then returns correct value`() { + val uncheckedColor = "#33FF57" + val styleProperties = StyleProperties(uncheckedColor = uncheckedColor) + + assertEquals(uncheckedColor, styleProperties.uncheckedColor) + } + + @Test + fun `given empty string color values when instantiating StyleProperties then accepts empty strings`() { + val styleProperties = StyleProperties( + checkedColor = "", + uncheckedColor = "" + ) + + assertEquals("", styleProperties.checkedColor) + assertEquals("", styleProperties.uncheckedColor) + } + + @Test + fun `given mixed null and non-null color values when comparing two instances then equality works correctly`() { + val styleProperties1 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = null + ) + val styleProperties2 = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = null + ) + + assertEquals(styleProperties1, styleProperties2) + } + + @Test + fun `given StyleProperties when using in copy with null overrides then sets fields to null`() { + val original = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + + val copied = original.copy( + checkedColor = null, + uncheckedColor = null + ) + + assertNull(copied.checkedColor) + assertNull(copied.uncheckedColor) + } + + @Test + fun `given StyleProperties instances when comparing with same reference then equals returns true`() { + val styleProperties = StyleProperties( + checkedColor = "#AABBCC", + uncheckedColor = "#DDEEFF" + ) + + assertEquals(styleProperties, styleProperties) + } + + @Test + fun `given StyleProperties with long hex color codes when instantiating then accepts valid values`() { + val checkedColor = "#FFFFFFFF" + val uncheckedColor = "#00000000" + + val styleProperties = StyleProperties( + checkedColor = checkedColor, + uncheckedColor = uncheckedColor + ) + + assertEquals(checkedColor, styleProperties.checkedColor) + assertEquals(uncheckedColor, styleProperties.uncheckedColor) + } + + @Test + fun `given StyleProperties with short hex color codes when instantiating then accepts valid values`() { + val checkedColor = "#FFF" + val uncheckedColor = "#000" + + val styleProperties = StyleProperties( + checkedColor = checkedColor, + uncheckedColor = uncheckedColor + ) + + assertEquals(checkedColor, styleProperties.checkedColor) + assertEquals(uncheckedColor, styleProperties.uncheckedColor) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/text/TextPropertiesTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/text/TextPropertiesTest.kt new file mode 100644 index 0000000..427fe52 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/data/model/text/TextPropertiesTest.kt @@ -0,0 +1,451 @@ +package com.github.codandotv.craftd.androidcore.data.model.text + +import io.mockk.* +import kotlinx.serialization.json.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import com.github.codandotv.craftd.androidcore.data.model.action.ActionProperties +import com.github.codandotv.craftd.androidcore.domain.CraftDAlign +import com.github.codandotv.craftd.androidcore.domain.CraftDTextStyle +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class TextPropertiesTest { + + private lateinit var actionPropertiesMock: ActionProperties + + @Before + fun setup() { + actionPropertiesMock = mockk() + } + + @Test + fun `given all parameters when constructing TextProperties then all fields are set correctly`() { + val text = "Sample Text" + val textColorHex = "#FF0000" + val align = CraftDAlign.CENTER + val textSize = "16sp" + val backgroundHex = "#FFFFFF" + val textStyle = CraftDTextStyle.BOLD + val textAllCaps = true + val textHtml = "HTML Text" + + val textProperties = TextProperties( + text = text, + textColorHex = textColorHex, + align = align, + textSize = textSize, + backgroundHex = backgroundHex, + textStyle = textStyle, + textAllCaps = textAllCaps, + actionProperties = actionPropertiesMock, + textHtml = textHtml + ) + + assertEquals(text, textProperties.text) + assertEquals(textColorHex, textProperties.textColorHex) + assertEquals(align, textProperties.align) + assertEquals(textSize, textProperties.textSize) + assertEquals(backgroundHex, textProperties.backgroundHex) + assertEquals(textStyle, textProperties.textStyle) + assertEquals(textAllCaps, textProperties.textAllCaps) + assertEquals(actionPropertiesMock, textProperties.actionProperties) + assertEquals(textHtml, textProperties.textHtml) + } + + @Test + fun `given no parameters when constructing TextProperties then all fields have default values`() { + val textProperties = TextProperties() + + assertNull(textProperties.text) + assertNull(textProperties.textColorHex) + assertNull(textProperties.align) + assertNull(textProperties.textSize) + assertNull(textProperties.backgroundHex) + assertNull(textProperties.textStyle) + assertEquals(false, textProperties.textAllCaps) + assertNull(textProperties.actionProperties) + assertNull(textProperties.textHtml) + } + + @Test + fun `given partial parameters when constructing TextProperties then only specified fields are set`() { + val text = "Partial Text" + val textColorHex = "#00FF00" + + val textProperties = TextProperties( + text = text, + textColorHex = textColorHex + ) + + assertEquals(text, textProperties.text) + assertEquals(textColorHex, textProperties.textColorHex) + assertNull(textProperties.align) + assertNull(textProperties.textSize) + assertNull(textProperties.backgroundHex) + assertNull(textProperties.textStyle) + assertEquals(false, textProperties.textAllCaps) + assertNull(textProperties.actionProperties) + assertNull(textProperties.textHtml) + } + + @Test + fun `given TextProperties with all fields when calling copy with new text then returns new instance with updated text`() { + val original = TextProperties( + text = "Original", + textColorHex = "#FF0000", + align = CraftDAlign.LEFT, + textSize = "14sp", + backgroundHex = "#FFFFFF", + textStyle = CraftDTextStyle.ITALIC, + textAllCaps = true, + actionProperties = actionPropertiesMock, + textHtml = "HTML" + ) + + val newText = "Updated" + val copied = original.copy(text = newText) + + assertEquals(newText, copied.text) + assertEquals(original.textColorHex, copied.textColorHex) + assertEquals(original.align, copied.align) + assertEquals(original.textSize, copied.textSize) + assertEquals(original.backgroundHex, copied.backgroundHex) + assertEquals(original.textStyle, copied.textStyle) + assertEquals(original.textAllCaps, copied.textAllCaps) + assertEquals(original.actionProperties, copied.actionProperties) + assertEquals(original.textHtml, copied.textHtml) + } + + @Test + fun `given TextProperties when calling copy with multiple fields then returns new instance with all updates`() { + val original = TextProperties(text = "Original") + + val copied = original.copy( + text = "Updated", + textColorHex = "#0000FF", + textAllCaps = true + ) + + assertEquals("Updated", copied.text) + assertEquals("#0000FF", copied.textColorHex) + assertEquals(true, copied.textAllCaps) + } + + @Test + fun `given two TextProperties with identical fields when comparing equality then returns true`() { + val textProperties1 = TextProperties( + text = "Same Text", + textColorHex = "#FF0000", + align = CraftDAlign.CENTER, + textSize = "16sp", + backgroundHex = "#FFFFFF", + textStyle = CraftDTextStyle.BOLD, + textAllCaps = true, + actionProperties = actionPropertiesMock, + textHtml = "HTML" + ) + + val textProperties2 = TextProperties( + text = "Same Text", + textColorHex = "#FF0000", + align = CraftDAlign.CENTER, + textSize = "16sp", + backgroundHex = "#FFFFFF", + textStyle = CraftDTextStyle.BOLD, + textAllCaps = true, + actionProperties = actionPropertiesMock, + textHtml = "HTML" + ) + + assertEquals(textProperties1, textProperties2) + } + + @Test + fun `given two TextProperties with different text when comparing equality then returns false`() { + val textProperties1 = TextProperties(text = "Text 1") + val textProperties2 = TextProperties(text = "Text 2") + + assertNotEquals(textProperties1, textProperties2) + } + + @Test + fun `given two TextProperties with different textColorHex when comparing equality then returns false`() { + val textProperties1 = TextProperties(textColorHex = "#FF0000") + val textProperties2 = TextProperties(textColorHex = "#00FF00") + + assertNotEquals(textProperties1, textProperties2) + } + + @Test + fun `given two TextProperties with different align when comparing equality then returns false`() { + val textProperties1 = TextProperties(align = CraftDAlign.LEFT) + val textProperties2 = TextProperties(align = CraftDAlign.RIGHT) + + assertNotEquals(textProperties1, textProperties2) + } + + @Test + fun `given two TextProperties with different textAllCaps when comparing equality then returns false`() { + val textProperties1 = TextProperties(textAllCaps = true) + val textProperties2 = TextProperties(textAllCaps = false) + + assertNotEquals(textProperties1, textProperties2) + } + + @Test + fun `given two identical TextProperties when calling hashCode then returns same value`() { + val textProperties1 = TextProperties( + text = "Same", + textColorHex = "#FF0000", + align = CraftDAlign.CENTER + ) + + val textProperties2 = TextProperties( + text = "Same", + textColorHex = "#FF0000", + align = CraftDAlign.CENTER + ) + + assertEquals(textProperties1.hashCode(), textProperties2.hashCode()) + } + + @Test + fun `given two different TextProperties when calling hashCode then likely returns different values`() { + val textProperties1 = TextProperties(text = "Text 1") + val textProperties2 = TextProperties(text = "Text 2") + + assertNotEquals(textProperties1.hashCode(), textProperties2.hashCode()) + } + + @Test + fun `given TextProperties with null text when calling toString then includes null representation`() { + val textProperties = TextProperties(text = null) + val stringRepresentation = textProperties.toString() + + assertTrue(stringRepresentation.contains("TextProperties")) + assertTrue(stringRepresentation.contains("text")) + } + + @Test + fun `given TextProperties with all fields populated when calling toString then includes all field values`() { + val textProperties = TextProperties( + text = "Test", + textColorHex = "#FF0000", + align = CraftDAlign.CENTER, + textSize = "16sp", + backgroundHex = "#FFFFFF", + textStyle = CraftDTextStyle.BOLD, + textAllCaps = true, + textHtml = "HTML" + ) + + val stringRepresentation = textProperties.toString() + + assertTrue(stringRepresentation.contains("Test")) + assertTrue(stringRepresentation.contains("#FF0000")) + assertTrue(stringRepresentation.contains("CENTER")) + } + + @Test + fun `given TextProperties when accessing actionProperties field then returns set value`() { + val textProperties = TextProperties(actionProperties = actionPropertiesMock) + + assertEquals(actionPropertiesMock, textProperties.actionProperties) + } + + @Test + fun `given TextProperties when modifying actionProperties field then updates mutable property`() { + val textProperties = TextProperties() + val newActionProperties = mockk() + + textProperties.actionProperties = newActionProperties + + assertEquals(newActionProperties, textProperties.actionProperties) + } + + @Test + fun `given TextProperties with boolean false when accessing textAllCaps then returns false`() { + val textProperties = TextProperties(textAllCaps = false) + + assertEquals(false, textProperties.textAllCaps) + } + + @Test + fun `given TextProperties with boolean true when accessing textAllCaps then returns true`() { + val textProperties = TextProperties(textAllCaps = true) + + assertEquals(true, textProperties.textAllCaps) + } + + @Test + fun `given CraftDAlign enum when accessing CENTER value then constant exists`() { + val align = CraftDAlign.CENTER + assertEquals("CENTER", align.name) + } + + @Test + fun `given CraftDAlign enum when accessing LEFT value then constant exists`() { + val align = CraftDAlign.LEFT + assertEquals("LEFT", align.name) + } + + @Test + fun `given CraftDAlign enum when accessing RIGHT value then constant exists`() { + val align = CraftDAlign.RIGHT + assertEquals("RIGHT", align.name) + } + + @Test + fun `given CraftDTextStyle enum when accessing BOLD value then constant exists`() { + val textStyle = CraftDTextStyle.BOLD + assertEquals("BOLD", textStyle.name) + } + + @Test + fun `given CraftDTextStyle enum when accessing ITALIC value then constant exists`() { + val textStyle = CraftDTextStyle.ITALIC + assertEquals("ITALIC", textStyle.name) + } + + @Test + fun `given CraftDTextStyle enum when accessing NORMAL value then constant exists`() { + val textStyle = CraftDTextStyle.NORMAL + assertEquals("NORMAL", textStyle.name) + } + + @Test + fun `given valid CraftDAlign name when using enumValueOf then returns correct enum value`() { + val align = enumValueOf("CENTER") + assertEquals(CraftDAlign.CENTER, align) + } + + @Test + fun `given valid CraftDTextStyle name when using enumValueOf then returns correct enum value`() { + val textStyle = enumValueOf("BOLD") + assertEquals(CraftDTextStyle.BOLD, textStyle) + } + + @Test + fun `given TextProperties with serialization annotations when constructing then respects SerialName`() { + val textProperties = TextProperties( + text = "Test", + textColorHex = "#FF0000", + align = CraftDAlign.CENTER, + textSize = "16sp", + backgroundHex = "#FFFFFF", + textStyle = CraftDTextStyle.BOLD, + textAllCaps = true, + textHtml = "HTML" + ) + + assertEquals("Test", textProperties.text) + assertEquals("#FF0000", textProperties.textColorHex) + assertEquals(CraftDAlign.CENTER, textProperties.align) + assertEquals("16sp", textProperties.textSize) + assertEquals("#FFFFFF", textProperties.backgroundHex) + assertEquals(CraftDTextStyle.BOLD, textProperties.textStyle) + assertEquals(true, textProperties.textAllCaps) + assertEquals("HTML", textProperties.textHtml) + } + + @Test + fun `given two TextProperties instances when comparing with equals then uses value semantics`() { + val props1 = TextProperties(text = "Value") + val props2 = TextProperties(text = "Value") + + assertEquals(props1, props2) + assertTrue(props1 === props1) + } + + @Test + fun `given TextProperties when accessing immutable annotation then class is marked immutable`() { + val textProperties = TextProperties(text = "Test") + + val annotation = textProperties::class.annotations.find { + it::class.simpleName == "Immutable" + } + + assertTrue(annotation != null || textProperties::class.simpleName != null) + } + + @Test + fun `given TextProperties when accessing stable annotation then class is marked stable`() { + val textProperties = TextProperties(text = "Test") + + val annotation = textProperties::class.annotations.find { + it::class.simpleName == "Stable" + } + + assertTrue(annotation != null || textProperties::class.simpleName != null) + } + + @Test + fun `given TextProperties with all null optional fields except default boolean when comparing then equals works`() { + val props1 = TextProperties( + text = null, + textColorHex = null, + align = null, + textSize = null, + backgroundHex = null, + textStyle = null, + textAllCaps = false, + actionProperties = null, + textHtml = null + ) + + val props2 = TextProperties() + + assertEquals(props1, props2) + } + + @Test + fun `given TextProperties when copying with no arguments then returns identical instance values`() { + val original = TextProperties( + text = "Test", + textColorHex = "#FF0000", + textAllCaps = true + ) + + val copied = original.copy() + + assertEquals(original, copied) + assertEquals(original.text, copied.text) + assertEquals(original.textColorHex, copied.textColorHex) + assertEquals(original.textAllCaps, copied.textAllCaps) + } + + @Test + fun `given TextProperties with empty string values when constructing then accepts empty strings`() { + val textProperties = TextProperties( + text = "", + textColorHex = "", + textSize = "", + backgroundHex = "", + textHtml = "" + ) + + assertEquals("", textProperties.text) + assertEquals("", textProperties.textColorHex) + assertEquals("", textProperties.textSize) + assertEquals("", textProperties.backgroundHex) + assertEquals("", textProperties.textHtml) + } + + @Test + fun `given two TextProperties when one has null and other has value then are not equal`() { + val props1 = TextProperties(text = "Value") + val props2 = TextProperties(text = null) + + assertNotEquals(props1, props2) + } + + @Test + fun `given TextProperties when comparing ActionProperties field then includes in equality check`() { + val actionProps1 = mockk() + \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/domain/CraftDAlignTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/domain/CraftDAlignTest.kt new file mode 100644 index 0000000..f92af63 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/domain/CraftDAlignTest.kt @@ -0,0 +1,214 @@ +package com.github.codandotv.craftd.androidcore.domain + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +@RunWith(JUnit4::class) +class CraftDAlignTest { + + @Test + fun `given CraftDAlign enum when accessing CENTER then constant exists`() { + val align = CraftDAlign.CENTER + assertEquals(CraftDAlign.CENTER, align) + } + + @Test + fun `given CraftDAlign enum when accessing LEFT then constant exists`() { + val align = CraftDAlign.LEFT + assertEquals(CraftDAlign.LEFT, align) + } + + @Test + fun `given CraftDAlign enum when accessing RIGHT then constant exists`() { + val align = CraftDAlign.RIGHT + assertEquals(CraftDAlign.RIGHT, align) + } + + @Test + fun `given CraftDAlign enum when accessing TOP then constant exists`() { + val align = CraftDAlign.TOP + assertEquals(CraftDAlign.TOP, align) + } + + @Test + fun `given CraftDAlign enum when accessing BOTTOM then constant exists`() { + val align = CraftDAlign.BOTTOM + assertEquals(CraftDAlign.BOTTOM, align) + } + + @Test + fun `given CraftDAlign enum when converting CENTER via enumValueOf then returns CENTER`() { + val align = enumValueOf("CENTER") + assertEquals(CraftDAlign.CENTER, align) + } + + @Test + fun `given CraftDAlign enum when converting LEFT via enumValueOf then returns LEFT`() { + val align = enumValueOf("LEFT") + assertEquals(CraftDAlign.LEFT, align) + } + + @Test + fun `given CraftDAlign enum when converting RIGHT via enumValueOf then returns RIGHT`() { + val align = enumValueOf("RIGHT") + assertEquals(CraftDAlign.RIGHT, align) + } + + @Test + fun `given CraftDAlign enum when converting TOP via enumValueOf then returns TOP`() { + val align = enumValueOf("TOP") + assertEquals(CraftDAlign.TOP, align) + } + + @Test + fun `given CraftDAlign enum when converting BOTTOM via enumValueOf then returns BOTTOM`() { + val align = enumValueOf("BOTTOM") + assertEquals(CraftDAlign.BOTTOM, align) + } + + @Test + fun `given CraftDAlign enum when converting invalid string via enumValueOf then throws exception`() { + assertFailsWith { + enumValueOf("INVALID") + } + } + + @Test + fun `given CraftDAlign enum when comparing CENTER instances then they are equal`() { + val align1 = CraftDAlign.CENTER + val align2 = CraftDAlign.CENTER + assertEquals(align1, align2) + } + + @Test + fun `given CraftDAlign enum when comparing different constants then they are not equal`() { + val align1 = CraftDAlign.CENTER + val align2 = CraftDAlign.LEFT + val areEqual = align1 == align2 + assertEquals(false, areEqual) + } + + @Test + fun `given CraftDAlign enum when getting values then all five constants are present`() { + val values = CraftDAlign.values() + assertEquals(5, values.size) + } + + @Test + fun `given CraftDAlign enum when getting values then CENTER is in values`() { + val values = CraftDAlign.values() + assert(values.contains(CraftDAlign.CENTER)) + } + + @Test + fun `given CraftDAlign enum when getting values then LEFT is in values`() { + val values = CraftDAlign.values() + assert(values.contains(CraftDAlign.LEFT)) + } + + @Test + fun `given CraftDAlign enum when getting values then RIGHT is in values`() { + val values = CraftDAlign.values() + assert(values.contains(CraftDAlign.RIGHT)) + } + + @Test + fun `given CraftDAlign enum when getting values then TOP is in values`() { + val values = CraftDAlign.values() + assert(values.contains(CraftDAlign.TOP)) + } + + @Test + fun `given CraftDAlign enum when getting values then BOTTOM is in values`() { + val values = CraftDAlign.values() + assert(values.contains(CraftDAlign.BOTTOM)) + } + + @Test + fun `given CraftDAlign enum when calling valueOf with CENTER then returns CENTER`() { + val align = CraftDAlign.valueOf("CENTER") + assertEquals(CraftDAlign.CENTER, align) + } + + @Test + fun `given CraftDAlign enum when calling valueOf with LEFT then returns LEFT`() { + val align = CraftDAlign.valueOf("LEFT") + assertEquals(CraftDAlign.LEFT, align) + } + + @Test + fun `given CraftDAlign enum when getting name of CENTER then returns CENTER string`() { + val align = CraftDAlign.CENTER + assertEquals("CENTER", align.name) + } + + @Test + fun `given CraftDAlign enum when getting name of LEFT then returns LEFT string`() { + val align = CraftDAlign.LEFT + assertEquals("LEFT", align.name) + } + + @Test + fun `given CraftDAlign enum when getting name of RIGHT then returns RIGHT string`() { + val align = CraftDAlign.RIGHT + assertEquals("RIGHT", align.name) + } + + @Test + fun `given CraftDAlign enum when getting name of TOP then returns TOP string`() { + val align = CraftDAlign.TOP + assertEquals("TOP", align.name) + } + + @Test + fun `given CraftDAlign enum when getting name of BOTTOM then returns BOTTOM string`() { + val align = CraftDAlign.BOTTOM + assertEquals("BOTTOM", align.name) + } + + @Test + fun `given CraftDAlign enum when getting ordinal of CENTER then returns 0`() { + val align = CraftDAlign.CENTER + assertEquals(0, align.ordinal) + } + + @Test + fun `given CraftDAlign enum when getting ordinal of LEFT then returns 1`() { + val align = CraftDAlign.LEFT + assertEquals(1, align.ordinal) + } + + @Test + fun `given CraftDAlign enum when getting ordinal of RIGHT then returns 2`() { + val align = CraftDAlign.RIGHT + assertEquals(2, align.ordinal) + } + + @Test + fun `given CraftDAlign enum when getting ordinal of TOP then returns 3`() { + val align = CraftDAlign.TOP + assertEquals(3, align.ordinal) + } + + @Test + fun `given CraftDAlign enum when getting ordinal of BOTTOM then returns 4`() { + val align = CraftDAlign.BOTTOM + assertEquals(4, align.ordinal) + } + + @Test + fun `given CraftDAlign enum when checking hash code of same constant then hash codes are equal`() { + val align1 = CraftDAlign.CENTER + val align2 = CraftDAlign.CENTER + assertEquals(align1.hashCode(), align2.hashCode()) + } + + @Test + fun `given CraftDAlign enum when converting to string then returns enum name`() { + val align = CraftDAlign.CENTER + assertEquals("CENTER", align.toString()) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/domain/CraftDTextStyleTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/domain/CraftDTextStyleTest.kt new file mode 100644 index 0000000..5d202c8 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/domain/CraftDTextStyleTest.kt @@ -0,0 +1,160 @@ +package com.github.codandotv.craftd.androidcore.domain + +import io.mockk.junit4.MockKRule +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +@RunWith(JUnit4::class) +class CraftDTextStyleTest { + + @get:Rule + val mockkRule = MockKRule(this) + + @Test + fun `given BOLD enum constant when accessed then returns correct name`() { + assertEquals("BOLD", CraftDTextStyle.BOLD.name) + } + + @Test + fun `given ITALIC enum constant when accessed then returns correct name`() { + assertEquals("ITALIC", CraftDTextStyle.ITALIC.name) + } + + @Test + fun `given NORMAL enum constant when accessed then returns correct name`() { + assertEquals("NORMAL", CraftDTextStyle.NORMAL.name) + } + + @Test + fun `given BOLD string when converting to enum then returns BOLD constant`() { + val result = enumValueOf("BOLD") + assertEquals(CraftDTextStyle.BOLD, result) + } + + @Test + fun `given ITALIC string when converting to enum then returns ITALIC constant`() { + val result = enumValueOf("ITALIC") + assertEquals(CraftDTextStyle.ITALIC, result) + } + + @Test + fun `given NORMAL string when converting to enum then returns NORMAL constant`() { + val result = enumValueOf("NORMAL") + assertEquals(CraftDTextStyle.NORMAL, result) + } + + @Test + fun `given all enum values when iterating then contains three constants`() { + val values = CraftDTextStyle.values() + assertEquals(3, values.size) + assertNotNull(values.find { it == CraftDTextStyle.BOLD }) + assertNotNull(values.find { it == CraftDTextStyle.ITALIC }) + assertNotNull(values.find { it == CraftDTextStyle.NORMAL }) + } + + @Test + fun `given BOLD constant when comparing ordinal then returns zero`() { + assertEquals(0, CraftDTextStyle.BOLD.ordinal) + } + + @Test + fun `given ITALIC constant when comparing ordinal then returns one`() { + assertEquals(1, CraftDTextStyle.ITALIC.ordinal) + } + + @Test + fun `given NORMAL constant when comparing ordinal then returns two`() { + assertEquals(2, CraftDTextStyle.NORMAL.ordinal) + } + + @Test + fun `given two same enum constants when comparing with equals then returns true`() { + val first = CraftDTextStyle.BOLD + val second = CraftDTextStyle.BOLD + assertEquals(first, second) + } + + @Test + fun `given two different enum constants when comparing with equals then returns false`() { + val first = CraftDTextStyle.BOLD + val second = CraftDTextStyle.ITALIC + assertNotEqual(first, second) + } + + @Test + fun `given BOLD constant when calling hashCode then returns consistent value`() { + val firstHash = CraftDTextStyle.BOLD.hashCode() + val secondHash = CraftDTextStyle.BOLD.hashCode() + assertEquals(firstHash, secondHash) + } + + @Test + fun `given two different enum constants when comparing hashCode then may differ`() { + val boldHash = CraftDTextStyle.BOLD.hashCode() + val italicHash = CraftDTextStyle.ITALIC.hashCode() + assertNotEqual(boldHash, italicHash) + } + + @Test + fun `given BOLD enum when calling toString then returns BOLD string`() { + val result = CraftDTextStyle.BOLD.toString() + assertEquals("BOLD", result) + } + + @Test + fun `given ITALIC enum when calling toString then returns ITALIC string`() { + val result = CraftDTextStyle.ITALIC.toString() + assertEquals("ITALIC", result) + } + + @Test + fun `given NORMAL enum when calling toString then returns NORMAL string`() { + val result = CraftDTextStyle.NORMAL.toString() + assertEquals("NORMAL", result) + } + + @Test + fun `given enum values when checking count then exactly three values exist`() { + assertEquals(3, CraftDTextStyle.values().size) + } + + @Test + fun `given BOLD constant when comparing reference equality then returns true for same instance`() { + val first = CraftDTextStyle.BOLD + val second = CraftDTextStyle.BOLD + assertEquals(first === second, true) + } + + @Test + fun `given different enum constants when comparing with when expression then returns correct branch`() { + val style = CraftDTextStyle.ITALIC + val result = when (style) { + CraftDTextStyle.BOLD -> "bold" + CraftDTextStyle.ITALIC -> "italic" + CraftDTextStyle.NORMAL -> "normal" + } + assertEquals("italic", result) + } + + @Test + fun `given NORMAL constant when comparing with when expression then returns normal branch`() { + val style = CraftDTextStyle.NORMAL + val result = when (style) { + CraftDTextStyle.BOLD -> "bold" + CraftDTextStyle.ITALIC -> "italic" + CraftDTextStyle.NORMAL -> "normal" + } + assertEquals("normal", result) + } + + private fun assertNotEqual(first: T, second: T) { + val isEqual = first == second + assertEquals(false, isEqual) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/extensions/StringExtensionsTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/extensions/StringExtensionsTest.kt new file mode 100644 index 0000000..bf8fa94 --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/extensions/StringExtensionsTest.kt @@ -0,0 +1,64 @@ +package com.github.codandotv.craftd.androidcore.extensions + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +@RunWith(JUnit4::class) +class StringExtensionsTest { + + @Test + fun `given String Companion when empty then returns empty string`() { + val result = String.empty() + assertEquals("", result) + } + + @Test + fun `given String Companion when empty then returns string with length zero`() { + val result = String.empty() + assertEquals(0, result.length) + } + + @Test + fun `given String Companion when empty then returns string that is empty`() { + val result = String.empty() + assertTrue(result.isEmpty()) + } + + @Test + fun `given String Companion when empty then returns string that equals literal empty string`() { + val result = String.empty() + val expected = "" + assertEquals(expected, result) + } + + @Test + fun `given String Companion when empty then returns consistent result on multiple calls`() { + val result1 = String.empty() + val result2 = String.empty() + assertEquals(result1, result2) + } + + @Test + fun `given String Companion when empty then result is not blank`() { + val result = String.empty() + assertEquals("", result) + assertTrue(!result.isNotEmpty()) + } + + @Test + fun `given String Companion when empty then result can be used in string operations`() { + val result = String.empty() + val concatenated = result + "test" + assertEquals("test", concatenated) + } + + @Test + fun `given String Companion when empty then result has correct hashCode`() { + val result = String.empty() + val expected = "" + assertEquals(expected.hashCode(), result.hashCode()) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/presentation/CraftDComponentKeyTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/presentation/CraftDComponentKeyTest.kt new file mode 100644 index 0000000..e0bbfff --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/presentation/CraftDComponentKeyTest.kt @@ -0,0 +1,221 @@ +package com.github.codandotv.craftd.androidcore.presentation + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +@RunWith(JUnit4::class) +class CraftDComponentKeyTest { + + @Test + fun `given TEXT_VIEW_COMPONENT enum when accessing key then returns correct string`() { + val expected = "CraftDTextView" + val actual = CraftDComponentKey.TEXT_VIEW_COMPONENT.key + + assertEquals(expected, actual) + } + + @Test + fun `given BUTTON_COMPONENT enum when accessing key then returns correct string`() { + val expected = "CraftDButton" + val actual = CraftDComponentKey.BUTTON_COMPONENT.key + + assertEquals(expected, actual) + } + + @Test + fun `given CHECK_BOX_COMPONENT enum when accessing key then returns correct string`() { + val expected = "CraftDCheckBox" + val actual = CraftDComponentKey.CHECK_BOX_COMPONENT.key + + assertEquals(expected, actual) + } + + @Test + fun `given all enum values when iterating then contains TEXT_VIEW_COMPONENT`() { + val values = CraftDComponentKey.values() + val exists = values.any { it == CraftDComponentKey.TEXT_VIEW_COMPONENT } + + assertEquals(true, exists) + } + + @Test + fun `given all enum values when iterating then contains BUTTON_COMPONENT`() { + val values = CraftDComponentKey.values() + val exists = values.any { it == CraftDComponentKey.BUTTON_COMPONENT } + + assertEquals(true, exists) + } + + @Test + fun `given all enum values when iterating then contains CHECK_BOX_COMPONENT`() { + val values = CraftDComponentKey.values() + val exists = values.any { it == CraftDComponentKey.CHECK_BOX_COMPONENT } + + assertEquals(true, exists) + } + + @Test + fun `given TEXT_VIEW_COMPONENT string when using enumValueOf then returns enum constant`() { + val result = enumValueOf("TEXT_VIEW_COMPONENT") + + assertEquals(CraftDComponentKey.TEXT_VIEW_COMPONENT, result) + } + + @Test + fun `given BUTTON_COMPONENT string when using enumValueOf then returns enum constant`() { + val result = enumValueOf("BUTTON_COMPONENT") + + assertEquals(CraftDComponentKey.BUTTON_COMPONENT, result) + } + + @Test + fun `given CHECK_BOX_COMPONENT string when using enumValueOf then returns enum constant`() { + val result = enumValueOf("CHECK_BOX_COMPONENT") + + assertEquals(CraftDComponentKey.CHECK_BOX_COMPONENT, result) + } + + @Test + fun `given invalid enum name when using enumValueOf then throws IllegalArgumentException`() { + assertFailsWith { + enumValueOf("INVALID_COMPONENT") + } + } + + @Test + fun `given enum constants when comparing equality then TEXT_VIEW_COMPONENT equals itself`() { + val first = CraftDComponentKey.TEXT_VIEW_COMPONENT + val second = CraftDComponentKey.TEXT_VIEW_COMPONENT + + assertEquals(first, second) + } + + @Test + fun `given different enum constants when comparing equality then BUTTON_COMPONENT does not equal TEXT_VIEW_COMPONENT`() { + val first = CraftDComponentKey.BUTTON_COMPONENT + val second = CraftDComponentKey.TEXT_VIEW_COMPONENT + + assertEquals(false, first == second) + } + + @Test + fun `given enum constant when accessing ordinal then TEXT_VIEW_COMPONENT is at index 0`() { + val ordinal = CraftDComponentKey.TEXT_VIEW_COMPONENT.ordinal + + assertEquals(0, ordinal) + } + + @Test + fun `given enum constant when accessing ordinal then BUTTON_COMPONENT is at index 1`() { + val ordinal = CraftDComponentKey.BUTTON_COMPONENT.ordinal + + assertEquals(1, ordinal) + } + + @Test + fun `given enum constant when accessing ordinal then CHECK_BOX_COMPONENT is at index 2`() { + val ordinal = CraftDComponentKey.CHECK_BOX_COMPONENT.ordinal + + assertEquals(2, ordinal) + } + + @Test + fun `given enum constant when calling toString then returns qualified name`() { + val result = CraftDComponentKey.TEXT_VIEW_COMPONENT.toString() + + assertEquals("TEXT_VIEW_COMPONENT", result) + } + + @Test + fun `given all enum values when counting then returns three constants`() { + val count = CraftDComponentKey.values().size + + assertEquals(3, count) + } + + @Test + fun `given CRAFT_D constant when accessing value then returns CraftD`() { + assertEquals("CraftD", "CraftD") + } + + @Test + fun `given enum key when checking prefix then TEXT_VIEW_COMPONENT key starts with CraftD`() { + val key = CraftDComponentKey.TEXT_VIEW_COMPONENT.key + val startsWithPrefix = key.startsWith("CraftD") + + assertEquals(true, startsWithPrefix) + } + + @Test + fun `given enum key when checking prefix then BUTTON_COMPONENT key starts with CraftD`() { + val key = CraftDComponentKey.BUTTON_COMPONENT.key + val startsWithPrefix = key.startsWith("CraftD") + + assertEquals(true, startsWithPrefix) + } + + @Test + fun `given enum key when checking prefix then CHECK_BOX_COMPONENT key starts with CraftD`() { + val key = CraftDComponentKey.CHECK_BOX_COMPONENT.key + val startsWithPrefix = key.startsWith("CraftD") + + assertEquals(true, startsWithPrefix) + } + + @Test + fun `given enum values when iterating then all keys are non empty strings`() { + val allKeysNonEmpty = CraftDComponentKey.values().all { it.key.isNotEmpty() } + + assertEquals(true, allKeysNonEmpty) + } + + @Test + fun `given enum values when iterating then all keys contain component naming pattern`() { + val allHaveComponent = CraftDComponentKey.values().all { it.key.contains("CraftD") } + + assertEquals(true, allHaveComponent) + } + + @Test + fun `given enum constant when comparing by reference then TEXT_VIEW_COMPONENT is singleton`() { + val first = CraftDComponentKey.TEXT_VIEW_COMPONENT + val second = CraftDComponentKey.TEXT_VIEW_COMPONENT + + assertEquals(true, first === second) + } + + @Test + fun `given enum constant when comparing by reference then BUTTON_COMPONENT is singleton`() { + val first = CraftDComponentKey.BUTTON_COMPONENT + val second = CraftDComponentKey.BUTTON_COMPONENT + + assertEquals(true, first === second) + } + + @Test + fun `given enum constant when comparing by reference then CHECK_BOX_COMPONENT is singleton`() { + val first = CraftDComponentKey.CHECK_BOX_COMPONENT + val second = CraftDComponentKey.CHECK_BOX_COMPONENT + + assertEquals(true, first === second) + } + + @Test + fun `given enum value when calling hashCode then same constant returns same hash`() { + val hash1 = CraftDComponentKey.TEXT_VIEW_COMPONENT.hashCode() + val hash2 = CraftDComponentKey.TEXT_VIEW_COMPONENT.hashCode() + + assertEquals(hash1, hash2) + } + + @Test + fun `given different enum values when calling hashCode then different constants may return different hashes`() { + val hash1 = CraftDComponentKey.TEXT_VIEW_COMPONENT.hashCode() + val hash2 = CraftDComponentKey.BUTTON_COMPONENT.hashCode() + + assertEquals(false, hash1 == hash2) + } +} \ No newline at end of file diff --git a/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/presentation/CraftDViewListenerTest.kt b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/presentation/CraftDViewListenerTest.kt new file mode 100644 index 0000000..466b78b --- /dev/null +++ b/android_kmp/craftd-core/src/test/java/com/github/codandotv/craftd/androidcore/presentation/CraftDViewListenerTest.kt @@ -0,0 +1,190 @@ +```kotlin +package com.github.codandotv.craftd.androidcore.presentation + +import com.github.codandotv.craftd.androidcore.data.model.action.ActionProperties +import io.mockk.mockk +import io.mockk.verify +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class CraftDViewListenerTest { + + @Test + `given valid ActionProperties when invoking listener then executes callback`() { + val actionProperties = mockk() + var callbackExecuted = false + var receivedProperties: ActionProperties? = null + + val listener: CraftDViewListener = { properties -> + callbackExecuted = true + receivedProperties = properties + } + + listener.invoke(actionProperties) + + assert(callbackExecuted) + assert(receivedProperties === actionProperties) + } + + @Test + `given listener when invoking with ActionProperties then callback receives correct argument`() { + val actionProperties = mockk() + var capturedProperties: ActionProperties? = null + + val listener: CraftDViewListener = { properties -> + capturedProperties = properties + } + + listener(actionProperties) + + assert(capturedProperties === actionProperties) + } + + @Test + `given multiple listeners when each invoked then all execute independently`() { + val actionProperties = mockk() + var listener1Called = false + var listener2Called = false + + val listener1: CraftDViewListener = { listener1Called = true } + val listener2: CraftDViewListener = { listener2Called = true } + + listener1(actionProperties) + listener2(actionProperties) + + assert(listener1Called) + assert(listener2Called) + } + + @Test + `given listener with side effects when invoked then executes all side effects`() { + val actionProperties = mockk() + val sideEffects = mutableListOf() + + val listener: CraftDViewListener = { _ -> + sideEffects.add("effect1") + sideEffects.add("effect2") + sideEffects.add("effect3") + } + + listener(actionProperties) + + assert(sideEffects.size == 3) + assert(sideEffects == listOf("effect1", "effect2", "effect3")) + } + + @Test + `given listener type alias when cast to function then behaves as function`() { + val actionProperties = mockk() + var executed = false + + val listener: CraftDViewListener = { _ -> executed = true } + val functionRef: (ActionProperties) -> Unit = listener + + functionRef(actionProperties) + + assert(executed) + } + + @Test + `given listener when assigned multiple times then last assignment takes effect`() { + val actionProperties = mockk() + var firstListenerCalled = false + var secondListenerCalled = false + + var listener: CraftDViewListener = { firstListenerCalled = true } + listener = { secondListenerCalled = true } + + listener(actionProperties) + + assert(!firstListenerCalled) + assert(secondListenerCalled) + } + + @Test + `given null properties in listener when handling then processes gracefully`() { + var receivedNull = false + val listener: CraftDViewListener = { properties -> + receivedNull = properties == null + } + + val actionProperties = mockk() + listener(actionProperties) + + assert(!receivedNull) + } + + @Test + `given listener with exception when invoked then propagates exception`() { + val actionProperties = mockk() + val listener: CraftDViewListener = { _ -> throw IllegalStateException("Test exception") } + + try { + listener(actionProperties) + assert(false) { "Expected exception to be thrown" } + } catch (e: IllegalStateException) { + assert(e.message == "Test exception") + } + } + + @Test + `given complex ActionProperties when listener invoked then correctly references object`() { + val actionProperties = mockk() + val listeners = mutableListOf() + + val listener: CraftDViewListener = { properties -> + listeners.add(properties) + } + + listener(actionProperties) + listener(actionProperties) + + assert(listeners.size == 2) + assert(listeners[0] === listeners[1]) + } + + @Test + `given listener assignment when using SAM conversion then compiles and works`() { + val actionProperties = mockk() + var called = false + + val listener: CraftDViewListener = CraftDViewListener { _ -> called = true } + + listener(actionProperties) + + assert(called) + } + + @Test + `given listener in collection when iterating then all can be invoked`() { + val actionProperties = mockk() + val callCounts = mutableListOf() + + val listeners = listOf( + { callCounts.add(1) }, + { callCounts.add(2) }, + { callCounts.add(3) } + ) + + listeners.forEach { it(actionProperties) } + + assert(callCounts == listOf(1, 2, 3)) + } + + @Test + `given listener when used as higher order function param then executes correctly`() { + val actionProperties = mockk() + var executed = false + + fun executeListener(listener: CraftDViewListener, props: ActionProperties) { + listener(props) + } + + executeListener({ _ -> executed = true }, actionProperties) + + assert(executed) + } +} +``` \ No newline at end of file