浏览代码

Making unit tests for BattleHex and some estetic improvements.

FeniksFire 8 年之前
父节点
当前提交
de7184d68d
共有 5 个文件被更改,包括 265 次插入124 次删除
  1. 98 35
      lib/BattleHex.cpp
  2. 28 75
      lib/BattleHex.h
  3. 124 0
      test/Battlefield.cpp
  4. 11 10
      test/CMakeLists.txt
  5. 4 4
      test/CVcmiTestConfig.cpp

+ 98 - 35
lib/BattleHex.cpp

@@ -1,6 +1,3 @@
-#include "StdInc.h"
-#include "BattleHex.h"
-
 /*
  * BattleHex.cpp, part of VCMI engine
  *
@@ -10,12 +7,78 @@
  * Full text of license available in license.txt file, in main folder
  *
  */
+#include "StdInc.h"
+#include "BattleHex.h"
 
-BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
+BattleHex::BattleHex() : hex(INVALID) {}
+
+BattleHex::BattleHex(si16 _hex) : hex(_hex) {}
+
+BattleHex::BattleHex(si16 x, si16 y)
+{
+	setXY(x, y);
+}
+
+BattleHex::BattleHex(std::pair<si16, si16> xy)
+{
+	setXY(xy);
+}
+
+BattleHex::operator si16() const
+{
+	return hex;
+}
+
+bool BattleHex::isValid() const
+{
+	return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
+}
+
+bool BattleHex::isAvailable() const
 {
-	si16 x = getX(),
-		y = getY();
+	return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH-1;
+}
+
+void BattleHex::setX(si16 x)
+{
+	setXY(x, getY());
+}
+
+void BattleHex::setY(si16 y)
+{
+	setXY(getX(), y);
+}
+
+void BattleHex::setXY(si16 x, si16 y, bool hasToBeValid)
+{
+	if(hasToBeValid)
+		assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
+	hex = x + y * GameConstants::BFIELD_WIDTH;
+}
+
+void BattleHex::setXY(std::pair<si16, si16> xy)
+{
+	setXY(xy.first, xy.second);
+}
+
+si16 BattleHex::getX() const
+{
+	return hex % GameConstants::BFIELD_WIDTH;
+}
+
+si16 BattleHex::getY() const
+{
+	return hex / GameConstants::BFIELD_WIDTH;
+}
 
+std::pair<si16, si16> BattleHex::getXY() const
+{
+	return std::make_pair(getX(), getY());
+}
+
+BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
+{
+	si16 x(getX()), y(getY());
 	switch(dir)
 	{
 	case TOP_LEFT:
@@ -39,11 +102,27 @@ BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
 	default:
 		throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
 		break;
-	}
-
+}
 	return *this;
 }
 
+BattleHex &BattleHex::operator+=(BattleHex::EDir dir)
+{
+	return moveInDir(dir);
+}
+
+BattleHex BattleHex::movedInDir(BattleHex::EDir dir, bool hasToBeValid) const
+{
+	BattleHex result(*this);
+	result.moveInDir(dir, hasToBeValid);
+	return result;
+}
+
+BattleHex BattleHex::operator+(BattleHex::EDir dir) const
+{
+	return movedInDir(dir);
+}
+
 std::vector<BattleHex> BattleHex::neighbouringTiles() const
 {
 	std::vector<BattleHex> ret;
@@ -66,32 +145,29 @@ signed char BattleHex::mutualPosition(BattleHex hex1, BattleHex hex2)
 		return 0;
 	if(hex2 == hex1 - ( (hex1/17)%2 ? 17 : 16 )) //top right
 		return 1;
-	if(hex2 == hex1 - 1 && hex1%17 != 0) //left
-		return 5;
 	if(hex2 == hex1 + 1 && hex1%17 != 16) //right
 		return 2;
-	if(hex2 == hex1 + ( (hex1/17)%2 ? 16 : 17 )) //bottom left
-		return 4;
 	if(hex2 == hex1 + ( (hex1/17)%2 ? 17 : 18 )) //bottom right
 		return 3;
+	if(hex2 == hex1 + ( (hex1/17)%2 ? 16 : 17 )) //bottom left
+		return 4;
+	if(hex2 == hex1 - 1 && hex1%17 != 0) //left
+		return 5;
 	return -1;
 }
 
 char BattleHex::getDistance(BattleHex hex1, BattleHex hex2)
