]> Git Repo - binutils.git/blob - gdb/unittests/gmp-utils-selftests.c
Automatic date update in version.in
[binutils.git] / gdb / unittests / gmp-utils-selftests.c
1 /* Self tests of the gmp-utils API.
2
3    Copyright (C) 2019-2022 Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 #include "gmp-utils.h"
21 #include "gdbsupport/selftest.h"
22
23 #include <math.h>
24
25 namespace selftests {
26
27 /* Perform a series of general tests of gdb_mpz's as_integer method.
28
29    This function limits itself to values which are in range (out-of-range
30    values will be tested separately).  In doing so, it tries to be reasonably
31    exhaustive, by testing the edges, as well as a resonable set of values
32    including negative ones, zero, and positive values.  */
33
34 static void
35 gdb_mpz_as_integer ()
36 {
37   /* Test a range of values, both as LONGEST and ULONGEST.  */
38   gdb_mpz v;
39   LONGEST l_expected;
40   ULONGEST ul_expected;
41
42   /* Start with the smallest LONGEST  */
43   l_expected = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
44
45   mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
46   mpz_neg (v.val, v.val);
47
48   SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
49
50   /* Try with a small range of integers including negative, zero,
51      and positive values.  */
52   for (int i = -256; i <= 256; i++)
53     {
54       l_expected = (LONGEST) i;
55       mpz_set_si (v.val, i);
56       SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
57
58       if (i >= 0)
59         {
60           ul_expected = (ULONGEST) i;
61           mpz_set_ui (v.val, i);
62           SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
63         }
64     }
65
66   /* Try with LONGEST_MAX.  */
67   l_expected = LONGEST_MAX;
68   ul_expected = (ULONGEST) l_expected;
69
70   mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
71   mpz_sub_ui (v.val, v.val, 1);
72
73   SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
74   SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
75
76   /* Try with ULONGEST_MAX.  */
77   ul_expected = ULONGEST_MAX;
78   mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8);
79   mpz_sub_ui (v.val, v.val, 1);
80
81   SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
82 }
83
84 /* A helper function which calls the given gdb_mpz object's as_integer
85    method with the given type T, and verifies that this triggers
86    an error due to VAL's value being out of range for type T.  */
87
88 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
89 static void
90 check_as_integer_raises_out_of_range_error (const gdb_mpz &val)
91 {
92   try
93     {
94       val.as_integer<T> ();
95     }
96   catch (const gdb_exception_error &ex)
97     {
98       SELF_CHECK (ex.reason == RETURN_ERROR);
99       SELF_CHECK (ex.error == GENERIC_ERROR);
100       SELF_CHECK (strstr (ex.what (), "Cannot export value") != nullptr);
101       return;
102     }
103   /* The expected exception did not get raised.  */
104   SELF_CHECK (false);
105 }
106
107 /* Perform out-of-range tests of gdb_mpz's as_integer method.
108
109    The goal of this function is to verify that gdb_mpz::as_integer
110    handles out-of-range values correctly.  */
111
112 static void
113 gdb_mpz_as_integer_out_of_range ()
114 {
115   gdb_mpz v;
116
117   /* Try LONGEST_MIN minus 1.  */
118   mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
119   mpz_neg (v.val, v.val);
120   mpz_sub_ui (v.val, v.val, 1);
121
122   check_as_integer_raises_out_of_range_error<ULONGEST> (v);
123   check_as_integer_raises_out_of_range_error<LONGEST> (v);
124
125   /* Try negative one (-1). */
126   v = -1;
127
128   check_as_integer_raises_out_of_range_error<ULONGEST> (v);
129   SELF_CHECK (v.as_integer<LONGEST> () == (LONGEST) -1);
130
131   /* Try LONGEST_MAX plus 1.  */
132   v = LONGEST_MAX;
133   mpz_add_ui (v.val, v.val, 1);
134
135   SELF_CHECK (v.as_integer<ULONGEST> () == (ULONGEST) LONGEST_MAX + 1);
136   check_as_integer_raises_out_of_range_error<LONGEST> (v);
137
138   /* Try ULONGEST_MAX plus 1.  */
139   v = ULONGEST_MAX;
140   mpz_add_ui (v.val, v.val, 1);
141
142   check_as_integer_raises_out_of_range_error<ULONGEST> (v);
143   check_as_integer_raises_out_of_range_error<LONGEST> (v);
144 }
145
146 /* A helper function to store the given integer value into a buffer,
147    before reading it back into a gdb_mpz.  Sets ACTUAL to the value
148    read back, while at the same time setting EXPECTED as the value
149    we would expect to be read back.
150
151    Note that this function does not perform the comparison between
152    EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
153    call, allowing the line information shown when the test fails
154    to provide a bit more information about the kind of values
155    that were used when the check failed.  This makes the writing
156    of the tests a little more verbose, but the debugging in case
157    of problems should hopefuly be easier.  */
158
159 template<typename T>
160 void
161 store_and_read_back (T val, size_t buf_len, enum bfd_endian byte_order,
162                      gdb_mpz &expected, gdb_mpz &actual)
163 {
164   gdb_byte *buf;
165
166   expected = val;
167
168   buf = (gdb_byte *) alloca (buf_len);
169   store_integer (buf, buf_len, byte_order, val);
170
171   /* Pre-initialize ACTUAL to something that's not the expected value.  */
172   mpz_set (actual.val, expected.val);
173   mpz_sub_ui (actual.val, actual.val, 500);
174
175   actual.read ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
176 }
177
178 /* Test the gdb_mpz::read method over a reasonable range of values.
179
180    The testing is done by picking an arbitrary buffer length, after
181    which we test every possible value that this buffer allows, both
182    with signed numbers as well as unsigned ones.  */
183
184 static void
185 gdb_mpz_read_all_from_small ()
186 {
187   /* Start with a type whose size is small enough that we can afford
188      to check the complete range.  */
189
190   int buf_len = 1;
191   LONGEST l_min = -pow (2.0, buf_len * 8 - 1);
192   LONGEST l_max = pow (2.0, buf_len * 8 - 1) - 1;
193
194   for (LONGEST l = l_min; l <= l_max; l++)
195     {
196       gdb_mpz expected, actual;
197
198       store_and_read_back (l, buf_len, BFD_ENDIAN_BIG, expected, actual);
199       SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
200
201       store_and_read_back (l, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
202       SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
203     }
204
205   /* Do the same as above, but with an unsigned type.  */
206   ULONGEST ul_min = 0;
207   ULONGEST ul_max = pow (2.0, buf_len * 8) - 1;
208
209   for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
210     {
211       gdb_mpz expected, actual;
212
213       store_and_read_back (ul, buf_len, BFD_ENDIAN_BIG, expected, actual);
214       SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
215
216       store_and_read_back (ul, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
217       SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
218     }
219 }
220
221 /* Test the gdb_mpz::read the extremes of LONGEST and ULONGEST.  */
222
223 static void
224 gdb_mpz_read_min_max ()
225 {
226   gdb_mpz expected, actual;
227
228   /* Start with the smallest LONGEST.  */
229
230   LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
231
232   store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG,
233                        expected, actual);
234   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
235
236   store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
237                        expected, actual);
238   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
239
240   /* Same with LONGEST_MAX.  */
241
242   LONGEST l_max = LONGEST_MAX;
243
244   store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG,
245                        expected, actual);
246   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
247
248   store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
249                        expected, actual);
250   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
251
252   /* Same with the smallest ULONGEST.  */
253
254   ULONGEST ul_min = 0;
255
256   store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG,
257                        expected, actual);
258   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
259
260   store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
261                        expected, actual);
262   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
263
264   /* Same with ULONGEST_MAX.  */
265
266   ULONGEST ul_max = ULONGEST_MAX;
267
268   store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG,
269                        expected, actual);
270   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
271
272   store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
273                        expected, actual);
274   SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
275 }
276
277 /* A helper function which creates a gdb_mpz object from the given
278    integer VAL, and then writes it using its gdb_mpz::write method.
279
280    The written value is then extracted from the buffer and returned,
281    for comparison with the original.
282
283    Note that this function does not perform the comparison between
284    VAL and the returned value.  The caller will do it inside a SELF_CHECK
285    call, allowing the line information shown when the test fails
286    to provide a bit more information about the kind of values
287    that were used when the check failed.  This makes the writing
288    of the tests a little more verbose, but the debugging in case
289    of problems should hopefuly be easier.  */
290
291 template<typename T>
292 T
293 write_and_extract (T val, size_t buf_len, enum bfd_endian byte_order)
294 {
295   gdb_mpz v (val);
296
297   SELF_CHECK (v.as_integer<T> () == val);
298
299   gdb_byte *buf = (gdb_byte *) alloca (buf_len);
300   v.write ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
301
302   return extract_integer<T> ({buf, buf_len}, byte_order);
303 }
304
305 /* Test the gdb_mpz::write method over a reasonable range of values.
306
307    The testing is done by picking an arbitrary buffer length, after
308    which we test every possible value that this buffer allows.  */
309
310 static void
311 gdb_mpz_write_all_from_small ()
312 {
313   int buf_len = 1;
314   LONGEST l_min = -pow (2.0, buf_len * 8 - 1);
315   LONGEST l_max = pow (2.0, buf_len * 8 - 1) - 1;
316
317   for (LONGEST l = l_min; l <= l_max; l++)
318     {
319       SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_BIG) == l);
320       SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_LITTLE) == l);
321     }
322
323     /* Do the same as above, but with an unsigned type.  */
324   ULONGEST ul_min = 0;
325   ULONGEST ul_max = pow (2.0, buf_len * 8) - 1;
326
327   for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
328     {
329       SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_BIG) == ul);
330       SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_LITTLE) == ul);
331     }
332 }
333
334 /* Test the gdb_mpz::write the extremes of LONGEST and ULONGEST.  */
335
336 static void
337 gdb_mpz_write_min_max ()
338 {
339   /* Start with the smallest LONGEST.  */
340
341   LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
342   SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG)
343               == l_min);
344   SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
345               == l_min);
346
347   /* Same with LONGEST_MAX.  */
348
349   LONGEST l_max = LONGEST_MAX;
350   SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG)
351               == l_max);
352   SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
353               == l_max);
354
355   /* Same with the smallest ULONGEST.  */
356
357   ULONGEST ul_min = (ULONGEST) 1 << (sizeof (ULONGEST) * 8 - 1);
358   SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG)
359               == ul_min);
360   SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
361               == ul_min);
362
363   /* Same with ULONGEST_MAX.  */
364
365   ULONGEST ul_max = ULONGEST_MAX;
366   SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG)
367               == ul_max);
368   SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
369               == ul_max);
370 }
371
372 /* A helper function which stores the signed number, the unscaled value
373    of a fixed point object, into a buffer, and then uses gdb_mpq's
374    read_fixed_point to read it as a fixed_point value, with
375    the given parameters.
376
377    EXPECTED is set to the value we expected to get after the call
378    to read_fixed_point.  ACTUAL is the value we actually do get.
379
380    Note that this function does not perform the comparison between
381    EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
382    call, allowing the line information shown when the test fails
383    to provide a bit more information about the kind of values
384    that were used when the check failed.  This makes the writing
385    of the tests a little more verbose, but the debugging in case
386    of problems should hopefuly be easier.  */
387
388 static void
389 read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
390               enum bfd_endian byte_order,
391               gdb_mpq &expected, gdb_mpq &actual)
392 {
393   /* For this kind of testing, we'll use a buffer the same size as
394      our unscaled parameter.  */
395   const size_t len = sizeof (unscaled);
396   gdb_byte buf[len];
397   store_signed_integer (buf, len, byte_order, unscaled);
398
399   actual.read_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
400
401   mpq_set_si (expected.val, unscaled, 1);
402   mpq_mul (expected.val, expected.val, scaling_factor.val);
403 }
404
405 /* Perform various tests of the gdb_mpq::read_fixed_point method.  */
406
407 static void
408 gdb_mpq_read_fixed_point ()
409 {
410   gdb_mpq expected, actual;
411   gdb_mpq scaling_factor;
412
413   /* Pick an arbitrary scaling_factor; this operation is trivial enough
414      thanks to GMP that the value we use isn't really important.  */
415   mpq_set_ui (scaling_factor.val, 3, 5);
416
417   /* Try a few values, both negative and positive... */
418
419   read_fp_test (-256, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
420   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
421   read_fp_test (-256, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
422   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
423
424   read_fp_test (-1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
425   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
426   read_fp_test (-1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
427   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
428
429   read_fp_test (0, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
430   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
431   read_fp_test (0, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
432   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
433
434   read_fp_test (1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
435   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
436   read_fp_test (1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
437   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
438
439   read_fp_test (1025, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
440   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
441   read_fp_test (1025, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
442   SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
443 }
444
445 /* A helper function which builds a gdb_mpq object from the given
446    NUMERATOR and DENOMINATOR, and then calls gdb_mpq's write_fixed_point
447    method to write it to a buffer.
448
449    The value written into the buffer is then read back as is,
450    and returned.  */
451
452 static LONGEST
453 write_fp_test (int numerator, unsigned int denominator,
454                const gdb_mpq &scaling_factor,
455                enum bfd_endian byte_order)
456 {
457   /* For this testing, we'll use a buffer the size of LONGEST.
458      This is really an arbitrary decision, as long as the buffer
459      is long enough to hold the unscaled values that we'll be
460      writing.  */
461   const size_t len = sizeof (LONGEST);
462   gdb_byte buf[len];
463   memset (buf, 0, len);
464
465   gdb_mpq v;
466   mpq_set_si (v.val, numerator, denominator);
467   mpq_canonicalize (v.val);
468   v.write_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
469
470   return extract_unsigned_integer (buf, len, byte_order);
471 }
472
473 /* Perform various tests of the gdb_mpq::write_fixed_point method.  */
474
475 static void
476 gdb_mpq_write_fixed_point ()
477 {
478   /* Pick an arbitrary factor; this operations is sufficiently trivial
479      with the use of GMP that the value of this factor is not really
480      all that important.  */
481   gdb_mpq scaling_factor;
482   mpq_set_ui (scaling_factor.val, 1, 3);
483
484   gdb_mpq vq;
485
486   /* Try a few multiples of the scaling factor, both negative,
487      and positive... */
488
489   SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_BIG) == -24);
490   SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_LITTLE) == -24);
491
492   SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_BIG) == -2);
493   SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_LITTLE) == -2);
494
495   SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_BIG) == 0);
496   SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 0);
497
498   SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_BIG) == 5);
499   SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 5);
500 }
501
502 }
503
504 void _initialize_gmp_utils_selftests ();
505
506 void
507 _initialize_gmp_utils_selftests ()
508 {
509   selftests::register_test ("gdb_mpz_as_integer",
510                             selftests::gdb_mpz_as_integer);
511   selftests::register_test ("gdb_mpz_as_integer_out_of_range",
512                             selftests::gdb_mpz_as_integer_out_of_range);
513   selftests::register_test ("gdb_mpz_read_all_from_small",
514                             selftests::gdb_mpz_read_all_from_small);
515   selftests::register_test ("gdb_mpz_read_min_max",
516                             selftests::gdb_mpz_read_min_max);
517   selftests::register_test ("gdb_mpz_write_all_from_small",
518                             selftests::gdb_mpz_write_all_from_small);
519   selftests::register_test ("gdb_mpz_write_min_max",
520                             selftests::gdb_mpz_write_min_max);
521   selftests::register_test ("gdb_mpq_read_fixed_point",
522                             selftests::gdb_mpq_read_fixed_point);
523   selftests::register_test ("gdb_mpq_write_fixed_point",
524                             selftests::gdb_mpq_write_fixed_point);
525 }
This page took 0.055612 seconds and 4 git commands to generate.