158 lines
6.3 KiB
Go
158 lines
6.3 KiB
Go
package eventtasks
|
|
|
|
import (
|
|
"bd2server/internal/server/gamedata"
|
|
"bd2server/internal/server/wire"
|
|
"bytes"
|
|
"testing"
|
|
)
|
|
|
|
func passClaimRequest(seq, rewardType uint64, all bool, level uint64) []byte {
|
|
b := req(seq)
|
|
if all {
|
|
b = wire.AppendVarint(b, 2, 1)
|
|
}
|
|
b = wire.AppendVarint(b, 3, 8)
|
|
if level != 0 {
|
|
b = wire.AppendVarint(b, 4, level)
|
|
}
|
|
if rewardType != 0 {
|
|
b = wire.AppendVarint(b, 5, rewardType)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func claimPass(t *testing.T, s *Service, request []byte) []byte {
|
|
t.Helper()
|
|
code, response, handled, err := s.Handle("/PassReward", request)
|
|
if err != nil || code != 126 || !handled {
|
|
t.Fatalf("pass claim failed: code=%d handled=%t err=%v", code, handled, err)
|
|
}
|
|
if _, present, err := wire.Bytes(response, 1); err != nil || !present {
|
|
t.Fatalf("native receiver requires a non-null reward bundle: %x, %v", response, err)
|
|
}
|
|
return response
|
|
}
|
|
|
|
func TestPassRewardNativeOneClickAfterPurchaseAndRestart(t *testing.T) {
|
|
s, e, store := setup(t)
|
|
s.design.PassLevels[8] = []gamedata.EventPassLevel{
|
|
{ID: 1, NeedExp: 20, Basic: gamedata.Reward{Type: 3, Count: 1}, Premium: gamedata.Reward{Type: 4, Count: 10}},
|
|
{ID: 2, NeedExp: 30, Basic: gamedata.Reward{Type: 3, Count: 2}, Premium: gamedata.Reward{Type: 4, Count: 20}},
|
|
{ID: 3, NeedExp: 40, Basic: gamedata.Reward{Type: 3, Count: 3}, Premium: gamedata.Reward{Type: 4, Count: 30}},
|
|
{ID: 4, Basic: gamedata.Reward{Type: 3, Count: 4}, Premium: gamedata.Reward{Type: 4, Count: 40}},
|
|
}
|
|
s.design.PassBuys = map[uint64][]gamedata.EventPassBuy{8: {{ID: 1, Type: 1, LevelsGranted: 3, Cost: gamedata.Reward{Type: 3, Count: 1000}}}}
|
|
buy := wire.AppendVarint(req(1), 2, 8)
|
|
buy = wire.AppendVarint(buy, 3, 1)
|
|
if _, _, _, err := s.Handle("/PassBuy", buy); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// PassRootUI.ReceiveAllReward sends BASIC first, then PREMIUM_1 in its callback.
|
|
basic := passClaimRequest(2, 0, true, 0)
|
|
basicReply := claimPass(t, s, basic)
|
|
for _, lv := range s.design.PassLevels[8] {
|
|
p := s.pass(s.registry.List()[2])
|
|
if !p.Claimed[key(lv.ID, 0)] || p.Claimed[key(lv.ID, 1)] {
|
|
t.Fatalf("basic phase incorrectly claimed premium at level %d", lv.ID)
|
|
}
|
|
}
|
|
if len(e.rewards) != 4 || e.rewards[0].Type != 3 || e.rewards[3].Count != 4 {
|
|
t.Fatalf("basic phase granted wrong rewards: %+v", e.rewards)
|
|
}
|
|
reopened, err := Open(store, s.design, s.registry, e)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
reopened.now = s.now
|
|
reopened.SetSession("test")
|
|
if replay := claimPass(t, reopened, basic); !bytes.Equal(replay, basicReply) || e.calls != 2 {
|
|
t.Fatal("restart replay repeated basic grants")
|
|
}
|
|
premium := passClaimRequest(3, 1, true, 0)
|
|
premiumReply := claimPass(t, reopened, premium)
|
|
if len(e.rewards) != 8 || e.rewards[4].Type != 4 || e.rewards[7].Count != 40 || e.calls != 3 {
|
|
t.Fatalf("premium phase granted wrong rewards: %+v", e.rewards)
|
|
}
|
|
for _, lv := range reopened.design.PassLevels[8] {
|
|
p := reopened.pass(reopened.registry.List()[2])
|
|
if !p.Claimed[key(lv.ID, 0)] || !p.Claimed[key(lv.ID, 1)] {
|
|
t.Fatalf("claim state incomplete at level %d", lv.ID)
|
|
}
|
|
}
|
|
if replay := claimPass(t, reopened, premium); !bytes.Equal(replay, premiumReply) || e.calls != 3 {
|
|
t.Fatal("premium replay repeated grants")
|
|
}
|
|
// A new one-click request after claiming must complete without granting again.
|
|
for typ := uint64(0); typ <= 1; typ++ {
|
|
response := claimPass(t, reopened, passClaimRequest(4+typ, typ, true, 0))
|
|
bundle, _, _ := wire.Bytes(response, 1)
|
|
if len(bundle) != 0 || e.calls != 3 || len(e.rewards) != 8 {
|
|
t.Fatal("already-claimed all request repeated rewards")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPassRewardBasicAlreadyClaimedBeforePremiumPurchase(t *testing.T) {
|
|
s, e, _ := setup(t)
|
|
s.design.PassLevels[8] = []gamedata.EventPassLevel{{ID: 1, Basic: gamedata.Reward{Type: 3, Count: 5}, Premium: gamedata.Reward{Type: 4, Count: 50}}}
|
|
claimPass(t, s, passClaimRequest(1, 0, true, 0))
|
|
s.design.PassBuys = map[uint64][]gamedata.EventPassBuy{8: {{ID: 1, Type: 1, Cost: gamedata.Reward{Type: 3, Count: 1000}}}}
|
|
buy := wire.AppendVarint(req(2), 2, 8)
|
|
buy = wire.AppendVarint(buy, 3, 1)
|
|
if _, _, _, err := s.Handle("/PassBuy", buy); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
claimPass(t, s, passClaimRequest(3, 0, true, 0))
|
|
if len(e.rewards) != 1 || e.calls != 2 {
|
|
t.Fatal("empty basic phase granted again")
|
|
}
|
|
claimPass(t, s, passClaimRequest(4, 1, true, 0))
|
|
if len(e.rewards) != 2 || e.rewards[1].Type != 4 || e.rewards[1].Count != 50 || e.calls != 3 {
|
|
t.Fatalf("empty basic phase prevented premium claim: %+v", e.rewards)
|
|
}
|
|
}
|
|
|
|
func TestPassRewardSingleClaimsAndLockedLevels(t *testing.T) {
|
|
s, e, _ := setup(t)
|
|
s.design.PassLevels[8] = []gamedata.EventPassLevel{
|
|
{ID: 1, NeedExp: 20, Basic: gamedata.Reward{Type: 3, Count: 5}, Premium: gamedata.Reward{Type: 4, Count: 50}},
|
|
{ID: 2, Basic: gamedata.Reward{Type: 3, Count: 6}, Premium: gamedata.Reward{Type: 4, Count: 60}},
|
|
}
|
|
if _, _, _, err := s.Handle("/PassReward", passClaimRequest(1, 1, true, 0)); err == nil || e.calls != 0 {
|
|
t.Fatal("premium reward granted without purchase")
|
|
}
|
|
claimPass(t, s, passClaimRequest(2, 0, false, 1))
|
|
if len(e.rewards) != 1 || e.rewards[0].Count != 5 {
|
|
t.Fatal("single basic reward incorrect")
|
|
}
|
|
for _, request := range [][]byte{passClaimRequest(3, 0, false, 1), passClaimRequest(4, 0, false, 2), passClaimRequest(5, 0, false, 99), passClaimRequest(6, 2, true, 0)} {
|
|
if _, _, _, err := s.Handle("/PassReward", request); err == nil || e.calls != 1 {
|
|
t.Fatal("duplicate, locked or fabricated reward accepted")
|
|
}
|
|
}
|
|
s.pass(s.registry.List()[2]).Premium = true
|
|
claimPass(t, s, passClaimRequest(7, 1, false, 1))
|
|
if len(e.rewards) != 2 || e.rewards[1].Count != 50 || s.pass(s.registry.List()[2]).Claimed[key(2, 1)] {
|
|
t.Fatal("single premium claim changed another level")
|
|
}
|
|
}
|
|
|
|
func TestPassRewardKeepsCurrentNewbieStepInEveryResponse(t *testing.T) {
|
|
s, _, _ := setup(t)
|
|
d := s.design.Passes[8]
|
|
d.NewbieStep = 1
|
|
s.design.Passes[8] = d
|
|
s.state.NewbieStep = 1
|
|
s.design.PassLevels[8] = []gamedata.EventPassLevel{{ID: 1, NeedExp: 20, Basic: gamedata.Reward{Type: 3, Count: 5}}, {ID: 2, Basic: gamedata.Reward{Type: 3, Count: 6}}}
|
|
response := claimPass(t, s, passClaimRequest(1, 0, true, 0))
|
|
if scalar(response, 2) != 1 || s.state.NewbieStep != 1 {
|
|
t.Fatal("partial claim resets native guide step")
|
|
}
|
|
response = claimPass(t, s, passClaimRequest(2, 0, true, 0))
|
|
if scalar(response, 2) != 1 {
|
|
t.Fatal("empty phase resets native guide step")
|
|
}
|
|
}
|