diff --git a/forge-core/src/main/java/forge/deck/DeckRecognizer.java b/forge-core/src/main/java/forge/deck/DeckRecognizer.java index 9b3104a83ab..b35e944511c 100644 --- a/forge-core/src/main/java/forge/deck/DeckRecognizer.java +++ b/forge-core/src/main/java/forge/deck/DeckRecognizer.java @@ -141,13 +141,6 @@ public class DeckRecognizer { } } -// // Let's think about it numbers in the back later -// // private static final Pattern searchNumbersInBack = -// // Pattern.compile("(.*)[^A-Za-wyz]*\\s+([\\d]{1,2})"); -// private static final Pattern SEARCH_NUMBERS_IN_FRONT = Pattern.compile("([\\d]{1,2})[^A-Za-wyz]*\\s+(.*)"); -// //private static final Pattern READ_SEPARATED_EDITION = Pattern.compile("[[\\(\\{]([a-zA-Z0-9]){1,3})[]*\\s+(.*)"); -// private static final Pattern SEARCH_SINGLE_SLASH = Pattern.compile("(?<=[^/])\\s*/\\s*(?=[^/])"); - // Utility Constants private final Pattern SEARCH_SINGLE_SLASH = Pattern.compile("(?<=[^/])\\s*/\\s*(?=[^/])"); private static final String LINE_COMMENT_DELIMITER = "#"; @@ -158,7 +151,7 @@ public class DeckRecognizer { // Core Matching Patterns (initialised in Constructor) public static final String REGRP_DECKNAME = "deckName"; public static final String REX_DECK_NAME = - String.format("^(//\\s*)?(?
(deck name|name|deck))(\\:|\\s)\\s*(?<%s>[a-zA-Z0-9',\\/\\-\\s]+)\\s*(.*)$",
+ String.format("^(//\\s*)?(?(deck|name))(\\:|\\s)\\s*(?<%s>[a-zA-Z0-9',\\/\\-\\s]+)\\s*(.*)$",
REGRP_DECKNAME);
public static final Pattern DECK_NAME_PATTERN = Pattern.compile(REX_DECK_NAME, Pattern.CASE_INSENSITIVE);
@@ -173,36 +166,47 @@ public class DeckRecognizer {
public static final String REX_CARD_NAME = String.format("(?<%s>[a-zA-Z0-9',\\.:!\\+\\\"\\/\\-\\s]+)", REGRP_CARD);
public static final String REX_SET_CODE = String.format("(?<%s>[a-zA-Z0-9_]{2,7})", REGRP_SET);
- public static final String REX_COLL_NUMBER = String.format("(?<%s>\\S?[0-9A-Z]+\\S?[A-Z]*)", REGRP_COLLNR);
+ public static final String REX_COLL_NUMBER = String.format("(?<%s>\\*?[0-9A-Z]+\\S?[A-Z]*)", REGRP_COLLNR);
public static final String REX_CARD_COUNT = String.format("(?<%s>[\\d]{1,2})(?x)?", REGRP_CARDNO);
+ // EXTRA
+ public static final String REGRP_FOIL_GFISH = "foil";
+ private static final String REX_FOIL_MTGGOLDFISH = String.format(
+ "(?<%s>\\(F\\))?", REGRP_FOIL_GFISH);
+
// 1. Card-Set Request (Amount?, CardName, Set)
public static final String REX_CARD_SET_REQUEST = String.format(
- "(%s\\s)?\\s*%s\\s*(\\s|\\||\\(|\\[|\\{)%s(\\s|\\)|\\]|\\})?",
- REX_CARD_COUNT, REX_CARD_NAME, REX_SET_CODE);
+ "(%s\\s)?\\s*%s\\s*(\\s|\\||\\(|\\[|\\{)%s(\\s|\\)|\\]|\\})?\\s*%s",
+ REX_CARD_COUNT, REX_CARD_NAME, REX_SET_CODE, REX_FOIL_MTGGOLDFISH);
public static final Pattern CARD_SET_PATTERN = Pattern.compile(REX_CARD_SET_REQUEST);
// 2. Set-Card Request (Amount?, Set, CardName)
public static final String REX_SET_CARD_REQUEST = String.format(
- "(%s\\s)?\\s*(\\(|\\[|\\{)?%s(\\s+|\\)|\\]|\\}|\\|)\\s*%s\\s*",
- REX_CARD_COUNT, REX_SET_CODE, REX_CARD_NAME);
+ "(%s\\s)?\\s*(\\(|\\[|\\{)?%s(\\s+|\\)|\\]|\\}|\\|)\\s*%s\\s*%s\\s*",
+ REX_CARD_COUNT, REX_SET_CODE, REX_CARD_NAME, REX_FOIL_MTGGOLDFISH);
public static final Pattern SET_CARD_PATTERN = Pattern.compile(REX_SET_CARD_REQUEST);
// 3. Full-Request (Amount?, CardName, Set, Collector Number|Art Index) - MTGArena Format
public static final String REX_FULL_REQUEST_CARD_SET = String.format(
- "(%s\\s)?\\s*%s\\s*(\\||\\(|\\[|\\{|\\s)%s(\\s|\\)|\\]|\\})?\\s+%s",
- REX_CARD_COUNT, REX_CARD_NAME, REX_SET_CODE, REX_COLL_NUMBER);
+ "(%s\\s)?\\s*%s\\s*(\\||\\(|\\[|\\{|\\s)%s(\\s|\\)|\\]|\\})?\\s+%s\\s*%s\\s*",
+ REX_CARD_COUNT, REX_CARD_NAME, REX_SET_CODE, REX_COLL_NUMBER, REX_FOIL_MTGGOLDFISH);
public static final Pattern CARD_SET_COLLNO_PATTERN = Pattern.compile(REX_FULL_REQUEST_CARD_SET);
// 4. Full-Request (Amount?, Set, CardName, Collector Number|Art Index) - Alternative for flexibility
public static final String REX_FULL_REQUEST_SET_CARD = String.format(
- "^(%s\\s)?\\s*(\\(|\\[|\\{)?%s(\\s+|\\)|\\]|\\}|\\|)\\s*%s\\s+%s$",
- REX_CARD_COUNT, REX_SET_CODE, REX_CARD_NAME, REX_COLL_NUMBER);
+ "^(%s\\s)?\\s*(\\(|\\[|\\{)?%s(\\s+|\\)|\\]|\\}|\\|)\\s*%s\\s+%s\\s*%s$",
+ REX_CARD_COUNT, REX_SET_CODE, REX_CARD_NAME, REX_COLL_NUMBER, REX_FOIL_MTGGOLDFISH);
public static final Pattern SET_CARD_COLLNO_PATTERN = Pattern.compile(REX_FULL_REQUEST_SET_CARD);
- // 5. Card-Only Request (Amount?)
+ // 5. (MTGGoldfish mostly) (Amount?, Card Name, , Set)
+ public static final String REX_FULL_REQUEST_CARD_COLLNO_SET = String.format(
+ "^(%s\\s)?\\s*%s\\s+(\\<%s\\>)\\s*(\\(|\\[|\\{)?%s(\\s+|\\)|\\]|\\}|\\|)\\s*%s$",
+ REX_CARD_COUNT, REX_CARD_NAME, REX_COLL_NUMBER, REX_SET_CODE, REX_FOIL_MTGGOLDFISH);
+ public static final Pattern CARD_COLLNO_SET_PATTERN = Pattern.compile(REX_FULL_REQUEST_CARD_COLLNO_SET);
+
+ // 6. Card-Only Request (Amount?)
public static final String REX_CARDONLY = String.format(
- "(%s\\s)?\\s*%s", REX_CARD_COUNT, REX_CARD_NAME);
+ "(%s\\s)?\\s*%s\\s*%s", REX_CARD_COUNT, REX_CARD_NAME, REX_FOIL_MTGGOLDFISH);
public static final Pattern CARD_ONLY_PATTERN = Pattern.compile(REX_CARDONLY);
@@ -271,6 +275,9 @@ public class DeckRecognizer {
String ccount = getRexGroup(matcher, REGRP_CARDNO);
String setCode = getRexGroup(matcher, REGRP_SET);
String collNo = getRexGroup(matcher, REGRP_COLLNR);
+ String foilGr = getRexGroup(matcher, REGRP_FOIL_GFISH);
+ if (foilGr != null)
+ cr.isFoil = true;
int cardCount = ccount != null ? Integer.parseInt(ccount) : 1;
// if any, it will be tried to convert specific collector number to art index (useful for lands).
String collectorNumber = collNo != null ? collNo : IPaperCard.NO_COLLECTOR_NUMBER;
@@ -298,7 +305,7 @@ public class DeckRecognizer {
PaperCard pc = this.getCardFromSet(cr.cardName, edition, collectorNumber, artIndex, cr.isFoil);
if (pc != null) {
// ok so the card has been found - let's see if there's any restriction on the set
- if (isIllegalSetInGameFormat(setCode) || isIllegalCardInDeckFormat(pc))
+ if (isIllegalSetInGameFormat(edition.getCode()) || isIllegalCardInDeckFormat(pc))
// Mark as illegal card
return Token.IllegalCard(pc.getName(), pc.getEdition(), cardCount);
return Token.KnownCard(pc, cardCount);
@@ -351,7 +358,8 @@ public class DeckRecognizer {
List matchers = new ArrayList<>();
Pattern[] patternsWithCollNumber = new Pattern[] {
CARD_SET_COLLNO_PATTERN,
- SET_CARD_COLLNO_PATTERN
+ SET_CARD_COLLNO_PATTERN,
+ CARD_COLLNO_SET_PATTERN
};
for (Pattern pattern : patternsWithCollNumber) {
Matcher matcher = pattern.matcher(line);
@@ -375,24 +383,26 @@ public class DeckRecognizer {
private PaperCard getCardFromSet(final String cardName, final CardEdition edition,
final String collectorNumber, final int artIndex,
final boolean isFoil) {
+ CardDb targetDb = this.db.contains(cardName) ? this.db : this.altDb;
// Try with collector number first
- PaperCard result = this.db.getCardFromSet(cardName, edition, collectorNumber, isFoil);
- if (result == null)
- result = this.altDb.getCardFromSet(cardName, edition, collectorNumber, isFoil);
- if (result == null && !collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER) &&
- artIndex != IPaperCard.NO_ART_INDEX){
- // So here we know cardName exists (checked before invoking this method)
- // and also a Collector Number was specified.
- // The only case we would reach this point is either due to a wrong edition-card match
- // (later resulting in Unknown card - e.g. "Counterspell|FEM") or due to the fact that
- // art Index was specified instead of collector number! Let's give it a go with that
- // but only if artIndex is not NO_ART_INDEX (e.g. collectorNumber = "*32")
- int maxArtForCard = this.db.contains(cardName) ? this.db.getMaxArtIndex(cardName) :
- this.altDb.getMaxArtIndex(cardName);
- if (artIndex <= maxArtForCard){
- // if collNr was "78", it's hardly an artIndex. It was just the wrong collNr for the requested card
- result = this.db.contains(cardName) ? this.db.getCardFromSet(cardName, edition, artIndex, isFoil) :
- this.altDb.getCardFromSet(cardName, edition, artIndex, isFoil);
+ PaperCard result = targetDb.getCardFromSet(cardName, edition, collectorNumber, isFoil);
+ if (result == null && !collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)) {
+ if (artIndex != IPaperCard.NO_ART_INDEX) {
+ // So here we know cardName exists (checked before invoking this method)
+ // and also a Collector Number was specified.
+ // The only case we would reach this point is either due to a wrong edition-card match
+ // (later resulting in Unknown card - e.g. "Counterspell|FEM") or due to the fact that
+ // art Index was specified instead of collector number! Let's give it a go with that
+ // but only if artIndex is not NO_ART_INDEX (e.g. collectorNumber = "*32")
+ int maxArtForCard = targetDb.getMaxArtIndex(cardName);
+ if (artIndex <= maxArtForCard) {
+ // if collNr was "78", it's hardly an artIndex. It was just the wrong collNr for the requested card
+ result = targetDb.getCardFromSet(cardName, edition, artIndex, isFoil);
+ }
+ }
+ if (result == null){
+ // Last chance, try without collector number and see if any match is found
+ result = targetDb.getCardFromSet(cardName, edition, isFoil);
}
}
return result;
@@ -463,6 +473,8 @@ public class DeckRecognizer {
// NOTE: Card types recognition is ONLY used for style formatting in the Import Editor
// This won't affect the import process of cards in any way !-)
public static boolean isCardType(final String lineAsIs) {
+ if (lineAsIs == null)
+ return false;
String line = lineAsIs.toLowerCase().trim();
Matcher noncardMatcher = NONCARD_PATTERN.matcher(line);
if (!noncardMatcher.matches())
@@ -472,6 +484,8 @@ public class DeckRecognizer {
}
public static boolean isDeckName(final String lineAsIs) {
+ if (lineAsIs == null)
+ return false;
final String line = lineAsIs.trim();
final Matcher deckNameMatcher = DECK_NAME_PATTERN.matcher(line);
boolean matches = deckNameMatcher.matches();
@@ -479,6 +493,8 @@ public class DeckRecognizer {
}
public static String getDeckName(final String text) {
+ if (text == null)
+ return "";
String line = text.trim();
final Matcher deckNamePattern = DECK_NAME_PATTERN.matcher(line);
if (deckNamePattern.matches())
@@ -487,6 +503,8 @@ public class DeckRecognizer {
}
public static boolean isDeckSectionName(final String text) {
+ if (text == null)
+ return false;
String line = text.toLowerCase().trim();
Matcher noncardMatcher = NONCARD_PATTERN.matcher(line);
if (!noncardMatcher.matches())
diff --git a/forge-gui-desktop/src/test/java/forge/deck/DeckRecognizerTest.java b/forge-gui-desktop/src/test/java/forge/deck/DeckRecognizerTest.java
index d163a09528f..c6c6491aeb8 100644
--- a/forge-gui-desktop/src/test/java/forge/deck/DeckRecognizerTest.java
+++ b/forge-gui-desktop/src/test/java/forge/deck/DeckRecognizerTest.java
@@ -125,7 +125,7 @@ public class DeckRecognizerTest extends ForgeCardMockTestCase {
@Test void testMatchDeckName(){
Pattern deckNamePattern = DeckRecognizer.DECK_NAME_PATTERN;
- String matchingDeckName = "Deck Name: Red Green Aggro";
+ String matchingDeckName = "Deck: Red Green Aggro";
Matcher deckNameMatcher = deckNamePattern.matcher(matchingDeckName);
assertTrue(deckNameMatcher.matches());
assertTrue(DeckRecognizer.isDeckName(matchingDeckName));
@@ -161,7 +161,7 @@ public class DeckRecognizerTest extends ForgeCardMockTestCase {
assertEquals(DeckRecognizer.getDeckName(matchingDeckName), "Red Green Aggro");
// Case Insensitive
- matchingDeckName = "deck name: Red Green Aggro";
+ matchingDeckName = "deck: Red Green Aggro";
deckNameMatcher = deckNamePattern.matcher(matchingDeckName);
assertTrue(deckNameMatcher.matches());
assertTrue(DeckRecognizer.isDeckName(matchingDeckName));
@@ -812,6 +812,69 @@ public class DeckRecognizerTest extends ForgeCardMockTestCase {
assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Power Sink+");
}
+ @Test void testMatchFoilCardRequestMTGGoldfishFormat(){
+ // card-set-collnr
+ String foilRequest = "4 Aspect of Hydra [BNG] (F)";
+ Pattern target = DeckRecognizer.CARD_SET_COLLNO_PATTERN;
+ Matcher matcher = target.matcher(foilRequest);
+ assertFalse(matcher.matches());
+
+ foilRequest = "4 Aspect of Hydra [BNG] 117 (F)";
+ target = DeckRecognizer.CARD_SET_COLLNO_PATTERN;
+ matcher = target.matcher(foilRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "4");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Aspect of Hydra "); // TRIM
+ assertEquals(matcher.group(DeckRecognizer.REGRP_SET), "BNG");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_COLLNR), "117");
+ assertNotNull(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH));
+
+ // Set-card-collnr
+ foilRequest = "4 [BNG] Aspect of Hydra (F)";
+ target = DeckRecognizer.SET_CARD_COLLNO_PATTERN;
+ matcher = target.matcher(foilRequest);
+ assertFalse(matcher.matches());
+
+ foilRequest = "4 [BNG] Aspect of Hydra 117 (F)";
+ target = DeckRecognizer.SET_CARD_COLLNO_PATTERN;
+ matcher = target.matcher(foilRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "4");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Aspect of Hydra");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_SET), "BNG");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_COLLNR), "117");
+ assertNotNull(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH));
+
+ // set-card
+ foilRequest = "4 [BNG] Aspect of Hydra (F)";
+ target = DeckRecognizer.SET_CARD_PATTERN;
+ matcher = target.matcher(foilRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "4");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Aspect of Hydra "); // TRIM
+ assertEquals(matcher.group(DeckRecognizer.REGRP_SET), "BNG");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH), "(F)");
+
+ // card-set
+ foilRequest = "4 Aspect of Hydra [BNG] (F)";
+ target = DeckRecognizer.CARD_SET_PATTERN;
+ matcher = target.matcher(foilRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "4");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Aspect of Hydra "); // TRIM
+ assertEquals(matcher.group(DeckRecognizer.REGRP_SET), "BNG");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH), "(F)");
+
+ // card-only
+ foilRequest = "4 Aspect of Hydra (F)";
+ target = DeckRecognizer.CARD_ONLY_PATTERN;
+ matcher = target.matcher(foilRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "4");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Aspect of Hydra "); // TRIM
+ assertEquals(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH), "(F)");
+ }
+
@Test void testRecogniseCardToken(){
StaticData magicDb = FModel.getMagicDb();
CardDb db = magicDb.getCommonCards();
@@ -1015,17 +1078,30 @@ public class DeckRecognizerTest extends ForgeCardMockTestCase {
assertEquals(tokenCard.getCollectorNumber(), "3");
}
- @Test void testRequestingCardWithWrongCollectorNumberReturnsUnknownCard(){
+ @Test void testCardRequestWithWrongCollectorNumberStillReturnsTheCardFromSetIfAny(){
StaticData magicDb = FModel.getMagicDb();
CardDb db = magicDb.getCommonCards();
CardDb altDb = magicDb.getVariantCards();
DeckRecognizer recognizer = new DeckRecognizer(db, altDb);
- String lineRequest = "2x Power Sink MIR 3";
- Token cardToken = recognizer.recogniseCardToken(lineRequest);
+ String requestLine = "3 Jayemdae Tome (LEB) 231"; // actually found in TappedOut Deck Export
+ // NOTE: Expected Coll Nr should be 255
+ Token cardToken = recognizer.recogniseCardToken(requestLine);
+ assertNotNull(cardToken);
+ assertNotNull(cardToken.getCard());
+ assertEquals(cardToken.getNumber(), 3);
+ PaperCard card = cardToken.getCard();
+ assertEquals(card.getName(), "Jayemdae Tome");
+ assertEquals(card.getEdition(), "LEB");
+ assertEquals(card.getCollectorNumber(), "255");
+
+ // No Match - Unknown card
+ requestLine = "3 Jayemdae Tome (TMP)"; // actually found in TappedOut Deck Export
+ // NOTE: Expected Coll Nr should be 255
+ cardToken = recognizer.recogniseCardToken(requestLine);
assertNotNull(cardToken);
- assertEquals(cardToken.getType(), TokenType.UNKNOWN_CARD_REQUEST);
assertNull(cardToken.getCard());
+ assertEquals(cardToken.getType(), TokenType.UNKNOWN_CARD_REQUEST);
}
@Test void testRequestingCardFromTheWrongSetReturnsUnknownCard(){
@@ -1157,4 +1233,83 @@ public class DeckRecognizerTest extends ForgeCardMockTestCase {
assertEquals(cardToken.getType(), TokenType.INVALID_CARD_REQUEST);
assertNull(cardToken.getCard());
}
+
+ @Test void testFoilRequestInMTGGoldfishExportFormat(){
+ String mtgGoldfishRequest = "18 Forest <254> [THB]";
+ Pattern target = DeckRecognizer.CARD_COLLNO_SET_PATTERN;
+ Matcher matcher = target.matcher(mtgGoldfishRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "18");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Forest"); // TRIM
+ assertEquals(matcher.group(DeckRecognizer.REGRP_SET), "THB");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_COLLNR), "254");
+ assertNull(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH));
+
+ mtgGoldfishRequest = "18 Forest <254> [THB] (F)";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertTrue(matcher.matches());
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARDNO), "18");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_CARD), "Forest"); // TRIM
+ assertEquals(matcher.group(DeckRecognizer.REGRP_SET), "THB");
+ assertEquals(matcher.group(DeckRecognizer.REGRP_COLLNR), "254");
+ assertNotNull(matcher.group(DeckRecognizer.REGRP_FOIL_GFISH));
+
+ mtgGoldfishRequest = "18 Forest [THB]";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+
+ mtgGoldfishRequest = "18 [THB] Forest";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+
+ mtgGoldfishRequest = "18 Forest [THB] (F)";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+
+ mtgGoldfishRequest = "18 [THB] Forest (F)";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+
+ mtgGoldfishRequest = "18 Forest 254 [THB] (F)";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+
+ mtgGoldfishRequest = "18 Forest 254 [THB]";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+
+ mtgGoldfishRequest = "18 [THB] Forest 254";
+ matcher = target.matcher(mtgGoldfishRequest);
+ assertFalse(matcher.matches());
+ }
+
+ @Test void testCardRecognisedMTGGoldfishFormat(){
+ StaticData magicDb = FModel.getMagicDb();
+ CardDb db = magicDb.getCommonCards();
+ CardDb altDb = magicDb.getVariantCards();
+ DeckRecognizer recognizer = new DeckRecognizer(db, altDb);
+ assertEquals(db.getCardArtPreference(), CardDb.CardArtPreference.LATEST_ART_ALL_EDITIONS);
+
+ String lineRequest = "4 Aspect of Hydra [BNG] (F)";
+ Token cardToken = recognizer.recogniseCardToken(lineRequest);
+ assertNotNull(cardToken);
+ assertEquals(cardToken.getType(), TokenType.LEGAL_CARD_REQUEST);
+ assertNotNull(cardToken.getCard());
+ PaperCard aspectOfHydraCard = cardToken.getCard();
+ assertEquals(cardToken.getNumber(), 4);
+ assertEquals(aspectOfHydraCard.getName(), "Aspect of Hydra");
+ assertEquals(aspectOfHydraCard.getEdition(), "BNG");
+ assertTrue(aspectOfHydraCard.isFoil());
+
+ lineRequest = "18 Forest <254> [THB] (F)";
+ cardToken = recognizer.recogniseCardToken(lineRequest);
+ assertNotNull(cardToken);
+ assertEquals(cardToken.getType(), TokenType.LEGAL_CARD_REQUEST);
+ assertNotNull(cardToken.getCard());
+ PaperCard forestCard = cardToken.getCard();
+ assertEquals(cardToken.getNumber(), 18);
+ assertEquals(forestCard.getName(), "Forest");
+ assertEquals(forestCard.getEdition(), "THB");
+ assertTrue(forestCard.isFoil());
+ }
}