From 8bc8e100759e069a2584378d91cbedf2c0ed2496 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Fri, 4 Sep 2015 04:26:58 -0400 Subject: [PATCH] Several more map read/write test cases --- src/classes/town.hpp | 1 + src/tools/fileio_scen.cpp | 7 +- src/tools/map_parse.cpp | 4 +- test/files/maps/bad_feature.map | 1 + test/files/maps/fields.map | 6 ++ test/files/maps/misc.map | 1 + test/files/maps/towns_entry.map | 3 + test/files/maps/towns_out.map | 2 + test/map_read.cpp | 158 ++++++++++++++++++++++++++++++++ test/map_write.cpp | 141 ++++++++++++++++++++++++++++ 10 files changed, 318 insertions(+), 6 deletions(-) create mode 100644 test/files/maps/bad_feature.map create mode 100644 test/files/maps/fields.map create mode 100644 test/files/maps/misc.map create mode 100644 test/files/maps/towns_entry.map create mode 100644 test/files/maps/towns_out.map diff --git a/src/classes/town.hpp b/src/classes/town.hpp index f8d5f1a5..d5b60465 100644 --- a/src/classes/town.hpp +++ b/src/classes/town.hpp @@ -61,6 +61,7 @@ public: void append(legacy::preset_field_type old); cField() : type(FIELD_DISPEL) {} + cField(location l, eFieldType t) : loc(l), type(t) {} }; short town_chop_time,town_chop_key; int bg_town, bg_fight; diff --git a/src/tools/fileio_scen.cpp b/src/tools/fileio_scen.cpp index b5eb82bc..0f9fbfb0 100644 --- a/src/tools/fileio_scen.cpp +++ b/src/tools/fileio_scen.cpp @@ -1902,11 +1902,8 @@ void loadTownMapData(map_data&& data, int which, cScenario& scen) { bool is_boat = false; cVehicle* what; switch(feat.first) { - // Special values - case eMapFeature::NONE: - break; - // Outdoor-only features - case eMapFeature::TOWN: break; + case eMapFeature::NONE: break; // Special value + case eMapFeature::TOWN: break; // Outdoor-only feature case eMapFeature::SPECIAL_NODE: town.special_locs.push_back({x, y, feat.second}); break; diff --git a/src/tools/map_parse.cpp b/src/tools/map_parse.cpp index 7fae1fe7..7cb74bef 100644 --- a/src/tools/map_parse.cpp +++ b/src/tools/map_parse.cpp @@ -19,9 +19,11 @@ map_data load_map(std::istream& fin, bool isTown, std::string name) { map_data data; data.file = name; int row = 0; - while(!fin.eof()) { + while(fin) { std::string line; getline(fin, line); + if(line.empty() && !fin.eof()) + continue; int n = 0, col = 0; eMapFeature curFeature = eMapFeature::NONE; // vehicle_owned = true means the party owns it diff --git a/test/files/maps/bad_feature.map b/test/files/maps/bad_feature.map new file mode 100644 index 00000000..d6d8d5f9 --- /dev/null +++ b/test/files/maps/bad_feature.map @@ -0,0 +1 @@ +0~0 \ No newline at end of file diff --git a/test/files/maps/fields.map b/test/files/maps/fields.map new file mode 100644 index 00000000..5a29453c --- /dev/null +++ b/test/files/maps/fields.map @@ -0,0 +1,6 @@ +0&1,0&2,0&3,0&4 +0&5,0&6,0&7,0&8 +0&9,0&10,0&11,0&12 +0&13,0&14,0&15,0&16 +0&17,0&18,0&19,0&20 +0&21,0&22,0&23,0&24 \ No newline at end of file diff --git a/test/files/maps/misc.map b/test/files/maps/misc.map new file mode 100644 index 00000000..e124e6f8 --- /dev/null +++ b/test/files/maps/misc.map @@ -0,0 +1 @@ +0*1, 0:2, 0!3, 0@4, 0$5 \ No newline at end of file diff --git a/test/files/maps/towns_entry.map b/test/files/maps/towns_entry.map new file mode 100644 index 00000000..4c82ebd1 --- /dev/null +++ b/test/files/maps/towns_entry.map @@ -0,0 +1,3 @@ +0,0,0,0,0^,0,0,0,0 +0<,0,0,0,0,0,0,0,0> +0,0,0,0,0v,0,0,0,0 \ No newline at end of file diff --git a/test/files/maps/towns_out.map b/test/files/maps/towns_out.map new file mode 100644 index 00000000..476b58c4 --- /dev/null +++ b/test/files/maps/towns_out.map @@ -0,0 +1,2 @@ +0,0,0 +0,12@5,0 \ No newline at end of file diff --git a/test/map_read.cpp b/test/map_read.cpp index 92eb4c20..a6069ce4 100644 --- a/test/map_read.cpp +++ b/test/map_read.cpp @@ -47,6 +47,98 @@ TEST_CASE("Loading map data from file") { test[0].second = -5; CHECK(map.getFeatures(3, 0) == test); } + SECTION("With fields") { + fin.open("files/maps/fields.map"); + map = load_map(fin, true, "fields.map"); + test.emplace_back(make_pair(eMapFeature::FIELD, WALL_FORCE)); + CHECK(map.getFeatures(0, 0) == test); + test[0].second = WALL_FIRE; + CHECK(map.getFeatures(1, 0) == test); + test[0].second = FIELD_ANTIMAGIC; + CHECK(map.getFeatures(2, 0) == test); + test[0].second = CLOUD_STINK; + CHECK(map.getFeatures(3, 0) == test); + test[0].second = WALL_ICE; + CHECK(map.getFeatures(0, 1) == test); + test[0].second = WALL_BLADES; + CHECK(map.getFeatures(1, 1) == test); + test[0].second = CLOUD_SLEEP; + CHECK(map.getFeatures(2, 1) == test); + test[0].second = OBJECT_BLOCK; + CHECK(map.getFeatures(3, 1) == test); + test[0].second = SPECIAL_SPOT; + CHECK(map.getFeatures(0, 2) == test); + test[0].second = FIELD_WEB; + CHECK(map.getFeatures(1, 2) == test); + test[0].second = OBJECT_CRATE; + CHECK(map.getFeatures(2, 2) == test); + test[0].second = OBJECT_BARREL; + CHECK(map.getFeatures(3, 2) == test); + test[0].second = BARRIER_FIRE; + CHECK(map.getFeatures(0, 3) == test); + test[0].second = BARRIER_FORCE; + CHECK(map.getFeatures(1, 3) == test); + test[0].second = FIELD_QUICKFIRE; + CHECK(map.getFeatures(2, 3) == test); + test[0].second = SFX_SMALL_BLOOD; + CHECK(map.getFeatures(3, 3) == test); + test[0].second = SFX_MEDIUM_BLOOD; + CHECK(map.getFeatures(0, 4) == test); + test[0].second = SFX_LARGE_BLOOD; + CHECK(map.getFeatures(1, 4) == test); + test[0].second = SFX_SMALL_SLIME; + CHECK(map.getFeatures(2, 4) == test); + test[0].second = SFX_LARGE_SLIME; + CHECK(map.getFeatures(3, 4) == test); + test[0].second = SFX_ASH; + CHECK(map.getFeatures(0, 5) == test); + test[0].second = SFX_BONES; + CHECK(map.getFeatures(1, 5) == test); + test[0].second = SFX_RUBBLE; + CHECK(map.getFeatures(2, 5) == test); + test[0].second = BARRIER_CAGE; + CHECK(map.getFeatures(3, 5) == test); + } + SECTION("With town entrance") { + fin.open("files/maps/towns_out.map"); + map = load_map(fin, false, "towns_out.map"); + test.emplace_back(make_pair(eMapFeature::TOWN, 5)); + CHECK(map.getFeatures(1, 1) == test); + } + SECTION("With town start locs") { + fin.open("files/maps/towns_entry.map"); + map = load_map(fin, true, "towns_entry.map"); + test.emplace_back(make_pair(eMapFeature::ENTRANCE_NORTH, 0)); + CHECK(map.getFeatures(4, 0) == test); + test[0].first = eMapFeature::ENTRANCE_WEST; + CHECK(map.getFeatures(0, 1) == test); + test[0].first = eMapFeature::ENTRANCE_EAST; + CHECK(map.getFeatures(8, 1) == test); + test[0].first = eMapFeature::ENTRANCE_SOUTH; + CHECK(map.getFeatures(4, 2) == test); + } + SECTION("With miscellaneous features") { + fin.open("files/maps/misc.map"); + map = load_map(fin, true, "misc.map"); + test.emplace_back(make_pair(eMapFeature::WANDERING, 1)); + CHECK(map.getFeatures(0, 0) == test); + test[0] = {eMapFeature::SPECIAL_NODE, 2}; + CHECK(map.getFeatures(1, 0) == test); + test[0] = {eMapFeature::SIGN, 3}; + CHECK(map.getFeatures(2, 0) == test); + test[0] = {eMapFeature::ITEM, 4}; + CHECK(map.getFeatures(3, 0) == test); + test[0] = {eMapFeature::CREATURE, 5}; + CHECK(map.getFeatures(4, 0) == test); + } + SECTION("With town start locs outfoors") { + fin.open("files/maps/towns_entry.map"); + REQUIRE_THROWS_AS(load_map(fin, false, "towns_entry.map"), xMapParseError); + } + SECTION("With invalid feature type") { + fin.open("files/maps/bad_feature.map"); + REQUIRE_THROWS_AS(load_map(fin, true, "bad_feature.map"), xMapParseError); + } } extern void loadOutMapData(map_data&& data, location which, cScenario& scen); @@ -119,6 +211,72 @@ TEST_CASE("Interpreting loaded map data") { CHECK(scen.boats[4].loc == loc(3,0)); } } + SECTION("With fields") { + fin.open("files/maps/fields.map"); + map = load_map(fin, true, "fields.map"); + loadTownMapData(move(map), 0, scen); + REQUIRE(scen.towns[0]->preset_fields.size() == 24); + static const std::map check = { + {WALL_FORCE, {0,0}}, {WALL_FIRE, {1,0}}, {FIELD_ANTIMAGIC, {2,0}}, {CLOUD_STINK, {3,0}}, + {WALL_ICE, {0,1}}, {WALL_BLADES, {1,1}}, {CLOUD_SLEEP, {2,1}}, {OBJECT_BLOCK, {3,1}}, + {SPECIAL_SPOT, {0,2}}, {FIELD_WEB, {1,2}}, {OBJECT_CRATE, {2,2}}, {OBJECT_BARREL, {3,2}}, + {BARRIER_FIRE, {0,3}}, {BARRIER_FORCE, {1,3}}, {FIELD_QUICKFIRE, {2,3}}, {SFX_SMALL_BLOOD, {3,3}}, + {SFX_MEDIUM_BLOOD, {0,4}}, {SFX_LARGE_BLOOD, {1,4}}, {SFX_SMALL_SLIME, {2,4}}, {SFX_LARGE_SLIME, {3,4}}, + {SFX_ASH, {0,5}}, {SFX_BONES, {1,5}}, {SFX_RUBBLE, {2,5}}, {BARRIER_CAGE, {3,5}}, + }; + set found; + for(const auto& fld : scen.towns[0]->preset_fields) { + if(found.count(fld.type)) + FAIL("Error: Two fields of the same type found!"); + found.insert(fld.type); + CAPTURE(fld.type); + CAPTURE(fld.loc); + CAPTURE(check.at(fld.type)); + CHECK(fld.loc == check.at(fld.type)); + } + if(found.size() != check.size()) + FAIL("Error: A field is missing!"); + } + SECTION("With town entrance") { + fin.open("files/maps/towns_out.map"); + map = load_map(fin, false, "towns_out.map"); + loadOutMapData(move(map), loc(0,0), scen); + REQUIRE(scen.outdoors[0][0]->city_locs.size() == 1); + CHECK(scen.outdoors[0][0]->city_locs[0] == loc(1,1)); + CHECK(scen.outdoors[0][0]->city_locs[0].spec == 5); + } + SECTION("With town start locs") { + fin.open("files/maps/towns_entry.map"); + map = load_map(fin, true, "towns_entry.map"); + loadTownMapData(move(map), 0, scen); + CHECK(scen.towns[0]->start_locs[0] == loc(4,2)); + CHECK(scen.towns[0]->start_locs[1] == loc(0,1)); + CHECK(scen.towns[0]->start_locs[2] == loc(4,0)); + CHECK(scen.towns[0]->start_locs[3] == loc(8,1)); + } + SECTION("With miscellaneous features") { + fin.open("files/maps/misc.map"); + map = load_map(fin, true, "misc.map"); + scen.towns[0]->sign_locs.resize(4); + scen.towns[0]->preset_items.resize(5); + scen.towns[0]->creatures.resize(6); + loadTownMapData(move(map), 0, scen); + CHECK(scen.towns[0]->wandering_locs[1] == loc(0,0)); + REQUIRE(scen.towns[0]->special_locs.size() == 1); + CHECK(scen.towns[0]->special_locs[0] == loc(1,0)); + CHECK(scen.towns[0]->special_locs[0].spec == 2); + REQUIRE(scen.towns[0]->sign_locs.size() == 4); + CHECK(scen.towns[0]->sign_locs[3] == loc(2,0)); + REQUIRE(scen.towns[0]->preset_items.size() == 5); + CHECK(scen.towns[0]->preset_items[4].loc == loc(3,0)); + REQUIRE(scen.towns[0]->creatures.size() == 6); + CHECK(scen.towns[0]->creatures[5].start_loc == loc(4,0)); + } + SECTION("With invalid field outdoors") { + fin.open("files/maps/fields.map"); + map = load_map(fin, false, "fields.map"); + REQUIRE_THROWS_AS(loadOutMapData(move(map), loc(0,0), scen), xMapParseError); + } } #define CASE(x) case eMapFeature::x: out << #x; break diff --git a/test/map_write.cpp b/test/map_write.cpp index 0d528e2e..53cf0d2b 100644 --- a/test/map_write.cpp +++ b/test/map_write.cpp @@ -91,6 +91,60 @@ TEST_CASE("Saving map data to file") { test[0].second = -4; CHECK(map.getFeatures(3, 3) == test); } + SECTION("With fields") { + map.addFeature(0, 0, eMapFeature::FIELD, FIELD_WEB); + map.addFeature(1, 1, eMapFeature::FIELD, SPECIAL_SPOT); + map.addFeature(2, 2, eMapFeature::FIELD, BARRIER_CAGE); + map.addFeature(3, 3, eMapFeature::FIELD, OBJECT_BLOCK); + in_and_out("fields", map, true); + test.emplace_back(make_pair(eMapFeature::FIELD, FIELD_WEB)); + CHECK(map.getFeatures(0, 0) == test); + test[0].second = SPECIAL_SPOT; + CHECK(map.getFeatures(1, 1) == test); + test[0].second = BARRIER_CAGE; + CHECK(map.getFeatures(2, 2) == test); + test[0].second = OBJECT_BLOCK; + CHECK(map.getFeatures(3, 3) == test); + } + SECTION("With town entrance") { + map.addFeature(0, 0, eMapFeature::TOWN, 4); + in_and_out("town entry loc", map, false); + test.emplace_back(make_pair(eMapFeature::TOWN, 4)); + CHECK(map.getFeatures(0, 0) == test); + } + SECTION("With town start points") { + map.addFeature(0, 0, eMapFeature::ENTRANCE_EAST); + map.addFeature(1, 1, eMapFeature::ENTRANCE_NORTH); + map.addFeature(2, 2, eMapFeature::ENTRANCE_SOUTH); + map.addFeature(3, 3, eMapFeature::ENTRANCE_WEST); + in_and_out("town start loc", map, true); + test.emplace_back(make_pair(eMapFeature::ENTRANCE_EAST, 0)); + CHECK(map.getFeatures(0, 0) == test); + test[0].first = eMapFeature::ENTRANCE_NORTH; + CHECK(map.getFeatures(1, 1) == test); + test[0].first = eMapFeature::ENTRANCE_SOUTH; + CHECK(map.getFeatures(2, 2) == test); + test[0].first = eMapFeature::ENTRANCE_WEST; + CHECK(map.getFeatures(3, 3) == test); + } + SECTION("With misc features") { + map.addFeature(0, 0, eMapFeature::SIGN); + map.addFeature(1, 1, eMapFeature::ITEM); + map.addFeature(2, 2, eMapFeature::CREATURE); + map.addFeature(3, 3, eMapFeature::SPECIAL_NODE); + map.addFeature(4, 4, eMapFeature::WANDERING); + in_and_out("misc", map, true); + test.emplace_back(make_pair(eMapFeature::SIGN, 0)); + CHECK(map.getFeatures(0, 0) == test); + test[0].first = eMapFeature::ITEM; + CHECK(map.getFeatures(1, 1) == test); + test[0].first = eMapFeature::CREATURE; + CHECK(map.getFeatures(2, 2) == test); + test[0].first = eMapFeature::SPECIAL_NODE; + CHECK(map.getFeatures(3, 3) == test); + test[0].first = eMapFeature::WANDERING; + CHECK(map.getFeatures(4, 4) == test); + } } TEST_CASE("Building map data") { @@ -172,4 +226,91 @@ TEST_CASE("Building map data") { CHECK(scen.horses[1].which_town == 0); } } + SECTION("With fields") { + scen.towns[0]->preset_fields.emplace_back(loc(0,0), FIELD_WEB); + scen.towns[0]->preset_fields.emplace_back(loc(1,1), OBJECT_BLOCK); + scen.towns[0]->preset_fields.emplace_back(loc(2,2), BARRIER_CAGE); + scen.towns[0]->preset_fields.emplace_back(loc(3,3), SPECIAL_SPOT); + in_and_out(scen, true); + REQUIRE(scen.towns[0]->preset_fields.size() == 4); + static const std::map check = { + {OBJECT_BLOCK, {1,1}}, {SPECIAL_SPOT, {3,3}}, {FIELD_WEB, {0,0}}, {BARRIER_CAGE, {2,2}}, + }; + set found; + for(const auto& fld : scen.towns[0]->preset_fields) { + if(found.count(fld.type)) + FAIL("Error: Two fields of the same type found!"); + found.insert(fld.type); + CAPTURE(fld.type); + CAPTURE(fld.loc); + CAPTURE(check.at(fld.type)); + CHECK(fld.loc == check.at(fld.type)); + } + if(found.size() != check.size()) + FAIL("Error: A field is missing!"); + } + SECTION("With town entrance") { + scen.outdoors[0][0]->city_locs.emplace_back(5, 6, 7); + in_and_out(scen, false); + REQUIRE(scen.outdoors[0][0]->city_locs.size() == 1); + CHECK(scen.outdoors[0][0]->city_locs[0] == loc(5,6)); + CHECK(scen.outdoors[0][0]->city_locs[0].spec == 7); + } + SECTION("With town entry points") { + int i = 0; + for(auto& start : scen.towns[0]->start_locs) { + start.x = i++; + start.y = i++; + } + in_and_out(scen, true); + i = 0; + for(const auto& start : scen.towns[0]->start_locs) { + CAPTURE(i); + CHECK(start == loc(i, i+1)); + i += 2; + } + } + SECTION("With placed special node") { + scen.towns[0]->special_locs.emplace_back(12, 13, 14); + in_and_out(scen, true); + REQUIRE(scen.towns[0]->special_locs.size() == 1); + CHECK(scen.towns[0]->special_locs[0] == loc(12,13)); + CHECK(scen.towns[0]->special_locs[0].spec == 14); + } + SECTION("With wandering arrival points") { + int i = 0; + for(auto& start : scen.towns[0]->wandering_locs) { + start.x = i++; + start.y = i++; + } + in_and_out(scen, true); + i = 0; + for(const auto& start : scen.towns[0]->wandering_locs) { + CAPTURE(i); + CHECK(start == loc(i, i+1)); + i += 2; + } + } + SECTION("With placed item") { + scen.towns[0]->preset_items.emplace_back(); + scen.towns[0]->preset_items[0].loc = {22,12}; + scen.towns[0]->preset_items[0].code = 1; + map_data map = buildTownMapData(0, scen); + std::vector> test = {{eMapFeature::ITEM, 0}}; + CHECK(map.getFeatures(22, 12) == test); + } + SECTION("With placed creature") { + scen.towns[0]->creatures.emplace_back(); + scen.towns[0]->creatures[0].start_loc = {9,18}; + scen.towns[0]->creatures[0].number = 1; + map_data map = buildTownMapData(0, scen); + std::vector> test = {{eMapFeature::CREATURE, 0}}; + CHECK(map.getFeatures(9, 18) == test); + } + SECTION("With a sign") { + scen.towns[0]->sign_locs.emplace_back(7,11," "); + map_data map = buildTownMapData(0, scen); + std::vector> test = {{eMapFeature::SIGN, 0}}; + CHECK(map.getFeatures(7, 11) == test); + } }