224 lines
5.1 KiB
Go
224 lines
5.1 KiB
Go
package tax
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestStatic_Name(t *testing.T) {
|
|
p := NewStatic()
|
|
if got := p.Name(); got != "static" {
|
|
t.Errorf("Name() = %q, want %q", got, "static")
|
|
}
|
|
}
|
|
|
|
func TestStatic_Compute(t *testing.T) {
|
|
// rateBp is basis points (2500 = 25%).
|
|
p := NewStatic()
|
|
tests := []struct {
|
|
total int64
|
|
rateBp int
|
|
want int64
|
|
}{
|
|
{1250, 2500, 250},
|
|
{25000, 2500, 5000},
|
|
{1000, 2000, 167},
|
|
{0, 2500, 0},
|
|
}
|
|
for _, tt := range tests {
|
|
got := p.Compute(tt.total, tt.rateBp)
|
|
if got != tt.want {
|
|
t.Errorf("Compute(%d, %d) = %d; want %d", tt.total, tt.rateBp, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStatic_DefaultTaxRate(t *testing.T) {
|
|
p := NewStatic()
|
|
if got := p.DefaultTaxRate("SE"); got != 0 {
|
|
t.Errorf("DefaultTaxRate(\"SE\") = %d; want 0", got)
|
|
}
|
|
}
|
|
|
|
func TestNordic_Name(t *testing.T) {
|
|
p := NewNordic("SE")
|
|
if got := p.Name(); got != "nordic" {
|
|
t.Errorf("Name() = %q, want %q", got, "nordic")
|
|
}
|
|
}
|
|
|
|
func TestNordic_Compute(t *testing.T) {
|
|
// rateBp is basis points (2500 = 25%).
|
|
tests := []struct {
|
|
total int64
|
|
rateBp int
|
|
want int64
|
|
desc string
|
|
}{
|
|
{0, 2500, 0, "zero total"},
|
|
{1250, 2500, 250, "25 % VAT on 1250"},
|
|
{1000, 2000, 167, "20 % VAT on 1000"},
|
|
{1200, 2500, 240, "25 % VAT on 1200"},
|
|
{25000, 2500, 5000, "25 % VAT on 25000"},
|
|
{100, 1000, 10, "10 % VAT on 100"},
|
|
{100, 10000, 50, "100 % VAT on 100"},
|
|
{100, 0, 0, "zero-rate"},
|
|
{100, -1, 0, "negative rate -> zero"},
|
|
}
|
|
for _, tt := range tests {
|
|
p := NewNordic("SE")
|
|
got := p.Compute(tt.total, tt.rateBp)
|
|
if got != tt.want {
|
|
t.Errorf("Compute(%d, %d) [%s] = %d; want %d", tt.total, tt.rateBp, tt.desc, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNordic_DefaultTaxRate(t *testing.T) {
|
|
tests := []struct {
|
|
country string
|
|
want int
|
|
desc string
|
|
}{
|
|
{"SE", 2500, "Sweden"},
|
|
{"NO", 2500, "Norway"},
|
|
{"DK", 2500, "Denmark"},
|
|
{"FI", 2550, "Finland (25.5%)"},
|
|
{"", 2500, "empty -> default SE"},
|
|
{"DE", 2500, "unknown -> fallback SE"},
|
|
}
|
|
for _, tt := range tests {
|
|
p := NewNordic("SE")
|
|
got := p.DefaultTaxRate(tt.country)
|
|
if got != tt.want {
|
|
t.Errorf("DefaultTaxRate(%q) [%s] = %d; want %d", tt.country, tt.desc, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCompute(t *testing.T) {
|
|
// rateBp is basis points (2500 = 25%).
|
|
tests := []struct {
|
|
total int64
|
|
rateBp int
|
|
want int64
|
|
desc string
|
|
}{
|
|
{1250, 2500, 250, "canonical: 25 %"},
|
|
{25000, 2500, 5000, "25k with 25 % -> 5k tax"},
|
|
{0, 2500, 0, "zero total"},
|
|
{1000, 1250, 112, "fractional: 12.5 %"}, // exVat 1000*10000/11250=888, tax 112
|
|
}
|
|
for _, tt := range tests {
|
|
got := Compute(tt.total, tt.rateBp)
|
|
if got != tt.want {
|
|
t.Errorf("Compute(%d, %d) [%s] = %d; want %d", tt.total, tt.rateBp, tt.desc, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestProviderInterface(t *testing.T) {
|
|
var p Provider = NewNordic("SE")
|
|
_ = p
|
|
p2 := NewStatic()
|
|
_ = p2
|
|
}
|
|
|
|
func TestPrice_NewAndString(t *testing.T) {
|
|
p := NewPrice()
|
|
if p.IncVat != 0 {
|
|
t.Errorf("NewPrice().IncVat = %d; want 0", p.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_NewPriceFromIncVat(t *testing.T) {
|
|
p := NewPriceFromIncVat(1250, 2500) // 25% in basis points
|
|
if p.IncVat != 1250 {
|
|
t.Errorf("IncVat = %d; want 1250", p.IncVat)
|
|
}
|
|
if len(p.VatRates) != 1 {
|
|
t.Errorf("expected 1 vat rate, got %d", len(p.VatRates))
|
|
}
|
|
}
|
|
|
|
func TestPrice_ValueExVat(t *testing.T) {
|
|
p := NewPriceFromIncVat(1250, 2500) // 25%
|
|
exVat := p.ValueExVat()
|
|
if exVat != 1000 {
|
|
t.Errorf("ValueExVat() = %d; want 1000", exVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_TotalVat(t *testing.T) {
|
|
p := NewPriceFromIncVat(1250, 2500) // 25%
|
|
totalVat := p.TotalVat()
|
|
if totalVat != 250 {
|
|
t.Errorf("TotalVat() = %d; want 250", totalVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_Multiply(t *testing.T) {
|
|
p := NewPriceFromIncVat(1250, 2500)
|
|
p.Multiply(2)
|
|
if p.IncVat != 2500 {
|
|
t.Errorf("IncVat after Multiply(2) = %d; want 2500", p.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_MultiplyPrice(t *testing.T) {
|
|
p := NewPriceFromIncVat(1250, 2500)
|
|
p2 := MultiplyPrice(*p, 3)
|
|
if p2.IncVat != 3750 {
|
|
t.Errorf("IncVat = %d; want 3750", p2.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_Add(t *testing.T) {
|
|
a := NewPriceFromIncVat(1250, 2500)
|
|
b := NewPriceFromIncVat(2500, 2500)
|
|
a.Add(*b)
|
|
if a.IncVat != 3750 {
|
|
t.Errorf("IncVat after Add = %d; want 3750", a.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_Subtract(t *testing.T) {
|
|
a := NewPriceFromIncVat(2500, 2500)
|
|
b := NewPriceFromIncVat(1250, 2500)
|
|
a.Subtract(*b)
|
|
if a.IncVat != 1250 {
|
|
t.Errorf("IncVat after Subtract = %d; want 1250", a.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_SumPrices(t *testing.T) {
|
|
a := NewPriceFromIncVat(1250, 2500)
|
|
b := NewPriceFromIncVat(2500, 2500)
|
|
total := SumPrices(*a, *b)
|
|
if total.IncVat != 3750 {
|
|
t.Errorf("SumPrices IncVat = %d; want 3750", total.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_JSONRoundTrip(t *testing.T) {
|
|
p := NewPriceFromIncVat(1250, 2500)
|
|
data, err := json.Marshal(p)
|
|
if err != nil {
|
|
t.Fatalf("marshal error: %v", err)
|
|
}
|
|
var p2 Price
|
|
if err := json.Unmarshal(data, &p2); err != nil {
|
|
t.Fatalf("unmarshal error: %v", err)
|
|
}
|
|
if p2.IncVat != p.IncVat {
|
|
t.Errorf("IncVat mismatch: have %d, want %d", p2.IncVat, p.IncVat)
|
|
}
|
|
}
|
|
|
|
func TestPrice_SumPricesEmpty(t *testing.T) {
|
|
total := SumPrices()
|
|
if total.IncVat != 0 {
|
|
t.Errorf("SumPrices() IncVat = %d; want 0", total.IncVat)
|
|
}
|
|
}
|