import java.math.BigInteger import java.security.PublicKey import kotlin.test.fail class DummyPublicKey(private val s: String) : PublicKey, Comparable { override fun getAlgorithm() = "DUMMY" override fun getEncoded() = s.toByteArray() override fun getFormat() = "ASN.1" override fun compareTo(other: PublicKey): Int = BigInteger(encoded).compareTo(BigInteger(other.encoded)) override fun toString() = "PUBKEY[$s]" } // A few dummy values for testing. val MEGA_CORP_KEY = DummyPublicKey("mini") val MINI_CORP_KEY = DummyPublicKey("mega") val DUMMY_PUBKEY_1 = DummyPublicKey("x1") val DUMMY_PUBKEY_2 = DummyPublicKey("x2") val MEGA_CORP = Institution("MegaCorp", MEGA_CORP_KEY) val MINI_CORP = Institution("MiniCorp", MINI_CORP_KEY) val keyToCorpMap: Map = mapOf( MEGA_CORP_KEY to MEGA_CORP, MINI_CORP_KEY to MINI_CORP ) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // DSL for building pseudo-transactions (not the same as the wire protocol) for testing purposes. // // Define a transaction like this: // // transaction { // input { someExpression } // output { someExpression } // arg { someExpression } // // transaction { // ... same thing but works with a copy of the parent, can add inputs/outputs/args just within this scope. // } // // contract.accepts() -> should pass // 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 // Corresponds to the args to Contract.verify data class TransactionForTest( private val inStates: MutableList = arrayListOf(), private val outStates: MutableList = arrayListOf(), private val args: MutableList = arrayListOf() ) { fun input(s: () -> ContractState) = inStates.add(s()) fun output(s: () -> ContractState) = outStates.add(s()) fun arg(key: PublicKey, c: () -> Command) = args.add(VerifiedSignedCommand(key, keyToCorpMap[key], c())) infix fun Contract.`fails requirement`(msg: String) { try { verify(inStates, outStates, args) } catch(e: Exception) { val m = e.message if (m == null) fail("Threw exception without a message") else if (!m.contains(msg)) throw AssertionError("Error was actually: $m") } } // which is uglier?? :) fun Contract.fails_requirement(msg: String) = this.`fails requirement`(msg) fun Contract.accepts() { verify(inStates, outStates, args) } // Allow customisation of partial transactions. fun transaction(body: TransactionForTest.() -> Unit): TransactionForTest { val tx = TransactionForTest() tx.inStates.addAll(inStates) tx.outStates.addAll(outStates) tx.args.addAll(args) tx.body() return tx } override fun toString(): String { return """transaction { inputs: $inStates outputs: $outStates args: $args }""" } } fun transaction(body: TransactionForTest.() -> Unit): TransactionForTest { val tx = TransactionForTest() tx.body() return tx }