Index: ps/trunk/source/simulation2/components/tests/test_scripts.h =================================================================== --- ps/trunk/source/simulation2/components/tests/test_scripts.h (revision 24181) +++ ps/trunk/source/simulation2/components/tests/test_scripts.h (revision 24182) @@ -1,106 +1,110 @@ /* Copyright (C) 2019 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 . */ #include "simulation2/system/ComponentTest.h" #include "ps/Filesystem.h" +#include "scriptinterface/ScriptContext.h" + class TestComponentScripts : 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(); } static void load_script(const ScriptInterface& scriptInterface, const VfsPath& pathname) { CVFSFile file; TS_ASSERT_EQUALS(file.Load(g_VFS, pathname), PSRETURN_OK); CStr content = file.DecodeUTF8(); // assume it's UTF-8 TSM_ASSERT(L"Running script "+pathname.string(), scriptInterface.LoadScript(pathname, content)); } static void Script_LoadComponentScript(ScriptInterface::CmptPrivate* pCmptPrivate, const VfsPath& pathname) { CComponentManager* componentManager = static_cast (pCmptPrivate->pCBData); TS_ASSERT(componentManager->LoadScript(VfsPath(L"simulation/components") / pathname)); } static void Script_LoadHelperScript(ScriptInterface::CmptPrivate* pCmptPrivate, const VfsPath& pathname) { CComponentManager* componentManager = static_cast (pCmptPrivate->pCBData); TS_ASSERT(componentManager->LoadScript(VfsPath(L"simulation/helpers") / pathname)); } void test_global_scripts() { if (!VfsDirectoryExists(L"globalscripts/tests/")) { debug_printf("Skipping globalscripts tests (can't find binaries/data/mods/public/globalscripts/tests/)\n"); return; } VfsPaths paths; TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"globalscripts/tests/", L"test_*.js", paths)); for (const VfsPath& path : paths) { CSimContext context; CComponentManager componentManager(context, g_ScriptContext, true); ScriptTestSetup(componentManager.GetScriptInterface()); load_script(componentManager.GetScriptInterface(), path); } } void test_scripts() { if (!VfsFileExists(L"simulation/components/tests/setup.js")) { debug_printf("Skipping component scripts tests (can't find binaries/data/mods/public/simulation/components/tests/setup.js)\n"); return; } VfsPaths paths; TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"simulation/components/tests/", L"test_*.js", paths)); TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"simulation/helpers/tests/", L"test_*.js", paths)); paths.push_back(VfsPath(L"simulation/components/tests/setup_test.js")); for (const VfsPath& path : paths) { + // Clean up previous scripts. + g_ScriptContext->ShrinkingGC(); CSimContext context; CComponentManager componentManager(context, g_ScriptContext, true); ScriptTestSetup(componentManager.GetScriptInterface()); componentManager.GetScriptInterface().RegisterFunction ("LoadComponentScript"); componentManager.GetScriptInterface().RegisterFunction ("LoadHelperScript"); componentManager.LoadComponentTypes(); load_script(componentManager.GetScriptInterface(), L"simulation/components/tests/setup.js"); load_script(componentManager.GetScriptInterface(), path); } } }; Index: ps/trunk/source/test_setup.cpp =================================================================== --- ps/trunk/source/test_setup.cpp (revision 24181) +++ ps/trunk/source/test_setup.cpp (revision 24182) @@ -1,150 +1,158 @@ /* 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 . */ // Got to be consistent with what the rest of the source files do before // including precompiled.h, so that the PCH works correctly #ifndef CXXTEST_RUNNING #define CXXTEST_RUNNING #endif #define _CXXTEST_HAVE_STD #include "precompiled.h" #include #include "lib/self_test.h" #include #if OS_WIN #include "lib/sysdep/os/win/wdbg_heap.h" #endif #include "lib/timer.h" #include "lib/sysdep/sysdep.h" #include "ps/Profiler2.h" #include "scriptinterface/ScriptEngine.h" #include "scriptinterface/ScriptContext.h" class LeakReporter : public CxxTest::GlobalFixture { virtual bool tearDownWorld() { // Enable leak reporting on exit. // (This is done in tearDownWorld so that it doesn't report 'leaks' // if the program is aborted before finishing cleanly.) #if OS_WIN wdbg_heap_Enable(true); #endif return true; } virtual bool setUpWorld() { #if MSC_VERSION // (Warning: the allocation numbers seem to differ by 3 when you // run in the build process vs the debugger) // _CrtSetBreakAlloc(1952); #endif return true; } }; class MiscSetup : public CxxTest::GlobalFixture { virtual bool setUpWorld() { // Timer must be initialised, else things will break when tests do IO timer_LatchStartTime(); #if OS_MACOSX || OS_BSD // See comment in GameSetup.cpp FixLocales setlocale(LC_CTYPE, "UTF-8"); #endif ThreadUtil::SetMainThread(); g_Profiler2.Initialise(); m_ScriptEngine = new ScriptEngine; g_ScriptContext = ScriptContext::CreateContext(); return true; } virtual bool tearDownWorld() { g_ScriptContext.reset(); SAFE_DELETE(m_ScriptEngine); g_Profiler2.Shutdown(); return true; } + virtual bool setUp() + { + // Clean up any JS leftover between tests. + g_ScriptContext->ShrinkingGC(); + + return true; + } + private: // We're doing the initialization and shutdown of the ScriptEngine explicitly here // to make sure it's only initialized when setUpWorld is called. ScriptEngine* m_ScriptEngine; }; static LeakReporter leakReporter; static MiscSetup miscSetup; // Definition of functions from lib/self_test.h bool ts_str_contains(const std::string& str1, const std::string& str2) { return str1.find(str2) != str1.npos; } bool ts_str_contains(const std::wstring& str1, const std::wstring& str2) { return str1.find(str2) != str1.npos; } // we need the (version-controlled) binaries/data directory because it // contains input files (it is assumed that developer's machines have // write access to those directories). note that argv0 isn't // available, so we use sys_ExecutablePathname. OsPath DataDir() { return sys_ExecutablePathname().Parent()/".."/"data"; } // Script-based testing setup: namespace { void script_TS_FAIL(ScriptInterface::CmptPrivate* UNUSED(pCmptPrivate), const std::wstring& msg) { TS_FAIL(utf8_from_wstring(msg).c_str()); } } void ScriptTestSetup(const ScriptInterface& scriptinterface) { scriptinterface.RegisterFunction("TS_FAIL"); // Load the TS_* function definitions // (We don't use VFS because tests might not have the normal VFS paths loaded) OsPath path = DataDir()/"tests"/"test_setup.js"; std::ifstream ifs(OsString(path).c_str()); ENSURE(ifs.good()); std::string content((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); bool ok = scriptinterface.LoadScript(L"test_setup.js", content); ENSURE(ok); }