package strategy import ( "context" "testing" "gorm.io/driver/sqlite" "gorm.io/gorm" "bindbox-game/internal/repository/mysql/dao" "bindbox-game/internal/repository/mysql/model" ) func TestIchibanSelectItemBySlot_Deterministic(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("db open err: %v", err) } if err := db.Exec(`CREATE TABLE activities ( id INTEGER PRIMARY KEY AUTOINCREMENT, commitment_seed_master BLOB, commitment_state_version INTEGER );`).Error; err != nil { t.Fatalf("migrate err: %v", err) } if err := db.Exec(`CREATE TABLE activity_reward_settings ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, updated_at DATETIME, issue_id INTEGER NOT NULL, product_id INTEGER, name TEXT NOT NULL, weight INTEGER NOT NULL, quantity INTEGER NOT NULL, original_qty INTEGER NOT NULL, level INTEGER NOT NULL, sort INTEGER NOT NULL, is_boss INTEGER NOT NULL, deleted_at DATETIME );`).Error; err != nil { t.Fatalf("migrate err: %v", err) } q := dao.Use(db) // seed activity commitment _ = db.Exec(`INSERT INTO activities (id, commitment_seed_master, commitment_state_version) VALUES (9, x'7365656476616c7565', 1);`).Error // rewards with original qty r1 := &model.ActivityRewardSettings{IssueID: 1, Name: "A", Weight: 10, Quantity: 10, OriginalQty: 2, Level: 1, Sort: 1} r2 := &model.ActivityRewardSettings{IssueID: 1, Name: "B", Weight: 20, Quantity: 10, OriginalQty: 3, Level: 2, Sort: 2} if err := q.ActivityRewardSettings.Create(r1, r2); err != nil { t.Fatalf("create rewards err: %v", err) } s := NewIchiban(q, q) ctx := context.Background() total := int64(r1.OriginalQty + r2.OriginalQty) got1 := make([]int64, total) got2 := make([]int64, total) for i := int64(0); i < total; i++ { id, _, err := s.SelectItemBySlot(ctx, 9, 1, i) if err != nil { t.Fatalf("select err: %v", err) } got1[i] = id } for i := int64(0); i < total; i++ { id, _, err := s.SelectItemBySlot(ctx, 9, 1, i) if err != nil { t.Fatalf("select err: %v", err) } got2[i] = id } for i := int64(0); i < total; i++ { if got1[i] != got2[i] { t.Fatalf("non-deterministic mapping at %d: %d != %d", i, got1[i], got2[i]) } } } func TestIchibanSelectItemBySlot_OutOfRange(t *testing.T) { db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) _ = db.Exec(`CREATE TABLE activities (id INTEGER PRIMARY KEY AUTOINCREMENT, commitment_seed_master BLOB, commitment_state_version INTEGER);`).Error _ = db.Exec(`CREATE TABLE activity_reward_settings (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, updated_at DATETIME, issue_id INTEGER NOT NULL, product_id INTEGER, name TEXT NOT NULL, weight INTEGER NOT NULL, quantity INTEGER NOT NULL, original_qty INTEGER NOT NULL, level INTEGER NOT NULL, sort INTEGER NOT NULL, is_boss INTEGER NOT NULL, deleted_at DATETIME);`).Error q := dao.Use(db) _ = db.Exec(`INSERT INTO activities (id, commitment_seed_master, commitment_state_version) VALUES (9, x'7365656476616c7565', 1);`).Error _ = q.ActivityRewardSettings.Create(&model.ActivityRewardSettings{IssueID: 2, Name: "A", OriginalQty: 1, Quantity: 1, Sort: 1}) s := NewIchiban(q, q) if _, _, err := s.SelectItemBySlot(context.Background(), 9, 2, 5); err == nil { t.Fatalf("expected out of range error") } } func TestIchibanGrantReward_Decrement(t *testing.T) { db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) _ = db.Exec(`CREATE TABLE activities (id INTEGER PRIMARY KEY AUTOINCREMENT, commitment_seed_master BLOB, commitment_state_version INTEGER);`).Error _ = db.Exec(`CREATE TABLE activity_reward_settings (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, updated_at DATETIME, issue_id INTEGER NOT NULL, product_id INTEGER, name TEXT NOT NULL, weight INTEGER NOT NULL, quantity INTEGER NOT NULL, original_qty INTEGER NOT NULL, level INTEGER NOT NULL, sort INTEGER NOT NULL, is_boss INTEGER NOT NULL, deleted_at DATETIME);`).Error q := dao.Use(db) r := &model.ActivityRewardSettings{IssueID: 3, Name: "A", OriginalQty: 1, Quantity: 2, Sort: 1} _ = q.ActivityRewardSettings.Create(r) s := NewIchiban(q, q) if err := s.GrantReward(context.Background(), 100, r.ID); err != nil { t.Fatalf("grant err: %v", err) } got, _ := q.ActivityRewardSettings.Where(q.ActivityRewardSettings.ID.Eq(r.ID)).First() if got.Quantity != 1 { t.Fatalf("quantity not decremented: %d", got.Quantity) } }