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
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.
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"
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
)
59 std::cerr
<< "Test failed at " << file
<< ":" << line
;
60 std::cerr
<< " with T a ";
62 std::cerr
<< "signed";
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
83 VERIFY(integer_traits
<T
>::twice_bigger_type_is_supported
);
84 VERIFY(sizeof(typename integer_traits
<T
>::twice_bigger_type
)
86 VERIFY(bool(integer_traits
<
87 typename integer_traits
<T
>::twice_bigger_type
88 >::is_signed
) == bool(integer_traits
<T
>::is_signed
));
93 struct test_twice_bigger_type
<T
, 8>
97 VERIFY_IS_FALSE(integer_traits
<T
>::twice_bigger_type_is_supported
);
105 static bool already_run
= false;
108 std::cerr
<< "You already tested this type. Copy/paste typo??" << std::endl
;
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!
132 for(unsigned int i
= 0; i
< sizeof(T
) * CHAR_BIT
- 1; i
++)
134 VERIFY((min_value
.value() & bit
) == 0);
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
);
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
;
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
);
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
);
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
));
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
);
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
;
383 VERIFY(two
- 1 == one
);
384 VERIFY(2 - one
== one
);
386 CheckedInt
<T
> x
= two
;
390 VERIFY(one
* 2 == two
);
391 VERIFY(2 * one
== two
);
393 CheckedInt
<T
> x
= one
;
397 VERIFY(four
/ 2 == two
);
398 VERIFY(4 / two
== two
);
400 CheckedInt
<T
> x
= four
;
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))); \
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 */
460 VERIFY_IS_VALID(x
++);
462 VERIFY_IS_INVALID(++x
);
464 VERIFY_IS_VALID(x
--);
466 VERIFY_IS_INVALID(--x
);
469 } // end namespace CheckedInt_test
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;