-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LF: Add conformance test of value nesting
CHANGELOG_BEGIN CHANGELOG_END
- Loading branch information
1 parent
159728d
commit 9e82d46
Showing
3 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
...ger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/suites/ValueNetsingIT.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
ledger/test-common/src/main/daml/semantic/ValueNesting.daml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|