#include #include "ccm/domain/Configuration.hpp" #include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/DigiBattle99SetCatalog.hpp" #include "ccm/domain/PokemonSetCatalog.hpp" #include "ccm/domain/YuGiOhSetCatalog.hpp" #include "ccm/domain/Enums.hpp" #include "ccm/domain/JapanesePokemonCard.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" #include "ccm/domain/YuGiOhBandaiCard.hpp" #include "ccm/domain/YuGiOhBandaiSetCatalog.hpp" #include "ccm/domain/YuGiOhCard.hpp" #include "ccm/domain/Set.hpp" #include using namespace ccm; TEST_SUITE("domain enums round-trip JSON as strings") { TEST_CASE("Game") { nlohmann::json j = Game::Magic; CHECK(j.get() == "Magic"); CHECK(j.get() == Game::Magic); nlohmann::json j2 = "Pokemon"; CHECK(j2.get() == Game::Pokemon); nlohmann::json jYgo = "YuGiOh"; CHECK(jYgo.get() == Game::YuGiOh); nlohmann::json jDigi = "DigiBattle99"; CHECK(jDigi.get() == Game::DigiBattle99); nlohmann::json jBandai = "YuGiOhBandai"; CHECK(jBandai.get() == Game::YuGiOhBandai); nlohmann::json jJp = "JapanesePokemon"; CHECK(jJp.get() == Game::JapanesePokemon); nlohmann::json j3 = Theme::Dark; CHECK(j3.get() == "Dark"); CHECK(j3.get() == Theme::Dark); } TEST_CASE("Language and Condition") { nlohmann::json l = Language::Japanese; CHECK(l.get() == "Japanese"); CHECK(l.get() == Language::Japanese); nlohmann::json k = Language::Korean; CHECK(k.get() == "Korean"); CHECK(k.get() == Language::Korean); nlohmann::json sc = Language::SimplifiedChinese; CHECK(sc.get() == "S-Chinese"); CHECK(sc.get() == Language::SimplifiedChinese); nlohmann::json tc = Language::TraditionalChinese; CHECK(tc.get() == "T-Chinese"); CHECK(tc.get() == Language::TraditionalChinese); nlohmann::json legacyChinese = "Chinese"; CHECK(legacyChinese.get() == Language::SimplifiedChinese); nlohmann::json c = Condition::LightPlayed; CHECK(c.get() == "LightPlayed"); CHECK(c.get() == Condition::LightPlayed); } TEST_CASE("PokemonRegion") { nlohmann::json j = PokemonRegion::Asia; CHECK(j.get() == "Asia"); CHECK(j.get() == PokemonRegion::Asia); nlohmann::json w = "West"; CHECK(w.get() == PokemonRegion::West); } TEST_CASE("allGames excludes JapanesePokemon but string mapping remains") { for (const auto game : allGames()) { CHECK(game != Game::JapanesePokemon); } CHECK(allGames().size() == 5); CHECK(gameFromString("JapanesePokemon") == Game::JapanesePokemon); CHECK(pokemonBackendGame(PokemonRegion::West) == Game::Pokemon); CHECK(pokemonBackendGame(PokemonRegion::Asia) == Game::JapanesePokemon); } TEST_CASE("invalid enum string throws") { nlohmann::json bad = "Spanglish"; CHECK_THROWS(bad.get()); } TEST_CASE("all enum values round-trip through string helpers") { for (const auto game : allGames()) { const auto name = to_string(game); CHECK(gameFromString(name).has_value()); CHECK(*gameFromString(name) == game); } for (const auto language : allLanguages()) { const auto name = to_string(language); CHECK(languageFromString(name).has_value()); CHECK(*languageFromString(name) == language); } for (const auto condition : allConditions()) { const auto name = to_string(condition); CHECK(conditionFromString(name).has_value()); CHECK(*conditionFromString(name) == condition); } for (const auto theme : allThemes()) { const auto name = to_string(theme); CHECK(themeFromString(name).has_value()); CHECK(*themeFromString(name) == theme); } } TEST_CASE("invalid enum helper inputs return nullopt") { CHECK_FALSE(gameFromString("magic").has_value()); CHECK_FALSE(languageFromString("EN").has_value()); CHECK_FALSE(conditionFromString("Near Mint").has_value()); CHECK_FALSE(themeFromString("OLED").has_value()); } TEST_CASE("invalid game, condition and theme JSON values throw") { nlohmann::json badGame = "YGO"; CHECK_THROWS(badGame.get()); nlohmann::json badCondition = "Pristine"; CHECK_THROWS(badCondition.get()); nlohmann::json badTheme = "Midnight"; CHECK_THROWS(badTheme.get()); } } TEST_SUITE("Set JSON shape stays stable") { TEST_CASE("uses 'releaseDate' alias") { Set s{"abc", "Test Set", "2024/05/01"}; const nlohmann::json j = s; CHECK(j.contains("releaseDate")); CHECK_FALSE(j.contains("release_date")); CHECK(j.at("releaseDate") == "2024/05/01"); const Set back = j.get(); CHECK(back == s); } } TEST_SUITE("MagicCard JSON") { TEST_CASE("round-trips with all original field names") { MagicCard c; c.id = 42; c.amount = 3; c.name = "Lightning Bolt"; c.set = Set{"lea", "Limited Edition Alpha", "1993/08/05"}; c.note = "rare promo"; c.images = {"foo+bar+0.png"}; c.language = Language::English; c.condition = Condition::NearMint; c.foil = true; c.signed_ = false; c.altered = false; nlohmann::json j = c; CHECK(j.contains("signed")); CHECK(j.at("signed") == false); CHECK(j.at("foil") == true); const MagicCard back = j.get(); CHECK(back == c); } } TEST_SUITE("PokemonCard JSON") { TEST_CASE("uses 'setNo' and 'firstEdition' aliases") { PokemonCard c; c.id = 7; c.amount = 1; c.name = "Charizard"; c.set = Set{"base1", "Base Set", "1999/01/09"}; c.setNo = "4/102"; c.note = ""; c.images = {}; c.language = Language::English; c.condition = Condition::Excellent; c.firstEdition = true; c.holo = true; c.signed_ = false; c.altered = false; c.region = PokemonRegion::West; nlohmann::json j = c; CHECK(j.at("setNo") == "4/102"); CHECK(j.at("firstEdition") == true); CHECK(j.at("signed") == false); CHECK(j.at("region") == "West"); const PokemonCard back = j.get(); CHECK(back == c); } TEST_CASE("region Asia round-trips and missing region defaults to West") { PokemonCard c; c.id = 1; c.amount = 1; c.name = "Charmander"; c.set = Set{"PMCG1", "Expansion Pack", "1996/10/20"}; c.setNo = "001"; c.language = Language::Japanese; c.condition = Condition::NearMint; c.region = PokemonRegion::Asia; nlohmann::json j = c; CHECK(j.at("region") == "Asia"); CHECK(j.get().region == PokemonRegion::Asia); j.erase("region"); const PokemonCard legacy = j.get(); CHECK(legacy.region == PokemonRegion::West); } TEST_CASE("West load migrates legacy pokemontcg set ids to TCGdex EN") { nlohmann::json j = { {"id", 1}, {"amount", 1}, {"name", "Charizard"}, {"set", {{"id", "sv1"}, {"name", "Scarlet & Violet"}, {"releaseDate", "2023/03/31"}}}, {"setNo", "6"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"firstEdition", false}, {"holo", false}, {"signed", false}, {"altered", false}, {"region", "West"}, }; const PokemonCard back = j.get(); CHECK(back.set.id == "sv01"); } TEST_CASE("Asia load does not rewrite set ids through West aliases") { nlohmann::json j = { {"id", 1}, {"amount", 1}, {"name", "Charmander"}, {"set", {{"id", "sv1"}, {"name", "Keep Asia id"}, {"releaseDate", "2023/01/01"}}}, {"setNo", "001"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "Japanese"}, {"condition", "NearMint"}, {"firstEdition", false}, {"holo", false}, {"signed", false}, {"altered", false}, {"region", "Asia"}, }; const PokemonCard back = j.get(); CHECK(back.set.id == "sv1"); } } TEST_SUITE("DigiBattle99Card JSON") { TEST_CASE("uses 'setNo' and 'firstEdition' aliases") { DigiBattle99Card c; c.id = 3; c.amount = 2; c.name = "Agumon"; c.set = Set{"series-1-starter-set", "Series 1 Starter Set", "1999/06/01"}; c.setNo = "ST-01"; c.note = "starter"; c.images = {"a.png"}; c.language = Language::English; c.condition = Condition::NearMint; c.firstEdition = false; c.holo = true; c.signed_ = true; c.altered = false; nlohmann::json j = c; CHECK(j.at("setNo") == "ST-01"); CHECK(j.at("firstEdition") == false); CHECK(j.at("holo") == true); CHECK(j.at("signed") == true); const DigiBattle99Card back = j.get(); CHECK(back == c); } } TEST_SUITE("DigiBattle99SetCatalog JSON") { TEST_CASE("round-trips packs and setNo alias") { DigiBattle99SetCatalog catalog; DigiBattle99SetCatalogPack pack; pack.setId = "series-1-starter-set"; pack.setName = "Series 1 Starter Set"; pack.cards.push_back(DigiBattle99CatalogCard{"ST-01", "Agumon"}); pack.cards.push_back(DigiBattle99CatalogCard{"ST-126", "Agumon"}); catalog.packs.push_back(std::move(pack)); nlohmann::json j = catalog; CHECK(j.at("packs").is_array()); CHECK(j.at("packs").at(0).at("id") == "series-1-starter-set"); CHECK(j.at("packs").at(0).at("cards").at(0).at("setNo") == "ST-01"); const DigiBattle99SetCatalog back = j.get(); CHECK(back == catalog); CHECK(back.findPack("series-1-starter-set") != nullptr); CHECK(back.findPack("missing") == nullptr); } } TEST_SUITE("YuGiOhBandaiCard JSON") { TEST_CASE("round-trips with setNo, rarity, holo and signed alias") { YuGiOhBandaiCard c; c.id = 14; c.amount = 2; c.name = "Dark Magician"; c.set = Set{"ban1", "1st Generation", "1998/09/01"}; c.setNo = "14"; c.rarity = "Rare"; c.note = "classic"; c.images = {"a.png"}; c.language = Language::Japanese; c.condition = Condition::NearMint; c.holo = true; c.signed_ = true; c.altered = false; nlohmann::json j = c; CHECK(j.at("setNo") == "14"); CHECK(j.at("rarity") == "Rare"); CHECK(j.at("holo") == true); CHECK(j.at("signed") == true); CHECK_FALSE(j.contains("firstEdition")); const YuGiOhBandaiCard back = j.get(); CHECK(back == c); } TEST_CASE("missing each required key throws") { const nlohmann::json full = { {"id", 14}, {"amount", 1}, {"name", "Dark Magician"}, {"set", nlohmann::json{ {"id", "ban1"}, {"name", "1st Generation"}, {"releaseDate", "1998/09/01"}, }}, {"setNo", "14"}, {"rarity", "Rare"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "Japanese"}, {"condition", "NearMint"}, {"holo", false}, {"signed", false}, {"altered", false}, }; for (const char* key : { "id", "amount", "name", "set", "setNo", "rarity", "note", "images", "language", "condition", "holo", "signed", "altered"}) { nlohmann::json partial = full; partial.erase(key); CHECK_THROWS(partial.get()); } } } TEST_SUITE("YuGiOhBandaiSetCatalog JSON") { TEST_CASE("round-trips packs with rarity") { YuGiOhBandaiSetCatalog catalog; YuGiOhBandaiSetCatalogPack pack; pack.setId = "ban1"; pack.setName = "1st Generation"; pack.cards.push_back(YuGiOhBandaiCatalogCard{"14", "Dark Magician", "Rare"}); pack.cards.push_back(YuGiOhBandaiCatalogCard{"9", "Blue-Eyes White Dragon", "Super Rare"}); catalog.packs.push_back(std::move(pack)); nlohmann::json j = catalog; CHECK(j.at("packs").at(0).at("id") == "ban1"); CHECK(j.at("packs").at(0).at("cards").at(0).at("setNo") == "14"); CHECK(j.at("packs").at(0).at("cards").at(0).at("rarity") == "Rare"); const YuGiOhBandaiSetCatalog back = j.get(); CHECK(back == catalog); CHECK(back.findPack("ban1") != nullptr); CHECK(back.findPack("missing") == nullptr); } } TEST_SUITE("YuGiOhSetCatalog JSON") { TEST_CASE("round-trips packs and setNo alias") { YuGiOhSetCatalog catalog; YuGiOhSetCatalogPack pack; pack.setId = "LOB"; pack.setName = "Legend of Blue Eyes White Dragon"; pack.cards.push_back(YuGiOhCatalogCard{"LOB-001", "Blue-Eyes White Dragon", "Ultra Rare"}); pack.cards.push_back(YuGiOhCatalogCard{"LOB-EN005", "Dark Magician", "Ultra Rare"}); catalog.packs.push_back(std::move(pack)); nlohmann::json j = catalog; CHECK(j.at("packs").is_array()); CHECK(j.at("packs").at(0).at("id") == "LOB"); CHECK(j.at("packs").at(0).at("cards").at(0).at("setNo") == "LOB-001"); CHECK(j.at("packs").at(0).at("cards").at(0).at("rarity") == "Ultra Rare"); const YuGiOhSetCatalog back = j.get(); CHECK(back == catalog); CHECK(back.findPack("LOB") != nullptr); CHECK(back.findPack("missing") == nullptr); } TEST_CASE("legacy catalog JSON without rarity still loads") { const auto j = nlohmann::json::parse(R"({ "packs":[{"id":"LOB","name":"Legend of Blue Eyes White Dragon", "cards":[{"setNo":"LOB-001","name":"Blue-Eyes White Dragon"}]}] })"); const YuGiOhSetCatalog back = j.get(); REQUIRE(back.packs.size() == 1); REQUIRE(back.packs[0].cards.size() == 1); CHECK(back.packs[0].cards[0].rarity.empty()); } } TEST_SUITE("PokemonSetCatalog JSON") { TEST_CASE("round-trips packs and setNo alias") { PokemonSetCatalog catalog; PokemonSetCatalogPack pack; pack.setId = "base1"; pack.setName = "Base"; pack.cards.push_back(PokemonCatalogCard{"4", "Charizard"}); pack.cards.push_back(PokemonCatalogCard{"58", "Growlithe"}); catalog.packs.push_back(std::move(pack)); nlohmann::json j = catalog; CHECK(j.at("packs").is_array()); CHECK(j.at("packs").at(0).at("id") == "base1"); CHECK(j.at("packs").at(0).at("cards").at(0).at("setNo") == "4"); const PokemonSetCatalog back = j.get(); CHECK(back == catalog); CHECK(back.findPack("base1") != nullptr); CHECK(back.findPack("missing") == nullptr); } } TEST_SUITE("JapanesePokemonCard JSON") { TEST_CASE("uses 'setNo' and 'firstEdition' aliases") { JapanesePokemonCard c; c.id = 9; c.amount = 1; c.name = "Charmander"; c.set = Set{"PMCG1", "Expansion Pack", "1996/10/20"}; c.setNo = "001"; c.note = ""; c.images = {}; c.language = Language::Japanese; c.condition = Condition::NearMint; c.firstEdition = true; c.holo = false; c.signed_ = false; c.altered = false; nlohmann::json j = c; CHECK(j.at("setNo") == "001"); CHECK(j.at("firstEdition") == true); CHECK(j.at("signed") == false); CHECK(j.at("language") == "Japanese"); const JapanesePokemonCard back = j.get(); CHECK(back == c); } } TEST_SUITE("Configuration JSON matches Rust serde aliases") { TEST_CASE("dataStorage / defaultGame / theme keys are present") { Configuration cfg; cfg.dataStorage = "/some/path"; cfg.defaultGame = Game::Pokemon; cfg.theme = Theme::Dark; nlohmann::json j = cfg; CHECK(j.at("dataStorage") == "/some/path"); CHECK(j.at("defaultGame") == "Pokemon"); CHECK(j.at("theme") == "Dark"); const auto back = j.get(); CHECK(back == cfg); } TEST_CASE("legacy defaultGame JapanesePokemon coerces to Pokemon") { nlohmann::json j = { {"dataStorage", "/data"}, {"defaultGame", "JapanesePokemon"}, {"theme", "Light"}, }; const auto cfg = j.get(); CHECK(cfg.defaultGame == Game::Pokemon); } TEST_CASE("missing theme key defaults to Light") { const nlohmann::json j = { {"dataStorage", "/portable/data"}, {"defaultGame", "YuGiOh"}, }; const auto cfg = j.get(); CHECK(cfg.dataStorage == "/portable/data"); CHECK(cfg.defaultGame == Game::YuGiOh); CHECK(cfg.theme == Theme::Light); } } TEST_SUITE("YuGiOhCard JSON") { TEST_CASE("round-trips with setNo and rarity fields") { YuGiOhCard c; c.id = 77; c.amount = 2; c.name = "Blue-Eyes White Dragon"; c.set = Set{"SDK-001", "Starter Deck Kaiba", "2002/03/29"}; c.setNo = "SDK-001"; c.rarity = "Ultra Rare"; c.note = "classic"; c.images = {"77+starter+blue-eyes+0.png"}; c.language = Language::English; c.condition = Condition::NearMint; c.firstEdition = true; c.signed_ = false; c.altered = false; nlohmann::json j = c; CHECK(j.at("setNo") == "SDK-001"); CHECK(j.at("rarity") == "Ultra Rare"); CHECK_FALSE(j.contains("rarityCode")); CHECK(j.at("signed") == false); const YuGiOhCard back = j.get(); CHECK(back == c); } TEST_CASE("legacy JSON without rarityCode key parses (domain uses rarity only)") { const nlohmann::json j = { {"id", 1}, {"amount", 1}, {"name", "Dark Magician"}, {"set", nlohmann::json{ {"id", "SDY"}, {"name", "Starter Deck: Yugi"}, {"releaseDate", "2002/03/29"}, }}, {"setNo", "SDY-006"}, {"rarity", "Ultra Rare"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"firstEdition", false}, {"signed", false}, {"altered", false}, }; const auto card = j.get(); CHECK(card.rarity == "Ultra Rare"); CHECK(card.setNo == "SDY-006"); CHECK(card.set.id == "SDY"); } TEST_CASE("serializes non-default flags and metadata fields") { YuGiOhCard c; c.id = 3; c.amount = 4; c.name = "Red-Eyes Black Dragon"; c.set = Set{"lob", "Legend of Blue Eyes", "2002/03/08"}; c.setNo = "LOB-070"; c.rarity = "Secret Rare"; c.note = "graded"; c.images = {}; c.language = Language::German; c.condition = Condition::Played; c.firstEdition = false; c.signed_ = true; c.altered = true; const nlohmann::json j = c; CHECK(j.at("firstEdition") == false); CHECK(j.at("signed") == true); CHECK(j.at("altered") == true); CHECK(j.at("language") == "German"); CHECK(j.at("condition") == "Played"); CHECK(j.at("images") == nlohmann::json::array()); const YuGiOhCard back = j.get(); CHECK(back == c); } TEST_CASE("operator== distinguishes each field") { YuGiOhCard base; base.id = 10; base.amount = 2; base.name = "Dark Magician"; base.set = Set{"lob", "Legend of Blue Eyes", "2002/03/08"}; base.setNo = "LOB-005"; base.rarity = "Ultra Rare"; base.note = "note"; base.images = {"a.png"}; base.language = Language::English; base.condition = Condition::NearMint; base.firstEdition = true; base.signed_ = false; base.altered = false; auto changed = base; changed.id = 11; CHECK_FALSE(changed == base); changed = base; changed.amount = 3; CHECK_FALSE(changed == base); changed = base; changed.name = "Other"; CHECK_FALSE(changed == base); changed = base; changed.set.name = "Other Set"; CHECK_FALSE(changed == base); changed = base; changed.setNo = "LOB-006"; CHECK_FALSE(changed == base); changed = base; changed.rarity = "Rare"; CHECK_FALSE(changed == base); changed = base; changed.note = "other"; CHECK_FALSE(changed == base); changed = base; changed.images = {}; CHECK_FALSE(changed == base); changed = base; changed.language = Language::Japanese; CHECK_FALSE(changed == base); changed = base; changed.condition = Condition::Played; CHECK_FALSE(changed == base); changed = base; changed.firstEdition = false; CHECK_FALSE(changed == base); changed = base; changed.signed_ = true; CHECK_FALSE(changed == base); changed = base; changed.altered = true; CHECK_FALSE(changed == base); } } TEST_SUITE("Domain JSON required fields") { TEST_CASE("Set missing required key throws") { const nlohmann::json j = { {"id", "lea"}, {"name", "Limited Edition Alpha"}, }; CHECK_THROWS(j.get()); } TEST_CASE("MagicCard missing required key throws") { const nlohmann::json j = { {"id", 10}, {"amount", 1}, {"name", "Lightning Bolt"}, {"set", nlohmann::json{ {"id", "lea"}, {"name", "Limited Edition Alpha"}, {"releaseDate", "1993/08/05"}, }}, // note missing on purpose {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"foil", false}, {"signed", false}, {"altered", false}, }; CHECK_THROWS(j.get()); } TEST_CASE("PokemonCard missing required key throws") { const nlohmann::json j = { {"id", 7}, {"amount", 1}, {"name", "Charizard"}, {"set", nlohmann::json{ {"id", "base1"}, {"name", "Base Set"}, {"releaseDate", "1999/01/09"}, }}, {"setNo", "4/102"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "Excellent"}, {"firstEdition", true}, // holo missing on purpose {"signed", false}, {"altered", false}, }; CHECK_THROWS(j.get()); } TEST_CASE("YuGiOhCard missing required key throws") { const nlohmann::json j = { {"id", 7}, {"amount", 1}, {"name", "Blue-Eyes White Dragon"}, {"set", nlohmann::json{ {"id", "sdk"}, {"name", "Starter Deck Kaiba"}, {"releaseDate", "2002/03/29"}, }}, {"setNo", "SDK-001"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"firstEdition", true}, // rarity missing on purpose {"signed", false}, {"altered", false}, }; CHECK_THROWS(j.get()); } TEST_CASE("YuGiOhCard missing each required key throws") { const nlohmann::json full = { {"id", 7}, {"amount", 1}, {"name", "Blue-Eyes White Dragon"}, {"set", nlohmann::json{ {"id", "sdk"}, {"name", "Starter Deck Kaiba"}, {"releaseDate", "2002/03/29"}, }}, {"setNo", "SDK-001"}, {"rarity", "Ultra Rare"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"firstEdition", true}, {"signed", false}, {"altered", false}, }; for (const char* key : { "id", "amount", "name", "set", "setNo", "note", "images", "language", "condition", "firstEdition", "rarity", "signed", "altered"}) { nlohmann::json partial = full; partial.erase(key); CHECK_THROWS(partial.get()); } } TEST_CASE("MagicCard missing each required key throws") { const nlohmann::json full = { {"id", 10}, {"amount", 1}, {"name", "Lightning Bolt"}, {"set", nlohmann::json{ {"id", "lea"}, {"name", "Limited Edition Alpha"}, {"releaseDate", "1993/08/05"}, }}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"foil", false}, {"signed", false}, {"altered", false}, }; for (const char* key : {"id", "amount", "name", "set", "note", "images", "language", "condition", "foil", "signed", "altered"}) { nlohmann::json partial = full; partial.erase(key); CHECK_THROWS(partial.get()); } } TEST_CASE("PokemonCard missing each required key throws") { const nlohmann::json full = { {"id", 7}, {"amount", 1}, {"name", "Charizard"}, {"set", nlohmann::json{ {"id", "base1"}, {"name", "Base Set"}, {"releaseDate", "1999/01/09"}, }}, {"setNo", "4/102"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "Excellent"}, {"firstEdition", true}, {"holo", true}, {"signed", false}, {"altered", false}, }; for (const char* key : {"id", "amount", "name", "set", "setNo", "note", "images", "language", "condition", "firstEdition", "holo", "signed", "altered"}) { nlohmann::json partial = full; partial.erase(key); CHECK_THROWS(partial.get()); } } TEST_CASE("DigiBattle99Card missing each required key throws") { const nlohmann::json full = { {"id", 3}, {"amount", 1}, {"name", "Agumon"}, {"set", nlohmann::json{ {"id", "series-1-starter-set"}, {"name", "Series 1 Starter Set"}, {"releaseDate", "1999/06/01"}, }}, {"setNo", "ST-01"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "English"}, {"condition", "NearMint"}, {"firstEdition", false}, {"holo", true}, {"signed", false}, {"altered", false}, }; for (const char* key : {"id", "amount", "name", "set", "setNo", "note", "images", "language", "condition", "firstEdition", "holo", "signed", "altered"}) { nlohmann::json partial = full; partial.erase(key); CHECK_THROWS(partial.get()); } } TEST_CASE("JapanesePokemonCard missing each required key throws") { const nlohmann::json full = { {"id", 9}, {"amount", 1}, {"name", "Charmander"}, {"set", nlohmann::json{ {"id", "PMCG1"}, {"name", "Expansion Pack"}, {"releaseDate", "1996/10/20"}, }}, {"setNo", "001"}, {"note", ""}, {"images", nlohmann::json::array()}, {"language", "Japanese"}, {"condition", "NearMint"}, {"firstEdition", true}, {"holo", false}, {"signed", false}, {"altered", false}, }; for (const char* key : {"id", "amount", "name", "set", "setNo", "note", "images", "language", "condition", "firstEdition", "holo", "signed", "altered"}) { nlohmann::json partial = full; partial.erase(key); CHECK_THROWS(partial.get()); } } TEST_CASE("Configuration missing required key throws") { const nlohmann::json j = { {"defaultGame", "Magic"}, {"theme", "Dark"}, }; CHECK_THROWS(j.get()); } TEST_CASE("Configuration invalid theme value throws when present") { const nlohmann::json j = { {"dataStorage", "/portable/data"}, {"defaultGame", "Magic"}, {"theme", "Neon"}, }; CHECK_THROWS(j.get()); } }