|
Packit |
01d647 |
#include <safe_op.hpp>
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#include "gtestwrapper.h"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
namespace si = Safe::Internal;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
* struct that contains test numbers for Safe::add. Since different test values
|
|
Packit |
01d647 |
* are required for signed and unsigned types, this struct is specialized via
|
|
Packit |
01d647 |
* SFINAE.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* Each overload has two arrays:
|
|
Packit |
01d647 |
* T summand[] - the test numbers
|
|
Packit |
01d647 |
* bool overflow[][] - overflow[i][j] indicates whether summand[i] + summand[j]
|
|
Packit |
01d647 |
* is expected to overflow
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* The numbers in summand are chosen accordingly to test all "interesting" cases
|
|
Packit |
01d647 |
* and cause some overflows. The actual test should simply check all possible
|
|
Packit |
01d647 |
* sums of summand against the value in overflow[][]
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
template <typename T, typename = void>
|
|
Packit |
01d647 |
struct AdditionTestValues;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
* Overload for unsigned types.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
struct AdditionTestValues<T, typename si::enable_if<!si::is_signed<T>::VALUE>::type>
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
static const size_t case_count = 5;
|
|
Packit |
01d647 |
static const T summand[case_count];
|
|
Packit |
01d647 |
static const bool overflow[case_count][case_count];
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
const T AdditionTestValues<T, typename si::enable_if<!si::is_signed<T>::VALUE>::type>::summand[] = {
|
|
Packit |
01d647 |
0, 1, 2, static_cast<T>(std::numeric_limits<T>::max() - 1), std::numeric_limits<T>::max()};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
const bool
|
|
Packit |
01d647 |
AdditionTestValues<T, typename si::enable_if<!si::is_signed<T>::VALUE>::type>::overflow[case_count][case_count] = {
|
|
Packit |
01d647 |
// 0
|
|
Packit |
01d647 |
{false, false, false, false, false},
|
|
Packit |
01d647 |
// 1
|
|
Packit |
01d647 |
{false, false, false, false, true},
|
|
Packit |
01d647 |
// 2
|
|
Packit |
01d647 |
{false, false, false, true, true},
|
|
Packit |
01d647 |
// max - 1
|
|
Packit |
01d647 |
{false, false, true, true, true},
|
|
Packit |
01d647 |
// max
|
|
Packit |
01d647 |
{false, true, true, true, true}};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
* Overload for signed integers
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
struct AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::type>
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
static const size_t case_count = 8;
|
|
Packit |
01d647 |
static const T summand[case_count];
|
|
Packit |
01d647 |
static const bool overflow[case_count][case_count];
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
const T AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::type>::summand[] = {
|
|
Packit |
01d647 |
std::numeric_limits<T>::min(),
|
|
Packit |
01d647 |
static_cast<T>(std::numeric_limits<T>::min() + 1),
|
|
Packit |
01d647 |
-1,
|
|
Packit |
01d647 |
0,
|
|
Packit |
01d647 |
1,
|
|
Packit |
01d647 |
2,
|
|
Packit |
01d647 |
static_cast<T>(std::numeric_limits<T>::max() - 1),
|
|
Packit |
01d647 |
std::numeric_limits<T>::max()};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
const bool
|
|
Packit |
01d647 |
AdditionTestValues<T, typename si::enable_if<si::is_signed<T>::VALUE>::type>::overflow[case_count][case_count] = {
|
|
Packit |
01d647 |
// min
|
|
Packit |
01d647 |
{true, true, true, false, false, false, false, false},
|
|
Packit |
01d647 |
// min + 1
|
|
Packit |
01d647 |
{true, true, false, false, false, false, false, false},
|
|
Packit |
01d647 |
// -1
|
|
Packit |
01d647 |
{true, false, false, false, false, false, false, false},
|
|
Packit |
01d647 |
// 0
|
|
Packit |
01d647 |
{false, false, false, false, false, false, false, false},
|
|
Packit |
01d647 |
// 1
|
|
Packit |
01d647 |
{false, false, false, false, false, false, false, true},
|
|
Packit |
01d647 |
// 2
|
|
Packit |
01d647 |
{false, false, false, false, false, false, true, true},
|
|
Packit |
01d647 |
// max - 1
|
|
Packit |
01d647 |
{false, false, false, false, false, true, true, true},
|
|
Packit |
01d647 |
// max
|
|
Packit |
01d647 |
{false, false, false, false, true, true, true, true}};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
* Test the addition of all combinations of AdditionTestValues<T>::summand[i],
|
|
Packit |
01d647 |
* AdditionTestValues<T>::summand[j] using fallback_add_overflow::add and
|
|
Packit |
01d647 |
* builtin_add_overflow::add. The return value is checked against
|
|
Packit |
01d647 |
* AdditionTestValues<T>::overflow[i][j]. If no overflow occurs, then the result
|
|
Packit |
01d647 |
* is checked too.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
void test_add()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
typedef AdditionTestValues<T> TestValues;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#define TEST_ADD(func) \
|
|
Packit |
01d647 |
for (size_t i = 0; i < TestValues::case_count; ++i) { \
|
|
Packit |
01d647 |
for (size_t j = 0; j < TestValues::case_count; ++j) { \
|
|
Packit |
01d647 |
T res = 0; \
|
|
Packit |
01d647 |
ASSERT_EQ(func(TestValues::summand[i], TestValues::summand[j], res), TestValues::overflow[i][j]); \
|
|
Packit |
01d647 |
if (!TestValues::overflow[i][j]) { \
|
|
Packit |
01d647 |
ASSERT_EQ(res, TestValues::summand[i] + TestValues::summand[j]); \
|
|
Packit |
01d647 |
} \
|
|
Packit |
01d647 |
} \
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TEST_ADD(si::fallback_add_overflow)
|
|
Packit |
01d647 |
TEST_ADD(si::builtin_add_overflow)
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#undef TEST_ADD
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
* Test the addition of all combinations of AdditionTestValues<T>::summand[i],
|
|
Packit |
01d647 |
* AdditionTestValues<T>::summand[j] using Safe::add.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* It is checked whether an exception is thrown when
|
|
Packit |
01d647 |
* AdditionTestValues<T>::overflow[i][j] is true, otherwise the result is
|
|
Packit |
01d647 |
* checked.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
template <typename T>
|
|
Packit |
01d647 |
void test_safe_add()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
typedef AdditionTestValues<T> TestValues;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
for (size_t i = 0; i < TestValues::case_count; ++i) {
|
|
Packit |
01d647 |
for (size_t j = 0; j < TestValues::case_count; ++j) {
|
|
Packit |
01d647 |
if (TestValues::overflow[i][j]) {
|
|
Packit |
01d647 |
ASSERT_THROW(Safe::add(TestValues::summand[i], TestValues::summand[j]), std::overflow_error);
|
|
Packit |
01d647 |
} else {
|
|
Packit |
01d647 |
ASSERT_EQ(Safe::add(TestValues::summand[i], TestValues::summand[j]),
|
|
Packit |
01d647 |
TestValues::summand[i] + TestValues::summand[j]);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TEST(lowLevelAddOverflow, checkUnsignedOverflow)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
test_add<unsigned char>();
|
|
Packit |
01d647 |
test_add<unsigned short>();
|
|
Packit |
01d647 |
test_add<unsigned int>();
|
|
Packit |
01d647 |
test_add<unsigned long>();
|
|
Packit |
01d647 |
test_add<unsigned long long>();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TEST(lowLevelAddOverflow, checkSignedOverflow)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
test_add<char>();
|
|
Packit |
01d647 |
test_add<short>();
|
|
Packit |
01d647 |
test_add<int>();
|
|
Packit |
01d647 |
test_add<long>();
|
|
Packit |
01d647 |
test_add<long long>();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TEST(safeAdd, checkUnsignedOverflow)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
test_safe_add<unsigned char>();
|
|
Packit |
01d647 |
test_safe_add<unsigned short>();
|
|
Packit |
01d647 |
test_safe_add<unsigned int>();
|
|
Packit |
01d647 |
test_safe_add<unsigned long>();
|
|
Packit |
01d647 |
test_safe_add<unsigned long long>();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TEST(safeAdd, checkSignedOverflow)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
test_safe_add<char>();
|
|
Packit |
01d647 |
test_safe_add<short>();
|
|
Packit |
01d647 |
test_safe_add<int>();
|
|
Packit |
01d647 |
test_safe_add<long>();
|
|
Packit |
01d647 |
test_safe_add<long long>();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
TEST(safeAbs, checkValues)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
static const int values[] = {-1, 1, std::numeric_limits<int>::max(), std::numeric_limits<int>::min() + 1};
|
|
Packit |
01d647 |
for (size_t i = 0; i < sizeof(values) / sizeof(*values); ++i) {
|
|
Packit |
01d647 |
ASSERT_EQ(Safe::abs(values[i]), abs(values[i]));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
ASSERT_EQ(Safe::abs(std::numeric_limits<int>::min()), std::numeric_limits<int>::max());
|
|
Packit |
01d647 |
}
|