/* * ===================================================================================== * * Filename: catch.cpp * * Description: Unit Tests using the Catch framework * * Version: 1.0 * Created: 07/03/2017 08:25:04 PM * Revision: none * Compiler: gcc * * Author: suhrke@teknik.io * * ===================================================================================== */ #ifndef CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN #include "catch.hpp" #include "catch-parser.cpp" #include #include #include #include #include "EntityConverter.hpp" #define PICKUP_FILENAME "ReflexToQ3/r2x.pck" #define DELTA 0.00001 TEST_CASE( "r2x: Unsupported entity types cause return of empty vector", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type NotAType"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted.size() == 0 ); } TEST_CASE( "r2x: a single Pickup entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type Pickup"); entity.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity.push_back(" Vector3 angles 180.00000 0.00000 0.00000"); entity.push_back(" UInt8 pickupType 2"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"weapon_grenadelauncher\"\n" ); // The z (vertical) is offset by +2 std::istringstream iss(converted[1]); std::string attribute; std::string coords[2]; float offsetCoord; iss >> attribute >> coords[0] >> coords[1] >> offsetCoord; REQUIRE( attribute == "\"origin\"" ); REQUIRE( coords[0] == "\"-216.00000" ); REQUIRE( coords[1] == "-1488.000488" ); REQUIRE( fabs(-130.00000 - offsetCoord) <= DELTA ); } TEST_CASE( "r2x: a single PlayerSpawn (race) entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up WorldSpawn entity // (needed for mode info) std::vector worldspawn; worldspawn.push_back(" type WorldSpawn"); worldspawn.push_back(" Bool8 modeCTF 0"); worldspawn.push_back(" Bool8 modeFFA 0"); worldspawn.push_back(" Bool8 modeTDM 0"); worldspawn.push_back(" Bool8 mode1v1 0"); // Mock up entity std::vector entity; entity.push_back(" type PlayerSpawn"); entity.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity.push_back(" Vector3 angles 180.00000 0.00000 0.00000"); entity.push_back(" Bool8 teamA 0"); entity.push_back(" Bool8 teamB 0"); entity.push_back(" Bool8 modeCTF 0"); entity.push_back(" Bool8 modeFFA 0"); entity.push_back(" Bool8 modeTDM 0"); entity.push_back(" Bool8 mode1v1 0"); // Mock up entity queue std::queue> q; q.push( worldspawn ); q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity (worldspawn conversion returns empty vector // BUT sets the supported game modes for entities in that worldspawn std::vector unused = ec.convert(worldspawn); std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"info_player_race\"\n" ); REQUIRE( converted[1] == "\"target\" \"cp1\"\n" ); REQUIRE( converted[2] == "\"race_place\" \"-1\"\n" ); // The z (vertical) is offset by +32 std::istringstream iss(converted[3]); std::string attribute; std::string coords[2]; float offsetCoord; iss >> attribute >> coords[0] >> coords[1] >> offsetCoord; REQUIRE( attribute == "\"origin\"" ); REQUIRE( coords[0] == "\"-216.00000" ); REQUIRE( coords[1] == "-1488.000488" ); REQUIRE( fabs(-100.00000 - offsetCoord) <= DELTA ); SECTION( "Converted angles are valid (Different coordinate system handedness)" ) { std::istringstream angleLineStream(converted[4]); std::string angleAttribute; std::string a; float angle; angleLineStream >> attribute >> a; a.erase(a.begin()); //removing preceding quote is necessary std::stringstream angleStream(a); angleStream >> angle; REQUIRE( attribute == "\"angle\"" ); REQUIRE( fabs( -90.0 - angle) <= DELTA ); } SECTION( "Encountering a new worldspawn reenables all modes" ) { std::vector basicWorldspawn; basicWorldspawn.push_back(" type WorldSpawn"); std::vector e; e.push_back(" type PlayerSpawn"); e.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); e.push_back(" Vector3 angles 180.00000 0.00000 0.00000"); std::vector u = ec.convert(basicWorldspawn); std::vector c = ec.convert(e); REQUIRE( c[0] == "\"classname\" \"info_player_deathmatch\"\n" ); } } TEST_CASE( "r2x: a single PlayerSpawn (teamA) entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type PlayerSpawn"); entity.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity.push_back(" Vector3 angles 180.00000 0.00000 0.00000"); entity.push_back(" Bool8 teamB 0"); entity.push_back(" Bool8 modeRace 0"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"info_player_team1\"\n" ); // The z (vertical) is offset by +32 std::istringstream iss(converted[1]); std::string attribute; std::string coords[2]; float offsetCoord; iss >> attribute >> coords[0] >> coords[1] >> offsetCoord; REQUIRE( attribute == "\"origin\"" ); REQUIRE( coords[0] == "\"-216.00000" ); REQUIRE( coords[1] == "-1488.000488" ); REQUIRE( fabs(-100.00000 - offsetCoord) <= DELTA ); } TEST_CASE( "r2x: a single PlayerSpawn (non-team) entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type PlayerSpawn"); entity.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity.push_back(" Vector3 angles 180.00000 0.00000 0.00000"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"info_player_deathmatch\"\n" ); // The z (vertical) is offset by +32 std::istringstream iss(converted[1]); std::string attribute; std::string coords[2]; float offsetCoord; iss >> attribute >> coords[0] >> coords[1] >> offsetCoord; REQUIRE( attribute == "\"origin\"" ); REQUIRE( coords[0] == "\"-216.00000" ); REQUIRE( coords[1] == "-1488.000488" ); REQUIRE( fabs(-100.00000 - offsetCoord) <= DELTA ); } TEST_CASE( "r2x: a single RaceStart entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type RaceStart"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"trigger_race_checkpoint\"\n" ); REQUIRE( converted[1] == "\"targetname\" \"cp1\"\n" ); REQUIRE( converted[2] == "\"cnt\" \"1\"\n" ); } TEST_CASE( "r2x: a single RaceFinish entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type RaceFinish"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"trigger_race_checkpoint\"\n" ); REQUIRE( converted[1] == "\"targetname\" \"finish\"\n" ); REQUIRE( converted[2] == "\"cnt\" \"0\"\n" ); } TEST_CASE( "r2x: a single Teleporter and related Target can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up Teleporter entity std::vector entity; entity.push_back(" type Teleporter"); entity.push_back(" String32 target tp1"); // Mock up Target entity std::vector entity2; entity2.push_back(" type Target"); entity2.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity2.push_back(" String32 name tp1"); // Mock up entity queue std::queue> q; q.push( entity ); q.push( entity2 ); // Match related entities (one pair) ec.extractMapInfo( q ); // Convert two entities std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"trigger_teleport\"\n" ); REQUIRE( converted[1] == "\"target\" \"tp1\"\n" ); std::vector converted2 = ec.convert(entity2); REQUIRE( converted2[0] == "\"classname\" \"misc_teleporter_dest\"\n" ); REQUIRE( converted2[2] == "\"targetname\" \"tp1\"\n" ); // // The z (vertical) is offset by +32 std::istringstream iss(converted2[1]); std::string attribute; std::string coords[2]; float offsetCoord; iss >> attribute >> coords[0] >> coords[1] >> offsetCoord; // next REQUIRE fails without busy wait for( int i = 0; i < 10000000; i++ ) int x = i; REQUIRE( attribute == "\"origin\"" ); REQUIRE( coords[0] == "\"-216.00000" ); REQUIRE( coords[1] == "-1488.000488" ); REQUIRE( fabs(-100.00000 - offsetCoord) <= DELTA ); SECTION( "When angle unspecified, defaults to 0.0 (converted to 90.0)" ) { std::istringstream angleStream(converted2[3]); std::string a; float angle; angleStream >> attribute >> a; a.erase(a.begin()); //removing preceding quote is necessary std::stringstream out(a); out >> angle; REQUIRE( fabs(90.0 - angle) <= DELTA ); } } TEST_CASE( "r2x: a single JumpPad and related Target can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up JumpPad entity std::vector entity; entity.push_back(" type JumpPad"); entity.push_back(" String32 target jp1"); // Mock up Target entity std::vector entity2; entity2.push_back(" type Target"); entity2.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity2.push_back(" String32 name jp1"); // Mock up entity queue std::queue> q; q.push( entity ); q.push( entity2 ); // Match related entities (one pair) ec.extractMapInfo( q ); // Convert two entities std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"trigger_push\"\n" ); REQUIRE( converted[1] == "\"target\" \"jp1\"\n" ); std::vector converted2 = ec.convert(entity2); REQUIRE( converted2[0] == "\"classname\" \"target_position\"\n" ); REQUIRE( converted2[1] == "\"origin\" \"-216.00000 -1488.000488 -132.00000\"\n" ); REQUIRE( converted2[2] == "\"targetname\" \"jp1\"\n" ); } TEST_CASE( "r2x: a single PointLight entity can be converted", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type PointLight"); entity.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); entity.push_back(" ColourXRGB32 color ffffc400"); entity.push_back(" Float intensity 1.500000"); entity.push_back(" Float nearAttenuation 32.000000"); entity.push_back(" Float farAttenuation 160.000000"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"light\"\n" ); REQUIRE( converted[1] == "\"origin\" \"-216.00000 -1488.000488 -132.00000\"\n" ); REQUIRE( converted[2] == "\"light\" \"75\"\n" ); INFO( converted[3] ); std::istringstream iss(converted[3]); std::string attribute; std::string r; float red; float green; float blue; iss >> attribute >> r >> green >> blue; r.erase(r.begin()); //removing preceding quote is necessary std::stringstream redStream(r); redStream >> red; REQUIRE( attribute == "\"_color\"" ); REQUIRE( fabs( 1.0 - red) <= DELTA ); REQUIRE( fabs( 0.768627 - green) <= DELTA ); REQUIRE( fabs( 0.0 - blue) <= DELTA ); } TEST_CASE( "r2x: PointLight defaults to white light of typical intensity", "[EntityConverter]" ) { // Instantiate object EntityConverter ec (PICKUP_FILENAME); // Mock up entity std::vector entity; entity.push_back(" type PointLight"); entity.push_back(" Vector3 position -216.00000 -132.00000 -1488.000488"); // Mock up entity queue std::queue> q; q.push( entity ); // Match related entities (none) ec.extractMapInfo( q ); // Convert a single entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"light\"\n" ); REQUIRE( converted[1] == "\"origin\" \"-216.00000 -1488.000488 -132.00000\"\n" ); REQUIRE( converted[2] == "\"light\" \"50\"\n" ); INFO( converted[3] ); std::istringstream iss(converted[3]); std::string attribute; std::string r; float red; float green; float blue; iss >> attribute >> r >> green >> blue; r.erase(r.begin()); //removing preceding quote is necessary std::stringstream redStream(r); redStream >> red; REQUIRE( attribute == "\"_color\"" ); REQUIRE( fabs( 0.0 - red) <= DELTA ); REQUIRE( fabs( 0.0 - green) <= DELTA ); REQUIRE( fabs( 0.0 - blue) <= DELTA ); } #endif //CATCH_CONFIG_MAIN