From 6109065dee6c2479b119b13d03b52d312578705b Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 21 Jun 2016 18:17:50 +0100 Subject: [PATCH 1/9] core: Use LastLineShouldTestForAcceptOrFailure trick on rejects() --- .../src/main/kotlin/com/r3corda/core/testing/TestUtils.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 1cae30a37c..875e79ff21 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -173,7 +173,7 @@ open class TransactionForTest : AbstractTransactionForTest() { runCommandsAndVerify(time) return LastLineShouldTestForAcceptOrFailure.Token } - fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME) { + fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure { val r = try { runCommandsAndVerify(time) false @@ -186,15 +186,13 @@ 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 - } + infix fun `fails requirement`(msg: String): LastLineShouldTestForAcceptOrFailure = rejects(msg) fun fails_requirement(msg: String) = this.`fails requirement`(msg) From bec1ab7a7eaaaf9588ff3a38f49894b972d913cd Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Wed, 22 Jun 2016 12:03:36 +0100 Subject: [PATCH 2/9] core: Add javadoc on how to be Java-compatible with the Kotlin DSL --- .../com/r3corda/core/contracts/ContractsDSL.kt | 2 +- .../com/r3corda/core/testing/TestUtils.kt | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 3e7e06def1..4108c88423 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -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. diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 875e79ff21..d667e4eb0a 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -39,8 +39,19 @@ 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 vals should be defined in the [Java] object and annotated with @JvmField first and should be referred + * to from the global val. This allows static importing of [Java] in Java tests, which mimicks top-level vals. + * - Same goes for top-level funs. Define them in [Java] with annotation @JvmStatic and define a global alias later. + * - 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 [Java] + */ // A few dummy values for testing. val MEGA_CORP_KEY = TestUtils.keypair @@ -94,8 +105,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) From 28e85923a3a8d4ca2d459b477a47a2e870b128b6 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 21 Jun 2016 18:19:27 +0100 Subject: [PATCH 3/9] core: Add CashTestsJava.java, containing some of CashTests.kt in Java --- .../r3corda/contracts/cash/CashTestsJava.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java b/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java new file mode 100644 index 0000000000..3b6eae6e33 --- /dev/null +++ b/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java @@ -0,0 +1,56 @@ +package com.r3corda.contracts.cash; + +import com.r3corda.core.contracts.PartyAndReference; +import com.r3corda.core.serialization.OpaqueBytes; +import com.r3corda.core.testing.TransactionTestBase; +import org.junit.Test; + +import static com.r3corda.core.testing.Dummies.*; +import static com.r3corda.contracts.testing.Methods.*; +import static com.r3corda.core.contracts.Currencies.*; +import static com.r3corda.core.contracts.Methods.*; + +public class CashTestsJava extends TransactionTestBase { + + private OpaqueBytes defaultRef = new OpaqueBytes(new byte[]{1});; + private PartyAndReference defaultIssuer = MEGA_CORP.ref(defaultRef); + private Cash.State inState = new Cash.State(issued_by(DOLLARS(2000), defaultIssuer), DUMMY_PUBKEY_1); + private Cash.State outState = inState.copy(inState.getAmount(), DUMMY_PUBKEY_2);; + + @Test + public void trivial() { + transaction(begin + .input(inState) + .fails_requirement("the amounts balance") + + .tweak(begin + .output(outState.copy(issued_by(DOLLARS(2000), defaultIssuer), DUMMY_PUBKEY_2)) + .fails_requirement("the amounts balance") + ) + + .tweak(begin + .output(outState) + .fails_requirement("required com.r3corda.contracts.cash.FungibleAsset.Commands.Move command") + ) + + .tweak(begin + .output(outState) + .arg(DUMMY_PUBKEY_2, new Cash.Commands.Move()) + .fails_requirement("the owning keys are the same as the signing keys") + ) + + .tweak(begin + .output(outState) + .output(issued_by(outState, MINI_CORP)) + .arg(DUMMY_PUBKEY_1, new Cash.Commands.Move()) + .fails_requirement("at least one asset input") + ) + + .tweak(begin + .output(outState) + .arg(DUMMY_PUBKEY_1, new Cash.Commands.Move()) + .accepts() + ) + ); + } +} From 040e51ec1242981d913547df128cfebb68e31748 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 21 Jun 2016 18:15:41 +0100 Subject: [PATCH 4/9] contracts, core: Expose top-level DSL values/functions to Java by wrapping them in an object core: Add overloads for convenient Java interop contracts, core: Uniform Java interop for tests, use camelCase --- .../r3corda/contracts/testing/TestUtils.kt | 47 +++++--- .../r3corda/contracts/cash/CashTestsJava.java | 58 ++++++++++ .../r3corda/contracts/cash/CashTestsJava.java | 56 --------- .../r3corda/core/contracts/ContractsDSL.kt | 34 ++++-- .../com/r3corda/core/testing/TestUtils.kt | 106 ++++++++++++------ .../contracts/ExperimentalTestUtils.kt | 24 ---- .../testing/ExperimentalTestUtils.kt | 33 ++++++ 7 files changed, 220 insertions(+), 138 deletions(-) create mode 100644 contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java delete mode 100644 contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java delete mode 100644 experimental/src/main/kotlin/com/r3corda/contracts/ExperimentalTestUtils.kt create mode 100644 experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt index e1d01a5079..7c3e9d6650 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt @@ -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>(amount.quantity, issuanceDef.copy(issuer = deposit.copy(party = party)))) -infix fun Cash.State.`issued by`(deposit: PartyAndReference) = copy(amount = Amount>(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 Java { + @JvmStatic fun ownedBy(state: Cash.State, owner: PublicKey) = state.copy(owner = owner) + @JvmStatic fun issuedBy(state: Cash.State, party: Party) = state.copy(amount = Amount>(state.amount.quantity, state.issuanceDef.copy(issuer = state.deposit.copy(party = party)))) + @JvmStatic fun issuedBy(state: Cash.State, deposit: PartyAndReference) = state.copy(amount = Amount>(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) = Cash.State( + Amount>(amount.quantity, Issued(DUMMY_CASH_ISSUER, amount.token)), + NullPublicKey) + @JvmStatic fun STATE(amount: Amount>) = Cash.State(amount, NullPublicKey) +} + + +infix fun Cash.State.`owned by`(owner: PublicKey) = Java.ownedBy(this, owner) +infix fun Cash.State.`issued by`(party: Party) = Java.issuedBy(this, party) +infix fun Cash.State.`issued by`(deposit: PartyAndReference) = Java.issuedBy(this, deposit) +infix fun Cash.State.`with notary`(notary: Party) = Java.withNotary(this, notary) +infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = Java.withDeposit(this, deposit) + +infix fun CommercialPaper.State.`owned by`(owner: PublicKey) = Java.ownedBy(this, owner) +infix fun CommercialPaper.State.`with notary`(notary: Party) = Java.withNotary(this, notary) +infix fun ICommercialPaperState.`owned by`(new_owner: PublicKey) = Java.ownedBy(this, new_owner) + +infix fun ContractState.`with notary`(notary: Party) = Java.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.CASH: Cash.State get() = Cash.State( - Amount>(this.quantity, Issued(DUMMY_CASH_ISSUER, this.token)), - NullPublicKey) +val Amount.CASH: Cash.State get() = Java.CASH(this) +val Amount>.STATE: Cash.State get() = Java.STATE(this) -val Amount>.STATE: Cash.State get() = Cash.State(this, NullPublicKey) - -infix fun ContractState.`with notary`(notary: Party) = TransactionState(this, notary) diff --git a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java b/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java new file mode 100644 index 0000000000..7dfdaaf849 --- /dev/null +++ b/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java @@ -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.Java.*; +import static com.r3corda.core.contracts.Java.*; +import static com.r3corda.contracts.testing.Java.*; + +/** + * 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 = MEGA_CORP.ref(defaultRef); + private Cash.State inState = new Cash.State(issuedBy(DOLLARS(1000), defaultIssuer), DUMMY_PUBKEY_1); + private Cash.State outState = new Cash.State(inState.getAmount(), DUMMY_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), DUMMY_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(DUMMY_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, MINI_CORP)); + tw.arg(DUMMY_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(DUMMY_PUBKEY_1, new Cash.Commands.Move()); + return tw.accepts(); + }); + }); + } +} diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java b/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java deleted file mode 100644 index 3b6eae6e33..0000000000 --- a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTestsJava.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.r3corda.contracts.cash; - -import com.r3corda.core.contracts.PartyAndReference; -import com.r3corda.core.serialization.OpaqueBytes; -import com.r3corda.core.testing.TransactionTestBase; -import org.junit.Test; - -import static com.r3corda.core.testing.Dummies.*; -import static com.r3corda.contracts.testing.Methods.*; -import static com.r3corda.core.contracts.Currencies.*; -import static com.r3corda.core.contracts.Methods.*; - -public class CashTestsJava extends TransactionTestBase { - - private OpaqueBytes defaultRef = new OpaqueBytes(new byte[]{1});; - private PartyAndReference defaultIssuer = MEGA_CORP.ref(defaultRef); - private Cash.State inState = new Cash.State(issued_by(DOLLARS(2000), defaultIssuer), DUMMY_PUBKEY_1); - private Cash.State outState = inState.copy(inState.getAmount(), DUMMY_PUBKEY_2);; - - @Test - public void trivial() { - transaction(begin - .input(inState) - .fails_requirement("the amounts balance") - - .tweak(begin - .output(outState.copy(issued_by(DOLLARS(2000), defaultIssuer), DUMMY_PUBKEY_2)) - .fails_requirement("the amounts balance") - ) - - .tweak(begin - .output(outState) - .fails_requirement("required com.r3corda.contracts.cash.FungibleAsset.Commands.Move command") - ) - - .tweak(begin - .output(outState) - .arg(DUMMY_PUBKEY_2, new Cash.Commands.Move()) - .fails_requirement("the owning keys are the same as the signing keys") - ) - - .tweak(begin - .output(outState) - .output(issued_by(outState, MINI_CORP)) - .arg(DUMMY_PUBKEY_1, new Cash.Commands.Move()) - .fails_requirement("at least one asset input") - ) - - .tweak(begin - .output(outState) - .arg(DUMMY_PUBKEY_1, new Cash.Commands.Move()) - .accepts() - ) - ); - } -} diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 4108c88423..32d370341f 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -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 Java { + @JvmField val USD = currency("USD") + @JvmField val GBP = currency("GBP") + @JvmField val CHF = currency("CHF") -val Int.DOLLARS: Amount get() = Amount(this.toLong() * 100, USD) -val Int.POUNDS: Amount get() = Amount(this.toLong() * 100, GBP) -val Int.SWISS_FRANCS: Amount 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 get() = Amount((this * 100).toLong(), USD) + @JvmStatic fun issuedBy(currency: Currency, deposit: PartyAndReference) = Issued(deposit, currency) + @JvmStatic fun issuedBy(amount: Amount, deposit: PartyAndReference) = Amount(amount.quantity, issuedBy(amount.token, deposit)) +} -infix fun Currency.`issued by`(deposit: PartyAndReference) : Issued = Issued(deposit, this) -infix fun Amount.`issued by`(deposit: PartyAndReference) : Amount> = Amount(quantity, Issued(deposit, this.token)) +val USD = Java.USD +val GBP = Java.GBP +val CHF = Java.CHF + +val Int.DOLLARS: Amount get() = Java.DOLLARS(this) +val Double.DOLLARS: Amount get() = Java.DOLLARS(this) +val Int.POUNDS: Amount get() = Java.POUNDS(this) +val Int.SWISS_FRANCS: Amount get() = Java.SWISS_FRANCS(this) + +infix fun Currency.`issued by`(deposit: PartyAndReference) = Java.issuedBy(this, deposit) +infix fun Amount.`issued by`(deposit: PartyAndReference) = Java.issuedBy(this, deposit) //// Requirements ///////////////////////////////////////////////////////////////////////////////////////////////////// @@ -111,4 +125,4 @@ inline fun verifyMoveCommand(inputs: List LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure { + return body(TransactionForTest()) + } +} + +val TEST_TX_TIME = Java.TEST_TX_TIME +val MEGA_CORP_KEY = Java.MEGA_CORP_KEY +val MEGA_CORP_PUBKEY = Java.MEGA_CORP_PUBKEY +val MINI_CORP_KEY = Java.MINI_CORP_KEY +val MINI_CORP_PUBKEY = Java.MINI_CORP_PUBKEY +val ORACLE_KEY = Java.ORACLE_KEY +val ORACLE_PUBKEY = Java.ORACLE_PUBKEY +val DUMMY_PUBKEY_1 = Java.DUMMY_PUBKEY_1 +val DUMMY_PUBKEY_2 = Java.DUMMY_PUBKEY_2 +val ALICE_KEY = Java.ALICE_KEY +val ALICE_PUBKEY = Java.ALICE_PUBKEY +val ALICE = Java.ALICE +val BOB_KEY = Java.BOB_KEY +val BOB_PUBKEY = Java.BOB_PUBKEY +val BOB = Java.BOB +val MEGA_CORP = Java.MEGA_CORP +val MINI_CORP = Java.MINI_CORP +val DUMMY_NOTARY_KEY = Java.DUMMY_NOTARY_KEY +val DUMMY_NOTARY = Java.DUMMY_NOTARY +val ALL_TEST_KEYS = Java.ALL_TEST_KEYS +val MOCK_IDENTITY_SERVICE = Java.MOCK_IDENTITY_SERVICE + +fun generateStateRef() = Java.generateStateRef() + +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure) = Java.transaction(body) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -120,7 +154,10 @@ abstract class AbstractTransactionForTest { protected val signers = LinkedHashSet() 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> { return commands.map { AuthenticatedObject(it.signers, it.signers.mapNotNull { MOCK_IDENTITY_SERVICE.partyFromKey(it) }, it.value) } @@ -130,10 +167,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) @@ -165,12 +203,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>() + 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() @@ -178,10 +219,13 @@ open class TransactionForTest : AbstractTransactionForTest() { tx.verify() } + @JvmOverloads fun accepts(time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure { runCommandsAndVerify(time) return LastLineShouldTestForAcceptOrFailure.Token } + + @JvmOverloads fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure { val r = try { runCommandsAndVerify(time) @@ -202,8 +246,7 @@ open class TransactionForTest : AbstractTransactionForTest() { * 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) - - fun fails_requirement(msg: String) = this.`fails requirement`(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. @@ -251,10 +294,6 @@ open class TransactionForTest : AbstractTransactionForTest() { } } -fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure { - return body(TransactionForTest()) -} - class TransactionGroupDSL(private val stateType: Class) { open inner class WireTransactionDSL : AbstractTransactionForTest() { private val inStates = ArrayList() @@ -335,6 +374,7 @@ class TransactionGroupDSL(private val stateType: Class) { val txns = ArrayList() private val txnToLabelMap = HashMap() + @JvmOverloads fun transaction(label: String? = null, body: WireTransactionDSL.() -> Unit): WireTransaction { val forTest = InternalWireTransactionDSL() forTest.body() diff --git a/experimental/src/main/kotlin/com/r3corda/contracts/ExperimentalTestUtils.kt b/experimental/src/main/kotlin/com/r3corda/contracts/ExperimentalTestUtils.kt deleted file mode 100644 index 247c57a135..0000000000 --- a/experimental/src/main/kotlin/com/r3corda/contracts/ExperimentalTestUtils.kt +++ /dev/null @@ -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 Obligation.State.`at`(dueBefore: Instant) = copy(template = template.copy(dueBefore = dueBefore)) -infix fun Obligation.State.`between`(parties: Pair) = copy(issuer = parties.first, owner = parties.second) -infix fun Obligation.State.`owned by`(owner: PublicKey) = copy(owner = owner) -infix fun Obligation.State.`issued by`(party: Party) = copy(issuer = party) - -// Allows you to write 100.DOLLARS.OBLIGATION -val Issued.OBLIGATION_DEF: Obligation.StateTemplate get() = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), - nonEmptySetOf(this), Instant.parse("2020-01-01T17:00:00Z")) -val Amount>.OBLIGATION: Obligation.State get() = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP, - this.token.OBLIGATION_DEF, this.quantity, NullPublicKey) \ No newline at end of file diff --git a/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt b/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt new file mode 100644 index 0000000000..d88cb52867 --- /dev/null +++ b/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt @@ -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 at(state: Obligation.State, dueBefore: Instant) = state.copy(template = state.template.copy(dueBefore = dueBefore)) + @JvmStatic fun between(state: Obligation.State, parties: Pair) = state.copy(issuer = parties.first, owner = parties.second) + @JvmStatic fun ownedBy(state: Obligation.State, owner: PublicKey) = state.copy(owner = owner) + @JvmStatic fun issuedBy(state: Obligation.State, party: Party) = state.copy(issuer = party) + + @JvmStatic fun OBLIGATION_DEF(issued: Issued) + = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(issued), Instant.parse("2020-01-01T17:00:00Z")) + @JvmStatic fun OBLIGATION(amount: Amount>) = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP, + OBLIGATION_DEF(amount.token), amount.quantity, NullPublicKey) +} +infix fun Obligation.State.`at`(dueBefore: Instant) = JavaExperimental.at(this, dueBefore) +infix fun Obligation.State.`between`(parties: Pair) = JavaExperimental.between(this, parties) +infix fun Obligation.State.`owned by`(owner: PublicKey) = JavaExperimental.ownedBy(this, owner) +infix fun Obligation.State.`issued by`(party: Party) = JavaExperimental.issuedBy(this, party) + +// Allows you to write 100.DOLLARS.OBLIGATION +val Issued.OBLIGATION_DEF: Obligation.StateTemplate get() = JavaExperimental.OBLIGATION_DEF(this) +val Amount>.OBLIGATION: Obligation.State get() = JavaExperimental.OBLIGATION(this) From 341adafd3a442773f3e57caba7b84dea50438d98 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 24 Jun 2016 16:35:43 +0100 Subject: [PATCH 5/9] contracts, core: Rename Java to JavaTestHelpers --- .../r3corda/contracts/testing/TestUtils.kt | 24 ++++----- .../r3corda/contracts/cash/CashTestsJava.java | 6 +-- .../r3corda/core/contracts/ContractsDSL.kt | 20 ++++---- .../com/r3corda/core/testing/TestUtils.kt | 51 ++++++++++--------- 4 files changed, 51 insertions(+), 50 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt index 7c3e9d6650..d7f3dfc526 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt @@ -49,7 +49,7 @@ fun generateState() = DummyContract.State(Random().nextInt()) // } // For Java compatibility please define helper methods here and then define the infix notation -object Java { +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>(state.amount.quantity, state.issuanceDef.copy(issuer = state.deposit.copy(party = party)))) @JvmStatic fun issuedBy(state: Cash.State, deposit: PartyAndReference) = state.copy(amount = Amount>(state.amount.quantity, state.issuanceDef.copy(issuer = deposit))) @@ -69,21 +69,21 @@ object Java { } -infix fun Cash.State.`owned by`(owner: PublicKey) = Java.ownedBy(this, owner) -infix fun Cash.State.`issued by`(party: Party) = Java.issuedBy(this, party) -infix fun Cash.State.`issued by`(deposit: PartyAndReference) = Java.issuedBy(this, deposit) -infix fun Cash.State.`with notary`(notary: Party) = Java.withNotary(this, notary) -infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = Java.withDeposit(this, deposit) +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) = Java.ownedBy(this, owner) -infix fun CommercialPaper.State.`with notary`(notary: Party) = Java.withNotary(this, notary) -infix fun ICommercialPaperState.`owned by`(new_owner: PublicKey) = Java.ownedBy(this, new_owner) +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) = Java.withNotary(this, notary) +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.CASH: Cash.State get() = Java.CASH(this) -val Amount>.STATE: Cash.State get() = Java.STATE(this) +val Amount.CASH: Cash.State get() = JavaTestHelpers.CASH(this) +val Amount>.STATE: Cash.State get() = JavaTestHelpers.STATE(this) diff --git a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java b/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java index 7dfdaaf849..004ffc6794 100644 --- a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java +++ b/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java @@ -4,9 +4,9 @@ import com.r3corda.core.contracts.PartyAndReference; import com.r3corda.core.serialization.OpaqueBytes; import org.junit.Test; -import static com.r3corda.core.testing.Java.*; -import static com.r3corda.core.contracts.Java.*; -import static com.r3corda.contracts.testing.Java.*; +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 diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 32d370341f..6bf07684bc 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -20,7 +20,7 @@ import java.util.* fun currency(code: String) = Currency.getInstance(code) // Java interop -object Java { +object JavaTestHelpers { @JvmField val USD = currency("USD") @JvmField val GBP = currency("GBP") @JvmField val CHF = currency("CHF") @@ -34,17 +34,17 @@ object Java { @JvmStatic fun issuedBy(amount: Amount, deposit: PartyAndReference) = Amount(amount.quantity, issuedBy(amount.token, deposit)) } -val USD = Java.USD -val GBP = Java.GBP -val CHF = Java.CHF +val USD = JavaTestHelpers.USD +val GBP = JavaTestHelpers.GBP +val CHF = JavaTestHelpers.CHF -val Int.DOLLARS: Amount get() = Java.DOLLARS(this) -val Double.DOLLARS: Amount get() = Java.DOLLARS(this) -val Int.POUNDS: Amount get() = Java.POUNDS(this) -val Int.SWISS_FRANCS: Amount get() = Java.SWISS_FRANCS(this) +val Int.DOLLARS: Amount get() = JavaTestHelpers.DOLLARS(this) +val Double.DOLLARS: Amount get() = JavaTestHelpers.DOLLARS(this) +val Int.POUNDS: Amount get() = JavaTestHelpers.POUNDS(this) +val Int.SWISS_FRANCS: Amount get() = JavaTestHelpers.SWISS_FRANCS(this) -infix fun Currency.`issued by`(deposit: PartyAndReference) = Java.issuedBy(this, deposit) -infix fun Amount.`issued by`(deposit: PartyAndReference) = Java.issuedBy(this, deposit) +infix fun Currency.`issued by`(deposit: PartyAndReference) = JavaTestHelpers.issuedBy(this, deposit) +infix fun Amount.`issued by`(deposit: PartyAndReference) = JavaTestHelpers.issuedBy(this, deposit) //// Requirements ///////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index dec02561d6..cb15837e18 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -50,9 +50,10 @@ object TestUtils { * - 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 [Java] + * - The Int.DOLLARS syntax doesn't work from Java. To remedy add a @JvmStatic DOLLARS(Int) function to + * [JavaTestHelpers] */ -object Java { +object JavaTestHelpers { // A dummy time at which we will be pretending test transactions are created. @JvmField val TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z") @@ -94,31 +95,31 @@ object Java { } } -val TEST_TX_TIME = Java.TEST_TX_TIME -val MEGA_CORP_KEY = Java.MEGA_CORP_KEY -val MEGA_CORP_PUBKEY = Java.MEGA_CORP_PUBKEY -val MINI_CORP_KEY = Java.MINI_CORP_KEY -val MINI_CORP_PUBKEY = Java.MINI_CORP_PUBKEY -val ORACLE_KEY = Java.ORACLE_KEY -val ORACLE_PUBKEY = Java.ORACLE_PUBKEY -val DUMMY_PUBKEY_1 = Java.DUMMY_PUBKEY_1 -val DUMMY_PUBKEY_2 = Java.DUMMY_PUBKEY_2 -val ALICE_KEY = Java.ALICE_KEY -val ALICE_PUBKEY = Java.ALICE_PUBKEY -val ALICE = Java.ALICE -val BOB_KEY = Java.BOB_KEY -val BOB_PUBKEY = Java.BOB_PUBKEY -val BOB = Java.BOB -val MEGA_CORP = Java.MEGA_CORP -val MINI_CORP = Java.MINI_CORP -val DUMMY_NOTARY_KEY = Java.DUMMY_NOTARY_KEY -val DUMMY_NOTARY = Java.DUMMY_NOTARY -val ALL_TEST_KEYS = Java.ALL_TEST_KEYS -val MOCK_IDENTITY_SERVICE = Java.MOCK_IDENTITY_SERVICE +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() = Java.generateStateRef() +fun generateStateRef() = JavaTestHelpers.generateStateRef() -fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure) = Java.transaction(body) +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure) = JavaTestHelpers.transaction(body) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // From bc326660a3e653ba65671a8f82eef85d190ba549 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 24 Jun 2016 16:36:35 +0100 Subject: [PATCH 6/9] contracts, core: Fix static init cycle issue of JavaTestHelpers --- .../r3corda/contracts/cash/CashTestsJava.java | 16 +++---- .../r3corda/core/contracts/ContractsDSL.kt | 6 +-- .../com/r3corda/core/testing/TestUtils.kt | 43 ++++++++++--------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java b/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java index 004ffc6794..63772ab0dc 100644 --- a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java +++ b/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java @@ -14,9 +14,9 @@ import static com.r3corda.contracts.testing.JavaTestHelpers.*; public class CashTestsJava { private OpaqueBytes defaultRef = new OpaqueBytes(new byte[]{1});; - private PartyAndReference defaultIssuer = MEGA_CORP.ref(defaultRef); - private Cash.State inState = new Cash.State(issuedBy(DOLLARS(1000), defaultIssuer), DUMMY_PUBKEY_1); - private Cash.State outState = new Cash.State(inState.getAmount(), DUMMY_PUBKEY_2);; + 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() { @@ -26,7 +26,7 @@ public class CashTestsJava { tx.failsRequirement("the amounts balance"); tx.tweak(tw -> { - tw.output(new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), DUMMY_PUBKEY_2)); + tw.output(new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), getDUMMY_PUBKEY_2())); return tw.failsRequirement("the amounts balance"); }); @@ -37,20 +37,20 @@ public class CashTestsJava { }); tx.tweak(tw -> { tw.output(outState); - tw.arg(DUMMY_PUBKEY_2, new Cash.Commands.Move()); + 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, MINI_CORP)); - tw.arg(DUMMY_PUBKEY_1, new Cash.Commands.Move()); + 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(DUMMY_PUBKEY_1, new Cash.Commands.Move()); + tw.arg(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); return tw.accepts(); }); }); diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 6bf07684bc..370db1a055 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -21,9 +21,9 @@ fun currency(code: String) = Currency.getInstance(code) // Java interop object JavaTestHelpers { - @JvmField val USD = currency("USD") - @JvmField val GBP = currency("GBP") - @JvmField val CHF = currency("CHF") + @JvmStatic val USD: Currency get() = currency("USD") + @JvmStatic val GBP: Currency get() = currency("GBP") + @JvmStatic val CHF: Currency get() = currency("CHF") @JvmStatic fun DOLLARS(amount: Int) = Amount(amount.toLong() * 100, USD) @JvmStatic fun DOLLARS(amount: Double) = Amount((amount * 100).toLong(), USD) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index cb15837e18..b1b7210688 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -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 @@ -55,38 +56,38 @@ object TestUtils { */ object JavaTestHelpers { // A dummy time at which we will be pretending test transactions are created. - @JvmField val TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z") + @JvmStatic val TEST_TX_TIME: Instant get() = Instant.parse("2015-04-17T12:00:00.00Z") // A few dummy values for testing. - @JvmField val MEGA_CORP_KEY = TestUtils.keypair - @JvmField val MEGA_CORP_PUBKEY = MEGA_CORP_KEY.public + @JvmStatic val MEGA_CORP_KEY: KeyPair get() = TestUtils.keypair + @JvmStatic val MEGA_CORP_PUBKEY: PublicKey get() = MEGA_CORP_KEY.public - @JvmField val MINI_CORP_KEY = TestUtils.keypair2 - @JvmField 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 - @JvmField val ORACLE_KEY = TestUtils.keypair3 - @JvmField val ORACLE_PUBKEY = ORACLE_KEY.public + @JvmStatic val ORACLE_KEY: KeyPair get() = TestUtils.keypair3 + @JvmStatic val ORACLE_PUBKEY: PublicKey get() = ORACLE_KEY.public - @JvmField val DUMMY_PUBKEY_1 = DummyPublicKey("x1") - @JvmField val DUMMY_PUBKEY_2 = DummyPublicKey("x2") + @JvmStatic val DUMMY_PUBKEY_1: PublicKey get() = DummyPublicKey("x1") + @JvmStatic val DUMMY_PUBKEY_2: PublicKey get() = DummyPublicKey("x2") - @JvmField val ALICE_KEY = generateKeyPair() - @JvmField val ALICE_PUBKEY = ALICE_KEY.public - @JvmField val ALICE = Party("Alice", ALICE_PUBKEY) + @JvmStatic val ALICE_KEY: KeyPair get() = generateKeyPair() + @JvmStatic val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public + @JvmStatic val ALICE: Party get() = Party("Alice", ALICE_PUBKEY) - @JvmField val BOB_KEY = generateKeyPair() - @JvmField val BOB_PUBKEY = BOB_KEY.public - @JvmField val BOB = Party("Bob", BOB_PUBKEY) + @JvmStatic val BOB_KEY: KeyPair get() = generateKeyPair() + @JvmStatic val BOB_PUBKEY: PublicKey get() = BOB_KEY.public + @JvmStatic val BOB: Party get() = Party("Bob", BOB_PUBKEY) - @JvmField val MEGA_CORP = Party("MegaCorp", MEGA_CORP_PUBKEY) - @JvmField 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) - @JvmField val DUMMY_NOTARY_KEY = generateKeyPair() - @JvmField val DUMMY_NOTARY = Party("Notary Service", DUMMY_NOTARY_KEY.public) + @JvmStatic val DUMMY_NOTARY_KEY: KeyPair get() = generateKeyPair() + @JvmStatic val DUMMY_NOTARY: Party get() = Party("Notary Service", DUMMY_NOTARY_KEY.public) - @JvmField val ALL_TEST_KEYS = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) + @JvmStatic val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) - @JvmField val MOCK_IDENTITY_SERVICE = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) + @JvmStatic val MOCK_IDENTITY_SERVICE: IdentityService get() = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) @JvmStatic fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0) From 10d8f5cd066ef8937ade2812d383b891a2988b16 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 24 Jun 2016 16:37:34 +0100 Subject: [PATCH 7/9] core: Add comment on how to define globals for the Java test DSL --- .../main/kotlin/com/r3corda/core/testing/TestUtils.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index b1b7210688..2270d8a3ea 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -45,9 +45,13 @@ object TestUtils { * * - 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 vals should be defined in a [Java] object and annotated with @JvmField first and should be referred - * to from the global val. This allows static importing of [Java] in Java tests, which mimicks top-level vals. - * - Same goes for top-level funs. Define them in [Java] with annotation @JvmStatic and define a global alias later. + * - 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 with a custom @JvmStatic get(). 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. From 59737251869dc593f478d22b78d0b4b184eb53bc Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 24 Jun 2016 18:33:21 +0100 Subject: [PATCH 8/9] core: Make top-level side-effecting getters lazy instead --- .../src/main/kotlin/com/r3corda/core/testing/TestUtils.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 2270d8a3ea..75ddecbfc3 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -51,7 +51,7 @@ object TestUtils { * - 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 with a custom @JvmStatic get(). See examples below. + * 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. @@ -75,18 +75,18 @@ object JavaTestHelpers { @JvmStatic val DUMMY_PUBKEY_1: PublicKey get() = DummyPublicKey("x1") @JvmStatic val DUMMY_PUBKEY_2: PublicKey get() = DummyPublicKey("x2") - @JvmStatic val ALICE_KEY: KeyPair get() = generateKeyPair() + @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) - @JvmStatic val BOB_KEY: KeyPair get() = generateKeyPair() + @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) @JvmStatic val MEGA_CORP: Party get() = Party("MegaCorp", MEGA_CORP_PUBKEY) @JvmStatic val MINI_CORP: Party get() = Party("MiniCorp", MINI_CORP_PUBKEY) - @JvmStatic val DUMMY_NOTARY_KEY: KeyPair get() = generateKeyPair() + @JvmStatic val DUMMY_NOTARY_KEY: KeyPair by lazy { generateKeyPair() } @JvmStatic val DUMMY_NOTARY: Party get() = Party("Notary Service", DUMMY_NOTARY_KEY.public) @JvmStatic val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) From 47decb3bbecf89b40019efe3986ba199bb8f0067 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 24 Jun 2016 18:33:53 +0100 Subject: [PATCH 9/9] coree: Expose MOCK_IDENTITY_SERVICE as MockIndentityService instead of IdentityService --- core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 75ddecbfc3..d5148803e6 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -91,7 +91,7 @@ object JavaTestHelpers { @JvmStatic val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) - @JvmStatic val MOCK_IDENTITY_SERVICE: IdentityService get() = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) + @JvmStatic val MOCK_IDENTITY_SERVICE: MockIdentityService get() = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) @JvmStatic fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)