Skip to content

Commit

Permalink
LF: Add conformance test of value nesting
Browse files Browse the repository at this point in the history
CHANGELOG_BEGIN
CHANGELOG_END
  • Loading branch information
remyhaemmerle-da committed Jul 19, 2021
1 parent 159728d commit 9e82d46
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.ledger.api.testtool.suites

import com.daml.ledger.api.refinements.ApiTypes.Party
import com.daml.ledger.api.testtool.infrastructure.Allocation._
import com.daml.ledger.api.testtool.infrastructure.Assertions._
import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite
import com.daml.ledger.api.testtool.infrastructure.participant.ParticipantTestContext
import com.daml.ledger.test.semantic.ValueNesting._
import io.grpc.Status

import scala.annotation.tailrec
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Success

final class ValueNestingIT extends LedgerTestSuite {

@tailrec
def toNat(i: Long, acc: Nat = Nat.Z(())): Nat =
if (i == 0) acc else toNat(i - 1, Nat.S(acc))

@tailrec
def toLong(n: Nat, acc: Long = 0): Int =
n match {
case Nat.Z(_) => 0
case Nat.S(n) => toLong(n, acc + 1)
}

def reify[X](future: Future[X])(implicit ec: ExecutionContext): Future[Either[Throwable, X]] =
future.transform(x => Success(x.toEither))

List[Long](30, 100, 101, 110, 200).foreach { depth =>
val accepted = depth <= 100
val result = if (accepted) "Accept" else "Reject"

def test[T](description: String)(
update: ExecutionContext => (
ParticipantTestContext,
Party,
) => Future[Either[Throwable, T]]
) =
super.test(
s"${result}$description$depth",
s"${result.toLowerCase}s $description with of $depth",
allocate(SingleParty),
)(implicit ec => { case Participants(Participant(alpha, party)) =>
update(ec)(alpha, party).map {
case Right(_) if accepted => ()
case Left(err: Throwable) if !accepted =>
assertGrpcError(err, Status.Code.INVALID_ARGUMENT, None)
case otherwise => fail("Unexpected " + otherwise.fold(_ => "success", _ => "failure"))
}
})

test("CreateArgument") { implicit ec => (alpha, party) =>
reify(alpha.create(party, Contract(party, depth, toNat(depth - 2))))

}

test("ExerciseArgument") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
result <- reify(alpha.exercise(party, handler.exerciseDestroy(_, toNat(depth - 2))))
} yield result
}

test("ExerciseOutput") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
result <- reify(alpha.exercise(party, handler.exerciseBuild(_, depth - 2)))
} yield result
}

test("Create") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
result <- reify(alpha.exercise(party, handler.exerciseCreate(_, depth - 2)))
} yield result
}

test("CreateKey") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
result <- reify(alpha.exercise(party, handler.exerciseCreateKey(_, depth - 2)))
} yield result
}

if (accepted)
test("FetchByKey") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
_ <- alpha.exercise(party, handler.exerciseCreateKey(_, depth - 2))
result <- reify(alpha.exercise(party, handler.exerciseFetchByKey(_, depth - 2)))
} yield result
}

test("FailingLookupByKey") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
result <- reify(alpha.exercise(party, handler.exerciseLookupByKey(_, depth - 2)))
} yield result
}

if (accepted)
test("SuccessfulLookupByKey") { implicit ec => (alpha, party) =>
for {
handler <- alpha.create(party, Handler(party))
_ <- alpha.exercise(party, handler.exerciseCreateKey(_, depth - 2))
result <- reify(alpha.exercise(party, handler.exerciseLookupByKey(_, depth - 2)))
} yield result
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ object Tests {
Vector(
new ParticipantPruningIT,
new MultiPartySubmissionIT,
new ValueNestingIT,
)

val retired: Vector[LedgerTestSuite] =
Expand Down
86 changes: 86 additions & 0 deletions ledger/test-common/src/main/daml/semantic/ValueNesting.daml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
-- Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0

module ValueNesting where

data Nat = Z | S Nat
deriving (Eq, Show)

build: Int -> Nat -> Nat
build x acc | x <= 0 = acc
build x acc = build (x-1) (S acc)

toNat : Int -> Nat
toNat x = build x Z

destroy: Nat -> Int -> Int
destroy Z acc = acc
destroy (S n) acc = destroy n (acc + 1)

toInt: Nat -> Int
toInt x = destroy x 0

template Contract
with
party: Party
n: Int
content: Nat
where
signatory party

template ContractWithKey
with
party: Party
n: Int
where
signatory party
key (party, toNat n): (Party, Nat)
maintainer key._1

template Handler
with
party : Party
where
signatory party
controller party can
nonconsuming Build : Nat
with
n : Int
do
pure $ toNat n
nonconsuming Destroy : Int
with
n: Nat
do pure $ toInt n
nonconsuming Create: ContractId Contract
with
n : Int
do
create Contract with
party = party
n = n
content = toNat n
nonconsuming CreateKey: ContractId ContractWithKey
with
n : Int
do
create ContractWithKey with
party = party
n = n
nonconsuming Fetch: Contract
with
cid: ContractId Contract
do
fetch cid
nonconsuming FetchByKey: ContractId ContractWithKey
with
n: Int
do
(cid, _) <- fetchByKey @ContractWithKey (party, toNat n)
pure cid
nonconsuming LookupByKey: Optional (ContractId ContractWithKey)
with
n: Int
do
lookupByKey @ContractWithKey (party, toNat n)

0 comments on commit 9e82d46

Please sign in to comment.