mirror of
https://github.com/hanzo-fi/stack.git
synced 2026-10-30 20:34:43 +00:00
272 lines
5.6 KiB
Go
272 lines
5.6 KiB
Go
package vm
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/formancehq/ledger/internal/machine"
|
|
)
|
|
|
|
func TestOverdraftNotEnough(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = @foo allowing overdraft up to [GEM 10]
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", 89)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{},
|
|
Error: &machine.ErrInsufficientFund{},
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestOverdraftEnough(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = @foo allowing overdraft up to [GEM 10]
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", 90)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(100),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
},
|
|
Error: nil,
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestOverdraftUnbounded(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 1000] (
|
|
source = @foo allowing unbounded overdraft
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", 90)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(1000),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
},
|
|
Error: nil,
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestOverdraftSourceAllotmentSuccess(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = {
|
|
50% from @foo allowing overdraft up to [GEM 10]
|
|
50% from {
|
|
@bar allowing overdraft up to [GEM 20]
|
|
@baz allowing unbounded overdraft
|
|
}
|
|
}
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", 40)
|
|
tc.setBalance("bar", "GEM", 20)
|
|
tc.setBalance("baz", "GEM", 0)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(50),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(40),
|
|
Source: "bar",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(10),
|
|
Source: "baz",
|
|
Destination: "world",
|
|
},
|
|
},
|
|
Error: nil,
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestOverdraftSourceInOrderSuccess(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = {
|
|
max [GEM 50] from {
|
|
@foo allowing overdraft up to [GEM 10]
|
|
@bar allowing overdraft up to [GEM 20]
|
|
@baz allowing unbounded overdraft
|
|
}
|
|
@qux allowing unbounded overdraft
|
|
}
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", 0)
|
|
tc.setBalance("bar", "GEM", 0)
|
|
tc.setBalance("baz", "GEM", 0)
|
|
tc.setBalance("qux", "GEM", 0)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(10),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(20),
|
|
Source: "bar",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(20),
|
|
Source: "baz",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(50),
|
|
Source: "qux",
|
|
Destination: "world",
|
|
},
|
|
},
|
|
Error: nil,
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestOverdraftBalanceTracking(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = @foo allowing unbounded overdraft
|
|
destination = @world
|
|
)
|
|
send [GEM 200] (
|
|
source = @foo allowing overdraft up to [GEM 300]
|
|
destination = @world
|
|
)
|
|
send [GEM 300] (
|
|
source = @foo allowing unbounded overdraft
|
|
destination = @world
|
|
)
|
|
`)
|
|
tc.setBalance("foo", "GEM", 0)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(100),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(200),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(300),
|
|
Source: "foo",
|
|
Destination: "world",
|
|
},
|
|
},
|
|
Error: nil,
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestWorldIsUnbounded(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = @world
|
|
destination = @foo
|
|
)
|
|
send [GEM 200] (
|
|
source = @world
|
|
destination = @foo
|
|
)
|
|
`)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(100),
|
|
Source: "world",
|
|
Destination: "foo",
|
|
},
|
|
{
|
|
Asset: "GEM",
|
|
Amount: machine.NewMonetaryInt(200),
|
|
Source: "world",
|
|
Destination: "foo",
|
|
},
|
|
},
|
|
Error: nil,
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestOverdraftComplexFailure(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = {
|
|
50% from @foo allowing overdraft up to [GEM 10]
|
|
50% from {
|
|
@bar allowing overdraft up to [GEM 20]
|
|
@baz
|
|
}
|
|
}
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", 40)
|
|
tc.setBalance("bar", "GEM", 20)
|
|
tc.setBalance("baz", "GEM", 0)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{},
|
|
Error: &machine.ErrInsufficientFund{},
|
|
}
|
|
test(t, tc)
|
|
}
|
|
|
|
func TestNegativeBalance(t *testing.T) {
|
|
tc := NewTestCase()
|
|
tc.compile(t, `send [GEM 100] (
|
|
source = @foo
|
|
destination = @world
|
|
)`)
|
|
tc.setBalance("foo", "GEM", -50)
|
|
tc.expected = CaseResult{
|
|
Printed: []machine.Value{},
|
|
Postings: []Posting{},
|
|
Error: &machine.ErrInsufficientFund{},
|
|
}
|
|
test(t, tc)
|
|
}
|