diff --git a/common/decklist.cpp b/common/decklist.cpp index 0993d71f..be96cfa2 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -2,8 +2,17 @@ #include #include #include +#include #include +#if QT_VERSION < 0x050600 +// qHash on QRegularExpression was added in 5.6, FIX IT +uint qHash(const QRegularExpression &key, uint seed) noexcept +{ + return qHash(key.pattern(), seed); // call qHash on pattern QString instead +} +#endif + SideboardPlan::SideboardPlan(const QString &_name, const QList &_moveList) : name(_name), moveList(_moveList) { @@ -477,161 +486,131 @@ bool DeckList::saveToFile_Native(QIODevice *device) bool DeckList::loadFromStream_Plain(QTextStream &in) { + const QRegularExpression reCardLine("^\\s*[\\w\\[\\(\\{].*$", QRegularExpression::UseUnicodePropertiesOption); + const QRegularExpression reEmpty("^\\s*$"); + const QRegularExpression reComment("[\\w\\[\\(\\{].*$", QRegularExpression::UseUnicodePropertiesOption); + const QRegularExpression reSBMark("^\\s*sb:\\s*(.+)", QRegularExpression::CaseInsensitiveOption); + const QRegularExpression reSBComment("sideboard", QRegularExpression::CaseInsensitiveOption); + + // simplified matches + const QRegularExpression reMultiplier("^[xX\\(\\[]*(\\d+)[xX\\*\\)\\]]* ?(.+)"); + const QRegularExpression reBrace(" ?[\\[\\{][^\\]\\}]*[\\]\\}] ?"); // not nested + const QRegularExpression reRoundBrace("^\\([^\\)]*\\) ?"); // () are only matched at start of string + const QRegularExpression reDigitBrace(" ?\\(\\d*\\) ?"); // () are matched if containing digits + const QHash differences{{QRegularExpression("’"), QString("'")}, + {QRegularExpression("Æ"), QString("Ae")}, + {QRegularExpression("æ"), QString("ae")}, + {QRegularExpression(" ?[|/]+ ?"), QString(" // ")}, + {QRegularExpression("(? inputs; // QTextStream -> QVector - bool priorEntryIsBlank = true, isAtBeginning = true; - int blankLines = 0; - while (!in.atEnd()) { - QString line = in.readLine().simplified().toLower(); + QStringList inputs = in.readAll().trimmed().split('\n'); + int max_line = inputs.size(); - /* - * Removes all blank lines at start of inputs - * Ex: ("", "", "", "Card1", "Card2") => ("Card1", "Card2") - * - * This will also concise multiple blank lines in a row to just one blank - * Ex: ("Card1", "Card2", "", "", "", "Card3") => ("Card1", "Card2", "", "Card3") - */ - if (line.isEmpty()) { - if (priorEntryIsBlank || isAtBeginning) { - continue; - } - - priorEntryIsBlank = true; - blankLines++; - } else { - isAtBeginning = false; - priorEntryIsBlank = false; + // start at the first empty line before the first cardline + int deckStart = inputs.indexOf(reCardLine); + if (deckStart == -1) { // there are no cards? + if (inputs.indexOf(reComment) == -1) + return false; // input is empty + deckStart = max_line; + } else { + deckStart = inputs.lastIndexOf(reEmpty, deckStart); + if (deckStart == -1) { + deckStart = 0; } - - inputs.push_back(line); } - /* - * Removes blank line at end of inputs (if applicable) - * Ex: ("Card1", "Card2", "") => ("Card1", "Card2") - * NOTE: Any duplicates were taken care of above, so there can be - * at most one blank line at the very end - */ - if (!inputs.empty() && inputs.last().isEmpty()) { - blankLines--; - inputs.erase(inputs.end() - 1); - } - - // If "Sideboard" line appears in inputs, then blank lines mean nothing - if (inputs.contains("sideboard")) { - blankLines = 2; - } - - bool inSideboard = false, titleFound = false, isSideboard; - int okRows = 0; - - foreach (QString line, inputs) { - // This is a comment line, ignore it - if (line.startsWith("//")) { - if (!titleFound) // Set the title to the first comment - { - name = line.mid(2).trimmed(); - titleFound = true; - } else if (okRows == 0) // We haven't processed any cards yet - { - comments += line.mid(2).trimmed() + "\n"; + // find sideboard position, if marks are used this won't be needed + int sBStart = -1; + if (inputs.indexOf(reSBMark, deckStart) == -1) { + sBStart = inputs.indexOf(reSBComment, deckStart); + if (sBStart == -1) { + sBStart = inputs.indexOf(reEmpty, deckStart + 1); + if (sBStart == -1) { + sBStart = max_line; } + int nextCard = inputs.indexOf(reCardLine, sBStart + 1); + if (inputs.indexOf(reEmpty, nextCard + 1) != -1) { + sBStart = max_line; // if there is another empty line all cards are mainboard + } + } + } + int index = 0; + QRegularExpressionMatch match; + + // parse name and comments + while (index < deckStart) { + const QString current = inputs.at(index++); + if (!current.contains(reEmpty)) { + match = reComment.match(current); + name = match.captured(); + break; + } + } + while (index < deckStart) { + const QString current = inputs.at(index++); + if (!current.contains(reEmpty)) { + match = reComment.match(current); + comments += match.captured() + '\n'; + } + } + comments.chop(1); // remove last newline + + // parse decklist + for (; index < max_line; ++index) { + + // check if line is a card + match = reCardLine.match(inputs.at(index)); + if (!match.hasMatch()) continue; - } + QString cardName = match.captured().simplified(); - // If we have a blank line and it's the _ONLY_ blank line in the paste - // and it follows at least one valid card - // Then we assume it means to start the sideboard section of the paste. - // If we have the word "Sideboard" appear on any line, then that will - // also indicate the start of the sideboard. - if ((line.isEmpty() && blankLines == 1 && okRows > 0) || line.startsWith("sideboard")) { - inSideboard = true; - continue; // The line isn't actually a card - } - - isSideboard = inSideboard; - - if (line.startsWith("sb:")) { - line = line.mid(3).trimmed(); - isSideboard = true; - } - - if (line.trimmed().isEmpty()) { - continue; // The line was " " instead of "\n" - } - - // Filter out MWS edition symbols and basic land extras - QRegExp rx("\\[.*\\]\\s?"); - line.remove(rx); - rx.setPattern("\\s?\\(.*\\)"); - line.remove(rx); - - // Filter out post card name editions - rx.setPattern("\\|.*$"); - line.remove(rx); - - // If the user inputs "Quicksilver Elemental" then it will cut it off - // 1x Squishy Treaker - int i = line.indexOf(' '); - int cardNameStart = i + 1; - - if (i > 0) { - // If the count ends with an 'x', ignore it. For example, - // "4x Storm Crow" will count 4 correctly. - if (line.at(i - 1) == 'x') { - i--; - } else if (!line.at(i - 1).isDigit()) { - // If the user inputs "Quicksilver Elemental" then it will work as 1x of that card - cardNameStart = 0; + // check if card should be sideboard + bool sideboard = false; + if (sBStart < 0) { + match = reSBMark.match(cardName); + if (match.hasMatch()) { + sideboard = true; + cardName = match.captured(1); } + } else { + if (index == sBStart) // skip sideboard line itself + continue; + sideboard = index > sBStart; } - bool ok; - int number = line.left(i).toInt(&ok); - - if (!ok) { - number = 1; // If input is "cardName" assume it's "1x cardName" + // check if a specific amount is mentioned + int amount = 1; + match = reMultiplier.match(cardName); + if (match.hasMatch()) { + amount = match.capturedRef(1).toInt(); + cardName = match.captured(2); } - QString cardName = line.mid(cardNameStart); + // remove stuff inbetween braces + cardName.remove(reBrace); + cardName.remove(reRoundBrace); // I'll be entirely honest here, these are split to accommodate just three cards + cardName.remove(reDigitBrace); // all cards from un-sets that have a word in between round braces at the end - // Common differences between Cockatrice's card names - // and what's commonly used in decklists - rx.setPattern("’"); - cardName.replace(rx, "'"); - rx.setPattern("Æ"); - cardName.replace(rx, "Ae"); - rx.setPattern("\\s*[|/]{1,2}\\s*"); - cardName.replace(rx, " // "); - - // Replace only if the ampersand is preceded by a non-capital letter, - // as would happen with acronyms. So 'Fire & Ice' is replaced but not - // 'R&D' or 'R & D'. - // Qt regexes don't support lookbehind so we capture and replace instead. - rx.setPattern("([^A-Z])\\s*&\\s*"); - if (rx.indexIn(cardName) != -1) { - cardName.replace(rx, QString("%1 // ").arg(rx.cap(1))); + // replace common differences in cardnames + for (auto diff = differences.constBegin(); diff != differences.constEnd(); ++diff) { + cardName.replace(diff.key(), diff.value()); } - // We need to get the name of the card from the database, - // but we can't do that until we get the "real" name - // (name stored in database for the card) - // and establish a card info that is of the card, then it's - // a simple getting the _real_ name of the card - // (i.e. "STOrm, CrOW" => "Storm Crow") + // get cardname, this function does nothing if the name is not found cardName = getCompleteCardName(cardName); - // Look for the correct card zone of where to place the new card - QString zoneName = getCardZoneFromName(cardName, isSideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN); + // get zone name based on if it's in sideboard + QString zoneName = getCardZoneFromName(cardName, sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN); - okRows++; - new DecklistCardNode(cardName, number, getZoneObjFromName(zoneName)); + // make new entry in decklist + new DecklistCardNode(cardName, amount, getZoneObjFromName(zoneName)); } updateDeckHash(); - return (okRows > 0); + return true; } InnerDecklistNode *DeckList::getZoneObjFromName(const QString zoneName) diff --git a/tests/loading_from_clipboard/CMakeLists.txt b/tests/loading_from_clipboard/CMakeLists.txt index bdb36e49..ddd49756 100644 --- a/tests/loading_from_clipboard/CMakeLists.txt +++ b/tests/loading_from_clipboard/CMakeLists.txt @@ -1,6 +1,7 @@ ADD_DEFINITIONS("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"") add_executable(loading_from_clipboard_test loading_from_clipboard_test.cpp + clipboard_testing.cpp ../../common/decklist.cpp ) @@ -12,4 +13,4 @@ find_package(Qt5 COMPONENTS Concurrent Network Widgets REQUIRED) set(TEST_QT_MODULES Qt5::Concurrent Qt5::Network Qt5::Widgets) target_link_libraries(loading_from_clipboard_test cockatrice_common ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) -add_test(NAME loading_from_clipboard_test COMMAND loading_from_clipboard_test) \ No newline at end of file +add_test(NAME loading_from_clipboard_test COMMAND loading_from_clipboard_test) diff --git a/tests/loading_from_clipboard/clipboard_testing.cpp b/tests/loading_from_clipboard/clipboard_testing.cpp new file mode 100644 index 00000000..5b6be593 --- /dev/null +++ b/tests/loading_from_clipboard/clipboard_testing.cpp @@ -0,0 +1,40 @@ +#include "clipboard_testing.h" +#include + +void Result::operator()(const InnerDecklistNode *innerDecklistNode, const DecklistCardNode *card) +{ + if (innerDecklistNode->getName() == DECK_ZONE_MAIN) { + mainboard.append({card->getName().toStdString(), card->getNumber()}); + } else if (innerDecklistNode->getName() == DECK_ZONE_SIDE) { + sideboard.append({card->getName().toStdString(), card->getNumber()}); + } else { + FAIL(); + } +} + +void testEmpty(const QString &clipboard) +{ + QString cp(clipboard); + DeckList deckList; + QTextStream stream(&cp); // text stream requires local copy + deckList.loadFromStream_Plain(stream); + + ASSERT_TRUE(deckList.getCardList().isEmpty()); +} + +void testDeck(const QString &clipboard, const Result &result) +{ + QString cp(clipboard); + DeckList deckList; + QTextStream stream(&cp); // text stream requires local copy + deckList.loadFromStream_Plain(stream); + + ASSERT_EQ(result.name, deckList.getName().toStdString()); + ASSERT_EQ(result.comments, deckList.getComments().toStdString()); + + Result decklistBuilder; + deckList.forEachCard(decklistBuilder); + + ASSERT_EQ(result.mainboard, decklistBuilder.mainboard); + ASSERT_EQ(result.sideboard, decklistBuilder.sideboard); +} diff --git a/tests/loading_from_clipboard/clipboard_testing.h b/tests/loading_from_clipboard/clipboard_testing.h new file mode 100644 index 00000000..03bdf5e9 --- /dev/null +++ b/tests/loading_from_clipboard/clipboard_testing.h @@ -0,0 +1,32 @@ +#ifndef CLIPBOARD_TESTING_H +#define CLIPBOARD_TESTING_H + +#include "../../common/decklist.h" +#include "gtest/gtest.h" + +struct Result +{ + // using std types because qt types aren't understood by gtest (without this you'll get less nice errors) + using CardRows = QVector>; + std::string name; + std::string comments; + CardRows mainboard; + CardRows sideboard; + + Result() + { + } + + Result(std::string _name, std::string _comments, CardRows _mainboard, CardRows _sideboard) + : name(_name), comments(_comments), mainboard(_mainboard), sideboard(_sideboard) + { + } + + void operator()(const InnerDecklistNode *innerDecklistNode, const DecklistCardNode *card); +}; + +void testEmpty(const QString &clipboard); + +void testDeck(const QString &clipboard, const Result &result); + +#endif // CLIPBOARD_TESTING_H diff --git a/tests/loading_from_clipboard/loading_from_clipboard_test.cpp b/tests/loading_from_clipboard/loading_from_clipboard_test.cpp index f21f610a..11b7a7f8 100644 --- a/tests/loading_from_clipboard/loading_from_clipboard_test.cpp +++ b/tests/loading_from_clipboard/loading_from_clipboard_test.cpp @@ -1,249 +1,169 @@ -#include "loading_from_clipboard_test.h" -#include "../../common/decklist.h" -#include "gtest/gtest.h" -#include +#include "clipboard_testing.h" -DeckList *fromClipboard(QString *clipboard); -DeckList *fromClipboard(QString *clipboard) -{ - DeckList *deckList = new DeckList; - QTextStream *stream = new QTextStream(clipboard); - deckList->loadFromStream_Plain(*stream); - return deckList; -} +// Testing is done by using the DeckList::loadFromString_Plain function in common/decklist.h +// It does not check if cards are in the database at all, so no comparisons to the database will be made. -using CardRows = QMap; - -struct DecklistBuilder -{ - CardRows actualMainboard; - CardRows actualSideboard; - - explicit DecklistBuilder() : actualMainboard({}), actualSideboard({}) - { - } - - void operator()(const InnerDecklistNode *innerDecklistNode, const DecklistCardNode *card) - { - if (innerDecklistNode->getName() == DECK_ZONE_MAIN) { - actualMainboard[card->getName()] += card->getNumber(); - } else if (innerDecklistNode->getName() == DECK_ZONE_SIDE) { - actualSideboard[card->getName()] += card->getNumber(); - } else { - FAIL(); - } - } - - CardRows mainboard() - { - return actualMainboard; - } - - CardRows sideboard() - { - return actualSideboard; - } -}; - -namespace -{ TEST(LoadingFromClipboardTest, EmptyDeck) { - DeckList *deckList = fromClipboard(new QString("")); - ASSERT_TRUE(deckList->getCardList().isEmpty()); + testEmpty(""); } TEST(LoadingFromClipboardTest, EmptySideboard) { - DeckList *deckList = fromClipboard(new QString("Sideboard")); - ASSERT_TRUE(deckList->getCardList().isEmpty()); + testEmpty("Sideboard"); } TEST(LoadingFromClipboardTest, QuantityPrefixed) { - QString *clipboard = new QString("1 Mountain\n" - "2x Island\n" - "3X FOREST\n"); - DeckList *deckList = fromClipboard(clipboard); - - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = CardRows({{"mountain", 1}, {"island", 2}, {"forest", 3}}); - CardRows expectedSideboard = CardRows({}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + QString clipboard("1 Mountain\n" + "2x Island\n" + "3x Forest\n"); + Result result("", "", {{"Mountain", 1}, {"Island", 2}, {"Forest", 3}}, {}); + testDeck(clipboard, result); } TEST(LoadingFromClipboardTest, CommentsAreIgnored) { - QString *clipboard = new QString("//1 Mountain\n" - "//2x Island\n" - "//SB:2x Island\n"); - - DeckList *deckList = fromClipboard(clipboard); - - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = CardRows({}); - CardRows expectedSideboard = CardRows({}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + QString clipboard("//1 Mountain\n" + "//2x Island\n" + "//SB:2x Island\n"); + testEmpty(clipboard); } TEST(LoadingFromClipboardTest, SideboardPrefix) { - QString *clipboard = new QString("1 Mountain\n" - "SB: 1 Mountain\n" - "SB: 2x Island\n"); - DeckList *deckList = fromClipboard(clipboard); + QString clipboard("1 Mountain\n" + "SB: 1 Mountain\n" + "sb: 2x Island\n" + "2 Swamp\n" + "\n" + "3 Plains\n"); + Result result("", "", {{"Mountain", 1}, {"Swamp", 2}, {"Plains", 3}}, {{"Mountain", 1}, {"Island", 2}}); + testDeck(clipboard, result); +} - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = CardRows({{"mountain", 1}}); - CardRows expectedSideboard = CardRows({{"mountain", 1}, {"island", 2}}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); +TEST(LoadingFromClipboardTest, SideboardLine) +{ + QString clipboard("1 Mountain\n" + "2 Swamp\n" + "\n" + "3 Plains\n" + "sideboard\n" + "1 Mountain\n" + "2x Island\n"); + Result result("", "", {{"Mountain", 1}, {"Swamp", 2}, {"Plains", 3}}, {{"Mountain", 1}, {"Island", 2}}); + testDeck(clipboard, result); } TEST(LoadingFromClipboardTest, UnknownCardsAreNotDiscarded) { - QString *clipboard = new QString("1 CardThatDoesNotExistInCardsXml\n"); - DeckList *deckList = fromClipboard(clipboard); + QString clipboard("1 CardThatDoesNotExistInCardsXml\n"); + Result result("", "", {{"CardThatDoesNotExistInCardsXml", 1}}, {}); + testDeck(clipboard, result); +} - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = CardRows({{"cardthatdoesnotexistincardsxml", 1}}); - CardRows expectedSideboard = CardRows({}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); +TEST(LoadingFromClipboardTest, WeirdWhitespaceIsIgnored) +{ + QString clipboard( + "\t\tSb:\t1\tOur Market Research Shows That Players Like Really Long Card Names So We Made " + " This Card to Have\tthe Absolute \t Longest Card Name \tEver Elemental\t\n\t"); + Result result("", "", {}, + {{"Our Market Research Shows That Players Like Really Long Card Names So We Made This Card to Have " + "the Absolute Longest Card Name Ever Elemental", + 1}}); + testDeck(clipboard, result); } TEST(LoadingFromClipboardTest, RemoveBlankEntriesFromBeginningAndEnd) { - QString *clipboard = new QString("\n" - "\n" - "\n" - "1x Algae Gharial\n" - "3x CardThatDoesNotExistInCardsXml\n" - "2x Phelddagrif\n" - "\n" - "\n"); + QString clipboard("\n" + "\n" + "\n" + "1x Algae Gharial\n" + "3x CardThatDoesNotExistInCardsXml\n" + "2x Phelddagrif\n" + "\n" + "\n"); - DeckList *deckList = fromClipboard(clipboard); - - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = - CardRows({{"algae gharial", 1}, {"cardthatdoesnotexistincardsxml", 3}, {"phelddagrif", 2}}); - CardRows expectedSideboard = CardRows({}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + Result result("", "", {{"Algae Gharial", 1}, {"CardThatDoesNotExistInCardsXml", 3}, {"Phelddagrif", 2}}, {}); + testDeck(clipboard, result); } TEST(LoadingFromClipboardTest, UseFirstBlankIfOnlyOneBlankToSplitSideboard) { - QString *clipboard = new QString("1x Algae Gharial\n" - "3x CardThatDoesNotExistInCardsXml\n" - "\n" - "2x Phelddagrif\n"); + QString clipboard("1x Algae Gharial\n" + "3x CardThatDoesNotExistInCardsXml\n" + "\n" + "2x Phelddagrif\n"); - DeckList *deckList = fromClipboard(clipboard); - - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = CardRows({{"algae gharial", 1}, {"cardthatdoesnotexistincardsxml", 3}}); - CardRows expectedSideboard = CardRows({{"phelddagrif", 2}}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + Result result("", "", {{"Algae Gharial", 1}, {"CardThatDoesNotExistInCardsXml", 3}}, {{"Phelddagrif", 2}}); + testDeck(clipboard, result); } TEST(LoadingFromClipboardTest, IfMultipleScatteredBlanksAllMainBoard) { - QString *clipboard = new QString("1x Algae Gharial\n" - "3x CardThatDoesNotExistInCardsXml\n" - "\n" - "2x Phelddagrif\n" - "\n" - "3 Giant Growth\n"); + QString clipboard("1x Algae Gharial\n" + "3x CardThatDoesNotExistInCardsXml\n" + "\n" + "2x Phelddagrif\n" + "\n" + "3 Giant Growth\n"); - DeckList *deckList = fromClipboard(clipboard); - - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); - - CardRows expectedMainboard = CardRows( - {{"algae gharial", 1}, {"cardthatdoesnotexistincardsxml", 3}, {"phelddagrif", 2}, {"giant growth", 3}}); - CardRows expectedSideboard = CardRows({}); - - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + Result result( + "", "", {{"Algae Gharial", 1}, {"CardThatDoesNotExistInCardsXml", 3}, {"Phelddagrif", 2}, {"Giant Growth", 3}}, + {}); + testDeck(clipboard, result); } -TEST(LoadingFromClipboardTest, LotsOfStuffInBulkTesting) +TEST(LoadingFromClipboardTest, EdgeCaseTesting) { - QString *clipboard = new QString("\n" - "\n" - "\n" - "1x test1\n" - "testNoValueMB\n" - "2x test2\n" - "SB: 10 testSB\n" - "3 test3\n" - "4X test4\n" - "\n" - "\n" - "\n" - "\n" - "5x test5\n" - "6X test6\n" - "testNoValueSB\n" - "\n" - "\n" - "\n" - "\n"); + QString clipboard(R"( +// DeckName - DeckList *deckList = fromClipboard(clipboard); + // Comment 1 - DecklistBuilder decklistBuilder = DecklistBuilder(); - deckList->forEachCard(decklistBuilder); +// +//Comment [two] +//(test) Æ ’ | / (3) - CardRows expectedMainboard = CardRows({{"test1", 1}, {"test2", 2}, {"test3", 3}, {"test4", 4}, {"testnovaluemb", 1} - }); - CardRows expectedSideboard = CardRows({{"testsb", 10}, {"test5", 5}, {"test6", 6}, {"testnovaluesb", 1} +// Mainboard (10 cards) +Æther Adept +2x Fire & Ice +3 Pain/Suffering +4X [B] Forest (3) - }); - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + +// Sideboard (11 cards) + +5x [WTH] Nature’s Resurgence +6X Gaea's Skyfolk +7 B.F.M. (Big Furry Monster) + + + +)"); + + Result result("DeckName", "Comment 1\n\nComment [two]\n(test) Æ ’ | / (3)", + {{"Aether Adept", 1}, {"Fire // Ice", 2}, {"Pain // Suffering", 3}, {"Forest", 4}}, + {{"Nature's Resurgence", 5}, {"Gaea's Skyfolk", 6}, {"B.F.M. (Big Furry Monster)", 7}}); + testDeck(clipboard, result); } TEST(LoadingFromClipboardTest, CommentsBeforeCardsTesting) { - QString *clipboard = new QString("//NAME: Title from Website.com\n" - "\n" - "//Main\n" - "1 test1\n"); - DeckList *decklist = fromClipboard(clipboard); - DecklistBuilder decklistBuilder = DecklistBuilder(); - decklist->forEachCard(decklistBuilder); - CardRows expectedMainboard = CardRows({{"test1", 1}}); - CardRows expectedSideboard = CardRows({}); - ASSERT_EQ(expectedMainboard, decklistBuilder.mainboard()); - ASSERT_EQ(expectedSideboard, decklistBuilder.sideboard()); + QString clipboard("// Title from website.com\n" + "// A nice deck\n" + "// With nice cards\n" + "\n" + "// Mainboard\n" + "1 test1\n" + "Sideboard\n" + "2 test2\n"); + + Result result("Title from website.com", "A nice deck\nWith nice cards", {{"test1", 1}}, {{"test2", 2}}); + testDeck(clipboard, result); } -} // namespace int main(int argc, char **argv) { diff --git a/tests/loading_from_clipboard/loading_from_clipboard_test.h b/tests/loading_from_clipboard/loading_from_clipboard_test.h deleted file mode 100644 index e69de29b..00000000