From d4390912ae9e225bcae3d0e6fea1b838ee90f185 Mon Sep 17 00:00:00 2001 From: timatifey Date: Mon, 12 Sep 2022 17:14:14 +0300 Subject: [PATCH] api-generator tests & boolean_int representation tests boolean_int tests api-generator-tests --- api_generator/.arcignore | 4 + api_generator/.gitignore | 4 + api_generator/api_generator/generator.py | 17 +- .../generators/kotlin/kotlin_entities.py | 6 +- .../kotlin/EntityWithSimpleProperties.kt | 8 +- .../EntityWithSimplePropertiesTemplate.kt | 12 +- api_generator/tests/test_api_generator.py | 2 +- .../api-generator-test/build.gradle.kts | 93 +++++++++ .../api-generator-test/jacoco.excludes | 18 ++ client/android/api-generator-test/lint.xml | 3 + .../api-generator-test/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 4 + .../generator/ArrayOfNestedItemsTest.kt | 86 +++++++++ .../java/com/yandex/generator/ArrayTest.kt | 156 +++++++++++++++ .../generator/ArrayWithTransformTest.kt | 50 +++++ .../yandex/generator/ComplexPropertyTest.kt | 86 +++++++++ .../generator/EntityParsingEnvironment.kt | 22 +++ .../generator/EntityTemplateTestCase.kt | 37 ++++ .../com/yandex/generator/EntityTestCase.kt | 14 ++ .../EntityWithComplexPropertyTest.kt | 49 +++++ ...WithComplexPropertyWithDefaultValueTest.kt | 38 ++++ .../EntityWithEntityArrayPropertyTest.kt | 103 ++++++++++ .../generator/EntityWithEntityPropertyTest.kt | 63 ++++++ .../EntityWithOptionalPropertyTest.kt | 51 +++++ ...ntityWithOptionalStringEnumPropertyTest.kt | 36 ++++ .../EntityWithRequiredPropertyTest.kt | 40 ++++ .../EntityWithSimplePropertiesTest.kt | 158 +++++++++++++++ .../EntityWithStringArrayPropertyTest.kt | 101 ++++++++++ .../EntityWithStringEnumPropertyTest.kt | 34 ++++ ...hStringEnumPropertyWithDefaultValueTest.kt | 56 ++++++ .../java/com/yandex/generator/Expected.kt | 92 +++++++++ .../generator/OptionalComplexPropertyTest.kt | 90 +++++++++ .../yandex/generator/OptionalPropertyTest.kt | 72 +++++++ .../generator/OptionalStringEnumTest.kt | 72 +++++++ .../generator/ParsingErrorLoggerTest.kt | 181 ++++++++++++++++++ .../yandex/generator/SimplePropertiesTest.kt | 47 +++++ .../com/yandex/generator/StrictArrayTest.kt | 84 ++++++++ .../com/yandex/generator/StringEnumTest.kt | 70 +++++++ .../com/yandex/generator/TestApplication.kt | 11 ++ .../src/test/resources/robolectric.properties | 2 + .../testing-generator-config.json | 8 + .../com/yandex/div/json/ParsingConverters.kt | 11 +- client/android/settings.gradle | 1 + 43 files changed, 2065 insertions(+), 27 deletions(-) create mode 100644 client/android/api-generator-test/build.gradle.kts create mode 100644 client/android/api-generator-test/jacoco.excludes create mode 100644 client/android/api-generator-test/lint.xml create mode 100644 client/android/api-generator-test/proguard-rules.pro create mode 100644 client/android/api-generator-test/src/main/AndroidManifest.xml create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayOfNestedItemsTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayWithTransformTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/ComplexPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityParsingEnvironment.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTemplateTestCase.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTestCase.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyWithDefaultValueTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityArrayPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalStringEnumPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithRequiredPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithSimplePropertiesTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringArrayPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyWithDefaultValueTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/Expected.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalComplexPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalPropertyTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalStringEnumTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/ParsingErrorLoggerTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/SimplePropertiesTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/StrictArrayTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/StringEnumTest.kt create mode 100644 client/android/api-generator-test/src/test/java/com/yandex/generator/TestApplication.kt create mode 100644 client/android/api-generator-test/src/test/resources/robolectric.properties create mode 100644 client/android/api-generator-test/testing-generator-config.json diff --git a/api_generator/.arcignore b/api_generator/.arcignore index 256041143..35749e249 100644 --- a/api_generator/.arcignore +++ b/api_generator/.arcignore @@ -1 +1,5 @@ /tests/output/ +config_hash +generator_hash +input_hash +output_hash diff --git a/api_generator/.gitignore b/api_generator/.gitignore index 256041143..35749e249 100644 --- a/api_generator/.gitignore +++ b/api_generator/.gitignore @@ -1 +1,5 @@ /tests/output/ +config_hash +generator_hash +input_hash +output_hash diff --git a/api_generator/api_generator/generator.py b/api_generator/api_generator/generator.py index 132bf1ee4..9dd500b2d 100644 --- a/api_generator/api_generator/generator.py +++ b/api_generator/api_generator/generator.py @@ -31,7 +31,7 @@ def __build_generator(config: Config) -> Generator: return generator(config) -def generate_api(config: Config): +def generate_api(config: Config, save_hash_files: bool = True): root_directory = schema_preprocessing(config) objects = build_objects(root_directory, config.generation) @@ -49,11 +49,12 @@ def generate_api(config: Config): generator.generate(objects) - def save_hash_file(filename: str, hash: str): - with open(os.path.join(config.output_path, filename), 'w') as f: - f.write(hash) + if save_hash_files: + def save_hash_file(filename: str, hash: str): + with open(os.path.join(config.output_path, filename), 'w') as f: + f.write(hash) - save_hash_file('input_hash', root_directory.hash) - save_hash_file('output_hash', expected_output_hash) - save_hash_file('generator_hash', config.generator_hash) - save_hash_file('config_hash', config.config_hash) + save_hash_file('input_hash', root_directory.hash) + save_hash_file('output_hash', expected_output_hash) + save_hash_file('generator_hash', config.generator_hash) + save_hash_file('config_hash', config.config_hash) diff --git a/api_generator/api_generator/generators/kotlin/kotlin_entities.py b/api_generator/api_generator/generators/kotlin/kotlin_entities.py index cbb36285b..2e1516d67 100644 --- a/api_generator/api_generator/generators/kotlin/kotlin_entities.py +++ b/api_generator/api_generator/generators/kotlin/kotlin_entities.py @@ -676,7 +676,7 @@ class KotlinPropertyType(PropertyType): elif isinstance(self, Color): return 'STRING_TO_COLOR_INT' elif isinstance(self, (Bool, BoolInt)): - return 'NUMBER_TO_BOOLEAN' + return 'ANY_TO_BOOLEAN' elif isinstance(self, Object) and isinstance(self.object, StringEnumeration): if string_enum_prefixed: typename = self.object.resolved_prefixed_declaration @@ -719,9 +719,7 @@ class KotlinPropertyType(PropertyType): def serialization_transform(self, string_enum_prefixed: bool) -> str: prefix = ', converter = ' - if isinstance(self, (Bool, BoolInt)): - return f'{prefix}BOOLEAN_TO_INT' - elif isinstance(self, String): + if isinstance(self, String): return f'{prefix}SPANNED_TO_HTML' if self.formatted else '' elif isinstance(self, Url): return f'{prefix}URI_TO_STRING' diff --git a/api_generator/tests/references/kotlin/EntityWithSimpleProperties.kt b/api_generator/tests/references/kotlin/EntityWithSimpleProperties.kt index c30e7fb79..93ede8793 100644 --- a/api_generator/tests/references/kotlin/EntityWithSimpleProperties.kt +++ b/api_generator/tests/references/kotlin/EntityWithSimpleProperties.kt @@ -30,8 +30,8 @@ class EntityWithSimpleProperties( override fun writeToJSON(): JSONObject { val json = JSONObject() - json.writeExpression(key = "boolean", value = boolean, converter = BOOLEAN_TO_INT) - json.writeExpression(key = "boolean_int", value = booleanInt, converter = BOOLEAN_TO_INT) + json.writeExpression(key = "boolean", value = boolean) + json.writeExpression(key = "boolean_int", value = booleanInt) json.writeExpression(key = "color", value = color, converter = COLOR_INT_TO_STRING) json.writeExpression(key = "double", value = double) json.write(key = "id", value = id) @@ -51,8 +51,8 @@ class EntityWithSimpleProperties( operator fun invoke(env: ParsingEnvironment, json: JSONObject): EntityWithSimpleProperties { val logger = env.logger return EntityWithSimpleProperties( - boolean = JsonParser.readOptionalExpression(json, "boolean", NUMBER_TO_BOOLEAN, logger, env, TYPE_HELPER_BOOLEAN), - booleanInt = JsonParser.readOptionalExpression(json, "boolean_int", NUMBER_TO_BOOLEAN, logger, env, TYPE_HELPER_BOOLEAN), + boolean = JsonParser.readOptionalExpression(json, "boolean", ANY_TO_BOOLEAN, logger, env, TYPE_HELPER_BOOLEAN), + booleanInt = JsonParser.readOptionalExpression(json, "boolean_int", ANY_TO_BOOLEAN, logger, env, TYPE_HELPER_BOOLEAN), color = JsonParser.readOptionalExpression(json, "color", STRING_TO_COLOR_INT, logger, env, TYPE_HELPER_COLOR), double = JsonParser.readOptionalExpression(json, "double", NUMBER_TO_DOUBLE, logger, env, TYPE_HELPER_DOUBLE), id = JsonParser.readOptional(json, "id", NUMBER_TO_INT, logger, env), diff --git a/api_generator/tests/references/kotlin/EntityWithSimplePropertiesTemplate.kt b/api_generator/tests/references/kotlin/EntityWithSimplePropertiesTemplate.kt index a4ad8495d..86d7faf82 100644 --- a/api_generator/tests/references/kotlin/EntityWithSimplePropertiesTemplate.kt +++ b/api_generator/tests/references/kotlin/EntityWithSimplePropertiesTemplate.kt @@ -34,8 +34,8 @@ class EntityWithSimplePropertiesTemplate : JSONSerializable, JsonTemplate { it: String -> it.length >= 1 } private val STRING_VALIDATOR = ValueValidator { it: String -> it.length >= 1 } - val BOOLEAN_READER: Reader?> = { key, json, env -> JsonParser.readOptionalExpression(json, key, NUMBER_TO_BOOLEAN, env.logger, env, TYPE_HELPER_BOOLEAN) } - val BOOLEAN_INT_READER: Reader?> = { key, json, env -> JsonParser.readOptionalExpression(json, key, NUMBER_TO_BOOLEAN, env.logger, env, TYPE_HELPER_BOOLEAN) } + val BOOLEAN_READER: Reader?> = { key, json, env -> JsonParser.readOptionalExpression(json, key, ANY_TO_BOOLEAN, env.logger, env, TYPE_HELPER_BOOLEAN) } + val BOOLEAN_INT_READER: Reader?> = { key, json, env -> JsonParser.readOptionalExpression(json, key, ANY_TO_BOOLEAN, env.logger, env, TYPE_HELPER_BOOLEAN) } val COLOR_READER: Reader?> = { key, json, env -> JsonParser.readOptionalExpression(json, key, STRING_TO_COLOR_INT, env.logger, env, TYPE_HELPER_COLOR) } val DOUBLE_READER: Reader?> = { key, json, env -> JsonParser.readOptionalExpression(json, key, NUMBER_TO_DOUBLE, env.logger, env, TYPE_HELPER_DOUBLE) } val ID_READER: Reader = { key, json, env -> JsonParser.readOptional(json, key, NUMBER_TO_INT, env.logger, env) } diff --git a/api_generator/tests/test_api_generator.py b/api_generator/tests/test_api_generator.py index 532f4af9a..a9d628251 100644 --- a/api_generator/tests/test_api_generator.py +++ b/api_generator/tests/test_api_generator.py @@ -89,7 +89,7 @@ def assert_test_generator(config_filename: str, schema_path: str, references_fol output_path=OUTPUT_PATH) if not os.path.exists(OUTPUT_PATH): os.makedirs(OUTPUT_PATH) - generate_api(config) + generate_api(config, save_hash_files=False) references_path = utils.path_generator_tests(os.path.join('references', references_folder_name)) if SHOULD_UPDATE_REFERENCES: diff --git a/client/android/api-generator-test/build.gradle.kts b/client/android/api-generator-test/build.gradle.kts new file mode 100644 index 000000000..ca8aff5f4 --- /dev/null +++ b/client/android/api-generator-test/build.gradle.kts @@ -0,0 +1,93 @@ +import com.android.build.gradle.internal.tasks.factory.dependsOn + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") +} + +val generatedSrcDir = File(buildDir, "generated/source/generator") +val projectDir = project.projectDir +val divKitPublicDir = "${projectDir}/../../.." +val testDataPath = "${divKitPublicDir}/test_data" + +apply(from = "${projectDir}/../div-library.gradle") +apply(from = "${projectDir}/../div-tests.gradle") + +tasks.withType { + kotlinOptions { + freeCompilerArgs = listOf("-Xjvm-default=all") + languageVersion = "1.6" + apiVersion = "1.6" + } +} + +android { + buildFeatures { buildConfig = true } + + sourceSets.getByName("main") { + java.srcDir(generatedSrcDir) + } + + buildToolsVersion = rootProject.ext["buildToolsVersion"] as String + compileSdk = rootProject.ext["compileSdkVersion"] as Int + + defaultConfig { + minSdk = rootProject.ext["minSdkVersion"] as Int + targetSdk = rootProject.ext["targetSdkVersion"] as Int + buildConfigField("String", "TEMPLATES_JSON_PATH", "\"$testDataPath\"") + } + + project.tasks.preBuild.dependsOn("generateHomePojoTask") + + testOptions { + unitTests { + all { + it.jvmArgs = listOf("-noverify") + it.testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + } + } + isIncludeAndroidResources = true + } + } +} + +dependencies { + implementation(project(":assertion")) + implementation(project(":div-core")) + implementation(project(":div-json")) +} + + +val schemes = listOf( + mapOf( + "name" to "testing", + "scheme" to File(testDataPath, "test_schema"), + "generated" to "${generatedSrcDir.absolutePath}/com/yandex/testing", + "config" to File(projectDir, "testing-generator-config.json") + ) +) + +schemes.forEach { item -> + tasks.register("scheme_${item["name"]}") { + val schemesDirectory = (item["scheme"] as File).absolutePath + val generatedDir = item["generated"] as String + val configPath = (item["config"] as File).absolutePath + val binPath = File(divKitPublicDir, "api_generator/api_generator.sh").absolutePath + + commandLine = listOf(binPath, configPath, schemesDirectory, generatedDir) + + println("Process schemes: $schemesDirectory") + println(commandLine.joinToString(" ")) + + inputs.dir(item["scheme"]!!) + inputs.file(item["config"]!!) + outputs.dir(generatedDir) + } +} + +tasks.register("generateHomePojoTask") { + dependsOn(provider { + tasks.filter { task -> task.name.startsWith("scheme_") } + }) +} diff --git a/client/android/api-generator-test/jacoco.excludes b/client/android/api-generator-test/jacoco.excludes new file mode 100644 index 000000000..4d9cb671e --- /dev/null +++ b/client/android/api-generator-test/jacoco.excludes @@ -0,0 +1,18 @@ +########################### +# Android support classes # +########################### +android/support/design/** +android/support/v7/** +android/support/constraint/** + +########################### +# Dagger +########################### + +##################### +# Generated classes # +##################### +**/R.class +**/R$*.class +**/BuildConfig.* +**/Manifest*.* diff --git a/client/android/api-generator-test/lint.xml b/client/android/api-generator-test/lint.xml new file mode 100644 index 000000000..475fc9f3d --- /dev/null +++ b/client/android/api-generator-test/lint.xml @@ -0,0 +1,3 @@ + + + diff --git a/client/android/api-generator-test/proguard-rules.pro b/client/android/api-generator-test/proguard-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/client/android/api-generator-test/src/main/AndroidManifest.xml b/client/android/api-generator-test/src/main/AndroidManifest.xml new file mode 100644 index 000000000..6b3723955 --- /dev/null +++ b/client/android/api-generator-test/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayOfNestedItemsTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayOfNestedItemsTest.kt new file mode 100644 index 000000000..ccabf9d8b --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayOfNestedItemsTest.kt @@ -0,0 +1,86 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.generator.ENTITY_WITH_ARRAY_OF_NESTED_ITEMS +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ArrayOfNestedItemsTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `array of nested items is parsed correctly`() { + val actual = case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_without_templates.json" + ) + Assert.assertEquals(ENTITY_WITH_ARRAY_OF_NESTED_ITEMS, actual) + } + + @Test + fun `array of nested item templates is parsed correctly`() { + val actual = case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_with_item_template.json" + ) + Assert.assertEquals(ENTITY_WITH_ARRAY_OF_NESTED_ITEMS, actual) + } + + @Test + fun `referenced array of nested items is parsed correctly`() { + val actual = case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_with_link_for_items.json" + ) + Assert.assertEquals(ENTITY_WITH_ARRAY_OF_NESTED_ITEMS, actual) + } + + @Test + fun `referenced array of nested item templates is parsed correctly`() { + val actual = case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_with_link_for_items_with_item_template.json" + ) + Assert.assertEquals(ENTITY_WITH_ARRAY_OF_NESTED_ITEMS, actual) + } + + @Test(expected = ParsingException::class) + fun `when data for nested item property references is missing parsing fails`() { + case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_with_item_template_without_data.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when required property of nested item is missing parsing fails`() { + case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_without_item_required_property.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when required property of nested item template is missing parsing fails`() { + case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_with_item_template_without_item_required_property.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when referenced array contains nested items without required property parsing fails`() { + case.parse( + directory = "array_of_nested_items", + filename = "test_array_of_nested_items_with_link_for_items_without_item_required_property.json" + ) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayTest.kt new file mode 100644 index 000000000..5df9a9376 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayTest.kt @@ -0,0 +1,156 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ArrayTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `when array is defined by link it is parsed correctly`() { + val actual = case.parse( + directory = "array", + filename = "test_array_with_link.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test + fun `when array does not contain link it is parsed correctly`() { + val actual = case.parse( + directory = "array", + filename = "test_array_without_link.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test + fun `when array contains elements defined by links it is parsed correctly`() { + val actual = case.parse( + directory = "array", + filename = "test_array_with_internal_links.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test + fun `when array contains links inside elements it is parsed correctly`() { + val actual = case.parse( + directory = "array", + filename = "test_array_with_complex_items_with_internal_links.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test(expected = ParsingException::class) + fun `array has minItems 1 and empty array received`() { + case.parse( + directory = "array", + filename = "test_array_empty.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when array has all items invalid in template parsing fails`() { + case.parse( + directory = "array", + filename = "test_array_invalid_items.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when array has all items invalid in data parsing fails`() { + case.parse( + directory = "array", + filename = "test_array_invalid_items_in_data.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when data is missing parsing fails`() { + case.parse( + directory = "array", + filename = "test_array_invalid_items_in_data.json" + ) + } + + @Test + fun `when array has some invalid items they are skipped`() { + val actual = case.parse( + directory = "array", + filename = "test_array_one_invalid_item.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test + fun `when array has some invalid links they are skipped`() { + val actual = case.parse( + directory = "array", + filename = "test_array_missing_one_link.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test + fun `when array is not templated parsing succeeds`() { + val actual = case.parse( + directory = "array", + filename = "test_array_not_templated.json" + ) + assertEquals(ENTITY_WITH_ARRAY, actual) + } + + @Test + fun `when array has heterogeneous items parsing succeeds`() { + val actual = case.parse( + directory = "array", + filename = "test_array_with_heterogeneous_items.json" + ) + assertEquals(ENTITY_WITH_HETEROGENOUS_ARRAY, actual) + } + + @Test + fun `when array has heterogeneous items with internal links parsing succeeds`() { + val actual = case.parse( + directory = "array", + filename = "test_array_with_heterogeneous_items_with_internal_links.json" + ) + assertEquals(ENTITY_WITH_HETEROGENOUS_ARRAY, actual) + } + + @Test + fun `when array has nested array parsing succeeds`() { + val actual = case.parse( + directory = "array", + filename = "test_array_nested.json" + ) + assertEquals(ENTITY_WITH_NESTED_ARRAY, actual) + } + + @Test + fun `when array has nested array with links inside parsing succeeds`() { + val actual = case.parse( + directory = "array", + filename = "test_array_nested_with_internal_link.json" + ) + assertEquals(ENTITY_WITH_NESTED_ARRAY, actual) + } + + @Test + fun `when array has nested templated array parsing succeeds`() { + val actual = case.parse( + directory = "array", + filename = "test_array_nested_with_internal_link.json" + ) + assertEquals(ENTITY_WITH_NESTED_ARRAY, actual) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayWithTransformTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayWithTransformTest.kt new file mode 100644 index 000000000..61d5a5e14 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/ArrayWithTransformTest.kt @@ -0,0 +1,50 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ArrayWithTransformTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `invalid item with transform skipped`() { + val actual = case.parse( + directory = "array_with_transform", + filename = "test_array_with_transform_not_templated_one_invalid_item.json" + ) + assertEquals(ENTITY_WITH_ARRAY_WITH_TRANSFORM, actual) + } + + @Test + fun `invalid templated item with transform skipped`() { + val actual = case.parse( + directory = "array_with_transform", + filename = "test_array_with_transform_one_invalid_item.json" + ) + assertEquals(ENTITY_WITH_ARRAY_WITH_TRANSFORM, actual) + } + + @Test(expected = ParsingException::class) + fun `array parsing failed when all items is invalid`() { + case.parse( + directory = "array_with_transform", + filename = "test_array_with_transform_not_templated_invalid_items.json" + ) + } + + @Test(expected = ParsingException::class) + fun `array parsing failed when all templated items is invalid`() { + case.parse( + directory = "array_with_transform", + filename = "test_array_with_transform_invalid_items.json" + ) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/ComplexPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/ComplexPropertyTest.kt new file mode 100644 index 000000000..75a102ed2 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/ComplexPropertyTest.kt @@ -0,0 +1,86 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.generator.ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ComplexPropertyTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `required complex property with reference is parsed correctly`() { + val actual = case.parse( + directory = "complex_property", + filename = "test_complex_property_with_link.json" + ) + assertEquals(ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, actual) + } + + @Test + fun `required complex property without reference is parsed correctly`() { + val actual = case.parse( + directory = "complex_property", + filename = "test_complex_property_without_link.json" + ) + assertEquals(ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, actual) + } + + @Test + fun `required complex property with internal reference is parsed correctly`() { + val actual = case.parse( + directory = "complex_property", + filename = "test_complex_property_with_internal_link.json" + ) + assertEquals(ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, actual) + } + + @Test(expected = ParsingException::class) + fun `when data for required complex property with reference is missing parsing fails`() { + case.parse( + directory = "complex_property", + filename = "test_complex_property_with_link_missing_data.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when data for required complex property without reference is missing parsing fails`() { + case.parse( + directory = "complex_property", + filename = "test_complex_property_without_link_missing_data.json" + ) + } + + @Test(expected = ParsingException::class) + fun `when data for required complex property with internal reference is missing parsing fails`() { + case.parse( + directory = "complex_property", + filename = "test_complex_property_with_internal_link_missing_data.json" + ) + } + + @Test + fun `required complex property without template is parsed correctly`() { + val actual = case.parse( + directory = "complex_property", + filename = "test_complex_property_not_templated.json" + ) + assertEquals(ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, actual) + } + + @Test(expected = ParsingException::class) + fun `when required complex property is invalid parsing fails`() { + case.parse( + directory = "complex_property", + filename = "test_invalid_complex_property_not_templated.json" + ) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityParsingEnvironment.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityParsingEnvironment.kt new file mode 100644 index 000000000..bf3ad9330 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityParsingEnvironment.kt @@ -0,0 +1,22 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingEnvironment +import com.yandex.div.json.ParsingErrorLogger +import com.yandex.div.json.TemplateParsingEnvironment +import com.yandex.testing.EntityTemplate +import org.json.JSONObject + +internal class EntityParsingEnvironment( + logger: ParsingErrorLogger +) : TemplateParsingEnvironment(logger) { + + override val templateFactory = object: TemplateFactory { + + override fun create(env: ParsingEnvironment, topLevel: Boolean, json: JSONObject): EntityTemplate { + return EntityTemplate(env, topLevel, json) + } + } +} + +internal val LOG_ENVIRONMENT = EntityParsingEnvironment(logger = ParsingErrorLogger.LOG) +internal val ASSERT_ENVIRONMENT = EntityParsingEnvironment(logger = ParsingErrorLogger.ASSERT) diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTemplateTestCase.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTemplateTestCase.kt new file mode 100644 index 000000000..cb6125165 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTemplateTestCase.kt @@ -0,0 +1,37 @@ +package com.yandex.generator + +import com.yandex.div.json.JSONSerializable +import com.yandex.div.json.ParsingEnvironment +import com.yandex.div.json.ParsingErrorLogger +import org.json.JSONObject +import java.io.File + +class EntityTemplateTestCase( + private val ctor: (ParsingEnvironment, JSONObject) -> T, +) { + + private val environment = EntityParsingEnvironment(ParsingErrorLogger.LOG) + + fun parse(directory: String, filename: String): T { + val bytes = readData(directory, filename) + return parse(jsonObject(bytes)) + } + + private fun readData(directory: String, filename: String): ByteArray { + val path = "${BuildConfig.TEMPLATES_JSON_PATH}/template_test_data/$directory/$filename" + return File(path).readBytes() + } + + private fun parse(json: JSONObject): T { + val templatesJson = json.optJSONObject("templates") + if (templatesJson != null) { + environment.parseTemplates(templatesJson) + } + val entityJson = json.getJSONObject("entity") + return ctor.invoke(environment, entityJson) + } + + private fun jsonObject(json: ByteArray): JSONObject { + return JSONObject(json.toString(charset = Charsets.UTF_8)) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTestCase.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTestCase.kt new file mode 100644 index 000000000..f5460f632 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityTestCase.kt @@ -0,0 +1,14 @@ +package com.yandex.generator + +import com.yandex.div.json.JSONSerializable +import com.yandex.div.json.ParsingEnvironment +import org.json.JSONObject + +class EntityTestCase( + private val ctor: (ParsingEnvironment, JSONObject) -> T, +) { + + fun parse(env: ParsingEnvironment, json: String): T { + return ctor.invoke(env, JSONObject(json)) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyTest.kt new file mode 100644 index 000000000..14a4fc62d --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyTest.kt @@ -0,0 +1,49 @@ +package com.yandex.generator + +import android.net.Uri +import com.yandex.div.json.ParsingException +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithComplexProperty +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithComplexPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithComplexProperty.Companion::invoke, + ) + + @Test + fun `property value is set`() { + val json = """{ + "property": { + "value": "https://ya.ru" + } + }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(Uri.parse("https://ya.ru"), entity.property.value.evaluate(ExpressionResolver.EMPTY)) + } + + @Test(expected = ParsingException::class) + fun `null property value`() { + val json = """{ }""" + + case.parse(LOG_ENVIRONMENT, json) + } + + @Test(expected = ParsingException::class) + fun `invalid property`() { + val json = """{ + "property": { + "value": 1 + } + }""" + + case.parse(LOG_ENVIRONMENT, json) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyWithDefaultValueTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyWithDefaultValueTest.kt new file mode 100644 index 000000000..83f580b08 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithComplexPropertyWithDefaultValueTest.kt @@ -0,0 +1,38 @@ +package com.yandex.generator + +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithComplexPropertyWithDefaultValue +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithComplexPropertyWithDefaultValueTest { + + private val case = EntityTestCase( + ctor = EntityWithComplexPropertyWithDefaultValue.Companion::invoke, + ) + + @Test + fun `property value is set`() { + val json = """{ + "property": { + "value": "Some text" + } + }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals("Some text", entity.property.value.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `null property value resolves as default value`() { + val json = """{ }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals("Default text", entity.property.value.evaluate(ExpressionResolver.EMPTY)) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityArrayPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityArrayPropertyTest.kt new file mode 100644 index 000000000..a5d7113f0 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityArrayPropertyTest.kt @@ -0,0 +1,103 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithArray +import com.yandex.testing.EntityWithRequiredProperty +import com.yandex.testing.EntityWithStringEnumPropertyWithDefaultValue +import org.hamcrest.Matchers.hasSize +import org.junit.Assert.assertEquals +import org.junit.Assert.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithEntityArrayPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithArray.Companion::invoke + ) + + @Test + fun `homogeneous array`() { + val json = """{ + "array": [ + { + "type": "entity_with_required_property", + "property": "Some text 1" + }, + { + "type": "entity_with_required_property", + "property": "Some text 2" + } + ] + }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertThat(entity.array, hasSize(2)) + assertEquals("Some text 1", (entity.array[0].value() as EntityWithRequiredProperty).property.evaluate(ExpressionResolver.EMPTY)) + assertEquals("Some text 2", (entity.array[1].value() as EntityWithRequiredProperty).property.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `heterogeneous array`() { + val json = """{ + "array": [ + { + "type": "entity_with_required_property", + "property": "Some text 1" + }, + { + "type": "entity_with_string_enum_property_with_default_value" + } + ] + }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertThat(entity.array, hasSize(2)) + assertEquals("Some text 1", (entity.array[0].value() as EntityWithRequiredProperty).property + .evaluate(ExpressionResolver.EMPTY)) + assertEquals( + EntityWithStringEnumPropertyWithDefaultValue.Value.SECOND, + (entity.array[1].value() as EntityWithStringEnumPropertyWithDefaultValue).value + .evaluate(ExpressionResolver.EMPTY) + ) + } + + @Test + fun `invalid object in array`() { + val json = """{ + "array": [ + { + "type": "entity_with_required_property", + "property": "Some text 1" + }, + { + "type": "entity_with_required_property" + }, + { + "type": "entity_with_required_property", + "property": "Some text 3" + } + ] + }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertThat(entity.array, hasSize(2)) + assertEquals("Some text 1", (entity.array[0].value() as EntityWithRequiredProperty).property + .evaluate(ExpressionResolver.EMPTY)) + assertEquals("Some text 3", (entity.array[1].value() as EntityWithRequiredProperty).property + .evaluate(ExpressionResolver.EMPTY)) + } + + @Test(expected = ParsingException::class) + fun `null property value`() { + val json = """{ }""" + + case.parse(LOG_ENVIRONMENT, json) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityPropertyTest.kt new file mode 100644 index 000000000..e9accbd99 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithEntityPropertyTest.kt @@ -0,0 +1,63 @@ +package com.yandex.generator + +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithEntityProperty +import com.yandex.testing.EntityWithRequiredProperty +import com.yandex.testing.EntityWithStringEnumProperty +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithEntityPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithEntityProperty.Companion::invoke + ) + + @Test + fun `property value is set`() { + val json = """{ + "entity": { + "type": "entity_with_required_property", + "property": "Some text" + } + }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals("Some text", (entity.entity.value() as EntityWithRequiredProperty).property + .evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `invalid value resoles as default value`() { + val json = """{ + "entity": { + "type": "entity_with_required_property" + } + }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertEquals( + EntityWithStringEnumProperty.Property.SECOND, + (entity.entity.value() as EntityWithStringEnumProperty).property + .evaluate(ExpressionResolver.EMPTY) + ) + } + + @Test + fun `null value resolves as default value`() { + val json = """{ }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals( + EntityWithStringEnumProperty.Property.SECOND, + (entity.entity.value() as EntityWithStringEnumProperty).property + .evaluate(ExpressionResolver.EMPTY) + ) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalPropertyTest.kt new file mode 100644 index 000000000..9b3dc3b59 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalPropertyTest.kt @@ -0,0 +1,51 @@ +package com.yandex.generator + +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithOptionalProperty +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithOptionalPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithOptionalProperty.Companion::invoke + ) + + @Test + fun `property value is set`() { + val json = """{ "property": "Some text" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals("Some text", entity.property!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `invalid value type`() { + val json = """{ "value": [ "Some text" ] }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertNull(entity.property) + } + + @Test(expected = AssertionError::class) + fun `error in value is logged`() { + val json = """{ "property": [ "Some text" ] }""" + + case.parse(ASSERT_ENVIRONMENT, json) + } + + @Test + fun `null property value`() { + val json = """{ }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertNull(entity.property) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalStringEnumPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalStringEnumPropertyTest.kt new file mode 100644 index 000000000..c30d38d2a --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithOptionalStringEnumPropertyTest.kt @@ -0,0 +1,36 @@ +package com.yandex.generator + +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithOptionalStringEnumProperty +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithOptionalStringEnumPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithOptionalStringEnumProperty.Companion::invoke + ) + + @Test + fun `property value is set`() { + val json = """{ "property": "second" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(EntityWithOptionalStringEnumProperty.Property.SECOND, + entity.property?.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `null property value`() { + val json = """{ }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertNull(entity.property) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithRequiredPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithRequiredPropertyTest.kt new file mode 100644 index 000000000..21f95f7af --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithRequiredPropertyTest.kt @@ -0,0 +1,40 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithRequiredProperty +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithRequiredPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithRequiredProperty.Companion::invoke + ) + + @Test + fun `property value is set`() { + val json = """{ "property": "Some text" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals("Some text", entity.property.evaluate(ExpressionResolver.EMPTY)) + } + + @Test(expected = ParsingException::class) + fun `invalid property type`() { + val json = """{ "property": [ "Some text" ] }""" + + case.parse(LOG_ENVIRONMENT, json) + } + + @Test(expected = ParsingException::class) + fun `null property value`() { + val json = """{ }""" + + case.parse(LOG_ENVIRONMENT, json) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithSimplePropertiesTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithSimplePropertiesTest.kt new file mode 100644 index 000000000..438811c74 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithSimplePropertiesTest.kt @@ -0,0 +1,158 @@ +package com.yandex.generator + +import android.graphics.Color +import android.net.Uri +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithSimpleProperties +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithSimplePropertiesTest { + + private val case = EntityTestCase( + ctor = EntityWithSimpleProperties.Companion::invoke + ) + + @Test + fun `string value`() { + val json = """{ "string": "Some text" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals("Some text", entity.string!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `integer value`() { + val json = """{ "integer": 20 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(20, entity.integer!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `double value as integer`() { + // sometimes Moshi reads integers as doubles for some reason + val json = """{ "integer": 20.0 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(20, entity.integer!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `double value`() { + val json = """{ "double": 20.123 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(20.123, entity.double!!.evaluate(ExpressionResolver.EMPTY), 0.0) + } + + @Test + fun `integer value as double`() { + val json = """{ "double": 20 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(20.0, entity.double!!.evaluate(ExpressionResolver.EMPTY), 0.0) + } + + @Test + fun `positive integer value`() { + val json = """{ "positive_integer": 20 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(20, entity.positiveInteger!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `invalid positive integer value`() { + val json = """{ "positive_integer": 0 }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertNull(entity.positiveInteger) + } + + @Test + fun `1 as true`() { + val json = """{ "boolean": 1 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertTrue(entity.boolean!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `0 as false`() { + val json = """{ "boolean": 0 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertFalse(entity.boolean!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `random integer value as null`() { + val json = """{ "boolean": 123 }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertNull(entity.boolean) + } + + @Test + fun `double value as true`() { + // sometimes Moshi reads integers as doubles for some reason + val json = """{ "boolean": 1.0 }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertTrue(entity.boolean!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `Url value`() { + val json = """{ "url": "https://yandex.ru" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(Uri.parse("https://yandex.ru"), entity.url!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `Color without alpha value`() { + val json = """{ "color": "#BBCCDD" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(Color.parseColor("#BBCCDD"), entity.color!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `Color with alpha value`() { + val json = """{ "color": "#AABBCCDD" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(Color.parseColor("#AABBCCDD"), entity.color!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `invalid Color value`() { + val json = """{ "color": "#ABBCCDD" }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertNull(entity.color) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringArrayPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringArrayPropertyTest.kt new file mode 100644 index 000000000..38f4bb1cf --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringArrayPropertyTest.kt @@ -0,0 +1,101 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithStringArrayProperty +import org.hamcrest.Matchers.hasSize +import org.junit.Assert.assertEquals +import org.junit.Assert.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithStringArrayPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithStringArrayProperty.Companion::invoke + ) + + @Test + fun `valid array`() { + val json = """{ + "array": [ + "Some text 1", + "Some text 2" + ] + }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + val array = entity.array.evaluate(ExpressionResolver.EMPTY) + assertThat(array, hasSize(2)) + assertEquals("Some text 1", array[0]) + assertEquals("Some text 2", array[1]) + } + + @Test + fun `invalid object in array`() { + val json = """{ + "array": [ + "Some text 1", + 123, + "Some text 3" + ] + }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + val array = entity.array.evaluate(ExpressionResolver.EMPTY) + assertThat(array, hasSize(2)) + assertEquals("Some text 1", array[0]) + assertEquals("Some text 3", array[1]) + } + + @Test + fun `array of expressions`() { + val json = """{ + "array": [ + "@{expression_1}", + "@{expression_2}", + "@{expression_3}" + ] + }""" + + + val entity = case.parse(LOG_ENVIRONMENT, json) + val array = entity.array.evaluate(ExpressionResolver.EMPTY) + assertThat(array, hasSize(3)) + + val typeDefault = "" + assertEquals(typeDefault, array[0]) + assertEquals(typeDefault, array[1]) + assertEquals(typeDefault, array[2]) + } + + @Test + fun `mixed array from expressions and values`() { + val json = """{ + "array": [ + "@{expression_1}", + "Some Text 2", + "@{expression_3}" + ] + }""" + + + val entity = case.parse(LOG_ENVIRONMENT, json) + val array = entity.array.evaluate(ExpressionResolver.EMPTY) + assertThat(array, hasSize(3)) + + val typeDefault = "" + assertEquals(typeDefault, array[0]) + assertEquals("Some Text 2", array[1]) + assertEquals(typeDefault, array[2]) + } + + @Test(expected = ParsingException::class) + fun `null property value`() { + val json = """{ }""" + + case.parse(LOG_ENVIRONMENT, json) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyTest.kt new file mode 100644 index 000000000..ca273a9fb --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyTest.kt @@ -0,0 +1,34 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithStringEnumProperty +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithStringEnumPropertyTest { + + private val case = EntityTestCase( + ctor = EntityWithStringEnumProperty.Companion::invoke + ) + + @Test + fun `property value is set`() { + val json = """{ "property": "second" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(EntityWithStringEnumProperty.Property.SECOND, + entity.property.evaluate(ExpressionResolver.EMPTY)) + } + + @Test(expected = ParsingException::class) + fun `null property value`() { + val json = """{ }""" + + case.parse(LOG_ENVIRONMENT, json) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyWithDefaultValueTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyWithDefaultValueTest.kt new file mode 100644 index 000000000..914827720 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/EntityWithStringEnumPropertyWithDefaultValueTest.kt @@ -0,0 +1,56 @@ +package com.yandex.generator + +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.testing.EntityWithStringEnumPropertyWithDefaultValue +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class EntityWithStringEnumPropertyWithDefaultValueTest { + + private val case = EntityTestCase( + ctor = EntityWithStringEnumPropertyWithDefaultValue.Companion::invoke + ) + + @Test + fun `property value is set`() { + val json = """{ "value": "third" }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(EntityWithStringEnumPropertyWithDefaultValue.Value.THIRD, + entity.value.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `invalid value resolves as default value`() { + val json = """{ "value": "no value" }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertEquals(EntityWithStringEnumPropertyWithDefaultValue.Value.SECOND, + entity.value.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `invalid value type resolves as default value`() { + val json = """{ "value": [ "first" ] }""" + + val entity = case.parse(LOG_ENVIRONMENT, json) + + assertEquals(EntityWithStringEnumPropertyWithDefaultValue.Value.SECOND, + entity.value.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `null value resolves as default value`() { + val json = """{ }""" + + val entity = case.parse(ASSERT_ENVIRONMENT, json) + + assertEquals(EntityWithStringEnumPropertyWithDefaultValue.Value.SECOND, + entity.value.evaluate(ExpressionResolver.EMPTY)) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/Expected.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/Expected.kt new file mode 100644 index 000000000..0566a916b --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/Expected.kt @@ -0,0 +1,92 @@ +package com.yandex.generator + +import android.graphics.Color +import android.net.Uri +import com.yandex.div.json.expressions.ConstantExpressionsList +import com.yandex.div.json.expressions.Expression +import com.yandex.testing.Entity +import com.yandex.testing.EntityWithArray +import com.yandex.testing.EntityWithArrayOfNestedItems +import com.yandex.testing.EntityWithArrayWithTransform +import com.yandex.testing.EntityWithComplexProperty +import com.yandex.testing.EntityWithOptionalComplexProperty +import com.yandex.testing.EntityWithOptionalProperty +import com.yandex.testing.EntityWithOptionalStringEnumProperty +import com.yandex.testing.EntityWithRequiredProperty +import com.yandex.testing.EntityWithStrictArray +import com.yandex.testing.EntityWithStringEnumProperty + +internal val ENTITY_WITH_STRING_ENUM_PROPERTY = Entity.WithStringEnumProperty( + EntityWithStringEnumProperty(Expression.constant(EntityWithStringEnumProperty.Property.SECOND)) +) + +internal val ENTITY_WITH_OPTIONAL_STRING_ENUM_PROPERTY = Entity.WithOptionalStringEnumProperty( + EntityWithOptionalStringEnumProperty(Expression.constant(EntityWithOptionalStringEnumProperty.Property.SECOND)) +) +internal val ENTITY_WITH_MISSING_STRING_ENUM_PROPERTY = Entity.WithOptionalStringEnumProperty( + EntityWithOptionalStringEnumProperty(null) +) + +internal val ENTITY_WITH_REQUIRED_PROPERTY = Entity.WithRequiredProperty( + EntityWithRequiredProperty(Expression.constant("Some text")) +) + +internal val ENTITY_WITH_OPTIONAL_PROPERTY = Entity.WithOptionalProperty( + EntityWithOptionalProperty(Expression.constant("Some text")) +) + +internal val ENTITY_WITH_MISSING_OPTIONAL_PROPERTY = Entity.WithOptionalProperty( + EntityWithOptionalProperty(null) +) + +internal val ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY = Entity.WithComplexProperty( + EntityWithComplexProperty(EntityWithComplexProperty.Property(Expression.constant(Uri.parse("https://ya.ru")))) +) + +internal val ENTITY_WITH_OPTIONAL_COMPLEX_PROPERTY = Entity.WithOptionalComplexProperty( + EntityWithOptionalComplexProperty(EntityWithOptionalComplexProperty.Property(Expression.constant(Uri.parse("https://ya.ru")))) +) + +internal val ENTITY_WITH_MISSING_OPTIONAL_COMPLEX_PROPERTY = Entity.WithOptionalComplexProperty( + EntityWithOptionalComplexProperty(null) +) + +internal val ENTITY_WITH_ARRAY = Entity.WithArray( + EntityWithArray(listOf( + ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, + ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY + )) +) + +internal val ENTITY_WITH_HETEROGENOUS_ARRAY = Entity.WithArray( + EntityWithArray(listOf( + ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, + ENTITY_WITH_REQUIRED_PROPERTY, + ENTITY_WITH_STRING_ENUM_PROPERTY + )) +) + +internal val ENTITY_WITH_NESTED_ARRAY = Entity.WithArray( + EntityWithArray(listOf(ENTITY_WITH_ARRAY)) +) + +internal val ENTITY_WITH_ARRAY_WITH_TRANSFORM = Entity.WithArrayWithTransform( + EntityWithArrayWithTransform(ConstantExpressionsList(listOf( + Color.parseColor("#FF00FF00"), + Color.parseColor("#AAFF0000") + ))) +) + +internal val ENTITY_WITH_ARRAY_OF_NESTED_ITEMS = Entity.WithArrayOfNestedItems( + EntityWithArrayOfNestedItems(listOf( + EntityWithArrayOfNestedItems.Item(ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, Expression.constant("Some text")), + EntityWithArrayOfNestedItems.Item(ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, Expression.constant("Some text")) + )) +) + +internal val ENTITY_WITH_STRICT_ARRAY = Entity.WithStrictArray( + EntityWithStrictArray(listOf( + ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY, + ENTITY_WITH_REQUIRED_COMPLEX_PROPERTY + )) +) diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalComplexPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalComplexPropertyTest.kt new file mode 100644 index 000000000..b7eba1b0c --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalComplexPropertyTest.kt @@ -0,0 +1,90 @@ +package com.yandex.generator + +import com.yandex.generator.ENTITY_WITH_MISSING_OPTIONAL_COMPLEX_PROPERTY +import com.yandex.generator.ENTITY_WITH_OPTIONAL_COMPLEX_PROPERTY +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class OptionalComplexPropertyTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `optional complex property with reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_with_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `optional complex property without reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_without_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `optional complex property with internal reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_with_internal_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `when data for optional complex property with reference is missing entity created`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_with_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `when data for optional complex property without reference is missing entity created`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_without_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `when data for optional complex property with internal reference is missing entity created`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_with_internal_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `optional complex property without template is parsed correctly`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_complex_property_not_templated.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_COMPLEX_PROPERTY, actual) + } + + @Test + fun `when optional complex property is invalid entity created`() { + val actual = case.parse( + directory = "optional_complex_property", + filename = "test_optional_invalid_complex_property_not_templated.json" + ) + assertEquals(ENTITY_WITH_MISSING_OPTIONAL_COMPLEX_PROPERTY, actual) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalPropertyTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalPropertyTest.kt new file mode 100644 index 000000000..ccbb510db --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalPropertyTest.kt @@ -0,0 +1,72 @@ +package com.yandex.generator + +import com.yandex.generator.ENTITY_WITH_MISSING_OPTIONAL_PROPERTY +import com.yandex.generator.ENTITY_WITH_OPTIONAL_PROPERTY +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class OptionalPropertyTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `optional property with reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_property", + filename = "test_optional_property_with_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_PROPERTY, actual) + } + + @Test + fun `optional property without reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_property", + filename = "test_optional_property_without_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_PROPERTY, actual) + } + + @Test + fun `missing optional property with reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_property", + filename = "test_optional_property_with_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_OPTIONAL_PROPERTY, actual) + } + + @Test + fun `missing optional property without reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_property", + filename = "test_optional_property_without_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_OPTIONAL_PROPERTY, actual) + } + + @Test + fun `optional property with override is parsed correctly`() { + val actual = case.parse( + directory = "optional_property", + filename = "test_optional_property_with_override.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_PROPERTY, actual) + } + + @Test + fun `optional property without template is parsed correctly`() { + val actual = case.parse( + directory = "optional_property", + filename = "test_optional_property_not_templated.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_PROPERTY, actual) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalStringEnumTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalStringEnumTest.kt new file mode 100644 index 000000000..8e8736cfb --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/OptionalStringEnumTest.kt @@ -0,0 +1,72 @@ +package com.yandex.generator + +import com.yandex.generator.ENTITY_WITH_MISSING_STRING_ENUM_PROPERTY +import com.yandex.generator.ENTITY_WITH_OPTIONAL_STRING_ENUM_PROPERTY +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class OptionalStringEnumTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `optional string enum property with reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_string_enum_property", + filename = "test_optional_string_enum_property_with_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `optional string enum property without reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_string_enum_property", + filename = "test_optional_string_enum_property_without_link.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `missing optional string enum property with reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_string_enum_property", + filename = "test_optional_string_enum_property_with_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `missing optional string enum property without reference is parsed correctly`() { + val actual = case.parse( + directory = "optional_string_enum_property", + filename = "test_optional_string_enum_property_without_link_missing_data.json" + ) + assertEquals(ENTITY_WITH_MISSING_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `string optional enum property with override is parsed correctly`() { + val actual = case.parse( + directory = "optional_string_enum_property", + filename = "test_optional_string_enum_property_with_override.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `string optional enum property without template is parsed correctly`() { + val actual = case.parse( + directory = "optional_string_enum_property", + filename = "test_optional_string_enum_property_not_templated.json" + ) + assertEquals(ENTITY_WITH_OPTIONAL_STRING_ENUM_PROPERTY, actual) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/ParsingErrorLoggerTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/ParsingErrorLoggerTest.kt new file mode 100644 index 000000000..415922714 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/ParsingErrorLoggerTest.kt @@ -0,0 +1,181 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingErrorLogger +import com.yandex.div.json.ParsingException +import com.yandex.div.json.summary +import com.yandex.testing.EntityWithOptionalProperty +import com.yandex.testing.EntityWithRequiredProperty +import com.yandex.testing.EntityWithOptionalComplexProperty +import org.json.JSONObject +import org.junit.Assert.assertEquals +import org.junit.Ignore +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyZeroInteractions +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ParsingErrorLoggerTest { + + private val logger = mock() + private val environment = EntityParsingEnvironment(logger = logger) + private val exceptionCaptor = argumentCaptor() + + private val exception: ParsingException + get() = exceptionCaptor.firstValue + + @Test + fun `error when optional property has invalid value`() { + val json = JSONObject("""{ "property": 123 }""") + + EntityWithOptionalProperty(environment, json) + + verify(logger).logError(exceptionCaptor.capture()) + assertEquals( + "Value for key 'property' has wrong type java.lang.Integer", + exception.message + ) + assertEquals(json.summary(), exception.jsonSummary) + } + + @Test + fun `no error when optional property has null value`() { + val json = JSONObject("""{ "property": null }""") + + EntityWithOptionalProperty(environment, json) + + verifyZeroInteractions(logger) + } + + @Test + fun `error when optional complex property has has null value`() { + val json = JSONObject("""{ "property": { "value": null } }""") + + try { + EntityWithOptionalComplexProperty(environment, json) + } catch (e: ParsingException) { + // expected + } + + verify(logger).logError(exceptionCaptor.capture()) + assertEquals( + "Value for key 'value' is missing", + exception.message + ) + assertEquals(json.getJSONObject("property").summary(), exception.jsonSummary) + } + + @Test + fun `no error when required property has invalid value`() { + val json = JSONObject("""{ "property": 123 }""") + + try { + EntityWithRequiredProperty(environment, json) + } catch (e: ParsingException) { + // expected + } + + verifyZeroInteractions(logger) + } + + @Test + fun `no error when required property has null value`() { + val json = JSONObject("""{ "property": null }""") + + try { + EntityWithRequiredProperty(environment, json) + } catch (e: ParsingException) { + // expected + } + + verifyZeroInteractions(logger) + } + + @Ignore + @Test + fun `error when template without type`() { + val json = JSONObject("""{ "template1": { } }""") + + environment.parseTemplates(json) + + verify(logger).logTemplateError(exceptionCaptor.capture(), eq("template1")) + assertEquals( + "Value for key 'type' is missing", + exception.message + ) + assertEquals(json.getJSONObject("template1").summary(), exception.jsonSummary) + } + + @Test + fun `error when template has invalid optional property value`() { + val json = JSONObject( + """{ + "template1": { + "type": "entity_with_optional_property", + "property": 123 + } + }""" + ) + + environment.parseTemplates(json) + + verify(logger).logTemplateError(exceptionCaptor.capture(), eq("template1")) + assertEquals( + "Value for key 'property' has wrong type java.lang.Integer", + exception.message + ) + assertEquals(json.getJSONObject("template1").summary(), exception.jsonSummary) + } + + @Test + fun `error when template has invalid link`() { + val json = JSONObject( + """{ + "template1": { + "type": "entity_with_optional_property", + "${'$'}property": 123 + } + }""" + ) + + environment.parseTemplates(json) + + verify(logger).logTemplateError(exceptionCaptor.capture(), eq("template1")) + assertEquals( + "Value for key '\$property' has wrong type java.lang.Integer", + exception.message + ) + assertEquals(json.getJSONObject("template1").summary(), exception.jsonSummary) + } + + @Test + fun `multiple errors when errors in multiple templates`() { + val json = JSONObject( + """{ + "template1": { + "type": "entity_with_optional_property", + "property": 123 + }, + "template2": { + "type": "entity_with_optional_property", + "property": 123 + } + }""" + ) + + environment.parseTemplates(json) + + val templateIdCaptor = argumentCaptor() + verify(logger, times(2)).logTemplateError(any(), templateIdCaptor.capture()) + + val ids = templateIdCaptor.allValues + assertEquals("template1", ids[0]) + assertEquals("template2", ids[1]) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/SimplePropertiesTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/SimplePropertiesTest.kt new file mode 100644 index 000000000..9f8b78edd --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/SimplePropertiesTest.kt @@ -0,0 +1,47 @@ +package com.yandex.generator + +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.EntityWithSimpleProperties +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class SimplePropertiesTest { + + private val case = EntityTemplateTestCase( + ctor = EntityWithSimpleProperties.Companion::invoke + ) + + @Test + fun `boolean as int`() { + val actual = case.parse( + directory = "simple_properties", + filename = "boolean_as_int.json" + ) + // TODO: boolean property represented by integer value must fail + // Assert.assertNull(actual.boolean!!.evaluate(ExpressionResolver.EMPTY)) + Assert.assertTrue(actual.boolean!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `boolean_int as boolean`() { + val actual = case.parse( + directory = "simple_properties", + filename = "boolean_int_as_boolean.json" + ) + Assert.assertTrue(actual.booleanInt!!.evaluate(ExpressionResolver.EMPTY)) + } + + @Test + fun `boolean_int as int`() { + val actual = case.parse( + directory = "simple_properties", + filename = "boolean_int_as_int.json" + ) + Assert.assertTrue(actual.booleanInt!!.evaluate(ExpressionResolver.EMPTY)) + } + +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/StrictArrayTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/StrictArrayTest.kt new file mode 100644 index 000000000..8d0fa5c90 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/StrictArrayTest.kt @@ -0,0 +1,84 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.generator.ENTITY_WITH_STRICT_ARRAY +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class StrictArrayTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `strict array is parsed correctly`() { + val actual = case.parse( + directory = "strict_array", + filename = "test_strict_array_happy_case.json" + ) + assertEquals(ENTITY_WITH_STRICT_ARRAY, actual) + } + + @Test + fun `referenced strict array is parsed correctly`() { + val actual = case.parse( + directory = "strict_array", + filename = "test_strict_array_happy_case_referenced.json" + ) + assertEquals(ENTITY_WITH_STRICT_ARRAY, actual) + } + + @Test(expected = ParsingException::class) + fun `strict array with non-object item parsing failed`() { + case.parse( + directory = "strict_array", + filename = "test_strict_array_with_non_object_item.json" + ) + } + + @Test(expected = ParsingException::class) + fun `referenced strict array with non-object item parsing failed`() { + case.parse( + directory = "strict_array", + filename = "test_referenced_strict_array_with_non_object_item.json" + ) + } + + @Test(expected = ParsingException::class) + fun `strict array with non-resolvable item parsing failed`() { + case.parse( + directory = "strict_array", + filename = "test_strict_array_with_non_resolvable_item.json" + ) + } + + @Test(expected = ParsingException::class) + fun `referenced strict array with non-resolvable item parsing failed`() { + case.parse( + directory = "strict_array", + filename = "test_referenced_strict_array_with_non_resolvable_item.json" + ) + } + + @Test(expected = ParsingException::class) + fun `strict array with non-object item reference parsing failed`() { + case.parse( + directory = "strict_array", + filename = "test_strict_array_with_non_object_item_ref.json" + ) + } + + @Test(expected = ParsingException::class) + fun `strict array with non-resolvable item reference parsing failed`() { + case.parse( + directory = "strict_array", + filename = "test_strict_array_with_non_resolvable_item_ref.json" + ) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/StringEnumTest.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/StringEnumTest.kt new file mode 100644 index 000000000..236a89fb5 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/StringEnumTest.kt @@ -0,0 +1,70 @@ +package com.yandex.generator + +import com.yandex.div.json.ParsingException +import com.yandex.generator.ENTITY_WITH_STRING_ENUM_PROPERTY +import com.yandex.generator.EntityTemplateTestCase +import com.yandex.testing.Entity +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class StringEnumTest { + + private val case = EntityTemplateTestCase( + ctor = Entity.Companion::invoke + ) + + @Test + fun `string enum property with reference is parsed correctly`() { + val actual = case.parse( + directory = "string_enum_property", + filename = "test_string_enum_property_with_link.json" + ) + assertEquals(ENTITY_WITH_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `string enum property without reference is parsed correctly`() { + val actual = case.parse( + directory = "string_enum_property", + filename = "test_string_enum_property_without_link.json" + ) + assertEquals(ENTITY_WITH_STRING_ENUM_PROPERTY, actual) + } + + @Test(expected = ParsingException::class) + fun `missing string enum property with reference parsing fails`() { + case.parse( + directory = "string_enum_property", + filename = "test_string_enum_property_with_link_missing_data.json" + ) + } + + @Test(expected = ParsingException::class) + fun `missing string enum property without reference parsing fails`() { + case.parse( + directory = "string_enum_property", + filename = "test_string_enum_property_without_link_missing_data.json" + ) + } + + @Test + fun `string enum property with override is parsed correctly`() { + val actual = case.parse( + directory = "string_enum_property", + filename = "test_string_enum_property_with_override.json" + ) + assertEquals(ENTITY_WITH_STRING_ENUM_PROPERTY, actual) + } + + @Test + fun `string enum property without template is parsed correctly`() { + val actual = case.parse( + directory = "string_enum_property", + filename = "test_string_enum_property_not_templated.json" + ) + assertEquals(ENTITY_WITH_STRING_ENUM_PROPERTY, actual) + } +} diff --git a/client/android/api-generator-test/src/test/java/com/yandex/generator/TestApplication.kt b/client/android/api-generator-test/src/test/java/com/yandex/generator/TestApplication.kt new file mode 100644 index 000000000..d7c347175 --- /dev/null +++ b/client/android/api-generator-test/src/test/java/com/yandex/generator/TestApplication.kt @@ -0,0 +1,11 @@ +package com.yandex.generator + +import android.app.Application +import com.yandex.div.core.util.Assert + +class TestApplication : Application() { + + init { + Assert.setEnabled(true) + } +} diff --git a/client/android/api-generator-test/src/test/resources/robolectric.properties b/client/android/api-generator-test/src/test/resources/robolectric.properties new file mode 100644 index 000000000..5656756a5 --- /dev/null +++ b/client/android/api-generator-test/src/test/resources/robolectric.properties @@ -0,0 +1,2 @@ +sdk=28 +application=com.yandex.generator.TestApplication diff --git a/client/android/api-generator-test/testing-generator-config.json b/client/android/api-generator-test/testing-generator-config.json new file mode 100644 index 000000000..718a2a159 --- /dev/null +++ b/client/android/api-generator-test/testing-generator-config.json @@ -0,0 +1,8 @@ +{ + "lang": "kotlin", + "header": "// Generated code. Do not modify.\n\npackage com.yandex.testing\n\nimport android.graphics.Color\nimport android.net.Uri\nimport androidx.annotation.ColorInt\nimport com.yandex.div.json.*\nimport com.yandex.div.json.expressions.Expression\nimport com.yandex.div.json.expressions.ExpressionsList\nimport com.yandex.div.json.schema.*\nimport com.yandex.div.core.annotations.Mockable\nimport java.io.IOException\nimport java.util.BitSet\nimport org.json.JSONObject\n", + "kotlinAnnotations": [ + "@Mockable" + ], + "generateEquality": true +} diff --git a/client/android/div-json/src/main/java/com/yandex/div/json/ParsingConverters.kt b/client/android/div-json/src/main/java/com/yandex/div/json/ParsingConverters.kt index c91400e31..2aa65201d 100644 --- a/client/android/div-json/src/main/java/com/yandex/div/json/ParsingConverters.kt +++ b/client/android/div-json/src/main/java/com/yandex/div/json/ParsingConverters.kt @@ -4,7 +4,6 @@ package com.yandex.div.json import android.net.Uri import com.yandex.div.evaluable.types.Color -import java.lang.ClassCastException typealias Converter = (T) -> R @@ -17,8 +16,6 @@ internal inline fun Converter.tryConvert(value: T): R? { } } -val BOOLEAN_TO_INT: Converter = { value -> if (value) 1 else 0 } - val COLOR_INT_TO_STRING: Converter = { value -> Color(value).toString() } val STRING_TO_COLOR_INT: Converter = { value -> when (value) { @@ -32,7 +29,13 @@ val STRING_TO_COLOR_INT: Converter = { value -> val URI_TO_STRING: Converter = { uri -> uri.toString() } val STRING_TO_URI: Converter = { value -> Uri.parse(value) } -val NUMBER_TO_BOOLEAN: Converter = { n -> n.toBoolean() } +val ANY_TO_BOOLEAN: Converter = { value -> + when (value) { + is Number -> value.toBoolean() + is Boolean -> value + else -> throw ClassCastException("Received value of wrong type") + } +} val NUMBER_TO_DOUBLE: Converter = { n: Number -> n.toDouble() } val NUMBER_TO_INT: Converter = { n: Number -> n.toInt() } diff --git a/client/android/settings.gradle b/client/android/settings.gradle index 524b1c882..fd71da236 100644 --- a/client/android/settings.gradle +++ b/client/android/settings.gradle @@ -1,5 +1,6 @@ includeBuild('screenshot-test-plugin') +include ':api-generator-test' include ':assertion' include ':beacon' include ':div'