package entities import "testing" func weightPtr(v float64) *float64 { return &v } func TestBillableQuantity(t *testing.T) { tests := []struct { name string item OrderItem want float64 }{ {"unit line counts items", OrderItem{Quantity: 3}, 3}, {"weighed line uses the weight", OrderItem{Quantity: 1, Weight: weightPtr(4.2)}, 4.2}, {"weight of zero is still a weighed line", OrderItem{Quantity: 1, Weight: weightPtr(0)}, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.item.BillableQuantity(); got != tt.want { t.Errorf("BillableQuantity() = %v, want %v", got, tt.want) } }) } } // A weighed line is voided or refunded whole, so the units asked for must not shrink // the amount: refunding "1" of a 4.2 ons line refunds all 4.2 ons. func TestBillableQuantityForIgnoresUnitsOnWeighedLines(t *testing.T) { weighed := OrderItem{Quantity: 1, Weight: weightPtr(5.6)} if got := weighed.BillableQuantityFor(1); got != 5.6 { t.Errorf("weighed BillableQuantityFor(1) = %v, want 5.6", got) } counted := OrderItem{Quantity: 3} if got := counted.BillableQuantityFor(2); got != 2 { t.Errorf("unit BillableQuantityFor(2) = %v, want 2", got) } } // The regression this whole feature exists to prevent: a 4.2 ons fish priced per ons // must not be billed as a single ons. func TestCalculateTotalPriceForWeighedLine(t *testing.T) { item := OrderItem{Quantity: 1, Weight: weightPtr(4.2), UnitPrice: 4500, UnitCost: 3000} item.CalculateTotalPrice() item.CalculateTotalCost() if item.TotalPrice != 18900 { t.Errorf("TotalPrice = %v, want 18900", item.TotalPrice) } if item.TotalCost != 12600 { t.Errorf("TotalCost = %v, want 12600", item.TotalCost) } } func TestCalculateTotalPriceForUnitLine(t *testing.T) { item := OrderItem{Quantity: 3, UnitPrice: 25000, UnitCost: 10000} item.CalculateTotalPrice() item.CalculateTotalCost() if item.TotalPrice != 75000 { t.Errorf("TotalPrice = %v, want 75000", item.TotalPrice) } if item.TotalCost != 30000 { t.Errorf("TotalCost = %v, want 30000", item.TotalCost) } } // Sub-rupiah residue must not survive into a decimal(10,2) column. func TestCalculateTotalPriceRoundsToStoredPrecision(t *testing.T) { item := OrderItem{Quantity: 1, Weight: weightPtr(4.237), UnitPrice: 4500} item.CalculateTotalPrice() if item.TotalPrice != 19066.5 { t.Errorf("TotalPrice = %v, want 19066.5", item.TotalPrice) } } func TestIsWeighed(t *testing.T) { if (&OrderItem{Quantity: 1}).IsWeighed() { t.Error("unit line reported as weighed") } if !(&OrderItem{Quantity: 1, Weight: weightPtr(1.5)}).IsWeighed() { t.Error("weighed line reported as unit") } } func TestRoundWeight(t *testing.T) { tests := []struct { in float64 want float64 }{ {4.2, 4.2}, {4.2374, 4.237}, {4.2375, 4.238}, {0.0004, 0}, } for _, tt := range tests { if got := RoundWeight(tt.in); got != tt.want { t.Errorf("RoundWeight(%v) = %v, want %v", tt.in, got, tt.want) } } }