]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/common/test_random.cc
667b69c789ee4c7b9442e6255b488c8cf51a7e4e
[ceph.git] / ceph / src / test / common / test_random.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2017 SUSE LINUX GmbH
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <sstream>
16
17 #include "include/random.h"
18
19 #include "gtest/gtest.h"
20
21 // Helper to see if calls compile with various types:
22 template <typename T>
23 T type_check_ok(const T min, const T max)
24 {
25 return ceph::util::generate_random_number(min, max);
26 }
27
28 /* Help wrangle "unused variable" warnings: */
29 template <typename X>
30 void swallow_values(const X x)
31 {
32 static_cast<void>(x);
33 }
34
35 template <typename X, typename ...XS>
36 void swallow_values(const X x, const XS... xs)
37 {
38 swallow_values(x), swallow_values(xs...);
39 }
40
41 // Mini-examples showing canonical usage:
42 TEST(util, test_random_canonical)
43 {
44 // Seed random number generation:
45 ceph::util::randomize_rng();
46
47 // Get a random int between 0 and max int:
48 auto a = ceph::util::generate_random_number();
49
50 // Get a random int between 0 and 20:
51 auto b = ceph::util::generate_random_number(20);
52
53 // Get a random int between 1 and 20:
54 auto c = ceph::util::generate_random_number(1, 20);
55
56 // Get a random float between 0.0 and 20.0:
57 auto d = ceph::util::generate_random_number(20.0);
58
59 // Get a random float between 0.001 and 0.991:
60 auto e = ceph::util::generate_random_number(0.001, 0.991);
61
62 // Make a function object RNG suitable for putting on its own thread:
63 auto gen_fn = ceph::util::random_number_generator<int>();
64 auto z = gen_fn();
65 gen_fn.seed(42); // re-seed
66
67 // Placate the compiler:
68 swallow_values(a, b, c, d, e, z);
69 }
70
71 TEST(util, test_random)
72 {
73 /* The intent of this test is not to formally test random number generation,
74 but rather to casually check that "it works" and catch regressions: */
75
76 // The default overload should compile:
77 ceph::util::randomize_rng();
78
79 {
80 int a = ceph::util::generate_random_number();
81 int b = ceph::util::generate_random_number();
82
83 /* Technically, this can still collide and cause a false negative, but let's
84 be optimistic: */
85 if (std::numeric_limits<int>::max() > 32767) {
86 ASSERT_NE(a, b);
87 }
88 }
89
90 // Check that the nullary version accepts different numeric types:
91 {
92 long def = ceph::util::generate_random_number();
93 long l = ceph::util::generate_random_number<long>();
94 int64_t i = ceph::util::generate_random_number<int64_t>();
95 double d = ceph::util::generate_random_number<double>();
96
97 swallow_values(def, l, i, d);
98 }
99
100 // (optimistically) Check that the nullary and unary versions never return < 0:
101 {
102 for(long i = 0; 1000000 != i; i++) {
103 ASSERT_LE(0, ceph::util::generate_random_number());
104 ASSERT_LE(0, ceph::util::generate_random_number(1));
105 ASSERT_LE(0, ceph::util::generate_random_number<float>(1.0));
106 }
107 }
108
109 {
110 auto a = ceph::util::generate_random_number(1, std::numeric_limits<int>::max());
111 auto b = ceph::util::generate_random_number(1, std::numeric_limits<int>::max());
112
113 if (std::numeric_limits<int>::max() > 32767) {
114 ASSERT_GT(a, 0);
115 ASSERT_GT(b, 0);
116
117 ASSERT_NE(a, b);
118 }
119 }
120
121 for (auto n = 100000; n; --n) {
122 int a = ceph::util::generate_random_number(0, 6);
123 ASSERT_GT(a, -1);
124 ASSERT_LT(a, 7);
125 }
126
127 // Check bounding on zero (checking appropriate value for zero compiles and works):
128 for (auto n = 10; n; --n) {
129 ASSERT_EQ(0, ceph::util::generate_random_number<int>(0, 0));
130 ASSERT_EQ(0, ceph::util::generate_random_number<float>(0.0, 0.0));
131 }
132
133 // Multiple types (integral):
134 {
135 int min = 0, max = 1;
136 type_check_ok(min, max);
137 }
138
139 {
140 long min = 0, max = 1l;
141 type_check_ok(min, max);
142 }
143
144 // Multiple types (floating point):
145 {
146 double min = 0.0, max = 1.0;
147 type_check_ok(min, max);
148 }
149
150 {
151 float min = 0.0, max = 1.0;
152 type_check_ok(min, max);
153 }
154
155 // When combining types, everything should convert to the largest type:
156 {
157 // Check with integral types:
158 {
159 int x = 0;
160 long long y = 1;
161
162 auto z = ceph::util::generate_random_number(x, y);
163
164 bool result = std::is_same_v<decltype(z), decltype(y)>;
165
166 ASSERT_TRUE(result);
167 }
168
169 // Check with floating-point types:
170 {
171 float x = 0.0;
172 long double y = 1.0;
173
174 auto z = ceph::util::generate_random_number(x, y);
175
176 bool result = std::is_same_v<decltype(z), decltype(y)>;
177
178 ASSERT_TRUE(result);
179 }
180
181 // It would be nice to have a test to check that mixing integral and floating point
182 // numbers should not compile, however we currently have no good way I know of
183 // to do such negative tests.
184 }
185 }
186
187 TEST(util, test_random_class_interface)
188 {
189 ceph::util::random_number_generator<int> rng_i;
190 ceph::util::random_number_generator<float> rng_f;
191
192 // Other ctors:
193 {
194 ceph::util::random_number_generator<int> rng(1234); // seed
195 }
196
197 // Test deduction guides:
198 {
199 { ceph::util::random_number_generator rng(1234); }
200 { ceph::util::random_number_generator rng(1234.1234); }
201
202 {
203 int x = 1234;
204 ceph::util::random_number_generator rng(x);
205 }
206 }
207
208 {
209 int a = rng_i();
210 int b = rng_i();
211
212 // Technically can fail, but should "almost never" happen:
213 ASSERT_NE(a, b);
214 }
215
216 {
217 int a = rng_i(10);
218 ASSERT_LE(a, 10);
219 ASSERT_GE(a, 0);
220 }
221
222 {
223 float a = rng_f(10.0);
224 ASSERT_LE(a, 10.0);
225 ASSERT_GE(a, 0.0);
226 }
227
228 {
229 int a = rng_i(10, 20);
230 ASSERT_LE(a, 20);
231 ASSERT_GE(a, 10);
232 }
233
234 {
235 float a = rng_f(10.0, 20.0);
236 ASSERT_LE(a, 20.0);
237 ASSERT_GE(a, 10.0);
238 }
239 }
240