1
#![cfg(test)]
2

            
3
use proptest::prelude::*;
4

            
5
use crate::constant_parser::{parse_numeric_constant, IntegerConst, NumConst, ParseResult};
6

            
7
1
#[test]
8
1
fn single_digits_should_parse_into_integer_constant() {
9
1
    let inputs = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
10

            
11
11
    for input in inputs {
12
10
        let integer = IntegerConst {
13
10
            value: input.parse().unwrap(),
14
10
            is_unsigned: false,
15
10
        };
16
10

            
17
10
        let expected = ParseResult {
18
10
            num_const: NumConst::Int(integer),
19
10
            has_overflowed: false,
20
10
        };
21
10

            
22
10
        assert_eq!(parse_numeric_constant(input), expected);
23
    }
24
1
}
25

            
26
260
proptest! {
27
260
    #[test]
28
260
    fn constants_that_start_with_something_other_than_zero_should_parse_as_decimal_integer_constants(
29
260
        input in "[1-9][0-9]{1,18}"
30
260
    ) {
31
260
        // Using at most 19 digits for this test, as that is the maximum number of digits that
32
260
        // guarantees it will never overflow 64 bits.
33
260

            
34
260
        let integer = IntegerConst {
35
260
            value: input.parse().unwrap(),
36
260
            is_unsigned: false,
37
260
        };
38
260

            
39
260
        let expected = ParseResult {
40
260
            num_const: NumConst::Int(integer),
41
260
            has_overflowed: false,
42
260
        };
43
260

            
44
260
        assert_eq!(parse_numeric_constant(&input), expected);
45
261
    }
46
261
}
47

            
48
260
proptest! {
49
260
    #[test]
50
260
    fn decimal_intenger_constants_that_go_over_64_bits_should_be_flagged_as_overflowed(
51
260
        input in "[1-9][0-9]{20,37}"
52
260
    ) {
53
260
        let truncated_value = input.parse::<u128>().unwrap() as u64;
54
260

            
55
260
        let integer = IntegerConst {
56
260
            value: truncated_value,
57
260
            is_unsigned: false,
58
260
        };
59
260

            
60
260
        let expected = ParseResult {
61
260
            num_const: NumConst::Int(integer),
62
260
            has_overflowed: true,
63
260
        };
64
260

            
65
260
        assert_eq!(parse_numeric_constant(&input), expected);
66
261
    }
67
261
}
68

            
69
1
#[test]
70
1
fn decimal_intenger_constant_that_goes_a_bit_over_64_bits_should_be_flagged_as_overflowed() {
71
1
    let valid_input = "18446744073709551615";
72
1

            
73
1
    assert_eq!(
74
1
        parse_numeric_constant(valid_input),
75
1
        ParseResult {
76
1
            num_const: NumConst::Int(IntegerConst {
77
1
                value: u64::MAX,
78
1
                is_unsigned: false
79
1
            }),
80
1
            has_overflowed: false,
81
1
        }
82
1
    );
83

            
84
1
    let invalid_input = "18446744073709551616";
85
1

            
86
1
    assert_eq!(
87
1
        parse_numeric_constant(invalid_input),
88
1
        ParseResult {
89
1
            num_const: NumConst::Int(IntegerConst {
90
1
                value: 0,
91
1
                is_unsigned: false
92
1
            }),
93
1
            has_overflowed: true,
94
1
        }
95
1
    );
96
1
}
97

            
98
260
proptest! {
99
260
    #[test]
100
260
    fn constants_that_start_with_zero_should_parse_as_octal_integer_constants(
101
260
        input in "0[1-7]{1,21}"
102
260
    ) {
103
260
        // Using at most 21 digits for this test, as that is the maximum number of digits that
104
260
        // guarantees it will never overflow 64 bits.
105
260

            
106
260
        let raw_value = u64::from_str_radix(&input[1..], 8).unwrap();
107
260

            
108
260
        let integer = IntegerConst {
109
260
            value: raw_value,
110
260
            is_unsigned: false,
111
260
        };
112
260

            
113
260
        let expected = ParseResult {
114
260
            num_const: NumConst::Int(integer),
115
260
            has_overflowed: false,
116
260
        };
117
260

            
118
260
        assert_eq!(parse_numeric_constant(&input), expected);
119
261
    }
120
261
}
121

            
122
260
proptest! {
123
260
    #[test]
124
260
    fn octal_intenger_constants_that_go_over_64_bits_should_be_flagged_as_overflowed(
125
260
        input in "0[1-7]{23,42}"
126
260
    ) {
127
260
        let truncated_value = u128::from_str_radix(&input[1..], 8).unwrap() as u64;
128
260

            
129
260
        let integer = IntegerConst {
130
260
            value: truncated_value,
131
260
            is_unsigned: false,
132
260
        };
133
260

            
134
260

            
135
260
        let expected = ParseResult {
136
260
            num_const: NumConst::Int(integer),
137
260
            has_overflowed: true,
138
260
        };
139
260

            
140
260
        assert_eq!(parse_numeric_constant(&input), expected);
141
261
    }
142
261
}
143

            
144
1
#[test]
145
1
fn octal_intenger_constant_that_goes_a_bit_over_64_bits_should_be_flagged_as_overflowed() {
146
1
    let valid_input = "01777777777777777777777";
147
1

            
148
1
    assert_eq!(
149
1
        parse_numeric_constant(valid_input),
150
1
        ParseResult {
151
1
            num_const: NumConst::Int(IntegerConst {
152
1
                value: u64::MAX,
153
1
                is_unsigned: false
154
1
            }),
155
1
            has_overflowed: false,
156
1
        }
157
1
    );
158

            
159
1
    let invalid_input = "02000000000000000000000";
160
1

            
161
1
    assert_eq!(
162
1
        parse_numeric_constant(invalid_input),
163
1
        ParseResult {
164
1
            num_const: NumConst::Int(IntegerConst {
165
1
                value: 0,
166
1
                is_unsigned: false
167
1
            }),
168
1
            has_overflowed: true,
169
1
        }
170
1
    );
171
1
}
172

            
173
260
proptest! {
174
260
    #[test]
175
260
    fn constants_that_start_with_zero_and_x_should_parse_as_hexadecimal_integer_constants(
176
260
        input in "0[xX][1-9a-fA-F]{1,16}"
177
260
    ) {
178
260
        // Using at most 16 digits for this test, as that is the maximum number of digits that
179
260
        // guarantees it will never overflow 64 bits.
180
260

            
181
260
        let raw_value = u64::from_str_radix(&input[2..], 16).unwrap();
182
260

            
183
260
        let integer = IntegerConst {
184
260
            value: raw_value,
185
260
            is_unsigned: false,
186
260
        };
187
260

            
188
260
        let expected = ParseResult {
189
260
            num_const: NumConst::Int(integer),
190
260
            has_overflowed: false,
191
260
        };
192
260

            
193
260
        assert_eq!(parse_numeric_constant(&input), expected);
194
261
    }
195
261
}
196

            
197
260
proptest! {
198
260
    #[test]
199
260
    fn hexadecimal_intenger_constants_that_go_over_64_bits_should_be_flagged_as_overflowed(
200
260
        input in "0[xX][1-9a-fA-F]{17,32}"
201
260
    ) {
202
260
        let truncated_value = u128::from_str_radix(&input[2..], 16).unwrap() as u64;
203
260

            
204
260
        let integer = IntegerConst {
205
260
            value: truncated_value,
206
260
            is_unsigned: false,
207
260
        };
208
260

            
209
260
        let expected = ParseResult {
210
260
            num_const: NumConst::Int(integer),
211
260
            has_overflowed: true,
212
260
        };
213
260

            
214
260
        assert_eq!(parse_numeric_constant(&input), expected);
215
261
    }
216
261
}
217

            
218
1
#[test]
219
1
fn hexadecimal_intenger_constant_that_goes_a_bit_over_64_bits_should_be_flagged_as_overflowed() {
220
1
    let valid_input = "0xffffffffffffffff";
221
1

            
222
1
    assert_eq!(
223
1
        parse_numeric_constant(valid_input),
224
1
        ParseResult {
225
1
            num_const: NumConst::Int(IntegerConst {
226
1
                value: u64::MAX,
227
1
                is_unsigned: false
228
1
            }),
229
1
            has_overflowed: false,
230
1
        }
231
1
    );
232

            
233
1
    let invalid_input = "0x10000000000000000";
234
1

            
235
1
    assert_eq!(
236
1
        parse_numeric_constant(invalid_input),
237
1
        ParseResult {
238
1
            num_const: NumConst::Int(IntegerConst {
239
1
                value: 0,
240
1
                is_unsigned: false
241
1
            }),
242
1
            has_overflowed: true,
243
1
        }
244
1
    );
245
1
}