Merged in java-test-dsl (pull request #181)

Java test DSL
This commit is contained in:
Andras Slemmer 2016-06-24 18:53:02 +01:00
commit 10b17d6862
6 changed files with 241 additions and 90 deletions

View File

@ -48,25 +48,42 @@ fun generateState() = DummyContract.State(Random().nextInt())
// contract `fails requirement` "some substring of the error message"
// }
infix fun Cash.State.`owned by`(owner: PublicKey) = copy(owner = owner)
infix fun Cash.State.`issued by`(party: Party) = copy(amount = Amount<Issued<Currency>>(amount.quantity, issuanceDef.copy(issuer = deposit.copy(party = party))))
infix fun Cash.State.`issued by`(deposit: PartyAndReference) = copy(amount = Amount<Issued<Currency>>(amount.quantity, issuanceDef.copy(issuer = deposit)))
infix fun Cash.State.`with notary`(notary: Party) = TransactionState(this, notary)
// For Java compatibility please define helper methods here and then define the infix notation
object JavaTestHelpers {
@JvmStatic fun ownedBy(state: Cash.State, owner: PublicKey) = state.copy(owner = owner)
@JvmStatic fun issuedBy(state: Cash.State, party: Party) = state.copy(amount = Amount<Issued<Currency>>(state.amount.quantity, state.issuanceDef.copy(issuer = state.deposit.copy(party = party))))
@JvmStatic fun issuedBy(state: Cash.State, deposit: PartyAndReference) = state.copy(amount = Amount<Issued<Currency>>(state.amount.quantity, state.issuanceDef.copy(issuer = deposit)))
@JvmStatic fun withNotary(state: Cash.State, notary: Party) = TransactionState(state, notary)
@JvmStatic fun withDeposit(state: Cash.State, deposit: PartyAndReference) = state.copy(amount = state.amount.copy(token = state.amount.token.copy(issuer = deposit)))
infix fun CommercialPaper.State.`owned by`(owner: PublicKey) = this.copy(owner = owner)
infix fun CommercialPaper.State.`with notary`(notary: Party) = TransactionState(this, notary)
infix fun ICommercialPaperState.`owned by`(new_owner: PublicKey) = this.withOwner(new_owner)
@JvmStatic fun ownedBy(state: CommercialPaper.State, owner: PublicKey) = state.copy(owner = owner)
@JvmStatic fun withNotary(state: CommercialPaper.State, notary: Party) = TransactionState(state, notary)
@JvmStatic fun ownedBy(state: ICommercialPaperState, new_owner: PublicKey) = state.withOwner(new_owner)
infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State =
copy(amount = amount.copy(token = amount.token.copy(issuer = deposit)))
@JvmStatic fun withNotary(state: ContractState, notary: Party) = TransactionState(state, notary)
@JvmStatic fun CASH(amount: Amount<Currency>) = Cash.State(
Amount<Issued<Currency>>(amount.quantity, Issued<Currency>(DUMMY_CASH_ISSUER, amount.token)),
NullPublicKey)
@JvmStatic fun STATE(amount: Amount<Issued<Currency>>) = Cash.State(amount, NullPublicKey)
}
infix fun Cash.State.`owned by`(owner: PublicKey) = JavaTestHelpers.ownedBy(this, owner)
infix fun Cash.State.`issued by`(party: Party) = JavaTestHelpers.issuedBy(this, party)
infix fun Cash.State.`issued by`(deposit: PartyAndReference) = JavaTestHelpers.issuedBy(this, deposit)
infix fun Cash.State.`with notary`(notary: Party) = JavaTestHelpers.withNotary(this, notary)
infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = JavaTestHelpers.withDeposit(this, deposit)
infix fun CommercialPaper.State.`owned by`(owner: PublicKey) = JavaTestHelpers.ownedBy(this, owner)
infix fun CommercialPaper.State.`with notary`(notary: Party) = JavaTestHelpers.withNotary(this, notary)
infix fun ICommercialPaperState.`owned by`(new_owner: PublicKey) = JavaTestHelpers.ownedBy(this, new_owner)
infix fun ContractState.`with notary`(notary: Party) = JavaTestHelpers.withNotary(this, notary)
val DUMMY_CASH_ISSUER_KEY = generateKeyPair()
val DUMMY_CASH_ISSUER = Party("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public).ref(1)
/** Allows you to write 100.DOLLARS.CASH */
val Amount<Currency>.CASH: Cash.State get() = Cash.State(
Amount<Issued<Currency>>(this.quantity, Issued<Currency>(DUMMY_CASH_ISSUER, this.token)),
NullPublicKey)
val Amount<Currency>.CASH: Cash.State get() = JavaTestHelpers.CASH(this)
val Amount<Issued<Currency>>.STATE: Cash.State get() = JavaTestHelpers.STATE(this)
val Amount<Issued<Currency>>.STATE: Cash.State get() = Cash.State(this, NullPublicKey)
infix fun ContractState.`with notary`(notary: Party) = TransactionState(this, notary)

View File

@ -0,0 +1,58 @@
package com.r3corda.contracts.cash;
import com.r3corda.core.contracts.PartyAndReference;
import com.r3corda.core.serialization.OpaqueBytes;
import org.junit.Test;
import static com.r3corda.core.testing.JavaTestHelpers.*;
import static com.r3corda.core.contracts.JavaTestHelpers.*;
import static com.r3corda.contracts.testing.JavaTestHelpers.*;
/**
* This is an incomplete Java replica of CashTests.kt to show how to use the Java test DSL
*/
public class CashTestsJava {
private OpaqueBytes defaultRef = new OpaqueBytes(new byte[]{1});;
private PartyAndReference defaultIssuer = getMEGA_CORP().ref(defaultRef);
private Cash.State inState = new Cash.State(issuedBy(DOLLARS(1000), defaultIssuer), getDUMMY_PUBKEY_1());
private Cash.State outState = new Cash.State(inState.getAmount(), getDUMMY_PUBKEY_2());
@Test
public void trivial() {
transaction(tx -> {
tx.input(inState);
tx.failsRequirement("the amounts balance");
tx.tweak(tw -> {
tw.output(new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), getDUMMY_PUBKEY_2()));
return tw.failsRequirement("the amounts balance");
});
tx.tweak(tw -> {
tw.output(outState);
// No command arguments
return tw.failsRequirement("required com.r3corda.contracts.cash.FungibleAsset.Commands.Move command");
});
tx.tweak(tw -> {
tw.output(outState);
tw.arg(getDUMMY_PUBKEY_2(), new Cash.Commands.Move());
return tw.failsRequirement("the owning keys are the same as the signing keys");
});
tx.tweak(tw -> {
tw.output(outState);
tw.output(issuedBy(outState, getMINI_CORP()));
tw.arg(getDUMMY_PUBKEY_1(), new Cash.Commands.Move());
return tw.failsRequirement("at least one asset input");
});
// Simple reallocation works.
return tx.tweak(tw -> {
tw.output(outState);
tw.arg(getDUMMY_PUBKEY_1(), new Cash.Commands.Move());
return tw.accepts();
});
});
}
}

