diff --git a/client/android/div-evaluable/src/main/java/com/yandex/div/evaluable/function/TrigonometricFunctions.kt b/client/android/div-evaluable/src/main/java/com/yandex/div/evaluable/function/TrigonometricFunctions.kt index 96c4bd5fa..d8fb43be3 100644 --- a/client/android/div-evaluable/src/main/java/com/yandex/div/evaluable/function/TrigonometricFunctions.kt +++ b/client/android/div-evaluable/src/main/java/com/yandex/div/evaluable/function/TrigonometricFunctions.kt @@ -5,6 +5,8 @@ import com.yandex.div.evaluable.EvaluationContext import com.yandex.div.evaluable.ExpressionContext import com.yandex.div.evaluable.Function import com.yandex.div.evaluable.FunctionArgument +import com.yandex.div.evaluable.throwExceptionOnEvaluationFailed +import kotlin.math.abs import kotlin.math.acos import kotlin.math.asin import kotlin.math.atan @@ -112,7 +114,9 @@ internal object Asin : Function() { expressionContext: ExpressionContext, args: List, ): Any { - return asin(args.first() as Double) + val x = args.first() as Double + val result = asin(x) + return evaluateMathResult(result, name, x) } } @@ -127,7 +131,9 @@ internal object Acos : Function() { expressionContext: ExpressionContext, args: List, ): Any { - return acos(args.first() as Double) + val x = args.first() as Double + val result = acos(x) + return evaluateMathResult(result, name, x) } } @@ -190,6 +196,40 @@ internal object Cot : Function() { args: List, ): Any { val x = args.first() as Double - return cos(x) / sin(x) + val result = cos(x) / sin(x) + return evaluateMathResult(result, name, x) } } + +private fun evaluateMathResult(result: Double, name: String, args: Double): Any { + if (!isValidTrigonometricResult(result)) throwIncorrectMathValueException(name, args) + return result +} + + +private fun isValidTrigonometricResult(value: Double, threshold: Double = 1e10): Boolean { + return when { + value.isNaN() -> false + abs(value) > threshold -> false + else -> true + } +} + +private fun String.toMathFunctionDisplayName() = when (this) { + "cot" -> "Cotangent" + "acos" -> "Arccosine" + "asin" -> "Arcsine" + else -> this +} + +private fun throwIncorrectMathValueException( + name: String, + args: Double, +) { + val displayName = name.toMathFunctionDisplayName() + val exceptionMessage = "$displayName is undefined for the given value." + val expression = "$name($args)" + throwExceptionOnEvaluationFailed(expression, exceptionMessage) +} + + diff --git a/client/android/div/src/test/java/com/yandex/div/core/expression/EvaluableMultiplatformTest.kt b/client/android/div/src/test/java/com/yandex/div/core/expression/EvaluableMultiplatformTest.kt index 326f3580e..ad7bedfea 100644 --- a/client/android/div/src/test/java/com/yandex/div/core/expression/EvaluableMultiplatformTest.kt +++ b/client/android/div/src/test/java/com/yandex/div/core/expression/EvaluableMultiplatformTest.kt @@ -45,6 +45,10 @@ class EvaluableMultiplatformTest(private val caseOrError: TestCaseOrError { val actualValue = evalExpression(testCase.expectedWarnings) diff --git a/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCase.kt b/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCase.kt index be6c36266..7e462cb6e 100644 --- a/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCase.kt +++ b/client/android/div/src/test/java/com/yandex/div/core/expression/ExpressionTestCase.kt @@ -1,5 +1,6 @@ package com.yandex.div.core.expression +import com.yandex.div.json.expressions.Expression import org.json.JSONArray import org.json.JSONObject @@ -12,6 +13,9 @@ data class ExpressionTestCase( val expectedValue: Any, val expectedWarnings: List, ) { + val isExpressionConstant: Boolean + get() = !Expression.mayBeExpression(expression) && !expression.contains("\\") + val description: String get() { val formattedExpression = if (expression.startsWith("@{") diff --git a/test_data/expression_test_data/functions_to_string.json b/test_data/expression_test_data/functions_to_string.json index 24bd8a4cc..0c62f4892 100644 --- a/test_data/expression_test_data/functions_to_string.json +++ b/test_data/expression_test_data/functions_to_string.json @@ -61,7 +61,10 @@ "platforms": [ "web", "flutter" - ] + ], + "unsupported_platforms": { + "android": "Double precision loss during conversion (1e23 → 9.999999999999999E22)" + } }, { "expression": "@{toString(number_var)}", diff --git a/test_data/expression_test_data/functions_trigonometry.json b/test_data/expression_test_data/functions_trigonometry.json index 251b47cee..c432fe3b1 100644 --- a/test_data/expression_test_data/functions_trigonometry.json +++ b/test_data/expression_test_data/functions_trigonometry.json @@ -270,6 +270,7 @@ "value": "Failed to evaluate [asin(2.0)]. Arcsine is undefined for the given value." }, "platforms": [ + "android", "ios", "web" ] @@ -336,6 +337,7 @@ "value": "Failed to evaluate [acos(2.0)]. Arccosine is undefined for the given value." }, "platforms": [ + "android", "ios", "web" ] @@ -468,6 +470,7 @@ "value": "Failed to evaluate [cot(0.0)]. Cotangent is undefined for the given value." }, "platforms": [ + "android", "ios", "web" ] @@ -479,6 +482,7 @@ "value": "Failed to evaluate [cot(3.141592653589793)]. Cotangent is undefined for the given value." }, "platforms": [ + "android", "ios", "web" ] diff --git a/test_data/expression_test_data/string_templates.json b/test_data/expression_test_data/string_templates.json index b83b6c644..c07975e78 100644 --- a/test_data/expression_test_data/string_templates.json +++ b/test_data/expression_test_data/string_templates.json @@ -339,19 +339,6 @@ "flutter" ] }, - { - "name": "empty value", - "expression": "", - "expected": { - "type": "error", - "value": "Expression expected" - }, - "deprecated": "Should not return error", - "platforms": [ - "android", - "flutter" - ] - }, { "expression": "", "expected": { @@ -359,6 +346,7 @@ "value": "" }, "platforms": [ + "android", "ios", "web", "flutter"