first
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
package pricing_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"backend/internal/modules/pricing"
|
||||
)
|
||||
|
||||
// fakeRepository is an in-memory pricing.Repository used to unit-test
|
||||
// pricing.Service without a real database.
|
||||
type fakeRepository struct {
|
||||
tiers map[uuid.UUID]*pricing.PriceTier
|
||||
}
|
||||
|
||||
func newFakeRepository() *fakeRepository {
|
||||
return &fakeRepository{tiers: map[uuid.UUID]*pricing.PriceTier{}}
|
||||
}
|
||||
|
||||
func (r *fakeRepository) Create(_ context.Context, t *pricing.PriceTier) error {
|
||||
cp := *t
|
||||
r.tiers[t.ID] = &cp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *fakeRepository) FindByID(_ context.Context, id uuid.UUID) (*pricing.PriceTier, error) {
|
||||
t, ok := r.tiers[id]
|
||||
if !ok {
|
||||
return nil, pricing.ErrNotFound
|
||||
}
|
||||
cp := *t
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
func (r *fakeRepository) ListByProduct(_ context.Context, productID uuid.UUID) ([]*pricing.PriceTier, error) {
|
||||
var list []*pricing.PriceTier
|
||||
for _, t := range r.tiers {
|
||||
if t.ProductID == productID {
|
||||
cp := *t
|
||||
list = append(list, &cp)
|
||||
}
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (r *fakeRepository) Update(_ context.Context, t *pricing.PriceTier) error {
|
||||
if _, ok := r.tiers[t.ID]; !ok {
|
||||
return pricing.ErrNotFound
|
||||
}
|
||||
cp := *t
|
||||
r.tiers[t.ID] = &cp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *fakeRepository) Delete(_ context.Context, id uuid.UUID) error {
|
||||
if _, ok := r.tiers[id]; !ok {
|
||||
return pricing.ErrNotFound
|
||||
}
|
||||
delete(r.tiers, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestService_PriceForQuantity_MultipliesTierPrice(t *testing.T) {
|
||||
repo := newFakeRepository()
|
||||
svc := pricing.NewService(repo)
|
||||
ctx := context.Background()
|
||||
|
||||
productID := uuid.New()
|
||||
unitID := uuid.New()
|
||||
|
||||
// "5 kg -> 45.00" tier, spec section 16 example.
|
||||
tier, err := svc.Create(ctx, productID, unitID, 5, 4500, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Create() error = %v", err)
|
||||
}
|
||||
|
||||
total, gotTier, err := svc.PriceForQuantity(ctx, tier.ID, 2)
|
||||
if err != nil {
|
||||
t.Fatalf("PriceForQuantity() error = %v", err)
|
||||
}
|
||||
if total != 9000 {
|
||||
t.Fatalf("PriceForQuantity() total = %d, want 9000 (2x 4500)", total)
|
||||
}
|
||||
if gotTier.ID != tier.ID {
|
||||
t.Fatalf("PriceForQuantity() returned tier %s, want %s", gotTier.ID, tier.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_PriceForQuantity_ZeroOrNegativeMultiplierTreatedAsOne(t *testing.T) {
|
||||
repo := newFakeRepository()
|
||||
svc := pricing.NewService(repo)
|
||||
ctx := context.Background()
|
||||
|
||||
tier, err := svc.Create(ctx, uuid.New(), uuid.New(), 1, 1000, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Create() error = %v", err)
|
||||
}
|
||||
|
||||
total, _, err := svc.PriceForQuantity(ctx, tier.ID, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("PriceForQuantity() error = %v", err)
|
||||
}
|
||||
if total != 1000 {
|
||||
t.Fatalf("PriceForQuantity() with multiplier=0 total = %d, want 1000 (treated as 1x)", total)
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_PriceForQuantity_UnknownTierRejected(t *testing.T) {
|
||||
svc := pricing.NewService(newFakeRepository())
|
||||
_, _, err := svc.PriceForQuantity(context.Background(), uuid.New(), 1)
|
||||
if !errors.Is(err, pricing.ErrNotFound) {
|
||||
t.Fatalf("PriceForQuantity() error = %v, want ErrNotFound", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_ListByProduct_FiltersByProduct(t *testing.T) {
|
||||
repo := newFakeRepository()
|
||||
svc := pricing.NewService(repo)
|
||||
ctx := context.Background()
|
||||
|
||||
productA := uuid.New()
|
||||
productB := uuid.New()
|
||||
unitID := uuid.New()
|
||||
|
||||
if _, err := svc.Create(ctx, productA, unitID, 1, 1000, 0); err != nil {
|
||||
t.Fatalf("Create() error = %v", err)
|
||||
}
|
||||
if _, err := svc.Create(ctx, productB, unitID, 1, 2000, 0); err != nil {
|
||||
t.Fatalf("Create() error = %v", err)
|
||||
}
|
||||
|
||||
list, err := svc.ListByProduct(ctx, productA)
|
||||
if err != nil {
|
||||
t.Fatalf("ListByProduct() error = %v", err)
|
||||
}
|
||||
if len(list) != 1 || list[0].ProductID != productA {
|
||||
t.Fatalf("ListByProduct(productA) = %+v, want exactly one tier for productA", list)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user