Skip to content
This repository has been archived by the owner on Jun 1, 2024. It is now read-only.

Commit

Permalink
fix: adjust context evaluation to return correct types (#1043)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
uziasferreirazup committed Oct 20, 2020
1 parent ff2d230 commit 541a18c
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 289 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -86,8 +86,8 @@ internal class FormSubmitter(
}
}

private fun createUrl(form: FormRemoteAction, formsValue: Map<String, String>)
= if (form.method == FormMethodType.GET || form.method == FormMethodType.DELETE)
private fun createUrl(form: FormRemoteAction, formsValue: Map<String, String>) =
if (form.method == FormMethodType.GET || form.method == FormMethodType.DELETE)
formsValue.filterValues {
isFormsValueValid(it)
}.toList().fold(Uri.parse(form.path).buildUpon()) { path, param ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,35 +56,79 @@ internal class ContextDataEvaluation(
evaluatedBindings: MutableMap<String, Any> = 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<String, Any>()
expressions.forEach { expressionToken ->
evaluateExpressionsForContext(
contextsData,
contextCache,
expressionToken,
bind,
evaluatedExpressions,
evaluatedBindings
)
private fun deserializeExpression(
bind: Bind.Expression<*>,
expressions: List<ExpressionToken>,
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<Any>(bind.type).fromJsonValue(response)
else -> {
val newType = if (bind.type == Any::class.java) type else bind.type
moshi.adapter<Any>(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<ContextData>,
bind: Bind.Expression<*>,
contextCache: LruCache<String, Any>?,
evaluatedBindings: MutableMap<String, Any>,
expressions: List<ExpressionToken>
): 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<ExpressionToken>,
contextsData: List<ContextData>,
contextCache: LruCache<String, Any>?,
bind: Bind.Expression<*>,
evaluatedBindings: MutableMap<String, Any>
): String {
val evaluatedExpressions = mutableMapOf<String, Any>()
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")
Expand Down Expand Up @@ -112,20 +156,7 @@ internal class ContextDataEvaluation(
expressionToken: ExpressionToken,
evaluatedBindings: MutableMap<String, Any>
): 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<Any>(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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

/*
Expand All @@ -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
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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<String>(this)
.evaluateForAction(rootView, view, caller)?.tryToDeserialize()
return expressionOf<Any>(this).evaluateForAction(rootView, view, caller)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -77,20 +77,20 @@ 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)

}

@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()
Expand Down

0 comments on commit 541a18c

Please sign in to comment.