CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / xpcom / tests / TestCheckedInt.cpp
blob949a6b22139b9cff8a36d71f3f99cac4901d14d7
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla code.
18 * The Initial Developer of the Original Code is the Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2009
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Benoit Jacob <bjacob@mozilla.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 #include "CheckedInt.h"
41 #include <iostream>
43 namespace CheckedInt_test {
45 using namespace mozilla::CheckedInt_internal;
46 using mozilla::CheckedInt;
48 int g_tests_passed = 0;
49 int g_tests_failed = 0;
51 void verify_impl_function(bool x, bool expected,
52 const char* file, int line,
53 int T_size, bool T_is_signed)
55 if (x == expected) {
56 g_tests_passed++;
57 } else {
58 g_tests_failed++;
59 std::cerr << "Test failed at " << file << ":" << line;
60 std::cerr << " with T a ";
61 if(T_is_signed)
62 std::cerr << "signed";
63 else
64 std::cerr << "unsigned";
65 std::cerr << " " << CHAR_BIT*T_size << "-bit integer type" << std::endl;
69 #define VERIFY_IMPL(x, expected) \
70 verify_impl_function((x), (expected), __FILE__, __LINE__, sizeof(T), integer_traits<T>::is_signed)
72 #define VERIFY(x) VERIFY_IMPL(x, true)
73 #define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
74 #define VERIFY_IS_VALID(x) VERIFY_IMPL((x).valid(), PR_TRUE)
75 #define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).valid(), PR_FALSE)
76 #define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).valid(), (condition))
78 template<typename T, unsigned int size = sizeof(T)>
79 struct test_twice_bigger_type
81 static void run()
83 VERIFY(integer_traits<T>::twice_bigger_type_is_supported);
84 VERIFY(sizeof(typename integer_traits<T>::twice_bigger_type)
85 == 2 * sizeof(T));
86 VERIFY(bool(integer_traits<
87 typename integer_traits<T>::twice_bigger_type
88 >::is_signed) == bool(integer_traits<T>::is_signed));
92 template<typename T>
93 struct test_twice_bigger_type<T, 8>
95 static void run()
97 VERIFY_IS_FALSE(integer_traits<T>::twice_bigger_type_is_supported);
102 template<typename T>
103 void test()
105 static bool already_run = false;
106 if (already_run) {
107 g_tests_failed++;
108 std::cerr << "You already tested this type. Copy/paste typo??" << std::endl;
109 return;
111 already_run = true;
113 VERIFY(integer_traits<T>::is_supported);
114 VERIFY(integer_traits<T>::size == sizeof(T));
115 enum{ is_signed = integer_traits<T>::is_signed };
116 VERIFY(bool(is_signed) == !bool(T(-1) > T(0)));
118 test_twice_bigger_type<T>::run();
120 typedef typename integer_traits<T>::unsigned_type unsigned_T;
122 VERIFY(sizeof(unsigned_T) == sizeof(T));
123 VERIFY(integer_traits<unsigned_T>::is_signed == false);
125 CheckedInt<T> max_value(integer_traits<T>::max_value());
126 CheckedInt<T> min_value(integer_traits<T>::min_value());
128 // check min_value() and max_value(), since they are custom implementations and a mistake there
129 // could potentially NOT be caught by any other tests... while making everything wrong!
131 T bit = 1;
132 for(unsigned int i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
134 VERIFY((min_value.value() & bit) == 0);
135 bit <<= 1;
137 VERIFY((min_value.value() & bit) == (is_signed ? bit : T(0)));
138 VERIFY(max_value.value() == T(~(min_value.value())));
140 CheckedInt<T> zero(0);
141 CheckedInt<T> one(1);
142 CheckedInt<T> two(2);
143 CheckedInt<T> three(3);
144 CheckedInt<T> four(4);
146 /* addition / substraction checks */
148 VERIFY_IS_VALID(zero+zero);
149 VERIFY(zero+zero == zero);
150 VERIFY_IS_FALSE(zero+zero == one); // check that == doesn't always return true
151 VERIFY_IS_VALID(zero+one);
152 VERIFY(zero+one == one);
153 VERIFY_IS_VALID(one+one);
154 VERIFY(one+one == two);
156 CheckedInt<T> max_value_minus_one = max_value - one;
157 CheckedInt<T> max_value_minus_two = max_value - two;
158 VERIFY_IS_VALID(max_value_minus_one);
159 VERIFY_IS_VALID(max_value_minus_two);
160 VERIFY_IS_VALID(max_value_minus_one + one);
161 VERIFY_IS_VALID(max_value_minus_two + one);
162 VERIFY_IS_VALID(max_value_minus_two + two);
163 VERIFY(max_value_minus_one + one == max_value);
164 VERIFY(max_value_minus_two + one == max_value_minus_one);
165 VERIFY(max_value_minus_two + two == max_value);
167 VERIFY_IS_VALID(max_value + zero);
168 VERIFY_IS_VALID(max_value - zero);
169 VERIFY_IS_INVALID(max_value + one);
170 VERIFY_IS_INVALID(max_value + two);
171 VERIFY_IS_INVALID(max_value + max_value_minus_one);
172 VERIFY_IS_INVALID(max_value + max_value);
174 CheckedInt<T> min_value_plus_one = min_value + one;
175 CheckedInt<T> min_value_plus_two = min_value + two;
176 VERIFY_IS_VALID(min_value_plus_one);
177 VERIFY_IS_VALID(min_value_plus_two);
178 VERIFY_IS_VALID(min_value_plus_one - one);
179 VERIFY_IS_VALID(min_value_plus_two - one);
180 VERIFY_IS_VALID(min_value_plus_two - two);
181 VERIFY(min_value_plus_one - one == min_value);
182 VERIFY(min_value_plus_two - one == min_value_plus_one);
183 VERIFY(min_value_plus_two - two == min_value);
185 CheckedInt<T> min_value_minus_one = min_value - one;
186 VERIFY_IS_VALID(min_value + zero);
187 VERIFY_IS_VALID(min_value - zero);
188 VERIFY_IS_INVALID(min_value - one);
189 VERIFY_IS_INVALID(min_value - two);
190 VERIFY_IS_INVALID(min_value - min_value_minus_one);
191 VERIFY_IS_VALID(min_value - min_value);
193 CheckedInt<T> max_value_over_two = max_value / two;
194 VERIFY_IS_VALID(max_value_over_two + max_value_over_two);
195 VERIFY_IS_VALID(max_value_over_two + one);
196 VERIFY((max_value_over_two + one) - one == max_value_over_two);
197 VERIFY_IS_VALID(max_value_over_two - max_value_over_two);
198 VERIFY(max_value_over_two - max_value_over_two == zero);
200 CheckedInt<T> min_value_over_two = min_value / two;
201 VERIFY_IS_VALID(min_value_over_two + min_value_over_two);
202 VERIFY_IS_VALID(min_value_over_two + one);
203 VERIFY((min_value_over_two + one) - one == min_value_over_two);
204 VERIFY_IS_VALID(min_value_over_two - min_value_over_two);
205 VERIFY(min_value_over_two - min_value_over_two == zero);
207 VERIFY_IS_INVALID(min_value - one);
208 VERIFY_IS_INVALID(min_value - two);
210 if (is_signed) {
211 VERIFY_IS_INVALID(min_value + min_value);
212 VERIFY_IS_INVALID(min_value_over_two + min_value_over_two + min_value_over_two);
213 VERIFY_IS_INVALID(zero - min_value + min_value);
214 VERIFY_IS_INVALID(one - min_value + min_value);
217 /* unary operator- checks */
219 CheckedInt<T> neg_one = -one;
220 CheckedInt<T> neg_two = -two;
222 if (is_signed) {
223 VERIFY_IS_VALID(-max_value);
224 VERIFY_IS_VALID(-max_value - one);
225 VERIFY_IS_VALID(neg_one);
226 VERIFY_IS_VALID(-max_value + neg_one);
227 VERIFY_IS_VALID(neg_one + one);
228 VERIFY(neg_one + one == zero);
229 VERIFY_IS_VALID(neg_two);
230 VERIFY_IS_VALID(neg_one + neg_one);
231 VERIFY(neg_one + neg_one == neg_two);
232 } else {
233 VERIFY_IS_INVALID(neg_one);
236 /* multiplication checks */
238 VERIFY_IS_VALID(zero*zero);
239 VERIFY(zero*zero == zero);
240 VERIFY_IS_VALID(zero*one);
241 VERIFY(zero*one == zero);
242 VERIFY_IS_VALID(one*zero);
243 VERIFY(one*zero == zero);
244 VERIFY_IS_VALID(one*one);
245 VERIFY(one*one == one);
246 VERIFY_IS_VALID(one*three);
247 VERIFY(one*three == three);
248 VERIFY_IS_VALID(two*two);
249 VERIFY(two*two == four);
251 VERIFY_IS_INVALID(max_value * max_value);
252 VERIFY_IS_INVALID(max_value_over_two * max_value);
253 VERIFY_IS_INVALID(max_value_over_two * max_value_over_two);
255 CheckedInt<T> max_value_approx_sqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
257 VERIFY_IS_VALID(max_value_approx_sqrt);
258 VERIFY_IS_VALID(max_value_approx_sqrt * two);
259 VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt);
260 VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt * max_value_approx_sqrt);
262 if (is_signed) {
263 VERIFY_IS_INVALID(min_value * min_value);
264 VERIFY_IS_INVALID(min_value_over_two * min_value);
265 VERIFY_IS_INVALID(min_value_over_two * min_value_over_two);
267 CheckedInt<T> min_value_approx_sqrt = -max_value_approx_sqrt;
269 VERIFY_IS_VALID(min_value_approx_sqrt);
270 VERIFY_IS_VALID(min_value_approx_sqrt * two);
271 VERIFY_IS_INVALID(min_value_approx_sqrt * max_value_approx_sqrt);
272 VERIFY_IS_INVALID(min_value_approx_sqrt * min_value_approx_sqrt);
275 // make sure to check all 4 paths in signed multiplication validity check.
276 // test positive * positive
277 VERIFY_IS_VALID(max_value * one);
278 VERIFY(max_value * one == max_value);
279 VERIFY_IS_INVALID(max_value * two);
280 VERIFY_IS_VALID(max_value_over_two * two);
281 VERIFY((max_value_over_two + max_value_over_two) == (max_value_over_two * two));
283 if (is_signed) {
284 // test positive * negative
285 VERIFY_IS_VALID(max_value * neg_one);
286 VERIFY_IS_VALID(-max_value);
287 VERIFY(max_value * neg_one == -max_value);
288 VERIFY_IS_VALID(one * min_value);
289 VERIFY_IS_INVALID(max_value * neg_two);
290 VERIFY_IS_VALID(max_value_over_two * neg_two);
291 VERIFY_IS_VALID(two * min_value_over_two);
292 VERIFY_IS_VALID((max_value_over_two + one) * neg_two);
293 VERIFY_IS_INVALID((max_value_over_two + two) * neg_two);
294 VERIFY_IS_INVALID(two * (min_value_over_two - one));
296 // test negative * positive
297 VERIFY_IS_VALID(min_value * one);
298 VERIFY_IS_VALID(min_value_plus_one * one);
299 VERIFY_IS_INVALID(min_value * two);
300 VERIFY_IS_VALID(min_value_over_two * two);
301 VERIFY(min_value_over_two * two == min_value);
302 VERIFY_IS_INVALID((min_value_over_two - one) * neg_two);
303 VERIFY_IS_INVALID(neg_two * max_value);
304 VERIFY_IS_VALID(min_value_over_two * two);
305 VERIFY(min_value_over_two * two == min_value);
306 VERIFY_IS_VALID(neg_two * max_value_over_two);
307 VERIFY_IS_INVALID((min_value_over_two - one) * two);
308 VERIFY_IS_VALID(neg_two * (max_value_over_two + one));
309 VERIFY_IS_INVALID(neg_two * (max_value_over_two + two));
311 // test negative * negative
312 VERIFY_IS_INVALID(min_value * neg_one);
313 VERIFY_IS_VALID(min_value_plus_one * neg_one);
314 VERIFY(min_value_plus_one * neg_one == max_value);
315 VERIFY_IS_INVALID(min_value * neg_two);
316 VERIFY_IS_INVALID(min_value_over_two * neg_two);
317 VERIFY_IS_INVALID(neg_one * min_value);
318 VERIFY_IS_VALID(neg_one * min_value_plus_one);
319 VERIFY(neg_one * min_value_plus_one == max_value);
320 VERIFY_IS_INVALID(neg_two * min_value);
321 VERIFY_IS_INVALID(neg_two * min_value_over_two);
324 /* division checks */
326 VERIFY_IS_VALID(one / one);
327 VERIFY(one / one == one);
328 VERIFY_IS_VALID(three / three);
329 VERIFY(three / three == one);
330 VERIFY_IS_VALID(four / two);
331 VERIFY(four / two == two);
332 VERIFY((four*three)/four == three);
334 // check that div by zero is invalid
335 VERIFY_IS_INVALID(zero / zero);
336 VERIFY_IS_INVALID(one / zero);
337 VERIFY_IS_INVALID(two / zero);
338 VERIFY_IS_INVALID(neg_one / zero);
339 VERIFY_IS_INVALID(max_value / zero);
340 VERIFY_IS_INVALID(min_value / zero);
342 if (is_signed) {
343 // check that min_value / -1 is invalid
344 VERIFY_IS_INVALID(min_value / neg_one);
346 // check that the test for div by -1 isn't banning other numerators than min_value
347 VERIFY_IS_VALID(one / neg_one);
348 VERIFY_IS_VALID(zero / neg_one);
349 VERIFY_IS_VALID(neg_one / neg_one);
350 VERIFY_IS_VALID(max_value / neg_one);
353 /* check that invalidity is correctly preserved by arithmetic ops */
355 CheckedInt<T> some_invalid = max_value + max_value;
356 VERIFY_IS_INVALID(some_invalid + zero);
357 VERIFY_IS_INVALID(some_invalid - zero);
358 VERIFY_IS_INVALID(zero + some_invalid);
359 VERIFY_IS_INVALID(zero - some_invalid);
360 VERIFY_IS_INVALID(-some_invalid);
361 VERIFY_IS_INVALID(some_invalid * zero);
362 VERIFY_IS_INVALID(some_invalid * one);
363 VERIFY_IS_INVALID(zero * some_invalid);
364 VERIFY_IS_INVALID(one * some_invalid);
365 VERIFY_IS_INVALID(some_invalid / zero);
366 VERIFY_IS_INVALID(some_invalid / one);
367 VERIFY_IS_INVALID(zero / some_invalid);
368 VERIFY_IS_INVALID(one / some_invalid);
369 VERIFY_IS_INVALID(some_invalid + some_invalid);
370 VERIFY_IS_INVALID(some_invalid - some_invalid);
371 VERIFY_IS_INVALID(some_invalid * some_invalid);
372 VERIFY_IS_INVALID(some_invalid / some_invalid);
374 /* check that mixing checked integers with plain integers in expressions is allowed */
376 VERIFY(one + T(2) == three);
377 VERIFY(2 + one == three);
379 CheckedInt<T> x = one;
380 x += 2;
381 VERIFY(x == three);
383 VERIFY(two - 1 == one);
384 VERIFY(2 - one == one);
386 CheckedInt<T> x = two;
387 x -= 1;
388 VERIFY(x == one);
390 VERIFY(one * 2 == two);
391 VERIFY(2 * one == two);
393 CheckedInt<T> x = one;
394 x *= 2;
395 VERIFY(x == two);
397 VERIFY(four / 2 == two);
398 VERIFY(4 / two == two);
400 CheckedInt<T> x = four;
401 x /= 2;
402 VERIFY(x == two);
405 VERIFY(one == 1);
406 VERIFY(1 == one);
407 VERIFY_IS_FALSE(two == 1);
408 VERIFY_IS_FALSE(1 == two);
409 VERIFY_IS_FALSE(some_invalid == 1);
410 VERIFY_IS_FALSE(1 == some_invalid);
412 /* Check that construction of CheckedInt from an integer value of a mismatched type is checked */
414 #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
416 bool is_U_signed = integer_traits<U>::is_signed; \
417 VERIFY_IS_VALID(CheckedInt<T>(U(0))); \
418 VERIFY_IS_VALID(CheckedInt<T>(U(1))); \
419 VERIFY_IS_VALID(CheckedInt<T>(U(100))); \
420 if (is_U_signed) \
421 VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), is_signed); \
422 if (sizeof(U) > sizeof(T)) \
423 VERIFY_IS_INVALID(CheckedInt<T>(U(integer_traits<T>::max_value())+1)); \
424 VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::max_value()), \
425 (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (is_U_signed || !is_signed)))); \
426 VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::min_value()), \
427 is_U_signed == false ? 1 : \
428 bool(is_signed) == false ? 0 : \
429 sizeof(T) >= sizeof(U)); \
431 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt8)
432 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint8)
433 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt16)
434 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint16)
435 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt32)
436 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint32)
437 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt64)
438 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint64)
440 /* Test increment/decrement operators */
442 CheckedInt<T> x, y;
443 x = one;
444 y = x++;
445 VERIFY(x == two);
446 VERIFY(y == one);
447 x = one;
448 y = ++x;
449 VERIFY(x == two);
450 VERIFY(y == two);
451 x = one;
452 y = x--;
453 VERIFY(x == zero);
454 VERIFY(y == one);
455 x = one;
456 y = --x;
457 VERIFY(x == zero);
458 VERIFY(y == zero);
459 x = max_value;
460 VERIFY_IS_VALID(x++);
461 x = max_value;
462 VERIFY_IS_INVALID(++x);
463 x = min_value;
464 VERIFY_IS_VALID(x--);
465 x = min_value;
466 VERIFY_IS_INVALID(--x);
469 } // end namespace CheckedInt_test
471 int main()
473 CheckedInt_test::test<PRInt8>();
474 CheckedInt_test::test<PRUint8>();
475 CheckedInt_test::test<PRInt16>();
476 CheckedInt_test::test<PRUint16>();
477 CheckedInt_test::test<PRInt32>();
478 CheckedInt_test::test<PRUint32>();
479 CheckedInt_test::test<PRInt64>();
480 CheckedInt_test::test<PRUint64>();
482 std::cerr << CheckedInt_test::g_tests_failed << " tests failed, "
483 << CheckedInt_test::g_tests_passed << " tests passed out of "
484 << CheckedInt_test::g_tests_failed + CheckedInt_test::g_tests_passed
485 << " tests." << std::endl;
487 return CheckedInt_test::g_tests_failed > 0;