mirror of
https://github.com/worldforge/ember
synced 2026-08-13 16:23:06 -04:00
647 lines
16 KiB
C++
647 lines
16 KiB
C++
#include <cppunit/extensions/TestFactoryRegistry.h>
|
|
#include <cppunit/ui/text/TestRunner.h>
|
|
#include <cppunit/extensions/HelperMacros.h>
|
|
#include <cppunit/BriefTestProgressListener.h>
|
|
#include <cppunit/TestResult.h>
|
|
|
|
#include "components/ogre/terrain/ICompilerTechniqueProvider.h"
|
|
#include "components/ogre/terrain/ITerrainPageBridge.h"
|
|
#include "components/ogre/terrain/TerrainHandler.h"
|
|
#include "components/ogre/terrain/Types.h"
|
|
#include "components/ogre/terrain/TerrainDefPoint.h"
|
|
#include "components/ogre/terrain/TerrainInfo.h"
|
|
#include "components/ogre/terrain/TerrainPageSurfaceCompiler.h"
|
|
#include "components/ogre/ILightning.h"
|
|
|
|
#include "framework/Exception.h"
|
|
#include "framework/TimeFrame.h"
|
|
#include "framework/MainLoopController.h"
|
|
|
|
#include <Eris/Entity.h>
|
|
#include <Eris/EventService.h>
|
|
|
|
#include <Atlas/Message/Element.h>
|
|
|
|
#include <Mercator/Terrain.h>
|
|
|
|
#include <wfmath/timestamp.h>
|
|
#include <wfmath/atlasconv.h>
|
|
|
|
#include <Ogre.h>
|
|
#include <sigc++/signal.h>
|
|
#include <sigc++/trackable.h>
|
|
|
|
#include <condition_variable>
|
|
|
|
using namespace Ember::OgreView;
|
|
using namespace Ember::OgreView::Terrain;
|
|
|
|
namespace Ember
|
|
{
|
|
|
|
class DummyTerrainTechnique : public TerrainPageSurfaceCompilerTechnique
|
|
{
|
|
virtual bool prepareMaterial()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
virtual bool compileMaterial(Ogre::MaterialPtr material, std::set<std::string>& managedTextures) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
virtual bool compileCompositeMapMaterial(Ogre::MaterialPtr material, std::set<std::string>& managedTextures) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
virtual std::string getShadowTextureName(const Ogre::MaterialPtr& material) const
|
|
{
|
|
return "";
|
|
}
|
|
|
|
|
|
virtual bool requiresPregenShadow() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
class DummyCompilerTechniqueProvider: public ICompilerTechniqueProvider
|
|
{
|
|
public:
|
|
virtual TerrainPageSurfaceCompilerTechnique* createTechnique(const TerrainPageGeometryPtr& geometry, const SurfaceLayerStore& terrainPageSurfaces, const TerrainPageShadow* terrainPageShadow) const
|
|
{
|
|
return new DummyTerrainTechnique();
|
|
}
|
|
|
|
};
|
|
|
|
class DummyTerrainBridge: public ITerrainPageBridge
|
|
{
|
|
public:
|
|
|
|
bool pageReady;
|
|
|
|
DummyTerrainBridge() :
|
|
pageReady(false)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @brief Updates the Ogre mesh after changes to the underlying heightdata.
|
|
*
|
|
* Call this when the heightdata has changed and you want the Ogre representation to be updated to reflect this.
|
|
*/
|
|
virtual void updateTerrain(TerrainPageGeometry& geometry)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @brief Notifies class in the ogre side about the page being ready (after being created or so).
|
|
*/
|
|
virtual void terrainPageReady()
|
|
{
|
|
pageReady = true;
|
|
}
|
|
|
|
virtual bool isPageShown() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
class DummyLightning : public ILightning {
|
|
public:
|
|
/**
|
|
* @brief Gets the direction of the main light, in world space.
|
|
* @returns The direction of the main light, in world space.
|
|
*/
|
|
virtual WFMath::Vector<3> getMainLightDirection() const
|
|
{
|
|
return WFMath::Vector<3>::ZERO();
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the default ambient light colour.
|
|
* @returns The default ambient light colour.
|
|
*/
|
|
virtual Ogre::ColourValue getAmbientLightColour() const
|
|
{
|
|
return Ogre::ColourValue::Black;
|
|
}
|
|
};
|
|
|
|
class DummyEntity: public Eris::Entity
|
|
{
|
|
public:
|
|
DummyEntity() :
|
|
Eris::Entity("0", 0)
|
|
{
|
|
}
|
|
|
|
Eris::TypeService* getTypeService() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void removeFromMovementPrediction()
|
|
{
|
|
}
|
|
|
|
void addToMovementPrediction()
|
|
{
|
|
}
|
|
|
|
Eris::Entity* getEntity(const std::string& id)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void setAttr(const std::string &p, const Atlas::Message::Element &v)
|
|
{
|
|
Eris::Entity::setAttr(p, v);
|
|
}
|
|
|
|
void setFromMessage(const Atlas::Message::MapType& attrs)
|
|
{
|
|
beginUpdate();
|
|
|
|
Atlas::Message::MapType::const_iterator A;
|
|
|
|
for (A = attrs.begin(); A != attrs.end(); ++A) {
|
|
if (A->first == "loc" || A->first == "id" || A->first == "contains")
|
|
continue;
|
|
|
|
Eris::Entity::AttrMap::iterator I = m_attrs.find(A->first);
|
|
if ((I != m_attrs.end()) && (I->second == A->second))
|
|
continue;
|
|
|
|
setAttr(A->first, A->second);
|
|
}
|
|
|
|
endUpdate();
|
|
}
|
|
|
|
};
|
|
|
|
class EntityHolder
|
|
{
|
|
public:
|
|
Eris::Entity& entity;
|
|
EntityHolder(Eris::Entity& entity) :
|
|
entity(entity)
|
|
{
|
|
|
|
}
|
|
~EntityHolder()
|
|
{
|
|
entity.shutdown();
|
|
}
|
|
};
|
|
|
|
class Timer
|
|
{
|
|
public:
|
|
|
|
WFMath::TimeStamp startTime;
|
|
|
|
Timer() :
|
|
startTime(WFMath::TimeStamp::now())
|
|
{
|
|
|
|
}
|
|
|
|
bool hasElapsed(long milliseconds)
|
|
{
|
|
return (WFMath::TimeStamp::now() - startTime).milliseconds() > milliseconds;
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* @brief Base class for listening to events. After the event is triggered isCompleted() will return true.
|
|
*
|
|
* For background events, call waitForCompletion(...).
|
|
*/
|
|
class CompleteEventListener: public virtual sigc::trackable
|
|
{
|
|
protected:
|
|
std::condition_variable mCondition;
|
|
std::mutex mMutex;
|
|
int mCompletedCount;
|
|
|
|
void handleEvent()
|
|
{
|
|
{
|
|
std::lock_guard < std::mutex > lock(mMutex);
|
|
mCompletedCount++;
|
|
}
|
|
mCondition.notify_all();
|
|
}
|
|
|
|
public:
|
|
CompleteEventListener() :
|
|
mCompletedCount(0)
|
|
{
|
|
}
|
|
|
|
int waitForCompletion(long milliseconds)
|
|
{
|
|
std::unique_lock < std::mutex > lock(mMutex);
|
|
if (mCompletedCount) {
|
|
return true;
|
|
}
|
|
mCondition.wait_for(lock, std::chrono::milliseconds(milliseconds));
|
|
return mCompletedCount;
|
|
}
|
|
|
|
int getCompletedCount()
|
|
{
|
|
return mCompletedCount;
|
|
}
|
|
};
|
|
|
|
class WorldSizeChangedListener: public CompleteEventListener
|
|
{
|
|
protected:
|
|
|
|
void eventListener()
|
|
{
|
|
handleEvent();
|
|
}
|
|
|
|
public:
|
|
WorldSizeChangedListener(sigc::signal<void()>& event)
|
|
{
|
|
event.connect(sigc::mem_fun(*this, &WorldSizeChangedListener::eventListener));
|
|
}
|
|
};
|
|
|
|
class AfterTerrainUpdateListener: public CompleteEventListener
|
|
{
|
|
protected:
|
|
|
|
void eventListener(const std::vector<WFMath::AxisBox<2>>& areas, const std::set<TerrainPage*>& pages)
|
|
{
|
|
handleEvent();
|
|
}
|
|
|
|
public:
|
|
AfterTerrainUpdateListener(sigc::signal<void(const std::vector<WFMath::AxisBox<2>>&, const std::set<TerrainPage*>&)>& event)
|
|
{
|
|
event.connect(sigc::mem_fun(*this, &AfterTerrainUpdateListener::eventListener));
|
|
}
|
|
};
|
|
|
|
class TestTerrainHandler: public Terrain::TerrainHandler
|
|
{
|
|
public:
|
|
|
|
TestTerrainHandler(int pageIndexSize, ICompilerTechniqueProvider& compilerTechniqueProvider, Eris::EventService& es) :
|
|
Terrain::TerrainHandler(pageIndexSize, compilerTechniqueProvider, es)
|
|
{
|
|
mLightning = new DummyLightning();
|
|
}
|
|
|
|
Mercator::Terrain* getTerrain()
|
|
{
|
|
return mTerrain;
|
|
}
|
|
|
|
/**
|
|
* Checks the height, using an integer.
|
|
* This is because of the floats being used, we can't be 100% certain that a piece of terrain should be exactly the specified height.
|
|
*/
|
|
bool checkTerrainHeight(float x, float y, int height)
|
|
{
|
|
float realHeight = 0;
|
|
getHeight(TerrainPosition(x,y), realHeight);
|
|
return (int)(realHeight) == height;
|
|
}
|
|
};
|
|
|
|
class TerrainSetup
|
|
{
|
|
public:
|
|
boost::asio::io_service io_service;
|
|
Eris::EventService es;
|
|
DummyCompilerTechniqueProvider compilerTechniqueProvider;
|
|
TestTerrainHandler terrainHandler;
|
|
|
|
|
|
TerrainSetup() :
|
|
es(io_service), terrainHandler(513, compilerTechniqueProvider, es)
|
|
{
|
|
}
|
|
|
|
bool createBaseTerrain(float height)
|
|
{
|
|
WorldSizeChangedListener worldSizeChangedListener(terrainHandler.EventWorldSizeChanged);
|
|
|
|
TerrainDefPointStore terrainDefPoints;
|
|
terrainDefPoints.push_back(TerrainDefPoint(-1, -1, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(-1, 0, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(-1, 1, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(0, -1, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(0, 0, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(0, 1, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(1, -1, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(1, 0, height));
|
|
terrainDefPoints.push_back(TerrainDefPoint(1, 1, height));
|
|
|
|
terrainHandler.updateTerrain(terrainDefPoints);
|
|
Timer timer;
|
|
do {
|
|
es.processAllHandlers();
|
|
} while (!timer.hasElapsed(5000) && !worldSizeChangedListener.getCompletedCount());
|
|
return worldSizeChangedListener.getCompletedCount() > 0;
|
|
}
|
|
|
|
bool createPages()
|
|
{
|
|
DummyTerrainBridge* bridge1 = new DummyTerrainBridge();
|
|
DummyTerrainBridge* bridge2 = new DummyTerrainBridge();
|
|
DummyTerrainBridge* bridge3 = new DummyTerrainBridge();
|
|
DummyTerrainBridge* bridge4 = new DummyTerrainBridge();
|
|
|
|
terrainHandler.setUpTerrainPageAtIndex(TerrainIndex(0, 0), bridge1);
|
|
terrainHandler.setUpTerrainPageAtIndex(TerrainIndex(0, 1), bridge2);
|
|
terrainHandler.setUpTerrainPageAtIndex(TerrainIndex(-1, 0), bridge3);
|
|
terrainHandler.setUpTerrainPageAtIndex(TerrainIndex(-1, 1), bridge4);
|
|
|
|
{
|
|
Timer timer;
|
|
do {
|
|
es.processAllHandlers();
|
|
} while ((!timer.hasElapsed(5000)) && (!bridge1->pageReady || !bridge2->pageReady || !bridge3->pageReady || !bridge4->pageReady));
|
|
}
|
|
CPPUNIT_ASSERT(bridge1->pageReady);
|
|
CPPUNIT_ASSERT(bridge2->pageReady);
|
|
CPPUNIT_ASSERT(bridge3->pageReady);
|
|
CPPUNIT_ASSERT(bridge4->pageReady);
|
|
return true;
|
|
}
|
|
|
|
bool reloadTerrain()
|
|
{
|
|
AfterTerrainUpdateListener afterTerrainUpdateListener(terrainHandler.EventAfterTerrainUpdate);
|
|
std::vector<TerrainPosition> positions;
|
|
positions.push_back(TerrainPosition(-32, -32));
|
|
positions.push_back(TerrainPosition(-32, 32));
|
|
positions.push_back(TerrainPosition(32, 32));
|
|
positions.push_back(TerrainPosition(32, -32));
|
|
|
|
terrainHandler.reloadTerrain(positions);
|
|
|
|
{
|
|
Timer timer;
|
|
do {
|
|
es.processAllHandlers();
|
|
} while ((!timer.hasElapsed(5000)) && afterTerrainUpdateListener.getCompletedCount() < 4);
|
|
}
|
|
CPPUNIT_ASSERT(afterTerrainUpdateListener.getCompletedCount() == 4);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class TerrainTestCase: public CppUnit::TestFixture
|
|
{
|
|
CPPUNIT_TEST_SUITE( TerrainTestCase);
|
|
// CPPUNIT_TEST( testCreateTerrain);
|
|
// CPPUNIT_TEST( testAlterTerrain);
|
|
CPPUNIT_TEST( testApplyMod);
|
|
// CPPUNIT_TEST( testUpdateMod);
|
|
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
protected:
|
|
|
|
public:
|
|
void testCreateTerrain()
|
|
{
|
|
|
|
Ogre::Root root;
|
|
|
|
TerrainSetup terrainSetup;
|
|
|
|
float terrainHeight = 25.0f;
|
|
|
|
CPPUNIT_ASSERT(terrainSetup.createBaseTerrain(terrainHeight));
|
|
CPPUNIT_ASSERT(terrainSetup.createPages());
|
|
CPPUNIT_ASSERT(terrainSetup.reloadTerrain());
|
|
|
|
CPPUNIT_ASSERT(terrainSetup.terrainHandler.getTerrainInfo().getTotalNumberOfPagesX() == 2);
|
|
CPPUNIT_ASSERT(terrainSetup.terrainHandler.getTerrainInfo().getTotalNumberOfPagesY() == 2);
|
|
float height = 0;
|
|
CPPUNIT_ASSERT(terrainSetup.terrainHandler.getHeight(TerrainPosition(-1, -1), height));
|
|
CPPUNIT_ASSERT(height == terrainHeight);
|
|
|
|
}
|
|
|
|
void testAlterTerrain()
|
|
{
|
|
|
|
Ogre::Root root;
|
|
TerrainSetup terrainSetup;
|
|
|
|
Terrain::TerrainHandler& terrainHandler = terrainSetup.terrainHandler;
|
|
CPPUNIT_ASSERT(terrainSetup.createBaseTerrain(25.0f));
|
|
CPPUNIT_ASSERT(terrainSetup.createPages());
|
|
CPPUNIT_ASSERT(terrainSetup.reloadTerrain());
|
|
|
|
TerrainDefPointStore terrainDefPoints;
|
|
terrainDefPoints.push_back(TerrainDefPoint(-1, -1, -200));
|
|
terrainDefPoints.push_back(TerrainDefPoint(-1, 0, -200));
|
|
terrainDefPoints.push_back(TerrainDefPoint(0, -1, -200));
|
|
terrainDefPoints.push_back(TerrainDefPoint(0, 0, -200));
|
|
|
|
terrainHandler.updateTerrain(terrainDefPoints);
|
|
|
|
AfterTerrainUpdateListener afterTerrainUpdateListener(terrainHandler.EventAfterTerrainUpdate);
|
|
|
|
{
|
|
Timer timer;
|
|
do {
|
|
terrainSetup.es.processAllHandlers();
|
|
} while ((!timer.hasElapsed(5000)) && afterTerrainUpdateListener.getCompletedCount() < 4);
|
|
}
|
|
CPPUNIT_ASSERT(afterTerrainUpdateListener.getCompletedCount() == 4);
|
|
CPPUNIT_ASSERT(terrainHandler.getTerrainInfo().getTotalNumberOfPagesX() == 2);
|
|
CPPUNIT_ASSERT(terrainHandler.getTerrainInfo().getTotalNumberOfPagesY() == 2);
|
|
float height = 0;
|
|
CPPUNIT_ASSERT(terrainHandler.getHeight(TerrainPosition(-32, -32), height));
|
|
CPPUNIT_ASSERT(height == -200);
|
|
}
|
|
|
|
void testApplyMod()
|
|
{
|
|
|
|
bool shouldQuit, pollEris;
|
|
MainLoopController loopController(shouldQuit, pollEris);
|
|
Ogre::Root root;
|
|
|
|
TerrainSetup terrainSetup;
|
|
Terrain::TerrainHandler& terrainHandler = terrainSetup.terrainHandler;
|
|
DummyEntity entity;
|
|
EntityHolder entityHolder(entity);
|
|
entity.setAttr("pos", WFMath::Point<3>::ZERO().toAtlas());
|
|
|
|
float terrainHeight = 25.0f;
|
|
|
|
CPPUNIT_ASSERT(terrainSetup.createBaseTerrain(terrainHeight));
|
|
CPPUNIT_ASSERT(terrainSetup.createPages());
|
|
CPPUNIT_ASSERT(terrainSetup.reloadTerrain());
|
|
|
|
Atlas::Message::ListType polygon;
|
|
|
|
polygon.push_back(WFMath::Point<2>(-10, -10).toAtlas());
|
|
polygon.push_back(WFMath::Point<2>(-10, 10).toAtlas());
|
|
polygon.push_back(WFMath::Point<2>(10, 10).toAtlas());
|
|
polygon.push_back(WFMath::Point<2>(10, -10).toAtlas());
|
|
|
|
Atlas::Message::MapType shape;
|
|
shape["points"] = polygon;
|
|
shape["type"] = "polygon";
|
|
|
|
Atlas::Message::MapType mod;
|
|
mod["shape"] = shape;
|
|
mod["type"] = "levelmod";
|
|
mod["heightoffset"] = 2.0f;
|
|
|
|
entity.setAttr("terrainmod", mod);
|
|
|
|
OgreView::Terrain::TerrainMod terrainMod(entity);
|
|
terrainMod.init();
|
|
terrainHandler.addTerrainMod(&terrainMod);
|
|
|
|
}
|
|
|
|
void testUpdateMod()
|
|
{
|
|
|
|
Ogre::Root root;
|
|
|
|
TerrainSetup terrainSetup;
|
|
TestTerrainHandler& terrainHandler = terrainSetup.terrainHandler;
|
|
DummyEntity entity;
|
|
EntityHolder entityHolder(entity);
|
|
|
|
entity.setAttr("pos", WFMath::Point<3>::ZERO().toAtlas());
|
|
|
|
float terrainHeight = 25.0f;
|
|
|
|
CPPUNIT_ASSERT(terrainSetup.createBaseTerrain(terrainHeight));
|
|
CPPUNIT_ASSERT(terrainSetup.createPages());
|
|
CPPUNIT_ASSERT(terrainSetup.reloadTerrain());
|
|
|
|
Atlas::Message::ListType polygon;
|
|
|
|
polygon.push_back(WFMath::Point<2>(-10, -10).toAtlas());
|
|
polygon.push_back(WFMath::Point<2>(-10, 10).toAtlas());
|
|
polygon.push_back(WFMath::Point<2>(10, 10).toAtlas());
|
|
polygon.push_back(WFMath::Point<2>(10, -10).toAtlas());
|
|
|
|
Atlas::Message::MapType shape;
|
|
shape["points"] = polygon;
|
|
shape["type"] = "polygon";
|
|
|
|
Atlas::Message::MapType mod;
|
|
mod["shape"] = shape;
|
|
mod["type"] = "levelmod";
|
|
mod["heightoffset"] = 2.0f;
|
|
|
|
entity.setAttr("terrainmod", mod);
|
|
|
|
OgreView::Terrain::TerrainMod* terrainMod = new Terrain::TerrainMod(entity);
|
|
terrainMod->init();
|
|
|
|
{
|
|
AfterTerrainUpdateListener afterTerrainUpdateListener(terrainHandler.EventAfterTerrainUpdate);
|
|
|
|
//The shape should affect all four pages.
|
|
terrainHandler.addTerrainMod(terrainMod);
|
|
|
|
{
|
|
Timer timer;
|
|
do {
|
|
terrainSetup.es.processAllHandlers();
|
|
} while (afterTerrainUpdateListener.getCompletedCount() < 4);
|
|
}
|
|
CPPUNIT_ASSERT(afterTerrainUpdateListener.getCompletedCount() == 4);
|
|
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(-5, -5, 2.0f));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(-5, 5, 2.0f));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(5, 5, 2.0f));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(5, -5, 2.0f));
|
|
|
|
}
|
|
|
|
mod["heightoffset"] = 20.0f;
|
|
//Setting the attribute should trigger a mod change
|
|
entity.setAttr("terrainmod", mod);
|
|
|
|
{
|
|
AfterTerrainUpdateListener afterTerrainUpdateListener(terrainHandler.EventAfterTerrainUpdate);
|
|
|
|
{
|
|
Timer timer;
|
|
do {
|
|
terrainSetup.es.processAllHandlers();
|
|
// } while ((!timer.hasElapsed(5000)) && afterTerrainUpdateListener.getCompletedCount() < 4);
|
|
} while (afterTerrainUpdateListener.getCompletedCount() < 4);
|
|
}
|
|
CPPUNIT_ASSERT(afterTerrainUpdateListener.getCompletedCount() == 4);
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(-5, -5, 20.0f));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(-5, 5, 20.0f));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(5, 5, 20.0f));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(5, -5, 20.0f));
|
|
|
|
}
|
|
|
|
//Move the mod out of the way
|
|
entity.setAttr("pos", WFMath::Point<3>(40, 40, 0).toAtlas());
|
|
|
|
{
|
|
AfterTerrainUpdateListener afterTerrainUpdateListener(terrainHandler.EventAfterTerrainUpdate);
|
|
|
|
{
|
|
Timer timer;
|
|
do {
|
|
terrainSetup.es.processAllHandlers();
|
|
} while ((!timer.hasElapsed(5000)) && afterTerrainUpdateListener.getCompletedCount() < 4);
|
|
}
|
|
CPPUNIT_ASSERT(afterTerrainUpdateListener.getCompletedCount() == 4);
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(-5, -5, 25));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(-5, 5, 25));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(5, 5, 25));
|
|
CPPUNIT_ASSERT(terrainHandler.checkTerrainHeight(5, -5, 25));
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION( Ember::TerrainTestCase);
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
CppUnit::TextUi::TestRunner runner;
|
|
CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry();
|
|
runner.addTest(registry.makeTest());
|
|
|
|
// Shows a message as each test starts
|
|
CppUnit::BriefTestProgressListener listener;
|
|
runner.eventManager().addListener(&listener);
|
|
|
|
bool wasSuccessful = runner.run("", false);
|
|
return !wasSuccessful;
|
|
}
|
|
|