1
1
// Author: Diffblue Ltd.
2
2
3
3
#include < util/arith_tools.h>
4
+ #include < util/bitvector_expr.h>
4
5
#include < util/bitvector_types.h>
5
6
#include < util/c_types.h>
7
+ #include < util/config.h>
6
8
#include < util/expr_initializer.h>
7
9
#include < util/namespace.h>
8
10
#include < util/std_code.h>
9
11
#include < util/symbol_table.h>
10
12
13
+ #include < testing-utils/invariant.h>
11
14
#include < testing-utils/use_catch.h>
12
15
16
+ #include < iomanip>
17
+ #include < sstream>
18
+
13
19
// / Helper struct to hold useful test components.
14
20
struct expr_initializer_test_environmentt
15
21
{
@@ -19,6 +25,10 @@ struct expr_initializer_test_environmentt
19
25
20
26
static expr_initializer_test_environmentt make ()
21
27
{
28
+ // These config lines are necessary before construction because char size
29
+ // depend on the global configuration.
30
+ config.ansi_c .mode = configt::ansi_ct::flavourt::GCC;
31
+ config.ansi_c .set_arch_spec_x86_64 ();
22
32
return {};
23
33
}
24
34
@@ -68,24 +78,209 @@ create_tag_populate_env(const typet &type, symbol_tablet &symbol_table)
68
78
UNREACHABLE;
69
79
}
70
80
71
- TEST_CASE (" nondet_initializer boolean" , " [core][util][expr_initializer]" )
81
+ exprt replicate_expression (
82
+ const exprt &expr,
83
+ const typet &output_type,
84
+ std::size_t times)
85
+ {
86
+ if (times == 1 )
87
+ {
88
+ return expr;
89
+ }
90
+ exprt::operandst operands;
91
+ operands.push_back (expr);
92
+ for (std::size_t i = 1 ; i < times; ++i)
93
+ {
94
+ operands.push_back (
95
+ shl_exprt{expr, from_integer (config.ansi_c .char_width * i, size_type ())});
96
+ }
97
+ return multi_ary_exprt{ID_bitor, operands, output_type};
98
+ }
99
+
100
+
101
+ TEST_CASE (
102
+ " duplicate_per_byte precondition works" ,
103
+ " [core][util][duplicate_per_byte]" )
104
+ {
105
+ auto test = expr_initializer_test_environmentt::make ();
106
+ typet input_type = signedbv_typet{8 };
107
+
108
+ SECTION (" duplicate_per_byte fails when init type is not a bitvector" )
109
+ {
110
+ const array_typet array_type{
111
+ bool_typet{}, from_integer (3 , signedbv_typet{8 })};
112
+
113
+ const cbmc_invariants_should_throwt invariants_throw;
114
+
115
+ REQUIRE_THROWS_MATCHES (
116
+ duplicate_per_byte (array_of_exprt{true_exprt{}, array_type}, input_type),
117
+ invariant_failedt,
118
+ invariant_failure_containing (" Condition: init_type_as_bitvector" ));
119
+ }
120
+
121
+ SECTION (
122
+ " duplicate_per_byte fails when init type is a bitvector larger than "
123
+ " char_width bits" )
124
+ {
125
+ const cbmc_invariants_should_throwt invariants_throw;
126
+
127
+ REQUIRE_THROWS_MATCHES (
128
+ duplicate_per_byte (from_integer (0 , unsignedbv_typet{10 }), input_type),
129
+ invariant_failedt,
130
+ invariant_failure_containing (
131
+ " init_type_as_bitvector->get_width() <= config.ansi_c.char_width" ));
132
+ }
133
+ }
134
+
135
+ std::string to_hex (unsigned int value)
136
+ {
137
+ std::stringstream ss;
138
+ ss << " 0x" << std::hex << value;
139
+ return ss.str ();
140
+ }
141
+
142
+ TEST_CASE (
143
+ " duplicate_per_byte on unsigned_bv with constant" ,
144
+ " [core][util][duplicate_per_byte]" )
145
+ {
146
+ auto test = expr_initializer_test_environmentt::make ();
147
+ // elements are init_expr_value, init_expr_size, output_expected_value, output_size
148
+ using rowt = std::tuple<std::size_t , unsigned int , std::size_t , unsigned int >;
149
+ unsigned int init_expr_value, output_expected_value;
150
+ std::size_t output_size, init_expr_size;
151
+ std::tie (
152
+ init_expr_value, init_expr_size, output_expected_value, output_size) =
153
+ GENERATE (
154
+ rowt{0xFF , 8 , 0xFF , 8 }, // same-type constant
155
+ rowt{0x2 , 2 , 0x02 , 8 }, // smaller-type constant gets promoted
156
+ rowt{0x11 , 5 , 0x11 , 5 }, // same-type constant
157
+ rowt{0x21 , 8 , 0x01 , 5 }, // bigger-type constant gets truncated
158
+ rowt{0x2 , 3 , 0x02 , 5 }, // smaller-type constant gets promoted
159
+ rowt{0xAB , 8 , 0xABAB , 16 }, // smaller-type constant gets replicated
160
+ rowt{0xAB , 8 , 0xBABAB , 20 } // smaller-type constant gets replicated
161
+ );
162
+ SECTION (
163
+ " Testing with output size " + std::to_string (output_size) + " init value " +
164
+ to_hex (init_expr_value) + " of size " + std::to_string (init_expr_size))
165
+ {
166
+ typet output_type = unsignedbv_typet{output_size};
167
+ const auto result = duplicate_per_byte (
168
+ from_integer (init_expr_value, unsignedbv_typet{init_expr_size}),
169
+ output_type);
170
+ const auto expected =
171
+ from_integer (output_expected_value, unsignedbv_typet{output_size});
172
+ REQUIRE (result == expected);
173
+ }
174
+ }
175
+
176
+ TEST_CASE (
177
+ " duplicate_per_byte on unsigned_bv with non-constant expr" ,
178
+ " [core][util][duplicate_per_byte]" )
179
+ {
180
+ auto test = expr_initializer_test_environmentt::make ();
181
+ // elements are init_expr_size, output_size, replication_count
182
+ using rowt = std::tuple<std::size_t , std::size_t , std::size_t >;
183
+ std::size_t init_expr_size, output_size, replication_count;
184
+ std::tie (init_expr_size, output_size, replication_count) = GENERATE (
185
+ rowt{8 , 8 , 1 }, // same-type expr no-cast
186
+ rowt{2 , 2 , 1 }, // same-type expr no-cast
187
+ rowt{3 , 8 , 1 }, // smaller-type gets promoted
188
+ rowt{8 , 2 , 1 }, // bigger type gets truncated
189
+ rowt{8 , 16 , 2 }, // replicated twice
190
+ rowt{8 , 20 , 3 }); // replicated three times and truncated
191
+ SECTION (
192
+ " Testing with output size " + std::to_string (output_size) + " init size " +
193
+ std::to_string (init_expr_size))
194
+ {
195
+ typet output_type = signedbv_typet{output_size};
196
+
197
+ const auto init_expr = plus_exprt{
198
+ from_integer (1 , unsignedbv_typet{init_expr_size}),
199
+ from_integer (2 , unsignedbv_typet{init_expr_size})};
200
+ const auto result = duplicate_per_byte (init_expr, output_type);
201
+
202
+ const auto casted_init_expr =
203
+ typecast_exprt::conditional_cast (init_expr, output_type);
204
+ const auto expected =
205
+ replicate_expression (casted_init_expr, output_type, replication_count);
206
+
207
+ REQUIRE (result == expected);
208
+ }
209
+ }
210
+
211
+ TEST_CASE (" expr_initializer boolean" , " [core][util][expr_initializer]" )
72
212
{
73
213
auto test = expr_initializer_test_environmentt::make ();
74
214
typet input = bool_typet{};
75
- const auto result = nondet_initializer (input, test.loc , test.ns );
76
- REQUIRE (result.has_value ());
77
- const auto expected = side_effect_expr_nondett{bool_typet{}, test.loc };
78
- REQUIRE (result.value () == expected);
215
+ SECTION (" nondet_initializer" )
216
+ {
217
+ const auto result = nondet_initializer (input, test.loc , test.ns );
218
+ REQUIRE (result.has_value ());
219
+ const auto expected = side_effect_expr_nondett{bool_typet{}, test.loc };
220
+ REQUIRE (result.value () == expected);
221
+ }
222
+ SECTION (" zero_initializer" )
223
+ {
224
+ const auto result = zero_initializer (input, test.loc , test.ns );
225
+ REQUIRE (result.has_value ());
226
+ const auto expected = from_integer (0 , bool_typet ());
227
+ ;
228
+ REQUIRE (result.value () == expected);
229
+ }
230
+ SECTION (" expr_initializer with same-type constant" )
231
+ {
232
+ const auto result =
233
+ expr_initializer (input, test.loc , test.ns , true_exprt{});
234
+ REQUIRE (result.has_value ());
235
+ const auto expected = true_exprt{};
236
+ REQUIRE (result.value () == expected);
237
+ }
238
+ SECTION (" expr_initializer with other-type constant" )
239
+ {
240
+ const auto result = expr_initializer (
241
+ input, test.loc , test.ns , from_integer (1 , signedbv_typet{8 }));
242
+ REQUIRE (result.has_value ());
243
+ const auto expected =
244
+ typecast_exprt{from_integer (1 , signedbv_typet{8 }), bool_typet{}};
245
+ REQUIRE (result.value () == expected);
246
+ }
247
+ SECTION (" expr_initializer with non-constant expr" )
248
+ {
249
+ const auto result = expr_initializer (
250
+ input, test.loc , test.ns , or_exprt{true_exprt (), true_exprt{}});
251
+ REQUIRE (result.has_value ());
252
+ const auto expected = or_exprt{true_exprt{}, true_exprt{}};
253
+ REQUIRE (result.value () == expected);
254
+ }
79
255
}
80
256
81
- TEST_CASE (" nondet_initializer signed_bv" , " [core][util][expr_initializer]" )
257
+ TEST_CASE (
258
+ " nondet_initializer 8-bit signed_bv" ,
259
+ " [core][util][expr_initializer]" )
82
260
{
83
261
auto test = expr_initializer_test_environmentt::make ();
84
- typet input = signedbv_typet{8 };
85
- const auto result = nondet_initializer (input, test.loc , test.ns );
86
- REQUIRE (result.has_value ());
87
- const auto expected = side_effect_expr_nondett{signedbv_typet{8 }, test.loc };
88
- REQUIRE (result.value () == expected);
262
+ const std::size_t input_type_size = 8 ;
263
+ typet input_type = signedbv_typet{input_type_size};
264
+ SECTION (" nondet_initializer" )
265
+ {
266
+ const auto result = nondet_initializer (input_type, test.loc , test.ns );
267
+ REQUIRE (result.has_value ());
268
+ const auto expected =
269
+ side_effect_expr_nondett{signedbv_typet{input_type_size}, test.loc };
270
+ REQUIRE (result.value () == expected);
271
+ }
272
+ SECTION (" zero_initializer" )
273
+ {
274
+ const auto result = zero_initializer (input_type, test.loc , test.ns );
275
+ REQUIRE (result.has_value ());
276
+ const auto expected = from_integer (0 , signedbv_typet{input_type_size});
277
+ REQUIRE (result.value () == expected);
278
+ }
279
+ SECTION (" expr_initializer calls duplicate_per_byte" )
280
+ {
281
+ // TODO: duplicate_per_byte is tested separately. Here we should check that
282
+ // expr_initializer calls duplicate_per_byte.
283
+ }
89
284
}
90
285
91
286
TEST_CASE (" nondet_initializer c_enum" , " [core][util][expr_initializer]" )
0 commit comments