mirror of
https://github.com/divkit/divkit.git
synced 2026-05-07 20:02:32 +00:00
Added test-utils module
commit_hash:b2f6363829ef137dd628946b6ce84f3a6d76ad23
This commit is contained in:
+16
-9
@@ -650,9 +650,7 @@
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/BorderModifiers.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/BorderModifiers.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/Modifiers.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/Modifiers.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/SizeModifiers.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/SizeModifiers.kt",
|
||||
"client/android/compose/src/test/kotlin/com/yandex/div/compose/DivDataUtils.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivDataUtils.kt",
|
||||
"client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewTest.kt",
|
||||
"client/android/compose/src/test/kotlin/com/yandex/div/compose/ExpressionUtils.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/ExpressionUtils.kt",
|
||||
"client/android/compose/src/test/kotlin/com/yandex/div/compose/TestReporter.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/TestReporter.kt",
|
||||
"client/android/compose/src/test/kotlin/com/yandex/div/compose/actions/DivActionHandlerTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/actions/DivActionHandlerTest.kt",
|
||||
"client/android/compose/src/test/kotlin/com/yandex/div/compose/actions/SetVariableActionHandlerTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/actions/SetVariableActionHandlerTest.kt",
|
||||
@@ -838,12 +836,12 @@
|
||||
"client/android/div-evaluable/src/main/java/com/yandex/div/evaluable/types/Url.kt":"divkit/public/client/android/div-evaluable/src/main/java/com/yandex/div/evaluable/types/Url.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/EvaluableTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/EvaluableTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/FunctionTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/FunctionTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/Utils.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/Utils.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/function/DateTimeFunctionsTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/function/DateTimeFunctionsTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/function/FunctionImpl.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/function/FunctionImpl.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/function/FunctionValidatorTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/function/FunctionValidatorTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/internal/LiteralsEscaperTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/internal/LiteralsEscaperTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/internal/TokenizerTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/internal/TokenizerTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/multiplatform/SignaturesMultiplatformTest.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/multiplatform/SignaturesMultiplatformTest.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/repl/Command.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/repl/Command.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/repl/EvaluableRepl.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/repl/EvaluableRepl.kt",
|
||||
"client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/repl/EvaluableReplRuntime.kt":"divkit/public/client/android/div-evaluable/src/test/java/com/yandex/div/evaluable/repl/EvaluableReplRuntime.kt",
|
||||
@@ -1633,6 +1631,7 @@
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionResolverImplTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionResolverImplTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCase.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCase.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCaseUtils.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCaseUtils.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/SignaturesMultiplatformTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/SignaturesMultiplatformTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/local/RuntimeStoreFillerTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/local/RuntimeStoreFillerTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/local/RuntimeStoreImplTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/local/RuntimeStoreImplTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/expression/triggers/ConditionPartTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/expression/triggers/ConditionPartTest.kt",
|
||||
@@ -1714,7 +1713,6 @@
|
||||
"client/android/div/src/test/java/com/yandex/div/core/widget/GridContainerDsl.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/widget/GridContainerDsl.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/core/widget/GridContainerTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/core/widget/GridContainerTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/interactive/IntegrationMultiplatformTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/interactive/IntegrationMultiplatformTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/interactive/IntegrationTestCase.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/interactive/IntegrationTestCase.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/interactive/IntegrationTestLogger.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/interactive/IntegrationTestLogger.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/internal/storage/DataStorageTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/internal/storage/DataStorageTest.kt",
|
||||
"client/android/div/src/test/java/com/yandex/div/internal/viewpool/ProfilingSessionExtensionTest.kt":"divkit/public/client/android/div/src/test/java/com/yandex/div/internal/viewpool/ProfilingSessionExtensionTest.kt",
|
||||
@@ -16552,11 +16550,6 @@
|
||||
"client/android/divkit-regression-testing/src/main/res/values/styles.xml":"divkit/public/client/android/divkit-regression-testing/src/main/res/values/styles.xml",
|
||||
"client/android/divkit-regression-testing/src/test/java/com/yandex/divkit/regression/data/FakeScenariosDataSource.kt":"divkit/public/client/android/divkit-regression-testing/src/test/java/com/yandex/divkit/regression/data/FakeScenariosDataSource.kt",
|
||||
"client/android/divkit-regression-testing/src/test/java/com/yandex/divkit/regression/data/ScenariosRepositoryTest.kt":"divkit/public/client/android/divkit-regression-testing/src/test/java/com/yandex/divkit/regression/data/ScenariosRepositoryTest.kt",
|
||||
"client/android/expression-test-common/build.gradle":"divkit/public/client/android/expression-test-common/build.gradle",
|
||||
"client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/MultiplatformTestUtils.kt":"divkit/public/client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/MultiplatformTestUtils.kt",
|
||||
"client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/TestCaseOrError.kt":"divkit/public/client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/TestCaseOrError.kt",
|
||||
"client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/TestCaseParsingError.kt":"divkit/public/client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/TestCaseParsingError.kt",
|
||||
"client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/Utils.kt":"divkit/public/client/android/expression-test-common/src/main/java/com/yandex/div/test/expression/Utils.kt",
|
||||
"client/android/fonts/build.gradle":"divkit/public/client/android/fonts/build.gradle",
|
||||
"client/android/fonts/proguard-rules.pro":"divkit/public/client/android/fonts/proguard-rules.pro",
|
||||
"client/android/fonts/src/main/java/com/yandex/div/font/YandexSansDisplayDivTypefaceProvider.kt":"divkit/public/client/android/fonts/src/main/java/com/yandex/div/font/YandexSansDisplayDivTypefaceProvider.kt",
|
||||
@@ -16679,6 +16672,20 @@
|
||||
"client/android/screenshot-test-runtime/src/main/java/com/yandex/test/screenshot/TestFile.kt":"divkit/public/client/android/screenshot-test-runtime/src/main/java/com/yandex/test/screenshot/TestFile.kt",
|
||||
"client/android/screenshot-test-runtime/src/main/java/com/yandex/test/screenshot/ViewRasterizer.kt":"divkit/public/client/android/screenshot-test-runtime/src/main/java/com/yandex/test/screenshot/ViewRasterizer.kt",
|
||||
"client/android/settings.gradle":"divkit/public/client/android/settings.gradle",
|
||||
"client/android/test-utils/build.gradle.kts":"divkit/public/client/android/test-utils/build.gradle.kts",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/IntegrationTestCase.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/IntegrationTestCase.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/MultiplatformTestUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/MultiplatformTestUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/ParsingResult.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/ParsingResult.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/ParsingUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/crossplatform/ParsingUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivActionUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivActionUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivContainerUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivContainerUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivDataUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivDataUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivTextUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivTextUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivTriggerUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivTriggerUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivTypedValueUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivTypedValueUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivVariableUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/DivVariableUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/ExpressionUtils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/ExpressionUtils.kt",
|
||||
"client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/Utils.kt":"divkit/public/client/android/test-utils/src/main/kotlin/com/yandex/div/test/data/Utils.kt",
|
||||
"client/android/ui-test-common/build.gradle":"divkit/public/client/android/ui-test-common/build.gradle",
|
||||
"client/android/ui-test-common/src/main/java/com/yandex/test/idling/ActivityIdlingResource.kt":"divkit/public/client/android/ui-test-common/src/main/java/com/yandex/test/idling/ActivityIdlingResource.kt",
|
||||
"client/android/ui-test-common/src/main/java/com/yandex/test/idling/IdlingResources.kt":"divkit/public/client/android/ui-test-common/src/main/java/com/yandex/test/idling/IdlingResources.kt",
|
||||
|
||||
@@ -131,10 +131,10 @@ apiValidation {
|
||||
"divkit-demo-app",
|
||||
"divkit-perftests",
|
||||
"divkit-regression-testing",
|
||||
"expression-test-common",
|
||||
"lint-rules",
|
||||
"sample",
|
||||
"screenshot-test-runtime",
|
||||
"test-utils",
|
||||
"ui-test-common",
|
||||
]
|
||||
ignoredPackages += ["com.yandex.div.internal"]
|
||||
|
||||
@@ -29,6 +29,7 @@ dependencies {
|
||||
|
||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||
|
||||
testImplementation(project(":test-utils"))
|
||||
testImplementation(libs.androidx.compose.ui.test.junit4)
|
||||
testImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.yandex.div.compose
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import com.yandex.div.evaluable.types.Color
|
||||
import com.yandex.div2.ArrayValue
|
||||
import com.yandex.div2.ColorValue
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivActionSetVariable
|
||||
import com.yandex.div2.DivActionTyped
|
||||
import com.yandex.div2.DivTypedValue
|
||||
import com.yandex.div2.DivTrigger
|
||||
import com.yandex.div2.DivTrigger.Mode
|
||||
import com.yandex.div2.DivVariable
|
||||
import com.yandex.div2.IntegerValue
|
||||
import com.yandex.div2.IntegerVariable
|
||||
import com.yandex.div2.StrVariable
|
||||
import com.yandex.div2.StrValue
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
fun variable(name: String, value: Long): DivVariable {
|
||||
return DivVariable.Integer(IntegerVariable(name = name, value = constant(value)))
|
||||
}
|
||||
|
||||
fun variable(name: String, value: String): DivVariable {
|
||||
return DivVariable.Str(StrVariable(name = name, value = constant(value)))
|
||||
}
|
||||
|
||||
fun action(
|
||||
typed: DivActionTyped? = null,
|
||||
payload: JSONObject? = null,
|
||||
url: String? = null,
|
||||
): DivAction {
|
||||
return DivAction(
|
||||
logId = constant("test"),
|
||||
payload = payload,
|
||||
typed = typed,
|
||||
url = url?.let { constant(it.toUri()) }
|
||||
)
|
||||
}
|
||||
|
||||
fun setVariableAction(name: String, value: DivTypedValue): DivActionTyped {
|
||||
return DivActionTyped.SetVariable(
|
||||
DivActionSetVariable(value = value, variableName = constant(name))
|
||||
)
|
||||
}
|
||||
|
||||
fun typedValue(value: String): DivTypedValue {
|
||||
return DivTypedValue.Str(StrValue(value = constant(value)))
|
||||
}
|
||||
|
||||
fun typedValue(value: Long): DivTypedValue {
|
||||
return DivTypedValue.Integer(IntegerValue(value = constant(value)))
|
||||
}
|
||||
|
||||
fun typedValue(value: JSONArray): DivTypedValue {
|
||||
return DivTypedValue.Array(ArrayValue(value = constant(value)))
|
||||
}
|
||||
|
||||
fun typedColorValue(value: Long): DivTypedValue {
|
||||
return DivTypedValue.Color(ColorValue(value = constant(value.toInt())))
|
||||
}
|
||||
|
||||
fun color(value: Long) = Color(value.toInt())
|
||||
|
||||
fun trigger(
|
||||
action: DivAction,
|
||||
condition: String,
|
||||
mode: Mode = Mode.ON_CONDITION
|
||||
): DivTrigger {
|
||||
return DivTrigger(
|
||||
actions = listOf(action),
|
||||
condition = booleanExpression(condition),
|
||||
mode = constant(mode)
|
||||
)
|
||||
}
|
||||
@@ -11,12 +11,15 @@ import androidx.compose.ui.test.performClick
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.yandex.div.core.expression.variables.DivVariableController
|
||||
import com.yandex.div.data.Variable
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div.test.data.constant
|
||||
import com.yandex.div.test.data.container
|
||||
import com.yandex.div.test.data.data
|
||||
import com.yandex.div.test.data.expression
|
||||
import com.yandex.div.test.data.text
|
||||
import com.yandex.div.test.data.trigger
|
||||
import com.yandex.div.test.data.variable
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivContainer
|
||||
import com.yandex.div2.DivData
|
||||
import com.yandex.div2.DivText
|
||||
import com.yandex.div2.DivTrigger
|
||||
import com.yandex.div2.DivVariable
|
||||
import org.junit.Rule
|
||||
@@ -210,51 +213,3 @@ class DivViewTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun data(
|
||||
content: Div,
|
||||
triggers: List<DivTrigger>? = null,
|
||||
variables: List<DivVariable>? = null
|
||||
): DivData {
|
||||
return DivData(
|
||||
logId = "test",
|
||||
states = listOf(
|
||||
DivData.State(
|
||||
stateId = 0,
|
||||
div = content
|
||||
)
|
||||
),
|
||||
variables = variables,
|
||||
variableTriggers = triggers,
|
||||
)
|
||||
}
|
||||
|
||||
private fun text(
|
||||
action: DivAction? = null,
|
||||
id: String? = null,
|
||||
text: Expression<String>,
|
||||
triggers: List<DivTrigger>? = null,
|
||||
variables: List<DivVariable>? = null
|
||||
): Div {
|
||||
return Div.Text(
|
||||
value = DivText(
|
||||
action = action,
|
||||
id = id,
|
||||
text = text,
|
||||
variables = variables,
|
||||
variableTriggers = triggers
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun container(
|
||||
items: List<Div>,
|
||||
variables: List<DivVariable>? = null
|
||||
): Div {
|
||||
return Div.Container(
|
||||
value = DivContainer(
|
||||
items = items,
|
||||
variables = variables
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@ package com.yandex.div.compose.actions
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.yandex.div.compose.TestReporter
|
||||
import com.yandex.div.compose.action
|
||||
import com.yandex.div.compose.expressions.DivComposeExpressionResolver
|
||||
import com.yandex.div.core.expression.variables.DivVariableController
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivActionCustom
|
||||
import com.yandex.div2.DivActionTyped
|
||||
|
||||
+5
-5
@@ -2,14 +2,14 @@ package com.yandex.div.compose.actions
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.yandex.div.compose.TestReporter
|
||||
import com.yandex.div.compose.action
|
||||
import com.yandex.div.compose.color
|
||||
import com.yandex.div.compose.expressions.DivComposeExpressionResolver
|
||||
import com.yandex.div.compose.setVariableAction
|
||||
import com.yandex.div.compose.typedColorValue
|
||||
import com.yandex.div.compose.typedValue
|
||||
import com.yandex.div.core.expression.variables.DivVariableController
|
||||
import com.yandex.div.data.Variable
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div.test.data.color
|
||||
import com.yandex.div.test.data.setVariableAction
|
||||
import com.yandex.div.test.data.typedColorValue
|
||||
import com.yandex.div.test.data.typedValue
|
||||
import com.yandex.div2.DivAction
|
||||
import org.json.JSONArray
|
||||
import org.junit.Assert.assertEquals
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@ package com.yandex.div.compose.expressions
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.yandex.div.compose.TestReporter
|
||||
import com.yandex.div.compose.expression
|
||||
import com.yandex.div.core.expression.variables.DivVariableController
|
||||
import com.yandex.div.data.Variable
|
||||
import com.yandex.div.test.data.expression
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
package com.yandex.div.compose.triggers
|
||||
|
||||
import com.yandex.div.compose.TestReporter
|
||||
import com.yandex.div.compose.action
|
||||
import com.yandex.div.compose.actions.DivActionHandler
|
||||
import com.yandex.div.compose.actions.DivActionHandlingContext
|
||||
import com.yandex.div.compose.expressions.DivComposeExpressionResolver
|
||||
import com.yandex.div.compose.trigger
|
||||
import com.yandex.div.core.expression.variables.DivVariableController
|
||||
import com.yandex.div.data.Variable
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div.test.data.trigger
|
||||
import com.yandex.div2.DivTrigger.Mode
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
+1
-1
@@ -10,12 +10,12 @@ import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.yandex.div.compose.TestReporter
|
||||
import com.yandex.div.compose.expressions.DivComposeExpressionResolver
|
||||
import com.yandex.div.compose.intExpression
|
||||
import com.yandex.div.compose.views.DivLocalContext
|
||||
import com.yandex.div.compose.views.LocalDivContext
|
||||
import com.yandex.div.core.expression.variables.DivVariableController
|
||||
import com.yandex.div.data.Variable
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.test.data.intExpression
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@@ -74,8 +74,6 @@ dependencies {
|
||||
generatorCompileOnly libs.json
|
||||
generatorImplementation libs.kotlinpoet
|
||||
|
||||
testImplementation project(path: ':expression-test-common')
|
||||
|
||||
testImplementation libs.json
|
||||
testImplementation libs.junit
|
||||
testImplementation libs.mockito.kotlin
|
||||
|
||||
-8
@@ -2,7 +2,6 @@ package com.yandex.div.evaluable.function
|
||||
|
||||
import com.yandex.div.evaluable.EvaluableType
|
||||
import com.yandex.div.evaluable.Function
|
||||
import com.yandex.div.evaluable.FunctionArgument
|
||||
import com.yandex.div.evaluable.FunctionProvider
|
||||
|
||||
@Deprecated(
|
||||
@@ -318,11 +317,4 @@ internal object BuiltinFunctionProvider : FunctionProvider {
|
||||
override fun getMethod(name: String, args: List<EvaluableType>): Function {
|
||||
return registry.getMethod(name, args)
|
||||
}
|
||||
|
||||
internal fun ensureFunctionRegistered(name: String,
|
||||
args: List<FunctionArgument>,
|
||||
resultType: EvaluableType,
|
||||
isMethod: Boolean,) {
|
||||
registry.ensureRegistered(name, args, resultType, isMethod)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.yandex.div.evaluable
|
||||
|
||||
import com.yandex.div.evaluable.function.GeneratedBuiltinFunctionProvider
|
||||
import com.yandex.div.test.expression.withEvaluator
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yandex.div.evaluable
|
||||
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
fun <T> withEvaluator(
|
||||
evaluationContext: EvaluationContext,
|
||||
block: Evaluator.() -> T
|
||||
) = run {
|
||||
val warnings = mutableListOf<String>()
|
||||
val evaluator = Evaluator(
|
||||
EvaluationContext(
|
||||
variableProvider = evaluationContext.variableProvider,
|
||||
storedValueProvider = evaluationContext.storedValueProvider,
|
||||
functionProvider = evaluationContext.functionProvider,
|
||||
warningSender = { expressionContext, message ->
|
||||
warnings.add(message)
|
||||
evaluationContext.warningSender.send(expressionContext, message)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
block(evaluator).also {
|
||||
assertTrue(warnings.isEmpty())
|
||||
}
|
||||
}
|
||||
+19
-10
@@ -9,8 +9,13 @@ import com.yandex.div.evaluable.function.GeneratedBuiltinFunctionProvider
|
||||
import com.yandex.div.evaluable.internal.Parser
|
||||
import com.yandex.div.evaluable.internal.Token
|
||||
import com.yandex.div.evaluable.internal.Tokenizer
|
||||
import com.yandex.div.test.expression.parseAsUTC
|
||||
import com.yandex.div.test.expression.withEvaluator
|
||||
import com.yandex.div.evaluable.types.DateTime
|
||||
import com.yandex.div.evaluable.withEvaluator
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
internal object EvaluableReplRuntime {
|
||||
private val variableProvider = VariableProvider { variableName -> variableList[variableName] }
|
||||
@@ -65,12 +70,7 @@ internal object EvaluableReplRuntime {
|
||||
fun evaluateExpression(expression: String) {
|
||||
val evaluable = parseEvaluable(expression) ?: return
|
||||
try {
|
||||
withEvaluator(
|
||||
evaluationContext,
|
||||
warningsValidator = { warnings ->
|
||||
warnings.forEach { println("Warning: $it") }
|
||||
}
|
||||
) {
|
||||
withEvaluator(evaluationContext) {
|
||||
eval<Any?>(evaluable).also { println(it) }
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
@@ -109,7 +109,7 @@ internal object EvaluableReplRuntime {
|
||||
|
||||
private fun String.getNewVariableValue(): Pair<String, Any> {
|
||||
val (_, name, type, value) = variableAssigningRegex.matchEntire(this.minifySpaces())!!.groupValues
|
||||
val evaluableType = EvaluableType.values().find { it.typeName.lowercase() == type.lowercase() }
|
||||
val evaluableType = EvaluableType.values().find { it.typeName.equals(type, ignoreCase = true) }
|
||||
?: throw RuntimeException("Unknown type $type.")
|
||||
return try {
|
||||
val convertedValue = when (evaluableType) {
|
||||
@@ -118,7 +118,7 @@ internal object EvaluableReplRuntime {
|
||||
EvaluableType.BOOLEAN -> value.toBoolean()
|
||||
EvaluableType.STRING -> value
|
||||
EvaluableType.COLOR -> value
|
||||
EvaluableType.DATETIME -> parseAsUTC(value)
|
||||
EvaluableType.DATETIME -> parseDateTime(value)
|
||||
EvaluableType.URL -> value
|
||||
EvaluableType.DICT -> value
|
||||
EvaluableType.ARRAY -> value
|
||||
@@ -151,3 +151,12 @@ internal object EvaluableReplRuntime {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseDateTime(utcString: String): DateTime {
|
||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefault())
|
||||
val date: Date = dateFormat.parse(utcString)!!
|
||||
return DateTime(
|
||||
timestampMillis = date.time + Calendar.getInstance().timeZone.rawOffset,
|
||||
timezone = TimeZone.getTimeZone("UTC"),
|
||||
)
|
||||
}
|
||||
|
||||
-14
@@ -1,6 +1,5 @@
|
||||
package com.yandex.div.evaluable.types
|
||||
|
||||
import com.yandex.div.test.expression.parseAsUTC
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.util.TimeZone
|
||||
@@ -23,19 +22,6 @@ class DateTimeTest {
|
||||
DateTime(timestampMillis = 101010, TimeZone.getDefault()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parsing initial date from string`() {
|
||||
val dateTime = parseAsUTC("1970-01-01 00:00:00")
|
||||
Assert.assertEquals(0, dateTime.timezoneMinutes)
|
||||
Assert.assertEquals(0, dateTime.timestampMillis)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `timestamp stored in millis`() {
|
||||
val dateTime = parseAsUTC("1970-01-01 00:00:01")
|
||||
Assert.assertEquals(1000, dateTime.timestampMillis)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `string representation does not include timezone in it`() {
|
||||
val dateTime = DateTime(timestampMillis = 5000, TimeZone.getTimeZone("UTC"))
|
||||
|
||||
@@ -69,7 +69,7 @@ dependencies {
|
||||
exclude group: "androidx.fragment", module: "fragment"
|
||||
}
|
||||
|
||||
testImplementation project(path: ':expression-test-common')
|
||||
testImplementation project(path: ':test-utils')
|
||||
|
||||
testImplementation libs.androidx.test.coreKtx
|
||||
testImplementation libs.json
|
||||
|
||||
@@ -8,19 +8,16 @@ import com.yandex.div.core.view2.Div2View
|
||||
import com.yandex.div.core.view2.disableAssertions
|
||||
import com.yandex.div.data.Variable
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div.test.data.container
|
||||
import com.yandex.div.test.data.setVariableAction
|
||||
import com.yandex.div.test.data.typedValue
|
||||
import com.yandex.div2.DivActionArrayInsertValue
|
||||
import com.yandex.div2.DivActionArrayRemoveValue
|
||||
import com.yandex.div2.DivActionArraySetValue
|
||||
import com.yandex.div2.DivActionDictSetValue
|
||||
import com.yandex.div2.DivActionSetVariable
|
||||
import com.yandex.div2.DivActionTyped
|
||||
import com.yandex.div2.DivContainer
|
||||
import com.yandex.div2.DivData
|
||||
import com.yandex.div2.DivTypedValue
|
||||
import com.yandex.div2.IntegerValue
|
||||
import com.yandex.div2.StrValue
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert
|
||||
@@ -44,7 +41,7 @@ class DivActionHandlerTest {
|
||||
)
|
||||
).apply {
|
||||
setData(
|
||||
DivData(logId = "id", states = listOf(DivData.State(Div.Container(DivContainer()), 0))),
|
||||
DivData(logId = "id", states = listOf(DivData.State(container(), 0))),
|
||||
DivDataTag("id")
|
||||
)
|
||||
}
|
||||
@@ -96,12 +93,7 @@ class DivActionHandlerTest {
|
||||
setVariable("string_var", "value")
|
||||
|
||||
val isHandled = handleTypedAction(
|
||||
DivActionTyped.SetVariable(
|
||||
DivActionSetVariable(
|
||||
value = typedValue("new value"),
|
||||
variableName = Expression.constant("string_var")
|
||||
)
|
||||
)
|
||||
setVariableAction(name = "string_var", value = typedValue("new value"))
|
||||
)
|
||||
|
||||
Assert.assertTrue(isHandled)
|
||||
@@ -111,12 +103,7 @@ class DivActionHandlerTest {
|
||||
@Test
|
||||
fun `SetVariable action does not add new variable`() {
|
||||
val isHandled = handleTypedAction(
|
||||
DivActionTyped.SetVariable(
|
||||
DivActionSetVariable(
|
||||
value = typedValue("new value"),
|
||||
variableName = Expression.constant("string_var")
|
||||
)
|
||||
)
|
||||
setVariableAction(name = "string_var", value = typedValue("new value"))
|
||||
)
|
||||
|
||||
Assert.assertTrue(isHandled)
|
||||
@@ -128,12 +115,7 @@ class DivActionHandlerTest {
|
||||
setVariable("string_var", "value")
|
||||
|
||||
val isHandled = handleTypedAction(
|
||||
DivActionTyped.SetVariable(
|
||||
DivActionSetVariable(
|
||||
value = typedValue(123),
|
||||
variableName = Expression.constant("string_var")
|
||||
)
|
||||
)
|
||||
setVariableAction(name = "string_var", value = typedValue(123))
|
||||
)
|
||||
|
||||
Assert.assertTrue(isHandled)
|
||||
@@ -514,10 +496,7 @@ class DivActionHandlerTest {
|
||||
|
||||
private fun handleTypedAction(action: DivActionTyped): Boolean {
|
||||
return underTest.handleAction(
|
||||
DivAction(
|
||||
logId = Expression.constant("log_id"),
|
||||
typed = action
|
||||
),
|
||||
action(typed = action),
|
||||
divView,
|
||||
divView.expressionResolver
|
||||
)
|
||||
@@ -544,12 +523,4 @@ class DivActionHandlerTest {
|
||||
Variable.DictVariable(name = name, defaultValue = value)
|
||||
)
|
||||
}
|
||||
|
||||
private fun typedValue(value: String): DivTypedValue {
|
||||
return DivTypedValue.Str(StrValue(Expression.constant(value)))
|
||||
}
|
||||
|
||||
private fun typedValue(value: Long): DivTypedValue {
|
||||
return DivTypedValue.Integer(IntegerValue(Expression.constant(value)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ import com.yandex.div.core.player.DivPlayerPreloader
|
||||
import com.yandex.div.core.preload.PreloadResult
|
||||
import com.yandex.div.core.view2.DivImagePreloader
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.test.data.constant
|
||||
import com.yandex.div.test.data.text
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivContainer
|
||||
import com.yandex.div2.DivCustom
|
||||
import com.yandex.div2.DivExtension
|
||||
import com.yandex.div2.DivInput
|
||||
import com.yandex.div2.DivSeparator
|
||||
import com.yandex.div2.DivText
|
||||
import com.yandex.div2.DivVideo
|
||||
import com.yandex.div2.DivVideoSource
|
||||
import org.junit.Test
|
||||
@@ -43,8 +44,7 @@ class DivPreloaderTest {
|
||||
private val extensionHandlers = listOf<DivExtensionHandler>(mock(), mock())
|
||||
private val extensionHandlersController = DivExtensionController(extensionHandlers)
|
||||
|
||||
private val text = DivText(text = Expression.constant("test"))
|
||||
private val divText = Div.Text(text)
|
||||
private val divText = text(text = constant("test"))
|
||||
|
||||
private val custom = DivCustom(customType = "test")
|
||||
private val divCustom = Div.Custom(custom)
|
||||
|
||||
+25
-21
@@ -12,11 +12,11 @@ import com.yandex.div.core.view2.divs.DivActionBinder
|
||||
import com.yandex.div.core.view2.errors.ErrorCollector
|
||||
import com.yandex.div.internal.expressions.DivExpressionParser
|
||||
import com.yandex.div.internal.util.UiThreadHandler
|
||||
import com.yandex.div.internal.util.map
|
||||
import com.yandex.div.json.ParsingErrorLogger
|
||||
import com.yandex.div.rule.LocaleRule
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.toSortedList
|
||||
import com.yandex.div.test.expression.TestCaseOrError
|
||||
import com.yandex.div.test.crossplatform.MultiplatformTestUtils
|
||||
import com.yandex.div.test.crossplatform.ParsingResult
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.junit.After
|
||||
@@ -26,16 +26,17 @@ import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class EvaluableMultiplatformTest(private val caseOrError: TestCaseOrError<ExpressionTestCase>) {
|
||||
class EvaluableMultiplatformTest(
|
||||
private val caseParsingResult: ParsingResult<ExpressionTestCase>
|
||||
) {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
@get:Rule
|
||||
val localeRule = LocaleRule()
|
||||
|
||||
private lateinit var testCase: ExpressionTestCase
|
||||
@@ -49,10 +50,9 @@ class EvaluableMultiplatformTest(private val caseOrError: TestCaseOrError<Expres
|
||||
|
||||
private val warnings = mutableListOf<String>()
|
||||
private val errors = mutableListOf<String>()
|
||||
private val warningCaptor = argumentCaptor<Throwable>()
|
||||
private val errorCollector = mock<ErrorCollector> {
|
||||
on { logWarning(warningCaptor.capture()) } doAnswer {
|
||||
warningCaptor.lastValue.cause?.message?.let { warnings += it }
|
||||
on { logWarning(any()) } doAnswer { answer ->
|
||||
(answer.arguments.first() as Throwable).cause?.message?.let { warnings += it }
|
||||
}
|
||||
}
|
||||
private val testParsingLogger = ParsingErrorLogger { e ->
|
||||
@@ -72,7 +72,12 @@ class EvaluableMultiplatformTest(private val caseOrError: TestCaseOrError<Expres
|
||||
|
||||
warnings.clear()
|
||||
errors.clear()
|
||||
testCase = caseOrError.getCaseOrThrow()
|
||||
|
||||
when (caseParsingResult) {
|
||||
is ParsingResult.Success -> testCase = caseParsingResult.value
|
||||
is ParsingResult.Error -> caseParsingResult.throwException()
|
||||
}
|
||||
|
||||
val testDivData = createDivDataFromTestVars(testCase.variables, testCase.functions, testParsingLogger)
|
||||
|
||||
runtimeProvider = ExpressionsRuntimeProvider(
|
||||
@@ -111,8 +116,8 @@ class EvaluableMultiplatformTest(private val caseOrError: TestCaseOrError<Expres
|
||||
is JSONArray, is JSONObject -> {
|
||||
if (testCase.expectedType == VALUE_TYPE_UNORDERED_ARRAY){
|
||||
checkEquality(testCase) { message, expected, actual ->
|
||||
val expectedList = (expected as JSONArray).toSortedList()
|
||||
val actualList = (actual as JSONArray).toSortedList()
|
||||
val expectedList = (expected as JSONArray).map { toString() }.sorted()
|
||||
val actualList = (actual as JSONArray).map { toString() }.sorted()
|
||||
Assert.assertEquals(message, expectedList.toString(), actualList.toString())
|
||||
}
|
||||
} else {
|
||||
@@ -172,17 +177,16 @@ class EvaluableMultiplatformTest(private val caseOrError: TestCaseOrError<Expres
|
||||
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
fun cases(): List<TestCaseOrError<ExpressionTestCase>> {
|
||||
val cases = mutableListOf<TestCaseOrError<ExpressionTestCase>>()
|
||||
val errors = MultiplatformTestUtils.walkJSONs(TEST_CASES_FILE_PATH) { file, jsonString ->
|
||||
val newCases = ExpressionTestCaseUtils.parseTestCases(JSONObject(jsonString), file.name)
|
||||
cases.addAll(newCases)
|
||||
}.map { TestCaseOrError<ExpressionTestCase>(it) }
|
||||
fun cases(): List<ParsingResult<ExpressionTestCase>> {
|
||||
val cases = mutableListOf<ParsingResult<ExpressionTestCase>>()
|
||||
val errors = MultiplatformTestUtils
|
||||
.walkJSONs(TEST_CASES_FILE_PATH) { file, jsonString ->
|
||||
val newCases = ExpressionTestCaseUtils.parseTestCases(JSONObject(jsonString), file.name)
|
||||
cases.addAll(newCases)
|
||||
}
|
||||
|
||||
val allCases = errors + cases
|
||||
|
||||
ExpressionTestCaseUtils.checkDuplicates(allCases.asSequence())
|
||||
|
||||
return allCases
|
||||
}
|
||||
}
|
||||
|
||||
+25
-79
@@ -6,16 +6,14 @@ import com.yandex.div.data.Variable
|
||||
import com.yandex.div.evaluable.EvaluableException
|
||||
import com.yandex.div.evaluable.types.Color
|
||||
import com.yandex.div.evaluable.types.Url
|
||||
import com.yandex.div.interactive.IntegrationTestCase
|
||||
import com.yandex.div.internal.parser.ANY_TO_BOOLEAN
|
||||
import com.yandex.div.internal.util.map
|
||||
import com.yandex.div.json.ParsingErrorLogger
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.isForAndroidPlatform
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.parsePlatform
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.toListOfJSONObject
|
||||
import com.yandex.div.test.expression.TestCaseOrError
|
||||
import com.yandex.div.test.expression.TestCaseParsingError
|
||||
import com.yandex.div.test.expression.parseAsUTC
|
||||
import com.yandex.div.test.crossplatform.ParsingResult
|
||||
import com.yandex.div.test.crossplatform.isForAndroid
|
||||
import com.yandex.div.test.crossplatform.parseDateTime
|
||||
import com.yandex.div.test.crossplatform.platforms
|
||||
import com.yandex.div.test.crossplatform.toObjectList
|
||||
import com.yandex.div2.DivData
|
||||
import com.yandex.div2.DivEvaluableType
|
||||
import com.yandex.div2.DivFunction
|
||||
@@ -39,46 +37,51 @@ object ExpressionTestCaseUtils {
|
||||
const val VALUE_TYPE_UNORDERED_ARRAY = "unordered_array"
|
||||
private const val VALUE_TYPE_UNIT = "unit"
|
||||
private const val VALUE_TYPE_ERROR = "error"
|
||||
private const val VALUE_TYPE_VARIABLE = "variable"
|
||||
|
||||
private const val CASES_FIELD = "cases"
|
||||
private const val CASE_VARIABLES_FIELD = "variables"
|
||||
private const val CASE_FUNCTIONS_FIELD = "functions"
|
||||
private const val CASE_VARIABLE_NAME_FIELD = "variable_name"
|
||||
private const val CASE_EXPECTED_VALUE_FIELD = "expected"
|
||||
private const val CASE_EXPECTED_WARNINGS_FIELD = "expected_warnings"
|
||||
private const val CASE_EXPRESSION_VALUE_FIELD = "expression"
|
||||
private const val TYPE_FIELD = "type"
|
||||
private const val VALUE_FIELD = "value"
|
||||
|
||||
fun parseTestCases(json: JSONObject, fileName: String): List<TestCaseOrError<ExpressionTestCase>> {
|
||||
fun parseTestCases(
|
||||
json: JSONObject,
|
||||
fileName: String
|
||||
): List<ParsingResult<ExpressionTestCase>> {
|
||||
return json.optJSONArray(CASES_FIELD)
|
||||
.toListOfJSONObject()
|
||||
.filter { isForAndroidPlatform(parsePlatform(it)) }
|
||||
.toObjectList()
|
||||
.filter { it.isForAndroid }
|
||||
.map { parseTestCase(it, fileName) }
|
||||
}
|
||||
|
||||
private fun parseTestCase(json: JSONObject, fileName: String): TestCaseOrError<ExpressionTestCase> {
|
||||
private fun parseTestCase(
|
||||
json: JSONObject,
|
||||
fileName: String
|
||||
): ParsingResult<ExpressionTestCase> {
|
||||
try {
|
||||
val testCase = ExpressionTestCase(
|
||||
fileName,
|
||||
json.getString(CASE_EXPRESSION_VALUE_FIELD),
|
||||
json.optJSONArray(CASE_VARIABLES_FIELD).toListOfJSONObject(),
|
||||
json.optJSONArray(CASE_FUNCTIONS_FIELD).toListOfJSONObject(),
|
||||
parsePlatform(json),
|
||||
json.optJSONArray(CASE_VARIABLES_FIELD).toObjectList(),
|
||||
json.optJSONArray(CASE_FUNCTIONS_FIELD).toObjectList(),
|
||||
json.platforms,
|
||||
json.getJSONObject(CASE_EXPECTED_VALUE_FIELD).type,
|
||||
json.getJSONObject(CASE_EXPECTED_VALUE_FIELD).getValue(),
|
||||
json.optJSONArray(CASE_EXPECTED_WARNINGS_FIELD)?.map { it as String } ?: emptyList(),
|
||||
)
|
||||
|
||||
return TestCaseOrError(testCase)
|
||||
return ParsingResult.Success(testCase)
|
||||
} catch (e: JSONException) {
|
||||
return TestCaseOrError(TestCaseParsingError(fileName, json, e))
|
||||
return ParsingResult.Error(fileName, json, e)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkDuplicates(cases: Sequence<TestCaseOrError<ExpressionTestCase>>) {
|
||||
val duplicate = cases.mapNotNull { it.testCase }
|
||||
fun checkDuplicates(cases: Sequence<ParsingResult<ExpressionTestCase>>) {
|
||||
val duplicate = cases
|
||||
.filterIsInstance<ParsingResult.Success<ExpressionTestCase>>()
|
||||
.map { it.value }
|
||||
.groupingBy { it.fileName to it.description }
|
||||
.eachCount()
|
||||
.filterValues { it > 1 }
|
||||
@@ -102,7 +105,7 @@ object ExpressionTestCaseUtils {
|
||||
VALUE_TYPE_ARRAY -> getJSONArray(VALUE_FIELD)
|
||||
VALUE_TYPE_UNORDERED_ARRAY -> getJSONArray(VALUE_FIELD)
|
||||
VALUE_TYPE_BOOLEAN, VALUE_TYPE_BOOL_INT -> ANY_TO_BOOLEAN(get(VALUE_FIELD))
|
||||
VALUE_TYPE_DATE_TIME -> parseAsUTC(getString(VALUE_FIELD))
|
||||
VALUE_TYPE_DATE_TIME -> parseDateTime(getString(VALUE_FIELD))
|
||||
VALUE_TYPE_UNIT -> Unit
|
||||
VALUE_TYPE_ERROR -> EvaluableException(optString(VALUE_FIELD))
|
||||
else -> throw IllegalAccessException("Unknown variable type: $type")
|
||||
@@ -112,21 +115,6 @@ object ExpressionTestCaseUtils {
|
||||
|
||||
val JSONObject.type: String get() = getString(TYPE_FIELD)
|
||||
|
||||
fun JSONObject.getVariableValue(type: String): Any {
|
||||
return when (type) {
|
||||
VALUE_TYPE_STRING -> getString(VALUE_FIELD)
|
||||
VALUE_TYPE_INTEGER -> getLong(VALUE_FIELD)
|
||||
VALUE_TYPE_DECIMAL ->getDouble(VALUE_FIELD)
|
||||
VALUE_TYPE_BOOLEAN -> get(VALUE_FIELD)
|
||||
VALUE_TYPE_COLOR -> Color.parse(getString(VALUE_FIELD))
|
||||
VALUE_TYPE_URL -> Uri.parse(getString(VALUE_FIELD))
|
||||
VALUE_TYPE_DICT -> getJSONObject(VALUE_FIELD)
|
||||
VALUE_TYPE_ARRAY -> getJSONArray(VALUE_FIELD)
|
||||
VALUE_TYPE_DATE_TIME -> parseAsUTC(getString(VALUE_FIELD))
|
||||
else -> throw IllegalAccessException("Unknown variable type: $type")
|
||||
}
|
||||
}
|
||||
|
||||
fun createVariable(type: String, name: String, value: Any?): Variable {
|
||||
return when (type) {
|
||||
VALUE_TYPE_STRING -> Variable.StringVariable(name, value as String? ?: "")
|
||||
@@ -141,48 +129,6 @@ object ExpressionTestCaseUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun parseIntegrationTestCase(fileName: String, jsonString: String): List<TestCaseOrError<IntegrationTestCase>> {
|
||||
val json = JSONObject(jsonString)
|
||||
return json.getJSONArray(CASES_FIELD).toListOfJSONObject().mapIndexedNotNull { index, jsonObject ->
|
||||
try {
|
||||
val data = JSONObject(jsonString).getJSONObject("div_data")
|
||||
jsonObject.parseStep(fileName, data, index)?.let { TestCaseOrError(it) }
|
||||
} catch (e: JSONException) {
|
||||
TestCaseOrError(TestCaseParsingError(fileName, json, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JSONObject.parseStep(
|
||||
fileName: String,
|
||||
data: JSONObject,
|
||||
index: Int,
|
||||
): IntegrationTestCase? {
|
||||
if (!isForAndroidPlatform(parsePlatform(this))) return null
|
||||
|
||||
val actions = optJSONArray("div_actions")?.toListOfJSONObject()
|
||||
|
||||
var name = "$fileName Case $index"
|
||||
actions?.forEach {
|
||||
name += ", ${it.getString("log_id")}"
|
||||
}
|
||||
|
||||
val expected = getJSONArray(CASE_EXPECTED_VALUE_FIELD).toListOfJSONObject().map {
|
||||
when (val type = it.type) {
|
||||
VALUE_TYPE_VARIABLE -> {
|
||||
IntegrationTestCase.ExpectedResult.Variable(
|
||||
it.getString(CASE_VARIABLE_NAME_FIELD),
|
||||
it.getJSONObject(VALUE_FIELD)
|
||||
)
|
||||
}
|
||||
VALUE_TYPE_ERROR -> IntegrationTestCase.ExpectedResult.Error(it.getString(VALUE_FIELD))
|
||||
else -> throw JSONException("Unknown expected result type: $type")
|
||||
}
|
||||
}
|
||||
|
||||
return IntegrationTestCase(name, data, actions, expected)
|
||||
}
|
||||
|
||||
fun createDivDataFromTestVars(
|
||||
vars: List<JSONObject>,
|
||||
functions: List<JSONObject>,
|
||||
|
||||
+34
-31
@@ -1,36 +1,37 @@
|
||||
package com.yandex.div.evaluable.multiplatform
|
||||
package com.yandex.div.core.expression
|
||||
|
||||
import com.yandex.div.evaluable.EvaluableException
|
||||
import com.yandex.div.evaluable.EvaluableType
|
||||
import com.yandex.div.evaluable.FunctionArgument
|
||||
import com.yandex.div.evaluable.function.BuiltinFunctionProvider
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.isForAndroidPlatform
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.parsePlatform
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils.toListOfJSONObject
|
||||
import com.yandex.div.test.expression.TestCaseOrError
|
||||
import com.yandex.div.test.expression.TestCaseParsingError
|
||||
import com.yandex.div.evaluable.function.GeneratedBuiltinFunctionProvider
|
||||
import com.yandex.div.test.crossplatform.isForAndroid
|
||||
import com.yandex.div.test.crossplatform.MultiplatformTestUtils
|
||||
import com.yandex.div.test.crossplatform.ParsingResult
|
||||
import com.yandex.div.test.crossplatform.toObjectList
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import java.io.File
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class SignaturesMultiplatformTest(caseOrError: TestCaseOrError<SignatureTestCase>) {
|
||||
private val functionProvider = BuiltinFunctionProvider
|
||||
private val signature = caseOrError.getCaseOrThrow()
|
||||
class SignaturesMultiplatformTest(testCaseParsingResult: ParsingResult<SignatureTestCase>) {
|
||||
private val functionProvider = GeneratedBuiltinFunctionProvider
|
||||
private val signature = testCaseParsingResult.getOrThrow()
|
||||
|
||||
@Test
|
||||
fun runSignatureTests() {
|
||||
try {
|
||||
functionProvider.ensureFunctionRegistered(
|
||||
signature.functionName,
|
||||
signature.arguments,
|
||||
signature.returnType,
|
||||
signature.isMethod
|
||||
)
|
||||
val name = signature.functionName
|
||||
val argumentTypes = signature.arguments.map { it.type }
|
||||
val function = if (signature.isMethod) {
|
||||
functionProvider.getMethod(name, argumentTypes)
|
||||
} else {
|
||||
functionProvider.get(name, argumentTypes)
|
||||
}
|
||||
assertEquals(signature.returnType, function.resultType)
|
||||
} catch (e: EvaluableException) {
|
||||
throw RuntimeException("Test for signature \"$signature\" failed.", e)
|
||||
}
|
||||
@@ -61,20 +62,22 @@ class SignaturesMultiplatformTest(caseOrError: TestCaseOrError<SignatureTestCase
|
||||
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
fun signatures(): List<TestCaseOrError<SignatureTestCase>> {
|
||||
val cases = mutableListOf<TestCaseOrError<SignatureTestCase>>()
|
||||
val errors = MultiplatformTestUtils.walkJSONs(File(SIGNATURES_DIR_PATH)) { file, jsonString ->
|
||||
val newCases = JSONObject(jsonString).optJSONArray(FIELD_SIGNATURE).toListOfJSONObject()
|
||||
.filter { isForAndroidPlatform(parsePlatform(it)) }
|
||||
.map { parseSignature(file, it) }
|
||||
.filter { it.error == null }
|
||||
cases.addAll(newCases)
|
||||
|
||||
}
|
||||
return errors.map { TestCaseOrError<SignatureTestCase>(it) } + cases
|
||||
fun signatures(): List<ParsingResult<SignatureTestCase>> {
|
||||
val cases = mutableListOf<ParsingResult<SignatureTestCase>>()
|
||||
val errors = MultiplatformTestUtils
|
||||
.walkJSONs(File(SIGNATURES_DIR_PATH)) { file, jsonString ->
|
||||
val newCases = JSONObject(jsonString)
|
||||
.optJSONArray(FIELD_SIGNATURE)
|
||||
.toObjectList()
|
||||
.filter { it.isForAndroid }
|
||||
.map { parseSignature(file, it) }
|
||||
.filterIsInstance<ParsingResult.Success<SignatureTestCase>>()
|
||||
cases.addAll(newCases)
|
||||
}
|
||||
return cases + errors
|
||||
}
|
||||
|
||||
private fun parseSignature(file: File, json: JSONObject): TestCaseOrError<SignatureTestCase> {
|
||||
private fun parseSignature(file: File, json: JSONObject): ParsingResult<SignatureTestCase> {
|
||||
val functionName = json.getString(FIELD_SIGNATURE_NAME)
|
||||
val arguments = json.optJSONArray(FIELD_SIGNATURE_ARGUMENTS)?.let { array ->
|
||||
val result = mutableListOf<FunctionArgument>()
|
||||
@@ -91,10 +94,10 @@ class SignaturesMultiplatformTest(caseOrError: TestCaseOrError<SignatureTestCase
|
||||
val resultType = try {
|
||||
EvaluableType.valueOf(json.getString(FIELD_SIGNATURE_RETURN_TYPE).uppercase())
|
||||
} catch (e: JSONException) {
|
||||
return TestCaseOrError(TestCaseParsingError(file.name, json, e))
|
||||
return ParsingResult.Error(file.name, json, e)
|
||||
}
|
||||
val isMethod = json.optBoolean(FIELD_SIGNATURE_IS_METHOD)
|
||||
return TestCaseOrError(SignatureTestCase(
|
||||
return ParsingResult.Success(SignatureTestCase(
|
||||
"$functionName(${arguments ?: ""}) $resultType",
|
||||
functionName,
|
||||
arguments ?: emptyList(),
|
||||
+27
-29
@@ -5,6 +5,8 @@ import android.net.Uri
|
||||
import com.yandex.div.core.expression.ExpressionResolverImpl
|
||||
import com.yandex.div.core.expression.ExpressionsRuntime
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.test.data.data
|
||||
import com.yandex.div.test.data.variable
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivCircleShape
|
||||
import com.yandex.div2.DivCollectionItemBuilder
|
||||
@@ -35,7 +37,6 @@ import com.yandex.div2.DivText
|
||||
import com.yandex.div2.DivTrigger
|
||||
import com.yandex.div2.DivVariable
|
||||
import com.yandex.div2.DivVideo
|
||||
import com.yandex.div2.StrVariable
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.assertEquals
|
||||
@@ -100,7 +101,7 @@ class RuntimeStoreFillerTest {
|
||||
val text3 = createText()
|
||||
val container1 = createContainer(items = listOf(text3))
|
||||
val container2 = createContainer(items = listOf(text1, text2, container1))
|
||||
val data = createData(container2)
|
||||
val data = data(content = container2)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -110,7 +111,7 @@ class RuntimeStoreFillerTest {
|
||||
@Test
|
||||
fun `create runtime for root div with id`() {
|
||||
val text = createText("root_id")
|
||||
val data = createData(text)
|
||||
val data = data(content = text)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -120,7 +121,7 @@ class RuntimeStoreFillerTest {
|
||||
@Test
|
||||
fun `create runtime for root div without id`() {
|
||||
val text = createText()
|
||||
val data = createData(text)
|
||||
val data = data(content = text)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -131,7 +132,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `create runtime for div with id`() {
|
||||
val text = createText("text_id")
|
||||
val container = createContainer(items = listOf(text))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -142,7 +143,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `create runtime for div without id`() {
|
||||
val text = createText()
|
||||
val container = createContainer(items = listOf(text))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -154,7 +155,7 @@ class RuntimeStoreFillerTest {
|
||||
val text1 = createText("item1")
|
||||
val text2 = createText()
|
||||
val gallery = createGallery(items = listOf(text1, text2))
|
||||
val data = createData(gallery)
|
||||
val data = data(content = gallery)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -166,7 +167,7 @@ class RuntimeStoreFillerTest {
|
||||
val text1 = createText("page1")
|
||||
val text2 = createText()
|
||||
val pager = createPager(items = listOf(text1, text2))
|
||||
val data = createData(pager)
|
||||
val data = data(content = pager)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -178,7 +179,7 @@ class RuntimeStoreFillerTest {
|
||||
val text1 = createText("item1")
|
||||
val text2 = createText()
|
||||
val grid = Div.Grid(DivGrid(columnCount = Expression.constant(2), items = listOf(text1, text2)))
|
||||
val data = createData(grid)
|
||||
val data = data(content = grid)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -191,7 +192,7 @@ class RuntimeStoreFillerTest {
|
||||
val text2 = createText()
|
||||
val items = listOf(text1, text2).map { DivTabs.Item(div = it, title = Expression.constant("Tab")) }
|
||||
val tabs = Div.Tabs(DivTabs(items = items))
|
||||
val data = createData(tabs)
|
||||
val data = data(content = tabs)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -204,7 +205,7 @@ class RuntimeStoreFillerTest {
|
||||
DivState.State(div = div, stateId = "state$index")
|
||||
}
|
||||
val state = Div.State(DivState(id = "state_id", states = states))
|
||||
val data = createData(state)
|
||||
val data = data(content = state)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -216,7 +217,7 @@ class RuntimeStoreFillerTest {
|
||||
val text1 = createText("custom_item1")
|
||||
val text2 = createText()
|
||||
val custom = Div.Custom(DivCustom(customType = "custom", id = "custom_id", items = listOf(text1, text2)))
|
||||
val data = createData(custom)
|
||||
val data = data(content = custom)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -246,7 +247,7 @@ class RuntimeStoreFillerTest {
|
||||
val container = createContainer("container_id", listOf(
|
||||
image, gifImage, separator, indicator, slider, input, select, video, switch
|
||||
))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -263,7 +264,7 @@ class RuntimeStoreFillerTest {
|
||||
val innerContainer = createContainer("inner", listOf(text1, text2))
|
||||
val text3 = createText("text3")
|
||||
val outerContainer = createContainer(items = listOf(innerContainer, text3))
|
||||
val data = createData(outerContainer)
|
||||
val data = data(content = outerContainer)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -276,7 +277,7 @@ class RuntimeStoreFillerTest {
|
||||
val text2 = createText("duplicate")
|
||||
val text3 = createText("duplicate")
|
||||
val container = createContainer("container", listOf(text1, text2, text3))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -286,15 +287,14 @@ class RuntimeStoreFillerTest {
|
||||
|
||||
@Test
|
||||
fun `fillStore returns root runtime`() {
|
||||
val data = createData(createText())
|
||||
val data = data(content = createText())
|
||||
val result = underTest.fillStore(store, data)
|
||||
assertSame(rootRuntime, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create runtime for container with null items`() {
|
||||
val container = createContainer()
|
||||
val data = createData(container)
|
||||
val data = data(content = createContainer())
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -304,7 +304,7 @@ class RuntimeStoreFillerTest {
|
||||
@Test
|
||||
fun `create runtime for container with empty items`() {
|
||||
val container = createContainer(items = emptyList())
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -313,9 +313,9 @@ class RuntimeStoreFillerTest {
|
||||
|
||||
@Test
|
||||
fun `create child runtime for div with variables`() {
|
||||
val text = createText("var_div", variables = listOf(DivVariable.Str(StrVariable("x", Expression.constant("")))))
|
||||
val text = createText("var_div", variables = listOf(variable("x", "")))
|
||||
val container = createContainer(items = listOf(text))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -327,7 +327,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `create child runtime for div with functions`() {
|
||||
val text = createText("var_div", functions = listOf(DivFunction(emptyList(), "", "", DivEvaluableType.INTEGER)))
|
||||
val container = createContainer(items = listOf(text))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -339,7 +339,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `copy resolver for div with triggers`() {
|
||||
val text = createText("var_div", triggers = listOf(DivTrigger(emptyList(), Expression.constant(true))))
|
||||
val container = createContainer(items = listOf(text))
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -351,7 +351,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `create runtime for items from builder in container`() {
|
||||
val builder = createItemBuilder()
|
||||
val container = createContainer(builder = builder)
|
||||
val data = createData(container)
|
||||
val data = data(content = container)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -362,7 +362,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `create runtime for items from builder in gallery`() {
|
||||
val builder = createItemBuilder()
|
||||
val gallery = createGallery(builder = builder)
|
||||
val data = createData(gallery)
|
||||
val data = data(content = gallery)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -373,7 +373,7 @@ class RuntimeStoreFillerTest {
|
||||
fun `create runtime for items from builder in pager`() {
|
||||
val builder = createItemBuilder()
|
||||
val pager = createPager(builder = builder)
|
||||
val data = createData(pager)
|
||||
val data = data(content = pager)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -390,7 +390,7 @@ class RuntimeStoreFillerTest {
|
||||
DivState.State(stateId = "state_1")
|
||||
)
|
||||
))
|
||||
val data = createData(state)
|
||||
val data = data(content = state)
|
||||
|
||||
underTest.fillStore(store, data)
|
||||
|
||||
@@ -456,8 +456,6 @@ class RuntimeStoreFillerTest {
|
||||
|
||||
private fun createData(states: List<DivData.State>) = DivData(logId = "test", states = states)
|
||||
|
||||
private fun createData(rootDiv: Div) = createData(listOf(DivData.State(rootDiv, 0)))
|
||||
|
||||
private fun assertPaths(expectedSize: Int, vararg paths: String) {
|
||||
assertEquals(expectedSize, runtimePaths.size)
|
||||
paths.forEach { assertTrue(runtimePaths.contains(it)) }
|
||||
|
||||
+3
-5
@@ -3,11 +3,9 @@ package com.yandex.div.core.expression.local
|
||||
import com.yandex.div.core.expression.ExpressionResolverImpl
|
||||
import com.yandex.div.core.expression.ExpressionsRuntime
|
||||
import com.yandex.div.core.state.DivStatePath
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.test.data.variable
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivBase
|
||||
import com.yandex.div2.DivVariable
|
||||
import com.yandex.div2.IntegerVariable
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.any
|
||||
@@ -90,7 +88,7 @@ class RuntimeStoreImplTest {
|
||||
}
|
||||
|
||||
private fun setVariable() {
|
||||
val variables = listOf(DivVariable.Integer(IntegerVariable(CHILD_VARIABLE, Expression.constant(123))))
|
||||
whenever(divBase.variables).doReturn(variables)
|
||||
val variables = listOf(variable(CHILD_VARIABLE, 123))
|
||||
whenever(divBase.variables) doReturn variables
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.yandex.div.core.util
|
||||
import android.net.Uri
|
||||
import com.yandex.div.core.asExpression
|
||||
import com.yandex.div.core.mockExpressionResolver
|
||||
import com.yandex.div.test.data.container
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivContainer
|
||||
import com.yandex.div2.DivGallery
|
||||
import com.yandex.div2.DivImage
|
||||
import com.yandex.div2.DivText
|
||||
@@ -30,7 +30,7 @@ class DivWalkTreeTest {
|
||||
|
||||
@Test
|
||||
fun `walking multiple node hierarchy`() {
|
||||
val rootDiv = divContainer(
|
||||
val rootDiv = container(
|
||||
listOf(
|
||||
divText("lorem ipsum"),
|
||||
divImage("https://none")
|
||||
@@ -45,9 +45,9 @@ class DivWalkTreeTest {
|
||||
|
||||
@Test
|
||||
fun `walking uses depth-first order`() {
|
||||
val rootDiv = divContainer(
|
||||
val rootDiv = container(
|
||||
listOf(
|
||||
divContainer(
|
||||
container(
|
||||
listOf(
|
||||
divText("lorem ipsum"),
|
||||
divImage("https://none")
|
||||
@@ -65,7 +65,7 @@ class DivWalkTreeTest {
|
||||
|
||||
@Test
|
||||
fun `onEnter excludes subtree from walking`() {
|
||||
val rootDiv = divContainer(
|
||||
val rootDiv = container(
|
||||
listOf(
|
||||
divGallery(
|
||||
listOf(
|
||||
@@ -86,10 +86,10 @@ class DivWalkTreeTest {
|
||||
|
||||
@Test
|
||||
fun `maxDepth limits walk depth`() {
|
||||
val rootDiv = divContainer(
|
||||
val rootDiv = container(
|
||||
listOf(
|
||||
divText("lorem ipsum"),
|
||||
divContainer(
|
||||
container(
|
||||
listOf(
|
||||
divText("lorem ipsum"),
|
||||
divImage("https://none")
|
||||
@@ -107,7 +107,7 @@ class DivWalkTreeTest {
|
||||
|
||||
@Test
|
||||
fun `onEnter() called only for branch nodes`() {
|
||||
val rootDiv = divContainer(
|
||||
val rootDiv = container(
|
||||
listOf(
|
||||
divText("lorem ipsum"),
|
||||
divGallery(
|
||||
@@ -132,7 +132,7 @@ class DivWalkTreeTest {
|
||||
|
||||
@Test
|
||||
fun `onLeave() called only for branch nodes`() {
|
||||
val rootDiv = divContainer(
|
||||
val rootDiv = container(
|
||||
listOf(
|
||||
divText("lorem ipsum"),
|
||||
divGallery(
|
||||
@@ -160,10 +160,6 @@ class DivWalkTreeTest {
|
||||
return Div.Image(DivImage(imageUrl = Uri.parse(imageUrl).asExpression()))
|
||||
}
|
||||
|
||||
private fun divContainer(items: List<Div>): Div {
|
||||
return Div.Container(DivContainer(items = items))
|
||||
}
|
||||
|
||||
private fun divGallery(items: List<Div>): Div {
|
||||
return Div.Gallery(DivGallery(items = items))
|
||||
}
|
||||
|
||||
+8
-12
@@ -1,13 +1,13 @@
|
||||
|
||||
package com.yandex.div.core.view2
|
||||
|
||||
import android.view.View
|
||||
import com.yandex.div.DivDataTag
|
||||
import com.yandex.div.core.asExpression
|
||||
import com.yandex.div.json.expressions.ExpressionResolver
|
||||
import com.yandex.div.test.data.constant
|
||||
import com.yandex.div.test.data.text
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivDisappearAction
|
||||
import com.yandex.div2.DivText
|
||||
import com.yandex.div2.DivVisibilityAction
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
@@ -65,16 +65,12 @@ class DivVisibilityActionTrackerTest {
|
||||
visibilityDuration = delay.asExpression()
|
||||
)
|
||||
}.toList()
|
||||
private val divBase1 = DivText(text = "test1".asExpression(), visibilityActions = listOf(action1))
|
||||
private val divBase2 = DivText(text = "test2".asExpression(), visibilityActions = listOf(action2))
|
||||
private val divBase3 = DivText(text = "test3".asExpression(), visibilityActions = lottaActions)
|
||||
private val divBase4 = DivText(text = "test4".asExpression(), visibilityActions = actionsWithThreeDifferentDelays)
|
||||
private val divBase5 = DivText(text = "test5".asExpression(), visibilityActions = listOf(action1), disappearActions = listOf(disappearAction1))
|
||||
private val div1 = Div.Text(divBase1)
|
||||
private val div2 = Div.Text(divBase2)
|
||||
private val div3 = Div.Text(divBase3)
|
||||
private val div4 = Div.Text(divBase4)
|
||||
private val div5 = Div.Text(divBase5)
|
||||
|
||||
private val div1 = text(text = constant("test1"), visibilityActions = listOf(action1))
|
||||
private val div2 = text(text = constant("test2"), visibilityActions = listOf(action2))
|
||||
private val div3 = text(text = constant("test3"), visibilityActions = lottaActions)
|
||||
private val div4 = text(text = constant("test4"), visibilityActions = actionsWithThreeDifferentDelays)
|
||||
private val div5 = text(text = constant("test5"), visibilityActions = listOf(action1), disappearActions = listOf(disappearAction1))
|
||||
|
||||
private val visibilityActionTracker = DivVisibilityActionTracker(
|
||||
viewVisibilityCalculator,
|
||||
|
||||
+5
-11
@@ -8,6 +8,7 @@ import com.yandex.div.core.view2.Div2View
|
||||
import com.yandex.div.core.view2.divs.widgets.DivLineHeightTextView
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.json.expressions.ExpressionResolver
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivBorder
|
||||
import com.yandex.div2.DivCornersRadius
|
||||
@@ -58,8 +59,8 @@ class DivFocusBinderTest {
|
||||
private val resolver = mock<ExpressionResolver>()
|
||||
private val context = BindingContext(divView, resolver)
|
||||
private val defaultBorder = DivBorder(hasShadow = Expression.constant(true))
|
||||
private val focusActions = listOf(mockDivAction("focus"))
|
||||
private val blurActions = listOf(mockDivAction("blur"))
|
||||
private val focusActions = listOf(action(url = "focus"))
|
||||
private val blurActions = listOf(action(url = "blur"))
|
||||
|
||||
private val underTest = DivFocusBinder(actionBinder)
|
||||
|
||||
@@ -339,7 +340,7 @@ class DivFocusBinderTest {
|
||||
|
||||
@Test
|
||||
fun `handle focus actions on focus after rebind actions`() {
|
||||
val newActions = listOf(mockDivAction("new_focus"))
|
||||
val newActions = listOf(action(url = "new_focus"))
|
||||
bindActions(focusActions, null)
|
||||
bindActions(newActions, null)
|
||||
|
||||
@@ -351,7 +352,7 @@ class DivFocusBinderTest {
|
||||
|
||||
@Test
|
||||
fun `handle blur actions on blur after rebind actions`() {
|
||||
val newActions = listOf(mockDivAction("new_blur"))
|
||||
val newActions = listOf(action(url = "new_blur"))
|
||||
bindActions(null, blurActions)
|
||||
bindActions(null, newActions)
|
||||
|
||||
@@ -383,13 +384,6 @@ class DivFocusBinderTest {
|
||||
|
||||
private fun onFocusChange(hasFocus: Boolean) = focusListener?.onFocusChange(view, hasFocus)
|
||||
|
||||
private fun mockDivAction(id: String): DivAction {
|
||||
return DivAction(
|
||||
logId = Expression.constant(id),
|
||||
url = mock()
|
||||
)
|
||||
}
|
||||
|
||||
private fun verifyBorderSet(
|
||||
border: DivBorder = defaultBorder,
|
||||
mode: VerificationMode = times(1)
|
||||
|
||||
+6
-11
@@ -1,7 +1,6 @@
|
||||
package com.yandex.div.core.view2.local
|
||||
|
||||
import android.app.Activity
|
||||
import android.net.Uri
|
||||
import android.widget.TextView
|
||||
import com.yandex.div.DivDataTag
|
||||
import com.yandex.div.core.Div2Context
|
||||
@@ -10,8 +9,7 @@ import com.yandex.div.core.view2.Div2View
|
||||
import com.yandex.div.core.view2.divs.widgets.DivLinearLayout
|
||||
import com.yandex.div.data.DivParsingEnvironment
|
||||
import com.yandex.div.internal.util.textString
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div2.DivData
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert
|
||||
@@ -116,21 +114,18 @@ class LocalTriggersTest {
|
||||
|
||||
private fun setState(stateNum: Int) {
|
||||
when (stateNum) {
|
||||
1 -> handleAction(Uri.parse("div-action://set_state?state_id=0/sample/first"))
|
||||
2 -> handleAction(Uri.parse("div-action://set_state?state_id=0/sample/second"))
|
||||
1 -> handleAction("div-action://set_state?state_id=0/sample/first")
|
||||
2 -> handleAction("div-action://set_state?state_id=0/sample/second")
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVariableValue(value: Int) {
|
||||
handleAction(Uri.parse("div-action://set_variable?name=counter&value=$value"))
|
||||
handleAction("div-action://set_variable?name=counter&value=$value")
|
||||
}
|
||||
|
||||
private fun handleAction(uri: Uri) {
|
||||
div2View.handleAction(DivAction(
|
||||
logId = Expression.constant("id"),
|
||||
url = Expression.constant(uri))
|
||||
)
|
||||
private fun handleAction(url: String) {
|
||||
div2View.handleAction(action(url = url))
|
||||
}
|
||||
|
||||
private fun assertTextShown(expected: String, view: TextView) {
|
||||
|
||||
+4
-9
@@ -1,7 +1,6 @@
|
||||
package com.yandex.div.core.view2.local
|
||||
|
||||
import android.app.Activity
|
||||
import android.net.Uri
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import com.yandex.div.DivDataTag
|
||||
@@ -12,9 +11,8 @@ import com.yandex.div.core.view2.divs.widgets.DivLinearLayout
|
||||
import com.yandex.div.core.view2.divs.widgets.DivStateLayout
|
||||
import com.yandex.div.data.DivParsingEnvironment
|
||||
import com.yandex.div.internal.util.textString
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivBase
|
||||
import com.yandex.div2.DivData
|
||||
import org.json.JSONObject
|
||||
@@ -115,14 +113,11 @@ class LocalVariablesTest {
|
||||
}
|
||||
|
||||
private fun setState(stateNum: Int) {
|
||||
handleAction(Uri.parse("div-action://set_state?state_id=0/label/state_$stateNum"))
|
||||
handleAction("div-action://set_state?state_id=0/label/state_$stateNum")
|
||||
}
|
||||
|
||||
private fun handleAction(uri: Uri) {
|
||||
div2View.handleAction(DivAction(
|
||||
logId = Expression.constant("id"),
|
||||
url = Expression.constant(uri))
|
||||
)
|
||||
private fun handleAction(url: String) {
|
||||
div2View.handleAction(action(url = url))
|
||||
}
|
||||
|
||||
private fun setVariable(name: String, value: String, path: String) {
|
||||
|
||||
+50
-41
@@ -5,7 +5,6 @@ import com.yandex.div.DivDataTag
|
||||
import com.yandex.div.core.Div2Context
|
||||
import com.yandex.div.core.DivConfiguration
|
||||
import com.yandex.div.core.actions.observeErrors
|
||||
import com.yandex.div.core.expression.ExpressionTestCaseUtils
|
||||
import com.yandex.div.core.expression.ExpressionTestCaseUtils.VALUE_TYPE_ARRAY
|
||||
import com.yandex.div.core.expression.ExpressionTestCaseUtils.VALUE_TYPE_DICT
|
||||
import com.yandex.div.core.expression.ExpressionTestCaseUtils.createVariable
|
||||
@@ -16,12 +15,13 @@ import com.yandex.div.core.images.DivImageLoader
|
||||
import com.yandex.div.core.images.LoadReference
|
||||
import com.yandex.div.core.view2.Div2View
|
||||
import com.yandex.div.data.DivParsingEnvironment
|
||||
import com.yandex.div.test.expression.MultiplatformTestUtils
|
||||
import com.yandex.div.test.expression.TestCaseOrError
|
||||
import com.yandex.div.test.crossplatform.IntegrationTestCase
|
||||
import com.yandex.div.test.crossplatform.MultiplatformTestUtils
|
||||
import com.yandex.div.test.crossplatform.ParsingResult
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivData
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner
|
||||
@@ -29,23 +29,24 @@ import org.robolectric.Robolectric
|
||||
import java.util.UUID
|
||||
|
||||
@RunWith(ParameterizedRobolectricTestRunner::class)
|
||||
class IntegrationMultiplatformTest(testCase: TestCaseOrError<IntegrationTestCase>) {
|
||||
class IntegrationMultiplatformTest(testCaseParsingResult: ParsingResult<IntegrationTestCase>) {
|
||||
|
||||
private val case = testCase.getCaseOrThrow()
|
||||
private val expected = case.expected
|
||||
private val testCase = testCaseParsingResult.getOrThrow()
|
||||
private val expectedResults = testCase.expectedResults
|
||||
private val activity = Robolectric.buildActivity(Activity::class.java).get()
|
||||
private val logger = IntegrationTestLogger()
|
||||
|
||||
@Test
|
||||
fun runTestCase() {
|
||||
val env = DivParsingEnvironment(LOGGER)
|
||||
case.divData.optJSONObject("templates")?.let {
|
||||
fun run() {
|
||||
val env = DivParsingEnvironment(logger)
|
||||
testCase.divData.optJSONObject("templates")?.let {
|
||||
env.parseTemplates(it)
|
||||
}
|
||||
val divData = runCatching {
|
||||
DivData(env, case.divData.getJSONObject("card"))
|
||||
DivData(env, testCase.divData.getJSONObject("card"))
|
||||
}.getOrElse {
|
||||
var errorIsExpected = false
|
||||
expected.forEach { e ->
|
||||
expectedResults.forEach { e ->
|
||||
if (e !is IntegrationTestCase.ExpectedResult.Error) return@forEach
|
||||
checkError(e)
|
||||
errorIsExpected = true
|
||||
@@ -58,34 +59,44 @@ class IntegrationMultiplatformTest(testCase: TestCaseOrError<IntegrationTestCase
|
||||
}
|
||||
|
||||
val context = Div2Context(activity, DivConfiguration.Builder(IMAGE_LOADER_STUB).build())
|
||||
expected.forEach { result ->
|
||||
val variable = result as? IntegrationTestCase.ExpectedResult.Variable ?: return@forEach
|
||||
if (divData.variables?.any { it.name == variable.name } == true) return@forEach
|
||||
context.divVariableController.declare(createVariable(variable.type, variable.name, null))
|
||||
|
||||
expectedResults.forEach { result ->
|
||||
when (result) {
|
||||
is IntegrationTestCase.ExpectedResult.Variable -> {
|
||||
if (divData.variables?.any { it.name == result.name } != true) {
|
||||
val variable = createVariable(result.type, result.name, null)
|
||||
context.divVariableController.declare(variable)
|
||||
}
|
||||
}
|
||||
|
||||
is IntegrationTestCase.ExpectedResult.Error -> return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
val divView = Div2View(context)
|
||||
divView.setData(divData, DivDataTag(UUID.randomUUID().toString()))
|
||||
divView.observeErrors { errors, _ ->
|
||||
errors.forEach { error ->
|
||||
LOGGER.logErrorDirectly(error)
|
||||
logger.logErrorDirectly(error)
|
||||
}
|
||||
}
|
||||
|
||||
case.actions?.forEach {
|
||||
testCase.actions.forEach {
|
||||
runCatching { divView.handleAction(DivAction(env, it)) }
|
||||
}
|
||||
|
||||
expected.forEach {
|
||||
expectedResults.forEach {
|
||||
when (it) {
|
||||
is IntegrationTestCase.ExpectedResult.Error -> checkError(it)
|
||||
is IntegrationTestCase.ExpectedResult.Variable -> {
|
||||
val expectedValue = it.value.wrapVariableValue()
|
||||
val actualValue = divView.expressionResolver.getVariable(it.name)?.getWrappedValue()
|
||||
val actualValue = divView.expressionResolver
|
||||
.getVariable(it.name)
|
||||
?.getWrappedValue()
|
||||
if (it.type == VALUE_TYPE_DICT || it.type == VALUE_TYPE_ARRAY) {
|
||||
Assert.assertEquals(expectedValue.toString(), actualValue.toString())
|
||||
assertEquals(expectedValue.toString(), actualValue.toString())
|
||||
} else {
|
||||
Assert.assertEquals(expectedValue, actualValue)
|
||||
assertEquals(expectedValue, actualValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,35 +104,33 @@ class IntegrationMultiplatformTest(testCase: TestCaseOrError<IntegrationTestCase
|
||||
}
|
||||
|
||||
private fun checkError(expected: IntegrationTestCase.ExpectedResult.Error) {
|
||||
Assert.assertTrue(
|
||||
"Expected: <${expected.message}> but was: <${LOGGER.messages.toSet().joinToString(", ")}>",
|
||||
LOGGER.messages.contains(expected.message)
|
||||
assertTrue(
|
||||
"Expected: <${expected.message}> but was: <${
|
||||
logger.messages.toSet().joinToString(", ")
|
||||
}>",
|
||||
logger.messages.contains(expected.message)
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun clear() = LOGGER.clear()
|
||||
|
||||
companion object {
|
||||
private const val TEST_CASES_FILE_PATH = "integration_test_data"
|
||||
private val EMPTY_REF = LoadReference { }
|
||||
private val IMAGE_LOADER_STUB = DivImageLoader { _, _ -> EMPTY_REF }
|
||||
|
||||
private val LOGGER = IntegrationTestLogger()
|
||||
private val CASES = getCases()
|
||||
// Store parsed test cases to prevent multiple parsing by
|
||||
// ParameterizedRobolectricTestRunner
|
||||
private val cases: List<ParsingResult<IntegrationTestCase>> = run {
|
||||
val cases = mutableListOf<ParsingResult<IntegrationTestCase>>()
|
||||
val errors = MultiplatformTestUtils
|
||||
.walkJSONs(TEST_CASES_FILE_PATH) { file, json ->
|
||||
cases.addAll(IntegrationTestCase.parse(file.name, json))
|
||||
}
|
||||
errors + cases
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
|
||||
fun cases() = CASES
|
||||
|
||||
private fun getCases(): List<TestCaseOrError<IntegrationTestCase>> {
|
||||
val cases = mutableListOf<TestCaseOrError<IntegrationTestCase>>()
|
||||
val errors = MultiplatformTestUtils.walkJSONs(TEST_CASES_FILE_PATH) { file, json ->
|
||||
val steps = ExpressionTestCaseUtils.parseIntegrationTestCase(file.name, json)
|
||||
cases.addAll(steps)
|
||||
}.map { TestCaseOrError<IntegrationTestCase>(it) }
|
||||
return errors + cases
|
||||
}
|
||||
fun cases() = cases
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.yandex.div.interactive
|
||||
|
||||
import com.yandex.div.core.expression.ExpressionTestCaseUtils.getVariableValue
|
||||
import com.yandex.div.core.expression.ExpressionTestCaseUtils.type
|
||||
import org.json.JSONObject
|
||||
|
||||
class IntegrationTestCase(
|
||||
val name: String,
|
||||
val divData: JSONObject,
|
||||
val actions: List<JSONObject>?,
|
||||
val expected: List<ExpectedResult>,
|
||||
) {
|
||||
|
||||
sealed interface ExpectedResult {
|
||||
|
||||
class Variable(val name: String, json: JSONObject): ExpectedResult {
|
||||
val type: String = json.type
|
||||
val value = json.getVariableValue(type)
|
||||
}
|
||||
|
||||
class Error(val message: String): ExpectedResult
|
||||
}
|
||||
|
||||
override fun toString() = name
|
||||
}
|
||||
@@ -20,6 +20,4 @@ class IntegrationTestLogger : ParsingErrorLogger {
|
||||
.mapNotNull { it.message }
|
||||
.forEach { _messages.add(it) }
|
||||
}
|
||||
|
||||
fun clear() = _messages.clear()
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'org.jetbrains.kotlin.jvm'
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':div-evaluable')
|
||||
|
||||
implementation libs.json
|
||||
implementation libs.junit
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
package com.yandex.div.test.expression
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
|
||||
private const val PLATFORM_FIELD = "platforms"
|
||||
private const val VALUE_PLATFORM_ANDROID = "android"
|
||||
private const val JSON_EXTENSION = "json"
|
||||
private const val DIV2_JSON_PATH = "../../../test_data/"
|
||||
|
||||
object MultiplatformTestUtils {
|
||||
|
||||
fun walkJSONs(
|
||||
relativePath: String,
|
||||
parseAction: (file: File, json: String) -> Unit
|
||||
): List<TestCaseParsingError> {
|
||||
return walkJSONs(directory = File(DIV2_JSON_PATH, relativePath), parseAction)
|
||||
}
|
||||
|
||||
fun walkJSONs(
|
||||
directory: File,
|
||||
parseAction: (file: File, json: String) -> Unit
|
||||
): List<TestCaseParsingError> {
|
||||
val errors = mutableListOf<TestCaseParsingError>()
|
||||
getFiles(directory)
|
||||
.forEach { file ->
|
||||
val json = try {
|
||||
file.readText(Charsets.UTF_8)
|
||||
} catch (e: Exception) {
|
||||
errors.add(
|
||||
TestCaseParsingError(fileName = file.name, json = null, error = e)
|
||||
)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
try {
|
||||
parseAction(file, json)
|
||||
} catch (e: JSONException) {
|
||||
errors.add(
|
||||
TestCaseParsingError(fileName = file.name, json = null, error = e)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
fun parsePlatform(json: JSONObject): List<String> {
|
||||
return json.getJSONArray(PLATFORM_FIELD).toListOfString()
|
||||
}
|
||||
|
||||
fun isForAndroidPlatform(platform: List<String>?): Boolean {
|
||||
return platform?.contains(VALUE_PLATFORM_ANDROID) == true
|
||||
}
|
||||
|
||||
fun JSONArray?.toListOfJSONObject(): List<JSONObject> {
|
||||
if (this == null) {
|
||||
return emptyList()
|
||||
}
|
||||
val result = mutableListOf<JSONObject>()
|
||||
for (i in 0 until this.length()) {
|
||||
result.add(this.getJSONObject(i))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun JSONArray.toSortedList(): List<String> {
|
||||
return (0 until length()).map { get(it).toString() }.sorted()
|
||||
}
|
||||
|
||||
private fun getFiles(dir: File): List<File> {
|
||||
val (directories, files) = dir.listFiles().orEmpty()
|
||||
.partition { it.isDirectory }
|
||||
return arrayListOf<File>().apply {
|
||||
addAll(files.filter { file -> file.extension == JSON_EXTENSION })
|
||||
addAll(directories.flatMap { getFiles(it) })
|
||||
}
|
||||
}
|
||||
|
||||
private fun JSONArray.toListOfString(): List<String> {
|
||||
val result = mutableListOf<String>()
|
||||
for (i in 0 until this.length()) {
|
||||
result.add(this.getString(i))
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.yandex.div.test.expression
|
||||
|
||||
class TestCaseOrError<T> private constructor(
|
||||
val testCase: T?,
|
||||
val error: TestCaseParsingError?,
|
||||
) {
|
||||
fun getCaseOrThrow(): T {
|
||||
error?.throwError()
|
||||
return testCase!!
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return testCase?.toString() ?: error?.toString() ?: "???"
|
||||
}
|
||||
|
||||
companion object {
|
||||
operator fun <T> invoke(testCase: T) = TestCaseOrError(testCase, null)
|
||||
operator fun <T> invoke(error: TestCaseParsingError) = TestCaseOrError<T>(null, error)
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.yandex.div.test.expression
|
||||
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
class TestCaseParsingError(
|
||||
private val fileName: String,
|
||||
private val json: JSONObject?,
|
||||
private val error: Exception,
|
||||
) {
|
||||
override fun toString() = "${fileName}/${error.message?:"?"}"
|
||||
|
||||
@Suppress("NewApi")
|
||||
fun throwError(): Nothing {
|
||||
if (json == null) {
|
||||
throw JSONException("$fileName parsing failed!", error)
|
||||
}
|
||||
throw JSONException(
|
||||
"Test case parsing failed: $fileName, $json",
|
||||
error
|
||||
)
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
package com.yandex.div.test.expression
|
||||
|
||||
import com.yandex.div.evaluable.EvaluationContext
|
||||
import com.yandex.div.evaluable.Evaluator
|
||||
import com.yandex.div.evaluable.types.DateTime
|
||||
import org.junit.Assert
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
private const val DEFAULT_FORMAT_PATTERN = "yyyy-MM-dd hh:mm:ss"
|
||||
|
||||
fun <T> withEvaluator(
|
||||
evaluationContext: EvaluationContext,
|
||||
warningsValidator: (List<String>) -> Unit = { Assert.assertTrue(it.isEmpty()) },
|
||||
block: Evaluator.() -> T
|
||||
) = run {
|
||||
val warnings = mutableListOf<String>()
|
||||
val evaluator = Evaluator(
|
||||
EvaluationContext(
|
||||
variableProvider = evaluationContext.variableProvider,
|
||||
storedValueProvider = evaluationContext.storedValueProvider,
|
||||
functionProvider = evaluationContext.functionProvider,
|
||||
warningSender = { expressionContext, message ->
|
||||
warnings.add(message)
|
||||
evaluationContext.warningSender.send(expressionContext, message)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
block(evaluator).also {
|
||||
warningsValidator(warnings)
|
||||
}
|
||||
}
|
||||
|
||||
fun parseAsUTC(source: String): DateTime {
|
||||
val dateFormat = SimpleDateFormat(DEFAULT_FORMAT_PATTERN, Locale.getDefault())
|
||||
val date: Date = dateFormat.parse(source)!!
|
||||
return DateTime(
|
||||
timestampMillis = date.time + Calendar.getInstance().timeZone.rawOffset,
|
||||
timezone = TimeZone.getTimeZone("UTC"),
|
||||
)
|
||||
}
|
||||
@@ -51,7 +51,6 @@ include ':div-video-m3'
|
||||
include ':divkit-demo-app'
|
||||
include ':divkit-perftests'
|
||||
include ':divkit-regression-testing'
|
||||
include ':expression-test-common'
|
||||
include ':fonts'
|
||||
include ':glide'
|
||||
include ':lint-rules'
|
||||
@@ -59,6 +58,7 @@ include ':logging'
|
||||
include ':picasso'
|
||||
include ':sample'
|
||||
include ':screenshot-test-runtime'
|
||||
include ':test-utils'
|
||||
include ':ui-test-common'
|
||||
include ':utils'
|
||||
include ':video-custom'
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
}
|
||||
|
||||
apply(from = "../div-library.gradle")
|
||||
|
||||
android {
|
||||
namespace = "com.yandex.div.test"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":div-data"))
|
||||
implementation(project(":div-evaluable"))
|
||||
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.androidx.coreKtx)
|
||||
implementation(libs.junit)
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.yandex.div.test.crossplatform
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import com.yandex.div.evaluable.types.Color
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
class IntegrationTestCase(
|
||||
val name: String,
|
||||
val divData: JSONObject,
|
||||
val actions: List<JSONObject>,
|
||||
val expectedResults: List<ExpectedResult>
|
||||
) {
|
||||
|
||||
sealed interface ExpectedResult {
|
||||
|
||||
class Variable(val name: String, val type: String, val value: Any) : ExpectedResult
|
||||
|
||||
class Error(val message: String) : ExpectedResult
|
||||
}
|
||||
|
||||
override fun toString() = name
|
||||
|
||||
companion object {
|
||||
|
||||
fun parse(
|
||||
fileName: String,
|
||||
jsonString: String
|
||||
): List<ParsingResult<IntegrationTestCase>> {
|
||||
val json = JSONObject(jsonString)
|
||||
return json.getJSONArray("cases")
|
||||
.toObjectList()
|
||||
.mapIndexedNotNull { index, jsonObject ->
|
||||
if (!jsonObject.isForAndroid) {
|
||||
return@mapIndexedNotNull null
|
||||
}
|
||||
try {
|
||||
val testCase = jsonObject.parseTestCase(
|
||||
fileName = fileName,
|
||||
index = index,
|
||||
// Fresh instance is required for every test case since JSONObject
|
||||
// may contain mutable elements (array and dict variables).
|
||||
divData = JSONObject(jsonString).getJSONObject("div_data")
|
||||
)
|
||||
ParsingResult.Success(testCase)
|
||||
} catch (e: JSONException) {
|
||||
ParsingResult.Error(fileName, json, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JSONObject.parseTestCase(
|
||||
fileName: String,
|
||||
index: Int,
|
||||
divData: JSONObject
|
||||
): IntegrationTestCase {
|
||||
val actions = optJSONArray("div_actions").toObjectList()
|
||||
var name = "$fileName Case $index"
|
||||
actions.forEach {
|
||||
name += ", ${it.getString("log_id")}"
|
||||
}
|
||||
|
||||
return IntegrationTestCase(
|
||||
name = name,
|
||||
divData = divData,
|
||||
actions = actions,
|
||||
expectedResults = getJSONArray("expected")
|
||||
.toObjectList()
|
||||
.map { it.parseExpectedResult() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun JSONObject.parseExpectedResult(): IntegrationTestCase.ExpectedResult {
|
||||
return when (val type = getString("type")) {
|
||||
"variable" -> {
|
||||
val value = getJSONObject("value")
|
||||
IntegrationTestCase.ExpectedResult.Variable(
|
||||
name = getString("variable_name"),
|
||||
type = value.getString("type"),
|
||||
value = value.getVariableValue()
|
||||
)
|
||||
}
|
||||
|
||||
"error" -> IntegrationTestCase.ExpectedResult.Error(getString("value"))
|
||||
else -> throw JSONException("Unknown expected result type: $type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun JSONObject.getVariableValue(): Any {
|
||||
return when (val type = getString("type")) {
|
||||
"array" -> getJSONArray("value")
|
||||
"boolean" -> get("value")
|
||||
"color" -> Color.parse(getString("value"))
|
||||
"datetime" -> parseDateTime(getString("value"))
|
||||
"dict" -> getJSONObject("value")
|
||||
"integer" -> getLong("value")
|
||||
"number" -> getDouble("value")
|
||||
"string" -> getString("value")
|
||||
"url" -> getString("value").toUri()
|
||||
else -> throw IllegalAccessException("Unknown variable type: $type")
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.yandex.div.test.crossplatform
|
||||
|
||||
import org.json.JSONException
|
||||
import java.io.File
|
||||
|
||||
private const val JSON_EXTENSION = "json"
|
||||
private const val TEST_DATA_PATH = "../../../test_data/"
|
||||
|
||||
object MultiplatformTestUtils {
|
||||
|
||||
fun walkJSONs(
|
||||
relativePath: String,
|
||||
parseAction: (file: File, json: String) -> Unit
|
||||
): List<ParsingResult.Error> {
|
||||
return walkJSONs(directory = File(TEST_DATA_PATH, relativePath), parseAction)
|
||||
}
|
||||
|
||||
fun walkJSONs(
|
||||
directory: File,
|
||||
parseAction: (file: File, json: String) -> Unit
|
||||
): List<ParsingResult.Error> {
|
||||
val errors = mutableListOf<ParsingResult.Error>()
|
||||
getFiles(directory)
|
||||
.forEach { file ->
|
||||
val json = try {
|
||||
file.readText(Charsets.UTF_8)
|
||||
} catch (e: Exception) {
|
||||
errors.add(ParsingResult.Error(fileName = file.name, error = e))
|
||||
return@forEach
|
||||
}
|
||||
|
||||
try {
|
||||
parseAction(file, json)
|
||||
} catch (e: JSONException) {
|
||||
errors.add(ParsingResult.Error(fileName = file.name, error = e))
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
private fun getFiles(dir: File): List<File> {
|
||||
val (directories, files) = dir.listFiles().orEmpty()
|
||||
.partition { it.isDirectory }
|
||||
return arrayListOf<File>().apply {
|
||||
addAll(files.filter { file -> file.extension == JSON_EXTENSION })
|
||||
addAll(directories.flatMap { getFiles(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.yandex.div.test.crossplatform
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
sealed class ParsingResult<out T> {
|
||||
|
||||
class Success<out T>(val value: T) : ParsingResult<T>() {
|
||||
override fun toString() = value.toString()
|
||||
}
|
||||
|
||||
class Error(
|
||||
private val fileName: String,
|
||||
private val json: JSONObject? = null,
|
||||
private val error: Exception
|
||||
) : ParsingResult<Nothing>() {
|
||||
fun throwException(): Nothing {
|
||||
if (json == null) {
|
||||
throw Exception("$fileName parsing failed", error)
|
||||
}
|
||||
throw Exception(
|
||||
"Test case parsing failed: $fileName, $json",
|
||||
error
|
||||
)
|
||||
}
|
||||
|
||||
override fun toString() = "$fileName/${error.message ?: "?"}"
|
||||
}
|
||||
|
||||
fun getOrThrow(): T {
|
||||
when (this) {
|
||||
is Success -> return value
|
||||
is Error -> throwException()
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.yandex.div.test.crossplatform
|
||||
|
||||
import com.yandex.div.evaluable.types.DateTime
|
||||
import com.yandex.div.internal.util.map
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
val JSONObject.platforms: List<String>
|
||||
get() = getJSONArray("platforms").map { it as String }
|
||||
|
||||
val JSONObject.isForAndroid: Boolean
|
||||
get() = platforms.contains("android")
|
||||
|
||||
fun JSONArray?.toObjectList(): List<JSONObject> {
|
||||
if (this == null) {
|
||||
return emptyList()
|
||||
}
|
||||
val result = mutableListOf<JSONObject>()
|
||||
for (i in 0 until this.length()) {
|
||||
result.add(this.getJSONObject(i))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun parseDateTime(utcString: String): DateTime {
|
||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefault())
|
||||
val date: Date = dateFormat.parse(utcString)!!
|
||||
return DateTime(
|
||||
timestampMillis = date.time + Calendar.getInstance().timeZone.rawOffset,
|
||||
timezone = TimeZone.getTimeZone("UTC")
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivActionSetVariable
|
||||
import com.yandex.div2.DivActionTyped
|
||||
import com.yandex.div2.DivTypedValue
|
||||
import org.json.JSONObject
|
||||
|
||||
fun action(
|
||||
typed: DivActionTyped? = null,
|
||||
payload: JSONObject? = null,
|
||||
url: String? = null,
|
||||
): DivAction {
|
||||
return DivAction(
|
||||
logId = constant("test"),
|
||||
payload = payload,
|
||||
typed = typed,
|
||||
url = url?.let { constant(it.toUri()) }
|
||||
)
|
||||
}
|
||||
|
||||
fun setVariableAction(name: String, value: DivTypedValue): DivActionTyped {
|
||||
return DivActionTyped.SetVariable(
|
||||
DivActionSetVariable(value = value, variableName = constant(name))
|
||||
)
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivContainer
|
||||
import com.yandex.div2.DivVariable
|
||||
|
||||
fun container(
|
||||
items: List<Div> = emptyList(),
|
||||
variables: List<DivVariable>? = null
|
||||
): Div {
|
||||
return Div.Container(
|
||||
value = DivContainer(
|
||||
items = items,
|
||||
variables = variables
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivData
|
||||
import com.yandex.div2.DivTrigger
|
||||
import com.yandex.div2.DivVariable
|
||||
|
||||
fun data(
|
||||
content: Div,
|
||||
triggers: List<DivTrigger>? = null,
|
||||
variables: List<DivVariable>? = null
|
||||
): DivData {
|
||||
return DivData(
|
||||
logId = "test",
|
||||
states = listOf(
|
||||
DivData.State(
|
||||
stateId = 0,
|
||||
div = content
|
||||
)
|
||||
),
|
||||
variables = variables,
|
||||
variableTriggers = triggers,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div.json.expressions.Expression
|
||||
import com.yandex.div2.Div
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivDisappearAction
|
||||
import com.yandex.div2.DivText
|
||||
import com.yandex.div2.DivTrigger
|
||||
import com.yandex.div2.DivVariable
|
||||
import com.yandex.div2.DivVisibilityAction
|
||||
|
||||
fun text(
|
||||
action: DivAction? = null,
|
||||
disappearActions: List<DivDisappearAction>? = null,
|
||||
id: String? = null,
|
||||
text: Expression<String>,
|
||||
triggers: List<DivTrigger>? = null,
|
||||
variables: List<DivVariable>? = null,
|
||||
visibilityActions: List<DivVisibilityAction>? = null
|
||||
): Div {
|
||||
return Div.Text(
|
||||
value = DivText(
|
||||
action = action,
|
||||
disappearActions = disappearActions,
|
||||
id = id,
|
||||
text = text,
|
||||
variables = variables,
|
||||
variableTriggers = triggers,
|
||||
visibilityActions = visibilityActions
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivTrigger
|
||||
import com.yandex.div2.DivTrigger.Mode
|
||||
|
||||
fun trigger(
|
||||
action: DivAction,
|
||||
condition: String,
|
||||
mode: Mode = Mode.ON_CONDITION
|
||||
): DivTrigger {
|
||||
return DivTrigger(
|
||||
actions = listOf(action),
|
||||
condition = booleanExpression(condition),
|
||||
mode = constant(mode)
|
||||
)
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div2.ArrayValue
|
||||
import com.yandex.div2.ColorValue
|
||||
import com.yandex.div2.DivTypedValue
|
||||
import com.yandex.div2.IntegerValue
|
||||
import com.yandex.div2.StrValue
|
||||
import org.json.JSONArray
|
||||
|
||||
fun typedValue(value: String): DivTypedValue {
|
||||
return DivTypedValue.Str(StrValue(value = constant(value)))
|
||||
}
|
||||
|
||||
fun typedValue(value: Long): DivTypedValue {
|
||||
return DivTypedValue.Integer(IntegerValue(value = constant(value)))
|
||||
}
|
||||
|
||||
fun typedValue(value: JSONArray): DivTypedValue {
|
||||
return DivTypedValue.Array(ArrayValue(value = constant(value)))
|
||||
}
|
||||
|
||||
fun typedColorValue(value: Long): DivTypedValue {
|
||||
return DivTypedValue.Color(ColorValue(value = constant(value.toInt())))
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div2.DivVariable
|
||||
import com.yandex.div2.IntegerVariable
|
||||
import com.yandex.div2.StrVariable
|
||||
|
||||
fun variable(name: String, value: Long): DivVariable {
|
||||
return DivVariable.Integer(IntegerVariable(name = name, value = constant(value)))
|
||||
}
|
||||
|
||||
fun variable(name: String, value: String): DivVariable {
|
||||
return DivVariable.Str(StrVariable(name = name, value = constant(value)))
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.yandex.div.compose
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div.internal.parser.TYPE_HELPER_BOOLEAN
|
||||
import com.yandex.div.internal.parser.TYPE_HELPER_INT
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.yandex.div.test.data
|
||||
|
||||
import com.yandex.div.evaluable.types.Color
|
||||
|
||||
fun color(value: Long) = Color(value.toInt())
|
||||
Reference in New Issue
Block a user