From dd78205ce81a390afd3f924cb11a28020e9f6b8d Mon Sep 17 00:00:00 2001 From: beegee1 Date: Mon, 22 Apr 2013 14:49:28 +0000 Subject: [PATCH] -Added test subfolder and updated CMakeLists for unit testing - Added a test case for the DrawTerrainOperation class(does not pass all tests successfully, 6 failures left to fix) - Fixed a few bugs --- CMakeLists.txt | 8 ++ config/terrainViewPatterns.json | 69 ++++++++++---- lib/logging/CLogger.h | 4 +- lib/mapping/CMapEditManager.cpp | 124 +++++++++++++++++++----- lib/mapping/CMapEditManager.h | 71 ++++++++------ lib/rmg/CMapGenerator.cpp | 5 +- lib/rmg/CMapGenerator.h | 2 +- test/CMakeLists.txt | 27 ++++++ test/CMapEditManagerTest.cpp | 83 ++++++++++++++++ test/CVcmiTestConfig.cpp | 37 ++++++++ test/CVcmiTestConfig.h | 20 ++++ test/StdInc.cpp | 7 ++ test/StdInc.h | 8 ++ test/TerrainViewTest.h3m | Bin 0 -> 4223 bytes test/terrainViewMappings.json | 161 ++++++++++++++++++++++++++++++++ 15 files changed, 554 insertions(+), 72 deletions(-) create mode 100644 test/CMakeLists.txt create mode 100644 test/CMapEditManagerTest.cpp create mode 100644 test/CVcmiTestConfig.cpp create mode 100644 test/CVcmiTestConfig.h create mode 100644 test/StdInc.cpp create mode 100644 test/StdInc.h create mode 100644 test/TerrainViewTest.h3m create mode 100644 test/terrainViewMappings.json diff --git a/CMakeLists.txt b/CMakeLists.txt index be0145e47..48a61b3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set(VCMI_VERSION_PATCH 0) option(DISABLE_ERM "Disable compilation of ERM scripting module" ON) option(ENABLE_EDITOR "Enable compilation of map editor" OFF) +option(ENABLE_TEST "Enable compilation of unit tests" OFF) ############################################ # Building section # @@ -56,6 +57,10 @@ if (ENABLE_EDITOR) find_package(Qt5Widgets REQUIRED) endif() +if(ENABLE_TEST) + find_package(Boost 1.46.0 COMPONENTS unit_test_framework REQUIRED) +endif() + if(NOT WIN32) set(FFmpeg_FIND_COMPONENTS AVFORMAT SWSCALE) find_package(FFmpeg REQUIRED) @@ -125,6 +130,9 @@ endif() if (ENABLE_EDITOR) add_subdirectory(editor) endif() +if(ENABLE_TEST) + add_subdirectory(test) +endif() ####################################### # Installation section # diff --git a/config/terrainViewPatterns.json b/config/terrainViewPatterns.json index 262d366b1..666b30a2e 100644 --- a/config/terrainViewPatterns.json +++ b/config/terrainViewPatterns.json @@ -45,6 +45,7 @@ [ // Standard transitions { + "id" : "s1", "data" : [ "?", "?", "T", @@ -54,6 +55,7 @@ "mapping" : "0-3, 20-23" }, { + "id" : "s2", "data" : [ "?", "N", "N", @@ -63,6 +65,7 @@ "mapping" : "4-7, 24-27" }, { + "id" : "s3", "data" : [ "?", "T", "?", @@ -72,6 +75,7 @@ "mapping" : "8-11, 28-31" }, { + "id" : "s4", "data" : [ "N", "N", "N", @@ -81,28 +85,30 @@ "mapping" : "12-15, 32-35" }, { + "id" : "s5", "data" : [ - "T", "T", "a-1,?", + "T", "T", "s5-1,?", "T", "N", "N", - "a-1,?", "N", "N" + "s5-1,?", "N", "N" ], "mapping" : "16-17, 36-37", - "id" : "a", "minPoints" : 1 }, { + "id" : "s6", "data" : [ "N", "N", "N", - "N", "N", "a-1,N", - "N", "a-1,N", "T" + "N", "N", "s5-1,N", + "N", "s5-1,N", "T" ], "mapping" : "18-19, 38-39", "minPoints" : 1 }, // Mixed transitions { + "id" : "m1", "data" : [ "T", "N", "N", @@ -112,6 +118,7 @@ "mapping" : "40, 42" }, { + "id" : "m2", "data" : [ "D", "N", "N", @@ -121,6 +128,7 @@ "mapping" : "41" }, { + "id" : "m3", "data" : [ "N", "N", "D,N", @@ -130,6 +138,7 @@ "mapping" : "43" }, { + "id" : "m4", "data" : [ "N", "N", "S", @@ -139,6 +148,7 @@ "mapping" : "44" }, { + "id" : "m5", "data" : [ "N", "N", "D,N", @@ -148,6 +158,7 @@ "mapping" : "45" }, { + "id" : "m6", "data" : [ "N", "N", "N", @@ -157,6 +168,7 @@ "mapping" : "46" }, { + "id" : "m7", "data" : [ "N", "N", "D,S,N", @@ -166,6 +178,7 @@ "mapping" : "47" }, { + "id" : "m8", "data" : [ "N", "N", "D", @@ -176,6 +189,7 @@ }, // No transition { + "id" : "n1", "data" : [ "N", "N", "N", @@ -189,6 +203,7 @@ [ // Standard transitions { + "id" : "s1", "data" : [ "?", "S", "S", @@ -198,6 +213,7 @@ "mapping" : "0-3" }, { + "id" : "s2", "data" : [ "?", "D", "D", @@ -207,6 +223,7 @@ "mapping" : "4-7" }, { + "id" : "s3", "data" : [ "?", "S", "?", @@ -216,6 +233,7 @@ "mapping" : "8-11" }, { + "id" : "s4", "data" : [ "D", "D", "D", @@ -225,29 +243,30 @@ "mapping" : "12-15" }, { + "id" : "s5", "data" : [ "S", "S", "D", - "S", "N", "b-1,D", - "D", "b-1,D", "D" + "S", "N", "s6-1,D", + "D", "s6-1,D", "D" ], "mapping" : "16-17", - "id" : "a", "minPoints" : 1 }, { + "id" : "s6", "data" : [ "D", "D", "D", - "D", "N", "a-1,D", - "D", "a-1,D", "S" + "D", "N", "s5-1,D", + "D", "s5-1,D", "S" ], "mapping" : "18-19", - "id" : "b", "minPoints" : 1 }, // Mixed transition { + "id" : "m1", "data" : [ "S", "D", "D", @@ -258,6 +277,7 @@ }, // No transition { + "id" : "n1", "data" : [ "D", "D", "D", @@ -270,6 +290,7 @@ "sand" : [ { + "id" : "n1", "data" : [ "?", "?", "?", @@ -283,6 +304,7 @@ [ // Standard transitions { + "id" : "s1", "data" : [ "S", "S", "S", @@ -292,6 +314,7 @@ "mapping" : "0-3" }, { + "id" : "s2", "data" : [ "?", "N", "N", @@ -301,6 +324,7 @@ "mapping" : "4-7" }, { + "id" : "s3", "data" : [ "?", "S", "?", @@ -310,6 +334,7 @@ "mapping" : "8-11" }, { + "id" : "s4", "data" : [ "N", "N", "N", @@ -319,6 +344,7 @@ "mapping" : "12-15" }, { + "id" : "s5", "data" : [ "S", "S", "N", @@ -326,20 +352,21 @@ "N", "N", "N" ], "mapping" : "16-17", - "id" : "a" }, { + "id" : "s6", "data" : [ "N", "N", "N", - "N", "N", "a-1,N", - "N", "a-1,N", "S" + "N", "N", "s5-1,N", + "N", "s5-1,N", "S" ], "mapping" : "18-19", "minPoints" : 1 }, // No transition { + "id" : "n1", "data" : [ "N", "N", "N", @@ -353,6 +380,7 @@ [ // No transition { + "id" : "n1", "data" : [ "N", "N", "N", @@ -363,6 +391,7 @@ }, // Standard transitions { + "id" : "s1", "data" : [ "?", "S", "?", @@ -373,6 +402,7 @@ "flipMode" : "diffImages" }, { + "id" : "s2", "data" : [ "?", "N", "N", @@ -383,6 +413,7 @@ "flipMode" : "diffImages" }, { + "id" : "s3", "data" : [ "?", "S", "?", @@ -393,6 +424,7 @@ "flipMode" : "diffImages" }, { + "id" : "s4", "data" : [ "N", "N", "N", @@ -403,6 +435,7 @@ "flipMode" : "diffImages" }, { + "id" : "s5", "data" : [ "S", "S", "N", @@ -410,15 +443,15 @@ "N", "N", "N" ], "mapping" : "32-39", - "flipMode" : "diffImages", - "id" : "a" + "flipMode" : "diffImages" }, { + "id" : "s6", "data" : [ "N", "N", "N", - "N", "N", "a-1,N", - "N", "a-1,N", "S" + "N", "N", "s5-1,N", + "N", "s5-1,N", "S" ], "mapping" : "40-47", "flipMode" : "diffImages", diff --git a/lib/logging/CLogger.h b/lib/logging/CLogger.h index 72f4b0cea..14c60b3fe 100644 --- a/lib/logging/CLogger.h +++ b/lib/logging/CLogger.h @@ -258,7 +258,7 @@ public: const CColorMapping & getColorMapping() const; void setColorMapping(const CColorMapping & colorMapping); - void write(const LogRecord & record); + void write(const LogRecord & record) override; private: CConsoleHandler * console; @@ -281,7 +281,7 @@ public: const CLogFormatter & getFormatter() const; void setFormatter(const CLogFormatter & formatter); - void write(const LogRecord & record); + void write(const LogRecord & record) override; private: std::ofstream file; diff --git a/lib/mapping/CMapEditManager.cpp b/lib/mapping/CMapEditManager.cpp index 89e20551f..cf4f66b95 100644 --- a/lib/mapping/CMapEditManager.cpp +++ b/lib/mapping/CMapEditManager.cpp @@ -5,6 +5,77 @@ #include "../filesystem/CResourceLoader.h" #include "../CDefObjInfoHandler.h" +MapRect::MapRect() : x(0), y(0), z(0), width(0), height(0) +{ + +} + +MapRect::MapRect(int3 pos, si32 width, si32 height) : x(pos.x), y(pos.y), z(pos.z), width(width), height(height) +{ + +} + +MapRect MapRect::operator&(const MapRect & rect) const +{ + bool intersect = right() > rect.left() && rect.right() > left() && + bottom() > rect.top() && rect.bottom() > top() && + z == rect.z; + if(intersect) + { + MapRect ret; + ret.x = std::max(left(), rect.left()); + ret.y = std::max(top(), rect.top()); + ret.z = rect.z; + ret.width = std::min(right(), rect.right()) - ret.x; + ret.height = std::min(bottom(), rect.bottom()) - ret.y; + return ret; + } + else + { + return MapRect(); + } +} + +si32 MapRect::left() const +{ + return x; +} + +si32 MapRect::right() const +{ + return x + width; +} + +si32 MapRect::top() const +{ + return y; +} + +si32 MapRect::bottom() const +{ + return y + height; +} + +int3 MapRect::topLeft() const +{ + return int3(x, y, z); +} + +int3 MapRect::topRight() const +{ + return int3(right(), y, z); +} + +int3 MapRect::bottomLeft() const +{ + return int3(x, bottom(), z); +} + +int3 MapRect::bottomRight() const +{ + return int3(right(), bottom(), z); +} + CMapOperation::CMapOperation(CMap * map) : map(map) { @@ -181,12 +252,11 @@ CTerrainViewPatternConfig & CTerrainViewPatternConfig::get() CTerrainViewPatternConfig::CTerrainViewPatternConfig() { const JsonNode config(ResourceID("config/terrainViewPatterns.json")); - const std::map terGroups - = boost::assign::map_list_of("normal", ETerrainGroup::NORMAL)("dirt", ETerrainGroup::DIRT) - ("sand", ETerrainGroup::SAND)("water", ETerrainGroup::WATER)("rock", ETerrainGroup::ROCK); - BOOST_FOREACH(auto terMapping, terGroups) + const auto & groupMap = config.Struct(); + BOOST_FOREACH(const auto & groupPair, groupMap) { - BOOST_FOREACH(const JsonNode & ptrnNode, config[terMapping.first].Vector()) + auto terGroup = getTerrainGroup(groupPair.first); + BOOST_FOREACH(const JsonNode & ptrnNode, groupPair.second.Vector()) { TerrainViewPattern pattern; @@ -238,8 +308,8 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() pattern.flipMode = TerrainViewPattern::FLIP_MODE_SAME_IMAGE; } - pattern.terGroup = terMapping.second; - patterns[terMapping.second].push_back(pattern); + pattern.terGroup = terGroup; + patterns[terGroup].push_back(pattern); } } } @@ -249,6 +319,17 @@ CTerrainViewPatternConfig::~CTerrainViewPatternConfig() } +ETerrainGroup::ETerrainGroup CTerrainViewPatternConfig::getTerrainGroup(const std::string & terGroup) const +{ + static const std::map terGroups + = boost::assign::map_list_of("normal", ETerrainGroup::NORMAL)("dirt", ETerrainGroup::DIRT) + ("sand", ETerrainGroup::SAND)("water", ETerrainGroup::WATER)("rock", ETerrainGroup::ROCK); + auto it = terGroups.find(terGroup); + if(it == terGroups.end()) throw std::runtime_error(boost::str(boost::format("Terrain group '%s' does not exist.") % terGroup)); + return it->second; +} + + const std::vector & CTerrainViewPatternConfig::getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const { return patterns.find(terGroup)->second; @@ -275,18 +356,19 @@ DrawTerrainOperation::DrawTerrainOperation(CMap * map, const MapRect & rect, ETe void DrawTerrainOperation::execute() { - for(int i = rect.pos.x; i < rect.pos.x + rect.width; ++i) + for(int i = rect.x; i < rect.x + rect.width; ++i) { - for(int j = rect.pos.y; j < rect.pos.y + rect.height; ++j) + for(int j = rect.y; j < rect.y + rect.height; ++j) { - map->getTile(int3(i, j, rect.pos.z)).terType = terType; + map->getTile(int3(i, j, rect.z)).terType = terType; } } //TODO there are situations where more tiles are affected implicitely //TODO add coastal bit to extTileFlags appropriately - updateTerrainViews(MapRect(int3(rect.pos.x - 1, rect.pos.y - 1, rect.pos.z), rect.width + 2, rect.height + 2)); + MapRect viewRect(int3(rect.x - 1, rect.y - 1, rect.z), rect.width + 2, rect.height + 2); // Has to overlap 1 tile around + updateTerrainViews(viewRect & MapRect(int3(0, 0, viewRect.z), map->width, map->height)); // Rect should not overlap map dimensions } void DrawTerrainOperation::undo() @@ -306,12 +388,12 @@ std::string DrawTerrainOperation::getLabel() const void DrawTerrainOperation::updateTerrainViews(const MapRect & rect) { - for(int i = rect.pos.x; i < rect.pos.x + rect.width; ++i) + for(int i = rect.x; i < rect.x + rect.width; ++i) { - for(int j = rect.pos.y; j < rect.pos.y + rect.height; ++j) + for(int j = rect.y; j < rect.y + rect.height; ++j) { const auto & patterns = - CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(i, j, rect.pos.z)).terType)); + CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(i, j, rect.z)).terType)); // Detect a pattern which fits best int bestPattern = -1, bestFlip = -1; @@ -322,10 +404,10 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect) for(int flip = 0; flip < 4; ++flip) { - auto valRslt = validateTerrainView(int3(i, j, rect.pos.z), flip > 0 ? getFlippedPattern(pattern, flip) : pattern); + auto valRslt = validateTerrainView(int3(i, j, rect.z), flip > 0 ? getFlippedPattern(pattern, flip) : pattern); if(valRslt.result) { - logGlobal->debugStream() << "Pattern detected at pos " << i << "x" << j << "x" << rect.pos.z << ": P-Nr. " << k + logGlobal->debugStream() << "Pattern detected at pos " << i << "x" << j << "x" << rect.z << ": P-Nr. " << k << ", Flip " << flip << ", Repl. " << valRslt.transitionReplacement; bestPattern = k; @@ -338,7 +420,7 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect) if(bestPattern == -1) { // This shouldn't be the case - logGlobal->warnStream() << "No pattern detected at pos " << i << "x" << j << "x" << rect.pos.z; + logGlobal->warnStream() << "No pattern detected at pos " << i << "x" << j << "x" << rect.z; continue; } @@ -355,7 +437,7 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect) } // Set terrain view - auto & tile = map->getTile(int3(i, j, rect.pos.z)); + auto & tile = map->getTile(int3(i, j, rect.z)); if(pattern.flipMode == TerrainViewPattern::FLIP_MODE_SAME_IMAGE) { tile.terView = gen->getInteger(mapping.first, mapping.second); @@ -363,9 +445,9 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect) } else { - int range = (mapping.second - mapping.first) / 4; - tile.terView = gen->getInteger(mapping.first + bestFlip * range, - mapping.first + (bestFlip + 1) * range - 1); + const int framesPerRot = 2; + int firstFrame = mapping.first + bestFlip * framesPerRot; + tile.terView = gen->getInteger(firstFrame, firstFrame + framesPerRot - 1); tile.extTileFlags = 0; } } diff --git a/lib/mapping/CMapEditManager.h b/lib/mapping/CMapEditManager.h index 640beb36c..b9e05e720 100644 --- a/lib/mapping/CMapEditManager.h +++ b/lib/mapping/CMapEditManager.h @@ -18,28 +18,30 @@ class CGObjectInstance; class CTerrainViewPatternConfig; struct TerrainViewPattern; -namespace ETerrainGroup -{ - enum ETerrainGroup - { - NORMAL, - DIRT, - SAND, - WATER, - ROCK - }; -} - /// Represents a map rectangle. struct DLL_LINKAGE MapRect { - MapRect(int3 pos, si32 width, si32 height) : pos(pos), width(width), height(height) { }; - int3 pos; + MapRect(); + MapRect(int3 pos, si32 width, si32 height); + si32 x, y, z; si32 width, height; + + si32 left() const; + si32 right() const; + si32 top() const; + si32 bottom() const; + + int3 topLeft() const; /// Top left corner of this rect. + int3 topRight() const; /// Top right corner of this rect. + int3 bottomLeft() const; /// Bottom left corner of this rect. + int3 bottomRight() const; /// Bottom right corner of this rect. + + /// Returns a MapRect of the intersection of this rectangle and the given one. + MapRect operator&(const MapRect & rect) const; }; /// The abstract base class CMapOperation defines an operation that can be executed, undone and redone. -class CMapOperation +class DLL_LINKAGE CMapOperation : public boost::noncopyable { public: CMapOperation(CMap * map); @@ -55,7 +57,7 @@ protected: }; /// The CMapUndoManager provides the functionality to save operations and undo/redo them. -class CMapUndoManager : boost::noncopyable +class DLL_LINKAGE CMapUndoManager : boost::noncopyable { public: CMapUndoManager(); @@ -77,8 +79,8 @@ public: private: typedef std::list > TStack; - inline void doOperation(TStack & fromStack, TStack & toStack, bool doUndo); - inline const CMapOperation * peek(const TStack & stack) const; + void doOperation(TStack & fromStack, TStack & toStack, bool doUndo); + const CMapOperation * peek(const TStack & stack) const; TStack undoStack; TStack redoStack; @@ -113,9 +115,21 @@ private: /* Implementation/Detail classes, Private API */ /* ---------------------------------------------------------------------------- */ +namespace ETerrainGroup +{ + enum ETerrainGroup + { + NORMAL, + DIRT, + SAND, + WATER, + ROCK + }; +} + /// The terrain view pattern describes a specific composition of terrain tiles /// in a 3x3 matrix and notes which terrain view frame numbers can be used. -struct TerrainViewPattern +struct DLL_LINKAGE TerrainViewPattern { struct WeightedRule { @@ -186,13 +200,14 @@ struct TerrainViewPattern }; /// The terrain view pattern config loads pattern data from the filesystem. -class CTerrainViewPatternConfig : public boost::noncopyable +class DLL_LINKAGE CTerrainViewPatternConfig : public boost::noncopyable { public: static CTerrainViewPatternConfig & get(); const std::vector & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; const TerrainViewPattern & getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; + ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const; private: CTerrainViewPatternConfig(); @@ -208,10 +223,10 @@ class DrawTerrainOperation : public CMapOperation public: DrawTerrainOperation(CMap * map, const MapRect & rect, ETerrainType terType, CRandomGenerator * gen); - void execute(); - void undo(); - void redo(); - std::string getLabel() const; + void execute() override; + void undo() override; + void redo() override; + std::string getLabel() const override; private: struct ValidationResult @@ -246,10 +261,10 @@ class InsertObjectOperation : public CMapOperation public: InsertObjectOperation(CMap * map, const int3 & pos, CGObjectInstance * obj); - void execute(); - void undo(); - void redo(); - std::string getLabel() const; + void execute() override; + void undo() override; + void redo() override; + std::string getLabel() const override; private: int3 pos; diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 0762a16a4..a1d079560 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -357,7 +357,7 @@ void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType val playerType = value; } -CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed) : +CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) : mapGenOptions(mapGenOptions), randomSeed(randomSeed) { gen.seed(randomSeed); @@ -376,6 +376,7 @@ std::unique_ptr CMapGenerator::generate() map = make_unique(); editManager = map->getEditManager(); + editManager->getUndoManager().setUndoRedoLimit(0); addHeaderInfo(); genTerrain(); @@ -472,7 +473,7 @@ void CMapGenerator::addPlayerInfo() void CMapGenerator::genTerrain() { - map->initTerrain(); //FIXME nicer solution + map->initTerrain(); editManager->clearTerrain(&gen); editManager->drawTerrain(MapRect(int3(10, 10, 0), 20, 30), ETerrainType::GRASS, &gen); } diff --git a/lib/rmg/CMapGenerator.h b/lib/rmg/CMapGenerator.h index 7222f9f24..c8cbce619 100644 --- a/lib/rmg/CMapGenerator.h +++ b/lib/rmg/CMapGenerator.h @@ -169,7 +169,7 @@ public: class DLL_LINKAGE CMapGenerator { public: - CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed); + explicit CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed = std::time(nullptr)); ~CMapGenerator(); // required due to unique_ptr std::unique_ptr generate(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..dff5364b8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 2.6) + +enable_testing() +include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/test) +include_directories(${Boost_INCLUDE_DIRS}) + +set(test_SRCS + StdInc.cpp + CVcmiTestConfig.cpp + CMapEditManagerTest.cpp +) + +add_executable(vcmitest ${test_SRCS}) +target_link_libraries(vcmitest vcmi ${Boost_LIBRARIES}) +add_test(vcmitest vcmitest) + +# Files to copy to the build directory after compilation +set(vcmitest_FILES + TerrainViewTest.h3m + terrainViewMappings.json +) + +foreach(file ${vcmitest_FILES}) + add_custom_command(TARGET vcmitest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" $ + ) +endforeach() diff --git a/test/CMapEditManagerTest.cpp b/test/CMapEditManagerTest.cpp new file mode 100644 index 000000000..da2c85c63 --- /dev/null +++ b/test/CMapEditManagerTest.cpp @@ -0,0 +1,83 @@ + +/* + * CMapEditManagerTest.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include + +#include "../lib/mapping/CMapService.h" +#include "../lib/mapping/CMap.h" +#include "../lib/filesystem/CResourceLoader.h" +#include "../lib/filesystem/CFilesystemLoader.h" +#include "../lib/JsonNode.h" +#include "../lib/mapping/CMapEditManager.h" +#include "../lib/int3.h" +#include "../lib/CRandomGenerator.h" + +BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain) +{ + try + { + // Load maps and json config + auto loader = make_shared("."); + CResourceHandler::get()->addLoader("test/", loader, false); + const auto originalMap = CMapService::loadMap("test/TerrainViewTest"); + auto map = CMapService::loadMap("test/TerrainViewTest"); + logGlobal->infoStream() << "Loaded test map successfully."; + + // Validate edit manager + auto editManager = map->getEditManager(); + CRandomGenerator gen; + const JsonNode viewNode(ResourceID("test/terrainViewMappings", EResType::TEXT)); + const auto & mappingsNode = viewNode["mappings"].Vector(); + BOOST_FOREACH(const auto & node, mappingsNode) + { + // Get terrain group and id + const auto & patternStr = node["pattern"].String(); + std::vector patternParts; + boost::split(patternParts, patternStr, boost::is_any_of(".")); + if(patternParts.size() != 2) throw std::runtime_error("A pattern should consist of two parts, the group and the id. Continue with next pattern."); + const auto & groupStr = patternParts[0]; + const auto & id = patternParts[1]; + auto terGroup = CTerrainViewPatternConfig::get().getTerrainGroup(groupStr); + + // Get mapping range + const auto & pattern = CTerrainViewPatternConfig::get().getPatternById(terGroup, id); + const auto & mapping = pattern.mapping; + + const auto & positionsNode = node["pos"].Vector(); + BOOST_FOREACH(const auto & posNode, positionsNode) + { + const auto & posVector = posNode.Vector(); + if(posVector.size() != 3) throw std::runtime_error("A position should consist of three values x,y,z. Continue with next position."); + int3 pos(posVector[0].Float(), posVector[1].Float(), posVector[2].Float()); + logGlobal->infoStream() << boost::format("Test pattern '%s' on position x '%d', y '%d', z '%d'.") % patternStr % pos.x % pos.y % pos.z; + const auto & originalTile = originalMap->getTile(pos); + editManager->drawTerrain(MapRect(pos, 1, 1), originalTile.terType, &gen); + const auto & tile = map->getTile(pos); + bool isInRange = false; + BOOST_FOREACH(const auto & range, mapping) + { + if(tile.terView >= range.first && tile.terView <= range.second) + { + isInRange = true; + break; + } + } + BOOST_CHECK(isInRange); + if(!isInRange) logGlobal->errorStream() << "No or invalid pattern found for current position."; + } + } + } + catch(const std::exception & e) + { + logGlobal-> errorStream() << e.what(); + } +} diff --git a/test/CVcmiTestConfig.cpp b/test/CVcmiTestConfig.cpp new file mode 100644 index 000000000..0dd457d8a --- /dev/null +++ b/test/CVcmiTestConfig.cpp @@ -0,0 +1,37 @@ + +/* + * CVcmiTestConfig.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "CVcmiTestConfig.h" + +#include "../lib/CConsoleHandler.h" +#include "../lib/logging/CBasicLogConfigurator.h" +#include "../lib/VCMIDirs.h" +#include "../lib/VCMI_Lib.h" +#include "../lib/logging/CLogger.h" +#include "../lib/CConfigHandler.h" + +CVcmiTestConfig::CVcmiTestConfig() +{ + console = new CConsoleHandler; + CBasicLogConfigurator logConfig(VCMIDirs::get().localPath() + "/VCMI_Test_log.txt", console); + logConfig.configureDefault(); + preinitDLL(console); + settings.init(); + logConfig.configure(); + loadDLLClasses(); + logGlobal->infoStream() << "Initialized global test setup."; +} + +CVcmiTestConfig::~CVcmiTestConfig() +{ + std::cout << "Ending global test tear-down." << std::endl; +} diff --git a/test/CVcmiTestConfig.h b/test/CVcmiTestConfig.h new file mode 100644 index 000000000..f6fec3b66 --- /dev/null +++ b/test/CVcmiTestConfig.h @@ -0,0 +1,20 @@ + +/* + * CVcmiTestConfig.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +/// Global setup/tear down class for unit tests. +class CVcmiTestConfig +{ +public: + CVcmiTestConfig(); + ~CVcmiTestConfig(); +}; diff --git a/test/StdInc.cpp b/test/StdInc.cpp new file mode 100644 index 000000000..6e11b3587 --- /dev/null +++ b/test/StdInc.cpp @@ -0,0 +1,7 @@ +// Creates the precompiled header +#include "StdInc.h" + +#define BOOST_TEST_MODULE VcmiTest +#include +#include "CVcmiTestConfig.h" +BOOST_GLOBAL_FIXTURE(CVcmiTestConfig); diff --git a/test/StdInc.h b/test/StdInc.h new file mode 100644 index 000000000..d50051f57 --- /dev/null +++ b/test/StdInc.h @@ -0,0 +1,8 @@ +#pragma once + +#include "../Global.h" + +#define BOOST_TEST_DYN_LINK + + + diff --git a/test/TerrainViewTest.h3m b/test/TerrainViewTest.h3m new file mode 100644 index 0000000000000000000000000000000000000000..78aa3e1c90bf1e98f7602c9f09003d49ebf59b12 GIT binary patch literal 4223 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 Vn?Ei+frsz<_kV8qNm=hp005glR)hcm literal 0 HcmV?d00001 diff --git a/test/terrainViewMappings.json b/test/terrainViewMappings.json new file mode 100644 index 000000000..cf6a1a4b3 --- /dev/null +++ b/test/terrainViewMappings.json @@ -0,0 +1,161 @@ +{ + "mappings" : [ + // Normal type + { + "pos" : [ [ 14,13,0 ], [ 4,34,0 ] ], + "pattern" : "normal.s1" + }, + { + "pos" : [ [ 14,15,0 ], [ 29,19,0 ] ], + "pattern" : "normal.s2" + }, + { + "pos" : [ [ 16,13,0 ], [ 23,30,0 ] ], + "pattern" : "normal.s3" + }, + { + "pos" : [ [ 16,14,0 ], [ 29,20,0 ] ], + "pattern" : "normal.s4" + }, + { + "pos" : [ [ 5,14,0 ], [ 31,13,0 ] ], + "pattern" : "normal.s5" + }, + { + "pos" : [ [ 9,17,0 ], [ 3,17,0 ] ], + "pattern" : "normal.s6" + }, + { + "pos" : [ [ 21,20,1 ], [ 28,27,1 ] ], + "pattern" : "normal.m1" + }, + { + "pos" : [ [ 22,22,1 ] ], + "pattern" : "normal.m2" + }, + { + "pos" : [ [ 12,31,0 ] ], + "pattern" : "normal.m3" + }, + { + "pos" : [ [ 5,34,0 ] ], + "pattern" : "normal.m4" + }, + { + "pos" : [ [ 12,34,0 ] ], + "pattern" : "normal.m5" + }, + { + "pos" : [ [ 8,25,0 ] ], + "pattern" : "normal.m6" + }, + { + "pos" : [ [ 5,32,0 ] ], + "pattern" : "normal.m7" + }, + { + "pos" : [ [ 28,23,1 ] ], + "pattern" : "normal.m8" + }, + { + "pos" : [ [ 7,23,0 ] ], + "pattern" : "normal.n1" + }, + // Dirt type + { + "pos" : [ [ 22,26,0 ], [ 27,35,0 ] ], + "pattern" : "dirt.s1" + }, + { + "pos" : [ [ 15,33,0 ], [ 19,34,0 ] ], + "pattern" : "dirt.s2" + }, + { + "pos" : [ [ 24,32,0 ], [ 25,26,0 ] ], + "pattern" : "dirt.s3" + }, + { + "pos" : [ [ 19,32,0 ] ], + "pattern" : "dirt.s4" + }, + { + "pos" : [ [ 26,28,1 ] ], + "pattern" : "dirt.s5" + }, + { + "pos" : [ [ 25,28,1 ] ], + "pattern" : "dirt.s6" + }, + { + "pos" : [ [ 9,25,1 ] ], + "pattern" : "dirt.m1" + }, + { + "pos" : [ [ 20,27,1 ] ], + "pattern" : "dirt.n1" + }, + // Sand type + { + "pos" : [ [ 22,27,1 ] ], + "pattern" : "sand.n1" + }, + // Water type + { + "pos" : [ [ 16,17,0 ] ], + "pattern" : "water.s1" + }, + { + "pos" : [ [ 20,15,0 ] ], + "pattern" : "water.s2" + }, + { + "pos" : [ [ 23,18,0 ] ], + "pattern" : "water.s3" + }, + { + "pos" : [ [ 20,11,0 ] ], + "pattern" : "water.s4" + }, + { + "pos" : [ [ 8,14,0 ] ], + "pattern" : "water.s5" + }, + { + "pos" : [ [ 8,13,0 ] ], + "pattern" : "water.s6" + }, + { + "pos" : [ [ 9,13,0 ] ], + "pattern" : "water.n1" + }, + // Rock type + { + "pos" : [ [ 13,12,1 ] ], + "pattern" : "rock.n1" + }, + { + "pos" : [ [ 11,21,1 ] ], + "pattern" : "rock.s1" + }, + { + "pos" : [ [ 8,21,1 ] ], + "pattern" : "rock.s2" + }, + { + "pos" : [ [ 10,12,1 ] ], + "pattern" : "rock.s3" + }, + { + "pos" : [ [ 13,21,1 ] ], + "pattern" : "rock.s4" + }, + { + "pos" : [ [ 10,22,1 ] ], + "pattern" : "rock.s5" + }, + { + "pos" : [ [ 8,23,1 ] ], + "pattern" : "rock.s6" + }, + ] +}