all repos

clerk @ 20a67e0

missing tooling for ledger/hledger

clerk/internal/decimal/decimal_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
syntax: respect commodity format; =*; ===; :=, 2 months ago
1
package decimal
2
3
import (
4
	"strings"
5
	"testing"
6
)
7
8
func TestNewFromString(t *testing.T) {
9
	tests := []struct{ in, want string }{
10
		{"10.00", "10"},
11
		{"150.60", "150.6"},
12
		{".33", "0.33"},
13
		{"1.", "1"},
14
		{"0001.2300", "1.23"},
15
		{"0", "0"},
16
		{"0.00", "0"},
17
		{"-0.00", "0"},
18
		{"-20", "-20"},
19
		{"-.75", "-0.75"},
20
		{"1E3", "1000"},
21
		{"1E-3", "0.001"},
22
		{"1E10000", "1" + strings.Repeat("0", 10000)},
23
	}
24
	for _, tt := range tests {
25
		got, err := FromString(tt.in)
26
		if err != nil {
27
			t.Fatalf("NewFromString(%q) unexpected error: %v", tt.in, err)
28
		}
29
		if got.String() != tt.want {
30
			t.Fatalf("NewFromString(%q).String() = %q, want %q", tt.in, got.String(), tt.want)
31
		}
32
	}
33
}
34
35
func TestNewFromStringInvalid(t *testing.T) {
36
	tests := []string{
37
		"", ".", "+", "-",
38
		"1_000.00", "1,000.00",
39
		"1..0",
40
		"a1", "1a",
41
		"1E10001", "1E-10001", "1E1000000000000",
42
	}
43
	for _, in := range tests {
44
		if _, err := FromString(in); err == nil {
45
			t.Fatalf("NewFromString(%q) expected error", in)
46
		}
47
	}
48
}
49
50
func TestStringFixed(t *testing.T) {
51
	tests := []struct {
52
		in           string
53
		places       int
54
		decSep       byte
55
		thousandsSep byte
56
		want         string
57
	}{
58
		{"0", 0, 0, 0, "0"},
59
		{"0", 1, 0, 0, "0.0"},
60
		{"0", 2, 0, 0, "0.00"},
61
		{"0", 3, 0, 0, "0.000"},
62
		{"-0", 2, 0, 0, "0.00"},
63
		{"10", 2, 0, 0, "10.00"},
64
		{"10", 0, 0, 0, "10"},
65
		{"1.2", 2, 0, 0, "1.20"},
66
		{"1.2", 1, 0, 0, "1.2"},
67
		{"1.2", 3, 0, 0, "1.200"},
68
		{"1.234", 2, 0, 0, "1.23"},
69
		{"1.235", 2, 0, 0, "1.23"},
70
		{"-1.2", 2, 0, 0, "-1.20"},
71
		{"-1.234", 2, 0, 0, "-1.23"},
72
		{"0.001", 2, 0, 0, "0.00"},
73
		{"0.001", 4, 0, 0, "0.0010"},
74
		{"123.456789", 3, 0, 0, "123.456"},
75
		{"-123.456789", 3, 0, 0, "-123.456"},
76
		{"1.23", 2, ',', 0, "1,23"},
77
		{"0", 2, ',', 0, "0,00"},
78
		{"-1.5", 2, ',', 0, "-1,50"},
79
		{"1234.56", 2, 0, ',', "1,234.56"},
80
		{"1234567.89", 2, 0, ',', "1,234,567.89"},
81
		{"123.45", 2, 0, ',', "123.45"},
82
		{"-1234.56", 2, 0, ',', "-1,234.56"},
83
		{"1234567.89", 2, ',', '.', "1.234.567,89"},
84
		{"-1234567.89", 2, ',', '.', "-1.234.567,89"},
85
		{"0", 2, ',', '.', "0,00"},
86
	}
87
	for _, tt := range tests {
88
		d, err := FromString(tt.in)
89
		if err != nil {
90
			t.Fatalf("FromString(%q) unexpected error: %v", tt.in, err)
91
		}
92
		if got := d.StringFixed(tt.places, tt.decSep, tt.thousandsSep); got != tt.want {
93
			t.Fatalf("FromString(%q).StringFixed(%d, %q, %q) = %q, want %q",
94
				tt.in, tt.places, tt.decSep, tt.thousandsSep, got, tt.want)
95
		}
96
	}
97
}
98
99
func TestArithmetic(t *testing.T) {
100
	a, _ := FromString("1.20")
101
	b, _ := FromString(".30")
102
103
	if got := a.Add(b).String(); got != "1.5" {
104
		t.Fatalf("a+b = %q, want %q", got, "1.5")
105
	}
106
	if got := a.Sub(b).String(); got != "0.9" {
107
		t.Fatalf("a-b = %q, want %q", got, "0.9")
108
	}
109
	if got := a.Mul(b).String(); got != "0.36" {
110
		t.Fatalf("a*b = %q, want %q", got, "0.36")
111
	}
112
}
113
114
func TestAbs(t *testing.T) {
115
	tests := []struct {
116
		in, want string
117
	}{
118
		{"0", "0"},
119
		{"-0", "0"},
120
		{"0.00", "0"},
121
		{"1.5", "1.5"},
122
		{"-1.5", "1.5"},
123
		{"100", "100"},
124
		{"-100", "100"},
125
		{"0.001", "0.001"},
126
		{"-0.001", "0.001"},
127
		{"123.456", "123.456"},
128
		{"-123.456", "123.456"},
129
	}
130
	for _, tt := range tests {
131
		d, err := FromString(tt.in)
132
		if err != nil {
133
			t.Fatalf("FromString(%q) unexpected error: %v", tt.in, err)
134
		}
135
		if got := d.Abs().String(); got != tt.want {
136
			t.Fatalf("Abs(%q) = %q, want %q", tt.in, got, tt.want)
137
		}
138
	}
139
}
140
141
func TestDiv(t *testing.T) {
142
	tests := []struct {
143
		a, b, want string
144
	}{
145
		{"1", "2", "0.5"},
146
		{"10", "3", "3.3333333333"},
147
		{"1.50", "3.00", "0.5"},
148
		{"0.1", "0.3", "0.33333333333"},
149
		{"100", "10", "10"},
150
		{"-1", "2", "-0.5"},
151
		{"1", "-2", "-0.5"},
152
		{"-1", "-2", "0.5"},
153
		{"0", "5", "0"},
154
		{"5.50", "5", "1.1"},
155
		{"1000", "3", "333.3333333333"},
156
	}
157
	for _, tt := range tests {
158
		a, err := FromString(tt.a)
159
		if err != nil {
160
			t.Fatalf("FromString(%q) unexpected error: %v", tt.a, err)
161
		}
162
		b, err := FromString(tt.b)
163
		if err != nil {
164
			t.Fatalf("FromString(%q) unexpected error: %v", tt.b, err)
165
		}
166
		got := a.Div(b).String()
167
		if got != tt.want {
168
			t.Fatalf("Div(%q, %q) = %q, want %q", tt.a, tt.b, got, tt.want)
169
		}
170
	}
171
}
172
173
func TestDivByZero(t *testing.T) {
174
	defer func() {
175
		if r := recover(); r == nil {
176
			t.Fatal("expected panic on division by zero")
177
		}
178
	}()
179
	d, _ := FromString("1")
180
	d.Div(Decimal{})
181
}
182
183
func TestCmpAndNeg(t *testing.T) {
184
	a, _ := FromString("1.0")
185
	b, _ := FromString("1")
186
	c, _ := FromString("1.01")
187
188
	if a.Cmp(b) != 0 {
189
		t.Fatalf("expected %q and %q to be equal", a.String(), b.String())
190
	}
191
	if b.Cmp(c) >= 0 {
192
		t.Fatalf("expected %q to be less than %q", b.String(), c.String())
193
	}
194
	if got := b.Neg().String(); got != "-1" {
195
		t.Fatalf("Neg(1) = %q, want %q", got, "-1")
196
	}
197
	if got := (Decimal{}).Neg().String(); got != "0" {
198
		t.Fatalf("Neg(0) = %q, want %q", got, "0")
199
	}
200
}