diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/meta-calc.num b/internal/interpreter/testdata/numscript-cookbook/experimental/meta-calc.num new file mode 100644 index 00000000..826833cc --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/meta-calc.num @@ -0,0 +1,10 @@ +vars { + number $x = 10 + 1 +} + +send [USD/2 10] ( + source = @world + destination = @alice +) + +set_tx_meta("key", $x/2) diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/meta-calc.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/experimental/meta-calc.num.specs.json new file mode 100644 index 00000000..8f5f92e2 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/meta-calc.num.specs.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "featureFlags": [ + "experimental-overdraft-function", + "experimental-mid-script-function-call", + "experimental-oneof" + ], + "testCases": [ + { + "it": "sets the expected meta", + "expect.txMetadata": { + "key": "11/2" + } + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/mixed-source-prefer-single-source.num b/internal/interpreter/testdata/numscript-cookbook/experimental/mixed-source-prefer-single-source.num new file mode 100644 index 00000000..d9821f5e --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/mixed-source-prefer-single-source.num @@ -0,0 +1,15 @@ +vars { + number $amt +} + +send [USD $amt] ( + source = oneof { + @s1 + @s2 + { + @s1 + @s2 + } + } + destination = @dest +) diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/mixed-source-prefer-single-source.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/experimental/mixed-source-prefer-single-source.num.specs.json new file mode 100644 index 00000000..431cca04 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/mixed-source-prefer-single-source.num.specs.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "variables": { + "amt": "10" + }, + "featureFlags": ["experimental-oneof"], + "testCases": [ + { + "it": "sends from the first source when there is enough balance", + "balances": { + "s1": { + "USD": 999 + } + }, + "expect.postings": [ + { + "source": "s1", + "destination": "dest", + "amount": 10, + "asset": "USD" + } + ] + }, + { + "it": "sends from the second one when it has enough balance but the first one doesn't", + "balances": { + "s1": { + "USD": 9 + }, + "s2": { + "USD": 999 + } + }, + "expect.postings": [ + { + "source": "s2", + "destination": "dest", + "amount": 10, + "asset": "USD" + } + ] + }, + { + "it": "sends partially from both when none of them has enough balance on its own", + "balances": { + "s1": { + "USD": 6 + }, + "s2": { + "USD": 9 + } + }, + "expect.postings": [ + { + "source": "s1", + "destination": "dest", + "amount": 6, + "asset": "USD" + }, + { + "source": "s2", + "destination": "dest", + "amount": 4, + "asset": "USD" + } + ] + }, + { + "it": "fails if there aren't enough funds between all sources", + "balances": { + "s1": { + "USD": 5 + }, + "s2": { + "USD": 4 + } + }, + "expect.missingFunds": true + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/top-up-many.num b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up-many.num new file mode 100644 index 00000000..34c69cfc --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up-many.num @@ -0,0 +1,13 @@ +vars { + number $amt +} + + +send [EUR $amt] ( + source = @world + destination = oneof { + max overdraft(@alice, EUR) to @alice + max overdraft(@bob, EUR) to @bob + remaining kept + } +) diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/top-up-many.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up-many.num.specs.json new file mode 100644 index 00000000..2c1cbc95 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up-many.num.specs.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "featureFlags": [ + "experimental-overdraft-function", + "experimental-mid-script-function-call", + "experimental-oneof" + ], + "variables": { + "amt": "100" + }, + "testCases": [ + { + "it": "should be a noop when all balances are >= 0", + "balances": { "alice": { "EUR": 100 }, "bob": { "EUR": 200 } }, + "expect.postings": [] + }, + { + "it": "should prioritize alice when both have missing funds", + "balances": { + "alice": { "EUR": -120 }, + "bob": { "EUR": -120 } + }, + "expect.postings": [ + { + "source": "world", + "destination": "alice", + "amount": 100, + "asset": "EUR" + } + ] + }, + { + "it": "doesn't send funds to alice if there aren't enough funds for the account to be topped-up", + "balances": { + "alice": { "EUR": -80 }, + "bob": { "EUR": -120 } + }, + "expect.postings": [ + { + "source": "world", + "destination": "bob", + "amount": 100, + "asset": "EUR" + } + ] + }, + { + "it": "funds are kept if there are spare funds", + "balances": { + "alice": { "EUR": -10 }, + "bob": { "EUR": -20 } + }, + "expect.postings": [] + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/top-up.num b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up.num new file mode 100644 index 00000000..322efb63 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up.num @@ -0,0 +1,8 @@ +vars { + monetary $alice_overdraft = overdraft(@alice, EUR) +} + +send $alice_overdraft ( + source = @world + destination = @alice +) diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/top-up.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up.num.specs.json new file mode 100644 index 00000000..fbaddc23 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/top-up.num.specs.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "featureFlags": ["experimental-overdraft-function"], + "testCases": [ + { + "it": "should not emit postings", + "balances": { "alice": { "EUR": 100 } }, + "expect.postings": [] + }, + { + "it": "should send the missing amount to an overdraft account", + "balances": { "alice": { "EUR": -100 } }, + "expect.volumes": { + "alice": { "EUR": 0 }, + "world": { "EUR": -100 } + }, + "expect.movements": { + "world": { + "alice": { "EUR": 100 } + } + }, + "expect.postings": [ + { + "source": "world", + "destination": "alice", + "amount": 100, + "asset": "EUR" + } + ] + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/transfer-example.num b/internal/interpreter/testdata/numscript-cookbook/experimental/transfer-example.num new file mode 100644 index 00000000..cf887c0a --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/transfer-example.num @@ -0,0 +1,11 @@ +vars { + number $amt + account $dest + monetary $bank_overdraft = overdraft(@bank_account, EUR) +} + +send [EUR $amt] ( + source = max $bank_overdraft from @wallet + destination = $dest +) + diff --git a/internal/interpreter/testdata/numscript-cookbook/experimental/transfer-example.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/experimental/transfer-example.num.specs.json new file mode 100644 index 00000000..fd4844de --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/experimental/transfer-example.num.specs.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "featureFlags": [ + "experimental-overdraft-function", + "experimental-mid-script-function-call", + "experimental-oneof" + ], + "variables": { + "amt": "100", + "dest": "alice" + }, + "testCases": [ + { + "it": "should authorize transfer if both wallet and bank accounts display enough balance", + "balances": { + "wallet": { "EUR": 100 }, + "bank_account": { "EUR": -100 } + }, + "expect.postings": [ + { + "source": "wallet", + "destination": "alice", + "amount": 100, + "asset": "EUR" + } + ] + }, + { + "it": "should not authorize transfer if wallet does not display enough balance and bank account does", + "balances": { + "wallet": { "EUR": 50 }, + "bank_account": { "EUR": -100 } + }, + "expect.missingFunds": true + }, + { + "it": "should not authorize transfer if bank account does not display enough balance and wallet does", + "balances": { + "wallet": { "EUR": 100 }, + "bank_account": { "EUR": -50 } + }, + "expect.missingFunds": true + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/max-fee.num b/internal/interpreter/testdata/numscript-cookbook/max-fee.num new file mode 100644 index 00000000..56235357 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/max-fee.num @@ -0,0 +1,16 @@ +vars { + number $amt + number $cap + portion $fee +} + +send [USD $amt] ( + source = @world + destination = { + $fee to { + max [USD $cap] to @fees + remaining to @dest + } + remaining to @dest + } +) diff --git a/internal/interpreter/testdata/numscript-cookbook/max-fee.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/max-fee.num.specs.json new file mode 100644 index 00000000..804b3a15 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/max-fee.num.specs.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "variables": { + "cap": "10", + "fee": "10%" + }, + "testCases": [ + { + "it": "it sends 10% of the fee when lower than cap", + "variables": { + "amt": "10" + }, + "expect.postings": [ + { + "source": "world", + "destination": "fees", + "amount": 1, + "asset": "USD" + }, + { + "source": "world", + "destination": "dest", + "amount": 9, + "asset": "USD" + } + ] + }, + { + "it": "it caps the fee to the $cap", + "variables": { + "amt": "500" + }, + "expect.postings": [ + { + "source": "world", + "destination": "fees", + "amount": 10, + "asset": "USD" + }, + { + "source": "world", + "destination": "dest", + "amount": 40, + "asset": "USD" + }, + { + "source": "world", + "destination": "dest", + "amount": 450, + "asset": "USD" + } + ] + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/mixed-source-dest-allotment.num b/internal/interpreter/testdata/numscript-cookbook/mixed-source-dest-allotment.num new file mode 100644 index 00000000..a1a37613 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/mixed-source-dest-allotment.num @@ -0,0 +1,11 @@ +send [USD 77] ( + source = { + 10% from @src1 + 20% from @src2 + remaining from @world + } + destination = { + 1/2 to @dest1 + 1/2 to @dest2 + } +) diff --git a/internal/interpreter/testdata/numscript-cookbook/mixed-source-dest-allotment.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/mixed-source-dest-allotment.num.specs.json new file mode 100644 index 00000000..cd0bc9e9 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/mixed-source-dest-allotment.num.specs.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "testCases": [ + { + "it": "matches sources and destinations allotments", + "balances": { + "src1": { + "USD": 999 + }, + "src2": { + "USD": 999 + } + }, + "expect.postings": [ + { + "source": "src1", + "destination": "dest1", + "amount": 8, + "asset": "USD" + }, + { + "source": "src2", + "destination": "dest1", + "amount": 16, + "asset": "USD" + }, + { + "source": "world", + "destination": "dest1", + "amount": 15, + "asset": "USD" + }, + { + "source": "world", + "destination": "dest2", + "amount": 38, + "asset": "USD" + } + ] + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/send-max.num b/internal/interpreter/testdata/numscript-cookbook/send-max.num new file mode 100644 index 00000000..51801a83 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/send-max.num @@ -0,0 +1,4 @@ +send [USD *] ( + source = max [USD 100] from @src + destination = @dest +) diff --git a/internal/interpreter/testdata/numscript-cookbook/send-max.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/send-max.num.specs.json new file mode 100644 index 00000000..d2e32539 --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/send-max.num.specs.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "testCases": [ + { + "it": "is capped to USD100 when balance is higher", + "balances": { + "src": { "USD": 999 } + }, + "expect.postings": [ + { + "source": "src", + "destination": "dest", + "amount": 100, + "asset": "USD" + } + ] + }, + { + "it": "allows sending less than the cap when balance is not enough", + "balances": { + "src": { "USD": 42 } + }, + "expect.postings": [ + { + "source": "src", + "destination": "dest", + "amount": 42, + "asset": "USD" + } + ] + } + ] +} diff --git a/internal/interpreter/testdata/numscript-cookbook/top-up-max.num b/internal/interpreter/testdata/numscript-cookbook/top-up-max.num new file mode 100644 index 00000000..8246036a --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/top-up-max.num @@ -0,0 +1,14 @@ +vars { + monetary $jon_balance = balance(@jon, EUR/2) + + // The amount to send + monetary $amt + + // The end balance we don't want to exceed + monetary $limit +} + +send $amt ( + source = max $limit - $jon_balance from @alice + destination = @jon +) diff --git a/internal/interpreter/testdata/numscript-cookbook/top-up-max.num.specs.json b/internal/interpreter/testdata/numscript-cookbook/top-up-max.num.specs.json new file mode 100644 index 00000000..0ef59acf --- /dev/null +++ b/internal/interpreter/testdata/numscript-cookbook/top-up-max.num.specs.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://raw.githubusercontent.com/formancehq/numscript/main/specs.schema.json", + "variables": { + "amt": "EUR/2 100", + "limit": "EUR/2 150" + }, + "balances": { + "alice": { + "EUR/2": 9999 + } + }, + "testCases": [ + { + "it": "should send the amount when destination doesn't reach 150", + "balances": { + "jon": { + "EUR/2": 0 + } + }, + "expect.postings": [ + { + "source": "alice", + "destination": "jon", + "amount": 100, + "asset": "EUR/2" + } + ] + }, + { + "it": "should send the amount when destination doesn't reach 150 (2)", + "balances": { + "jon": { + "EUR/2": 50 + } + }, + "expect.postings": [ + { + "source": "alice", + "destination": "jon", + "amount": 100, + "asset": "EUR/2" + } + ] + }, + { + "it": "should fail if the end balance would exceed 150", + "balances": { + "jon": { + "EUR/2": 51 + } + }, + "expect.missingFunds": true + } + ] +}