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 --- src/eu/equalparts/cardbase/Cardbase.java | 197 +---------- src/eu/equalparts/cardbase/cards/Card.java | 3 + .../cardstorage/ReferenceCardContainer.java | 50 +++ .../cardstorage/StandaloneCardContainer.java | 73 ++++ src/eu/equalparts/cardbase/cli/CardbaseCLI.java | 2 +- src/eu/equalparts/cardbase/utils/JSON.java | 6 + 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 - test/testbase.cb | 2 +- 15 files changed, 826 insertions(+), 787 deletions(-) create mode 100644 src/eu/equalparts/cardbase/cardstorage/ReferenceCardContainer.java create mode 100644 src/eu/equalparts/cardbase/cardstorage/StandaloneCardContainer.java 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 diff --git a/src/eu/equalparts/cardbase/Cardbase.java b/src/eu/equalparts/cardbase/Cardbase.java index be66127..d17ab2a 100644 --- a/src/eu/equalparts/cardbase/Cardbase.java +++ b/src/eu/equalparts/cardbase/Cardbase.java @@ -2,20 +2,14 @@ package eu.equalparts.cardbase; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; -import eu.equalparts.cardbase.cards.Card; import eu.equalparts.cardbase.cardstorage.StandaloneCardContainer; -import eu.equalparts.cardbase.comparator.CardComparator; import eu.equalparts.cardbase.decks.ReferenceDeck; import eu.equalparts.cardbase.utils.JSON; @@ -26,31 +20,10 @@ import eu.equalparts.cardbase.utils.JSON; */ public class Cardbase extends StandaloneCardContainer { -// private static class DataContainer { -// /** -// * The cards in the cardbase, set in key-value pairs where the key is the card hash, -// * generated using {makeHash()}. -// */ -// public Map cards; -// /** -// * TODO comment -// */ -// public Map collection; - -// -// public DataContainer() { -// cards = new HashMap(); -// collection = new HashMap(); -// decks = new HashMap(); -// } -// } - -// private DataContainer dataContainer; - /** * The decks which have been saved along with this collection of cards. */ - public Map decks; + @JsonProperty private Map decks; /** * Initialises the cardbase with the contents of a file. @@ -65,13 +38,6 @@ public class Cardbase extends StandaloneCardContainer { return JSON.mapper.readValue(cardbaseFile, Cardbase.class); } - /** - * Initialises a clean cardbase. - */ - public Cardbase() { - super(); - } - /** * Writes the provided {@code Cardbase} to the provided file in JSON format. * @@ -82,164 +48,7 @@ public class Cardbase extends StandaloneCardContainer { * @throws JsonMappingException if the data structure given does not generate valid JSON as well? * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) occurs. */ - public void writeCollection(File outputFile) throws JsonGenerationException, JsonMappingException, IOException { + public void write(File outputFile) throws JsonGenerationException, JsonMappingException, IOException { JSON.mapper.writeValue(outputFile, this); } - - /** - * Adds a specific amount of a card to the cardbase. - * If the card is not already in the cardbase, it is added. - * If it is already present, the count is simply updated. - * - * @param cardToAdd the card to be added. The count value - * of this object is added to the existing count if the card - * already exists. - *TODO fix comment - */ -// public void addCard(Card cardToAdd, int addCount) { -// Integer hashCode = cardToAdd.hashCode(); -// -// // ensure that card is in the card map -// dataContainer.cards.putIfAbsent(hashCode, cardToAdd); -// -// // ensure that card is in the collection, with the correct count -// Integer currentCount = dataContainer.collection.get(hashCode); -// if (currentCount != null) { -// dataContainer.collection.replace(hashCode, currentCount + addCount); -// } else { -// dataContainer.collection.put(hashCode, addCount); -// } -// } - - /** - * Removes a specific amount of a card from the cardbase. - * If the card is not present in the cardbase, nothing happens. - * If the card is present in the cardbase, the specified amount is removed. - * If that amount is equal to or exceeds the count already in the cardbase, - * the card entry is removed altogether. - *

- * In any case, the value returned is the actual number of cards removed. - * For example, if 5 Shivan Dragons are in the cardbase and the method is - * called to remove 10 Shivan Dragons, the {@code Card} representing the - * Shivan Dragon is removed from the cardbase, and the value returned is 5. - * - * @param cardToRemove the card to be removed. - * @param removeCount the amount of the card to be removed. - * @return the number of cards actually removed. - *TODO comment - */ -// public Integer removeCard(Card cardToRemove, int removeCount) { -// Integer hashCode = cardToRemove.hashCode(); -// int removed = 0; -// -// Integer currentCount = dataContainer.collection.get(hashCode); -// if (currentCount != null) { -// if (removeCount >= currentCount) { -// dataContainer.collection.remove(hashCode); -// dataContainer.cards.remove(hashCode); -// removed = currentCount; -// } else { -// dataContainer.collection.replace(hashCode, currentCount - removeCount); -// removed = removeCount; -// } -// } -// return removed; -// } - - /** - * Returns a card from the cardbase by set code and number. - * If no such card is in the cardbase, returns null. - * - * @param setCode the set to which the requested card belongs. - * @param number the requested card's set number. - * @return the requested {@code Card} or null if no card is found. - */ -// public Card getCard(String setCode, String number) { -// return dataContainer.cards.get(Card.makeHash(setCode, number)); -// } - - /** - * Returns a card from the cardbase by hash. The card's hash - * can be generated using {@code Cardbase.makeHash()}. - * If no such card is in the cardbase, returns null. - * - * @param hash the Cardbase hash of the requested card. - * @return the requested {@code Card} or null if no card is found. - */ -// protected Card getCardByHash(Integer hash) { -// return dataContainer.cards.get(hash); -// } - - /** - * @param fieldName the name of the field by which to sort. - * @return an unmodifiable collection representing the cardbase sorted in the required order. - * @throws NoSuchFieldException if the field provided is invalid. - */ - public Collection sortByField(String fieldName) throws NoSuchFieldException { - List sortedCards = new ArrayList(getCards()); - sortedCards.sort(new CardComparator(Card.class.getDeclaredField(fieldName))); - return Collections.unmodifiableCollection(sortedCards); - } - -// public int getCount(Card card) { -// Integer count = dataContainer.collection.get(Card.makeHash(card.setCode, card.number)); -// return count != null ? count : 0; -// } - -// public List getMissingCards(StandaloneDeck deckToCheck) { -// List missingCards = new ArrayList(); -// for (Card card : deckToCheck.cards) { -// Integer hash = card.hashCode(); -// if (cards.containsKey(hash)) { -// if (cards.get(hash).count < card.count) { -// Card missingCard = card.clone(); -// missingCard.count = card.count - cards.get(hash).count; -// missingCards.add(missingCard); -// } -// } else { -// missingCards.add(card); -// } -// } -// return missingCards; -// } - -// public void addStandaloneDeck(StandaloneDeck deckToAdd) { -// List missingCards = getMissingCards(deckToAdd); -// if (missingCards.size() <= 0) { -// decks.put(deckToAdd.name, new ReferenceDeck(deckToAdd)); -// } else { -// throw new IllegalArgumentException("The cardbase is missing cards to add this deck."); -// } -// } - -// public StandaloneDeck exportDeck(String deckName) { -// ReferenceDeck referenceDeck = decks.get(deckName); -// -// if (referenceDeck != null) { -// StandaloneDeck standaloneDeck = new StandaloneDeck(); -// -// standaloneDeck.name = referenceDeck.name; -// standaloneDeck.plains = referenceDeck.plains; -// standaloneDeck.islands = referenceDeck.islands; -// standaloneDeck.swamps = referenceDeck.swamps; -// standaloneDeck.mountains = referenceDeck.mountains; -// standaloneDeck.forests = referenceDeck.forests; -// -// for (Integer cardHash : referenceDeck.cardReferences.keySet()) { -// Card card = getCardByHash(cardHash); -// if (card != null) { -// // must clone otherwise the original count is affected too -// card = card.clone(); -// card.count = referenceDeck.cardReferences.get(cardHash); -// standaloneDeck.cards.add(card); -// } else { -// throw new IllegalArgumentException("Deck refers to card not in cardbase: " + cardHash); -// } -// } -// -// return standaloneDeck; -// } else { -// throw new IllegalArgumentException("The specified deck does not exist."); -// } -// } } diff --git a/src/eu/equalparts/cardbase/cards/Card.java b/src/eu/equalparts/cardbase/cards/Card.java index 9b0975b..37cc13e 100644 --- a/src/eu/equalparts/cardbase/cards/Card.java +++ b/src/eu/equalparts/cardbase/cards/Card.java @@ -1,8 +1,11 @@ package eu.equalparts.cardbase.cards; +import com.fasterxml.jackson.annotation.JsonAutoDetect; + import eu.equalparts.cardbase.comparator.SpecialFields.DirtyNumber; import eu.equalparts.cardbase.comparator.SpecialFields.Rarity; +@JsonAutoDetect public class Card { public String name; diff --git a/src/eu/equalparts/cardbase/cardstorage/ReferenceCardContainer.java b/src/eu/equalparts/cardbase/cardstorage/ReferenceCardContainer.java new file mode 100644 index 0000000..ccd5508 --- /dev/null +++ b/src/eu/equalparts/cardbase/cardstorage/ReferenceCardContainer.java @@ -0,0 +1,50 @@ +package eu.equalparts.cardbase.cardstorage; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import eu.equalparts.cardbase.cards.Card; + +public abstract class ReferenceCardContainer { + + @JsonProperty private Map cardReferences; + + public ReferenceCardContainer() { + cardReferences = new HashMap<>(); + } + + public int getCount(Card cardToCount) { + int hashCode = cardToCount.hashCode(); + return cardReferences.containsKey(hashCode) ? cardReferences.get(hashCode) : 0; + } + + public void addCard(Card cardToAdd, int count) { + int hashCode = cardToAdd.hashCode(); + if (cardReferences.containsKey(hashCode)) { + cardReferences.replace(hashCode, cardReferences.get(hashCode) + count); + } else { + cardReferences.put(hashCode, count); + } + } + + public int removeCard(Card cardToRemove, int count) { + int hashCode = cardToRemove.hashCode(); + int removed = 0; + + if (cardReferences.containsKey(hashCode) && count > 0) { + int oldCount = cardReferences.get(hashCode); + + if (oldCount > count) { + cardReferences.replace(hashCode, oldCount - count); + removed = count; + } else { + cardReferences.remove(hashCode); + removed = oldCount; + } + } + + return removed; + } +} diff --git a/src/eu/equalparts/cardbase/cardstorage/StandaloneCardContainer.java b/src/eu/equalparts/cardbase/cardstorage/StandaloneCardContainer.java new file mode 100644 index 0000000..52fc89e --- /dev/null +++ b/src/eu/equalparts/cardbase/cardstorage/StandaloneCardContainer.java @@ -0,0 +1,73 @@ +package eu.equalparts.cardbase.cardstorage; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import eu.equalparts.cardbase.cards.Card; +import eu.equalparts.cardbase.comparator.CardComparator; + +public abstract class StandaloneCardContainer extends ReferenceCardContainer { + + @JsonProperty private Map cardData; + + public StandaloneCardContainer() { + super(); + cardData = new HashMap<>(); + } + + @Override + public void addCard(Card cardToAdd, int count) { + super.addCard(cardToAdd, count); + cardData.putIfAbsent(cardToAdd.hashCode(), cardToAdd); + } + + @Override + public int removeCard(Card cardToRemove, int count) { + int removed = super.removeCard(cardToRemove, count); + if (getCount(cardToRemove) <= 0) { + cardData.remove(cardToRemove.hashCode()); + } + return removed; + } + + /** + * Returns a card from the cardbase by set code and number. + * If no such card is in the cardbase, returns null. + * + * @param setCode the set to which the requested card belongs. + * @param number the requested card's set number. + * @return the requested {@code Card} or null if no card is found. + */ + public Card getCard(String setCode, String number) { + return cardData.get(Card.makeHash(setCode, number)); + } + + /** + * This method is intended to allow iteration directly on the list of cards, + * while at the same time retaining control over the insert and remove procedures. + * The returned {@code List} is a read-only; trying to modify its structure will + * result in an {@code UnsupportedOperationException}. + * + * @return an unmodifiable list of all the cards in the cardbase. + */ + public Collection getCards() { + return Collections.unmodifiableCollection(cardData.values()); + } + + /** + * @param fieldName the name of the field by which to sort. + * @return an unmodifiable collection representing the cardbase sorted in the required order. + * @throws NoSuchFieldException if the field provided is invalid. + */ + public Collection sortByField(String fieldName) throws NoSuchFieldException { + List sortedCards = new ArrayList(getCards()); + sortedCards.sort(new CardComparator(Card.class.getDeclaredField(fieldName))); + return Collections.unmodifiableCollection(sortedCards); + } +} diff --git a/src/eu/equalparts/cardbase/cli/CardbaseCLI.java b/src/eu/equalparts/cardbase/cli/CardbaseCLI.java index cbce4f9..7a932d0 100644 --- a/src/eu/equalparts/cardbase/cli/CardbaseCLI.java +++ b/src/eu/equalparts/cardbase/cli/CardbaseCLI.java @@ -256,7 +256,7 @@ public final class CardbaseCLI { } else { // handle these exceptions locally - they don't necessarily mean the program should exit try { - cardbase.writeCollection(outputFile); + cardbase.write(outputFile); // we are now working off outputFile, which may or may not be the same as cardbaseFile at this point cardbaseFile = outputFile; System.out.println("Cardbase was saved to \"" + outputFile.getAbsolutePath() + "\". " diff --git a/src/eu/equalparts/cardbase/utils/JSON.java b/src/eu/equalparts/cardbase/utils/JSON.java index 17e8392..4a21311 100644 --- a/src/eu/equalparts/cardbase/utils/JSON.java +++ b/src/eu/equalparts/cardbase/utils/JSON.java @@ -1,6 +1,7 @@ package eu.equalparts.cardbase.utils; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; /** @@ -30,6 +31,11 @@ public final class JSON { ObjectMapper objectMapper = new ObjectMapper(); // classes don't necessarily use all json fields objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // disable auto detection + objectMapper.disable(MapperFeature.AUTO_DETECT_CREATORS, + MapperFeature.AUTO_DETECT_FIELDS, + MapperFeature.AUTO_DETECT_GETTERS, + MapperFeature.AUTO_DETECT_IS_GETTERS); return objectMapper; } } 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 diff --git a/test/testbase.cb b/test/testbase.cb index e617fd8..cf06e9f 100644 --- a/test/testbase.cb +++ b/test/testbase.cb @@ -1 +1 @@ -{"cards":{"1588769":{"name":"Reverberate","layout":"normal","manaCost":"{R}{R}","cmc":2,"type":"Instant","rarity":"Rare","text":"Copy target instant or sorcery spell. You may choose new targets for the copy.","flavor":"For every action, there is a swifter and more violent reaction.","artist":"jD","number":"152","power":null,"toughness":null,"loyalty":null,"multiverseid":233722,"imageName":"reverberate","watermark":null,"setCode":"M12","imageCode":"m12"},"126251":{"name":"Mighty Leap","layout":"normal","manaCost":"{1}{W}","cmc":2,"type":"Instant","rarity":"Common","text":"Target creature gets +2/+2 and gains flying until end of turn. (It can't be blocked except by creatures with flying or reach.)","flavor":"\"The southern fortress taken by invaders? Heh, sure . . . when elephants fly.\"\n—Brezard Skeinbow, captain of the guard","artist":"rk post","number":"26","power":null,"toughness":null,"loyalty":null,"multiverseid":241989,"imageName":"mighty leap","watermark":null,"setCode":"M12","imageCode":"m12"},"1580419":{"name":"Formless Nurturing","layout":"normal","manaCost":"{3}{G}","cmc":4,"type":"Sorcery","rarity":"Common","text":"Manifest the top card of your library, then put a +1/+1 counter on it. (To manifest a card, put it onto the battlefield face down as a 2/2 creature. Turn it face up any time for its mana cost if it's a creature card.)","flavor":null,"artist":"Cliff Childs","number":"129","power":null,"toughness":null,"loyalty":null,"multiverseid":391837,"imageName":"formless nurturing","watermark":null,"setCode":"FRF","imageCode":"frf"},"1580388":{"name":"Feral Krushok","layout":"normal","manaCost":"{4}{G}","cmc":5,"type":"Creature — Beast","rarity":"Common","text":null,"flavor":"In a stunning act of diplomacy, Yasova Dragonclaw ceded a portion of Temur lands to the Sultai. Her clan protested until they saw she had given the Sultai the breeding grounds of the krushoks. They hadn't realized she had a sense of humor.","artist":"Kev Walker","number":"128","power":"5","toughness":"4","loyalty":null,"multiverseid":391831,"imageName":"feral krushok","watermark":null,"setCode":"FRF","imageCode":"frf"},"1580357":{"name":"Destructor Dragon","layout":"normal","manaCost":"{4}{G}{G}","cmc":6,"type":"Creature — Dragon","rarity":"Uncommon","text":"Flying\nWhen Destructor Dragon dies, destroy target noncreature permanent.","flavor":"After countless attacks on the Salt Road where it passes through the frozen tundra, the Abzan began to refer to the area as Atarka territory rather than Temur lands.","artist":"Peter Mohrbacher","number":"127","power":"4","toughness":"4","loyalty":null,"multiverseid":391818,"imageName":"destructor dragon","watermark":"Atarka","setCode":"FRF","imageCode":"frf"},"127150":{"name":"Siege Mastodon","layout":"normal","manaCost":"{4}{W}","cmc":5,"type":"Creature — Elephant","rarity":"Common","text":null,"flavor":"\"The walls of the wicked will fall before us. Ready the siege engines. We proceed to war!\"\n—General Avitora","artist":"Matt Cavotta","number":"34","power":"3","toughness":"5","loyalty":null,"multiverseid":222635,"imageName":"siege mastodon","watermark":null,"setCode":"M12","imageCode":"m12"}},"collection":{"1588769":1,"126251":1,"1580419":8,"1580388":1,"1580357":1,"127150":2},"decks":{}} \ No newline at end of file +{"cardData":{"1588769":{"name":"Reverberate","layout":"normal","manaCost":"{R}{R}","cmc":2,"type":"Instant","rarity":"Rare","text":"Copy target instant or sorcery spell. You may choose new targets for the copy.","flavor":"For every action, there is a swifter and more violent reaction.","artist":"jD","number":"152","power":null,"toughness":null,"loyalty":null,"multiverseid":233722,"imageName":"reverberate","watermark":null,"setCode":"M12","imageCode":"m12"},"126251":{"name":"Mighty Leap","layout":"normal","manaCost":"{1}{W}","cmc":2,"type":"Instant","rarity":"Common","text":"Target creature gets +2/+2 and gains flying until end of turn. (It can't be blocked except by creatures with flying or reach.)","flavor":"\"The southern fortress taken by invaders? Heh, sure . . . when elephants fly.\"\n—Brezard Skeinbow, captain of the guard","artist":"rk post","number":"26","power":null,"toughness":null,"loyalty":null,"multiverseid":241989,"imageName":"mighty leap","watermark":null,"setCode":"M12","imageCode":"m12"},"1580419":{"name":"Formless Nurturing","layout":"normal","manaCost":"{3}{G}","cmc":4,"type":"Sorcery","rarity":"Common","text":"Manifest the top card of your library, then put a +1/+1 counter on it. (To manifest a card, put it onto the battlefield face down as a 2/2 creature. Turn it face up any time for its mana cost if it's a creature card.)","flavor":null,"artist":"Cliff Childs","number":"129","power":null,"toughness":null,"loyalty":null,"multiverseid":391837,"imageName":"formless nurturing","watermark":null,"setCode":"FRF","imageCode":"frf"},"1580388":{"name":"Feral Krushok","layout":"normal","manaCost":"{4}{G}","cmc":5,"type":"Creature — Beast","rarity":"Common","text":null,"flavor":"In a stunning act of diplomacy, Yasova Dragonclaw ceded a portion of Temur lands to the Sultai. Her clan protested until they saw she had given the Sultai the breeding grounds of the krushoks. They hadn't realized she had a sense of humor.","artist":"Kev Walker","number":"128","power":"5","toughness":"4","loyalty":null,"multiverseid":391831,"imageName":"feral krushok","watermark":null,"setCode":"FRF","imageCode":"frf"},"1580357":{"name":"Destructor Dragon","layout":"normal","manaCost":"{4}{G}{G}","cmc":6,"type":"Creature — Dragon","rarity":"Uncommon","text":"Flying\nWhen Destructor Dragon dies, destroy target noncreature permanent.","flavor":"After countless attacks on the Salt Road where it passes through the frozen tundra, the Abzan began to refer to the area as Atarka territory rather than Temur lands.","artist":"Peter Mohrbacher","number":"127","power":"4","toughness":"4","loyalty":null,"multiverseid":391818,"imageName":"destructor dragon","watermark":"Atarka","setCode":"FRF","imageCode":"frf"},"127150":{"name":"Siege Mastodon","layout":"normal","manaCost":"{4}{W}","cmc":5,"type":"Creature — Elephant","rarity":"Common","text":null,"flavor":"\"The walls of the wicked will fall before us. Ready the siege engines. We proceed to war!\"\n—General Avitora","artist":"Matt Cavotta","number":"34","power":"3","toughness":"5","loyalty":null,"multiverseid":222635,"imageName":"siege mastodon","watermark":null,"setCode":"M12","imageCode":"m12"}},"cardReferences":{"1588769":1,"126251":1,"1580419":8,"1580388":1,"1580357":1,"127150":2},"decks":{}} -- cgit v1.2.3