Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix type resolution in sub execution #209

Merged
merged 6 commits into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -302,24 +302,29 @@ trait TemplateExecutionResult {
}}).variables.map(_.name)

def findVariableType(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] = {
val mainType = findVariableTypeInternal(variableTypeDefinition)
val parameterType = variableTypeDefinition.typeParameter.flatMap(findVariableTypeInternal)
val mainType = findVariableTypeAllDirection(variableTypeDefinition)
val parameterType = variableTypeDefinition.typeParameter.flatMap(findVariableTypeAllDirection)
mainType match {
case Some(varType:ParameterTypeProvider) =>
parameterType.map(varType.createParameterInstance)
Some(varType.createParameterInstance(parameterType.getOrElse(TextType)))
case other =>
other
}
}

private def findVariableTypeInternal(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
variableTypes.find(_.checkTypeName(variableTypeDefinition.name)) match {
case Some(variableType) =>
Some(variableType)
case None =>
parentExecution
.flatMap(_.findVariableType(variableTypeDefinition))
}
private def findVariableTypeAllDirection(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
findVariableTypeInternalCurrent(variableTypeDefinition) orElse
findVariableTypeInternalParent(variableTypeDefinition) orElse
findVariableTypeInternalEmbedded(variableTypeDefinition)

def findVariableTypeInternalCurrent(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
variableTypes.find(_.checkTypeName(variableTypeDefinition.name))

def findVariableTypeInternalParent(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
parentExecution.flatMap(parent => parent.findVariableTypeInternalCurrent(variableTypeDefinition) orElse parent.findVariableTypeInternalParent(variableTypeDefinition))

def findVariableTypeInternalEmbedded(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
subExecutions.values.filter(_.embedded).flatMap(subExecution => subExecution.findVariableTypeInternalCurrent(variableTypeDefinition) orElse subExecution.findVariableType(variableTypeDefinition)).headOption

def getSignatureProof(identity: Identity):Option[SignatureProof] = signatureProofs.get(identity.email) match {
case Some(value) => Some(value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,11 @@ final case class VariableDefinition(name: VariableName, variableTypeDefinition:O

def isAnonymous: Boolean = name.isAnonymous

def varType(executionResult: TemplateExecutionResult):VariableType = variableTypeDefinition
.flatMap(typeDefinition => executionResult.findVariableType(typeDefinition)).getOrElse(TextType)
def varType(executionResult: TemplateExecutionResult):VariableType =
(for {
typeDefinition <- variableTypeDefinition
variableType <- executionResult.findVariableType(typeDefinition)
} yield variableType).getOrElse(TextType)

def verifyConstructor(executionResult: TemplateExecutionResult): Result[Option[Any]] = {
implicit val eqCls:Eq[Class[_]] = Eq.fromUniversalEquals
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ object EthereumAddress {
def apply(a: String): Result[EthereumAddress] = Option(a) match {
case None => empty
case Some(address) if address.startsWith("0x") => apply(address.substring(2))
case Some(address) if address.length =!= 40 => Failure("the address string should be 40 or 42 with '0x' prefix")
case Some(address) if address.length =!= 40 => Failure(s"the address string should be 40 or 42 with '0x' prefix. value(${address})")
case Some(address) => apply(hex2bytes(address))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,74 @@ class OpenlawExecutionEngineSpec extends FlatSpec with Matchers {
}
}

it should "look at sub execution results for variable type" in {
val mainTemplate = compile("""[[c:Clause("clause")]]""")
val clauseTemplate = compile(
"""
|<%
|# Arranged Variables by Header
|==MOU Terms==
|[[Terms: Collection<Text>]]
|
|==MOU Parties==
|[[Party Info: Structure(
| Party Name: Text;
| Party Email: Identity
| )]]
|[[#Parties: Collection<Party Info>]]
|%>
|
|\centered **__MEMORANDUM OF UNDERSTANDING__**
|
|**NOW, THEREFORE,** the undersigned parties (the "***Parties***") see mutual benefit in entering into a partnership and formalizing their cooperation over the matters and under the terms sufficiently described in this Memorandum of Understanding ("***MOU***"):
|
|{{#for each Term: Terms =>
|
| ^^[[Term]]
|}}
|
|The Parties shall keep confidential and shall not divulge to any other party, without the other's prior written consent, any non-public information concerning this MOU and the cooperation contemplated hereby, treating such confidential information with the same due care as their own proprietary information.
|
|The Parties shall jointly operate and exchange information with the intention of completing the transactions contemplated hereby and within determined timeframes and reasonable best efforts.
|
|After a preliminary review period, not to exceed two (2) months from the date of mutual execution below, the Parties may enter into a legally-binding agreement regarding these matters and shall make reasonable best efforts to conduct a meeting regarding the same following such MOU review period.
|
|This MOU is not a legally-binding agreement.
|
|***__SIGNATORIES__***
|
|{{#for each Party: Parties =>
|
|**[[Party.Party Name | Uppercase]]**
|
|*__[[Party.Party Email | Signature]]__*
|Authorized Representative
|
|}}
|""".stripMargin)

engine.execute(mainTemplate, TemplateParameters(), Map(TemplateSourceIdentifier(TemplateTitle("clause")) -> clauseTemplate,TemplateSourceIdentifier(TemplateTitle("clause")) -> clauseTemplate)) match {
case Right(result) =>
val variable = VariableDefinition(VariableName("Parties"), Some(VariableTypeDefinition("Collection",Some(VariableTypeDefinition("Parefhuzegfty Info",None)))))
getCollection(variable, result, "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about adding an assert here to check if the returned type is indeed a collection value type with the expected values? If the returned collection is empty, should it break the test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The collection will be empty because the internal format value is an empty string.
The test here is more to check that the call actually works, there was an issue with this call previously

case Left(ex) =>
fail(ex.message, ex)
}
}

def getCollection(variable:VariableDefinition, executionResult: TemplateExecutionResult, value:String):CollectionValue = {
variable.varType(executionResult) match {
case collectionType:CollectionType =>
if(value.isEmpty) {
CollectionValue(collectionType = collectionType)
} else {
VariableType.convert[CollectionValue](collectionType.cast(value, executionResult).getOrThrow()).getOrThrow()
}
case other =>
throw new RuntimeException(s"add element to collection only works for a variable of type Collection, not '${other.name}'")
}
}

it should "fail if it makes a divide by zero error" in {
val template =
compile("""
Expand Down