-{	
-	int y1 = hex1.getY(), 
-		y2 = hex2.getY();
-	
+{
+	int y1 = hex1.getY(), y2 = hex2.getY();
+
 	// FIXME: Omit floating point arithmetics
-	int x1 = (int)(hex1.getX() + y1 * 0.5),
-		x2 = (int)(hex2.getX() + y2 * 0.5);
+	int x1 = (hex1.getX() + y1 * 0.5), x2 = (hex2.getX() + y2 * 0.5);
 
-	int xDst = x2 - x1,
-		yDst = y2 - y1;
+	int xDst = x2 - x1, yDst = y2 - y1;
 
-	if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0)) 
+	if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0))
 		return std::max(std::abs(xDst), std::abs(yDst));
-	
+
 	return std::abs(xDst) + std::abs(yDst);
 }
 
@@ -101,32 +177,21 @@ void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
 		ret.push_back(tile);
 }
 
-bool BattleHex::isAvailable() const
-{
-	return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH-1;
-}
-
 BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities)
 {
 	std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :(
-
 	BattleHex initialHex = BattleHex(initialPos);
 	auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool
 	{
 		return initialHex.getDistance (initialHex, left) < initialHex.getDistance (initialHex, right);
 	};
-
 	boost::sort (sortedTiles, compareDistance); //closest tiles at front
-
 	int closestDistance = initialHex.getDistance(initialPos, sortedTiles.front()); //sometimes closest tiles can be many hexes away
-
 	auto notClosest = [closestDistance, initialPos](const BattleHex here) -> bool
 	{
 		return closestDistance < here.getDistance (initialPos, here);
 	};
-
 	vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting
-
 	auto compareHorizontal = [attackerOwned, initialPos](const BattleHex left, const BattleHex right) -> bool
 	{
 		if(left.getX() != right.getX())
@@ -142,9 +207,7 @@ BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, st
 			return std::abs(left.getY() - initialPos.getY()) < std::abs(right.getY() - initialPos.getY());
 		}
 	};
-
 	boost::sort (sortedTiles, compareHorizontal);
-
 	return sortedTiles.front();
 }
 

+ 28 - 75
lib/BattleHex.h

@@ -1,8 +1,3 @@
-#pragma once
-
-#include "GameConstants.h"
-
-
 /*
  * BattleHex.h, part of VCMI engine
  *
@@ -12,93 +7,51 @@
  * Full text of license available in license.txt file, in main folder
  *
  */
+#pragma once
+#include <bits/stl_pair.h>
+#include "GameConstants.h"
 
 // for battle stacks' positions
