forked from amazon-ion/ion-c
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Fixed issues amazon-ion#224 & amazon-ion#226: Ion int to/from int64_t
* Fixed issues amazon-ion#224 & amazon-ion#226: Ion int to/from int64_t * Addressed a corner case in ion_int_from_long that caused an infinite loop when MIN_INT64 was passed in as the long value. * Modified the `ion_int_to_int64` function to work on 63- and 64-bit magnitudes. * Adds roundtripping unit tests that convert an int64_t to an IINT and then back to an int64_t again. * Added a unit test to verify that `ion_int_to_int64` detects overflow as expected. It tests both the case where the value can fit in 64 unsigned bits (but not 64 signed bits) and the case where the number is too big to fit in 64 bits. Co-authored-by: Zack Slayton <[email protected]>
- Loading branch information
Showing
3 changed files
with
190 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
* Copyright 2009-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). | ||
* You may not use this file except in compliance with the License. | ||
* A copy of the License is located at: | ||
* | ||
* http://aws.amazon.com/apache2.0/ | ||
* | ||
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific | ||
* language governing permissions and limitations under the License. | ||
*/ | ||
|
||
#include "ion_assert.h" | ||
#include "ion_helpers.h" | ||
#include "ion_test_util.h" | ||
|
||
iERR test_ion_int_roundtrip_int64_t(int64_t value_in, int64_t * value_out) { | ||
iENTER; | ||
// Create an uninitialized Ion integer. | ||
ION_INT * iint; | ||
// Initialize the Ion integer, setting its owner to NULL. | ||
IONCHECK(ion_int_alloc(NULL, &iint)); | ||
// Populate the Ion integer with the provided int64_t value. | ||
IONCHECK(ion_int_from_long(iint, value_in)); | ||
// Read the Ion integer's value back out into the output int64_t. | ||
IONCHECK(ion_int_to_int64(iint, value_out)); | ||
// Free the memory used to store the Ion integer's digits. | ||
ion_int_free(iint); | ||
iRETURN; | ||
} | ||
|
||
TEST(IonInteger, IIntToInt64RoundTrip) { | ||
// This test verifies that the `ion_int_from_long` and `ion_int_to_int64` functions work as | ||
// intended. For each of the following values in the range from MIN_INT64 to MAX_INT64 inclusive, | ||
// the test will convert the int64_t to an IINT and then back again, confirming that the output | ||
// int64_t is equal to the input int64_t. | ||
const uint32_t number_of_values = 19; | ||
int64_t values[number_of_values] = { | ||
MIN_INT64, MAX_INT64, | ||
MIN_INT64 + 16, MAX_INT64 - 16, | ||
-9670031482938124, 9670031482938124, | ||
-10031482954246, 10031482954246, | ||
-58116329947, 58116329947, | ||
-66182226, 66182226, | ||
-75221, 75221, | ||
-825, 825 | ||
-1, 1, | ||
0 | ||
}; | ||
|
||
int64_t value_in; | ||
int64_t value_out; | ||
for(int m = 0; m < number_of_values; m++) { | ||
value_in = values[m]; | ||
ION_ASSERT_OK(test_ion_int_roundtrip_int64_t(value_in, &value_out)); | ||
ASSERT_EQ(value_in, value_out); | ||
} | ||
} | ||
|
||
iERR test_ion_int_to_int64_t_overflow_detection(const char * p_chars) { | ||
iENTER; | ||
const uint32_t max_string_length = 32; | ||
uint32_t string_length = strnlen(p_chars, max_string_length); | ||
// Create an uninitialized Ion integer. | ||
ION_INT iint; | ||
// Create an int64_t that we will later populate with the value of iint. | ||
int64_t value_out; | ||
// Initialize the Ion integer, setting its owner to NULL. | ||
IONCHECK(ion_int_init(&iint, NULL)); | ||
// Populate the Ion integer with the value of the provided base-10 string | ||
IONCHECK(ion_int_from_chars(&iint, p_chars, string_length)); | ||
// Attempt to read the Ion integer's value back out into the int64_t. | ||
// If the number is outside the range of values that can be represented by | ||
// an int64_t, this should return IERR_NUMERIC_OVERFLOW. | ||
IONCHECK(ion_int_to_int64(&iint, &value_out)); | ||
iRETURN; | ||
} | ||
|
||
TEST(IonInteger, IIntToInt64Overflow) { | ||
// This test verifies that the `ion_int_to_int64` method will return IERR_NUMERIC_OVERFLOW | ||
// if the provided Ion integer's value will not fit in an int64_t. Because any Ion integer | ||
// constructed using `ion_int_from_long` will inherently fit in an int64_t, we instead | ||
// construct each Ion integer with `ion_int_from_chars`, passing in Ion text encodings | ||
// of the integers to create. | ||
const uint32_t number_of_ok_values = 9; | ||
const char *small_integers[number_of_ok_values] = { | ||
"-10004991088", | ||
"-9862", | ||
"-138", | ||
"-1", | ||
"0", | ||
"1", | ||
"138", | ||
"9862", | ||
"10004991088" | ||
}; | ||
|
||
// Each of the above values will fit in an int64_t, so the test function should succeed. | ||
for (int m = 0; m < number_of_ok_values; m++) { | ||
const char *small_integer = small_integers[m]; | ||
ION_ASSERT_OK(test_ion_int_to_int64_t_overflow_detection(small_integer)); | ||
} | ||
|
||
const uint32_t number_of_oversized_values = 4; | ||
const char *oversized_integers[number_of_oversized_values] = { | ||
"9223372036854775808", // MAX_INT64 + 1 | ||
"-9223372036854775809", // MIN_INT64 - 1 | ||
"10004991088252643637337337422", | ||
"-10004991088252643637337337422", | ||
}; | ||
|
||
// Each of the above values has a magnitude that is too large to fit in an int64_t, | ||
// so the test function should fail, returning IERR_NUMERIC_OVERFLOW. | ||
for (int m = 0; m < number_of_oversized_values; m++) { | ||
const char *oversized_integer = oversized_integers[m]; | ||
iERR error_value = test_ion_int_to_int64_t_overflow_detection(oversized_integer); | ||
ASSERT_EQ(error_value, IERR_NUMERIC_OVERFLOW); | ||
} | ||
} |