mirror of
https://github.com/corda/corda.git
synced 2025-02-21 17:56:54 +00:00
core, contracts: Rewrite Generators to use functions instead of classes
This commit is contained in:
parent
491b1abd4a
commit
2ac31a53b5
@ -16,73 +16,55 @@ import java.util.*
|
|||||||
* This file contains generators for quickcheck style testing. The idea is that we can write random instance generators
|
* This file contains generators for quickcheck style testing. The idea is that we can write random instance generators
|
||||||
* for each type we have in the code and test against those instead of predefined mock data. This style of testing can
|
* for each type we have in the code and test against those instead of predefined mock data. This style of testing can
|
||||||
* catch corner case bugs and test algebraic properties of the code, for example deserialize(serialize(generatedThing)) == generatedThing
|
* catch corner case bugs and test algebraic properties of the code, for example deserialize(serialize(generatedThing)) == generatedThing
|
||||||
*
|
|
||||||
* TODO add combinators for easier Generator writing
|
|
||||||
*/
|
*/
|
||||||
class ContractStateGenerator : Generator<ContractState>(ContractState::class.java) {
|
val contractStateGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): ContractState {
|
Cash.State(
|
||||||
return Cash.State(
|
amount = amountGenerator(issuedGenerator(currencyGenerator)).generate(random, status),
|
||||||
amount = AmountGenerator(IssuedGenerator(CurrencyGenerator())).generate(random, status),
|
owner = publicKeyGenerator.generate(random, status)
|
||||||
owner = PublicKeyGenerator().generate(random, status)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoveGenerator : Generator<Cash.Commands.Move>(Cash.Commands.Move::class.java) {
|
val moveGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Cash.Commands.Move {
|
Cash.Commands.Move(secureHashGenerator.generate(random, status))
|
||||||
return Cash.Commands.Move(SecureHashGenerator().generate(random, status))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IssueGenerator : Generator<Cash.Commands.Issue>(Cash.Commands.Issue::class.java) {
|
val issueGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Cash.Commands.Issue {
|
Cash.Commands.Issue(random.nextLong())
|
||||||
return Cash.Commands.Issue(random.nextLong())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExitGenerator : Generator<Cash.Commands.Exit>(Cash.Commands.Exit::class.java) {
|
val exitGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Cash.Commands.Exit {
|
Cash.Commands.Exit(amountGenerator(issuedGenerator(currencyGenerator)).generate(random, status))
|
||||||
return Cash.Commands.Exit(AmountGenerator(IssuedGenerator(CurrencyGenerator())).generate(random, status))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommandDataGenerator : Generator<CommandData>(CommandData::class.java) {
|
val commandDataGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): CommandData {
|
val generators = listOf(moveGenerator, issueGenerator, exitGenerator)
|
||||||
val generators = listOf(MoveGenerator(), IssueGenerator(), ExitGenerator())
|
generators[random.nextInt(0, generators.size - 1)].generate(random, status)
|
||||||
return generators[random.nextInt(0, generators.size - 1)].generate(random, status)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommandGenerator : Generator<Command>(Command::class.java) {
|
val commandGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Command {
|
val signersGenerator = ArrayListGenerator()
|
||||||
val signersGenerator = ArrayListGenerator()
|
signersGenerator.addComponentGenerators(listOf(publicKeyGenerator))
|
||||||
signersGenerator.addComponentGenerators(listOf(PublicKeyGenerator()))
|
Command(commandDataGenerator.generate(random, status), publicKeyGenerator.generate(random, status))
|
||||||
return Command(CommandDataGenerator().generate(random, status), PublicKeyGenerator().generate(random, status))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WiredTransactionGenerator: Generator<WireTransaction>(WireTransaction::class.java) {
|
val wiredTransactionGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): WireTransaction {
|
val commands = commandGenerator.generateList(random, status) + listOf(commandGenerator.generate(random, status))
|
||||||
val commands = CommandGenerator().generateList(random, status) + listOf(CommandGenerator().generate(random, status))
|
WireTransaction(
|
||||||
return WireTransaction(
|
inputs = stateRefGenerator.generateList(random, status),
|
||||||
inputs = StateRefGenerator().generateList(random, status),
|
attachments = secureHashGenerator.generateList(random, status),
|
||||||
attachments = SecureHashGenerator().generateList(random, status),
|
outputs = transactionStateGenerator(contractStateGenerator).generateList(random, status),
|
||||||
outputs = TransactionStateGenerator(ContractStateGenerator()).generateList(random, status),
|
commands = commands,
|
||||||
commands = commands,
|
notary = partyGenerator.generate(random, status),
|
||||||
notary = PartyGenerator().generate(random, status),
|
signers = commands.flatMap { it.signers },
|
||||||
signers = commands.flatMap { it.signers },
|
type = TransactionType.General(),
|
||||||
type = TransactionType.General(),
|
timestamp = timestampGenerator.generate(random, status)
|
||||||
timestamp = TimestampGenerator().generate(random, status)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SignedTransactionGenerator: Generator<SignedTransaction>(SignedTransaction::class.java) {
|
val signedTransactionGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): SignedTransaction {
|
val wireTransaction = wiredTransactionGenerator.generate(random, status)
|
||||||
val wireTransaction = WiredTransactionGenerator().generate(random, status)
|
SignedTransaction(
|
||||||
return SignedTransaction(
|
txBits = wireTransaction.serialized,
|
||||||
txBits = wireTransaction.serialized,
|
sigs = listOf(NullSignature)
|
||||||
sigs = listOf(NullSignature)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package com.r3corda.core.testing
|
|||||||
import com.pholser.junit.quickcheck.generator.GenerationStatus
|
import com.pholser.junit.quickcheck.generator.GenerationStatus
|
||||||
import com.pholser.junit.quickcheck.generator.Generator
|
import com.pholser.junit.quickcheck.generator.Generator
|
||||||
import com.pholser.junit.quickcheck.generator.java.lang.StringGenerator
|
import com.pholser.junit.quickcheck.generator.java.lang.StringGenerator
|
||||||
|
import com.pholser.junit.quickcheck.generator.java.time.DurationGenerator
|
||||||
|
import com.pholser.junit.quickcheck.generator.java.time.InstantGenerator
|
||||||
import com.pholser.junit.quickcheck.generator.java.util.ArrayListGenerator
|
import com.pholser.junit.quickcheck.generator.java.util.ArrayListGenerator
|
||||||
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
||||||
import com.r3corda.core.contracts.*
|
import com.r3corda.core.contracts.*
|
||||||
@ -27,84 +29,71 @@ fun <A> Generator<A>.generateList(random: SourceOfRandomness, status: Generation
|
|||||||
return arrayGenerator.generate(random, status) as List<A>
|
return arrayGenerator.generate(random, status) as List<A>
|
||||||
}
|
}
|
||||||
|
|
||||||
class PrivateKeyGenerator: Generator<PrivateKey>(PrivateKey::class.java) {
|
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): PrivateKey {
|
inline fun <reified B : Any> generator(
|
||||||
return entropyToKeyPair(random.nextBigInteger(32)).private
|
crossinline generatorFunction: (SourceOfRandomness, GenerationStatus) -> B
|
||||||
|
): Generator<B> {
|
||||||
|
return object : Generator<B>(B::class.java) {
|
||||||
|
override fun generate(random: SourceOfRandomness, status: GenerationStatus) = generatorFunction(random, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PublicKeyGenerator: Generator<PublicKey>(PublicKey::class.java) {
|
val privateKeyGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): PublicKey {
|
entropyToKeyPair(random.nextBigInteger(32)).private
|
||||||
return entropyToKeyPair(random.nextBigInteger(32)).public
|
}
|
||||||
}
|
class PrivateKeyGenerator : Generator<PrivateKey>(PrivateKey::class.java) {
|
||||||
|
override fun generate(random: SourceOfRandomness, status: GenerationStatus) = privateKeyGenerator.generate(random, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PartyGenerator: Generator<Party>(Party::class.java) {
|
val publicKeyGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Party {
|
entropyToKeyPair(random.nextBigInteger(32)).public
|
||||||
return Party(StringGenerator().generate(random, status), PublicKeyGenerator().generate(random, status))
|
}
|
||||||
}
|
class PublicKeyGenerator : Generator<PublicKey>(PublicKey::class.java) {
|
||||||
|
override fun generate(random: SourceOfRandomness, status: GenerationStatus) = publicKeyGenerator.generate(random, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PartyAndReferenceGenerator: Generator<PartyAndReference>(PartyAndReference::class.java) {
|
val partyGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): PartyAndReference {
|
Party(StringGenerator().generate(random, status), publicKeyGenerator.generate(random, status))
|
||||||
return PartyAndReference(PartyGenerator().generate(random, status), OpaqueBytes(random.nextBytes(16)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SecureHashGenerator: Generator<SecureHash>(SecureHash::class.java) {
|
val partyAndReferenceGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): SecureHash {
|
PartyAndReference(partyGenerator.generate(random, status), OpaqueBytes(random.nextBytes(16)))
|
||||||
return SecureHash.Companion.sha256(random.nextBytes(16))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StateRefGenerator: Generator<StateRef>(StateRef::class.java) {
|
val secureHashGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): StateRef {
|
SecureHash.Companion.sha256(random.nextBytes(16))
|
||||||
return StateRef(SecureHash.Companion.sha256(random.nextBytes(16)), random.nextInt(0, 10))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TransactionStateGenerator<T : ContractState>(val stateGenerator: Generator<T>) : Generator<TransactionState<T>>(TransactionState::class.java as Class<TransactionState<T>>) {
|
val stateRefGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): TransactionState<T> {
|
StateRef(SecureHash.Companion.sha256(random.nextBytes(16)), random.nextInt(0, 10))
|
||||||
return TransactionState(stateGenerator.generate(random, status), PartyGenerator().generate(random, status))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IssuedGenerator<T>(val productGenerator: Generator<T>) : Generator<Issued<T>>(Issued::class.java as Class<Issued<T>>) {
|
fun <T : ContractState> transactionStateGenerator(stateGenerator: Generator<T>) = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Issued<T> {
|
TransactionState(stateGenerator.generate(random, status), partyGenerator.generate(random, status))
|
||||||
return Issued(PartyAndReferenceGenerator().generate(random, status), productGenerator.generate(random, status))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AmountGenerator<T>(val tokenGenerator: Generator<T>) : Generator<Amount<T>>(Amount::class.java as Class<Amount<T>>) {
|
fun <T> issuedGenerator(productGenerator: Generator<T>) = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Amount<T> {
|
Issued(partyAndReferenceGenerator.generate(random, status), productGenerator.generate(random, status))
|
||||||
return Amount(random.nextLong(0, 1000000), tokenGenerator.generate(random, status))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CurrencyGenerator() : Generator<Currency>(Currency::class.java) {
|
fun <T> amountGenerator(tokenGenerator: Generator<T>) = generator { random, status ->
|
||||||
companion object {
|
Amount(random.nextLong(0, 1000000), tokenGenerator.generate(random, status))
|
||||||
val currencies = Currency.getAvailableCurrencies().toList()
|
|
||||||
}
|
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Currency {
|
|
||||||
return currencies[random.nextInt(0, currencies.size - 1)]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class InstantGenerator : Generator<Instant>(Instant::class.java) {
|
private val currencies = Currency.getAvailableCurrencies().toList()
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Instant {
|
val currencyGenerator = generator { random, status ->
|
||||||
return Instant.ofEpochMilli(random.nextLong(0, 1000000))
|
currencies[random.nextInt(0, currencies.size - 1)]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DurationGenerator : Generator<Duration>(Duration::class.java) {
|
val instantGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Duration {
|
Instant.ofEpochMilli(random.nextLong(0, 1000000))
|
||||||
return Duration.ofMillis(random.nextLong(0, 1000000))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimestampGenerator : Generator<Timestamp>(Timestamp::class.java) {
|
val durationGenerator = generator { random, status ->
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Timestamp {
|
Duration.ofMillis(random.nextLong(0, 1000000))
|
||||||
return Timestamp(InstantGenerator().generate(random, status), DurationGenerator().generate(random, status))
|
}
|
||||||
}
|
|
||||||
|
val timestampGenerator = generator { random, status ->
|
||||||
|
Timestamp(InstantGenerator().generate(random, status), DurationGenerator().generate(random, status))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,15 +2,17 @@ package com.r3corda.core.protocols
|
|||||||
|
|
||||||
import com.esotericsoftware.kryo.io.Input
|
import com.esotericsoftware.kryo.io.Input
|
||||||
import com.pholser.junit.quickcheck.From
|
import com.pholser.junit.quickcheck.From
|
||||||
|
import com.pholser.junit.quickcheck.Produced
|
||||||
import com.pholser.junit.quickcheck.Property
|
import com.pholser.junit.quickcheck.Property
|
||||||
import com.pholser.junit.quickcheck.generator.GenerationStatus
|
import com.pholser.junit.quickcheck.generator.GenerationStatus
|
||||||
import com.pholser.junit.quickcheck.generator.Generator
|
import com.pholser.junit.quickcheck.generator.Generator
|
||||||
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
||||||
import com.pholser.junit.quickcheck.runner.JUnitQuickcheck
|
import com.pholser.junit.quickcheck.runner.JUnitQuickcheck
|
||||||
import com.r3corda.contracts.testing.SignedTransactionGenerator
|
import com.r3corda.contracts.testing.signedTransactionGenerator
|
||||||
import com.r3corda.core.serialization.createKryo
|
import com.r3corda.core.serialization.createKryo
|
||||||
import com.r3corda.core.serialization.serialize
|
import com.r3corda.core.serialization.serialize
|
||||||
import com.r3corda.core.testing.PartyGenerator
|
import com.r3corda.core.testing.generator
|
||||||
|
import com.r3corda.core.testing.partyGenerator
|
||||||
import com.r3corda.protocols.BroadcastTransactionProtocol
|
import com.r3corda.protocols.BroadcastTransactionProtocol
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -18,15 +20,18 @@ import kotlin.test.assertEquals
|
|||||||
@RunWith(JUnitQuickcheck::class)
|
@RunWith(JUnitQuickcheck::class)
|
||||||
class BroadcastTransactionProtocolTest {
|
class BroadcastTransactionProtocolTest {
|
||||||
|
|
||||||
class NotifyTxRequestMessageGenerator : Generator<BroadcastTransactionProtocol.NotifyTxRequestMessage>(BroadcastTransactionProtocol.NotifyTxRequestMessage::class.java) {
|
companion object {
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): BroadcastTransactionProtocol.NotifyTxRequestMessage {
|
val notifyTxRequestMessageGenerator = generator { random, status ->
|
||||||
return BroadcastTransactionProtocol.NotifyTxRequestMessage(
|
BroadcastTransactionProtocol.NotifyTxRequestMessage(
|
||||||
tx = SignedTransactionGenerator().generate(random, status),
|
tx = signedTransactionGenerator.generate(random, status),
|
||||||
events = setOf(),
|
events = setOf(),
|
||||||
replyToParty = PartyGenerator().generate(random, status),
|
replyToParty = partyGenerator.generate(random, status),
|
||||||
sessionID = random.nextLong()
|
sessionID = random.nextLong()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
class NotifyTxRequestMessageGenerator: Generator<BroadcastTransactionProtocol.NotifyTxRequestMessage>(BroadcastTransactionProtocol.NotifyTxRequestMessage::class.java) {
|
||||||
|
override fun generate(random: SourceOfRandomness, status: GenerationStatus) = notifyTxRequestMessageGenerator.generate(random, status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
|
Loading…
x
Reference in New Issue
Block a user