Blame unitTests/test_safe_op.cpp

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
}