summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/ctest.cc
blob: 48227254e2ecc703868e32cc5634004df4ba2d92 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
 *  File:       ctest.cc
 *  Summary:    Crawl Lua test cases
 *  Written by: Darshan Shaligram
 *
 *  Modified for Crawl Reference by $Author$ on $Date$
 *
 *  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

#include "clua.h"
#include "files.h"
#include "luadgn.h"
#include "maps.h"
#include "stuff.h"

#include <algorithm>
#include <vector>

namespace crawl_tests
{
    const std::string test_dir = "test";
    const std::string test_player_name = "Superbug99";

    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();
        // XXX: Good grief, you.your_name is still not a C++ string?!
        strncpy(you.your_name, test_player_name.c_str(), kNameLen);
        you.your_name[kNameLen - 1] = 0;
    }

    int crawl_begin_test(lua_State *ls)
    {
        mprf(MSGCH_PROMPT, "Starting tests: %s", luaL_checkstring(ls, 1));
        lua_pushnumber(ls, ++ntests);
        return (1);
    }

    int crawl_test_success(lua_State *ls)
    {
        mprf(MSGCH_PROMPT, "Test success: %s", luaL_checkstring(ls, 1));
        lua_pushnumber(ls, ++nsuccess);
        return (1);
    }

    static const struct luaL_reg crawl_test_lib[] =
    {
        { "begin_test", crawl_begin_test },
        { "test_success", crawl_test_success },
        { NULL, NULL }
    };

    void init_test_bindings()
    {
        lua_stack_cleaner clean(dlua);
        luaL_openlib(dlua, "crawl", crawl_test_lib, 0);
    }

    void run_test(const std::string &file)
    {
        ++ntests;
        const std::string path(catpath(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)
    {
        run_map_preludes();
        reset_test_data();

        init_test_bindings();

        // 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(test_dir, ".lua"));
        std::for_each(tests.begin(), tests.end(),
                      run_test);

        if (exit_on_complete)
        {
            cio_cleanup();
            for (int i = 0, size = failures.size(); i < size; ++i)
            {
                const file_error &fe(failures[i]);
                fprintf(stderr, "Test error: %s\n",
                        fe.second.c_str());
            }
            const int code = failures.empty() ? 0 : 1;
            end(code, false, "%d tests, %d succeeded, %d failed",
                ntests, nsuccess, failures.size());
        }
        return (failures.empty());
    }
}

#endif // DEBUG_DIAGNOSTICS