Universal: completed Cap unit test, full life cycle

This commit is contained in:
sofusmortensen 2016-09-19 00:06:42 +02:00
parent 2299b3beae
commit c328655f68
2 changed files with 86 additions and 79 deletions

View File

@ -115,12 +115,16 @@ class UniversalContract : Contract {
val nextStart = schedule.first() val nextStart = schedule.first()
// todo: look into schedule for final dates // todo: look into schedule for final dates
// todo: we may have to save original start date in order to roll out correctly
val newRollOut = RollOut(nextStart, end, rollOut.frequency, rollOut.template)
val arr = replaceStartEnd(rollOut.template, start.toInstant(), nextStart.toInstant()) val arr = replaceStartEnd(rollOut.template, start.toInstant(), nextStart.toInstant())
return replaceNext(arr, newRollOut ) if (nextStart < end) {
// todo: we may have to save original start date in order to roll out correctly
val newRollOut = RollOut(nextStart, end, rollOut.frequency, rollOut.template)
return replaceNext(arr, newRollOut )
}
else {
return removeNext(arr)
}
} }
fun<T> replaceStartEnd(p: Perceivable<T>, start: Instant, end: Instant) : Perceivable<T> = fun<T> replaceStartEnd(p: Perceivable<T>, start: Instant, end: Instant) : Perceivable<T> =
@ -156,6 +160,21 @@ class UniversalContract : Contract {
else -> throw NotImplementedError("replaceNext " + arrangement.javaClass.name) else -> throw NotImplementedError("replaceNext " + arrangement.javaClass.name)
} }
fun removeNext(arrangement: Arrangement) : Arrangement =
when (arrangement) {
is Actions -> Actions(arrangement.actions.map { Action(it.name, it.condition, it.actors, removeNext(it.arrangement)) }.toSet())
is And -> {
val a = arrangement.arrangements.map { removeNext(it) }.filter { it != zero }
if (a.count() > 1)
And(a.toSet())
else
a.single()
}
is Transfer -> arrangement
is Zero -> arrangement
is Continuation -> zero
else -> throw NotImplementedError("replaceNext " + arrangement.javaClass.name)
}
override fun verify(tx: TransactionForContract) { override fun verify(tx: TransactionForContract) {

View File

@ -23,8 +23,8 @@ class Cap {
val tradeDate: LocalDate = LocalDate.of(2016, 9, 1) val tradeDate: LocalDate = LocalDate.of(2016, 9, 1)
val contract = arrange { val contractInitial = arrange {
rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.Quarterly) { rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) {
actions { actions {
(acmeCorp or highStreetBank).may { (acmeCorp or highStreetBank).may {
"exercise".anytime { "exercise".anytime {
@ -43,14 +43,14 @@ class Cap {
} }
} }
val contractFixed = arrange { val contractAfterFixingFirst = arrange {
actions { actions {
(acmeCorp or highStreetBank).may { (acmeCorp or highStreetBank).may {
"exercise".anytime() { "exercise".anytime() {
val floating1 = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2016-12-01") val floating1 = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2017-03-01")
val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-09-01", "2016-12-01") val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-09-01", "2017-03-01")
highStreetBank.gives(acmeCorp, floating1 - fixed1, currency) highStreetBank.gives(acmeCorp, floating1 - fixed1, currency)
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Quarterly) { rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) {
actions { actions {
(acmeCorp or highStreetBank).may { (acmeCorp or highStreetBank).may {
"exercise".anytime { "exercise".anytime {
@ -71,56 +71,7 @@ class Cap {
} }
acmeCorp.may { acmeCorp.may {
"skip".anytime { "skip".anytime {
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Quarterly) { rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
}
}
}
val contractFixed2 = arrange {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating1 = interest(notional, "act/365", 1.0.bd, "2016-12-01", "2017-03-01")
val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-12-01", "2017-03-01")
highStreetBank.gives(acmeCorp, floating1 - fixed1, currency)
rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
highStreetBank.gives(acmeCorp, floating - fixed, currency)
next()
}
}
acmeCorp.may {
"skip".anytime {
next()
}
}
}
}
}
}
acmeCorp.may {
"skip".anytime {
rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.Quarterly) {
actions { actions {
(acmeCorp or highStreetBank).may { (acmeCorp or highStreetBank).may {
"exercise".anytime { "exercise".anytime {
@ -142,8 +93,24 @@ class Cap {
} }
} }
val contractAfterExecute = arrange { val contractAfterFixingFinal = arrange {
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Quarterly) { actions {
(acmeCorp or highStreetBank).may {
"exercise".anytime() {
val floating1 = interest(notional, "act/365", 1.0.bd, "2017-03-01", "2017-09-01")
val fixed1 = interest(notional, "act/365", 0.5.bd, "2017-03-01", "2017-09-01")
highStreetBank.gives(acmeCorp, floating1 - fixed1, currency)
}
}
acmeCorp.may {
"skip".anytime {
}
}
}
}
val contractAfterExecutionFirst = arrange {
rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) {
actions { actions {
(acmeCorp or highStreetBank).may { (acmeCorp or highStreetBank).may {
"exercise".anytime { "exercise".anytime {
@ -163,19 +130,21 @@ class Cap {
} }
val paymentFirst = arrange { highStreetBank.gives(acmeCorp, 250.K, EUR) } val paymentFirst = arrange { highStreetBank.gives(acmeCorp, 250.K, EUR) }
val paymentFinal = arrange { highStreetBank.gives(acmeCorp, 250.K, EUR) }
val stateStart = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contract) val stateInitial = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractInitial)
val stateFixed = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFixed) val stateAfterFixingFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterFixingFirst)
val stateAfterExecute = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterExecute) val stateAfterExecutionFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterExecutionFirst)
val statePaymentFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), paymentFirst) val statePaymentFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), paymentFirst)
val stateFixed2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFixed2) val stateAfterFixingFinal = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterFixingFinal)
val statePaymentFinal = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), paymentFinal)
val contractLimitedCap = arrange { val contractLimitedCap = arrange {
rollOut("2016-04-01".ld, "2017-04-01".ld, Frequency.Quarterly, object { rollOut("2016-04-01".ld, "2017-04-01".ld, Frequency.SemiAnnual, object {
val limit = variable(150.K) val limit = variable(150.K)
}) { }) {
actions { actions {
@ -200,7 +169,7 @@ class Cap {
@Test @Test
fun issue() { fun issue() {
transaction { transaction {
output { stateStart } output { stateInitial }
timestamp(TEST_TX_TIME_1) timestamp(TEST_TX_TIME_1)
this `fails with` "transaction has a single command" this `fails with` "transaction has a single command"
@ -219,8 +188,8 @@ class Cap {
@Test @Test
fun `first fixing`() { fun `first fixing`() {
transaction { transaction {
input { stateStart } input { stateInitial }
output { stateFixed } output { stateAfterFixingFirst }
timestamp(TEST_TX_TIME_1) timestamp(TEST_TX_TIME_1)
tweak { tweak {
@ -264,8 +233,8 @@ class Cap {
@Test @Test
fun `first execute`() { fun `first execute`() {
transaction { transaction {
input { stateFixed } input { stateAfterFixingFirst }
output { stateAfterExecute } output { stateAfterExecutionFirst }
output { statePaymentFirst } output { statePaymentFirst }
timestamp(TEST_TX_TIME_1) timestamp(TEST_TX_TIME_1)
@ -281,11 +250,30 @@ class Cap {
} }
} }
@Test
fun `final execute`() {
transaction {
input { stateAfterFixingFinal }
output { statePaymentFinal }
timestamp(TEST_TX_TIME_1)
tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
this `fails with` "action must be defined"
}
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("exercise") }
this.verifies()
}
}
@Test @Test
fun `second fixing`() { fun `second fixing`() {
transaction { transaction {
input { stateAfterExecute } input { stateAfterExecutionFirst }
output { stateFixed2 } output { stateAfterFixingFinal }
timestamp(TEST_TX_TIME_1) timestamp(TEST_TX_TIME_1)
tweak { tweak {
@ -295,32 +283,32 @@ class Cap {
tweak { tweak {
// wrong source // wrong source
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBORx", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("3M")), 1.0.bd))) } command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBORx", BusinessCalendar.parseDateFromString("2017-03-01"), Tenor("3M")), 1.0.bd))) }
this `fails with` "relevant fixing must be included" this `fails with` "relevant fixing must be included"
} }
tweak { tweak {
// wrong date // wrong date
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01").plusYears(1), Tenor("3M")), 1.0.bd))) } command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2017-03-01").plusYears(1), Tenor("3M")), 1.0.bd))) }
this `fails with` "relevant fixing must be included" this `fails with` "relevant fixing must be included"
} }
tweak { tweak {
// wrong tenor // wrong tenor
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("9M")), 1.0.bd))) } command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2017-03-01"), Tenor("9M")), 1.0.bd))) }
this `fails with` "relevant fixing must be included" this `fails with` "relevant fixing must be included"
} }
tweak { tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("3M")), 1.5.bd))) } command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2017-03-01"), Tenor("3M")), 1.5.bd))) }
this `fails with` "output state does not reflect fix command" this `fails with` "output state does not reflect fix command"
} }
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2016-12-01"), Tenor("3M")), 1.0.bd))) } command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", BusinessCalendar.parseDateFromString("2017-03-01"), Tenor("3M")), 1.0.bd))) }
this.verifies() this.verifies()
} }