1
0
forked from 0ad/0ad

Support random map script tests, fixes #4827.

Differential Revision: https://code.wildfiregames.com/D2085
Comments By: wraitii
This was SVN commit r23455.
This commit is contained in:
elexis 2020-01-29 00:30:07 +00:00
parent 67a4c18c74
commit 0a6db43c83
5 changed files with 192 additions and 34 deletions

View File

@ -1,14 +1,16 @@
function RandomMapLogger()
{
this.lastTime = undefined;
this.startTime = Engine.GetMicroseconds();
this.startTime = Engine.GetMicroseconds ? Engine.GetMicroseconds() : 0;
this.prefix = ""; // seems noisy
// Don't print in test cases
if (g_MapSettings.Name)
this.printDirectly(
this.prefix +
"Generating " + g_MapSettings.Name +
" of size " + g_MapSettings.Size +
" and " + getNumPlayers() + " players.\n");
" and " + (g_MapSettings.PlayerData.length - 1) + " players.\n");
}
RandomMapLogger.prototype.printDirectly = function(string)

View File

@ -0,0 +1,91 @@
Engine.LoadLibrary("rmgen");
var g_MapSettings = { "Size": 512 };
var g_Map = new RandomMap(0, "blackness");
// Test that that it checks by value, not by reference
{
let tileClass = new TileClass(2);
let reference1 = new Vector2D(1, 1);
let reference2 = new Vector2D(1, 1);
tileClass.add(reference1);
TS_ASSERT(tileClass.has(reference2));
}
// Test out-of-bounds
{
let tileClass = new TileClass(32);
let absentPoints = [
new Vector2D(0, 0),
new Vector2D(0, 1),
new Vector2D(1, 0),
new Vector2D(-1, -1),
new Vector2D(2048, 0),
new Vector2D(0, NaN),
new Vector2D(0, Infinity)
];
for (let point of absentPoints)
TS_ASSERT(!tileClass.has(point));
}
// Test multi-insertion
{
let tileClass = new TileClass(32);
let point = new Vector2D(1, 1);
tileClass.add(point);
tileClass.add(point);
TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 0), 1);
// Still one point remaining
tileClass.remove(point);
tileClass.remove(point);
TS_ASSERT(!tileClass.has(point));
}
// Test multi-insertion removal
{
let tileClass = new TileClass(32);
let point = new Vector2D(2, 7);
tileClass.add(point);
tileClass.add(point);
tileClass.remove(point);
TS_ASSERT(tileClass.has(point));
tileClass.remove(point);
TS_ASSERT(!tileClass.has(point));
}
// Test multi-insertion removal
{
let tileClass = new TileClass(55);
let point = new Vector2D(5, 4);
for (let i = 0; i < 50; ++i)
tileClass.add(point);
tileClass.remove(point);
TS_ASSERT(tileClass.has(point));
tileClass.remove(point);
TS_ASSERT(tileClass.has(point));
}
// Test getters
{
let tileClass = new TileClass(88);
let point = new Vector2D(5, 1);
tileClass.add(point);
let point2 = new Vector2D(4, 9);
tileClass.add(point2);
TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 1), 1);
TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 100), 2);
TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 1), 4);
TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 2), 12);
TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 3), 28);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -57,7 +57,8 @@ MapGeneratorInterruptCallback(JSContext* UNUSED(cx))
return true;
}
CMapGeneratorWorker::CMapGeneratorWorker()
CMapGeneratorWorker::CMapGeneratorWorker(ScriptInterface* scriptInterface) :
m_ScriptInterface(scriptInterface)
{
// If something happens before we initialize, that's a failure
m_Progress = -1;
@ -66,6 +67,7 @@ CMapGeneratorWorker::CMapGeneratorWorker()
CMapGeneratorWorker::~CMapGeneratorWorker()
{
// Wait for thread to end
if (m_WorkerThread.joinable())
m_WorkerThread.join();
}
@ -116,13 +118,6 @@ bool CMapGeneratorWorker::Run()
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
m_ScriptInterface->SetCallbackData(static_cast<void*> (this));
// Replace RNG with a seeded deterministic function
m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG);
RegisterScriptFunctions();
// Parse settings
JS::RootedValue settingsVal(cx);
if (!m_ScriptInterface->ParseJSON(m_Settings, &settingsVal) && settingsVal.isUndefined())
@ -144,7 +139,9 @@ bool CMapGeneratorWorker::Run()
!m_ScriptInterface->GetProperty(settingsVal, "Seed", seed))
LOGWARNING("CMapGeneratorWorker::Run: No seed value specified - using 0");
m_MapGenRNG.seed(seed);
InitScriptInterface(seed);
RegisterScriptFunctions_MapGenerator();
// Copy settings to global variable
JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject());
@ -165,8 +162,13 @@ bool CMapGeneratorWorker::Run()
return true;
}
void CMapGeneratorWorker::RegisterScriptFunctions()
void CMapGeneratorWorker::InitScriptInterface(const u32 seed)
{
m_ScriptInterface->SetCallbackData(static_cast<void*>(this));
m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG);
m_MapGenRNG.seed(seed);
// VFS
JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface);
@ -178,17 +180,6 @@ void CMapGeneratorWorker::RegisterScriptFunctions()
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadHeightmap>("LoadHeightmapImage");
m_ScriptInterface->RegisterFunction<JS::Value, VfsPath, CMapGeneratorWorker::LoadMapTerrain>("LoadMapTerrain");
// Progression and profiling
m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress");
m_ScriptInterface->RegisterFunction<double, CMapGeneratorWorker::GetMicroseconds>("GetMicroseconds");
m_ScriptInterface->RegisterFunction<void, JS::HandleValue, CMapGeneratorWorker::ExportMap>("ExportMap");
// Template functions
m_ScriptInterface->RegisterFunction<CParamNode, std::string, CMapGeneratorWorker::GetTemplate>("GetTemplate");
m_ScriptInterface->RegisterFunction<bool, std::string, CMapGeneratorWorker::TemplateExists>("TemplateExists");
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindTemplates>("FindTemplates");
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates");
// Engine constants
// Length of one tile of the terrain grid in metres.
@ -199,6 +190,20 @@ void CMapGeneratorWorker::RegisterScriptFunctions()
m_ScriptInterface->SetGlobal("MAP_BORDER_WIDTH", static_cast<int>(MAP_EDGE_TILES));
}
void CMapGeneratorWorker::RegisterScriptFunctions_MapGenerator()
{
// Template functions
m_ScriptInterface->RegisterFunction<CParamNode, std::string, CMapGeneratorWorker::GetTemplate>("GetTemplate");
m_ScriptInterface->RegisterFunction<bool, std::string, CMapGeneratorWorker::TemplateExists>("TemplateExists");
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindTemplates>("FindTemplates");
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates");
// Progression and profiling
m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress");
m_ScriptInterface->RegisterFunction<double, CMapGeneratorWorker::GetMicroseconds>("GetMicroseconds");
m_ScriptInterface->RegisterFunction<void, JS::HandleValue, CMapGeneratorWorker::ExportMap>("ExportMap");
}
int CMapGeneratorWorker::GetProgress()
{
std::lock_guard<std::mutex> lock(m_WorkerMutex);
@ -410,7 +415,7 @@ JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CxPrivate* pCxPri
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
CMapGenerator::CMapGenerator() : m_Worker(new CMapGeneratorWorker())
CMapGenerator::CMapGenerator() : m_Worker(new CMapGeneratorWorker(nullptr))
{
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -86,7 +86,7 @@ private:
class CMapGeneratorWorker
{
public:
CMapGeneratorWorker();
CMapGeneratorWorker(ScriptInterface* scriptInterface);
~CMapGeneratorWorker();
/**
@ -112,12 +112,18 @@ public:
*/
shared_ptr<ScriptInterface::StructuredClone> GetResults();
/**
* Set initial seed, callback data.
* Expose functions, globals and classes defined in this class relevant to the map and test scripts.
*/
void InitScriptInterface(const u32 seed);
private:
/**
* Expose functions defined in this class to the script.
* Expose functions defined in this class that are relevant to mapscripts but not the tests.
*/
void RegisterScriptFunctions();
void RegisterScriptFunctions_MapGenerator();
/**
* Load all scripts of the given library

View File

@ -0,0 +1,54 @@
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics/MapGenerator.h"
#include "ps/Filesystem.h"
#include "simulation2/system/ComponentTest.h"
class TestMapGenerator : public CxxTest::TestSuite
{
public:
void setUp()
{
g_VFS = CreateVfs();
g_VFS->Mount(L"", DataDir() / "mods" / "mod", VFS_MOUNT_MUST_EXIST);
g_VFS->Mount(L"", DataDir() / "mods" / "public", VFS_MOUNT_MUST_EXIST, 1); // ignore directory-not-found errors
CXeromyces::Startup();
}
void tearDown()
{
CXeromyces::Terminate();
g_VFS.reset();
}
void test_mapgen_scripts()
{
VfsPaths paths;
TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"maps/random/tests/", L"test_*.js", paths));
for (const VfsPath& path : paths)
{
ScriptInterface scriptInterface("Engine", "MapGenerator", g_ScriptRuntime);
ScriptTestSetup(scriptInterface);
CMapGeneratorWorker worker(&scriptInterface);
worker.InitScriptInterface(0);
scriptInterface.LoadGlobalScriptFile(path);
}
}
};