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