mirror of
https://github.com/hanzo-fi/numscript.git
synced 2026-10-30 20:54:52 +00:00
365 lines
8.3 KiB
Go
365 lines
8.3 KiB
Go
package builder_test
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/hanzo-fi/numscript/builder"
|
|
"github.com/gkampitakis/go-snaps/snaps"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestSimpleSend(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(42)),
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src"),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 42] (
|
|
source = $account_0
|
|
destination = $account_1
|
|
)`))
|
|
}
|
|
|
|
func TestSimpleSendWithFlag(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(42)),
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src"),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgramWithFeatureFlags([]string{
|
|
"my-flag",
|
|
"another-flag",
|
|
}, stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`#![feature("my-flag", "another-flag")]
|
|
vars {
|
|
account $account_0
|
|
account $account_1
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 42] (
|
|
source = $account_0
|
|
destination = $account_1
|
|
)`))
|
|
}
|
|
|
|
func TestSendAll(t *testing.T) {
|
|
stmt := builder.StmtSendAll(
|
|
builder.ExprAsset("COIN"),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src"),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 *] (
|
|
source = $account_0
|
|
destination = $account_1
|
|
)`))
|
|
}
|
|
|
|
func TestSrcAllowingBoundedOverdraft(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(100)),
|
|
),
|
|
builder.SrcAccountOverdraft(
|
|
builder.ExprAccount("tmp:acc"),
|
|
builder.BoundedOverdraft(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(100)),
|
|
),
|
|
),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 100] (
|
|
source = $account_0 allowing overdraft up to [$asset_0 100]
|
|
destination = $account_1
|
|
)`),
|
|
)
|
|
}
|
|
|
|
func TestColoredAllowingUnboundedOverdraft(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(100)),
|
|
),
|
|
builder.SrcColoredOverdraft(
|
|
builder.ExprAccount("tmp:acc"),
|
|
builder.ExprString("ABCDEF"),
|
|
builder.UnboundedOverdraft(),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
string $string_0
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 100] (
|
|
source = $account_0 \ $string_0 allowing unbounded overdraft
|
|
destination = $account_1
|
|
)`))
|
|
}
|
|
|
|
func TestInorder(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(42)),
|
|
),
|
|
builder.SrcInorder(
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src1"),
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src2"),
|
|
),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
vars, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
account $account_2
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 42] (
|
|
source = {
|
|
$account_0
|
|
$account_1
|
|
}
|
|
destination = $account_2
|
|
)`))
|
|
|
|
require.Equal(t, map[string]string{
|
|
"account_0": "src1",
|
|
"account_1": "src2",
|
|
"account_2": "dest",
|
|
"asset_0": "USD/2",
|
|
}, vars)
|
|
}
|
|
|
|
func TestInorderNested(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(42)),
|
|
),
|
|
builder.SrcInorder(
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src1"),
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src2"),
|
|
),
|
|
builder.SrcInorder(
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src_nested1"),
|
|
),
|
|
builder.SrcAccountOverdraft(
|
|
builder.ExprAccount("src_nested2"),
|
|
builder.UnboundedOverdraft(),
|
|
),
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src_upper"),
|
|
),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
account $account_2
|
|
account $account_3
|
|
account $account_4
|
|
account $account_5
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 42] (
|
|
source = {
|
|
$account_0
|
|
$account_1
|
|
{
|
|
$account_2
|
|
$account_3 allowing unbounded overdraft
|
|
}
|
|
$account_4
|
|
}
|
|
destination = $account_5
|
|
)`))
|
|
}
|
|
|
|
func TestInorderWithColors(t *testing.T) {
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprNumberBigInt(big.NewInt(42)),
|
|
),
|
|
builder.SrcInorder(
|
|
builder.SrcColored(
|
|
builder.ExprAccount("acc"),
|
|
builder.ExprString("col"),
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprAccount("src2"),
|
|
),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
_, _, script := builder.BuildProgram(stmt)
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
account $account_2
|
|
string $string_0
|
|
asset $asset_0
|
|
}
|
|
|
|
send [$asset_0 42] (
|
|
source = {
|
|
$account_0 \ $string_0
|
|
$account_1
|
|
}
|
|
destination = $account_2
|
|
)`))
|
|
}
|
|
|
|
func TestWithExternVar(t *testing.T) {
|
|
// The builder module exposes a type-safe API to create scripts
|
|
|
|
// We can create (typed) vars this way:
|
|
accVar := builder.NewAccountVar()
|
|
amtVar := builder.NewNumberVar()
|
|
|
|
// sources, destinations, expressions, and statements are typed, so you can never
|
|
// use a source node instead of a expression node, and so on.
|
|
// In addition to that, expressions are typed, so you can't use a string expression
|
|
// instead of a number expression
|
|
stmt := builder.StmtSend(
|
|
builder.ExprMonetary(
|
|
builder.ExprAsset("USD/2"),
|
|
builder.ExprVar(&amtVar), // <- you can reference vars this way (identified by address)
|
|
),
|
|
builder.SrcAccount(
|
|
builder.ExprVar(&accVar),
|
|
),
|
|
builder.DestAccount(
|
|
builder.ExprAccount("dest"),
|
|
),
|
|
)
|
|
|
|
// When you build the program, it'll create 3 values:
|
|
vars, varsEnv, script := builder.BuildProgram(stmt)
|
|
|
|
// 1: (vars) the map[string]string of KNOWN variables. This is generated via the
|
|
// strings literals you pass (in the example above, USD/2 and @dest).
|
|
// This way, you'll pass this map to the tx and numscript will handle interpolation instead of
|
|
// handling that in this lib
|
|
require.Equal(t, map[string]string{
|
|
"asset_0": "USD/2",
|
|
"account_1": "dest",
|
|
}, vars)
|
|
|
|
// 2: (varsEnv) The env of the NAMES of each variable that is referenced within the script.
|
|
// You'll reference them by ptr address. The "Fill*()" methods are typed, and return you the name of the var,
|
|
// and the "stringified" value of the var content (in the case of account/asset/string, the string itself)
|
|
// Behaviour of Fill*() of vars that are never referenced in the script (thus, whose name is never allocated) is undefined
|
|
// (it may panic in the future)
|
|
//
|
|
// user code would likely be something like:
|
|
//
|
|
// varsCp := maps.Clone(vars)
|
|
// k, v := varsEnv.FillAccount(..)
|
|
// varsCp[k] = v
|
|
// (etc)
|
|
k, v := varsEnv.FillAccount(&accVar, "my_src")
|
|
require.Equal(t, "account_0", k)
|
|
require.Equal(t, "my_src", v)
|
|
|
|
k, v = varsEnv.FillNumber(&amtVar, big.NewInt(42))
|
|
require.Equal(t, "number_0", k)
|
|
require.Equal(t, "42", v)
|
|
|
|
// 3: (script) the script itself. It's generated while trying to be as "stable" as possible,
|
|
// e.g. vars are declared with an hardcoded order of types, and with an increasing order of names
|
|
snaps.MatchInlineSnapshot(t, script, snaps.Inline(`vars {
|
|
account $account_0
|
|
account $account_1
|
|
asset $asset_0
|
|
number $number_0
|
|
}
|
|
|
|
send [$asset_0 $number_0] (
|
|
source = $account_0
|
|
destination = $account_1
|
|
)`))
|
|
}
|