aboutsummaryrefslogtreecommitdiffstats
path: root/libtests/qintc.cc
blob: d3e19f5bd087b75ec2e166a6267db7725f4da52a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <qpdf/QIntC.hh>
#include <stdint.h>

#ifdef NDEBUG
// We need assert even in a release build for test code.
# undef NDEBUG
#endif
#include <cassert>

#define try_convert(exp_pass, fn, i) \
 try_convert_real(#fn "(" #i ")", exp_pass, fn, i)

template <typename From, typename To>
static void
try_convert_real(
    char const* description,
    bool exp_pass,
    To (*fn)(From const&),
    From const& i)
{
    bool passed = false;
    try {
        To result = fn(i);
        passed = true;
        std::cout << description << ": " << i << " " << result;
    } catch (std::range_error& e) {
        std::cout << description << ": " << e.what();
        passed = false;
    }
    std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl;
}

#define try_range_check(exp_pass, a, b) \
 try_range_check_real(#a " + " #b, exp_pass, a, b)

template <typename T>
static void
try_range_check_real(
    char const* description, bool exp_pass, T const& a, T const& b)
{
    bool passed = false;
    try {
        QIntC::range_check(a, b);
        std::cout << description << ": okay";
        passed = true;
    } catch (std::range_error& e) {
        std::cout << description << ": " << e.what();
        passed = false;
    }
    std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl;
}

#define try_range_check_subtract(exp_pass, a, b) \
 try_range_check_subtract_real(#a " - " #b, exp_pass, a, b)

template <typename T>
static void
try_range_check_subtract_real(
    char const* description, bool exp_pass, T const& a, T const& b)
{
    bool passed = false;
    try {
        QIntC::range_check_substract(a, b);
        std::cout << description << ": okay";
        passed = true;
    } catch (std::range_error& e) {
        std::cout << description << ": " << e.what();
        passed = false;
    }
    std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl;
}

int
main()
{
    uint32_t u1 = 3141592653U;      // Too big for signed type
    int32_t i1 = -1153374643;       // Same bit pattern as u1
    uint64_t ul1 = 1099511627776LL; // Too big for 32-bit
    uint64_t ul2 = 12345;           // Fits into 32-bit
    int32_t i2 = 81;                // Fits in char and uchar
    signed char c1 = static_cast<signed char>('\xf7'); // Signed value when char
    char c2 = 'W'; // char; may be signed or unsigned

    // Verify i1 and u1 have same bit pattern
    assert(static_cast<uint32_t>(i1) == u1);
    // Verify that we can unsafely convert between signed and unsigned char
    assert(c1 == static_cast<signed char>(static_cast<unsigned char>(c1)));

    try_convert(true, QIntC::to_int<int32_t>, i1);
    try_convert(true, QIntC::to_uint<uint32_t>, u1);
    try_convert(false, QIntC::to_int<uint32_t>, u1);
    try_convert(false, QIntC::to_uint<int32_t>, i1);
    try_convert(false, QIntC::to_int<uint64_t>, ul1);
    try_convert(true, QIntC::to_int<uint64_t>, ul2);
    try_convert(true, QIntC::to_uint<uint64_t>, ul2);
    try_convert(true, QIntC::to_offset<uint32_t>, u1);
    try_convert(true, QIntC::to_offset<int32_t>, i1);
    try_convert(false, QIntC::to_ulonglong<int32_t>, i1);
    try_convert(true, QIntC::to_char<int32_t>, i2);
    try_convert(true, QIntC::to_uchar<int32_t>, i2);
    try_convert(false, QIntC::to_uchar<signed char>, c1);
    try_convert(true, QIntC::to_uchar<char>, c2);
    try_convert(true, QIntC::to_char<char>, c2);

    auto constexpr max_ll = std::numeric_limits<long long>::max();
    auto constexpr max_ull = std::numeric_limits<unsigned long long>::max();
    auto constexpr min_ll = std::numeric_limits<long long>::min();
    auto constexpr max_sc = std::numeric_limits<signed char>::max();
    try_range_check(true, 1, 2);
    try_range_check(true, -1, 2);
    try_range_check(true, -100, -200);
    try_range_check(true, max_ll, 0LL);
    try_range_check(false, max_ll, 1LL);
    try_range_check(true, max_ll, 0LL);
    try_range_check(false, max_ll, 1LL);
    try_range_check(true, max_ull, 0ULL);
    try_range_check(false, max_ull, 1ULL);
    try_range_check(true, min_ll, 0LL);
    try_range_check(false, min_ll, -1LL);
    try_range_check(false, max_sc, max_sc);
    try_range_check(true, '!', '#');
    try_range_check_subtract(true, 1, 2);
    try_range_check_subtract(true, -1, -2);
    try_range_check_subtract(true, 1, 10);
    try_range_check_subtract(true, -1, -10);
    try_range_check_subtract(false, 0LL, min_ll);
    try_range_check_subtract(false, 1LL, min_ll);
    try_range_check_subtract(true, 0LL, max_ll);
    try_range_check_subtract(true, -1LL, max_ll);
    try_range_check_subtract(false, -2LL, max_ll);
    return 0;
}