From 19800a0886d51220f28f85f3845c74e7f46500e3 Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Sat, 26 Mar 2016 14:16:42 +0100 Subject: Refactored storage hierarchy, now need to look into decks again --- test/eu/equalparts/cardbase/CardbaseSortTest.java | 386 --------------------- test/eu/equalparts/cardbase/CardbaseTest.java | 6 +- .../cardstorage/ReferenceCardContainerTest.java | 131 +++++++ .../StandaloneCardContainerSortTest.java | 385 ++++++++++++++++++++ .../cardstorage/StandaloneCardContainerTest.java | 170 +++++++++ test/eu/equalparts/cardbase/decks/DeckTest.java | 53 --- .../equalparts/cardbase/decks/StatisticsTest.java | 148 -------- test/eu/equalparts/cardbase/decks/deck.cbd | 1 - 8 files changed, 689 insertions(+), 591 deletions(-) delete mode 100644 test/eu/equalparts/cardbase/CardbaseSortTest.java create mode 100644 test/eu/equalparts/cardbase/cardstorage/ReferenceCardContainerTest.java create mode 100644 test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerSortTest.java create mode 100644 test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerTest.java delete mode 100644 test/eu/equalparts/cardbase/decks/DeckTest.java delete mode 100644 test/eu/equalparts/cardbase/decks/StatisticsTest.java delete mode 100644 test/eu/equalparts/cardbase/decks/deck.cbd (limited to 'test/eu') diff --git a/test/eu/equalparts/cardbase/CardbaseSortTest.java b/test/eu/equalparts/cardbase/CardbaseSortTest.java deleted file mode 100644 index b0dbd40..0000000 --- a/test/eu/equalparts/cardbase/CardbaseSortTest.java +++ /dev/null @@ -1,386 +0,0 @@ -package eu.equalparts.cardbase; - -import static org.junit.Assert.assertTrue; - -import java.util.Collection; -import java.util.List; - -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; - -import eu.equalparts.cardbase.Cardbase; -import eu.equalparts.cardbase.cards.Card; - -/** - * Tests the sorting functionality. - * - * @author Eduardo Pedroni - * - */ -public class CardbaseSortTest { - - private Cardbase uut; - private static List testCards; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - ObjectMapper mapper = new ObjectMapper(); - testCards = mapper.readValue(CardbaseSortTest.class.getResourceAsStream("/testcards.json"), new TypeReference>() {}); - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - uut = new Cardbase(); - int[] cardCounts = {1, 2, 3, 8, 1, 15, 1, 1}; - for (int i = 0; i < testCards.size(); i++) { - uut.addCard(testCards.get(i), cardCounts[i]); - } - } - - @Test - public void sortByName() throws Exception { - Collection sortedCards = uut.sortByField("name"); - int i = 0; - String[] names = { - "Callow Jushi", - "Coerced Confession", - "Disrupting Shoal", - "Khalni Hydra", - "Nightmare", - "Shivan Dragon", - "Sorin Markov", - "Ugin's Construct", - }; - for (Card card : sortedCards) { - assertTrue(card.name + " should have been " + names[i] + ", i = " + i, card.name.equals(names[i])); - i++; - } - } - - @Test - public void sortByLayout() throws Exception { - Collection sortedCards = uut.sortByField("layout"); - int i = 0; - String[] layouts = { - "flip", - "normal", - "normal", - "normal", - "normal", - "normal", - "normal", - "normal", - }; - for (Card card : sortedCards) { - assertTrue(card.layout + " should have been " + layouts[i] + ", i = " + i, card.layout.equals(layouts[i])); - i++; - } - } - - @Test - public void sortByManaCost() throws Exception { - Collection sortedCards = uut.sortByField("manaCost"); - int i = 0; - String[] costs = { - "{1}{U}{U}", - "{3}{B}{B}{B}", - "{4}", - "{4}{R}{R}", - "{4}{U/B}", - "{5}{B}", - "{G}{G}{G}{G}{G}{G}{G}{G}", - "{X}{U}{U}", - }; - for (Card card : sortedCards) { - assertTrue(card.manaCost + " should have been " + costs[i] + ", i = " + i, card.manaCost.equals(costs[i])); - i++; - } - } - - @Test - public void sortByCMC() throws Exception { - Collection sortedCards = uut.sortByField("cmc"); - int i = 0; - Integer[] cmcs = {2, 3, 4, 5, 6, 6, 6, 8}; - for (Card card : sortedCards) { - assertTrue(card.cmc + " should have been " + cmcs[i] + ", i = " + i, card.cmc.equals(cmcs[i])); - i++; - } - } - - @Test - public void sortByType() throws Exception { - Collection sortedCards = uut.sortByField("type"); - int i = 0; - String[] types = { - "Artifact Creature — Construct", - "Creature — Dragon", - "Creature — Human Wizard", - "Creature — Hydra", - "Creature — Nightmare Horse", - "Instant — Arcane", - "Planeswalker — Sorin", - "Sorcery", - }; - for (Card card : sortedCards) { - assertTrue(card.type + " should have been " + types[i] + ", i = " + i, card.type.equals(types[i])); - i++; - } - } - - @Test - public void sortByRarity() throws Exception { - Collection sortedCards = uut.sortByField("rarity"); - int i = 0; - String[] rarities = { - "Uncommon", - "Uncommon", - "Uncommon", - "Rare", - "Rare", - "Rare", - "Mythic Rare", - "Mythic Rare", - }; - for (Card card : sortedCards) { - assertTrue(card.rarity + " should have been " + rarities[i] + ", i = " + i, card.rarity.equals(rarities[i])); - i++; - } - } - - @Test - public void sortByText() throws Exception { - Collection sortedCards = uut.sortByField("text"); - int i = 0; - String[] texts = { - "+2: Sorin Markov deals 2 damage to target creature or player and you gain 2 life.\n−3: Target opponent's life total becomes 10.\n−7: You control target player during that player's next turn.", - "Flying (This creature can't be blocked except by creatures with flying or reach.)\nNightmare's power and toughness are each equal to the number of Swamps you control.", - "Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.", - "Khalni Hydra costs {G} less to cast for each green creature you control.\nTrample", - "Target player puts the top four cards of his or her library into his or her graveyard. You draw a card for each creature card put into that graveyard this way.", - "When Ugin's Construct enters the battlefield, sacrifice a permanent that's one or more colors.", - "Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Callow Jushi.\nAt the beginning of the end step, if there are two or more ki counters on Callow Jushi, you may flip it.", - "You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost.\nCounter target spell if its converted mana cost is X.", - }; - for (Card card : sortedCards) { - assertTrue(card.text + " should have been " + texts[i] + ", i = " + i, card.text.equals(texts[i])); - i++; - } - } - - @Test - public void sortByFlavor() throws Exception { - Collection sortedCards = uut.sortByField("flavor"); - int i = 0; - String[] flavors = { - "", - "", - "", - "\"Ask the right questions in the right way and truth is inevitable.\"\n—Lazav", - "\"In ages past, bargains were struck and promises were made. Now we must collect on our debt. Begin the hymns.\"\n—Moruul, Khalni druid", - "The thunder of its hooves beats dreams into despair.", - "The undisputed master of the mountains of Shiv.", - "While trapping the Eldrazi on Zendikar, Ugin learned little from Sorin, but he gleaned the rudiments of lithomancy from Nahiri.", - }; - for (Card card : sortedCards) { - String flavor = card.flavor != null ? card.flavor : ""; - assertTrue(flavor + " should have been " + flavors[i] + ", i = " + i, flavor.equals(flavors[i])); - i++; - } - } - - @Test - public void sortByArtist() throws Exception { - Collection sortedCards = uut.sortByField("artist"); - int i = 0; - String[] artists = { - "Donato Giancola", - "Mathias Kollros", - "Michael Komarck", - "Peter Mohrbacher", - "Scott M. Fischer", - "Todd Lockwood", - "Tsutomu Kawade", - "Vance Kovacs", - }; - for (Card card : sortedCards) { - assertTrue(card.artist + " should have been " + artists[i] + ", i = " + i, card.artist.equals(artists[i])); - i++; - } - } - - @Test - public void sortByNumber() throws Exception { - Collection sortedCards = uut.sortByField("number"); - int i = 0; - String[] numbers = { - "31a", - "33", - "109", - "164", - "192", - "217", - "276", - "281", - }; - for (Card card : sortedCards) { - assertTrue(card.number + " should have been " + numbers[i] + ", i = " + i, card.number.equals(numbers[i])); - i++; - } - } - - @Test - public void sortByPower() throws Exception { - Collection sortedCards = uut.sortByField("power"); - int i = 0; - String[] powers = { - "", - "", - "", - "*", - "2", - "4", - "5", - "8", - }; - for (Card card : sortedCards) { - String power = card.power != null ? card.power : ""; - assertTrue(power + " should have been " + powers[i] + ", i = " + i, power.equals(powers[i])); - i++; - } - } - - @Test - public void sortByToughness() throws Exception { - Collection sortedCards = uut.sortByField("power"); - int i = 0; - String[] toughnesses = { - "", - "", - "", - "*", - "2", - "5", - "5", - "8", - }; - for (Card card : sortedCards) { - String toughness = card.toughness != null ? card.toughness : ""; - assertTrue(toughness + " should have been " + toughnesses[i] + ", i = " + i, toughness.equals(toughnesses[i])); - i++; - } - } - - @Test - public void sortByLoyalty() throws Exception { - Collection sortedCards = uut.sortByField("loyalty"); - int i = 0; - Integer[] loyalties = {0, 0, 0, 0, 0, 0, 0, 4}; - for (Card card : sortedCards) { - Integer loyalty = card.loyalty != null ? card.loyalty : 0; - assertTrue(loyalty + " should have been " + loyalties[i] + ", i = " + i, loyalty.equals(loyalties[i])); - i++; - } - } - - @Test - public void sortByMultiverseID() throws Exception { - Collection sortedCards = uut.sortByField("multiverseid"); - int i = 0; - Integer[] ids = {74128, 74489, 193551, 238330, 366408, 383168, 383172, 391949 }; - for (Card card : sortedCards) { - Integer id = card.multiverseid != null ? card.multiverseid : 0; - assertTrue(id + " should have been " + ids[i] + ", i = " + i, id.equals(ids[i])); - i++; - } - } - - @Test - public void sortByImageName() throws Exception { - Collection sortedCards = uut.sortByField("imageName"); - int i = 0; - String[] names = { - "callow jushi", - "coerced confession", - "disrupting shoal", - "khalni hydra", - "nightmare", - "shivan dragon", - "sorin markov", - "ugin's construct", - }; - for (Card card : sortedCards) { - assertTrue(card.imageName + " should have been " + names[i] + ", i = " + i, card.imageName.equals(names[i])); - i++; - } - } - - @Test - public void sortByWatermark() throws Exception { - Collection sortedCards = uut.sortByField("watermark"); - int i = 0; - String[] watermarks = { - "", - "", - "", - "", - "", - "", - "", - "Dimir", - }; - for (Card card : sortedCards) { - String watermark = card.watermark != null ? card.watermark : ""; - assertTrue(watermark + " should have been " + watermarks[i] + ", i = " + i, watermark.equals(watermarks[i])); - i++; - } - } - - @Test - public void sortBySetCode() throws Exception { - Collection sortedCards = uut.sortByField("setCode"); - int i = 0; - String[] sets = { - "BOK", - "BOK", - "FRF", - "GTC", - "M12", - "M15", - "M15", - "ROE", - }; - for (Card card : sortedCards) { - assertTrue(card.setCode + " should have been " + sets[i] + ", i = " + i, card.setCode.equals(sets[i])); - i++; - } - } - - public void sortByImageCode() throws Exception { - Collection sortedCards = uut.sortByField("imageCode"); - int i = 0; - String[] codes = { - "bok", - "bok", - "frf", - "gtc", - "m12", - "m15", - "m15", - "roe", - }; - for (Card card : sortedCards) { - assertTrue(card.imageCode + " should have been " + codes[i] + ", i = " + i, card.imageCode.equals(codes[i])); - i++; - } - } -} diff --git a/test/eu/equalparts/cardbase/CardbaseTest.java b/test/eu/equalparts/cardbase/CardbaseTest.java index 1a54298..c9576ce 100644 --- a/test/eu/equalparts/cardbase/CardbaseTest.java +++ b/test/eu/equalparts/cardbase/CardbaseTest.java @@ -151,13 +151,13 @@ public class CardbaseTest { final int testCount = 5; File testFile = tempFolder.newFile("saveTest.cb"); - uut.writeCollection(testFile); + uut.write(testFile); uut = Cardbase.load(testFile); assertEquals("Cardbase should contain no cards.", 0, uut.getCards().size()); uut.addCard(testCard, testCount); - uut.writeCollection(testFile); + uut.write(testFile); uut = Cardbase.load(testFile); assertEquals("Cardbase should contain 1 card.", 1, uut.getCards().size()); Card card = uut.getCard("M15", "281"); @@ -173,7 +173,7 @@ public class CardbaseTest { File testFile = tempFolder.newFile("saveTest.cb"); testFile.setWritable(false); exception.expect(IOException.class); - uut.writeCollection(testFile); + uut.write(testFile); } @Test diff --git a/test/eu/equalparts/cardbase/cardstorage/ReferenceCardContainerTest.java b/test/eu/equalparts/cardbase/cardstorage/ReferenceCardContainerTest.java new file mode 100644 index 0000000..d233ddf --- /dev/null +++ b/test/eu/equalparts/cardbase/cardstorage/ReferenceCardContainerTest.java @@ -0,0 +1,131 @@ +package eu.equalparts.cardbase.cardstorage; + +import static org.junit.Assert.assertEquals; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import eu.equalparts.cardbase.cards.Card; + +/** + * This test class tests storage-by-reference behaviour only. + * For standalone storage behaviour tests, see {@code StandaloneCardContainerTest}. + * + * @author Eduardo Pedroni + * + */ +public class ReferenceCardContainerTest { + private ReferenceCardContainer uut; + private static Card testCard; + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + testCard = mapper.readValue(ReferenceCardContainerTest.class.getResourceAsStream("/shivandragon.json"), Card.class); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + uut = new ReferenceCardContainer() { + }; + } + + /*********************************************************************************** + * Adding card tests, happy path + ***********************************************************************************/ + @Test + public void newCardIsAdded() throws Exception { + uut.addCard(testCard, 1); + + assertEquals("Container should have contained 1 test card.", 1, uut.getCount(testCard)); + } + + @Test + public void existingCardIsIncremented() throws Exception { + uut.addCard(testCard, 2); + uut.addCard(testCard, 4); + + assertEquals("Container should have contained 6 test cards.", 6, uut.getCount(testCard)); + } + + /* + * Edge cases + */ + @Test + public void cardAddedIsNull() throws Exception { + exception.expect(NullPointerException.class); + uut.addCard(null, 0); + } + + /*********************************************************************************** + * Removing card tests, happy path + ***********************************************************************************/ + @Test + public void cardRemoveCountIsLessThanCardCount() throws Exception { + uut.addCard(testCard, 5); + + int removed = uut.removeCard(testCard, 3); + + assertEquals("Card count was not updated correctly.", 2, uut.getCount(testCard)); + assertEquals("Container reports wrong removed count.", 3, removed); + } + + @Test + public void cardRemoveCountIsEqualToCardCount() throws Exception { + uut.addCard(testCard, 5); + + int removed = uut.removeCard(testCard, 5); + + assertEquals("Card was not removed from container.", 0, uut.getCount(testCard)); + assertEquals("Container reports wrong removed count.", 5, removed); + } + + @Test + public void cardRemoveCountIsGreaterThanCardCount() throws Exception { + uut.addCard(testCard, 3); + + int removed = uut.removeCard(testCard, 5); + + assertEquals("Card was not removed from container.", 0, uut.getCount(testCard)); + assertEquals("Container reports wrong removed count.", 3, removed); + } + + /* + * Edge cases + */ + @Test + public void removedCardIsNull() throws Exception { + exception.expect(NullPointerException.class); + uut.removeCard(null, 0); + } + + @Test + public void removedCardIsNotInCardbase() throws Exception { + int removed = uut.removeCard(testCard, 1); + + assertEquals("Removed count should be 0.", 0, removed); + } + + @Test + public void removedCountIsLessThanZero() throws Exception { + uut.addCard(testCard, 3); + + int removed = uut.removeCard(testCard, -4); + + assertEquals("Card count in container should be unchanged.", 3, uut.getCount(testCard)); + assertEquals("Container reports wrong removed count.", 0, removed); + } +} diff --git a/test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerSortTest.java b/test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerSortTest.java new file mode 100644 index 0000000..2a4a3ba --- /dev/null +++ b/test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerSortTest.java @@ -0,0 +1,385 @@ +package eu.equalparts.cardbase.cardstorage; + +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import eu.equalparts.cardbase.cards.Card; + +/** + * Tests the sorting functionality. + * + * @author Eduardo Pedroni + * + */ +public class StandaloneCardContainerSortTest { + + private StandaloneCardContainer uut; + private static List testCards; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + testCards = mapper.readValue(StandaloneCardContainerSortTest.class.getResourceAsStream("/testcards.json"), new TypeReference>() {}); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + uut = new StandaloneCardContainer() {}; + int[] cardCounts = {1, 2, 3, 8, 1, 15, 1, 1}; + for (int i = 0; i < testCards.size(); i++) { + uut.addCard(testCards.get(i), cardCounts[i]); + } + } + + @Test + public void sortByName() throws Exception { + Collection sortedCards = uut.sortByField("name"); + int i = 0; + String[] names = { + "Callow Jushi", + "Coerced Confession", + "Disrupting Shoal", + "Khalni Hydra", + "Nightmare", + "Shivan Dragon", + "Sorin Markov", + "Ugin's Construct", + }; + for (Card card : sortedCards) { + assertTrue(card.name + " should have been " + names[i] + ", i = " + i, card.name.equals(names[i])); + i++; + } + } + + @Test + public void sortByLayout() throws Exception { + Collection sortedCards = uut.sortByField("layout"); + int i = 0; + String[] layouts = { + "flip", + "normal", + "normal", + "normal", + "normal", + "normal", + "normal", + "normal", + }; + for (Card card : sortedCards) { + assertTrue(card.layout + " should have been " + layouts[i] + ", i = " + i, card.layout.equals(layouts[i])); + i++; + } + } + + @Test + public void sortByManaCost() throws Exception { + Collection sortedCards = uut.sortByField("manaCost"); + int i = 0; + String[] costs = { + "{1}{U}{U}", + "{3}{B}{B}{B}", + "{4}", + "{4}{R}{R}", + "{4}{U/B}", + "{5}{B}", + "{G}{G}{G}{G}{G}{G}{G}{G}", + "{X}{U}{U}", + }; + for (Card card : sortedCards) { + assertTrue(card.manaCost + " should have been " + costs[i] + ", i = " + i, card.manaCost.equals(costs[i])); + i++; + } + } + + @Test + public void sortByCMC() throws Exception { + Collection sortedCards = uut.sortByField("cmc"); + int i = 0; + Integer[] cmcs = {2, 3, 4, 5, 6, 6, 6, 8}; + for (Card card : sortedCards) { + assertTrue(card.cmc + " should have been " + cmcs[i] + ", i = " + i, card.cmc.equals(cmcs[i])); + i++; + } + } + + @Test + public void sortByType() throws Exception { + Collection sortedCards = uut.sortByField("type"); + int i = 0; + String[] types = { + "Artifact Creature — Construct", + "Creature — Dragon", + "Creature — Human Wizard", + "Creature — Hydra", + "Creature — Nightmare Horse", + "Instant — Arcane", + "Planeswalker — Sorin", + "Sorcery", + }; + for (Card card : sortedCards) { + assertTrue(card.type + " should have been " + types[i] + ", i = " + i, card.type.equals(types[i])); + i++; + } + } + + @Test + public void sortByRarity() throws Exception { + Collection sortedCards = uut.sortByField("rarity"); + int i = 0; + String[] rarities = { + "Uncommon", + "Uncommon", + "Uncommon", + "Rare", + "Rare", + "Rare", + "Mythic Rare", + "Mythic Rare", + }; + for (Card card : sortedCards) { + assertTrue(card.rarity + " should have been " + rarities[i] + ", i = " + i, card.rarity.equals(rarities[i])); + i++; + } + } + + @Test + public void sortByText() throws Exception { + Collection sortedCards = uut.sortByField("text"); + int i = 0; + String[] texts = { + "+2: Sorin Markov deals 2 damage to target creature or player and you gain 2 life.\n−3: Target opponent's life total becomes 10.\n−7: You control target player during that player's next turn.", + "Flying (This creature can't be blocked except by creatures with flying or reach.)\nNightmare's power and toughness are each equal to the number of Swamps you control.", + "Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.", + "Khalni Hydra costs {G} less to cast for each green creature you control.\nTrample", + "Target player puts the top four cards of his or her library into his or her graveyard. You draw a card for each creature card put into that graveyard this way.", + "When Ugin's Construct enters the battlefield, sacrifice a permanent that's one or more colors.", + "Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Callow Jushi.\nAt the beginning of the end step, if there are two or more ki counters on Callow Jushi, you may flip it.", + "You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost.\nCounter target spell if its converted mana cost is X.", + }; + for (Card card : sortedCards) { + assertTrue(card.text + " should have been " + texts[i] + ", i = " + i, card.text.equals(texts[i])); + i++; + } + } + + @Test + public void sortByFlavor() throws Exception { + Collection sortedCards = uut.sortByField("flavor"); + int i = 0; + String[] flavors = { + "", + "", + "", + "\"Ask the right questions in the right way and truth is inevitable.\"\n—Lazav", + "\"In ages past, bargains were struck and promises were made. Now we must collect on our debt. Begin the hymns.\"\n—Moruul, Khalni druid", + "The thunder of its hooves beats dreams into despair.", + "The undisputed master of the mountains of Shiv.", + "While trapping the Eldrazi on Zendikar, Ugin learned little from Sorin, but he gleaned the rudiments of lithomancy from Nahiri.", + }; + for (Card card : sortedCards) { + String flavor = card.flavor != null ? card.flavor : ""; + assertTrue(flavor + " should have been " + flavors[i] + ", i = " + i, flavor.equals(flavors[i])); + i++; + } + } + + @Test + public void sortByArtist() throws Exception { + Collection sortedCards = uut.sortByField("artist"); + int i = 0; + String[] artists = { + "Donato Giancola", + "Mathias Kollros", + "Michael Komarck", + "Peter Mohrbacher", + "Scott M. Fischer", + "Todd Lockwood", + "Tsutomu Kawade", + "Vance Kovacs", + }; + for (Card card : sortedCards) { + assertTrue(card.artist + " should have been " + artists[i] + ", i = " + i, card.artist.equals(artists[i])); + i++; + } + } + + @Test + public void sortByNumber() throws Exception { + Collection sortedCards = uut.sortByField("number"); + int i = 0; + String[] numbers = { + "31a", + "33", + "109", + "164", + "192", + "217", + "276", + "281", + }; + for (Card card : sortedCards) { + assertTrue(card.number + " should have been " + numbers[i] + ", i = " + i, card.number.equals(numbers[i])); + i++; + } + } + + @Test + public void sortByPower() throws Exception { + Collection sortedCards = uut.sortByField("power"); + int i = 0; + String[] powers = { + "", + "", + "", + "*", + "2", + "4", + "5", + "8", + }; + for (Card card : sortedCards) { + String power = card.power != null ? card.power : ""; + assertTrue(power + " should have been " + powers[i] + ", i = " + i, power.equals(powers[i])); + i++; + } + } + + @Test + public void sortByToughness() throws Exception { + Collection sortedCards = uut.sortByField("power"); + int i = 0; + String[] toughnesses = { + "", + "", + "", + "*", + "2", + "5", + "5", + "8", + }; + for (Card card : sortedCards) { + String toughness = card.toughness != null ? card.toughness : ""; + assertTrue(toughness + " should have been " + toughnesses[i] + ", i = " + i, toughness.equals(toughnesses[i])); + i++; + } + } + + @Test + public void sortByLoyalty() throws Exception { + Collection sortedCards = uut.sortByField("loyalty"); + int i = 0; + Integer[] loyalties = {0, 0, 0, 0, 0, 0, 0, 4}; + for (Card card : sortedCards) { + Integer loyalty = card.loyalty != null ? card.loyalty : 0; + assertTrue(loyalty + " should have been " + loyalties[i] + ", i = " + i, loyalty.equals(loyalties[i])); + i++; + } + } + + @Test + public void sortByMultiverseID() throws Exception { + Collection sortedCards = uut.sortByField("multiverseid"); + int i = 0; + Integer[] ids = {74128, 74489, 193551, 238330, 366408, 383168, 383172, 391949 }; + for (Card card : sortedCards) { + Integer id = card.multiverseid != null ? card.multiverseid : 0; + assertTrue(id + " should have been " + ids[i] + ", i = " + i, id.equals(ids[i])); + i++; + } + } + + @Test + public void sortByImageName() throws Exception { + Collection sortedCards = uut.sortByField("imageName"); + int i = 0; + String[] names = { + "callow jushi", + "coerced confession", + "disrupting shoal", + "khalni hydra", + "nightmare", + "shivan dragon", + "sorin markov", + "ugin's construct", + }; + for (Card card : sortedCards) { + assertTrue(card.imageName + " should have been " + names[i] + ", i = " + i, card.imageName.equals(names[i])); + i++; + } + } + + @Test + public void sortByWatermark() throws Exception { + Collection sortedCards = uut.sortByField("watermark"); + int i = 0; + String[] watermarks = { + "", + "", + "", + "", + "", + "", + "", + "Dimir", + }; + for (Card card : sortedCards) { + String watermark = card.watermark != null ? card.watermark : ""; + assertTrue(watermark + " should have been " + watermarks[i] + ", i = " + i, watermark.equals(watermarks[i])); + i++; + } + } + + @Test + public void sortBySetCode() throws Exception { + Collection sortedCards = uut.sortByField("setCode"); + int i = 0; + String[] sets = { + "BOK", + "BOK", + "FRF", + "GTC", + "M12", + "M15", + "M15", + "ROE", + }; + for (Card card : sortedCards) { + assertTrue(card.setCode + " should have been " + sets[i] + ", i = " + i, card.setCode.equals(sets[i])); + i++; + } + } + + public void sortByImageCode() throws Exception { + Collection sortedCards = uut.sortByField("imageCode"); + int i = 0; + String[] codes = { + "bok", + "bok", + "frf", + "gtc", + "m12", + "m15", + "m15", + "roe", + }; + for (Card card : sortedCards) { + assertTrue(card.imageCode + " should have been " + codes[i] + ", i = " + i, card.imageCode.equals(codes[i])); + i++; + } + } +} diff --git a/test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerTest.java b/test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerTest.java new file mode 100644 index 0000000..bd1bbfb --- /dev/null +++ b/test/eu/equalparts/cardbase/cardstorage/StandaloneCardContainerTest.java @@ -0,0 +1,170 @@ +package eu.equalparts.cardbase.cardstorage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Field; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import eu.equalparts.cardbase.cards.Card; + +public class StandaloneCardContainerTest { + private StandaloneCardContainer uut; + private static Card testCard; + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + testCard = mapper.readValue(StandaloneCardContainerTest.class.getResourceAsStream("/shivandragon.json"), Card.class); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + uut = new StandaloneCardContainer() { + }; + } + + /*********************************************************************************** + * StandaloneCardContainer should extend ReferenceCardContainer + ***********************************************************************************/ + @Test + public void classInherits() throws Exception { + assertTrue("StandaloneCardContainer should be subclass of ReferenceCardContainer.", uut instanceof ReferenceCardContainer); + } + + /*********************************************************************************** + * Adding card tests, happy path + ***********************************************************************************/ + @Test + public void newCardIsAdded() throws Exception { + assertNull("Container should not contain the test card to begin with.", uut.getCard(testCard.setCode, testCard.number)); + + uut.addCard(testCard, 1); + + assertEquals("Container should contain the test card once it is added.", testCard, uut.getCard(testCard.setCode, testCard.number)); + } + + @Test + public void existingCardIsIncremented() throws Exception { + uut.addCard(testCard, 2); + uut.addCard(testCard, 4); + + Card addedCard = uut.getCard(testCard.setCode, testCard.number); + assertNotNull("Card was not found in cardbase.", addedCard); + assertEquals("Card count was not updated correctly.", 6, uut.getCount(addedCard)); + } + + /* + * Edge cases + */ + @Test + public void cardAddedIsNull() throws Exception { + exception.expect(NullPointerException.class); + uut.addCard(null, 0); + } + + /*********************************************************************************** + * Removing card tests, happy path + ***********************************************************************************/ + @Test + public void cardIsStillPresentIfRemoveCountIsLessThanCardCount() throws Exception { + uut.addCard(testCard, 5); + + uut.removeCard(testCard, 3); + + assertEquals("Card is missing from container.", testCard, uut.getCard(testCard.setCode, testCard.number)); + } + + @Test + public void cardIsRemovedIfRemoveCountIsEqualToCardCount() throws Exception { + uut.addCard(testCard, 5); + + uut.removeCard(testCard, 5); + + assertNull("Card is not missing from container.", uut.getCard(testCard.setCode, testCard.number)); + } + + @Test + public void cardIsRemovedIfRemoveCountIsGreaterThanCardCount() throws Exception { + uut.addCard(testCard, 3); + + uut.removeCard(testCard, 5); + + assertNull("Card is not missing from container.", uut.getCard(testCard.setCode, testCard.number)); + } + + /* + * Edge cases + */ + @Test + public void removedCardIsNull() throws Exception { + exception.expect(NullPointerException.class); + uut.removeCard(null, 0); + } + + @Test + public void removedCardIsNotInContainer() throws Exception { + assertNull("Card is not initially missing from container.", uut.getCard(testCard.setCode, testCard.number)); + + uut.removeCard(testCard, 1); + + assertNull("Card is not missing from container.", uut.getCard(testCard.setCode, testCard.number)); + } + + @Test + public void removedCountIsLessThanZero() throws Exception { + uut.addCard(testCard, 3); + + uut.removeCard(testCard, -4); + + assertEquals("Card should not be missing from container.", testCard, uut.getCard(testCard.setCode, testCard.number)); + } + + /*********************************************************************************** + * Card getter tests, happy path + ***********************************************************************************/ + @Test + public void correctCardIsReturnedByGetter() throws Exception { + uut.addCard(testCard, 1); + + Card card = uut.getCard(testCard.setCode, testCard.number); + + for (Field field : Card.class.getFields()) { + assertEquals("Field " + field.getName(), field.get(testCard), field.get(card)); + } + } + + @Test + public void correctCardCollectionIsReturnedByGetter() throws Exception { + uut.addCard(testCard, 1); + + assertTrue("Not all cards were returned by the getter.", uut.getCards().contains(testCard)); + } + + @Test + public void cardCollectionWhenContainerIsEmpty() throws Exception { + assertEquals("Returned collection size should have been 0.", 0, uut.getCards().size()); + } + + @Test + public void getCardIsNotInCardbase() throws Exception { + assertNull("Method should have returned null", uut.getCard(testCard.setCode, testCard.number)); + } +} diff --git a/test/eu/equalparts/cardbase/decks/DeckTest.java b/test/eu/equalparts/cardbase/decks/DeckTest.java deleted file mode 100644 index 1c00e5b..0000000 --- a/test/eu/equalparts/cardbase/decks/DeckTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package eu.equalparts.cardbase.decks; - -import static org.junit.Assert.*; - -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import eu.equalparts.cardbase.cards.Card; -import eu.equalparts.cardbase.decks.ReferenceDeck; -import eu.equalparts.cardbase.decks.StandaloneDeck; - -public class DeckTest { - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - } - - // TODO sort out -// @Test -// public void test_createReferenceDeckFromStandaloneDeck() throws Exception { -// ObjectMapper mapper = new ObjectMapper(); -// StandaloneDeck standaloneDeck = mapper.readValue(getClass().getResourceAsStream("deck.cbd"), StandaloneDeck.class); -// -// ReferenceDeck uut = new ReferenceDeck(standaloneDeck); -// -// boolean condition = uut.name == standaloneDeck.name && -// uut.plains == standaloneDeck.plains && -// uut.islands == standaloneDeck.islands && -// uut.swamps == standaloneDeck.swamps && -// uut.mountains == standaloneDeck.mountains && -// uut.forests == standaloneDeck.forests; -// assertTrue("Metadata was not correctly set.", condition); -// assertEquals("Wrong number of cards.", uut.cardReferences.size(), standaloneDeck.cards.size()); -// for (Card card : standaloneDeck.cards) { -// Integer count = uut.cardReferences.get(card.hashCode()); -// assertNotNull("Reference missing in deck.", count); -// assertEquals("Card count is wrong.", card.count, count); -// } -// } -} diff --git a/test/eu/equalparts/cardbase/decks/StatisticsTest.java b/test/eu/equalparts/cardbase/decks/StatisticsTest.java deleted file mode 100644 index 6210f89..0000000 --- a/test/eu/equalparts/cardbase/decks/StatisticsTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package eu.equalparts.cardbase.decks; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import eu.equalparts.cardbase.decks.StandaloneDeck; -import eu.equalparts.cardbase.decks.Statistics; - -public class StatisticsTest { - - private static StandaloneDeck uut; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - ObjectMapper mapper = new ObjectMapper(); - uut = mapper.readValue(StatisticsTest.class.getResourceAsStream("deck.cbd"), StandaloneDeck.class); - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - } - - @Test - public void test_totalLandCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Land"); - - assertEquals(23, count); - } - - @Test - public void test_basicLandCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Basic Land"); - - assertEquals(20, count); - } - - @Test - public void test_cardCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut); - - assertEquals(60, count); - } - - @Test - public void test_landPercentageIsComputedCorrectly() throws Exception { - double percentage = Statistics.calculatePercentage(uut, "Land"); - - assertTrue("Land percentage should be " + (23.0 / 60.0) + ", is " + percentage, percentage == (23.0 / 60.0)); - } - - @Test - public void test_creaturePercentageIsComputedCorrectly() throws Exception { - double percentage = Statistics.calculatePercentage(uut, "Creature"); - - assertTrue("Creature percentage should be " + (24.0 / 60.0) + ", is " + percentage, percentage == (24.0 / 60.0)); - } - - @Test - public void test_creatureCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Creature"); - - assertEquals(24, count); - } - - @Test - public void test_sorceryCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Sorcery"); - - assertEquals(1, count); - } - - @Test - public void test_instantCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Instant"); - - assertEquals(6, count); - } - - @Test - public void test_planeswalkerCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Planeswalker"); - - assertEquals(0, count); - } - - @Test - public void test_elfCountIsComputedCorrectly() throws Exception { - int count = Statistics.count(uut, "Elf"); - - assertEquals(2, count); - } - - @Test - public void test_overallCostDistributionIsComputedCorrectly() throws Exception { - int[] actualCosts = Statistics.computeDistribution(uut); - int[] expectedCosts = {0, 8, 11, 3, 4, 7, 4}; - - assertEquals("Array lengths do not match.", expectedCosts.length, actualCosts.length); - for (int i = 0; i < expectedCosts.length; i++) { - assertEquals("CMC: " + i, expectedCosts[i], actualCosts[i]); - } - } - - @Test - public void test_creatureCostDistributionIsComputedCorrectly() throws Exception { - int[] actualCosts = Statistics.computeDistribution(uut, "Creature"); - int[] expectedCosts = {0, 3, 6, 2, 2, 7, 4}; - - assertEquals("Array lengths do not match.", expectedCosts.length, actualCosts.length); - for (int i = 0; i < expectedCosts.length; i++) { - assertEquals("CMC: " + i, expectedCosts[i], actualCosts[i]); - } - } - - @Test - public void test_instantCostDistributionIsComputedCorrectly() throws Exception { - int[] actualCosts = Statistics.computeDistribution(uut, "Instant"); - int[] expectedCosts = {0, 2, 4}; - - assertEquals("Array lengths do not match.", expectedCosts.length, actualCosts.length); - for (int i = 0; i < expectedCosts.length; i++) { - assertEquals("CMC: " + i, expectedCosts[i], actualCosts[i]); - } - } - - @Test - public void test_planeswalkerCostDistributionIsComputedCorrectly() throws Exception { - int[] actualCosts = Statistics.computeDistribution(uut, "Planeswalker"); - int[] expectedCosts = {}; - - assertEquals("Array lengths do not match.", expectedCosts.length, actualCosts.length); - for (int i = 0; i < expectedCosts.length; i++) { - assertEquals("CMC: " + i, expectedCosts[i], actualCosts[i]); - } - } - -} \ No newline at end of file diff --git a/test/eu/equalparts/cardbase/decks/deck.cbd b/test/eu/equalparts/cardbase/decks/deck.cbd deleted file mode 100644 index 57d479a..0000000 --- a/test/eu/equalparts/cardbase/decks/deck.cbd +++ /dev/null @@ -1 +0,0 @@ -{"name":"Red-green Ramp","plains":0,"islands":0,"swamps":0,"mountains":11,"forests":9,"cards":[{"name":"Titanic Growth","layout":"normal","manaCost":"{1}{G}","cmc":2,"type":"Instant","rarity":"Common","text":"Target creature gets +4/+4 until end of turn.","flavor":"The massive dominate through might. The tiny survive with guile. Beware the tiny who become massive.","artist":"Ryan Pancoast","number":"203","power":null,"toughness":null,"loyalty":null,"multiverseid":383415,"imageName":"titanic growth","watermark":null,"setCode":"M15","imageCode":"m15","count":1},{"name":"Nessian Asp","layout":"normal","manaCost":"{4}{G}","cmc":5,"type":"Creature — Snake","rarity":"Common","text":"Reach\n{6}{G}: Monstrosity 4. (If this creature isn't monstrous, put four +1/+1 counters on it and it becomes monstrous.)","flavor":"It's not the two heads you should fear. It's the four fangs.","artist":"Alex Horley-Orlandelli","number":"164","power":"4","toughness":"5","loyalty":null,"multiverseid":373650,"imageName":"nessian asp","watermark":null,"setCode":"THS","imageCode":"ths","count":2},{"name":"Satyr Hedonist","layout":"normal","manaCost":"{1}{G}","cmc":2,"type":"Creature — Satyr","rarity":"Common","text":"{R}, Sacrifice Satyr Hedonist: Add {R}{R}{R} to your mana pool.","flavor":"\"Any festival you can walk away from wasn't worth attending in the first place.\"","artist":"Chase Stone","number":"174","power":"2","toughness":"1","loyalty":null,"multiverseid":373744,"imageName":"satyr hedonist","watermark":null,"setCode":"THS","imageCode":"ths","count":1},{"name":"Awe for the Guilds","layout":"normal","manaCost":"{2}{R}","cmc":3,"type":"Sorcery","rarity":"Common","text":"Monocolored creatures can't block this turn.","flavor":"When the guilds cooperate, the guildless celebrate their peaceful society. When the guilds clash, the guildless just try to keep out of the way.","artist":"Mathias Kollros","number":"31","power":null,"toughness":null,"loyalty":null,"multiverseid":369053,"imageName":"awe for the guilds","watermark":null,"setCode":"DGM","imageCode":"dgm","count":1},{"name":"Voyaging Satyr","layout":"normal","manaCost":"{1}{G}","cmc":2,"type":"Creature — Satyr Druid","rarity":"Common","text":"{T}: Untap target land.","flavor":"\"None can own the land's bounty. The gods made this world for all to share its riches. And I'm not just saying that because you caught me stealing your fruit.\"","artist":"Tyler Jacobson","number":"182","power":"1","toughness":"2","loyalty":null,"multiverseid":373518,"imageName":"voyaging satyr","watermark":null,"setCode":"THS","imageCode":"ths","count":1},{"name":"Rugged Highlands","layout":"normal","manaCost":null,"cmc":null,"type":"Land","rarity":"Common","text":"Rugged Highlands enters the battlefield tapped.\nWhen Rugged Highlands enters the battlefield, you gain 1 life.\n{T}: Add {R} or {G} to your mana pool.","flavor":null,"artist":"Eytan Zana","number":"240","power":null,"toughness":null,"loyalty":null,"multiverseid":386641,"imageName":"rugged highlands","watermark":null,"setCode":"KTK","imageCode":"ktk","count":1},{"name":"Karametra's Favor","layout":"normal","manaCost":"{1}{G}","cmc":2,"type":"Enchantment — Aura","rarity":"Common","text":"Enchant creature\nWhen Karametra's Favor enters the battlefield, draw a card.\nEnchanted creature has \"{T}: Add one mana of any color to your mana pool.\"","flavor":"The harvest god's cornucopia contains the fruits of the fields, the forest, and beyond.","artist":"Chase Stone","number":"125","power":null,"toughness":null,"loyalty":null,"multiverseid":378497,"imageName":"karametra's favor","watermark":null,"setCode":"BNG","imageCode":"bng","count":1},{"name":"Segmented Krotiq","layout":"normal","manaCost":"{5}{G}","cmc":6,"type":"Creature — Insect","rarity":"Common","text":"Megamorph {6}{G} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its megamorph cost and put a +1/+1 counter on it.)","flavor":"The list of things a krotiq eats is as long as the krotiq itself.","artist":"Christopher Moeller","number":"202","power":"6","toughness":"5","loyalty":null,"multiverseid":394684,"imageName":"segmented krotiq","watermark":null,"setCode":"DTK","imageCode":"dtk","count":2},{"name":"Sprinting Warbrute","layout":"normal","manaCost":"{4}{R}","cmc":5,"type":"Creature — Ogre Berserker","rarity":"Common","text":"Sprinting Warbrute attacks each turn if able.\nDash {3}{R} (You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.)","flavor":null,"artist":"Lake Hurwitz","number":"157","power":"5","toughness":"4","loyalty":null,"multiverseid":394709,"imageName":"sprinting warbrute","watermark":"Kolaghan","setCode":"DTK","imageCode":"dtk","count":3},{"name":"Searing Blood","layout":"normal","manaCost":"{R}{R}","cmc":2,"type":"Instant","rarity":"Uncommon","text":"Searing Blood deals 2 damage to target creature. When that creature dies this turn, Searing Blood deals 3 damage to the creature's controller.","flavor":"Purphoros's blessing: sometimes a boon, sometimes a bane. Always ablaze.","artist":"Daniel Ljunggren","number":"111","power":null,"toughness":null,"loyalty":null,"multiverseid":378483,"imageName":"searing blood","watermark":null,"setCode":"BNG","imageCode":"bng","count":1},{"name":"Surrak, the Hunt Caller","layout":"normal","manaCost":"{2}{G}{G}","cmc":4,"type":"Legendary Creature — Human Warrior","rarity":"Rare","text":"Formidable — At the beginning of combat on your turn, if creatures you control have total power 8 or greater, target creature you control gains haste until end of turn.","flavor":"\"The greatest honor is to feed Atarka.\"","artist":"Wesley Burt","number":"210","power":"5","toughness":"4","loyalty":null,"multiverseid":394721,"imageName":"surrak, the hunt caller","watermark":"Atarka","setCode":"DTK","imageCode":"dtk","count":1},{"name":"Kolaghan Aspirant","layout":"normal","manaCost":"{1}{R}","cmc":2,"type":"Creature — Human Warrior","rarity":"Common","text":"Whenever Kolaghan Aspirant becomes blocked by a creature, Kolaghan Aspirant deals 1 damage to that creature.","flavor":"She answers the call of the Crave, the desire for battle sated only by bloodshed.","artist":"Aaron Miller","number":"143","power":"2","toughness":"1","loyalty":null,"multiverseid":394608,"imageName":"kolaghan aspirant","watermark":"Kolaghan","setCode":"DTK","imageCode":"dtk","count":1},{"name":"Alpine Grizzly","layout":"normal","manaCost":"{2}{G}","cmc":3,"type":"Creature — Bear","rarity":"Common","text":null,"flavor":"The Temur welcome bears into the clan, fighting alongside them in battle. The relationship dates back to when they labored side by side under Sultai rule.","artist":"John Severin Brassell","number":"127","power":"4","toughness":"2","loyalty":null,"multiverseid":386474,"imageName":"alpine grizzly","watermark":null,"setCode":"KTK","imageCode":"ktk","count":1},{"name":"Valley Dasher","layout":"normal","manaCost":"{1}{R}","cmc":2,"type":"Creature — Human Berserker","rarity":"Common","text":"Haste\nValley Dasher attacks each turn if able.","flavor":"Mardu riders' greatest fear is that a battle might end before their weapons draw blood.","artist":"Matt Stewart","number":"125","power":"2","toughness":"2","loyalty":null,"multiverseid":386712,"imageName":"valley dasher","watermark":"Mardu","setCode":"KTK","imageCode":"ktk","count":1},{"name":"Terra Stomper","layout":"normal","manaCost":"{3}{G}{G}{G}","cmc":6,"type":"Creature — Beast","rarity":"Rare","text":"Terra Stomper can't be countered.\nTrample (If this creature would assign enough damage to its blockers to destroy them, you may have it assign the rest of its damage to defending player or planeswalker.)","flavor":"Its footfalls cause violent earthquakes, hurtling boulders, and unseasonable dust storms.","artist":"Goran Josic","number":"284","power":"8","toughness":"8","loyalty":null,"multiverseid":383173,"imageName":"terra stomper","watermark":null,"setCode":"M15","imageCode":"m15","count":1},{"name":"Vaultbreaker","layout":"normal","manaCost":"{3}{R}","cmc":4,"type":"Creature — Orc Rogue","rarity":"Uncommon","text":"Whenever Vaultbreaker attacks, you may discard a card. If you do, draw a card.\nDash {2}{R} (You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.)","flavor":null,"artist":"Wayne Reynolds","number":"117","power":"4","toughness":"2","loyalty":null,"multiverseid":391951,"imageName":"vaultbreaker","watermark":"Mardu","setCode":"FRF","imageCode":"frf","count":1},{"name":"Elvish Mystic","layout":"normal","manaCost":"{G}","cmc":1,"type":"Creature — Elf Druid","rarity":"Common","text":"{T}: Add {G} to your mana pool.","flavor":"\"Life grows everywhere. My kin merely find those places where it grows strongest.\"\n—Nissa Revane","artist":"Wesley Burt","number":"173","power":"1","toughness":"1","loyalty":null,"multiverseid":383229,"imageName":"elvish mystic","watermark":null,"setCode":"M15","imageCode":"m15","count":2},{"name":"Collateral Damage","layout":"normal","manaCost":"{R}","cmc":1,"type":"Instant","rarity":"Common","text":"As an additional cost to cast Collateral Damage, sacrifice a creature.\nCollateral Damage deals 3 damage to target creature or player.","flavor":"It is much easier to create fire than to contain it.","artist":"Ryan Barger","number":"95","power":null,"toughness":null,"loyalty":null,"multiverseid":391811,"imageName":"collateral damage","watermark":null,"setCode":"FRF","imageCode":"frf","count":1},{"name":"Dragon Whisperer","layout":"normal","manaCost":"{R}{R}","cmc":2,"type":"Creature — Human Shaman","rarity":"Mythic Rare","text":"{R}: Dragon Whisperer gains flying until end of turn.\n{1}{R}: Dragon Whisperer gets +1/+0 until end of turn.\nFormidable — {4}{R}{R}: Put a 4/4 red Dragon creature token with flying onto the battlefield. Activate this ability only if creatures you control have total power 8 or greater.","flavor":null,"artist":"Chris Rallis","number":"137","power":"2","toughness":"2","loyalty":null,"multiverseid":394543,"imageName":"dragon whisperer","watermark":"Atarka","setCode":"DTK","imageCode":"dtk","count":1},{"name":"Magma Spray","layout":"normal","manaCost":"{R}","cmc":1,"type":"Instant","rarity":"Common","text":"Magma Spray deals 2 damage to target creature. If that creature would die this turn, exile it instead.","flavor":"The ancient dragon Thraxes sleeps in Purphoros's sacred peak. When he stirs in dreams, so does the mountain.","artist":"Richard Wright","number":"103","power":null,"toughness":null,"loyalty":null,"multiverseid":380452,"imageName":"magma spray","watermark":null,"setCode":"JOU","imageCode":"jou","count":1},{"name":"Hammerhand","layout":"normal","manaCost":"{R}","cmc":1,"type":"Enchantment — Aura","rarity":"Common","text":"Enchant creature\nWhen Hammerhand enters the battlefield, target creature can't block this turn.\nEnchanted creature gets +1/+1 and has haste. (It can attack and {T} no matter when it came under your control.)","flavor":null,"artist":"Tomasz Jedruszek","number":"147","power":null,"toughness":null,"loyalty":null,"multiverseid":383262,"imageName":"hammerhand","watermark":null,"setCode":"M15","imageCode":"m15","count":1},{"name":"Brindle Boar","layout":"normal","manaCost":"{2}{G}","cmc":3,"type":"Creature — Boar","rarity":"Common","text":"Sacrifice Brindle Boar: You gain 4 life.","flavor":"\"Tell the cooks to prepare the fires. Tonight we feast!\"\n—Tolar Wolfbrother, Krosan tracker","artist":"Dave Allsop","number":"167","power":"2","toughness":"2","loyalty":null,"multiverseid":370778,"imageName":"brindle boar","watermark":null,"setCode":"M14","imageCode":"m14","count":1},{"name":"Harbinger of the Hunt","layout":"normal","manaCost":"{3}{R}{G}","cmc":5,"type":"Creature — Dragon","rarity":"Rare","text":"Flying\n{2}{R}: Harbinger of the Hunt deals 1 damage to each creature without flying.\n{2}{G}: Harbinger of the Hunt deals 1 damage to each other creature with flying.","flavor":"An Atarka dragon's exhale cooks what its inhale consumes.","artist":"Aaron Miller","number":"223","power":"5","toughness":"3","loyalty":null,"multiverseid":394591,"imageName":"harbinger of the hunt","watermark":"Atarka","setCode":"DTK","imageCode":"dtk","count":1},{"name":"Lightning Strike","layout":"normal","manaCost":"{1}{R}","cmc":2,"type":"Instant","rarity":"Common","text":"Lightning Strike deals 3 damage to target creature or player.","flavor":"\"The hand of Keranos can be seen in every rumbling storm cloud. Best not to stand where he points.\"\n—Rakleia of Shrine Peak","artist":"Adam Paquette","number":"127","power":null,"toughness":null,"loyalty":null,"multiverseid":373651,"imageName":"lightning strike","watermark":null,"setCode":"THS","imageCode":"ths","count":2},{"name":"Monastery Swiftspear","layout":"normal","manaCost":"{R}","cmc":1,"type":"Creature — Human Monk","rarity":"Uncommon","text":"Haste\nProwess (Whenever you cast a noncreature spell, this creature gets +1/+1 until end of turn.)","flavor":"The calligraphy of combat is written with strokes of sudden blood.","artist":"Steve Argyle","number":"118","power":"1","toughness":"2","loyalty":null,"multiverseid":386608,"imageName":"monastery swiftspear","watermark":"Jeskai","setCode":"KTK","imageCode":"ktk","count":1},{"name":"Evolving Wilds","layout":"normal","manaCost":null,"cmc":null,"type":"Land","rarity":"Common","text":"{T}, Sacrifice Evolving Wilds: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.","flavor":"Without the interfering hands of civilization, nature will always shape itself to its own needs.","artist":"Steven Belledin","number":"243","power":null,"toughness":null,"loyalty":null,"multiverseid":383235,"imageName":"evolving wilds","watermark":null,"setCode":"M15","imageCode":"m15","count":2},{"name":"Market Festival","layout":"normal","manaCost":"{3}{G}","cmc":4,"type":"Enchantment — Aura","rarity":"Common","text":"Enchant land\nWhenever enchanted land is tapped for mana, its controller adds two mana in any combination of colors to his or her mana pool (in addition to the mana the land produces).","flavor":"Commerce is always the basis for peace.","artist":"Ryan Barger","number":"130","power":null,"toughness":null,"loyalty":null,"multiverseid":380454,"imageName":"market festival","watermark":null,"setCode":"JOU","imageCode":"jou","count":2},{"name":"Lightning Shrieker","layout":"normal","manaCost":"{4}{R}","cmc":5,"type":"Creature — Dragon","rarity":"Common","text":"Flying, trample, haste\nAt the beginning of the end step, Lightning Shrieker's owner shuffles it into his or her library.","flavor":"Dragonslayers learned to keep silent about their deeds after seeing the terrible vengeance wrought by Kolaghan and her brood.","artist":"Slawomir Maniak","number":"106","power":"5","toughness":"5","loyalty":null,"multiverseid":391868,"imageName":"lightning shrieker","watermark":"Kolaghan","setCode":"FRF","imageCode":"frf","count":1},{"name":"Kalonian Tusker","layout":"normal","manaCost":"{G}{G}","cmc":2,"type":"Creature — Beast","rarity":"Uncommon","text":null,"flavor":"\"And all this time I thought we were tracking it.\"\n—Juruk, Kalonian tracker","artist":"Svetlin Velinov","number":"182","power":"3","toughness":"3","loyalty":null,"multiverseid":370700,"imageName":"kalonian tusker","watermark":null,"setCode":"M14","imageCode":"m14","count":1},{"name":"Dragon Mantle","layout":"normal","manaCost":"{R}","cmc":1,"type":"Enchantment — Aura","rarity":"Common","text":"Enchant creature\nWhen Dragon Mantle enters the battlefield, draw a card.\nEnchanted creature has \"{R}: This creature gets +1/+0 until end of turn.\"","flavor":null,"artist":"Anthony Palumbo","number":"119","power":null,"toughness":null,"loyalty":null,"multiverseid":373634,"imageName":"dragon mantle","watermark":null,"setCode":"THS","imageCode":"ths","count":2},{"name":"Shivan Dragon","layout":"normal","manaCost":"{4}{R}{R}","cmc":6,"type":"Creature — Dragon","rarity":"Rare","text":"Flying (This creature can't be blocked except by creatures with flying or reach.)\n{R}: Shivan Dragon gets +1/+0 until end of turn.","flavor":"The undisputed master of the mountains of Shiv.","artist":"Donato Giancola","number":"281","power":"5","toughness":"5","loyalty":null,"multiverseid":383172,"imageName":"shivan dragon","watermark":null,"setCode":"M15","imageCode":"m15","count":1}]} \ No newline at end of file -- cgit v1.2.3