mirror of
https://github.com/corda/corda.git
synced 2025-02-21 09:51:57 +00:00
testdsl: Add failsWith to Ledger
This commit is contained in:
parent
cd0299f650
commit
9bb8439dc3
@ -85,7 +85,7 @@ class CommercialPaperTestsGeneric {
|
||||
input("paper")
|
||||
input("alice's $900")
|
||||
output("borrowed $900") { 900.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
|
||||
output("alice's paper") { "paper".output<ICommercialPaperState>().data `owned by` ALICE_PUBKEY }
|
||||
output("alice's paper") { "paper".output<ICommercialPaperState>() `owned by` ALICE_PUBKEY }
|
||||
command(ALICE_PUBKEY) { Cash.Commands.Move() }
|
||||
command(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() }
|
||||
this.verifies()
|
||||
@ -120,7 +120,7 @@ class CommercialPaperTestsGeneric {
|
||||
timestamp(TEST_TX_TIME + 8.days)
|
||||
|
||||
tweak {
|
||||
output { "paper".output<ICommercialPaperState>().data }
|
||||
output { "paper".output<ICommercialPaperState>() }
|
||||
this `fails with` "must be destroyed"
|
||||
}
|
||||
|
||||
|
@ -377,11 +377,11 @@ class IRSTests {
|
||||
input("irs post agreement")
|
||||
val postAgreement = "irs post agreement".output<InterestRateSwap.State>()
|
||||
output("irs post first fixing") {
|
||||
postAgreement.data.copy(
|
||||
postAgreement.data.fixedLeg,
|
||||
postAgreement.data.floatingLeg,
|
||||
postAgreement.data.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))),
|
||||
postAgreement.data.common
|
||||
postAgreement.copy(
|
||||
postAgreement.fixedLeg,
|
||||
postAgreement.floatingLeg,
|
||||
postAgreement.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))),
|
||||
postAgreement.common
|
||||
)
|
||||
}
|
||||
command(ORACLE_PUBKEY) {
|
||||
@ -693,20 +693,20 @@ class IRSTests {
|
||||
input("irs post agreement2")
|
||||
val postAgreement1 = "irs post agreement1".output<InterestRateSwap.State>()
|
||||
output("irs post first fixing1") {
|
||||
postAgreement1.data.copy(
|
||||
postAgreement1.data.fixedLeg,
|
||||
postAgreement1.data.floatingLeg,
|
||||
postAgreement1.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))),
|
||||
postAgreement1.data.common.copy(tradeID = "t1")
|
||||
postAgreement1.copy(
|
||||
postAgreement1.fixedLeg,
|
||||
postAgreement1.floatingLeg,
|
||||
postAgreement1.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))),
|
||||
postAgreement1.common.copy(tradeID = "t1")
|
||||
)
|
||||
}
|
||||
val postAgreement2 = "irs post agreement2".output<InterestRateSwap.State>()
|
||||
output("irs post first fixing2") {
|
||||
postAgreement2.data.copy(
|
||||
postAgreement2.data.fixedLeg,
|
||||
postAgreement2.data.floatingLeg,
|
||||
postAgreement2.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))),
|
||||
postAgreement2.data.common.copy(tradeID = "t2")
|
||||
postAgreement2.copy(
|
||||
postAgreement2.fixedLeg,
|
||||
postAgreement2.floatingLeg,
|
||||
postAgreement2.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))),
|
||||
postAgreement2.common.copy(tradeID = "t2")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,225 @@
|
||||
package com.r3corda.contracts.asset;
|
||||
|
||||
import kotlin.Unit;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.r3corda.core.testing.JavaTestHelpers.*;
|
||||
import static com.r3corda.core.contracts.JavaTestHelpers.*;
|
||||
|
||||
public class TmpTest {
|
||||
|
||||
public static class Asd {
|
||||
@Test
|
||||
public void emptyLedger() {
|
||||
ledger(l -> {
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
//
|
||||
// @Test
|
||||
// public void simpleCashDoesntCompile() {
|
||||
// Cash.State inState = new Cash.State(
|
||||
// issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
// getDUMMY_PUBKEY_1()
|
||||
// );
|
||||
// ledger(l -> {
|
||||
// l.transaction(tx -> {
|
||||
// tx.input(inState);
|
||||
// });
|
||||
// return Unit.INSTANCE;
|
||||
// });
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void simpleCash() {
|
||||
Cash.State inState = new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getDUMMY_PUBKEY_1()
|
||||
);
|
||||
ledger(l -> {
|
||||
l.transaction(tx -> {
|
||||
tx.input(inState);
|
||||
return tx.verifies();
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCashFailsWith() {
|
||||
Cash.State inState = new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getDUMMY_PUBKEY_1()
|
||||
);
|
||||
ledger(l -> {
|
||||
l.transaction(tx -> {
|
||||
tx.input(inState);
|
||||
return tx.failsWith("the amounts balance");
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCashSuccess() {
|
||||
Cash.State inState = new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getDUMMY_PUBKEY_1()
|
||||
);
|
||||
ledger(l -> {
|
||||
l.transaction(tx -> {
|
||||
tx.input(inState);
|
||||
tx.failsWith("the amounts balance");
|
||||
tx.output(inState.copy(inState.getAmount(), getDUMMY_PUBKEY_2()));
|
||||
tx.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCashTweakSuccess() {
|
||||
Cash.State inState = new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getDUMMY_PUBKEY_1()
|
||||
);
|
||||
ledger(l -> {
|
||||
l.transaction(tx -> {
|
||||
tx.input(inState);
|
||||
tx.failsWith("the amounts balance");
|
||||
tx.output(inState.copy(inState.getAmount(), getDUMMY_PUBKEY_2()));
|
||||
|
||||
tx.tweak(tw -> {
|
||||
tw.command(getDUMMY_PUBKEY_2(), new Cash.Commands.Move());
|
||||
return tw.failsWith("the owning keys are the same as the signing keys");
|
||||
});
|
||||
tx.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCashTweakSuccessTopLevelTransaction() {
|
||||
Cash.State inState = new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getDUMMY_PUBKEY_1()
|
||||
);
|
||||
transaction(tx -> {
|
||||
tx.input(inState);
|
||||
tx.failsWith("the amounts balance");
|
||||
tx.output(inState.copy(inState.getAmount(), getDUMMY_PUBKEY_2()));
|
||||
|
||||
tx.tweak(tw -> {
|
||||
tw.command(getDUMMY_PUBKEY_2(), new Cash.Commands.Move());
|
||||
return tw.failsWith("the owning keys are the same as the signing keys");
|
||||
});
|
||||
tx.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void chainCash() {
|
||||
ledger(l -> {
|
||||
l.unverifiedTransaction(tx -> {
|
||||
tx.output("MEGA_CORP cash",
|
||||
new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getMEGA_CORP_PUBKEY()
|
||||
)
|
||||
);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
l.transaction(tx -> {
|
||||
tx.input("MEGA_CORP cash");
|
||||
Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash");
|
||||
tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_1()));
|
||||
tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chainCashDoubleSpend() {
|
||||
ledger(l -> {
|
||||
l.unverifiedTransaction(tx -> {
|
||||
tx.output("MEGA_CORP cash",
|
||||
new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getMEGA_CORP_PUBKEY()
|
||||
)
|
||||
);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
l.transaction(tx -> {
|
||||
tx.input("MEGA_CORP cash");
|
||||
Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash");
|
||||
tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_1()));
|
||||
tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
|
||||
l.transaction(tx -> {
|
||||
tx.input("MEGA_CORP cash");
|
||||
Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash");
|
||||
// We send it to another pubkey so that the transaction is not identical to the previous one
|
||||
tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_2()));
|
||||
tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chainCashDoubleSpendFailsWith() {
|
||||
ledger(l -> {
|
||||
l.unverifiedTransaction(tx -> {
|
||||
tx.output("MEGA_CORP cash",
|
||||
new Cash.State(
|
||||
issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)),
|
||||
getMEGA_CORP_PUBKEY()
|
||||
)
|
||||
);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
l.transaction(tx -> {
|
||||
tx.input("MEGA_CORP cash");
|
||||
Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash");
|
||||
tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_1()));
|
||||
tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
|
||||
l.tweak(lw -> {
|
||||
lw.transaction(tx -> {
|
||||
tx.input("MEGA_CORP cash");
|
||||
Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash");
|
||||
// We send it to another pubkey so that the transaction is not identical to the previous one
|
||||
tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_2()));
|
||||
tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
|
||||
return tx.verifies();
|
||||
});
|
||||
lw.fails();
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
l.verifies();
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
209
contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.kt
Normal file
209
contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.kt
Normal file
@ -0,0 +1,209 @@
|
||||
package com.r3corda.contracts.asset
|
||||
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.`issued by`
|
||||
import com.r3corda.core.testing.*
|
||||
import org.junit.Test
|
||||
|
||||
|
||||
class Asd {
|
||||
|
||||
class Asd {
|
||||
|
||||
@Test
|
||||
fun emptyLedger() {
|
||||
ledger {
|
||||
}
|
||||
}
|
||||
//
|
||||
// @Test
|
||||
// fun simpleCashFails() {
|
||||
// ledger {
|
||||
// transaction {
|
||||
// input(Cash.State(
|
||||
// amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
// owner = DUMMY_PUBKEY_1
|
||||
// ))
|
||||
// this.verifies()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun simpleCash() {
|
||||
val inState = Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = DUMMY_PUBKEY_1
|
||||
)
|
||||
ledger {
|
||||
transaction {
|
||||
input(inState)
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simpleCashFailsWith() {
|
||||
val inState = Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = DUMMY_PUBKEY_1
|
||||
)
|
||||
ledger {
|
||||
transaction {
|
||||
input(inState)
|
||||
this `fails with` "the amounts balance"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simpleCashSuccess() {
|
||||
val inState = Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = DUMMY_PUBKEY_1
|
||||
)
|
||||
ledger {
|
||||
transaction {
|
||||
input(inState)
|
||||
this `fails with` "the amounts balance"
|
||||
output(inState.copy(owner = DUMMY_PUBKEY_2))
|
||||
command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simpleCashTweakSuccess() {
|
||||
val inState = Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = DUMMY_PUBKEY_1
|
||||
)
|
||||
ledger {
|
||||
transaction {
|
||||
input(inState)
|
||||
this `fails with` "the amounts balance"
|
||||
output(inState.copy(owner = DUMMY_PUBKEY_2))
|
||||
|
||||
tweak {
|
||||
command(DUMMY_PUBKEY_2) { Cash.Commands.Move() }
|
||||
this `fails with` "the owning keys are the same as the signing keys"
|
||||
}
|
||||
|
||||
command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simpleCashTweakSuccessTopLevelTransaction() {
|
||||
val inState = Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = DUMMY_PUBKEY_1
|
||||
)
|
||||
transaction {
|
||||
input(inState)
|
||||
this `fails with` "the amounts balance"
|
||||
output(inState.copy(owner = DUMMY_PUBKEY_2))
|
||||
|
||||
tweak {
|
||||
command(DUMMY_PUBKEY_2) { Cash.Commands.Move() }
|
||||
this `fails with` "the owning keys are the same as the signing keys"
|
||||
}
|
||||
|
||||
command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun chainCash() {
|
||||
ledger {
|
||||
unverifiedTransaction {
|
||||
output("MEGA_CORP cash") {
|
||||
Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = MEGA_CORP_PUBKEY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
transaction {
|
||||
input("MEGA_CORP cash")
|
||||
output("MEGA_CORP cash".output<Cash.State>().copy(owner = DUMMY_PUBKEY_1))
|
||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun chainCashDoubleSpend() {
|
||||
ledger {
|
||||
unverifiedTransaction {
|
||||
output("MEGA_CORP cash") {
|
||||
Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = MEGA_CORP_PUBKEY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
transaction {
|
||||
input("MEGA_CORP cash")
|
||||
output("MEGA_CORP cash".output<Cash.State>().copy(owner = DUMMY_PUBKEY_1))
|
||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
|
||||
transaction {
|
||||
input("MEGA_CORP cash")
|
||||
// We send it to another pubkey so that the transaction is not identical to the previous one
|
||||
output("MEGA_CORP cash".output<Cash.State>().copy(owner = DUMMY_PUBKEY_1))
|
||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chainCashDoubleSpendFailsWith() {
|
||||
ledger {
|
||||
unverifiedTransaction {
|
||||
output("MEGA_CORP cash") {
|
||||
Cash.State(
|
||||
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
|
||||
owner = MEGA_CORP_PUBKEY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
transaction {
|
||||
input("MEGA_CORP cash")
|
||||
output("MEGA_CORP cash".output<Cash.State>().copy(owner = DUMMY_PUBKEY_1))
|
||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
|
||||
tweak {
|
||||
transaction {
|
||||
input("MEGA_CORP cash")
|
||||
// We send it to another pubkey so that the transaction is not identical to the previous one
|
||||
output("MEGA_CORP cash".output<Cash.State>().copy(owner = DUMMY_PUBKEY_2))
|
||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
this.verifies()
|
||||
}
|
||||
this.fails()
|
||||
}
|
||||
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -169,4 +169,4 @@ operator fun KeyPair.component1() = this.private
|
||||
operator fun KeyPair.component2() = this.public
|
||||
|
||||
/** A simple wrapper that will make it easier to swap out the EC algorithm we use in future */
|
||||
fun generateKeyPair() = EddsaKeyPairGenerator().generateKeyPair()!!
|
||||
fun generateKeyPair(): KeyPair = EddsaKeyPairGenerator().generateKeyPair()
|
||||
|
@ -61,6 +61,12 @@ interface LedgerDSLInterpreter<R, out T : TransactionDSLInterpreter<R>> : Output
|
||||
* Verifies the ledger using [TransactionGroup.verify], throws if the verification fails.
|
||||
*/
|
||||
fun verifies()
|
||||
|
||||
/**
|
||||
* Verifies the ledger, expecting an exception to be thrown.
|
||||
* @param expectedMessage: An optional string to be searched for in the raised exception.
|
||||
*/
|
||||
fun failsWith(expectedMessage: String?)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,12 +103,28 @@ class LedgerDSL<R, out T : TransactionDSLInterpreter<R>, out L : LedgerDSLInterp
|
||||
* Retrieves the output [TransactionState] based on the label.
|
||||
* @see OutputStateLookup.retrieveOutputStateAndRef
|
||||
*/
|
||||
inline fun <reified S : ContractState> String.output(): TransactionState<S> =
|
||||
outputStateAndRef<S>().state
|
||||
inline fun <reified S : ContractState> String.output(): S =
|
||||
outputStateAndRef<S>().state.data
|
||||
|
||||
/**
|
||||
* Retrieves the output [StateRef] based on the label.
|
||||
* @see OutputStateLookup.retrieveOutputStateAndRef
|
||||
*/
|
||||
fun String.outputRef(): StateRef = outputStateAndRef<ContractState>().ref
|
||||
|
||||
/**
|
||||
* @see OutputStateLookup.retrieveOutputStateAndRef
|
||||
*/
|
||||
fun <S : ContractState> retrieveOutput(clazz: Class<S>, label: String) =
|
||||
retrieveOutputStateAndRef(clazz, label).state.data
|
||||
|
||||
/**
|
||||
* Asserts that the transaction will fail verification
|
||||
*/
|
||||
fun fails() = failsWith(null)
|
||||
|
||||
/**
|
||||
* @see TransactionDSLInterpreter.failsWith
|
||||
*/
|
||||
infix fun `fails with`(msg: String) = failsWith(msg)
|
||||
}
|
||||
|
@ -161,27 +161,8 @@ data class TestTransactionDSLInterpreter private constructor(
|
||||
}
|
||||
|
||||
override fun failsWith(expectedMessage: String?): EnforceVerifyOrFail {
|
||||
val exceptionThrown = try {
|
||||
expectExceptionContainingString(expectedMessage) {
|
||||
this.verifies()
|
||||
false
|
||||
} catch (exception: Exception) {
|
||||
if (expectedMessage != null) {
|
||||
val exceptionMessage = exception.message
|
||||
if (exceptionMessage == null) {
|
||||
throw AssertionError(
|
||||
"Expected exception containing '$expectedMessage' but raised exception had no message"
|
||||
)
|
||||
} else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) {
|
||||
throw AssertionError(
|
||||
"Expected exception containing '$expectedMessage' but raised exception was '$exception'"
|
||||
)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
if (!exceptionThrown) {
|
||||
throw AssertionError("Expected exception but didn't get one")
|
||||
}
|
||||
|
||||
return EnforceVerifyOrFail.Token
|
||||
@ -202,7 +183,6 @@ data class TestLedgerDSLInterpreter private constructor (
|
||||
private val transactionWithLocations: HashMap<SecureHash, WireTransactionWithLocation> = HashMap(),
|
||||
private val nonVerifiedTransactionWithLocations: HashMap<SecureHash, WireTransactionWithLocation> = HashMap()
|
||||
) : LedgerDSLInterpreter<EnforceVerifyOrFail, TestTransactionDSLInterpreter> {
|
||||
|
||||
val wireTransactions: List<WireTransaction> get() = transactionWithLocations.values.map { it.transaction }
|
||||
|
||||
// We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling
|
||||
@ -211,19 +191,25 @@ data class TestLedgerDSLInterpreter private constructor (
|
||||
)
|
||||
|
||||
companion object {
|
||||
private fun getCallerLocation(offset: Int): String {
|
||||
val stackTraceElement = Thread.currentThread().stackTrace[3 + offset]
|
||||
return stackTraceElement.toString()
|
||||
private fun getCallerLocation(): String? {
|
||||
val stackTrace = Thread.currentThread().stackTrace
|
||||
for (i in 1 .. stackTrace.size) {
|
||||
val stackTraceElement = stackTrace[i]
|
||||
if (!stackTraceElement.fileName.contains("DSL")) {
|
||||
return stackTraceElement.toString()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
internal data class WireTransactionWithLocation(
|
||||
val label: String?,
|
||||
val transaction: WireTransaction,
|
||||
val location: String
|
||||
val location: String?
|
||||
)
|
||||
class VerifiesFailed(transactionLocation: String, cause: Throwable) :
|
||||
Exception("Transaction defined at ($transactionLocation) didn't verify: $cause", cause)
|
||||
class VerifiesFailed(transactionName: String, cause: Throwable) :
|
||||
Exception("Transaction ($transactionName) didn't verify: $cause", cause)
|
||||
class TypeMismatch(requested: Class<*>, actual: Class<*>) :
|
||||
Exception("Actual type $actual is not a subtype of requested type $requested")
|
||||
|
||||
@ -309,7 +295,7 @@ data class TestLedgerDSLInterpreter private constructor (
|
||||
dsl: TransactionDSL<EnforceVerifyOrFail, TestTransactionDSLInterpreter>.() -> R,
|
||||
transactionMap: HashMap<SecureHash, WireTransactionWithLocation> = HashMap()
|
||||
): WireTransaction {
|
||||
val transactionLocation = getCallerLocation(3)
|
||||
val transactionLocation = getCallerLocation()
|
||||
val transactionInterpreter = interpretTransactionDsl(transactionBuilder, dsl)
|
||||
// Create the WireTransaction
|
||||
val wireTransaction = transactionInterpreter.toWireTransaction()
|
||||
@ -353,7 +339,15 @@ data class TestLedgerDSLInterpreter private constructor (
|
||||
try {
|
||||
transactionGroup.verify()
|
||||
} catch (exception: TransactionVerificationException) {
|
||||
throw VerifiesFailed(transactionWithLocations[exception.tx.origHash]?.location ?: "<unknown>", exception)
|
||||
val transactionWithLocation = transactionWithLocations[exception.tx.origHash]
|
||||
val transactionName = transactionWithLocation?.label ?: transactionWithLocation?.location ?: "<unknown>"
|
||||
throw VerifiesFailed(transactionName, exception)
|
||||
}
|
||||
}
|
||||
|
||||
override fun failsWith(expectedMessage: String?) {
|
||||
expectExceptionContainingString(expectedMessage) {
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,3 +391,28 @@ fun signAll(transactionsToSign: List<WireTransaction>, extraKeys: Array<out KeyP
|
||||
*/
|
||||
fun LedgerDSL<EnforceVerifyOrFail, TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.signAll(
|
||||
vararg extraKeys: KeyPair) = signAll(this.interpreter.wireTransactions, extraKeys)
|
||||
|
||||
internal inline fun expectExceptionContainingString(string: String?, body:() -> Unit) {
|
||||
val exceptionThrown = try {
|
||||
body()
|
||||
false
|
||||
} catch (exception: Exception) {
|
||||
if (string != null) {
|
||||
val exceptionMessage = exception.message
|
||||
if (exceptionMessage == null) {
|
||||
throw AssertionError(
|
||||
"Expected exception containing '$string' but raised exception had no message"
|
||||
)
|
||||
} else if (!exceptionMessage.toLowerCase().contains(string.toLowerCase())) {
|
||||
throw AssertionError(
|
||||
"Expected exception containing '$string' but raised exception was '$exception'"
|
||||
)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
if (!exceptionThrown) {
|
||||
throw AssertionError("Expected exception but didn't get one")
|
||||
}
|
||||
}
|
||||
|
@ -96,10 +96,12 @@ class TransactionDSL<R, out T : TransactionDSLInterpreter<R>> (val interpreter:
|
||||
/**
|
||||
* @see TransactionDSLInterpreter._output
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun output(label: String? = null, contractState: ContractState) =
|
||||
fun output(label: String, contractState: ContractState) =
|
||||
_output(label, DUMMY_NOTARY, contractState)
|
||||
|
||||
fun output(contractState: ContractState) =
|
||||
_output(null, DUMMY_NOTARY, contractState)
|
||||
|
||||
/**
|
||||
* @see TransactionDSLInterpreter._command
|
||||
*/
|
||||
|
@ -88,7 +88,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
override fun generateKeyPair(): KeyPair? = keyPair ?: super.generateKeyPair()
|
||||
override fun generateKeyPair(): KeyPair = keyPair ?: super.generateKeyPair()
|
||||
|
||||
// It's OK to not have a network map service in the mock network.
|
||||
override fun noNetworkMapConfigured() = Futures.immediateFuture(Unit)
|
||||
|
Loading…
x
Reference in New Issue
Block a user