View File

@ -5,7 +5,7 @@ import java.security.PublicKey
import java.util.*
/**
* Defines a simple domain specific language for the specificiation of financial contracts. Currently covers:
* Defines a simple domain specific language for the specification of financial contracts. Currently covers:
*
* - Some utilities for working with commands.
* - Code for working with currencies.
@ -19,18 +19,32 @@ import java.util.*
fun currency(code: String) = Currency.getInstance(code)
val USD = currency("USD")
val GBP = currency("GBP")
val CHF = currency("CHF")
// Java interop
object JavaTestHelpers {
@JvmStatic val USD: Currency get() = currency("USD")
@JvmStatic val GBP: Currency get() = currency("GBP")
@JvmStatic val CHF: Currency get() = currency("CHF")
val Int.DOLLARS: Amount<Currency> get() = Amount(this.toLong() * 100, USD)
val Int.POUNDS: Amount<Currency> get() = Amount(this.toLong() * 100, GBP)
val Int.SWISS_FRANCS: Amount<Currency> get() = Amount(this.toLong() * 100, CHF)
@JvmStatic fun DOLLARS(amount: Int) = Amount(amount.toLong() * 100, USD)
@JvmStatic fun DOLLARS(amount: Double) = Amount((amount * 100).toLong(), USD)
@JvmStatic fun POUNDS(amount: Int) = Amount(amount.toLong() * 100, GBP)
@JvmStatic fun SWISS_FRANCS(amount: Int) = Amount(amount.toLong() * 100, CHF)
val Double.DOLLARS: Amount<Currency> get() = Amount((this * 100).toLong(), USD)
@JvmStatic fun issuedBy(currency: Currency, deposit: PartyAndReference) = Issued<Currency>(deposit, currency)
@JvmStatic fun issuedBy(amount: Amount<Currency>, deposit: PartyAndReference) = Amount(amount.quantity, issuedBy(amount.token, deposit))
}
infix fun Currency.`issued by`(deposit: PartyAndReference) : Issued<Currency> = Issued<Currency>(deposit, this)
infix fun <T> Amount<T>.`issued by`(deposit: PartyAndReference) : Amount<Issued<T>> = Amount(quantity, Issued<T>(deposit, this.token))
val USD = JavaTestHelpers.USD
val GBP = JavaTestHelpers.GBP
val CHF = JavaTestHelpers.CHF
val Int.DOLLARS: Amount<Currency> get() = JavaTestHelpers.DOLLARS(this)
val Double.DOLLARS: Amount<Currency> get() = JavaTestHelpers.DOLLARS(this)
val Int.POUNDS: Amount<Currency> get() = JavaTestHelpers.POUNDS(this)
val Int.SWISS_FRANCS: Amount<Currency> get() = JavaTestHelpers.SWISS_FRANCS(this)
infix fun Currency.`issued by`(deposit: PartyAndReference) = JavaTestHelpers.issuedBy(this, deposit)
infix fun Amount<Currency>.`issued by`(deposit: PartyAndReference) = JavaTestHelpers.issuedBy(this, deposit)
//// Requirements /////////////////////////////////////////////////////////////////////////////////////////////////////
@ -111,4 +125,4 @@ inline fun <reified T : CommandData> verifyMoveCommand(inputs: List<OwnableState
requireThat {
"the owning keys are the same as the signing keys" by keysThatSigned.containsAll(owningPubKeys)
}
}
}

View File

@ -6,6 +6,7 @@ import com.google.common.base.Throwables
import com.google.common.net.HostAndPort
import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.*
import com.r3corda.core.node.services.IdentityService
import com.r3corda.core.node.services.testing.MockIdentityService
import com.r3corda.core.node.services.testing.MockStorageService
import com.r3corda.core.seconds
@ -39,41 +40,91 @@ object TestUtils {
val keypair3 = generateKeyPair()
}
// A dummy time at which we will be pretending test transactions are created.
val TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z")
/**
* JAVA INTEROP. Please keep the following points in mind when extending the Kotlin DSL
*
* - Annotate functions with Kotlin defaults with @JvmOverloads. This produces the relevant overloads for Java.
* - Void closures in arguments are inconvenient in Java, use overloading to define non-closure variants as well.
* - Top-level funs should be defined in a [JavaTestHelpers] object and annotated with @JvmStatic first and should be
* referred to from the global fun. This allows static importing of [JavaTestHelpers] in Java tests, which mimicks
* top-level funs.
* - Top-level vals are trickier. *DO NOT USE @JvmField INSIDE [JavaTestHelpers]*. It's surprisingly easy to
* introduce a static init cycle because of the way Kotlin compiles top-level things, which can cause
* non-deterministic behaviour, including your field not being initialized at all! Instead opt for a proper Kotlin
* val either with a custom @JvmStatic get() or a lazy delegate if the initialiser has side-effects See examples below.
* - Infix functions work as regular ones from Java, but symbols with spaces in them don't! Define a camelCase variant
* as well.
* - varargs are exposed as array types in Java. Define overloads for common cases.
* - The Int.DOLLARS syntax doesn't work from Java. To remedy add a @JvmStatic DOLLARS(Int) function to
* [JavaTestHelpers]
*/
object JavaTestHelpers {
// A dummy time at which we will be pretending test transactions are created.
@JvmStatic val TEST_TX_TIME: Instant get() = Instant.parse("2015-04-17T12:00:00.00Z")
// A few dummy values for testing.
val MEGA_CORP_KEY = TestUtils.keypair
val MEGA_CORP_PUBKEY = MEGA_CORP_KEY.public
// A few dummy values for testing.
@JvmStatic val MEGA_CORP_KEY: KeyPair get() = TestUtils.keypair
@JvmStatic val MEGA_CORP_PUBKEY: PublicKey get() = MEGA_CORP_KEY.public
val MINI_CORP_KEY = TestUtils.keypair2
val MINI_CORP_PUBKEY = MINI_CORP_KEY.public
@JvmStatic val MINI_CORP_KEY: KeyPair get() = TestUtils.keypair2
@JvmStatic val MINI_CORP_PUBKEY: PublicKey get() = MINI_CORP_KEY.public
val ORACLE_KEY = TestUtils.keypair3
val ORACLE_PUBKEY = ORACLE_KEY.public
@JvmStatic val ORACLE_KEY: KeyPair get() = TestUtils.keypair3
@JvmStatic val ORACLE_PUBKEY: PublicKey get() = ORACLE_KEY.public
val DUMMY_PUBKEY_1 = DummyPublicKey("x1")
val DUMMY_PUBKEY_2 = DummyPublicKey("x2")
@JvmStatic val DUMMY_PUBKEY_1: PublicKey get() = DummyPublicKey("x1")
@JvmStatic val DUMMY_PUBKEY_2: PublicKey get() = DummyPublicKey("x2")
val ALICE_KEY = generateKeyPair()
val ALICE_PUBKEY = ALICE_KEY.public
val ALICE = Party("Alice", ALICE_PUBKEY)
@JvmStatic val ALICE_KEY: KeyPair by lazy { generateKeyPair() }
@JvmStatic val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public
@JvmStatic val ALICE: Party get() = Party("Alice", ALICE_PUBKEY)
val BOB_KEY = generateKeyPair()
val BOB_PUBKEY = BOB_KEY.public
val BOB = Party("Bob", BOB_PUBKEY)
@JvmStatic val BOB_KEY: KeyPair by lazy { generateKeyPair() }
@JvmStatic val BOB_PUBKEY: PublicKey get() = BOB_KEY.public
@JvmStatic val BOB: Party get() = Party("Bob", BOB_PUBKEY)
val MEGA_CORP = Party("MegaCorp", MEGA_CORP_PUBKEY)
val MINI_CORP = Party("MiniCorp", MINI_CORP_PUBKEY)
@JvmStatic val MEGA_CORP: Party get() = Party("MegaCorp", MEGA_CORP_PUBKEY)
@JvmStatic val MINI_CORP: Party get() = Party("MiniCorp", MINI_CORP_PUBKEY)
val DUMMY_NOTARY_KEY = generateKeyPair()
val DUMMY_NOTARY = Party("Notary Service", DUMMY_NOTARY_KEY.public)
@JvmStatic val DUMMY_NOTARY_KEY: KeyPair by lazy { generateKeyPair() }
@JvmStatic val DUMMY_NOTARY: Party get() = Party("Notary Service", DUMMY_NOTARY_KEY.public)
val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY)
@JvmStatic val ALL_TEST_KEYS: List<KeyPair> get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY)
val MOCK_IDENTITY_SERVICE = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
@JvmStatic val MOCK_IDENTITY_SERVICE: MockIdentityService get() = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)
@JvmStatic fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)
@JvmStatic fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure {
return body(TransactionForTest())
}
}
val TEST_TX_TIME = JavaTestHelpers.TEST_TX_TIME
val MEGA_CORP_KEY = JavaTestHelpers.MEGA_CORP_KEY
val MEGA_CORP_PUBKEY = JavaTestHelpers.MEGA_CORP_PUBKEY
val MINI_CORP_KEY = JavaTestHelpers.MINI_CORP_KEY
val MINI_CORP_PUBKEY = JavaTestHelpers.MINI_CORP_PUBKEY
val ORACLE_KEY = JavaTestHelpers.ORACLE_KEY
val ORACLE_PUBKEY = JavaTestHelpers.ORACLE_PUBKEY
val DUMMY_PUBKEY_1 = JavaTestHelpers.DUMMY_PUBKEY_1
val DUMMY_PUBKEY_2 = JavaTestHelpers.DUMMY_PUBKEY_2
val ALICE_KEY = JavaTestHelpers.ALICE_KEY
val ALICE_PUBKEY = JavaTestHelpers.ALICE_PUBKEY
val ALICE = JavaTestHelpers.ALICE
val BOB_KEY = JavaTestHelpers.BOB_KEY
val BOB_PUBKEY = JavaTestHelpers.BOB_PUBKEY
val BOB = JavaTestHelpers.BOB
val MEGA_CORP = JavaTestHelpers.MEGA_CORP
val MINI_CORP = JavaTestHelpers.MINI_CORP
val DUMMY_NOTARY_KEY = JavaTestHelpers.DUMMY_NOTARY_KEY
val DUMMY_NOTARY = JavaTestHelpers.DUMMY_NOTARY
val ALL_TEST_KEYS = JavaTestHelpers.ALL_TEST_KEYS
val MOCK_IDENTITY_SERVICE = JavaTestHelpers.MOCK_IDENTITY_SERVICE
fun generateStateRef() = JavaTestHelpers.generateStateRef()
fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure) = JavaTestHelpers.transaction(body)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
@ -94,8 +145,6 @@ fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)
// contract `fails requirement` "some substring of the error message"
// }
//
// TODO: Make it impossible to forget to test either a failure or an accept for each transaction{} block
class LabeledOutput(val label: String?, val state: TransactionState<*>) {
override fun toString() = state.toString() + (if (label != null) " ($label)" else "")
override fun equals(other: Any?) = other is LabeledOutput && state.equals(other.state)
@ -111,7 +160,10 @@ abstract class AbstractTransactionForTest {
protected val signers = LinkedHashSet<PublicKey>()
protected val type = TransactionType.General()
@JvmOverloads
open fun output(label: String? = null, s: () -> ContractState) = LabeledOutput(label, TransactionState(s(), DUMMY_NOTARY)).apply { outStates.add(this) }
@JvmOverloads
open fun output(label: String? = null, s: ContractState) = output(label) { s }
protected fun commandsToAuthenticatedObjects(): List<AuthenticatedObject<CommandData>> {
return commands.map { AuthenticatedObject(it.signers, it.signers.mapNotNull { MOCK_IDENTITY_SERVICE.partyFromKey(it) }, it.value) }
@ -121,10 +173,11 @@ abstract class AbstractTransactionForTest {
attachments.add(attachmentID)
}
fun arg(vararg key: PublicKey, c: () -> CommandData) {
val keys = listOf(*key)
addCommand(Command(c(), keys))
fun arg(vararg keys: PublicKey, c: () -> CommandData) {
val keysList = listOf(*keys)
addCommand(Command(c(), keysList))
}
fun arg(key: PublicKey, c: CommandData) = arg(key) { c }
fun timestamp(time: Instant) {
val data = TimestampCommand(time, 30.seconds)
@ -156,12 +209,15 @@ sealed class LastLineShouldTestForAcceptOrFailure {
}
// Corresponds to the args to Contract.verify
// Note on defaults: try to avoid Kotlin defaults as they don't work from Java. Instead define overloads
open class TransactionForTest : AbstractTransactionForTest() {
private val inStates = arrayListOf<TransactionState<ContractState>>()
fun input(s: () -> ContractState) {
signers.add(DUMMY_NOTARY.owningKey)
inStates.add(TransactionState(s(), DUMMY_NOTARY))
}
fun input(s: ContractState) = input { s }
protected fun runCommandsAndVerify(time: Instant) {
val cmds = commandsToAuthenticatedObjects()
@ -169,11 +225,14 @@ open class TransactionForTest : AbstractTransactionForTest() {
tx.verify()
}
@JvmOverloads
fun accepts(time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure {
runCommandsAndVerify(time)
return LastLineShouldTestForAcceptOrFailure.Token
}
fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME) {
@JvmOverloads
fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure {
val r = try {
runCommandsAndVerify(time)
false
@ -186,17 +245,14 @@ open class TransactionForTest : AbstractTransactionForTest() {
true
}
if (!r) throw AssertionError("Expected exception but didn't get one")
return LastLineShouldTestForAcceptOrFailure.Token
}
/**
* Used to confirm that the test, when (implicitly) run against the .verify() method, fails with the text of the message
*/
infix fun `fails requirement`(msg: String): LastLineShouldTestForAcceptOrFailure {
rejects(msg)
return LastLineShouldTestForAcceptOrFailure.Token
}
fun fails_requirement(msg: String) = this.`fails requirement`(msg)
infix fun `fails requirement`(msg: String): LastLineShouldTestForAcceptOrFailure = rejects(msg)
fun failsRequirement(msg: String) = this.`fails requirement`(msg)
// Use this to create transactions where the output of this transaction is automatically used as an input of
// the next.
@ -244,10 +300,6 @@ open class TransactionForTest : AbstractTransactionForTest() {
}
}
fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure {
return body(TransactionForTest())
}
class TransactionGroupDSL<T : ContractState>(private val stateType: Class<T>) {
open inner class WireTransactionDSL : AbstractTransactionForTest() {
private val inStates = ArrayList<StateRef>()
@ -328,6 +380,7 @@ class TransactionGroupDSL<T : ContractState>(private val stateType: Class<T>) {
val txns = ArrayList<WireTransaction>()
private val txnToLabelMap = HashMap<SecureHash, String>()
@JvmOverloads
fun transaction(label: String? = null, body: WireTransactionDSL.() -> Unit): WireTransaction {
val forTest = InternalWireTransactionDSL()
forTest.body()

View File

@ -1,24 +0,0 @@
package com.r3corda.contracts.testing
import com.r3corda.contracts.Obligation
import com.r3corda.contracts.cash.Cash
import com.r3corda.core.contracts.Amount
import com.r3corda.core.contracts.Issued
import com.r3corda.core.crypto.NullPublicKey
import com.r3corda.core.crypto.Party
import com.r3corda.core.testing.MINI_CORP
import com.r3corda.core.utilities.nonEmptySetOf
import java.security.PublicKey
import java.time.Instant
import java.util.*
infix fun <T> Obligation.State<T>.`at`(dueBefore: Instant) = copy(template = template.copy(dueBefore = dueBefore))
infix fun <T> Obligation.State<T>.`between`(parties: Pair<Party, PublicKey>) = copy(issuer = parties.first, owner = parties.second)
infix fun <T> Obligation.State<T>.`owned by`(owner: PublicKey) = copy(owner = owner)
infix fun <T> Obligation.State<T>.`issued by`(party: Party) = copy(issuer = party)
// Allows you to write 100.DOLLARS.OBLIGATION
val Issued<Currency>.OBLIGATION_DEF: Obligation.StateTemplate<Currency> get() = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference),
nonEmptySetOf(this), Instant.parse("2020-01-01T17:00:00Z"))
val Amount<Issued<Currency>>.OBLIGATION: Obligation.State<Currency> get() = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP,
this.token.OBLIGATION_DEF, this.quantity, NullPublicKey)

View File

@ -0,0 +1,33 @@
package com.r3corda.contracts.testing
import com.r3corda.contracts.Obligation
import com.r3corda.contracts.cash.Cash
import com.r3corda.core.contracts.Amount
import com.r3corda.core.contracts.Issued
import com.r3corda.core.crypto.NullPublicKey
import com.r3corda.core.crypto.Party
import com.r3corda.core.testing.MINI_CORP
import com.r3corda.core.utilities.nonEmptySetOf
import java.security.PublicKey
import java.time.Instant
import java.util.*
object JavaExperimental {
@JvmStatic fun <T> at(state: Obligation.State<T>, dueBefore: Instant) = state.copy(template = state.template.copy(dueBefore = dueBefore))
@JvmStatic fun <T> between(state: Obligation.State<T>, parties: Pair<Party, PublicKey>) = state.copy(issuer = parties.first, owner = parties.second)
@JvmStatic fun <T> ownedBy(state: Obligation.State<T>, owner: PublicKey) = state.copy(owner = owner)
@JvmStatic fun <T> issuedBy(state: Obligation.State<T>, party: Party) = state.copy(issuer = party)
@JvmStatic fun OBLIGATION_DEF(issued: Issued<Currency>)
= Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(issued), Instant.parse("2020-01-01T17:00:00Z"))
@JvmStatic fun OBLIGATION(amount: Amount<Issued<Currency>>) = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP,
OBLIGATION_DEF(amount.token), amount.quantity, NullPublicKey)
}
infix fun <T> Obligation.State<T>.`at`(dueBefore: Instant) = JavaExperimental.at(this, dueBefore)
infix fun <T> Obligation.State<T>.`between`(parties: Pair<Party, PublicKey>) = JavaExperimental.between(this, parties)
infix fun <T> Obligation.State<T>.`owned by`(owner: PublicKey) = JavaExperimental.ownedBy(this, owner)
infix fun <T> Obligation.State<T>.`issued by`(party: Party) = JavaExperimental.issuedBy(this, party)
// Allows you to write 100.DOLLARS.OBLIGATION
val Issued<Currency>.OBLIGATION_DEF: Obligation.StateTemplate<Currency> get() = JavaExperimental.OBLIGATION_DEF(this)
val Amount<Issued<Currency>>.OBLIGATION: Obligation.State<Currency> get() = JavaExperimental.OBLIGATION(this)