The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
test_rng.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
3 by Chris Beck <render787@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-test"
17
18#include <boost/test/unit_test.hpp>
19#include "random_synced.hpp"
21#include "config.hpp"
22#include <sstream>
23#include <iomanip>
24
26
27/* this test adapted from validation routine at
28 http://www.boost.org/doc/libs/1_38_0/libs/random/random_test.cpp
29*/
30BOOST_AUTO_TEST_CASE( validate_mt19937 )
31{
32 std::mt19937 rng;
33 for (int i = 0; i < 9999 ; i++) {
34 // silence C4834 warning in MSVC
35 static_cast<void>(rng());
36 }
37 unsigned long val = rng();
38 BOOST_CHECK_EQUAL( val , 4123659995U );
39}
40
41/* this test checks the soundness of mt_rng string manipulations */
42BOOST_AUTO_TEST_CASE( test_mt_rng_seed_manip )
43{
44 uint32_t seed = 42;
45 std::stringstream stream;
46 stream << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed;
47
48 std::string seed_str = stream.str();
49
51 rng.seed_random(seed_str);
52
53 BOOST_CHECK (rng.get_random_seed() == seed);
54 BOOST_CHECK (rng.get_random_seed_str() == seed_str);
55
56 std::string seed_str2 = rng.get_random_seed_str();
57 rng.seed_random(seed_str2);
58
59 BOOST_CHECK (rng.get_random_seed() == seed);
60 BOOST_CHECK (rng.get_random_seed_str() == seed_str);
61
62
63 uint32_t seed3 = 1123581321; //try the same with a different number
64 std::stringstream stream2;
65 stream2 << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed3;
66 std::string seed_str3 = stream2.str();
67
68 rng.seed_random(seed_str3);
69 BOOST_CHECK (rng.get_random_seed() == seed3);
70 BOOST_CHECK (rng.get_random_seed_str() == seed_str3);
71
72 std::string seed_str4 = rng.get_random_seed_str();
73 rng.seed_random(seed_str4);
74
75 BOOST_CHECK (rng.get_random_seed() == seed3);
76 BOOST_CHECK (rng.get_random_seed_str() == seed_str3);
77
78
79 //now check that the results that shouldn't match don't
80 BOOST_CHECK (seed != seed3);
81 BOOST_CHECK (seed_str != seed_str3);
82
83}
84
85BOOST_AUTO_TEST_CASE( test_mt_rng_config_seed_manip )
86{
87 uint32_t seed = 42;
88 std::stringstream stream;
89 stream << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed;
90 std::string seed_str = stream.str();
91
92 config cfg;
93 cfg["random_seed"] = seed_str;
94 cfg["random_calls"] = 0;
95
97
98 BOOST_CHECK (rng.get_random_seed() == seed);
99 BOOST_CHECK (rng.get_random_seed_str() == seed_str);
100
101 std::string seed_str2 = rng.get_random_seed_str();
102 rng.seed_random(seed_str2);
103
104 BOOST_CHECK (rng.get_random_seed() == seed);
105 BOOST_CHECK (rng.get_random_seed_str() == seed_str);
106
107
108 uint32_t seed3 = 1123581321; //try the same with a different number
109 std::stringstream stream2;
110 stream2 << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed3;
111 std::string seed_str3 = stream2.str();
112
113 config cfg2;
114 cfg2["random_seed"] = seed_str3;
115 cfg2["random_calls"] = 0;
116
117 randomness::mt_rng rng2(cfg2);
118
119 BOOST_CHECK (rng2.get_random_seed() == seed3);
120 BOOST_CHECK (rng2.get_random_seed_str() == seed_str3);
121
122 std::string seed_str4 = rng2.get_random_seed_str();
123 rng2.seed_random(seed_str4);
124
125 BOOST_CHECK (rng2.get_random_seed() == seed3);
126 BOOST_CHECK (rng2.get_random_seed_str() == seed_str3);
127
128
129 //now check that the results that shouldn't match don't
130 BOOST_CHECK (seed != seed3);
131 BOOST_CHECK (seed_str != seed_str3);
132}
133
134BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility )
135{
136 config cfg;
137 cfg["random_seed"] = "5eedf00d";
138 cfg["random_calls"] = 0;
139
142
143 BOOST_CHECK(rng1 == rng2);
144 for (int i = 0; i < 10 ; i++) {
145 BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
146 }
147}
148
149BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility2 )
150{
151 config cfg;
152 cfg["random_seed"] = "18da5eed";
153 cfg["random_calls"] = 9999;
154
157
158 BOOST_CHECK(rng1 == rng2);
159 for (int i = 0; i < 10 ; i++) {
160 BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
161 }
162}
163
164BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility3 )
165{
167 config cfg;
168 cfg["random_seed"] = rng1.get_random_seed_str();
169 cfg["random_calls"] = rng1.get_random_calls();
170
172
173 BOOST_CHECK(rng1 == rng2);
174 for (int i = 0; i < 10 ; i++) {
175 BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
176 }
177}
178
179BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility4 )
180{
182
183 for (int i = 0; i < 5; i++) {
184 rng1.get_next_random();
185 }
186
187 config cfg;
188 cfg["random_seed"] = rng1.get_random_seed_str();
189 cfg["random_calls"] = rng1.get_random_calls();
190
192
193 BOOST_CHECK(rng1 == rng2);
194 BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
195}
196
197BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility5 )
198{
199 config cfg;
200 cfg["random_seed"] = "5eedc0de";
201 cfg["random_calls"] = 0;
202
204
205 for (int i = 0; i < 9999 ; i++) {
206 rng.get_next_random();
207 }
208
209 config cfg2;
210 cfg2["random_seed"] = rng.get_random_seed_str();
211 cfg2["random_calls"] = rng.get_random_calls();
212
213 randomness::mt_rng rng2(cfg2);
214
215 uint32_t result1 = rng.get_next_random();
216 uint32_t result2 = rng2.get_next_random();
217
218 BOOST_CHECK (rng == rng2);
219 BOOST_CHECK (rng.get_random_seed_str() == rng2.get_random_seed_str());
220 BOOST_CHECK (rng.get_random_calls() == rng2.get_random_calls());
221 BOOST_CHECK (result1 == result2);
222
223 config cfg_save;
224 cfg_save["random_seed"] = rng.get_random_seed_str();
225 cfg_save["random_calls"] = rng.get_random_calls();
226
227 uint32_t result3 = rng.get_next_random();
228
229 randomness::mt_rng rng3(cfg_save);
230 uint32_t result4 = rng3.get_next_random();
231
232 BOOST_CHECK (rng == rng3);
233 BOOST_CHECK (rng.get_random_seed_str() == rng3.get_random_seed_str());
234 BOOST_CHECK (rng.get_random_calls() == rng3.get_random_calls());
235 BOOST_CHECK (result3 == result4);
236}
237
238namespace {
239
240void validate_seed_string(const std::string& seed_str)
241{
242 config cfg;
243 cfg["random_seed"] = seed_str;
244 cfg["random_calls"] = 0;
245
247
248 for (int i = 0; i < 9999 ; i++) {
249 rng1.get_next_random();
250 }
251
252 config cfg2;
253 cfg2["random_seed"] = rng1.get_random_seed_str();
254 cfg2["random_calls"] = rng1.get_random_calls();
255
256 randomness::mt_rng rng2(cfg2);
257
258 for (int i = 0; i < 9999 ; i++) {
259 rng1.get_next_random();
260 rng2.get_next_random();
261 }
262
263 BOOST_CHECK(rng1 == rng2);
264 BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
265
266}
267
268}
269
270BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility_coverage )
271{
272 validate_seed_string("0000badd");
273 validate_seed_string("00001234");
274 validate_seed_string("deadbeef");
275 validate_seed_string("12345678");
276 validate_seed_string("00009999");
277 validate_seed_string("ffffaaaa");
278 validate_seed_string("11110000");
279 validate_seed_string("10101010");
280 validate_seed_string("aaaa0000");
281}
282
283namespace {
284
285std::string validate_get_random_int_seed_generator()
286{
287 return "dada5eed";
288}
289
290}
291
292#define validation_get_random_int_num_draws 19999
293
294#define validation_get_random_int_max 32000
295
296#define validation_get_random_int_correct_answer 10885
297
298/**
299 * This test and the next validate that we are getting the correct values
300 * from the get_random_int function, in the class random.
301 * We test both subclasses of random.
302 * If these tests fail but the seed manipulation tests all pass,
303 * and validate_mt19937 passes, then it suggests that the implementation
304 * of get_random_int may not be working properly on your platform.
305 */
306BOOST_AUTO_TEST_CASE( validate_get_random_int )
307{
308 config cfg;
309 cfg["random_seed"] = validate_get_random_int_seed_generator();
311
313
314 auto gen_ = std::make_shared<randomness::rng_deterministic>(mt_);
315
316 int val = gen_->get_random_int(0, validation_get_random_int_max);
317 BOOST_CHECK_EQUAL ( val , validation_get_random_int_correct_answer );
318}
319
320BOOST_AUTO_TEST_CASE( validate_get_random_int2 )
321{
322 auto gen_ = std::make_shared<randomness::synced_rng>(validate_get_random_int_seed_generator);
323
324 for (int i = 0; i < validation_get_random_int_num_draws; i++) {
325 gen_->next_random();
326 }
327
328 int val = gen_->get_random_int(0,validation_get_random_int_max);
329 BOOST_CHECK_EQUAL ( val , validation_get_random_int_correct_answer );
330}
331
332
333BOOST_AUTO_TEST_SUITE_END()
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
std::string get_random_seed_str() const
Definition mt_rng.cpp:99
uint32_t get_random_seed() const
Definition mt_rng.hpp:54
uint32_t get_next_random()
Get a new random number.
Definition mt_rng.cpp:62
void seed_random(const std::string &seed, const unsigned int call_count=0)
Same as uint32_t version, but uses a stringstream to convert given hex string.
Definition mt_rng.cpp:88
unsigned int get_random_calls() const
Definition mt_rng.hpp:56
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
BOOST_AUTO_TEST_SUITE(filesystem)
BOOST_AUTO_TEST_CASE(validate_mt19937)
Definition test_rng.cpp:30
#define validation_get_random_int_max
Definition test_rng.cpp:294
#define validation_get_random_int_num_draws
Definition test_rng.cpp:292
#define validation_get_random_int_correct_answer
Definition test_rng.cpp:296
#define i