Skip to content

Commit 554a868

Browse files
committed
fixed edge cases about balance, neg and zero
1 parent 8f5df95 commit 554a868

File tree

5 files changed

+107
-12
lines changed

5 files changed

+107
-12
lines changed

interpreter/interpreter.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -687,12 +687,16 @@ func (s *programState) receiveFrom(destination parser.Destination, amount *big.I
687687
case *parser.DestinationTo:
688688
var remainingAmount big.Int
689689
remainingAmount.Sub(&amountToReceive, receivedTotal)
690-
// receivedTotal += destination.receive(monetary-receivedTotal, ctx)
691-
received, err := s.receiveFrom(destinationTarget.Destination, &remainingAmount)
692-
if err != nil {
693-
return err
690+
691+
if remainingAmount.Cmp(big.NewInt(0)) != 0 {
692+
// receivedTotal += destination.receive(monetary-receivedTotal, ctx)
693+
received, err := s.receiveFrom(destinationTarget.Destination, &remainingAmount)
694+
if err != nil {
695+
return err
696+
}
697+
receivedTotal.Add(receivedTotal, received)
694698
}
695-
receivedTotal.Add(receivedTotal, received)
699+
696700
return nil
697701

698702
default:
@@ -815,6 +819,13 @@ func balance(
815819

816820
// body
817821
balance := s.getBalance(*account, *asset)
822+
if balance.Cmp(big.NewInt(0)) == -1 {
823+
return nil, NegativeBalanceError{
824+
Account: *account,
825+
Amount: *balance,
826+
}
827+
}
828+
818829
var balanceCopy big.Int
819830
balanceCopy.Set(balance)
820831

interpreter/interpreter_error.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ func (e InvalidTypeErr) Error() string {
6464
return fmt.Sprintf("This type does not exist: %s", e.Name)
6565
}
6666

67+
type NegativeBalanceError struct {
68+
Account string
69+
Amount big.Int
70+
}
71+
72+
func (e NegativeBalanceError) Error() string {
73+
return fmt.Sprintf("Cannot fetch negative balance from account @%s", e.Account)
74+
}
75+
6776
type NegativeAmountErr struct{ Amount MonetaryInt }
6877

6978
func (e NegativeAmountErr) Error() string {

interpreter/interpreter_test.go

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,27 @@ func TestDestinationComplex(t *testing.T) {
14591459

14601460
// TODO TestNeededBalances, TestSetTxMeta, TestSetAccountMeta
14611461

1462+
func TestSendZero(t *testing.T) {
1463+
tc := NewTestCase()
1464+
tc.compile(t, `
1465+
send [COIN 0] (
1466+
source = @src
1467+
destination = @dest
1468+
)`)
1469+
tc.expected = CaseResult{
1470+
Postings: []Posting{
1471+
{
1472+
Asset: "COIN",
1473+
Amount: big.NewInt(0),
1474+
Source: "src",
1475+
Destination: "dest",
1476+
},
1477+
},
1478+
Error: nil,
1479+
}
1480+
test(t, tc)
1481+
}
1482+
14621483
func TestBalance(t *testing.T) {
14631484
tc := NewTestCase()
14641485
tc.compile(t, `
@@ -1485,6 +1506,52 @@ func TestBalance(t *testing.T) {
14851506
test(t, tc)
14861507
}
14871508

1509+
func TestNegativeBalance(t *testing.T) {
1510+
tc := NewTestCase()
1511+
tc.compile(t, `
1512+
vars {
1513+
monetary $balance = balance(@a, EUR/2)
1514+
}
1515+
1516+
send $balance (
1517+
source = @world
1518+
destination = @dest
1519+
)`)
1520+
tc.setBalance("a", "EUR/2", -100)
1521+
tc.expected = CaseResult{
1522+
Error: machine.NegativeBalanceError{
1523+
Account: "a",
1524+
Amount: *big.NewInt(-100),
1525+
},
1526+
}
1527+
test(t, tc)
1528+
}
1529+
1530+
func TestBalanceNotFound(t *testing.T) {
1531+
tc := NewTestCase()
1532+
tc.compile(t, `
1533+
vars {
1534+
monetary $balance = balance(@a, EUR/2)
1535+
}
1536+
1537+
send $balance (
1538+
source = @world
1539+
destination = @dest
1540+
)`)
1541+
tc.expected = CaseResult{
1542+
Postings: []Posting{
1543+
{
1544+
Asset: "EUR/2",
1545+
Amount: big.NewInt(0),
1546+
Source: "world",
1547+
Destination: "dest",
1548+
},
1549+
},
1550+
Error: nil,
1551+
}
1552+
test(t, tc)
1553+
}
1554+
14881555
func TestInoderDestination(t *testing.T) {
14891556
tc := NewTestCase()
14901557
tc.compile(t, `send [COIN 100] (
@@ -1695,16 +1762,19 @@ func TestVariableBalance(t *testing.T) {
16951762
tc := NewTestCase()
16961763
script = `
16971764
vars {
1698-
monetary $amount = balance(@world, USD/2)
1765+
monetary $amount = balance(@src, USD/2)
16991766
}
17001767
send $amount (
17011768
source = @A
17021769
destination = @B
17031770
)`
17041771
tc.compile(t, script)
1705-
tc.setBalance("world", "USD/2", -40)
1772+
tc.setBalance("src", "USD/2", -40)
17061773
tc.expected = CaseResult{
1707-
Error: machine.NegativeAmountErr{Amount: machine.NewMonetaryInt(-40)},
1774+
Error: machine.NegativeBalanceError{
1775+
Account: "src",
1776+
Amount: *big.NewInt(-40),
1777+
},
17081778
}
17091779
test(t, tc)
17101780
})

interpreter/reconciler.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,6 @@ func Reconcile(asset string, senders []Sender, receivers []Receiver) ([]Posting,
105105
postingAmount = *receiver.Monetary
106106
}
107107

108-
if postingAmt := big.Int(postingAmount); postingAmt.BitLen() == 0 {
109-
continue
110-
}
111-
112108
var postingToMerge *Posting
113109
if len(postings) != 0 {
114110
posting := &postings[len(postings)-1]

interpreter/reconciler_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ func TestReconcileSingletonExactMatch(t *testing.T) {
4141
})
4242
}
4343

44+
func TestReconcileZero(t *testing.T) {
45+
runReconcileTestCase(t, ReconcileTestCase{
46+
Currency: "COIN",
47+
Senders: []Sender{{"src", big.NewInt(0)}},
48+
Receivers: []Receiver{{"dest", big.NewInt(0)}},
49+
Expected: []Posting{{"src", "dest", big.NewInt(0), "COIN"}},
50+
})
51+
}
52+
4453
func TestNoReceiversLeft(t *testing.T) {
4554
runReconcileTestCase(t, ReconcileTestCase{
4655
Senders: []Sender{{

0 commit comments

Comments
 (0)