-struct DLL_LINKAGE BattleHex
+class DLL_LINKAGE BattleHex
 {
+public:
+	si16 hex;
 	static const si16 INVALID = -1;
 	enum EDir { RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT };
 
-	si16 hex;
-
-	BattleHex() : hex(INVALID) {}
-	BattleHex(si16 _hex) : hex(_hex) {}
-	
-	operator si16() const { return hex; }
-
-	bool isValid() const { return hex >= 0 && hex < GameConstants::BFIELD_SIZE; }
-
-	template<typename inttype>
-	BattleHex(inttype x, inttype y)
-	{
-		setXY(x, y);
-	}
-
-	template<typename inttype>
-	BattleHex(std::pair<inttype, inttype> xy)
-	{
-		setXY(xy);
-	}
-
-	template<typename inttype>
-	void setX(inttype x)
-	{
-		setXY(x, getY());
-	}
-
-	template<typename inttype>
-	void setY(inttype y)
-	{
-		setXY(getX(), y);
-	}
-
-	void setXY(si16 x, si16 y, bool hasToBeValid = true)
-	{
-		if(hasToBeValid)
-			assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
-		hex = x + y * GameConstants::BFIELD_WIDTH;
-	}
-
-	template<typename inttype>
-	void setXY(std::pair<inttype, inttype> xy)
-	{
-		setXY(xy.first, xy.second);
-	}
-
-	si16 getY() const { return hex / GameConstants::BFIELD_WIDTH; }
-	si16 getX() const { return hex % GameConstants::BFIELD_WIDTH; }
-
-	std::pair<si16, si16> getXY() const { return std::make_pair(getX(), getY()); }
-
+	BattleHex();
+	BattleHex(si16 _hex);
+	BattleHex(si16 x, si16 y);
+	BattleHex(std::pair<si16, si16> xy);
+	operator si16() const;
+	bool isValid() const;
+	bool isAvailable() const; //valid position not in first or last column
+	void setX(si16 x);
+	void setY(si16 y);
+	void setXY(si16 x, si16 y, bool hasToBeValid = true);
+	void setXY(std::pair<si16, si16> xy);
+	si16 getX() const;
+	si16 getY() const;
+	std::pair<si16, si16> getXY() const;
 	//moving to direction
-	BattleHex& moveInDir(EDir dir, bool hasToBeValid = true); 
-	BattleHex& operator+=(EDir dir) { return moveInDir(dir); } //sugar for above
-
+	BattleHex& moveInDir(EDir dir, bool hasToBeValid = true);
+	BattleHex& operator+=(EDir dir); //sugar for above
 	//generates new BattleHex moved by given dir
-	BattleHex movedInDir(EDir dir, bool hasToBeValid = true) const
-	{
-		BattleHex result(*this);
-		result.moveInDir(dir, hasToBeValid);
-		return result;
-	}
-	BattleHex operator+(EDir dir) const { return movedInDir(dir); }
-
+	BattleHex movedInDir(EDir dir, bool hasToBeValid = true) const;
+	BattleHex operator+(EDir dir) const;
 	std::vector<BattleHex> neighbouringTiles() const;
-
 	//returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
 	static signed char mutualPosition(BattleHex hex1, BattleHex hex2);
-
 	//returns distance between given hexes
 	static char getDistance(BattleHex hex1, BattleHex hex2);
+	static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
+	static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
 
-	template <typename Handler> void serialize(Handler &h, const int version)
+	template <typename Handler>
+	void serialize(Handler &h, const int version)
 	{
 		h & hex;
 	}
-	static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
-
-	bool isAvailable() const; //valid position not in first or last column
-	static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
 };
 
 DLL_EXPORT std::ostream & operator<<(std::ostream & os, const BattleHex & hex);

+ 124 - 0
test/Battlefield.cpp

