Add pets for tiers 1-3.
This commit is contained in:
+157
-19
@@ -84,24 +84,60 @@ func TestTurnValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscardConvertsToApples(t *testing.T) {
|
||||
func TestSellConvertsToApples(t *testing.T) {
|
||||
g, _, _ := testGame(t)
|
||||
p := current(g)
|
||||
// Sell a plain pet (no sell effect) for exactly one apple.
|
||||
plain := g.pet("Plain", 2)
|
||||
p.Deck = append(p.Deck, plain)
|
||||
if err := g.Sell(p.ID, []string{plain.ID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p.Coins != CoinsPerRound-1 {
|
||||
t.Fatalf("sell should cost 1 coin, coins=%d", p.Coins)
|
||||
}
|
||||
if p.PetCount() != 0 || len(p.Deck) != 1 || p.Deck[0].Food != FoodApple {
|
||||
t.Fatalf("sold pet should become an apple: %+v", p.Deck)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSellDuckAddsExtraApple(t *testing.T) {
|
||||
g, _, _ := testGame(t)
|
||||
p := current(g)
|
||||
duck := g.tier1(t, "Duck")
|
||||
p.Deck = append(p.Deck, duck)
|
||||
if err := g.Sell(p.ID, []string{duck.ID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
apples := 0
|
||||
for _, c := range p.Deck {
|
||||
if c.Food == FoodApple {
|
||||
apples++
|
||||
}
|
||||
}
|
||||
if apples != 2 {
|
||||
t.Fatalf("selling a Duck should yield 2 apples (1 base + 1 effect), got %d", apples)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuyOtterAddsApple(t *testing.T) {
|
||||
g, _, _ := testGame(t)
|
||||
p := current(g)
|
||||
g.ShopRow[0] = g.tier1(t, "Otter")
|
||||
if err := g.Buy(p.ID, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Skip opponent back to p.
|
||||
if err := g.Buy(current(g).ID, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
hasOtter, apples := false, 0
|
||||
for _, c := range p.Deck {
|
||||
if c.Name == "Otter" {
|
||||
hasOtter = true
|
||||
}
|
||||
if c.Food == FoodApple {
|
||||
apples++
|
||||
}
|
||||
}
|
||||
if err := g.Discard(p.ID, deckIDs(p, Card.IsPet)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p.Coins != CoinsPerRound-2 {
|
||||
t.Fatalf("discard should cost 1 coin, coins=%d", p.Coins)
|
||||
}
|
||||
if p.PetCount() != 0 || len(p.Deck) != 1 || p.Deck[0].Food != FoodApple {
|
||||
t.Fatalf("discarded pet should become an apple: %+v", p.Deck)
|
||||
if !hasOtter || apples != 1 {
|
||||
t.Fatalf("buying an Otter should also add an apple: %+v", p.Deck)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +147,7 @@ func TestTradeInThreeMatchingSuits(t *testing.T) {
|
||||
// Hand p three same-suit tier-1 pets directly.
|
||||
for range 3 {
|
||||
c := g.pet("Fodder", 1)
|
||||
c.Suit = SuitMoon
|
||||
c.Suit = SuitBlue
|
||||
p.Deck = append(p.Deck, c)
|
||||
}
|
||||
nextDeckBefore := len(g.ShopDecks[1])
|
||||
@@ -150,11 +186,113 @@ func TestTradeInThreeMatchingSuits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Fish fires its Triple effect when traded in, and a pet received from the
|
||||
// trade fires its Buy effect.
|
||||
func TestTradeTriggersTripleAndBuyEffects(t *testing.T) {
|
||||
g, _, _ := testGame(t)
|
||||
p := current(g)
|
||||
countApples := func() int {
|
||||
n := 0
|
||||
for _, c := range p.Deck {
|
||||
if c.Food == FoodApple {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
var ids []string
|
||||
for range 3 {
|
||||
f := g.tier1(t, "Fish")
|
||||
f.Suit = SuitYellow
|
||||
p.Deck = append(p.Deck, f)
|
||||
ids = append(ids, f.ID)
|
||||
}
|
||||
if err := g.TradeStart(p.ID, ids); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if countApples() != 3 {
|
||||
t.Fatalf("each traded Fish should add an apple, got %d", countApples())
|
||||
}
|
||||
// Rig the revealed options so the chosen card is an Otter (Buy effect).
|
||||
g.Pending.Options[0] = g.tier1(t, "Otter")
|
||||
if err := g.TradeChoose(p.ID, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if countApples() != 4 {
|
||||
t.Fatalf("trade-received Otter should fire its Buy effect, got %d apples", countApples())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuyWormAddsTwoApples(t *testing.T) {
|
||||
g, _, _ := testGame(t)
|
||||
p := current(g)
|
||||
g.ShopRow[0] = g.realPet(t, "Worm")
|
||||
if err := g.Buy(p.ID, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
apples := 0
|
||||
for _, c := range p.Deck {
|
||||
if c.Food == FoodApple {
|
||||
apples++
|
||||
}
|
||||
}
|
||||
if apples != 2 {
|
||||
t.Fatalf("buying a Worm should add 2 apples, got %d", apples)
|
||||
}
|
||||
}
|
||||
|
||||
// Swan's Triple refreshes a spent gold, but only from round 3 on.
|
||||
func TestSwanTripleRefreshesGold(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
round int
|
||||
wantCoins int
|
||||
}{
|
||||
{round: 1, wantCoins: CoinsPerRound - 1}, // too early: coin stays spent
|
||||
{round: 3, wantCoins: CoinsPerRound}, // refreshed (capped at 3)
|
||||
} {
|
||||
g, _, _ := testGame(t)
|
||||
g.Round = tc.round
|
||||
p := current(g)
|
||||
var ids []string
|
||||
for range 3 {
|
||||
s := g.realPet(t, "Swan")
|
||||
s.Suit = SuitRed
|
||||
p.Deck = append(p.Deck, s)
|
||||
ids = append(ids, s.ID)
|
||||
}
|
||||
if err := g.TradeStart(p.ID, ids); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p.Coins != tc.wantCoins {
|
||||
t.Fatalf("round %d: coins after swan trade = %d, want %d", tc.round, p.Coins, tc.wantCoins)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Giraffe's Battle Prep hands out apples the moment arranging begins.
|
||||
func TestGiraffeBattlePrep(t *testing.T) {
|
||||
g, p1, _ := testGame(t)
|
||||
p1.Deck = append(p1.Deck, g.realPet(t, "Giraffe"))
|
||||
spendAllCoins(t, g)
|
||||
if g.Phase != PhaseArrange {
|
||||
t.Fatalf("expected arrange, got %s", g.Phase)
|
||||
}
|
||||
apples := 0
|
||||
for _, c := range p1.Deck {
|
||||
if c.Food == FoodApple {
|
||||
apples++
|
||||
}
|
||||
}
|
||||
if apples != 2 {
|
||||
t.Fatalf("giraffe should add 2 apples at battle prep, got %d", apples)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTradeRequiresMatchingSuit(t *testing.T) {
|
||||
g, _, _ := testGame(t)
|
||||
p := current(g)
|
||||
a, b, c := g.pet("A", 1), g.pet("B", 1), g.pet("C", 1)
|
||||
a.Suit, b.Suit, c.Suit = SuitSun, SuitSun, SuitMoon
|
||||
a.Suit, b.Suit, c.Suit = SuitRed, SuitRed, SuitBlue
|
||||
p.Deck = append(p.Deck, a, b, c)
|
||||
if err := g.TradeStart(p.ID, []string{a.ID, b.ID, c.ID}); err == nil {
|
||||
t.Fatal("mismatched suits should be rejected")
|
||||
@@ -170,7 +308,7 @@ func TestTradeBlockedOnFinalRound(t *testing.T) {
|
||||
p := current(g)
|
||||
for range 3 {
|
||||
c := g.pet("Fodder", 1)
|
||||
c.Suit = SuitMoon
|
||||
c.Suit = SuitBlue
|
||||
p.Deck = append(p.Deck, c)
|
||||
}
|
||||
if err := g.TradeStart(p.ID, deckIDs(p, nil)); err == nil {
|
||||
@@ -206,10 +344,10 @@ func TestForcedDiscardOverPetLimit(t *testing.T) {
|
||||
t.Fatalf("player with %d pets must be forced to discard, got phase %s", MaxPets+2, g.Phase)
|
||||
}
|
||||
// Wrong count rejected.
|
||||
if err := g.CleanupDiscard(p1.ID, deckIDs(p1, Card.IsPet)[:1]); err == nil {
|
||||
t.Fatal("must discard exactly the excess")
|
||||
if err := g.CleanupSell(p1.ID, deckIDs(p1, Card.IsPet)[:1]); err == nil {
|
||||
t.Fatal("must sell exactly the excess")
|
||||
}
|
||||
if err := g.CleanupDiscard(p1.ID, deckIDs(p1, Card.IsPet)[:2]); err != nil {
|
||||
if err := g.CleanupSell(p1.ID, deckIDs(p1, Card.IsPet)[:2]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p1.PetCount() != MaxPets {
|
||||
@@ -313,7 +451,7 @@ func TestViewHidesSecrets(t *testing.T) {
|
||||
// Pending trade options hidden from the opponent.
|
||||
for range 3 {
|
||||
c := g.pet("Fodder", 1)
|
||||
c.Suit = SuitLeaf
|
||||
c.Suit = SuitYellow
|
||||
p1.Deck = append(p1.Deck, c)
|
||||
}
|
||||
g.Turn = p1.Seat
|
||||
|
||||
Reference in New Issue
Block a user