• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

APN-Pucky / tyrant_optimize / 26396287599

25 May 2026 10:39AM UTC coverage: 70.501% (+0.1%) from 70.364%
26396287599

Pull #112

github

web-flow
Merge 330a16f82 into adf7c9377
Pull Request #112: Correct skipped-simulation accounting by counting DB-hit results as skipped

18 of 18 new or added lines in 1 file covered. (100.0%)

2 existing lines in 1 file now uncovered.

4799 of 6807 relevant lines covered (70.5%)

8983151.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.51
/sim_test.cpp
1
// exec: ./tuo-test , verbose: ./tuo-test --log_level=all
2
// set-iterations ./tuo-test 100  , default = 10 // more than 100 cause errors
3
#ifdef TEST
4
#ifdef NQUEST // only without quests
5
#define BOOST_TEST_DYN_LINK
6
#define BOOST_TEST_MODULE sim
7

8
#include <chrono>
9
#include <boost/test/included/unit_test.hpp>
10
#include <boost/test/data/test_case.hpp>
11
#include <boost/test/data/monomorphic.hpp>
12
#include <iostream>
13
#include <fstream>
14
#include <iostream>
15
#include <exception>
16
#include <sstream>
17
#include <regex>
18
#include "tyrant.h"
19
#include "tyrant_optimize.h"
20
#include "sim.h"
21
#include "read.h"
22

23
using namespace std;
24
namespace bdata = boost::unit_test::data;
25
typedef std::tuple<FinalResults<long double>, std::string, double, std::string> Result; // score, output, time, result_deck
26
int iter = 1000;
27
unsigned seed = 0;
28
// limit for float diffing
29
// disable
30
double eps = 1.;
31
// enable
32
// double eps = 0.0000001;
33

34
// pipe output: https://stackoverflow.com/questions/5405016/can-i-check-my-programs-output-with-boost-test
35
struct ios_redirect
36
{
37
    ios_redirect(std::streambuf *new_buffer, std::ostream &ios)
168✔
38
        : old(ios.rdbuf(new_buffer)), iios(ios)
168✔
39
    {
40
    }
41

42
    ~ios_redirect()
168✔
43
    {
44
        iios.rdbuf(old);
84✔
45
    }
46

47
private:
48
    std::streambuf *old;
49
    std::ostream &iios;
50
};
51

52
struct TestInfo
77✔
53
{
54
    std::string your_deck, enemy_deck, bge;
55
};
56
std::ostream &operator<<(std::ostream &os, const TestInfo &ti)
61✔
57
{
58
    return os << "Your Deck: " << ti.your_deck << "; Enemy Deck: " << ti.enemy_deck << "; BGE: " << ti.bge;
61✔
59
}
60

