171 lines
6.5 KiB
Go
171 lines
6.5 KiB
Go
package cart
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
cart_messages "git.k6n.net/mats/go-cart-actor/proto/cart"
|
|
)
|
|
|
|
// Parent qty 1 → 2 resizes every direct child proportionally. Children all
|
|
// start at qty 1 so the proportional factor of 2 doubles them.
|
|
func TestChangeQuantity_ParentCascadesDoublingChildren(t *testing.T) {
|
|
reg := NewCartMultationRegistry(NewCartMutationContext(nil))
|
|
g := NewCartGrain(1, time.Now())
|
|
ctx := context.Background()
|
|
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 100, Sku: "P", Quantity: 1, Price: 1000})
|
|
parentLine := g.Items[0].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 101, Sku: "C1", Quantity: 1, Price: 100, ParentId: &parentLine})
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 102, Sku: "C2", Quantity: 1, Price: 200, ParentId: &parentLine})
|
|
|
|
if _, err := reg.Apply(ctx, g, &cart_messages.ChangeQuantity{Id: parentLine, Quantity: 2}); err != nil {
|
|
t.Fatalf("change qty: %v", err)
|
|
}
|
|
|
|
if g.Items[0].Quantity != 2 {
|
|
t.Errorf("parent qty = %d, want 2", g.Items[0].Quantity)
|
|
}
|
|
for _, it := range g.Items {
|
|
if it.Id == parentLine {
|
|
continue
|
|
}
|
|
if it.Quantity != 2 {
|
|
t.Errorf("child %s qty = %d, want 2 (cascaded from parent)", it.Sku, it.Quantity)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parent qty 2 → 3 with children at qty 2 → 3 (factor 3/2 = 1.5, integer math).
|
|
func TestChangeQuantity_ParentCascadesNonIntegerRatio(t *testing.T) {
|
|
reg := NewCartMultationRegistry(NewCartMutationContext(nil))
|
|
g := NewCartGrain(1, time.Now())
|
|
ctx := context.Background()
|
|
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 100, Sku: "P", Quantity: 2, Price: 1000})
|
|
parentLine := g.Items[0].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 101, Sku: "C1", Quantity: 2, Price: 100, ParentId: &parentLine})
|
|
|
|
if _, err := reg.Apply(ctx, g, &cart_messages.ChangeQuantity{Id: parentLine, Quantity: 3}); err != nil {
|
|
t.Fatalf("change qty: %v", err)
|
|
}
|
|
|
|
// parent: 2 -> 3 (direct set), child: 2 * 3 / 2 = 3
|
|
if g.Items[0].Quantity != 3 {
|
|
t.Errorf("parent qty = %d, want 3", g.Items[0].Quantity)
|
|
}
|
|
if g.Items[1].Quantity != 3 {
|
|
t.Errorf("child qty = %d, want 3 (proportional scale)", g.Items[1].Quantity)
|
|
}
|
|
}
|
|
|
|
// Scale-down that would round to 0 (parent 2 → 1, child qty 1 → (1*1)/2 = 0)
|
|
// must clamp to 1 so the child is never silently dropped by integer math.
|
|
func TestChangeQuantity_ParentScaleDownFloorsAtOne(t *testing.T) {
|
|
reg := NewCartMultationRegistry(NewCartMutationContext(nil))
|
|
g := NewCartGrain(1, time.Now())
|
|
ctx := context.Background()
|
|
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 100, Sku: "P", Quantity: 2, Price: 1000})
|
|
parentLine := g.Items[0].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 101, Sku: "C1", Quantity: 1, Price: 100, ParentId: &parentLine})
|
|
|
|
if _, err := reg.Apply(ctx, g, &cart_messages.ChangeQuantity{Id: parentLine, Quantity: 1}); err != nil {
|
|
t.Fatalf("change qty: %v", err)
|
|
}
|
|
|
|
if g.Items[0].Quantity != 1 {
|
|
t.Errorf("parent qty = %d, want 1", g.Items[0].Quantity)
|
|
}
|
|
if g.Items[1].Quantity != 1 {
|
|
t.Errorf("child qty = %d, want 1 (floor; integer math dropped to 0 without clamp)", g.Items[1].Quantity)
|
|
}
|
|
}
|
|
|
|
// Setting parent qty to 0 delegates to RemoveItem so the existing parent→
|
|
// child cascade takes over. Unrelated lines are left untouched.
|
|
func TestChangeQuantity_ZeroCascadesRemoval(t *testing.T) {
|
|
reg := NewCartMultationRegistry(NewCartMutationContext(nil))
|
|
g := NewCartGrain(1, time.Now())
|
|
ctx := context.Background()
|
|
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 100, Sku: "P", Quantity: 1, Price: 1000})
|
|
parentLine := g.Items[0].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 101, Sku: "C1", Quantity: 1, Price: 100, ParentId: &parentLine})
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 200, Sku: "OTHER", Quantity: 1, Price: 500})
|
|
|
|
if _, err := reg.Apply(ctx, g, &cart_messages.ChangeQuantity{Id: parentLine, Quantity: 0}); err != nil {
|
|
t.Fatalf("change qty 0: %v", err)
|
|
}
|
|
|
|
if len(g.Items) != 1 {
|
|
t.Fatalf("items = %d, want 1 (only OTHER survives)", len(g.Items))
|
|
}
|
|
if g.Items[0].Sku != "OTHER" {
|
|
t.Errorf("remaining sku = %q, want OTHER", g.Items[0].Sku)
|
|
}
|
|
}
|
|
|
|
// Changing a child's qty directly updates only that child — siblings and
|
|
// the parent are untouched. (The UI no longer exposes this control, but
|
|
// the HTTP surface still allows it for tools & direct API calls.)
|
|
func TestChangeQuantity_ChildDoesNotCascade(t *testing.T) {
|
|
reg := NewCartMultationRegistry(NewCartMutationContext(nil))
|
|
g := NewCartGrain(1, time.Now())
|
|
ctx := context.Background()
|
|
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 100, Sku: "P", Quantity: 1, Price: 1000})
|
|
parentLine := g.Items[0].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 101, Sku: "C1", Quantity: 1, Price: 100, ParentId: &parentLine})
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 102, Sku: "C2", Quantity: 1, Price: 200, ParentId: &parentLine})
|
|
targetChild := g.Items[1].Id
|
|
|
|
if _, err := reg.Apply(ctx, g, &cart_messages.ChangeQuantity{Id: targetChild, Quantity: 3}); err != nil {
|
|
t.Fatalf("change child qty: %v", err)
|
|
}
|
|
|
|
for _, it := range g.Items {
|
|
switch it.Id {
|
|
case parentLine:
|
|
if it.Quantity != 1 {
|
|
t.Errorf("parent qty = %d, want 1 (untouched on child edit)", it.Quantity)
|
|
}
|
|
case targetChild:
|
|
if it.Quantity != 3 {
|
|
t.Errorf("target child qty = %d, want 3", it.Quantity)
|
|
}
|
|
default:
|
|
// Sibling
|
|
if it.Quantity != 1 {
|
|
t.Errorf("sibling %s qty = %d, want 1 (untouched on child edit)", it.Sku, it.Quantity)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cascade descends into grandchildren so deeply nested accessory trees
|
|
// remain internally consistent with the top-level parent change.
|
|
func TestChangeQuantity_NestedChildren(t *testing.T) {
|
|
reg := NewCartMultationRegistry(NewCartMutationContext(nil))
|
|
g := NewCartGrain(1, time.Now())
|
|
ctx := context.Background()
|
|
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 100, Sku: "P", Quantity: 1, Price: 1000})
|
|
parentLine := g.Items[0].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 101, Sku: "C1", Quantity: 1, Price: 100, ParentId: &parentLine})
|
|
childLine := g.Items[1].Id
|
|
mustApply(t, reg, g, &cart_messages.AddItem{ItemId: 102, Sku: "G1", Quantity: 1, Price: 50, ParentId: &childLine})
|
|
|
|
if _, err := reg.Apply(ctx, g, &cart_messages.ChangeQuantity{Id: parentLine, Quantity: 2}); err != nil {
|
|
t.Fatalf("change qty: %v", err)
|
|
}
|
|
|
|
// parent 1 -> 2; child 1 -> 2 (parent -> child cascade); grandchild 1 -> 2 (child -> grandchild cascade)
|
|
for _, it := range g.Items {
|
|
if it.Quantity != 2 {
|
|
t.Errorf("line %s qty = %d, want 2 (nested cascade)", it.Sku, it.Quantity)
|
|
}
|
|
}
|
|
}
|