/*
* File: ctest.cc
* Summary: Crawl Lua test cases
* Written by: Darshan Shaligram
*
* ctest runs Lua tests found in the test directory. The intent here
* is to test parts of Crawl that can be easily tested from within Crawl
* itself (such as LOS). As a side-effect, writing Lua bindings to support
* tests will expand the available Lua bindings. :-)
*
* Tests will run only with Crawl built in its source tree without
* DATA_DIR_PATH set.
*/
#include "AppHdr.h"
#if DEBUG_DIAGNOSTICS || DEBUG_TESTS
#include "clua.h"
#include "cluautil.h"
#include "dlua.h"
#include "files.h"
#include "libutil.h"
#include "maps.h"
#include "message.h"
#include "ng-init.h"
#include "state.h"
#include "stuff.h"
#include <algorithm>
#include <vector>
namespace crawl_tests
{
const std::string test_dir = "test";
const std::string script_dir = "scripts";
const std::string test_player_name = "Superbug99";
const species_type test_player_species = SP_HUMAN;
const job_type test_player_job = JOB_FIGHTER;
const char *activity = "test";
int ntests = 0;
int nsuccess = 0;
typedef std::pair<std::string, std::string> file_error;
std::vector<file_error> failures;
void reset_test_data()
{
ntests = 0;
nsuccess = 0;
failures.clear();
you.your_name = test_player_name;
you.species = test_player_species;
you.char_class = test_player_job;
}
int crawl_begin_test(lua_State *ls)
{
mprf(MSGCH_PROMPT, "Starting %s: %s",
activity,
luaL_checkstring(ls, 1));
lua_pushnumber(ls, ++ntests);
return (1);
}
int crawl_test_success(lua_State *ls)
{
if (!crawl_state.script)
mprf(MSGCH_PROMPT, "Test success: %s", luaL_checkstring(ls, 1));
lua_pushnumber(ls, ++nsuccess);
return (1);
}
int crawl_script_args(lua_State *ls)
{
return clua_stringtable(ls, crawl_state.script_args);
}
static const struct luaL_reg crawl_test_lib[] =
{
{ "begin_test", crawl_begin_test },
{ "test_success", crawl_test_success },
{ "script_args", crawl_script_args },
{ NULL, NULL }
};
void init_test_bindings()
{
lua_stack_cleaner clean(dlua);
luaL_openlib(dlua, "crawl", crawl_test_lib, 0);
dlua.execfile("clua/test.lua", true, true);
initialise_branch_depths();
}
bool is_test_selected(const std::string &testname)
{
if (crawl_state.tests_selected.empty())
return (true);
for (int i = 0, size = crawl_state.tests_selected.size();
i < size; ++i)
{
const std::string &phrase(crawl_state.tests_selected[i]);
if (testname.find(phrase) != std::string::npos)
return (true);
}
return (false);
}
void run_test(const std::string &file)
{
if (!is_test_selected(file))
return;
++ntests;
mprf(MSGCH_DIAGNOSTICS, "Running %s %d: %s",
activity, ntests, file.c_str());
flush_prev_message();
const std::string path(
catpath(crawl_state.script? script_dir : test_dir, file));
dlua.execfile(path.c_str(), true, false);
if (dlua.error.empty())
++nsuccess;
else
failures.push_back(file_error(file, dlua.error));
}
// Assumes curses has already been initialized.
bool run_tests(bool exit_on_complete)
{
if (crawl_state.script)
activity = "script";
flush_prev_message();
run_map_preludes();
reset_test_data();
init_test_bindings();
if ((crawl_state.tests_selected.empty()
|| (crawl_state.tests_selected[0].find("makeitem") !=
std::string::npos))
&& !crawl_state.script)
{
makeitem_tests();
}
// Get a list of Lua files in test. Order of execution of
// tests should be irrelevant.
const std::vector<std::string> tests(
get_dir_files_ext(crawl_state.script? script_dir : test_dir,
".lua"));
std::for_each(tests.begin(), tests.end(),
run_test);
if (failures.empty() && !ntests && crawl_state.script)
failures.push_back(
file_error(
"Script setup",
"No scripts found matching " +
comma_separated_line(crawl_state.tests_selected.begin(),
crawl_state.tests_selected.end(),
", ",
", ")));
if (exit_on_complete)
{
cio_cleanup();
for (int i = 0, size = failures.size(); i < size; ++i)
{
const file_error &fe(failures[i]);
fprintf(stderr, "%s error: %s\n",
activity, fe.second.c_str());
}
const int code = failures.empty() ? 0 : 1;
end(code, false, "%d %ss, %d succeeded, %d failed",
ntests, activity, nsuccess, failures.size());
}
return (failures.empty());
}
}
#endif // DEBUG_DIAGNOSTICS