Automatic Copyright Year update after running gdb/copyright.py
[deliverable/binutils-gdb.git] / gdb / unittests / gmp-utils-selftests.c
CommitLineData
b34c74ab
JB
1/* Self tests of the gmp-utils API.
2
88b9d363 3 Copyright (C) 2019-2022 Free Software Foundation, Inc.
b34c74ab
JB
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
25namespace selftests {
26
27/* Perform a series of general tests of gdb_mpz's as_integer method.
28
63c457b9
JB
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. */
b34c74ab
JB
33
34static void
35gdb_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
63c457b9
JB
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
88template<typename T, typename = gdb::Requires<std::is_integral<T>>>
89static void
90check_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
112static void
113gdb_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
b34c74ab
JB
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
159template<typename T>
160void
c9f0b43f 161store_and_read_back (T val, size_t buf_len, enum bfd_endian byte_order,
b34c74ab
JB
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
c9f0b43f 175 actual.read ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
b34c74ab
JB
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
184static void
185gdb_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;
c0ad05d5
SM
191 LONGEST l_min = -pow (2.0, buf_len * 8 - 1);
192 LONGEST l_max = pow (2.0, buf_len * 8 - 1) - 1;
b34c74ab
JB
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;
c0ad05d5 207 ULONGEST ul_max = pow (2.0, buf_len * 8) - 1;
b34c74ab
JB
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
223static void
224gdb_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
291template<typename T>
292T
c9f0b43f 293write_and_extract (T val, size_t buf_len, enum bfd_endian byte_order)
b34c74ab
JB
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);
c9f0b43f 300 v.write ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
b34c74ab
JB
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
310static void
311gdb_mpz_write_all_from_small ()
312{
313 int buf_len = 1;
c0ad05d5
SM
314 LONGEST l_min = -pow (2.0, buf_len * 8 - 1);
315 LONGEST l_max = pow (2.0, buf_len * 8 - 1) - 1;
b34c74ab
JB
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;
c0ad05d5 325 ULONGEST ul_max = pow (2.0, buf_len * 8) - 1;
b34c74ab
JB
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
336static void
337gdb_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
388static void
389read_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. */
c9f0b43f 395 const size_t len = sizeof (unscaled);
b34c74ab
JB
396 gdb_byte buf[len];
397 store_signed_integer (buf, len, byte_order, unscaled);
398
c9f0b43f 399 actual.read_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
b34c74ab
JB
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
407static void
408gdb_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
452static LONGEST
453write_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. */
c9f0b43f 461 const size_t len = sizeof (LONGEST);
b34c74ab
JB
462 gdb_byte buf[len];
463 memset (buf, 0, len);
464
465 gdb_mpq v;
4fbb7cce 466 mpq_set_si (v.val, numerator, denominator);
b34c74ab 467 mpq_canonicalize (v.val);
c9f0b43f 468 v.write_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
b34c74ab
JB
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
475static void
476gdb_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
504void _initialize_gmp_utils_selftests ();
505
506void
507_initialize_gmp_utils_selftests ()
508{
509 selftests::register_test ("gdb_mpz_as_integer",
510 selftests::gdb_mpz_as_integer);
63c457b9
JB
511 selftests::register_test ("gdb_mpz_as_integer_out_of_range",
512 selftests::gdb_mpz_as_integer_out_of_range);
b34c74ab
JB
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.143202 seconds and 4 git commands to generate.