From 541a18ca338a2c4ff82d3ae55d36e5e235b17c10 Mon Sep 17 00:00:00 2001 From: Uzias Ferreira <63263091+uziasferreirazup@users.noreply.github.com> Date: Tue, 20 Oct 2020 15:30:52 -0300 Subject: [PATCH] fix: adjust context evaluation to return correct types (#1043) * refactor: remove deprecated from constructor * fix: adjust name action backend * fix: adjust serialization context * adjust try serializer * adjust context data manager * adjust try to deserializer * adjust unit tests * adjust class * remove space extra * adjust test in form * adjust evaluation * adjust lint * fix: adjust context data evaluation to enum * adjust lint --- .../zup/beagle/android/action/SetContext.kt | 3 +- .../components/form/core/FormSubmitter.kt | 6 +- .../android/context/ContextDataEvaluation.kt | 97 ++++++++----- .../android/context/ContextDataExtensions.kt | 15 +- .../android/context/ContextDataManager.kt | 5 - .../context/ContextExpressionReplacer.kt | 13 +- .../beagle/android/utils/ActionExtensions.kt | 5 +- .../beagle/android/utils/BeagleConstants.kt | 4 +- .../android/utils/BeagleMoshiExtensions.kt | 49 ------- .../zup/beagle/android/view/BeagleActivity.kt | 1 - .../view/mapper/SendRequestActionMapper.kt | 9 +- .../components/form/core/FormSubmitterTest.kt | 10 +- .../context/ContextDataEvaluationTest.kt | 42 ++++-- .../android/utils/ActionExtensionsKtTest.kt | 80 ++++++++++- .../utils/BeagleMoshiExtensionsTest.kt | 128 ------------------ .../mapper/SendRequestActionMapperTest.kt | 30 ---- 16 files changed, 208 insertions(+), 289 deletions(-) delete mode 100644 android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensions.kt delete mode 100644 android/beagle/src/test/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensionsTest.kt diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/action/SetContext.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/action/SetContext.kt index a4d86e8d85..b42e2ceb62 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/action/SetContext.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/action/SetContext.kt @@ -18,6 +18,7 @@ package br.com.zup.beagle.android.action import android.view.View import br.com.zup.beagle.android.annotation.ContextDataValue +import br.com.zup.beagle.android.context.normalizeContextValue import br.com.zup.beagle.android.logger.BeagleLoggerProxy import br.com.zup.beagle.android.utils.evaluateExpression import br.com.zup.beagle.android.utils.generateViewModelInstance @@ -56,7 +57,7 @@ data class SetContext( private fun toInternalSetContext(rootView: RootView, origin: View) = SetContextInternal( contextId = this.contextId, - value = evaluateExpression(rootView, origin, this.value) + value = evaluateExpression(rootView, origin, this.value)?.normalizeContextValue() ?: throw IllegalStateException("SetContext with id=${this.contextId} evaluated to null"), path = this.path ) diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/components/form/core/FormSubmitter.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/components/form/core/FormSubmitter.kt index 0bd47b918d..a196e2fd27 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/components/form/core/FormSubmitter.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/components/form/core/FormSubmitter.kt @@ -39,7 +39,7 @@ internal class FormSubmitter( private val beagleApi: BeagleApi = BeagleApi(), private val deserialization: BeagleSerializer = BeagleSerializer(), private val urlBuilder: UrlBuilder = UrlBuilderFactory().make(), - private val job:Job = Job(), + private val job: Job = Job(), override val coroutineContext: CoroutineContext = job + Main ) : CoroutineScope { @@ -86,8 +86,8 @@ internal class FormSubmitter( } } - private fun createUrl(form: FormRemoteAction, formsValue: Map) - = if (form.method == FormMethodType.GET || form.method == FormMethodType.DELETE) + private fun createUrl(form: FormRemoteAction, formsValue: Map) = + if (form.method == FormMethodType.GET || form.method == FormMethodType.DELETE) formsValue.filterValues { isFormsValueValid(it) }.toList().fold(Uri.parse(form.path).buildUpon()) { path, param -> diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataEvaluation.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataEvaluation.kt index a14902e4f7..226c0c9a58 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataEvaluation.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataEvaluation.kt @@ -56,35 +56,79 @@ internal class ContextDataEvaluation( evaluatedBindings: MutableMap = mutableMapOf() ): Any? { val expressions = bind.expressions + val response = getExpressionEvaluated(contextsData, bind, contextCache, evaluatedBindings, expressions) + val type = getType(response.toString()) + return deserializeExpression(bind, expressions, type, response) + } - return when { - bind.type == String::class.java -> { - val evaluatedExpressions = mutableMapOf() - expressions.forEach { expressionToken -> - evaluateExpressionsForContext( - contextsData, - contextCache, - expressionToken, - bind, - evaluatedExpressions, - evaluatedBindings - ) + private fun deserializeExpression( + bind: Bind.Expression<*>, + expressions: List, + type: Type?, + response: Any? + ): Any? { + return try { + return when { + bind.type == String::class.java -> response?.toString() ?: "" + expressions.size == 1 && type == null && bind.type == Any::class.java -> response + expressions.size == 1 && type == null -> moshi.adapter(bind.type).fromJsonValue(response) + else -> { + val newType = if (bind.type == Any::class.java) type else bind.type + moshi.adapter(newType ?: bind.type).fromJson(response.toString()) + ?: showLogErrorAndReturn(bind) } - - contextExpressionReplacer.replace(bind, evaluatedExpressions) } - expressions.size == 1 -> evaluateExpression( + + } catch (ex: Exception) { + showLogErrorAndReturn(bind) + null + } + } + + private fun getExpressionEvaluated( + contextsData: List, + bind: Bind.Expression<*>, + contextCache: LruCache?, + evaluatedBindings: MutableMap, + expressions: List + ): Any? { + return if (expressions.size == 1 && bind.value == "@{${bind.expressions[0].value}}") { + evaluateExpression( contextsData, contextCache, bind, expressions[0], evaluatedBindings ) - else -> { - BeagleMessageLogs.multipleExpressionsInValueThatIsNotString() - null - } + } else evaluateMultipleExpression(expressions, contextsData, contextCache, bind, evaluatedBindings) + } + + private fun evaluateMultipleExpression( + expressions: List, + contextsData: List, + contextCache: LruCache?, + bind: Bind.Expression<*>, + evaluatedBindings: MutableMap + ): String { + val evaluatedExpressions = mutableMapOf() + expressions.forEach { expressionToken -> + evaluateExpressionsForContext( + contextsData, + contextCache, + expressionToken, + bind, + evaluatedExpressions, + evaluatedBindings + ) } + + return contextExpressionReplacer.replace(bind, evaluatedExpressions) + } + + private fun getType(json: String): Type? { + val valueNormalized = json.normalizeContextValue() + if (valueNormalized is JSONArray || valueNormalized is JSONObject) return valueNormalized::class.java + return null } @Suppress("LongParameterList") @@ -112,20 +156,7 @@ internal class ContextDataEvaluation( expressionToken: ExpressionToken, evaluatedBindings: MutableMap ): Any? { - val value = getValueFromExpression(contextsData, expressionToken, contextCache, bind, evaluatedBindings) - - return try { - if (bind.type == String::class.java) { - value?.toString() ?: showLogErrorAndReturn(bind) - } else if (value is JSONArray || value is JSONObject) { - moshi.adapter(bind.type).fromJson(value.toString()) ?: showLogErrorAndReturn(bind) - } else { - value ?: showLogErrorAndReturn(bind) - } - } catch (ex: Exception) { - BeagleMessageLogs.errorWhileTryingToNotifyContextChanges(ex) - null - } + return getValueFromExpression(contextsData, expressionToken, contextCache, bind, evaluatedBindings) } private fun getValueFromExpression( diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataExtensions.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataExtensions.kt index 18e1362843..2de69b310d 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataExtensions.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataExtensions.kt @@ -18,6 +18,7 @@ package br.com.zup.beagle.android.context import br.com.zup.beagle.android.data.serializer.BeagleMoshi import org.json.JSONArray +import org.json.JSONException import org.json.JSONObject /* @@ -34,15 +35,19 @@ internal fun Any.normalizeContextValue(): Any { this } else { val newValue = BeagleMoshi.moshi.adapter(Any::class.java).toJson(this) ?: "" - return newValue.normalizeContextValue() + newValue.normalizeContextValue() } } internal fun String.normalizeContextValue(): Any { - return when { - this.startsWith("{") -> JSONObject(this) - this.startsWith("[") -> JSONArray(this) - else -> this + return try { + JSONObject(this) + } catch (ex: JSONException) { + try { + JSONArray(this) + } catch (ex1: JSONException) { + this + } } } diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataManager.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataManager.kt index b680c23960..2bfb422296 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataManager.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextDataManager.kt @@ -55,11 +55,6 @@ internal class ContextDataManager( GlobalContext.clearObserverGlobalContext(globalContextObserver) } - fun clearContext(view: View) { - contexts.remove(view.id) - viewBinding.remove(view) - } - fun addContext(view: View, context: ContextData) { if (context.id == globalContext.context.id) { BeagleMessageLogs.globalKeywordIsReservedForGlobalContext() diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextExpressionReplacer.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextExpressionReplacer.kt index 70e3c41ade..bfae68a061 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextExpressionReplacer.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/context/ContextExpressionReplacer.kt @@ -95,7 +95,7 @@ class ContextExpressionReplacer { if (isNotTheLastMatch(index, listInReverseOrderOfStringsToEvaluate)) { val nextStringItem = listInReverseOrderOfStringsToEvaluate[index + 1] listInReverseOrderOfStringsToEvaluate[index + 1] = nextStringItem.plus(actualStringToEvaluate) - }else{ + } else { evaluatedItemsInReverseOrder.add(actualStringToEvaluate) } } @@ -114,10 +114,15 @@ class ContextExpressionReplacer { actualStringToEvaluate: String ): String { val valueToChangeInEvaluation = matchResult.groupValues[2] - val evaluatedValueToBeReplaced = evaluatedExpressions[valueToChangeInEvaluation].toString() + val evaluatedValueToBeReplaced = evaluatedExpressions[valueToChangeInEvaluation] + var valueReplaced = "@{$valueToChangeInEvaluation}" + val newType = "\"@{$valueToChangeInEvaluation}\"" + if (evaluatedValueToBeReplaced !is String && actualStringToEvaluate.contains(newType)) { + valueReplaced = newType + } return actualStringToEvaluate - .replace("@{$valueToChangeInEvaluation}", evaluatedValueToBeReplaced) + .replace(valueReplaced, evaluatedValueToBeReplaced.toString()) } - private fun isQuantityEven(quantity: Int) = quantity %2 == 0 + private fun isQuantityEven(quantity: Int) = quantity % 2 == 0 } \ No newline at end of file diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/utils/ActionExtensions.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/utils/ActionExtensions.kt index 9c3b456118..711ec24e01 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/utils/ActionExtensions.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/utils/ActionExtensions.kt @@ -23,11 +23,13 @@ import br.com.zup.beagle.android.context.ContextActionExecutor import br.com.zup.beagle.android.context.ContextData import br.com.zup.beagle.android.context.expressionOf import br.com.zup.beagle.android.context.hasExpression +import br.com.zup.beagle.android.context.tokenizer.function.builtin.toJSONArray import br.com.zup.beagle.android.logger.BeagleMessageLogs import br.com.zup.beagle.android.utils.HandleEventDeprecatedConstants.HANDLE_EVENT_ACTIONS_POINTER import br.com.zup.beagle.android.utils.HandleEventDeprecatedConstants.HANDLE_EVENT_DEPRECATED_MESSAGE import br.com.zup.beagle.android.utils.HandleEventDeprecatedConstants.HANDLE_EVENT_POINTER import br.com.zup.beagle.android.widget.RootView +import java.lang.reflect.Type internal var contextActionExecutor = ContextActionExecutor() @@ -144,6 +146,5 @@ internal fun Action.evaluateExpression(rootView: RootView, view: View, data: Any } private fun String.generateBindAndEvaluateForAction(rootView: RootView, view: View, caller: Action): Any? { - return expressionOf(this) - .evaluateForAction(rootView, view, caller)?.tryToDeserialize() + return expressionOf(this).evaluateForAction(rootView, view, caller) } \ No newline at end of file diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleConstants.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleConstants.kt index 11d5b60629..86376ef840 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleConstants.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleConstants.kt @@ -17,8 +17,8 @@ package br.com.zup.beagle.android.utils internal object BeagleRegex { - val EXPRESSION_REGEX = "(\\\\*)@\\{(([^'\\}]|('([^'\\\\]|\\\\.)*'))*)\\}".toRegex() - val FULL_MATCH_EXPRESSION_SEPARATOR_REGEX = "(?<=\\})".toRegex() + val EXPRESSION_REGEX = "(\\\\*)\"?@\\{(([^'\\}]|('([^'\\\\]|\\\\.)*'))*)\\}\"?".toRegex() + val FULL_MATCH_EXPRESSION_SEPARATOR_REGEX = "(?<=\\}\"?)".toRegex() val QUANTITY_OF_SLASHES_REGEX = "(\\\\*)@".toRegex() } diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensions.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensions.kt deleted file mode 100644 index 136769f144..0000000000 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensions.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package br.com.zup.beagle.android.utils - -import br.com.zup.beagle.android.data.serializer.BeagleMoshi -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Types -import org.json.JSONArray -import org.json.JSONObject - -internal fun String.tryToDeserialize(): Any? = - try { - when (val value = BeagleMoshi.moshi.adapter(Any::class.java).fromJson(this)) { - is Collection<*> -> { - try { - val type = Types.newParameterizedType(MutableList::class.java, JSONObject::class.java) - val adapter: JsonAdapter> = BeagleMoshi.moshi.adapter(type) - JSONArray(adapter.fromJson(this)) - } catch (ex: Exception) { - JSONArray(value) - } - } - is Map<*, *> -> BeagleMoshi.moshi.adapter(JSONObject::class.java).fromJson(this) - is Number -> { - try { - this.toInt() - } catch (ex: NumberFormatException) { - this.toDoubleOrNull() - } - } - else -> value - } - } catch (ex: Exception) { - this - } diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/view/BeagleActivity.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/view/BeagleActivity.kt index 02e5b92756..2ff75bca85 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/view/BeagleActivity.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/view/BeagleActivity.kt @@ -37,7 +37,6 @@ import br.com.zup.beagle.android.utils.BeagleRetry import br.com.zup.beagle.android.utils.DeprecationMessages.DEPRECATED_STATE_LOADING import br.com.zup.beagle.android.utils.NewIntentDeprecatedConstants import br.com.zup.beagle.android.utils.toComponent -import br.com.zup.beagle.android.utils.tryToDeserialize import br.com.zup.beagle.android.view.viewmodel.BeagleViewModel import br.com.zup.beagle.android.view.viewmodel.ViewState import br.com.zup.beagle.core.ServerDrivenComponent diff --git a/android/beagle/src/main/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapper.kt b/android/beagle/src/main/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapper.kt index 49b873777e..d0e4eb730c 100644 --- a/android/beagle/src/main/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapper.kt +++ b/android/beagle/src/main/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapper.kt @@ -18,13 +18,11 @@ package br.com.zup.beagle.android.view.mapper import br.com.zup.beagle.android.action.RequestActionMethod import br.com.zup.beagle.android.action.SendRequestInternal -import br.com.zup.beagle.android.annotation.ContextDataValue +import br.com.zup.beagle.android.context.normalizeContextValue import br.com.zup.beagle.android.data.formatUrl -import br.com.zup.beagle.android.data.serializer.BeagleMoshi import br.com.zup.beagle.android.networking.HttpMethod import br.com.zup.beagle.android.networking.RequestData import br.com.zup.beagle.android.networking.ResponseData -import br.com.zup.beagle.android.utils.tryToDeserialize import br.com.zup.beagle.android.view.viewmodel.Response import java.net.URI @@ -62,8 +60,5 @@ internal object SendRequestActionMapper { ) } - private fun getDataFormatted(byteData: ByteArray): Any? { - val data = String(byteData) - return data.tryToDeserialize() - } + private fun getDataFormatted(byteData: ByteArray): Any? = String(byteData).normalizeContextValue() } \ No newline at end of file diff --git a/android/beagle/src/test/java/br/com/zup/beagle/android/components/form/core/FormSubmitterTest.kt b/android/beagle/src/test/java/br/com/zup/beagle/android/components/form/core/FormSubmitterTest.kt index 2af2206291..0cf6f30c1f 100644 --- a/android/beagle/src/test/java/br/com/zup/beagle/android/components/form/core/FormSubmitterTest.kt +++ b/android/beagle/src/test/java/br/com/zup/beagle/android/components/form/core/FormSubmitterTest.kt @@ -54,7 +54,7 @@ class FormSubmitterTest : BaseTest() { @MockK private lateinit var beagleApi: BeagleApi - @MockK + @MockK(relaxed = true, relaxUnitFun = true) private lateinit var beagleSerializer: BeagleSerializer @MockK @@ -77,12 +77,12 @@ class FormSubmitterTest : BaseTest() { every { Uri.parse(any()) } returns uri every { uri.buildUpon() } returns uriBuilder - every {uriBuilder.appendQueryParameter(any(), any())} returns uriBuilder - every {uriBuilder.build()} returns uri + every { uriBuilder.appendQueryParameter(any(), any()) } returns uriBuilder + every { uriBuilder.build() } returns uri every { uri.toString() } returns ACTION every { beagleSdk.config.baseUrl } returns RandomData.httpUrl() - coEvery { beagleApi.fetchData(capture(requestDataSlot)) } returns mockk() + coEvery { beagleApi.fetchData(capture(requestDataSlot)) } returns mockk(relaxed = true) every { urlBuilder.format(any(), capture(urlSlot)) } returns ACTION formSubmitter = FormSubmitter(beagleApi, beagleSerializer, urlBuilder) @@ -90,7 +90,7 @@ class FormSubmitterTest : BaseTest() { } @Test - fun submitForm_should_create_requestData_correctly() = runBlockingTest{ + fun submitForm_should_create_requestData_correctly() = runBlockingTest { // Given val action = createAction(FormMethodType.POST) val inputName = RandomData.string() diff --git a/android/beagle/src/test/java/br/com/zup/beagle/android/context/ContextDataEvaluationTest.kt b/android/beagle/src/test/java/br/com/zup/beagle/android/context/ContextDataEvaluationTest.kt index 6e19bdde4d..a1fbdfd232 100644 --- a/android/beagle/src/test/java/br/com/zup/beagle/android/context/ContextDataEvaluationTest.kt +++ b/android/beagle/src/test/java/br/com/zup/beagle/android/context/ContextDataEvaluationTest.kt @@ -25,6 +25,7 @@ import br.com.zup.beagle.android.logger.BeagleMessageLogs import br.com.zup.beagle.android.mockdata.ComponentModel import br.com.zup.beagle.android.testutil.RandomData import br.com.zup.beagle.android.utils.getExpressions +import br.com.zup.beagle.widget.core.TextAlignment import com.squareup.moshi.Moshi import io.mockk.* import org.json.JSONArray @@ -90,6 +91,22 @@ internal class ContextDataEvaluationTest : BaseTest() { assertEquals(contextData.value, actualValue) } + @Test + fun `GIVEN expression with context string enum WHEN evaluate expression THEN return correct enum`() { + // Given + val contextData = ContextData( + id = CONTEXT_ID, + value = "LEFT" + ) + val bind = expressionOf("@{$CONTEXT_ID}") + + // When + val actualValue = contextDataEvaluation.evaluateBindExpression(listOf(contextData), bind) + + // Then + assertEquals(TextAlignment.LEFT, actualValue) + } + @Test fun evaluateContextBindings_should_get_float_value_from_root_of_context() { // Given @@ -157,7 +174,6 @@ internal class ContextDataEvaluationTest : BaseTest() { @Test fun evaluateAllContext_should_evaluate_text_string_text_expression() { // Given - val hello = "hello" val bind = expressionOf("This is an expression @{$CONTEXT_ID.a} and this @{$CONTEXT_ID.b}") // When @@ -186,17 +202,16 @@ internal class ContextDataEvaluationTest : BaseTest() { } @Test - fun evaluateAllContext_should_not_evaluate_multiple_expressions_that_is_not_text() { + fun `GIVEN expression with values is not a string WHEN call evaluate expression THEN return correct text `() { // Given - val bind = expressionOf("This is an expression @{$CONTEXT_ID.a} and this @{$CONTEXT_ID.b}") + val bind = expressionOf("This is an expression @{$CONTEXT_ID.a} and this @{$CONTEXT_ID.b}") every { BeagleMessageLogs.multipleExpressionsInValueThatIsNotString() } just Runs // When val value = contextDataEvaluation.evaluateBindExpression(listOf(CONTEXT_DATA), bind) // Then - assertNull(value) - verify(exactly = once()) { BeagleMessageLogs.multipleExpressionsInValueThatIsNotString() } + assertEquals("This is an expression a and this true", value) } @Test @@ -290,9 +305,9 @@ internal class ContextDataEvaluationTest : BaseTest() { // Given val context = ContextData( id = "binding", - value = listOf(1, 2, 3) + value = listOf(1, 2, 3).normalizeContextValue() ) - val bind = expressionOf("@{insert(binding, 2)}") + val bind = expressionOf("@{insert(binding, 2)}") // When val value = contextDataEvaluation.evaluateBindExpression(listOf(context), bind) @@ -383,10 +398,10 @@ internal class ContextDataEvaluationTest : BaseTest() { @Test fun evaluateContextBindings_with_operation_should_evaluate_contains_operation() { // Given - val bind = expressionOf("result: @{contains(insert(${CONTEXT_ID}, 4), 4)}") + val bind = expressionOf("@{contains(insert(${CONTEXT_ID}, 4), 4)}") val contextData = ContextData( id = CONTEXT_ID, - value = listOf(1, 2, 3) + value = listOf(1, 2, 3).normalizeContextValue() ) // When @@ -399,18 +414,19 @@ internal class ContextDataEvaluationTest : BaseTest() { @Test fun evaluateContextBindings_with_operation_should_throw_error_insert_operation_index_out_of_bound() { // Given - val bind = expressionOf>("result: @{insert(${CONTEXT_ID}, 4, 4)}") + val bind = expressionOf("@{insert(${CONTEXT_ID}, 4, 5)}") + + val initialArray = listOf(1, 2, 3).normalizeContextValue() val contextData = ContextData( id = CONTEXT_ID, - value = listOf(1, 2, 3) + value = initialArray ) // When val value = contextDataEvaluation.evaluateBindExpression(listOf(contextData), bind) // Then - assertNull(value) - verify(exactly = once()) { BeagleMessageLogs.errorWhenExpressionEvaluateNullValue(any()) } + assertEquals(initialArray.toString(), value.toString()) } @Test diff --git a/android/beagle/src/test/java/br/com/zup/beagle/android/utils/ActionExtensionsKtTest.kt b/android/beagle/src/test/java/br/com/zup/beagle/android/utils/ActionExtensionsKtTest.kt index 04aa564480..ee4b533663 100644 --- a/android/beagle/src/test/java/br/com/zup/beagle/android/utils/ActionExtensionsKtTest.kt +++ b/android/beagle/src/test/java/br/com/zup/beagle/android/utils/ActionExtensionsKtTest.kt @@ -31,7 +31,6 @@ import org.json.JSONArray import org.json.JSONObject import org.junit.Test import kotlin.test.assertEquals -import kotlin.test.assertFalse import kotlin.test.assertTrue class ActionExtensionsKtTest : BaseTest() { @@ -262,6 +261,40 @@ class ActionExtensionsKtTest : BaseTest() { assertEquals(contextValue, actualValue as Double) } + @Test + fun `GIVEN expression with context string number WHEN evaluate expression THEN return string with correct text`() { + // Given + val contextValue = "93629893111" + viewModel.addContext(contextView, ContextData( + id = "context", + value = contextValue + )) + val value = "@{context}" + + // When + val actualValue = action.evaluateExpression(rootView, bindView, value) + + // Then + assertEquals(contextValue, actualValue) + } + + @Test + fun `GIVEN expression with context integer value WHEN evaluate expression THEN return correct integer type`() { + // Given + val contextValue = Integer.MAX_VALUE + viewModel.addContext(contextView, ContextData( + id = "context", + value = contextValue + )) + val value = "@{context}" + + // When + val actualValue = action.evaluateExpression(rootView, bindView, value) + + // Then + assertEquals(contextValue, actualValue as Int) + } + @Test fun evaluateExpression_should_evaluate_expression_of_type_boolean() { // Given @@ -449,6 +482,34 @@ class ActionExtensionsKtTest : BaseTest() { assertEquals("""{"value2":"${context2.value}","value1":"${context1.value}"}""", actualValue.toString()) } + @Test + fun `GIVEN expression with JsonObject and fields it is expression WHEN evaluate expression THEN return correct JsonObject`() { + // Given + val context1 = ContextData( + id = "context1", + value = 93629893111 + ) + val context2 = ContextData( + id = "context2", + value = 93629893130 + ) + val contextView1 = createViewForContext() + val contextView2 = createViewForContext(contextView1) + viewModel.addContext(contextView1, context1) + viewModel.addContext(contextView2, context2) + val value = JSONObject().apply { + put("value1", "@{context1}") + put("value2", "@{context2}") + } + + // When + val actualValue = action.evaluateExpression(rootView, contextView2, value) + + // Then + assertTrue(actualValue is JSONObject) + assertEquals("""{"value2":${context2.value},"value1":${context1.value}}""", actualValue.toString()) + } + @Test fun evaluateExpression_should_return_evaluated_value_from_implicit_context_and_normal_context() { // Given @@ -513,6 +574,23 @@ class ActionExtensionsKtTest : BaseTest() { assertEquals(implicitContextValue, actualValue) } + @Test + fun + `GIVEN context implicit WHEN call evaluate expression THEN show correct value with correct type`() { + // Given + val secondAction = mockk(relaxed = true) + val bind = expressionOf("@{onChange}") + val implicitContextValue = 99999 + val context = ContextData(id = "onChange", value = implicitContextValue) + action.handleEvent(rootView, contextView, secondAction, context) + + // When + val actualValue = secondAction.evaluateExpression(rootView, bindView, bind) + + // Then + assertEquals(implicitContextValue, actualValue) + } + @Test fun evaluateExpression_should_return_cached_result_if_there_is() { // Given diff --git a/android/beagle/src/test/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensionsTest.kt b/android/beagle/src/test/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensionsTest.kt deleted file mode 100644 index 50ad745230..0000000000 --- a/android/beagle/src/test/java/br/com/zup/beagle/android/utils/BeagleMoshiExtensionsTest.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package br.com.zup.beagle.android.utils - -import br.com.zup.beagle.android.BaseTest -import org.json.JSONArray -import org.json.JSONObject -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class BeagleMoshiExtensionsTest : BaseTest() { - - @Test - fun getMoshiDataFormatted_evaluate_string() { - // Given - val value = "hello" - - // When - val result = value.tryToDeserialize() - - // Then - assertEquals("hello", result) - } - - @Test - fun getMoshiDataFormatted_evaluate_int() { - // Given - val value = "20" - - // When - val result = value.tryToDeserialize() - - // Then - assertEquals(20, result) - } - - @Test - fun getMoshiDataFormatted_evaluate_double() { - // Given - val value = "20.5" - - // When - val result = value.tryToDeserialize() - - // Then - assertEquals(20.5, result) - } - - @Test - fun getMoshiDataFormatted_evaluate_JSONObject_with_string() { - // Given - val value = "{\"value\":\"hello\"}" - - // When - val result = value.tryToDeserialize() - - // Then - assertTrue(result is JSONObject) - assertEquals(value, result.toString()) - } - - @Test - fun getMoshiDataFormatted_evaluate_JSONArray_with_int() { - // Given - val value = "[{\"value\":2}]" - - // When - val result = value.tryToDeserialize() - - // Then - assertTrue(result is JSONArray) - assertEquals(value, result.toString()) - } - - @Test - fun getMoshiDataFormatted_evaluate_JSONArray_with_double() { - // Given - val value = "[{\"value\":2.5}]" - - // When - val result = value.tryToDeserialize() - - // Then - assertTrue(result is JSONArray) - assertEquals(value, result.toString()) - } - - @Test - fun getMoshiDataFormatted_evaluate_JSONObject_with_int() { - // Given - val value = "{\"value\":2}" - - // When - val result = value.tryToDeserialize() - - // Then - assertTrue(result is JSONObject) - assertEquals(value, result.toString()) - } - - @Test - fun getMoshiDataFormatted_evaluate_json_with_double() { - // Given - val value = "{\"value\":2.5}" - - // When - val result = value.tryToDeserialize() - - // Then - assertTrue(result is JSONObject) - assertEquals(value, result.toString()) - } -} \ No newline at end of file diff --git a/android/beagle/src/test/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapperTest.kt b/android/beagle/src/test/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapperTest.kt index 36f1e2f8df..39f2e94f4f 100644 --- a/android/beagle/src/test/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapperTest.kt +++ b/android/beagle/src/test/java/br/com/zup/beagle/android/view/mapper/SendRequestActionMapperTest.kt @@ -25,36 +25,6 @@ import kotlin.test.assertEquals class SendRequestActionMapperTest : BaseTest(){ - @Test - fun `GIVEN response data is an integer WHEN toResponse is called THEN it should return an object of type Int`() { - //Given - val responseData = ResponseData( - statusCode = 200, - data = "10".toByteArray() - ) - - //When - val response = SendRequestActionMapper.toResponse(responseData) - - //Then - assert(response.data is Int) - } - - @Test - fun `GIVEN response data is a string with value '10' WHEN toResponse is called THEN it should return 10 as Int`() { - //Given - val responseData = ResponseData( - statusCode = 200, - data = "10".toByteArray() - ) - - //When - val response = SendRequestActionMapper.toResponse(responseData) - - //Then - assert(response.data == 10) - } - @Test fun `GIVEN response data is an valid json WHEN toResponse is called THEN it should return an object of type JSONObject`() { //Given