Test cases for reading terrain, monster, and item definitions

- For monster attacks, 'd4' now means '1d4' instead of '0d4', and simple numbers without a 'd' are not accepted
- Pop string path after pushing it in the shop test cases
This commit is contained in:
2015-07-29 15:25:19 -04:00
parent e9381f194e
commit 7719d62773
56 changed files with 659 additions and 14 deletions

View File

@@ -251,6 +251,9 @@
91D634560F8FD77800674AB3 /* BoE.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2B8F435C0C0973680012E4A8 /* BoE.icns */; };
91EF052C1904D099001BEF85 /* bold.ttf in Copy Fonts */ = {isa = PBXBuildFile; fileRef = 91EF05291904D082001BEF85 /* bold.ttf */; };
91EF052D1904D099001BEF85 /* plain.ttf in Copy Fonts */ = {isa = PBXBuildFile; fileRef = 91EF052A1904D082001BEF85 /* plain.ttf */; };
91EF27731B693D3900666469 /* ter_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91EF27721B693D3800666469 /* ter_read.cpp */; };
91EF27771B693D5500666469 /* item_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91EF27761B693D5500666469 /* item_read.cpp */; };
91EF277B1B693D6E00666469 /* monst_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91EF277A1B693D6E00666469 /* monst_read.cpp */; };
91F6F8E318F87F3700E3EA15 /* sfml-audio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8DD18F87F3700E3EA15 /* sfml-audio.framework */; };
91F6F8E418F87F3700E3EA15 /* sfml-audio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8DD18F87F3700E3EA15 /* sfml-audio.framework */; };
91F6F8E518F87F3700E3EA15 /* sfml-audio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8DD18F87F3700E3EA15 /* sfml-audio.framework */; };
@@ -764,6 +767,9 @@
91EC481018FBABB100BB1E86 /* prefs.mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = prefs.mac.mm; sourceTree = "<group>"; };
91EF05291904D082001BEF85 /* bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = bold.ttf; sourceTree = "<group>"; };
91EF052A1904D082001BEF85 /* plain.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = plain.ttf; sourceTree = "<group>"; };
91EF27721B693D3800666469 /* ter_read.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ter_read.cpp; sourceTree = "<group>"; };
91EF27761B693D5500666469 /* item_read.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = item_read.cpp; sourceTree = "<group>"; };
91EF277A1B693D6E00666469 /* monst_read.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = monst_read.cpp; sourceTree = "<group>"; };
91F06E8F1A2EBEE70038E902 /* special_parse.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = special_parse.hpp; sourceTree = "<group>"; };
91F6F8DD18F87F3700E3EA15 /* sfml-audio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "sfml-audio.framework"; path = "/Library/Frameworks/sfml-audio.framework"; sourceTree = "<absolute>"; };
91F6F8DE18F87F3700E3EA15 /* sfml-graphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "sfml-graphics.framework"; path = "/Library/Frameworks/sfml-graphics.framework"; sourceTree = "<absolute>"; };
@@ -1306,6 +1312,9 @@
91C763D81B4C4BB30086D879 /* enums.cpp */,
91C763DA1B4EE6E00086D879 /* map_read.cpp */,
91C763DC1B4EE7950086D879 /* map_write.cpp */,
91EF27721B693D3800666469 /* ter_read.cpp */,
91EF27761B693D5500666469 /* item_read.cpp */,
91EF277A1B693D6E00666469 /* monst_read.cpp */,
);
name = src;
sourceTree = "<group>";
@@ -1799,6 +1808,9 @@
91C763D91B4C50710086D879 /* enums.cpp in Sources */,
91C763DB1B4EE77F0086D879 /* map_read.cpp in Sources */,
91C763DD1B4EE7950086D879 /* map_write.cpp in Sources */,
91EF27731B693D3900666469 /* ter_read.cpp in Sources */,
91EF27771B693D5500666469 /* item_read.cpp in Sources */,
91EF277B1B693D6E00666469 /* monst_read.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -45,6 +45,9 @@ static bool load_scenario_v2(fs::path file_to_load, cScenario& scenario, bool on
// Some of these are non-static so that the test cases can access them.
ticpp::Document xmlDocFromStream(std::istream& stream, std::string name);
void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario);
void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario);
void readItemsFromXml(ticpp::Document&& data, cScenario& scenario);
void readMonstersFromXml(ticpp::Document&& data, cScenario& scenario);
void loadOutMapData(map_data&& data, location which, cScenario& scen);
void loadTownMapData(map_data&& data, int which, cScenario& scen);
@@ -899,7 +902,7 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
throw xMissingElem("scenario", *reqs.begin(), data.FirstChildElement()->Row(), data.FirstChildElement()->Column(), fname);
}
static void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario) {
void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario) {
using namespace ticpp;
int maj, min, rev;
std::string fname, type, name, val;
@@ -1014,7 +1017,7 @@ static void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario) {
}
}
static void readItemsFromXml(ticpp::Document&& data, cScenario& scenario) {
void readItemsFromXml(ticpp::Document&& data, cScenario& scenario) {
using namespace ticpp;
int maj, min, rev;
std::string fname, type, name, val;
@@ -1090,20 +1093,22 @@ static void readItemsFromXml(ticpp::Document&& data, cScenario& scenario) {
Iterator<Element> prop;
for(prop = prop.begin(item.Get()); prop != prop.end(); prop++) {
prop->GetValue(&type);
prop->GetText(&val);
bool state = val == "true";
auto state = [&prop,&val]() -> bool {
prop->GetText(&val);
return val == "true";
};
if(type == "identified") {
the_item.ident = state;
the_item.ident = state();
} else if(type == "magic") {
the_item.magic = state;
the_item.magic = state();
} else if(type == "cursed") {
the_item.cursed = state;
the_item.cursed = state();
} else if(type == "concealed") {
the_item.concealed = state;
the_item.concealed = state();
} else if(type == "enchanted") {
the_item.enchanted = state;
the_item.enchanted = state();
} else if(type == "unsellable") {
the_item.unsellable = state;
the_item.unsellable = state();
} else throw xBadNode(type, prop->Row(), prop->Column(), fname);
}
} else if(type == "description") {
@@ -1130,10 +1135,14 @@ static std::pair<int,int> parseDice(std::string str, std::string elem, std::stri
count *= 10;
count += c - '0';
}
} else if(!found_d && c == 'd')
} else if(!found_d && c == 'd') {
found_d = true;
if(count == 0) count = 1;
}
else throw xBadVal(elem, attr, str, row, col, fname);
}
if(!found_d)
throw xBadVal(elem, attr, str, row, col, fname);
return {count, sides};
}
@@ -1291,7 +1300,7 @@ static void readMonstAbilFromXml(ticpp::Element& data, cMonster& monst) {
}
}
static void readMonstersFromXml(ticpp::Document&& data, cScenario& scenario) {
void readMonstersFromXml(ticpp::Document&& data, cScenario& scenario) {
using namespace ticpp;
int maj, min, rev;
std::string fname, type, name, val;

View File

@@ -0,0 +1,7 @@
<items boes="2.0.0">
<item id='0'>
<ability>
<type>bad</type>
</ability>
</item>
</items>

View File

@@ -0,0 +1,7 @@
<items boes="2.0.0">
<item id='0'>
<ability>
<bad></bad>
</ability>
</item>
</items>

View File

@@ -0,0 +1,7 @@
<items boes="2.0.0">
<item id='0'>
<properties>
<bad></bad>
</properties>
</item>
</items>

View File

@@ -0,0 +1 @@
<items vers="2.0.0"></items>

View File

@@ -0,0 +1,5 @@
<items boes="2.0.0">
<item id='0'>
<bad></bad>>
</item>
</items>

View File

@@ -0,0 +1 @@
<items boes="2.0.0"><obj></obj></items>

View File

@@ -0,0 +1,5 @@
<items boes="2.0.0">
<item id='0'>
<variety>bad</variety>
</item>
</items>

View File

@@ -0,0 +1,7 @@
<items boes="2.0.0">
<item id='0'>
<ability>
<use-flag>bad</use-flag>
</ability>
</item>
</items>

View File

@@ -0,0 +1,5 @@
<items boes="2.0.0">
<item id='0'>
<weapon-type>bad</weapon-type>
</item>
</items>

View File

@@ -0,0 +1,11 @@
<items boes="2.0.0">
<item id='0'>
<variety>weapon-1hand</variety>
<level>3</level>
<pic>0</pic>
<value>100</value>
<weight>10</weight>
<full-name>Test Sword</full-name>
<name>Sword</name>
</item>
</items>

View File

@@ -0,0 +1,5 @@
<items boes="2.0.0">
<item id='0'>
<ability></ability>
</item>
</items>

View File

@@ -0,0 +1 @@
<items boes="2.0.0"><item></item></items>

View File

@@ -0,0 +1 @@
<items boes="2.0.0"><item id='0'></item></items>

View File

@@ -0,0 +1 @@
<items></items>

View File

@@ -0,0 +1,19 @@
<monsters boes="2.0.0">
<monster id='1'>
<name>Test Monster</name>
<level>1</level>
<armor>0</armor>
<skill>1</skill>
<hp>10</hp>
<speed>4</speed>
<race>humanoid</race>
<attacks>
<attack type='swing'>d10</attack>
<attack type='punch'>2d4</attack>
<attack type='burn'>1d8</attack>
</attacks>
<pic h='1' w='1'>0</pic>
<attitude>hostile-a</attitude>
<immunity/>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<attack type='swing'>bad</attack>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<attack type='swing'>100</attack>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<attack kind='bad'>1d4</attack>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<bad/>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<attack type='bad'>1d4</attack>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1 @@
<monsters boes="2.0.0"><monster id='0'></monster></monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<immunity>
<unholy>50</unholy>
</immunity>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<loot>
<bad/>
</loot>
</monster>
</monsters>

View File

@@ -0,0 +1,5 @@
<monsters boes="2.0.0">
<monster id='1'>
<loot/>
</monster>
</monsters>

View File

@@ -0,0 +1,5 @@
<monsters boes="2.0.0">
<monster id='1'>
<pic>5</pic>
</monster>
</monsters>

View File

@@ -0,0 +1,5 @@
<monsters boes="2.0.0">
<monster id='1'>
<pic h='1' v='1'>5</pic>
</monster>
</monsters>

View File

@@ -0,0 +1 @@
<monsters vers="2.0.0"></monsters>

View File

@@ -0,0 +1,5 @@
<monsters boes="2.0.0">
<monster id='1'>
<bad></bad>>
</monster>
</monsters>

View File

@@ -0,0 +1 @@
<monsters boes="2.0.0"><monst></monst></monsters>

View File

@@ -0,0 +1,15 @@
<monsters boes="2.0.0">
<monster id='1'>
<name>Test Monster</name>
<level>1</level>
<armor>0</armor>
<skill>2</skill>
<hp>10</hp>
<speed>4</speed>
<race>humanoid</race>
<attacks/>
<pic h='1' w='1'>5</pic>
<attitude>hostile-a</attitude>
<immunity/>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<attack>1d4</attack>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1 @@
<monsters boes="2.0.0"><monster></monster></monsters>

View File

@@ -0,0 +1 @@
<monsters boes="2.0.0"><monster id='1'></monster></monsters>

View File

@@ -0,0 +1 @@
<monsters></monsters>

View File

@@ -0,0 +1,10 @@
<monsters boes="2.0.0">
<monster id='1'>
<attacks>
<attack type='swing'>1d4</attack>
<attack type='swing'>1d4</attack>
<attack type='swing'>1d4</attack>
<attack type='swing'>1d4</attack>
</attacks>
</monster>
</monsters>

View File

@@ -0,0 +1,7 @@
<terrains boes="2.0.0">
<terrain id='0'>
<special>
<type>bad</type>
</special>
</terrain>
</terrains>

View File

@@ -0,0 +1,7 @@
<terrains boes="2.0.0">
<terrain id='0'>
<special>
<bad></bad>
</special>
</terrain>
</terrains>

View File

@@ -0,0 +1,5 @@
<terrains boes="2.0.0">
<terrain id='0'>
<blockage>bad</blockage>
</terrain>
</terrains>

View File

@@ -0,0 +1 @@
<terrains vers="2.0.0"></terrains>

View File

@@ -0,0 +1,5 @@
<terrains boes="2.0.0">
<terrain id='0'>
<bad></bad>
</terrain>
</terrains>

View File

@@ -0,0 +1 @@
<terrains boes="2.0.0"><ter></ter></terrains>

View File

@@ -0,0 +1,5 @@
<terrains boes="2.0.0">
<terrain id='0'>
<trim>bad</trim>
</terrain>
</terrains>

View File

@@ -0,0 +1,13 @@
<terrains boes="2.0.0">
<terrain id='0'>
<name>Test Terrain</name>
<pic>0</pic>
<map>0</map>
<blockage>move</blockage>
<trim>none</trim>
<arena>0</arena>
<special>
<type>none</type>
</special>
</terrain>
</terrains>

View File

@@ -0,0 +1,5 @@
<terrains boes="2.0.0">
<terrain id='0'>
<special></special>
</terrain>
</terrains>

View File

@@ -0,0 +1 @@
<terrains boes="2.0.0"><terrain></terrain></terrains>

View File

@@ -0,0 +1 @@
<terrains boes="2.0.0"><terrain id='0'></terrain></terrains>

View File

@@ -0,0 +1 @@
<terrains></terrains>

View File

@@ -0,0 +1,11 @@
<terrains boes="2.0.0">
<terrain id='0'>
<special>
<type>none</type>
<flag>0</flag>
<flag>0</flag>
<flag>0</flag>
<flag>0</flag>
</special>
</terrain>
</terrains>

110
test/item_read.cpp Normal file
View File

@@ -0,0 +1,110 @@
//
// item_read.cpp
// BoE
//
// Created by Celtic Minstrel on 15-07-29.
//
//
#include <fstream>
#include "ticpp.h"
#include "catch.hpp"
#include "dialog.hpp"
#include "scenario.hpp"
using namespace std;
using namespace ticpp;
extern Document xmlDocFromStream(istream& stream, string name);
extern void readItemsFromXml(Document&& data, cScenario& scenario);
TEST_CASE("Loading an item type definition") {
ifstream fin;
cScenario scen;
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(readItemsFromXml(move(doc), scen), xBadNode);
}
SECTION("When the version attribute is missing") {
fin.open("files/items/no_version.xml");
doc = xmlDocFromStream(fin, "no_version.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xMissingAttr);
}
SECTION("When the root tag has a bad attribute") {
fin.open("files/items/bad_root_attr.xml");
doc = xmlDocFromStream(fin, "bad_root_attr.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xBadAttr);
}
SECTION("When an unknown toplevel tag appears") {
fin.open("files/items/bad_toplevel.xml");
doc = xmlDocFromStream(fin, "bad_toplevel.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xBadNode);
}
SECTION("When the ID attribute is missing") {
fin.open("files/items/missing_id.xml");
doc = xmlDocFromStream(fin, "missing_id.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), Exception);
}
SECTION("When a required subtag is missing") {
fin.open("files/items/missing_req.xml");
doc = xmlDocFromStream(fin, "missing_req.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xMissingElem);
}
SECTION("When a bad subtag is found") {
fin.open("files/items/bad_tag.xml");
doc = xmlDocFromStream(fin, "bad_tag.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xBadNode);
}
SECTION("When an unknown property is found") {
fin.open("files/items/bad_prop.xml");
doc = xmlDocFromStream(fin, "bad_prop.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xBadNode);
}
SECTION("When the variety is invalid") {
fin.open("files/items/bad_type.xml");
doc = xmlDocFromStream(fin, "bad_type.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), Exception);
}
SECTION("When the weapon key skill is invalid") {
fin.open("files/items/bad_weapon.xml");
doc = xmlDocFromStream(fin, "bad_weapon.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), Exception);
}
SECTION("When the special ability is missing a required subtag") {
fin.open("files/items/missing_abil.xml");
doc = xmlDocFromStream(fin, "missing_abil.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xMissingElem);
}
SECTION("When the special ability is invalid") {
fin.open("files/items/bad_abil.xml");
doc = xmlDocFromStream(fin, "bad_abil.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), Exception);
}
SECTION("When the special ability has an invalid subtag") {
fin.open("files/items/bad_abil_tag.xml");
doc = xmlDocFromStream(fin, "bad_abil_tag.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), xBadNode);
}
SECTION("When the special ability has an invalid use flag") {
fin.open("files/items/bad_use.xml");
doc = xmlDocFromStream(fin, "bad_use.xml");
REQUIRE_THROWS_AS(readItemsFromXml(move(doc), scen), Exception);
}
SECTION("With the minimal required data") {
fin.open("files/items/minimal.xml");
doc = xmlDocFromStream(fin, "minimal.xml");
REQUIRE_NOTHROW(readItemsFromXml(move(doc), scen));
REQUIRE(scen.scen_items.size() >= 1);
CHECK(scen.scen_items[0].full_name == "Test Sword");
CHECK(scen.scen_items[0].name == "Sword");
CHECK(scen.scen_items[0].variety == eItemType::ONE_HANDED);
CHECK(scen.scen_items[0].item_level == 3);
CHECK(scen.scen_items[0].graphic_num == 0);
CHECK(scen.scen_items[0].value == 100);
CHECK(scen.scen_items[0].weight == 10);
}
}

154
test/monst_read.cpp Normal file
View File

@@ -0,0 +1,154 @@
//
// monst_read.cpp
// BoE
//
// Created by Celtic Minstrel on 15-07-29.
//
//
#include <fstream>
#include "ticpp.h"
#include "catch.hpp"
#include "dialog.hpp"
#include "scenario.hpp"
using namespace std;
using namespace ticpp;
extern Document xmlDocFromStream(istream& stream, string name);
extern void readMonstersFromXml(Document&& data, cScenario& scenario);
TEST_CASE("Loading a monster type definition") {
ifstream fin;
cScenario scen;
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(readMonstersFromXml(move(doc), scen), xBadNode);
}
SECTION("When the version attribute is missing") {
fin.open("files/monsters/no_version.xml");
doc = xmlDocFromStream(fin, "no_version.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xMissingAttr);
}
SECTION("When the root tag has a bad attribute") {
fin.open("files/monsters/bad_root_attr.xml");
doc = xmlDocFromStream(fin, "bad_root_attr.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadAttr);
}
SECTION("When an unknown toplevel tag appears") {
fin.open("files/monsters/bad_toplevel.xml");
doc = xmlDocFromStream(fin, "bad_toplevel.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadNode);
}
SECTION("When the ID attribute is missing") {
fin.open("files/monsters/missing_id.xml");
doc = xmlDocFromStream(fin, "missing_id.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), Exception);
}
SECTION("When the ID attribute is zero") {
fin.open("files/monsters/bad_id.xml");
doc = xmlDocFromStream(fin, "missing_id.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadVal);
}
SECTION("When a required subtag is missing") {
fin.open("files/monsters/missing_req.xml");
doc = xmlDocFromStream(fin, "missing_req.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xMissingElem);
}
SECTION("When a bad subtag is found") {
fin.open("files/monsters/bad_tag.xml");
doc = xmlDocFromStream(fin, "bad_tag.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadNode);
}
SECTION("When an attack has a bad subtag") {
fin.open("files/monsters/bad_attack_tag.xml");
doc = xmlDocFromStream(fin, "bad_attack_tag.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadNode);
}
SECTION("When an attack has a bad attribute") {
fin.open("files/monsters/bad_attack_attr.xml");
doc = xmlDocFromStream(fin, "bad_attack_attr.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadAttr);
}
SECTION("When an attack has a bad type") {
fin.open("files/monsters/bad_attack_type.xml");
doc = xmlDocFromStream(fin, "bad_attack_type.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), Exception);
}
SECTION("When an attack damage is invalid") {
fin.open("files/monsters/bad_attack.xml");
doc = xmlDocFromStream(fin, "bad_attack.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadVal);
}
SECTION("When an attack damage is missing 'd'") {
fin.open("files/monsters/bad_attack2.xml");
doc = xmlDocFromStream(fin, "bad_attack2.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadVal);
}
SECTION("When an attack is missing the type") {
fin.open("files/monsters/missing_attack_type.xml");
doc = xmlDocFromStream(fin, "missing_attack_type.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xMissingAttr);
}
SECTION("When the picture is missing the size attributes") {
fin.open("files/monsters/bad_pic.xml");
doc = xmlDocFromStream(fin, "bad_pic.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xMissingAttr);
}
SECTION("When the picture has a bad attribute") {
fin.open("files/monsters/bad_pic2.xml");
doc = xmlDocFromStream(fin, "bad_pic2.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadAttr);
}
SECTION("When there is a bad immunity") {
fin.open("files/monsters/bad_immune.xml");
doc = xmlDocFromStream(fin, "bad_immune.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadNode);
}
SECTION("When the loot has a bad subtag") {
fin.open("files/monsters/bad_loot.xml");
doc = xmlDocFromStream(fin, "bad_loot.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xBadNode);
}
SECTION("When the loot has a missing subtag") {
fin.open("files/monsters/bad_loot2.xml");
doc = xmlDocFromStream(fin, "bad_loot2.xml");
REQUIRE_THROWS_AS(readMonstersFromXml(move(doc), scen), xMissingElem);
}
SECTION("With the minimal required data") {
fin.open("files/monsters/minimal.xml");
doc = xmlDocFromStream(fin, "minimal.xml");
REQUIRE_NOTHROW(readMonstersFromXml(move(doc), scen));
REQUIRE(scen.scen_monsters.size() >= 2);
CHECK(scen.scen_monsters[1].m_name == "Test Monster");
CHECK(scen.scen_monsters[1].level == 1);
CHECK(scen.scen_monsters[1].armor == 0);
CHECK(scen.scen_monsters[1].skill == 2);
CHECK(scen.scen_monsters[1].m_health == 10);
CHECK(scen.scen_monsters[1].speed == 4);
CHECK(scen.scen_monsters[1].m_type == eRace::HUMANOID);
CHECK(scen.scen_monsters[1].picture_num == 5);
CHECK(scen.scen_monsters[1].x_width == 1);
CHECK(scen.scen_monsters[1].y_width == 1);
CHECK(scen.scen_monsters[1].default_attitude == eAttitude::HOSTILE_A);
}
SECTION("With some attacks") {
fin.open("files/monsters/attacks.xml");
doc = xmlDocFromStream(fin, "attacks.xml");
REQUIRE_NOTHROW(readMonstersFromXml(move(doc), scen));
REQUIRE(scen.scen_monsters.size() >= 2);
CHECK(scen.scen_monsters[1].a[0].type == eMonstMelee::SWING);
CHECK(scen.scen_monsters[1].a[0].dice == 1);
CHECK(scen.scen_monsters[1].a[0].sides == 10);
CHECK(scen.scen_monsters[1].a[1].type == eMonstMelee::PUNCH);
CHECK(scen.scen_monsters[1].a[1].dice == 2);
CHECK(scen.scen_monsters[1].a[1].sides == 4);
CHECK(scen.scen_monsters[1].a[2].type == eMonstMelee::BURN);
CHECK(scen.scen_monsters[1].a[2].dice == 1);
CHECK(scen.scen_monsters[1].a[2].sides == 8);
}
}

View File

@@ -19,8 +19,8 @@ TEST_CASE("Loading a new-format scenario record") {
Document doc;
fin.exceptions(ios::badbit);
SECTION("When the version attribute is missing") {
fin.open("files/scenario/bad_root.xml");
SECTION("When the root tag is wrong") {
fin.open("files/bad_root.xml");
doc = xmlDocFromStream(fin, "bad_root.xml");
REQUIRE_THROWS_AS(readScenarioFromXml(move(doc), scen), xBadNode);
}
@@ -326,5 +326,6 @@ TEST_CASE("Loading a new-format scenario record") {
doc = xmlDocFromStream(fin, "shop-bad_entry.xml");
REQUIRE_THROWS_AS(readScenarioFromXml(move(doc), scen), xBadNode);
}
ResMgr::popPath<StringRsrc>();
}
}

View File

@@ -248,6 +248,7 @@ TEST_CASE("Saving a scenario record") {
CHECK(scen.shops[2].getItem(11).item.graphic_num == 24);
CHECK(scen.shops[2].getItem(11).item.full_name == "Magic!");
CHECK(scen.shops[2].getItem(11).item.desc == "This is magic!");
ResMgr::popPath<StringRsrc>();
}
SECTION("With some empty strings, only trailing ones are stripped") {
scen.spec_strs.resize(12);

105
test/ter_read.cpp Normal file
View File

@@ -0,0 +1,105 @@
//
// ter_read.cpp
// BoE
//
// Created by Celtic Minstrel on 15-07-29.
//
//
#include <fstream>
#include "ticpp.h"
#include "catch.hpp"
#include "dialog.hpp"
#include "scenario.hpp"
using namespace std;
using namespace ticpp;
extern Document xmlDocFromStream(istream& stream, string name);
extern void readTerrainFromXml(Document&& data, cScenario& scenario);
TEST_CASE("Loading a terrain type definition") {
ifstream fin;
cScenario scen;
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(readTerrainFromXml(move(doc), scen), xBadNode);
}
SECTION("When the version attribute is missing") {
fin.open("files/terrain/no_version.xml");
doc = xmlDocFromStream(fin, "no_version.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xMissingAttr);
}
SECTION("When the root tag has a bad attribute") {
fin.open("files/terrain/bad_root_attr.xml");
doc = xmlDocFromStream(fin, "bad_root_attr.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xBadAttr);
}
SECTION("When an unknown toplevel tag appears") {
fin.open("files/terrain/bad_toplevel.xml");
doc = xmlDocFromStream(fin, "bad_toplevel.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xBadNode);
}
SECTION("When the ID attribute is missing") {
fin.open("files/terrain/missing_id.xml");
doc = xmlDocFromStream(fin, "missing_id.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), Exception);
}
SECTION("When a required subtag is missing") {
fin.open("files/terrain/missing_req.xml");
doc = xmlDocFromStream(fin, "missing_req.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xMissingElem);
}
SECTION("When an invalid subtag is found") {
fin.open("files/terrain/bad_tag.xml");
doc = xmlDocFromStream(fin, "bad_tag.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xBadNode);
}
SECTION("When the blockage type is invalid") {
fin.open("files/terrain/bad_block.xml");
doc = xmlDocFromStream(fin, "bad_block.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), Exception);
}
SECTION("When the trim type is invalid") {
fin.open("files/terrain/bad_trim.xml");
doc = xmlDocFromStream(fin, "bad_trim.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), Exception);
}
SECTION("When the special ability type is missing") {
fin.open("files/terrain/missing_abil.xml");
doc = xmlDocFromStream(fin, "missing_abil.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xMissingElem);
}
SECTION("When the special ability type is invalid") {
fin.open("files/terrain/bad_abil.xml");
doc = xmlDocFromStream(fin, "bad_abil.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), Exception);
}
SECTION("When there are too many special ability flags") {
fin.open("files/terrain/too_many_flags.xml");
doc = xmlDocFromStream(fin, "too_many_flags.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xBadNode);
}
SECTION("When the special ability has an invalid subtag") {
fin.open("files/terrain/bad_abil_tag.xml");
doc = xmlDocFromStream(fin, "bad_abil_tag.xml");
REQUIRE_THROWS_AS(readTerrainFromXml(move(doc), scen), xBadNode);
}
SECTION("With the minimal required data") {
fin.open("files/terrain/minimal.xml");
doc = xmlDocFromStream(fin, "minimal.xml");
REQUIRE_NOTHROW(readTerrainFromXml(move(doc), scen));
REQUIRE(scen.ter_types.size() >= 1);
CHECK(scen.ter_types[0].name == "Test Terrain");
CHECK(scen.ter_types[0].picture == 0);
CHECK(scen.ter_types[0].map_pic == 0);
CHECK(scen.ter_types[0].combat_arena == 0);
CHECK(scen.ter_types[0].blockage == eTerObstruct::BLOCK_MOVE);
CHECK(scen.ter_types[0].trim_type == eTrimType::NONE);
CHECK(scen.ter_types[0].special == eTerSpec::NONE);
}
}