61
inline Result run_sim(int argc, const char **argv, bool pipe_output = true)
84✔
62
{
63
    init();
84✔
64
    Result res;
84✔
65
    std::string rdeck = "";
84✔
66
    FinalResults<long double> fr;
84✔
67
    //
68

69
    auto start_time = std::chrono::system_clock::now();
84✔
70
    // pipe output
71
    std::stringstream output;
84✔
72
    std::stringstream eoutput;
84✔
73
    {
84✔
74
        ios_redirect guard2(eoutput.rdbuf(), std::cerr); // block warnings
84✔
75
        if (pipe_output)
84✔
76
        {
77
            ios_redirect guard1(output.rdbuf(), std::cout);
84✔
78

79
            //////////////////////
80
            // only single thread for string stream build
81
            //////////////////////
82
            const char **param = new const char *[argc + 2];
84✔
83
            for (int i = 0; i < argc; i++)
991✔
84
                param[i] = const_cast<char *>(argv[i]);
907✔
85
            param[argc] = const_cast<char *>("-t");
84✔
86
            param[argc + 1] = const_cast<char *>("1");
84✔
87
            auto rett = run(argc + 2, param);
84✔
88
            delete[] param;
84✔
89
            fr = rett.second;
84✔
90
            // result to string
91
            auto drc = rett;
84✔
92
            std::stringstream oss;
84✔
93
            if (drc.first->commander)
84✔
94
                oss << drc.first->commander->m_name << ", ";
84✔
95
            if (drc.first->alpha_dominion)
84✔
96
                oss << drc.first->alpha_dominion->m_name << ", ";
71✔
97
            print_cards_inline(drc.first->cards, oss, drc.first);
84✔
98
            rdeck = oss.str();
84✔
99
        }
84✔
100
        else
101
        {
102
            // no guard here
103
            //////////////////////
104
            // only single thread, else crashes
105
            //////////////////////
106
            const char **param = new const char *[argc + 2];
×
107
            for (int i = 0; i < argc; i++)
×
108
                param[i] = const_cast<char *>(argv[i]);
×
109
            param[argc] = const_cast<char *>("-t");
×
110
            param[argc + 1] = const_cast<char *>("1");
×
111
            auto rett = run(argc + 2, param);
×
112
            delete[] param;
×
113
            fr = rett.second;
×
114
            // result to string
115
            auto drc = rett;
×
116
            std::stringstream oss;
×
117
            if (drc.first->commander)
×
118
                oss << drc.first->commander->m_name << ", ";
×
119
            if (drc.first->alpha_dominion)
×
120
                oss << drc.first->alpha_dominion->m_name << ", ";
×
121
            print_cards_inline(drc.first->cards, oss, drc.first);
×
122
            rdeck = oss.str();
×
123
        }
×
124
    }
×
125

126
    auto end_time = std::chrono::system_clock::now();
84✔
127
    std::chrono::duration<double> delta_t = (end_time - start_time);
84✔
128
    res = std::make_tuple(fr, "\n" + debug_str + output.str(), delta_t.count(), rdeck);
252✔
129
    return res;
168✔
130
}
84✔
131

