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) } }