@@ -0,0 +1,124 @@
+/*
+ * BattleField.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 <boost/test/unit_test.hpp>
+#include "lib/BattleHex.h"
+
+BOOST_AUTO_TEST_SUITE(BattlefieldHex_Suite)
+
+BOOST_AUTO_TEST_CASE(getNeighbouringTiles)
+{
+	BattleHex mainHex;
+	std::vector<BattleHex> neighbouringTiles;
+	mainHex.setXY(16,0);
+	neighbouringTiles = mainHex.neighbouringTiles();
+	BOOST_TEST(neighbouringTiles.size()==1);
+	mainHex.setXY(0,0);
+	neighbouringTiles = mainHex.neighbouringTiles();
+	BOOST_TEST(neighbouringTiles.size()==2);
+	mainHex.setXY(15,2);
+	neighbouringTiles = mainHex.neighbouringTiles();
+	BOOST_TEST(neighbouringTiles.size()==3);
+	mainHex.setXY(2,0);
+	neighbouringTiles = mainHex.neighbouringTiles();
+	BOOST_TEST(neighbouringTiles.size()==4);
+	mainHex.setXY(1,2);
+	neighbouringTiles = mainHex.neighbouringTiles();
+	BOOST_TEST(neighbouringTiles.size()==5);
+	mainHex.setXY(8,5);
+	neighbouringTiles = mainHex.neighbouringTiles();
+	BOOST_TEST(neighbouringTiles.size()==6);
+
+	BOOST_REQUIRE(neighbouringTiles.size()==6 && mainHex==93);
+	BOOST_TEST(neighbouringTiles.at(0)==75);
+	BOOST_TEST(neighbouringTiles.at(1)==94);
+	BOOST_TEST(neighbouringTiles.at(2)==110);
+	BOOST_TEST(neighbouringTiles.at(3)==109);
+	BOOST_TEST(neighbouringTiles.at(4)==92);
+	BOOST_TEST(neighbouringTiles.at(5)==76);
+}
+
+BOOST_AUTO_TEST_CASE(getDistance)
+{
+	BattleHex firstHex(0,0), secondHex(16,0);
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==16);
+	firstHex=0, secondHex=170;
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==10);
+	firstHex=16, secondHex=181;
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==10);
+	firstHex=186, secondHex=70;
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==17);
+	firstHex=166, secondHex=39;
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==11);
+	firstHex=25, secondHex=103;
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==9);
+	firstHex=18, secondHex=71;
+	BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==4);
+}
+
+BOOST_AUTO_TEST_CASE(mutualPositions)
+{
+	BattleHex firstHex(0,0), secondHex(16,0);
+	firstHex=86, secondHex=68;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==0);
+	secondHex=69;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==1);
+	secondHex=87;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==2);
+	secondHex=103;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==3);
+	secondHex=102;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==4);
+	secondHex=85;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==5);
+	secondHex=46;
+	BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==-1);
+}
+
+BOOST_AUTO_TEST_CASE(getClosestTile)
+{
+	BattleHex mainHex(0);
+	std::set<BattleHex> possibilities;
+	possibilities.insert(3);
+	possibilities.insert(170);
+	possibilities.insert(100);
+	possibilities.insert(119);
+	possibilities.insert(186);
+
+	BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==3);
+	mainHex = 139;
+	BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==119);
+	mainHex = 16;
+	BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==100);
+	mainHex = 166;
+	BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==186);
+	mainHex = 76;
+	BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==3);
+	BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==100);
+}
+
+BOOST_AUTO_TEST_CASE(moveEDir)
+{
+	BattleHex mainHex(20);
+	mainHex.moveInDir(BattleHex::EDir::BOTTOM_RIGHT);
+	BOOST_TEST(mainHex==37);
+	mainHex.moveInDir(BattleHex::EDir::RIGHT);
+	BOOST_TEST(mainHex==38);
+	mainHex.moveInDir(BattleHex::EDir::TOP_RIGHT);
+	BOOST_TEST(mainHex==22);
+	mainHex.moveInDir(BattleHex::EDir::TOP_LEFT);
+	BOOST_TEST(mainHex==4);
+	mainHex.moveInDir(BattleHex::EDir::LEFT);
+	BOOST_TEST(mainHex==3);
+	mainHex.moveInDir(BattleHex::EDir::BOTTOM_LEFT);
+	BOOST_TEST(mainHex==20);
+}
+
+BOOST_AUTO_TEST_SUITE_END()

+ 11 - 10
test/CMakeLists.txt

@@ -1,13 +1,14 @@
-cmake_minimum_required(VERSION 2.6)
-
+cmake_minimum_required(VERSION 2.8.7)
+project(test)
 enable_testing()
 include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/test)
 include_directories(${Boost_INCLUDE_DIRS})
 
 set(test_SRCS
-		StdInc.cpp
-		CVcmiTestConfig.cpp
-		CMapEditManagerTest.cpp
+    StdInc.cpp
+    Battlefield.cpp
+    CVcmiTestConfig.cpp
+    CMapEditManagerTest.cpp
     MapComparer.cpp
     CMapFormatTest.cpp
 )
@@ -22,12 +23,12 @@ cotire(vcmitest)
 # Files to copy to the build directory
 add_custom_target(vcmitestFiles ALL)
 set(vcmitest_FILES
-		TerrainViewTest.h3m
-		terrainViewMappings.json
+                TerrainViewTest.h3m
+                terrainViewMappings.json
 )
 
 foreach(file ${vcmitest_FILES})
-		add_custom_command(TARGET vcmitestFiles POST_BUILD
-				COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" ${CMAKE_CURRENT_BINARY_DIR}
-	)
+                add_custom_command(TARGET vcmitestFiles POST_BUILD
+                                COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" ${CMAKE_CURRENT_BINARY_DIR}
+        )
 endforeach()

+ 4 - 4
test/CVcmiTestConfig.cpp

@@ -33,10 +33,10 @@ CVcmiTestConfig::CVcmiTestConfig()
 	loadDLLClasses();
 	logGlobal->info("Initialized global test setup.");
 
-	const std::string TEST_DATA_DIR = "test/";
-
-	auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR);
-	dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
+// These lines make a "Test setup error:"
+//	const std::string TEST_DATA_DIR = "test/";
+//	auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR);
+//	dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
 }
 
 CVcmiTestConfig::~CVcmiTestConfig()