The Battle for Wesnoth  1.15.2+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 
24 BOOST_AUTO_TEST_SUITE( rng )
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  rng();
34  }
35  unsigned long val = rng();
36  BOOST_CHECK_EQUAL( val , 4123659995U );
37 }
38 
39 /* this test checks the soundness of mt_rng string manipulations */
40 BOOST_AUTO_TEST_CASE( test_mt_rng_seed_manip )
41 {
42  uint32_t seed = 42;
43  std::stringstream stream;
44  stream << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed;
45 
46  std::string seed_str = stream.str();
47 
49  rng.seed_random(seed_str);
50 
51  BOOST_CHECK (rng.get_random_seed() == seed);
52  BOOST_CHECK (rng.get_random_seed_str() == seed_str);
53 
54  std::string seed_str2 = rng.get_random_seed_str();
55  rng.seed_random(seed_str2);
56 
57  BOOST_CHECK (rng.get_random_seed() == seed);
58  BOOST_CHECK (rng.get_random_seed_str() == seed_str);
59 
60 
61  uint32_t seed3 = 1123581321; //try the same with a different number
62  std::stringstream stream2;
63  stream2 << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed3;
64  std::string seed_str3 = stream2.str();
65 
66  rng.seed_random(seed_str3);
67  BOOST_CHECK (rng.get_random_seed() == seed3);
68  BOOST_CHECK (rng.get_random_seed_str() == seed_str3);
69 
70  std::string seed_str4 = rng.get_random_seed_str();
71  rng.seed_random(seed_str4);
72 
73  BOOST_CHECK (rng.get_random_seed() == seed3);
74  BOOST_CHECK (rng.get_random_seed_str() == seed_str3);
75 
76 
77  //now check that the results that shouldn't match don't
78  BOOST_CHECK (seed != seed3);
79  BOOST_CHECK (seed_str != seed_str3);
80 
81 }
82 
83 BOOST_AUTO_TEST_CASE( test_mt_rng_config_seed_manip )
84 {
85  uint32_t seed = 42;
86  std::stringstream stream;
87  stream << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed;
88  std::string seed_str = stream.str();
89 
90  config cfg;
91  cfg["random_seed"] = seed_str;
92  cfg["random_calls"] = 0;
93 
94  randomness::mt_rng rng(cfg);
95 
96  BOOST_CHECK (rng.get_random_seed() == seed);
97  BOOST_CHECK (rng.get_random_seed_str() == seed_str);
98 
99  std::string seed_str2 = rng.get_random_seed_str();
100  rng.seed_random(seed_str2);
101 
102  BOOST_CHECK (rng.get_random_seed() == seed);
103  BOOST_CHECK (rng.get_random_seed_str() == seed_str);
104 
105 
106  uint32_t seed3 = 1123581321; //try the same with a different number
107  std::stringstream stream2;
108  stream2 << std::setfill('0') << std::setw(sizeof(uint32_t)*2) << std::hex << seed3;
109  std::string seed_str3 = stream2.str();
110 
111  config cfg2;
112  cfg2["random_seed"] = seed_str3;
113  cfg2["random_calls"] = 0;
114 
115  randomness::mt_rng rng2(cfg2);
116 
117  BOOST_CHECK (rng2.get_random_seed() == seed3);
118  BOOST_CHECK (rng2.get_random_seed_str() == seed_str3);
119 
120  std::string seed_str4 = rng2.get_random_seed_str();
121  rng2.seed_random(seed_str4);
122 
123  BOOST_CHECK (rng2.get_random_seed() == seed3);
124  BOOST_CHECK (rng2.get_random_seed_str() == seed_str3);
125 
126 
127  //now check that the results that shouldn't match don't
128  BOOST_CHECK (seed != seed3);
129  BOOST_CHECK (seed_str != seed_str3);
130 }
131 
132 BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility )
133 {
134  config cfg;
135  cfg["random_seed"] = "5eedf00d";
136  cfg["random_calls"] = 0;
137 
138  randomness::mt_rng rng1(cfg);
139  randomness::mt_rng rng2(cfg);
140 
141  BOOST_CHECK(rng1 == rng2);
142  for (int i = 0; i < 10 ; i++) {
143  BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
144  }
145 }
146 
147 BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility2 )
148 {
149  config cfg;
150  cfg["random_seed"] = "18da5eed";
151  cfg["random_calls"] = 9999;
152 
153  randomness::mt_rng rng1(cfg);
154  randomness::mt_rng rng2(cfg);
155 
156  BOOST_CHECK(rng1 == rng2);
157  for (int i = 0; i < 10 ; i++) {
158  BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
159  }
160 }
161 
162 BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility3 )
163 {
164  randomness::mt_rng rng1;
165  config cfg;
166  cfg["random_seed"] = rng1.get_random_seed_str();
167  cfg["random_calls"] = rng1.get_random_calls();
168 
169  randomness::mt_rng rng2(cfg);
170 
171  BOOST_CHECK(rng1 == rng2);
172  for (int i = 0; i < 10 ; i++) {
173  BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
174  }
175 }
176 
177 BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility4 )
178 {
179  randomness::mt_rng rng1;
180 
181  for (int i = 0; i < 5; i++) {
182  rng1.get_next_random();
183  }
184 
185  config cfg;
186  cfg["random_seed"] = rng1.get_random_seed_str();
187  cfg["random_calls"] = rng1.get_random_calls();
188 
189  randomness::mt_rng rng2(cfg);
190 
191  BOOST_CHECK(rng1 == rng2);
192  BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
193 }
194 
195 BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility5 )
196 {
197  config cfg;
198  cfg["random_seed"] = "5eedc0de";
199  cfg["random_calls"] = 0;
200 
201  randomness::mt_rng rng(cfg);
202 
203  for (int i = 0; i < 9999 ; i++) {
204  rng.get_next_random();
205  }
206 
207  config cfg2;
208  cfg2["random_seed"] = rng.get_random_seed_str();
209  cfg2["random_calls"] = rng.get_random_calls();
210 
211  randomness::mt_rng rng2(cfg2);
212 
213  uint32_t result1 = rng.get_next_random();
214  uint32_t result2 = rng2.get_next_random();
215 
216  BOOST_CHECK (rng == rng2);
217  BOOST_CHECK (rng.get_random_seed_str() == rng2.get_random_seed_str());
218  BOOST_CHECK (rng.get_random_calls() == rng2.get_random_calls());
219  BOOST_CHECK (result1 == result2);
220 
221  config cfg_save;
222  cfg_save["random_seed"] = rng.get_random_seed_str();
223  cfg_save["random_calls"] = rng.get_random_calls();
224 
225  uint32_t result3 = rng.get_next_random();
226 
227  randomness::mt_rng rng3(cfg_save);
228  uint32_t result4 = rng3.get_next_random();
229 
230  BOOST_CHECK (rng == rng3);
231  BOOST_CHECK (rng.get_random_seed_str() == rng3.get_random_seed_str());
232  BOOST_CHECK (rng.get_random_calls() == rng3.get_random_calls());
233  BOOST_CHECK (result3 == result4);
234 }
235 
236 namespace {
237 
238 void validate_seed_string(std::string seed_str)
239 {
240  config cfg;
241  cfg["random_seed"] = seed_str;
242  cfg["random_calls"] = 0;
243 
244  randomness::mt_rng rng1(cfg);
245 
246  for (int i = 0; i < 9999 ; i++) {
247  rng1.get_next_random();
248  }
249 
250  config cfg2;
251  cfg2["random_seed"] = rng1.get_random_seed_str();
252  cfg2["random_calls"] = rng1.get_random_calls();
253 
254  randomness::mt_rng rng2(cfg2);
255 
256  for (int i = 0; i < 9999 ; i++) {
257  rng1.get_next_random();
258  rng2.get_next_random();
259  }
260 
261  BOOST_CHECK(rng1 == rng2);
262  BOOST_CHECK(rng1.get_next_random() == rng2.get_next_random());
263 
264 }
265 
266 }
267 
268 BOOST_AUTO_TEST_CASE( test_mt_rng_reproducibility_coverage )
269 {
270  validate_seed_string("0000badd");
271  validate_seed_string("00001234");
272  validate_seed_string("deadbeef");
273  validate_seed_string("12345678");
274  validate_seed_string("00009999");
275  validate_seed_string("ffffaaaa");
276  validate_seed_string("11110000");
277  validate_seed_string("10101010");
278  validate_seed_string("aaaa0000");
279 }
280 
281 namespace {
282 
283 std::string validate_get_random_int_seed_generator()
284 {
285  return "dada5eed";
286 }
287 
288 }
289 
290 #define validation_get_random_int_num_draws 19999
291 
292 #define validation_get_random_int_max 32000
293 
294 #define validation_get_random_int_correct_answer 10885
295 
296 /**
297  * This test and the next validate that we are getting the correct values
298  * from the get_random_int function, in the class random.
299  * We test both subclasses of random.
300  * If these tests fail but the seed manipulation tests all pass,
301  * and validate_mt19937 passes, then it suggests that the implementation
302  * of get_random_int may not be working properly on your platform.
303  */
304 BOOST_AUTO_TEST_CASE( validate_get_random_int )
305 {
306  config cfg;
307  cfg["random_seed"] = validate_get_random_int_seed_generator();
308  cfg["random_calls"] = validation_get_random_int_num_draws;
309 
310  randomness::mt_rng mt_(cfg);
311 
312  auto gen_ = std::make_shared<randomness::rng_deterministic>(mt_);
313 
314  int val = gen_->get_random_int(0, validation_get_random_int_max);
315  BOOST_CHECK_EQUAL ( val , validation_get_random_int_correct_answer );
316 }
317 
318 BOOST_AUTO_TEST_CASE( validate_get_random_int2 )
319 {
320  auto gen_ = std::make_shared<randomness::synced_rng>(validate_get_random_int_seed_generator);
321 
322  for (int i = 0; i < validation_get_random_int_num_draws; i++) {
323  gen_->next_random();
324  }
325 
326  int val = gen_->get_random_int(0,validation_get_random_int_max);
327  BOOST_CHECK_EQUAL ( val , validation_get_random_int_correct_answer );
328 }
329 
330 
331 BOOST_AUTO_TEST_SUITE_END()
#define validation_get_random_int_num_draws
Definition: test_rng.cpp:290
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
uint32_t get_random_seed() const
Definition: mt_rng.hpp:53
#define validation_get_random_int_correct_answer
Definition: test_rng.cpp:294
unsigned int get_random_calls() const
Definition: mt_rng.hpp:55
std::size_t i
Definition: function.cpp:933
#define validation_get_random_int_max
Definition: test_rng.cpp:292
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:68