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,208 @@ 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
+ TEST_CASE (
101
+ " duplicate_per_byte precondition works" ,
102
+ " [core][util][duplicate_per_byte]" )
103
+ {
104
+ auto test = expr_initializer_test_environmentt::make ();
105
+ typet input_type = signedbv_typet{8 };
106
+
107
+ SECTION (" duplicate_per_byte fails when init type is not a bitvector" )
108
+ {
109
+ const array_typet array_type{
110
+ bool_typet{}, from_integer (3 , signedbv_typet{8 })};
111
+
112
+ const cbmc_invariants_should_throwt invariants_throw;
113
+
114
+ REQUIRE_THROWS_MATCHES (
115
+ duplicate_per_byte (array_of_exprt{true_exprt{}, array_type}, input_type),
116
+ invariant_failedt,
117
+ invariant_failure_containing (" Condition: init_type_as_bitvector" ));
118
+ }
119
+
120
+ SECTION (
121
+ " duplicate_per_byte fails when init type is a bitvector larger than "
122
+ " char_width bits" )
123
+ {
124
+ const cbmc_invariants_should_throwt invariants_throw;
125
+
126
+ REQUIRE_THROWS_MATCHES (
127
+ duplicate_per_byte (from_integer (0 , unsignedbv_typet{10 }), input_type),
128
+ invariant_failedt,
129
+ invariant_failure_containing (
130
+ " init_type_as_bitvector->get_width() <= config.ansi_c.char_width" ));
131
+ }
132
+ }
133
+
134
+ std::string to_hex (unsigned int value)
135
+ {
136
+ std::stringstream ss;
137
+ ss << " 0x" << std::hex << value;
138
+ return ss.str ();
139
+ }
140
+
141
+ TEST_CASE (
142
+ " duplicate_per_byte on unsigned_bv with constant" ,
143
+ " [core][util][duplicate_per_byte]" )
144
+ {
145
+ auto test = expr_initializer_test_environmentt::make ();
146
+ // elements are init_expr_value, init_expr_size, output_expected_value, output_size
147
+ using rowt = std::tuple<std::size_t , unsigned int , std::size_t , unsigned int >;
148
+ unsigned int init_expr_value, output_expected_value;
149
+ std::size_t output_size, init_expr_size;
150
+ std::tie (
151
+ init_expr_value, init_expr_size, output_expected_value, output_size) =
152
+ GENERATE (
153
+ rowt{0xFF , 8 , 0xFF , 8 }, // same-type constant
154
+ rowt{0x2 , 2 , 0x02 , 8 }, // smaller-type constant gets promoted
155
+ rowt{0x11 , 5 , 0x11 , 5 }, // same-type constant
156
+ rowt{0x21 , 8 , 0x01 , 5 }, // bigger-type constant gets truncated
157
+ rowt{0x2 , 3 , 0x02 , 5 }, // smaller-type constant gets promoted
158
+ rowt{0xAB , 8 , 0xABAB , 16 }, // smaller-type constant gets replicated
159
+ rowt{0xAB , 8 , 0xBABAB , 20 } // smaller-type constant gets replicated
160
+ );
161
+ SECTION (
162
+ " Testing with output size " + std::to_string (output_size) + " init value " +
163
+ to_hex (init_expr_value) + " of size " + std::to_string (init_expr_size))
164
+ {
165
+ typet output_type = unsignedbv_typet{output_size};
166
+ const auto result = duplicate_per_byte (
167
+ from_integer (init_expr_value, unsignedbv_typet{init_expr_size}),
168
+ output_type);
169
+ const auto expected =
170
+ from_integer (output_expected_value, unsignedbv_typet{output_size});
171
+ REQUIRE (result == expected);
172
+ }
173
+ }
174
+
175
+ TEST_CASE (
176
+ " duplicate_per_byte on unsigned_bv with non-constant expr" ,
177
+ " [core][util][duplicate_per_byte]" )
178
+ {
179
+ auto test = expr_initializer_test_environmentt::make ();
180
+ // elements are init_expr_size, output_size, replication_count
181
+ using rowt = std::tuple<std::size_t , std::size_t , std::size_t >;
182
+ std::size_t init_expr_size, output_size, replication_count;
183
+ std::tie (init_expr_size, output_size, replication_count) = GENERATE (
184
+ rowt{8 , 8 , 1 }, // same-type expr no-cast
185
+ rowt{2 , 2 , 1 }, // same-type expr no-cast
186
+ rowt{3 , 8 , 1 }, // smaller-type gets promoted
187
+ rowt{8 , 2 , 1 }, // bigger type gets truncated
188
+ rowt{8 , 16 , 2 }, // replicated twice
189
+ rowt{8 , 20 , 3 }); // replicated three times and truncated
190
+ SECTION (
191
+ " Testing with output size " + std::to_string (output_size) + " init size " +
192
+ std::to_string (init_expr_size))
193
+ {
194
+ typet output_type = signedbv_typet{output_size};
195
+
196
+ const auto init_expr = plus_exprt{
197
+ from_integer (1 , unsignedbv_typet{init_expr_size}),
198
+ from_integer (2 , unsignedbv_typet{init_expr_size})};
199
+ const auto result = duplicate_per_byte (init_expr, output_type);
200
+
201
+ const auto casted_init_expr =
202
+ typecast_exprt::conditional_cast (init_expr, output_type);
203
+ const auto expected =
204
+ replicate_expression (casted_init_expr, output_type, replication_count);
205
+
206
+ REQUIRE (result == expected);
207
+ }
208
+ }
209
+
210
+ TEST_CASE (" expr_initializer boolean" , " [core][util][expr_initializer]" )
72
211
{
73
212
auto test = expr_initializer_test_environmentt::make ();
74
213
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);
214
+ SECTION (" nondet_initializer" )
215
+ {
216
+ const auto result = nondet_initializer (input, test.loc , test.ns );
217
+ REQUIRE (result.has_value ());
218
+ const auto expected = side_effect_expr_nondett{bool_typet{}, test.loc };
219
+ REQUIRE (result.value () == expected);
220
+ }
221
+ SECTION (" zero_initializer" )
222
+ {
223
+ const auto result = zero_initializer (input, test.loc , test.ns );
224
+ REQUIRE (result.has_value ());
225
+ const auto expected = from_integer (0 , bool_typet ());
226
+ ;
227
+ REQUIRE (result.value () == expected);
228
+ }
229
+ SECTION (" expr_initializer with same-type constant" )
230
+ {
231
+ const auto result =
232
+ expr_initializer (input, test.loc , test.ns , true_exprt{});
233
+ REQUIRE (result.has_value ());
234
+ const auto expected = true_exprt{};
235
+ REQUIRE (result.value () == expected);
236
+ }
237
+ SECTION (" expr_initializer with other-type constant" )
238
+ {
239
+ const auto result = expr_initializer (
240
+ input, test.loc , test.ns , from_integer (1 , signedbv_typet{8 }));
241
+ REQUIRE (result.has_value ());
242
+ const auto expected =
243
+ typecast_exprt{from_integer (1 , signedbv_typet{8 }), bool_typet{}};
244
+ REQUIRE (result.value () == expected);
245
+ }
246
+ SECTION (" expr_initializer with non-constant expr" )
247
+ {
248
+ const auto result = expr_initializer (
249
+ input, test.loc , test.ns , or_exprt{true_exprt (), true_exprt{}});
250
+ REQUIRE (result.has_value ());
251
+ const auto expected = or_exprt{true_exprt{}, true_exprt{}};
252
+ REQUIRE (result.value () == expected);
253
+ }
79
254
}
80
255
81
- TEST_CASE (" nondet_initializer signed_bv" , " [core][util][expr_initializer]" )
256
+ TEST_CASE (
257
+ " nondet_initializer 8-bit signed_bv" ,
258
+ " [core][util][expr_initializer]" )
82
259
{
83
260
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);
261
+ const std::size_t input_type_size = 8 ;
262
+ typet input_type = signedbv_typet{input_type_size};
263
+ SECTION (" nondet_initializer" )
264
+ {
265
+ const auto result = nondet_initializer (input_type, test.loc , test.ns );
266
+ REQUIRE (result.has_value ());
267
+ const auto expected =
268
+ side_effect_expr_nondett{signedbv_typet{input_type_size}, test.loc };
269
+ REQUIRE (result.value () == expected);
270
+ }
271
+ SECTION (" zero_initializer" )
272
+ {
273
+ const auto result = zero_initializer (input_type, test.loc , test.ns );
274
+ REQUIRE (result.has_value ());
275
+ const auto expected = from_integer (0 , signedbv_typet{input_type_size});
276
+ REQUIRE (result.value () == expected);
277
+ }
278
+ SECTION (" expr_initializer calls duplicate_per_byte" )
279
+ {
280
+ // TODO: duplicate_per_byte is tested separately. Here we should check that
281
+ // expr_initializer calls duplicate_per_byte.
282
+ }
89
283
}
90
284
91
285
TEST_CASE (" nondet_initializer c_enum" , " [core][util][expr_initializer]" )
0 commit comments