132
inline void check_win(Result result)
63✔
133
{
134
    BOOST_CHECK_MESSAGE(
63✔
135
        1 - eps <= std::get<0>(result).wins &&
136
            eps >= std::get<0>(result).losses &&
137
            eps >= std::get<0>(result).draws,
138
        std::get<1>(result));
139
    // BOOST_CHECK(100==result.points);
140
}
63✔
141
// inline void check_win_sim(const char* your_deck, const char* enemy_deck, const char* bge="") {
142
inline void check_win_sim(TestInfo ti)
61✔
143
{
144
    /////////////
145
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
146
    ////////////
147
    string s = std::to_string(iter);
61✔
148
    char *ii = new char[s.length()+1];
61✔
149
    strcpy(ii, s.c_str());
61✔
150
    s = std::to_string(seed);
61✔
151
    char *iii = new char[s.length()+1];
61✔
152
    strcpy(iii, s.c_str());
61✔
153
    const char *argv[] = {"tuo", ti.your_deck.c_str(), ti.enemy_deck.c_str(), "-e", ti.bge.c_str(), "sim", ii, "seed", iii, "prefix", "tests/sim/"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
61✔
154
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
155
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
61✔
156
    delete[] ii;
61✔
157
    delete[] iii;
61✔
158
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
159
    check_win(result);
122✔
160
}
61✔
161
inline double time_db_sim(std::string gnt1, std::string gnt2)
1✔
162
{
163
    /////////////
164
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
165
    ////////////
166
    string s = std::to_string(iter);
1✔
167
    char *ii = new char[s.length()+1];
1✔
168
    strcpy(ii, s.c_str());
1✔
169
    s = std::to_string(seed);
1✔
170
    char *iii = new char[s.length()+1];
1✔
171
    strcpy(iii, s.c_str());
1✔
172
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/db/", "db", "no-db-load"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1✔
173
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
174
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1✔
175
    delete[] ii;
1✔
176
    delete[] iii;
1✔
177
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
178
    // check_win(result);
179
    return std::get<2>(result);
1✔
180
}
1✔
181
inline double time_db(std::string gnt1, std::string gnt2)
1✔
182
{
183
    /////////////
184
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
185
    ////////////
186
    string s = std::to_string(iter);
1✔
187
    char *ii = new char[s.length()+1];
1✔
188
    strcpy(ii, s.c_str());
1✔
189
    s = std::to_string(seed);
1✔
190
    char *iii = new char[s.length()+1];
1✔
191
    strcpy(iii, s.c_str());
1✔
192
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/db/", "db"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1✔
193
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
194
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1✔
195
    delete[] ii;
1✔
196
    delete[] iii;
1✔
197
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
198
    // check_win(result);
199
    return std::get<2>(result);
1✔
200
}
1✔
201
inline double time_ml_sim(std::string gnt1, std::string gnt2)
1✔
202
{
203
    /////////////
204
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
205
    ////////////
206
    string s = std::to_string(iter);
1✔
207
    char *ii = new char[s.length()+1];
1✔
208
    strcpy(ii, s.c_str());
1✔
209
    s = std::to_string(seed);
1✔
210
    char *iii = new char[s.length()+1];
1✔
211
    strcpy(iii, s.c_str());
1✔
212
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/ml/", "no-db-load"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1✔
213
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
214
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1✔
215
    delete[] ii;
1✔
216
    delete[] iii;
1✔
217
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
218
    // check_win(result);
219
    return std::get<2>(result);
1✔
220
}
1✔
221
inline double time_ml(std::string gnt1, std::string gnt2)
1✔
222
{
223
    /////////////
224
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
225
    ////////////
226
    string s = std::to_string(iter);
1✔
227
    char *ii = new char[s.length()+1];
1✔
228
    strcpy(ii, s.c_str());
1✔
229
    s = std::to_string(seed);
1✔
230
    char *iii = new char[s.length()+1];
1✔
231
    strcpy(iii, s.c_str());
1✔
232
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/ml/", "no-db", "ml"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1✔
233
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
234
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1✔
235
    delete[] ii;
1✔
236
    delete[] iii;
1✔
237
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
238
    // check_win(result);
239
    return std::get<2>(result);
1✔
240
}
1✔
241

242
inline bool try_get_skipped_simulations(std::string const& output, unsigned long& skipped_simulations)
2✔
243
{
244
    std::smatch matches;
2✔
245
    if (std::regex_search(output, matches, std::regex("Evaluated [0-9]+ decks \\([0-9]+ \\+ ([0-9]+) simulations\\)\\.")))
4✔
246
    {
247
        skipped_simulations = std::stoul(matches[1].str());
6✔
248
        return true;
2✔
249
    }
250
    return false;
251
}
2✔
252

253
inline void genetic(std::string gnt1, std::string gnt2)
254
{
255
    string s = std::to_string(iter);
256
    char *ii = new char[s.length()+1];
257
    strcpy(ii, s.c_str());
258
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "brawl", "genetic", ii};
259
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv, false));
260
    std::ofstream mf;
261
    mf.open("out.csv", std::ios_base::app);
262
    mf << gnt1 << ";" << gnt2 << ";" << std::get<0>(result).points << ";" << std::get<2>(result) << std::endl;
263
    mf.close();
264
}
265

