// // town_read.cpp // BoE // // Created by Celtic Minstrel on 15-08-27. // // #include #include "ticpp.h" #include "catch.hpp" #include "dialogxml/dialogs/dialog.hpp" #include "scenario/scenario.hpp" #include "scenario/town.hpp" using namespace std; using namespace ticpp; extern Document xmlDocFromStream(istream& stream, string name); extern void readTownFromXml(Document&& data, cTown*& town, cScenario& scen); TEST_CASE("Loading a town definition") { ifstream fin; cScenario scen; cTown* town = nullptr; Document doc; fin.exceptions(ios::badbit); SECTION("When the root tag is wrong") { fin.open("files/bad_root.xml"); doc = xmlDocFromStream(fin, "bad_root.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When the version attribute is missing") { fin.open("files/town/no_version.xml"); doc = xmlDocFromStream(fin, "no_version.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xMissingAttr); } SECTION("When the root tag has a bad attribute") { fin.open("files/town/bad_root_attr.xml"); doc = xmlDocFromStream(fin, "bad_root_attr.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadAttr); } SECTION("When an essential toplevel element is missing") { fin.open("files/town/missing_toplevel.xml"); doc = xmlDocFromStream(fin, "missing_toplevel.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xMissingElem); } SECTION("When the size is not first") { fin.open("files/town/size_not_first.xml"); doc = xmlDocFromStream(fin, "size_not_first.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When the size is invalid") { fin.open("files/town/bad_size.xml"); doc = xmlDocFromStream(fin, "bad_size.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal); } SECTION("When there is an invalid toplevel node") { fin.open("files/town/bad_toplevel.xml"); doc = xmlDocFromStream(fin, "bad_toplevel.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When there are too many comments") { fin.open("files/town/too_many_comments.xml"); doc = xmlDocFromStream(fin, "too_many_comments.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When the onenter condition is invalid") { fin.open("files/town/bad_onenter_condition.xml"); doc = xmlDocFromStream(fin, "bad_onenter_condition.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal); } SECTION("When the onenter condition is duplicated") { fin.open("files/town/dup_onenter_condition.xml"); doc = xmlDocFromStream(fin, "dup_onenter_condition.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal); } SECTION("When the onexit direction is invalid") { fin.open("files/town/bad_onexit_dir.xml"); doc = xmlDocFromStream(fin, "bad_onexit_dir.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal); } SECTION("When the exit direction is invalid") { fin.open("files/town/bad_exit_dir.xml"); doc = xmlDocFromStream(fin, "bad_exit_dir.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadVal); } SECTION("When there are too many timers") { fin.open("files/town/too_many_timers.xml"); doc = xmlDocFromStream(fin, "too_many_timers.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When there is an invalid flag") { fin.open("files/town/bad_flag.xml"); doc = xmlDocFromStream(fin, "bad_flag.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When there is a bad wandering definition") { fin.open("files/town/bad_wandering.xml"); doc = xmlDocFromStream(fin, "bad_wandering.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When there is an empty wandering definition") { fin.open("files/town/empty_wandering.xml"); doc = xmlDocFromStream(fin, "empty_wandering.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xMissingElem); } SECTION("When there is a preset item with an invalid tag") { fin.open("files/town/bad_item.xml"); doc = xmlDocFromStream(fin, "bad_item.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When there is a preset item without a type") { fin.open("files/town/empty_item.xml"); doc = xmlDocFromStream(fin, "empty_item.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xMissingElem); } SECTION("When there is a preset creature with an invalid tag") { fin.open("files/town/bad_creature.xml"); doc = xmlDocFromStream(fin, "bad_creature.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xBadNode); } SECTION("When there is a preset creature without a type") { fin.open("files/town/empty_creature.xml"); doc = xmlDocFromStream(fin, "empty_creature.xml"); REQUIRE_THROWS_AS(readTownFromXml(move(doc), town, scen), xMissingElem); } SECTION("With the minimal required data") { fin.open("files/town/minimal.xml"); doc = xmlDocFromStream(fin, "minimal.xml"); REQUIRE_NOTHROW(readTownFromXml(move(doc), town, scen)); CHECK(town->max_dim == 32); CHECK(town->name == "Test Town"); CHECK(town->in_town_rect == rect(4, 4, 28, 28)); CHECK(town->difficulty == 1); CHECK(town->lighting_type == LIGHT_NORMAL); } SECTION("With all possible data") { fin.open("files/town/full.xml"); doc = xmlDocFromStream(fin, "full.xml"); REQUIRE_NOTHROW(readTownFromXml(move(doc), town, scen)); CHECK(town->comment[0] == "This is a silly little comment."); CHECK(town->spec_on_entry == 12); CHECK(town->spec_on_entry_if_dead == 13); CHECK(town->exits[0] == loc(4,16)); CHECK(town->exits[0].spec == 52); CHECK(town->spec_on_hostile == 42); CHECK(town->town_chop_time == 18); CHECK(town->town_chop_key == 4); CHECK(town->max_num_monst == 50000); CHECK(town->is_hidden); CHECK(town->strong_barriers); CHECK(town->has_tavern); CHECK(town->defy_mapping); CHECK(town->defy_scrying); REQUIRE(town->timers.size() >= 1); CHECK(town->timers[0].node_type == eSpecCtxType::TOWN); CHECK(town->timers[0].node == 15); CHECK(town->timers[0].time == 100); REQUIRE(town->wandering.size() >= 1); CHECK(town->wandering[0].monst[0] == 40); CHECK(town->wandering[0].monst[1] == 41); CHECK(town->wandering[0].monst[2] == 42); CHECK(town->wandering[0].monst[3] == 43); REQUIRE(town->sign_locs.size() >= 2); CHECK(town->sign_locs[1].text == "This is a sample sign."); REQUIRE(town->spec_strs.size() >= 8); CHECK(town->spec_strs[7] == "Here is a town string."); REQUIRE(town->preset_items.size() >= 3); CHECK(town->preset_items[2].code == 120); CHECK(town->preset_items[2].ability == eEnchant::PLUS_THREE); CHECK(town->preset_items[2].charges == 17); CHECK(town->preset_items[2].always_there); CHECK(town->preset_items[2].property); CHECK(town->preset_items[2].contained); REQUIRE(town->creatures.size() >= 13); CHECK(town->creatures[12].number == 140); CHECK(town->creatures[12].start_attitude == eAttitude::HOSTILE_B); CHECK(town->creatures[12].mobility == 1); CHECK(town->creatures[12].spec1 == 12); CHECK(town->creatures[12].spec2 == 13); CHECK(town->creatures[12].spec_enc_code == 50); CHECK(town->creatures[12].time_flag == eMonstTime::APPEAR_WHEN_EVENT); CHECK(town->creatures[12].monster_time == 17); CHECK(town->creatures[12].time_code == 14); CHECK(town->creatures[12].facial_pic == 142); CHECK(town->creatures[12].personality == 1); CHECK(town->creatures[12].special_on_kill == 80); CHECK(town->creatures[12].special_on_talk == 81); REQUIRE(town->area_desc.size() >= 1); CHECK(town->area_desc[0].descr == "This is a sample area description."); } delete town; }