diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index d26452fb59..62ceb0979d 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -71,6 +71,7 @@ public class VerifyCardDataTest { private static final String SKIP_LIST_DOUBLE_RARE = "DOUBLE_RARE"; private static final String SKIP_LIST_UNSUPPORTED_SETS = "UNSUPPORTED_SETS"; private static final String SKIP_LIST_SCRYFALL_DOWNLOAD_SETS = "SCRYFALL_DOWNLOAD_SETS"; + private static final String SKIP_LIST_SAMPLE_DECKS = "SAMPLE_DECKS"; private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")"); static { @@ -190,6 +191,10 @@ public class VerifyCardDataTest { // scryfall download sets (missing from scryfall website) skipListCreate(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS); skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "SWS"); // Star Wars + + // sample decks checking - some decks can contains unimplemented cards, so ignore it + skipListCreate(SKIP_LIST_SAMPLE_DECKS); + skipListAddName(SKIP_LIST_SAMPLE_DECKS, "\\Commander\\Commander 2019\\Merciless Rage.dck"); // TODO: delete after Aeon Engine implemented } private final ArrayList outputMessages = new ArrayList<>(); @@ -472,7 +477,6 @@ public class VerifyCardDataTest { } @Test - //@Ignore // TODO: enable and fix broken decks after promo sets merge https://github.com/magefree/mage/pull/6190 public void test_checkSampleDecks() { Collection errorsList = new ArrayList<>(); @@ -496,7 +500,11 @@ public class VerifyCardDataTest { // try to open deck files int totalErrorFiles = 0; for (Path deckFile : filesList) { - String deckName = deckFile.toString().replace(rootPath, ""); + String deckName = "\\" + deckFile.toString().replace(rootPath, ""); + if (skipListHaveName(SKIP_LIST_SAMPLE_DECKS, deckName)) { + continue; + } + StringBuilder deckErrors = new StringBuilder(); DeckCardLists deckCards = DeckImporter.importDeckFromFile(deckFile.toString(), deckErrors, AUTO_FIX_SAMPLE_DECKS); @@ -508,7 +516,7 @@ public class VerifyCardDataTest { } if ((deckCards.getCards().size() + deckCards.getSideboard().size()) < 10) { - errorsList.add("Error: sample deck contains too little cards " + deckName); + errorsList.add("Error: sample deck contains too little cards (" + deckCards.getSideboard().size() + ") " + deckName); totalErrorFiles++; continue; } diff --git a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java index e5ed8a29f2..834aaf0ef8 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java @@ -7,7 +7,7 @@ import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -28,7 +28,9 @@ public class DckDeckImporter extends PlainTextDeckImporter { private static final Pattern layoutStackEntryPattern = Pattern.compile("\\[(\\w+[^:]*\\w*):(\\w+\\w*)]"); // test cases: [JR:64ab],[JR:64],[MPSAK1321:43],[MPSAKH:9],[MPS123-AKH:32],[MPS-13AKH:30],[MPS-AKH:49],[MPS-AKH:11], [PUMA:U16] - private final Map possibleFixes = new HashMap<>(); // possible fixes for card codes and numbers [code:123] -> [code:456] + // possible fixes for card numbers: [code:123] -> [code:456] + // possible fixes for card numbers with name: [code:123] card1 -> [code:456] card2 + private final Map possibleFixes = new LinkedHashMap<>(); @Override protected void readLine(String line, DeckCardLists deckList, FixedInfo fixedInfo) { @@ -60,13 +62,14 @@ public class DckDeckImporter extends PlainTextDeckImporter { setCode = setCode == null ? "" : setCode.trim(); cardName = cardName == null ? "" : cardName.trim(); - // text for auto-fix - String originalText = ""; + // text for auto-fix (don't work on extra spaces between numbers and name -- it's ok) + String originalNumbers = ""; + String originalNumbersWithName = ""; if (!setCode.isEmpty() && !cardNum.isEmpty()) { - // [ISD:144] - originalText = "[" + setCode + ":" + cardNum + "]"; + // [ISD:144] card_name + originalNumbers = "[" + setCode + ":" + cardNum + "]"; + originalNumbersWithName = originalNumbers + " " + cardName; } - String fixedText = originalText; // search priority: set/number -> name // with bulletproof on card number or name changes @@ -74,7 +77,7 @@ public class DckDeckImporter extends PlainTextDeckImporter { DeckCardInfo deckCardInfo = null; // search by set/number - CardInfo foundedCard = CardRepository.instance.findCard(setCode, cardNum); + CardInfo foundedCard = CardRepository.instance.findCard(setCode, cardNum, true); boolean wasOutdated = false; if ((foundedCard != null) && !foundedCard.getName().equals(cardName)) { sbMessage.append("Line ").append(lineCount).append(": ").append("found outdated card number or name, will try to replace: ").append(line).append('\n'); @@ -93,15 +96,24 @@ public class DckDeckImporter extends PlainTextDeckImporter { } if (foundedCard != null) { - sbMessage.append("Line ").append(lineCount).append(": ") - .append("replaced to [").append(foundedCard.getSetCode()).append(":").append(foundedCard.getCardNumberAsInt()).append("] ") - .append(foundedCard.getName()).append('\n'); + if (foundedCard.isNightCard()) { + sbMessage.append("Line ").append(lineCount).append(": ").append("ERROR, you can't use night card in deck [").append(foundedCard.getName()).append("]").append('\n'); + } else { + sbMessage.append("Line ").append(lineCount).append(": ") + .append("replaced to [").append(foundedCard.getSetCode()).append(":").append(foundedCard.getCardNumberAsInt()).append("] ") + .append(foundedCard.getName()).append('\n'); - // AUTO-FIX POSSIBLE (apply and save it for another lines like layout) - // [ISD:144] - fixedText = "[" + foundedCard.getSetCode() + ":" + foundedCard.getCardNumber() + "]"; - fixedInfo.setFixedLine(fixedInfo.getOriginalLine().replace(originalText, fixedText)); - this.possibleFixes.put(originalText, fixedText); + // AUTO-FIX POSSIBLE (apply and save it for another lines like layout) + // [ISD:144] card + String fixNumbers = "[" + foundedCard.getSetCode() + ":" + foundedCard.getCardNumber() + "]"; + String fixNumbersWithName = fixNumbers + " " + foundedCard.getName(); + this.possibleFixes.put(originalNumbersWithName, fixNumbersWithName); // name fix must goes first + this.possibleFixes.put(originalNumbers, fixNumbers); + String fixedLine = fixedInfo.getOriginalLine() + .replace(originalNumbersWithName, fixNumbersWithName) + .replace(originalNumbers, fixNumbers); + fixedInfo.setFixedLine(fixedLine); + } } else { sbMessage.append("Line ").append(lineCount).append(": ").append("ERROR, can't find card [").append(cardName).append("]").append('\n'); } diff --git a/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java index 748e1970f1..c6b9600d17 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java @@ -58,6 +58,10 @@ public abstract class PlainTextDeckImporter extends DeckImporter { saveFixedDeckFile(fixedFile, f); } + if (deckList.getCards().isEmpty() && deckList.getSideboard().isEmpty()) { + sbMessage.append("ERROR, unknown deck format, can't find any cards").append("\n"); + } + if (sbMessage.length() > 0) { if (errorMessages != null) { // normal output for user diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 96fe7d248b..f92a1b20e8 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -39,7 +39,7 @@ public enum CardRepository { private static final long CARD_CONTENT_VERSION = 231; private Dao cardDao; private Set classNames; - private RepositoryEventSource eventSource = new RepositoryEventSource(); + private final RepositoryEventSource eventSource = new RepositoryEventSource(); CardRepository() { File file = new File("db"); @@ -335,11 +335,22 @@ public enum CardRepository { } public CardInfo findCard(String setCode, String cardNumber) { + return findCard(setCode, cardNumber, true); + } + + public CardInfo findCard(String setCode, String cardNumber, boolean ignoreNightCards) { try { QueryBuilder queryBuilder = cardDao.queryBuilder(); - queryBuilder.limit(1L).where().eq("setCode", new SelectArg(setCode)) - .and().eq("cardNumber", new SelectArg(cardNumber)) - .and().eq("nightCard", new SelectArg(false)); + if (ignoreNightCards) { + queryBuilder.limit(1L).where() + .eq("setCode", new SelectArg(setCode)) + .and().eq("cardNumber", new SelectArg(cardNumber)) + .and().eq("nightCard", new SelectArg(false)); + } else { + queryBuilder.limit(1L).where() + .eq("setCode", new SelectArg(setCode)) + .and().eq("cardNumber", new SelectArg(cardNumber)); + } List result = cardDao.query(queryBuilder.prepare()); if (!result.isEmpty()) { return result.get(0);