Files

107 lines
3.0 KiB
Go
Raw Permalink Normal View History

2026-09-06 17:14:42 +07:00
package processor
import (
"testing"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/entities"
)
func fPtr(v float64) *float64 { return &v }
func TestResolveLineQuantity(t *testing.T) {
weightProduct := &entities.Product{Name: "Ikan Tude", SellBy: constants.SellByWeight}
unitProduct := &entities.Product{Name: "Nasi Goreng", SellBy: constants.SellByUnit}
tests := []struct {
name string
product *entities.Product
quantity int
weight *float64
wantQuantity int
wantWeight *float64
wantErr bool
}{
{
name: "weighed line is pinned to quantity 1",
// Mirrors chk_order_items_weight_single_line: even if a client sends 3,
// one weighing is one line.
product: weightProduct, quantity: 3, weight: fPtr(4.2),
wantQuantity: 1, wantWeight: fPtr(4.2),
},
{
name: "weight is rounded to stored precision",
product: weightProduct, quantity: 1, weight: fPtr(5.6004),
wantQuantity: 1, wantWeight: fPtr(5.6),
},
{
name: "weight product without a weight is rejected",
product: weightProduct, quantity: 1, weight: nil,
wantErr: true,
},
{
name: "weight that rounds away to zero is rejected",
product: weightProduct, quantity: 1, weight: fPtr(0.0004),
wantErr: true,
},
{
name: "unit line keeps its quantity and carries no weight",
product: unitProduct, quantity: 3, weight: nil,
wantQuantity: 3, wantWeight: nil,
},
{
name: "weight on a unit product is rejected",
// Otherwise the line would silently be priced by weight.
product: unitProduct, quantity: 1, weight: fPtr(4.2),
wantErr: true,
},
{
name: "non-positive quantity on a unit product is rejected",
product: unitProduct, quantity: 0, weight: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotQty, gotWeight, err := resolveLineQuantity(tt.product, tt.quantity, tt.weight)
if tt.wantErr {
if err == nil {
t.Fatalf("expected an error, got quantity=%v weight=%v", gotQty, gotWeight)
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gotQty != tt.wantQuantity {
t.Errorf("quantity = %v, want %v", gotQty, tt.wantQuantity)
}
switch {
case tt.wantWeight == nil && gotWeight != nil:
t.Errorf("weight = %v, want nil", *gotWeight)
case tt.wantWeight != nil && gotWeight == nil:
t.Errorf("weight = nil, want %v", *tt.wantWeight)
case tt.wantWeight != nil && *gotWeight != *tt.wantWeight:
t.Errorf("weight = %v, want %v", *gotWeight, *tt.wantWeight)
}
})
}
}
// A product created before this feature has sell_by defaulted to 'unit' by the
// migration, but a zero-valued struct must behave the same way.
func TestResolveLineQuantityTreatsEmptySellByAsUnit(t *testing.T) {
legacy := &entities.Product{Name: "Legacy"}
quantity, weight, err := resolveLineQuantity(legacy, 2, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if quantity != 2 || weight != nil {
t.Errorf("got quantity=%v weight=%v, want quantity=2 weight=nil", quantity, weight)
}
}