266
inline void check_algo(std::string gnt1, std::string gnt2, std::string algo)
3✔
267
{
268
    string s = std::to_string(iter);
3✔
269
    char *ii = new char[s.length()+1];
3✔
270
    strcpy(ii, s.c_str());
3✔
271
    s = std::to_string(seed);
3✔
272
    char *iii = new char[s.length()+1];
3✔
273
    strcpy(iii, s.c_str());
3✔
274
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
3✔
275
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
3✔
276
    // Do the algo
277
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
3✔
278
    Result result(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
3✔
279
    // Rerun sim with optimized deck to check if algo produced wrong sim result
280
    const char *argv3[] = {"tuo", std::get<3>(result).c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
3✔
281
    Result result_opt(run_sim(sizeof(argv3) / sizeof(*argv3), argv3));
3✔
282
    delete[] ii;
3✔
283
    delete[] iii;
3✔
284
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
18✔
285
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
286
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
287
}
9✔
288
inline void check_anneal(std::string gnt1, std::string gnt2)
1✔
289
{
290
    std::string algo = "anneal";
1✔
291
    double anneal_temp = 100;
1✔
292
    double anneal_temp_down = 0.01;
1✔
293
    string s = std::to_string(iter);
1✔
294
    char *ii = new char[s.length()+1];
1✔
295
    strcpy(ii, s.c_str());
1✔
296
    s = std::to_string(seed);
1✔
297
    char *iii = new char[s.length()+1];
1✔
298
    strcpy(iii, s.c_str());
1✔
299
    s = std::to_string(anneal_temp);
1✔
300
    char *iv = new char[s.length()+1];
1✔
301
    strcpy(iv, s.c_str());
1✔
302
    s = std::to_string(anneal_temp_down);
1✔
303
    char *v = new char[s.length()+1];
1✔
304
    strcpy(v, s.c_str());
1✔
305
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1✔
306
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
1✔
307
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), ii, iv, v, "seed", iii, "prefix", "tests/algo/", "no-db"};
1✔
308
    Result result(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
1✔
309
    // Rerun sim with optimized deck to check if algo produced wrong sim result
310
    const char *argv3[] = {"tuo", std::get<3>(result).c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1✔
311
    Result result_opt(run_sim(sizeof(argv3) / sizeof(*argv3), argv3));
1✔
312
    delete[] ii;
1✔
313
    delete[] iii;
1✔
314
    delete[] iv;
1✔
315
    delete[] v;
1✔
316
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
6✔
317
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
318
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
319
}
3✔
320
inline void check_climbex(std::string gnt1, std::string gnt2)
1✔
321
{
322
    std::string algo = "climbex";
1✔
323
    int init = 10;
1✔
324
    string s = std::to_string(iter);
1✔
325
    char *ii = new char[s.length()+1];
1✔
326
    strcpy(ii, s.c_str());
1✔
327
    s = std::to_string(seed);
1✔
328
    char *iii = new char[s.length()+1];
1✔
329
    strcpy(iii, s.c_str());
1✔
330
    s = std::to_string(init);
1✔
331
    char *iv = new char[s.length()+1];
1✔
332
    strcpy(iv, s.c_str());
1✔
333
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1✔
334
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
1✔
335
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), iv, ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1✔
336
    Result result(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
1✔
337
    // Rerun sim with optimized deck to check if algo produced wrong sim result
338
    const char *argv3[] = {"tuo", std::get<3>(result).c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1✔
339
    Result result_opt(run_sim(sizeof(argv3) / sizeof(*argv3), argv3));
1✔
340
    delete[] ii;
1✔
341
    delete[] iii;
1✔
342
    delete[] iv;
1✔
343
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
6✔
344
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
345
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
346
}
3✔
347

348
inline void check_climb_forts(std::string gnt1, std::string gnt2, std::string yf, std::string ef)
349
{
350
    std::string algo = "climb_forts";
351
    int init = 10;
352
    string s = std::to_string(iter);
353
    char *ii = new char[s.length()+1];
354
    strcpy(ii, s.c_str());
355
    s = std::to_string(seed);
356
    char *iii = new char[s.length()+1];
357
    strcpy(iii, s.c_str());
358
    s = std::to_string(init);
359
    char *iv = new char[s.length()+1];
360
    strcpy(iv, s.c_str());
361
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "yf", yf.c_str(), "yfpool", "2", "ef", ef.c_str(), "efpool", "2", "prefix", "tests/algo/", "no-db"};
362
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
363
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), iv, ii, "seed", iii, "yf", yf.c_str(), "yfpool", "2", "ef", ef.c_str(), "efpool", "2", "prefix", "tests/algo/", "no-db"};
364
    Result result_opt(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
365
    // Rerun sim with optimized deck to check if algo produced wrong sim result
366
    // const char* argv3[] = {"tuo",gnt1.c_str(),gnt2.c_str(),"sim",ii, "seed", iii,  "yf",std::get<3>(result).c_str(), "yfpool","2", "ef", ef.c_str(), "efpool", "2","prefix" , "tests/algo/", "no-db"};
367
    // Result result_opt(run_sim(sizeof(argv3)/sizeof(*argv3),argv3));
368
    delete[] ii;
369
    delete[] iii;
370
    delete[] iv;
371
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
372
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
373
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
374
}
375

376
std::vector<TestInfo> read_test_file(const std::string filename)
5✔
377
{
378
    std::vector<TestInfo> ret;
5✔
379
    std::ifstream test_file(filename);
5✔
380
    if (test_file.good())
5✔
381
    {
382
        try
383
        {
384
            while (test_file && !test_file.eof())
82✔
385
            {
386
                TestInfo ti;
77✔
387
                std::string line, yd, ed, bg;
77✔
388
                std::getline(test_file, line);
77✔
389
                if (is_line_empty_or_commented(line))
77✔
390
                {
391
                    continue;
16✔
392
                }
393
                std::istringstream iss(line);
61✔
394
                std::getline(iss, ti.your_deck, ';');
61✔
395
                std::getline(iss, ti.enemy_deck, ';');
61✔
396
                std::getline(iss, ti.bge, ';');
61✔
397
                ret.push_back(ti);
61✔
398
            }
77✔
399
        }
400
        catch (std::exception &e)
×
401
        {
402
        }
×
403
    }
404
    return ret;
5✔
405
}
5✔
406

407
BOOST_AUTO_TEST_SUITE(test)
408
BOOST_AUTO_TEST_CASE(test_init)
7✔
409
{
410
    init();
1✔
411

412
    seed = std::chrono::system_clock::now().time_since_epoch().count() * 2654435761;
1✔
413
    if (boost::unit_test::framework::master_test_suite().argc >= 2)
1✔
414
    {
415
        iter = atoi(boost::unit_test::framework::master_test_suite().argv[1]);
×
416
    }
417
    if (boost::unit_test::framework::master_test_suite().argc >= 3)
1✔
418
    {
419
        seed = atoi(boost::unit_test::framework::master_test_suite().argv[2]);
×
420
    }
421
    //BOOST_TEST_MESSAGE("ITER: " << iter);
422
    BOOST_TEST_MESSAGE("SEED: " << seed);
2✔
423
    BOOST_CHECK(1 == 1); //..
1✔
424
}
1✔
425

426
BOOST_AUTO_TEST_SUITE(test_algo)
427
BOOST_AUTO_TEST_CASE(test_algo_init)
6✔
428
{
429
    iter = 1000;
1✔
430
}
×
431
BOOST_AUTO_TEST_SUITE(test_algo_climb)
432
BOOST_AUTO_TEST_CASE(test_algo_climb)
7✔
433
{
434
    check_algo("Mission#134", "Mission#135", "climb");
2✔
435
}
1✔
436
BOOST_AUTO_TEST_SUITE_END()
437

438
BOOST_AUTO_TEST_SUITE(test_algo_anneal)
439
BOOST_AUTO_TEST_CASE(test_algo_anneal)
7✔
440
{
441
    check_anneal("Mission#134", "Mission#135");
2✔
442
}
1✔
443
BOOST_AUTO_TEST_SUITE_END()
444

445
BOOST_AUTO_TEST_SUITE(test_algo_climbex)
446
BOOST_AUTO_TEST_CASE(test_algo_climbex)
7✔
447
{
448
    check_climbex("Mission#134", "Mission#135");
2✔
449
}
1✔
450
BOOST_AUTO_TEST_SUITE_END()
451

452
BOOST_AUTO_TEST_SUITE(test_algo_genetic)
453
BOOST_AUTO_TEST_CASE(test_algo_genetic)
7✔
454
{
455
    check_algo("Mission#134", "Mission#135", "genetic");
2✔
456
}
1✔
457
BOOST_AUTO_TEST_SUITE_END()
458

459
BOOST_AUTO_TEST_SUITE(test_algo_beam)
460
BOOST_AUTO_TEST_CASE(test_algo_beam)
7✔
461
{
462
    check_algo("Mission#134", "Mission#135", "beam");
2✔
463
}
1✔
464
BOOST_AUTO_TEST_SUITE_END()
465

466
// TODO Fix this test
467
// BOOST_AUTO_TEST_SUITE(test_algo_climb_forts)
468
// BOOST_AUTO_TEST_CASE(test_algo_climb_forts)
469
//{
470
//        check_climb_forts("Mission#135","Mission#135","LC#2, TC#2, IB#2, DF#2","LC#2, TC#2, IB#2, DF#2");
471
//}
472
// BOOST_AUTO_TEST_SUITE_END()
473

474
BOOST_AUTO_TEST_SUITE_END()
475

476
BOOST_AUTO_TEST_SUITE(test_sim)
477
BOOST_AUTO_TEST_CASE(test_sim_init)
6✔
478
{
479
    iter = 100;
1✔
480
    debug_print++;
1✔
481
    debug_cached++;
1✔
482
    debug_line = true;
1✔
483
}
×
484
/////////////////////////////////////
485
// Test Cases !should! be very close fights for maximum sensitivity of errors
486
/////////////////////////////////////
487
BOOST_AUTO_TEST_SUITE(test_single_units)
488
BOOST_DATA_TEST_CASE(test_single_units, bdata::make(read_test_file("tests/test_sinlge_units.csv")), ti)
42✔
489
{
490
    check_win_sim(ti);
6✔
491
}
6✔
492
BOOST_AUTO_TEST_SUITE_END()
493

494
BOOST_AUTO_TEST_SUITE(test_multi_units)
495
BOOST_DATA_TEST_CASE(test_multi_units, bdata::make(read_test_file("tests/test_multi_units.csv")), ti)
91✔
496
{
497
    check_win_sim(ti);
13✔
498
}
13✔
499
BOOST_AUTO_TEST_SUITE_END()
500

501
BOOST_AUTO_TEST_SUITE(test_bges)
502
BOOST_DATA_TEST_CASE(test_bges, bdata::make(read_test_file("tests/test_bges.csv")), ti)
28✔
503
{
504
    check_win_sim(ti);
4✔
505
}
4✔
506
BOOST_AUTO_TEST_SUITE_END()
507

508
BOOST_AUTO_TEST_SUITE(test_whole_decks)
509
BOOST_DATA_TEST_CASE(test_whole_decks, bdata::make(read_test_file("tests/test_whole_decks.csv")), ti)
7✔
510
{
511
    check_win_sim(ti);
1✔
512
}
1✔
513
BOOST_AUTO_TEST_SUITE_END()
514

515
BOOST_AUTO_TEST_SUITE(test_crashes)
516
BOOST_DATA_TEST_CASE(test_crashes, bdata::make(read_test_file("tests/test_crash.csv")), ti)
259✔
517
{
518
    eps = 1.; // only check for crashes now
37✔
519
    check_win_sim(ti);
37✔
520
}
37✔
521
BOOST_AUTO_TEST_SUITE_END()
522
BOOST_AUTO_TEST_SUITE_END()
523

524
BOOST_AUTO_TEST_SUITE(test_db)
525
BOOST_AUTO_TEST_CASE(test_db_init)
6✔
526
{
527
    iter = 100000;
1✔
528
    debug_print = 0;
1✔
529
    debug_cached = 0;
1✔
530
    debug_line = false;
1✔
531
}
×
532
BOOST_AUTO_TEST_SUITE(test_db_scaling)
533
BOOST_AUTO_TEST_CASE(test_db_scaling)
7✔
534
{
535
    BOOST_TEST_MESSAGE("DB time improvement test");
2✔
536
    auto t1 = time_db_sim("Sir Alaric the Swift-1, Broodmother's Nexus-1, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1✔
537
    auto t2 =     time_db("Sir Alaric the Swift-1, Broodmother's Nexus-1, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1✔
538
    BOOST_CHECK_MESSAGE(t1 > t2, "DB time improvement failed: " + std::to_string(t1) + " > " + std::to_string(t2));
3✔
539
}
1✔
540
BOOST_AUTO_TEST_SUITE_END()
541

542
BOOST_AUTO_TEST_SUITE(test_db_skipped_counter)
543
BOOST_AUTO_TEST_CASE(test_db_skipped_counter_on_hit)
7✔
544
{
545
    iter = 1;
1✔
546
    const char *warmup_argv[] = {"tuo", "Mission#134", "Mission#135", "beam", "1", "seed", "1", "prefix", "tests/db/", "db", "no-db-load"};
1✔
547
    Result warmup(run_sim(sizeof(warmup_argv) / sizeof(*warmup_argv), warmup_argv));
1✔
548
    unsigned long warmup_skipped{0};
1✔
549
    BOOST_REQUIRE_MESSAGE(try_get_skipped_simulations(std::get<1>(warmup), warmup_skipped), "Failed to parse skipped simulations from warmup output");
1✔
550

551
    const char *cached_argv[] = {"tuo", "Mission#134", "Mission#135", "beam", "1", "seed", "1", "prefix", "tests/db/", "db"};
1✔
552
    Result cached(run_sim(sizeof(cached_argv) / sizeof(*cached_argv), cached_argv));
1✔
553
    unsigned long cached_skipped{0};
1✔
554
    BOOST_REQUIRE_MESSAGE(try_get_skipped_simulations(std::get<1>(cached), cached_skipped), "Failed to parse skipped simulations from cached output");
1✔
555
    BOOST_CHECK_MESSAGE(cached_skipped > 0, "Expected skipped simulations to include DB-hit results, got " + std::to_string(cached_skipped) + ". Warmup skipped: " + std::to_string(warmup_skipped));
3✔
556
}
2✔
557
BOOST_AUTO_TEST_SUITE_END()
558
BOOST_AUTO_TEST_SUITE_END()
559

560
BOOST_AUTO_TEST_SUITE(test_ml)
561
BOOST_AUTO_TEST_CASE(test_ml_init)
6✔
562
{
563
    iter = 100000;
1✔
564
    debug_print = 0;
1✔
565
    debug_cached = 0;
1✔
566
    debug_line = false;
1✔
UNCOV
567
}
×
568
BOOST_AUTO_TEST_SUITE(test_ml_scaling)
569
BOOST_AUTO_TEST_CASE(test_ml_scaling)
7✔
570
{
571
    auto t1 = time_ml_sim("Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1✔
572
    auto t2 = time_ml("Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1✔
573
    BOOST_CHECK_MESSAGE(t1 > t2, "ML time improvement failed: " + std::to_string(t1) + " > " + std::to_string(t2));
3✔
574
}
1✔
575
BOOST_AUTO_TEST_SUITE_END()
576
BOOST_AUTO_TEST_SUITE_END()
577

578
// Define raw C-style arrays
579
static const char* test_case_1[] = {
580
    "tuo", "Bug86", "Bug86", "sim", "100", "seed", "100", "prefix", "tests/sim/",
581
    "update-reduce-delay-summoned-by-tower", nullptr
582
};
583

584
static const char* test_case_2[] = {
585
    "tuo", "Bug86", "Bug86", "sim", "100", "seed", "100", "prefix", "tests/sim/",
586
    "no-update-reduce-delay-summoned-by-tower", nullptr
587
};
588

589
static const std::array<const char**, 2> argv_dataset = {
590
    test_case_1,
591
    test_case_2
592
};
593
BOOST_AUTO_TEST_SUITE(test_fixes)
594
BOOST_AUTO_TEST_CASE(test_fixes_init)
6✔
595
{
596
    iter = 10000;
1✔
597
    debug_print = 0;
1✔
598
    debug_cached = 0;
1✔
599
    debug_line = false;
1✔
600
    eps = 1.; // only check for crashes now
1✔
UNCOV
601
}
×
602
BOOST_AUTO_TEST_SUITE(test_fixes_run)
603
BOOST_DATA_TEST_CASE(test_fixes_run, bdata::make(test::argv_dataset),argv)
14✔
604
{
605
    // Convert vector to argv-style array
606
    int argc = 0;
2✔
607
    while (argv[argc] != nullptr) ++argc;
22✔
608
    check_win(run_sim(argc, argv));
2✔
609
    //check_win(run_sim(sizeof(argv) / sizeof(*argv), argv));
610
}
2✔
611
BOOST_AUTO_TEST_SUITE_END()
612
BOOST_AUTO_TEST_SUITE_END()
613

614
BOOST_AUTO_TEST_SUITE_END()
615
#endif
616
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc