Skip to content

Commit fefeac2

Browse files
author
Enrico Steffinlongo
committed
Added tests for duplicate_per_byte in the BV case
1 parent 54efb47 commit fefeac2

File tree

1 file changed

+214
-11
lines changed

1 file changed

+214
-11
lines changed

unit/util/expr_initializer.cpp

Lines changed: 214 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
// Author: Diffblue Ltd.
22

33
#include <util/arith_tools.h>
4+
#include <util/bitvector_expr.h>
45
#include <util/bitvector_types.h>
56
#include <util/c_types.h>
7+
#include <util/config.h>
68
#include <util/expr_initializer.h>
79
#include <util/namespace.h>
810
#include <util/std_code.h>
911
#include <util/symbol_table.h>
1012

13+
#include <testing-utils/invariant.h>
1114
#include <testing-utils/use_catch.h>
1215

16+
#include <iomanip>
17+
#include <sstream>
18+
1319
/// Helper struct to hold useful test components.
1420
struct expr_initializer_test_environmentt
1521
{
@@ -19,6 +25,10 @@ struct expr_initializer_test_environmentt
1925

2026
static expr_initializer_test_environmentt make()
2127
{
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();
2232
return {};
2333
}
2434

@@ -68,24 +78,217 @@ create_tag_populate_env(const typet &type, symbol_tablet &symbol_table)
6878
UNREACHABLE;
6979
}
7080

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(
118+
"Condition: (init_type_as_bitvector && "
119+
"init_type_as_bitvector->get_width() <= config.ansi_c.char_width) || "
120+
"init_byte_expr.type().id() == ID_bool"));
121+
}
122+
123+
SECTION(
124+
"duplicate_per_byte fails when init type is a bitvector larger than "
125+
"char_width bits")
126+
{
127+
const cbmc_invariants_should_throwt invariants_throw;
128+
129+
REQUIRE_THROWS_MATCHES(
130+
duplicate_per_byte(from_integer(0, unsignedbv_typet{10}), input_type),
131+
invariant_failedt,
132+
invariant_failure_containing(
133+
"init_type_as_bitvector->get_width() <= config.ansi_c.char_width"));
134+
}
135+
}
136+
137+
std::string to_hex(unsigned int value)
138+
{
139+
std::stringstream ss;
140+
ss << "0x" << std::hex << value;
141+
return ss.str();
142+
}
143+
144+
TEST_CASE(
145+
"duplicate_per_byte on unsigned_bv with constant",
146+
"[core][util][duplicate_per_byte]")
147+
{
148+
auto test = expr_initializer_test_environmentt::make();
149+
// elements are init_expr_value, init_expr_size, output_expected_value, output_size
150+
using rowt = std::tuple<std::size_t, unsigned int, std::size_t, unsigned int>;
151+
unsigned int init_expr_value, output_expected_value;
152+
std::size_t output_size, init_expr_size;
153+
std::tie(
154+
init_expr_value, init_expr_size, output_expected_value, output_size) =
155+
GENERATE(
156+
rowt{0xFF, 8, 0xFF, 8}, // same-type constant
157+
rowt{0x2, 2, 0x02, 8}, // smaller-type constant gets promoted
158+
rowt{0x11, 5, 0x11, 5}, // same-type constant
159+
rowt{0x21, 8, 0x01, 5}, // bigger-type constant gets truncated
160+
rowt{0x2, 3, 0x02, 5}, // smaller-type constant gets promoted
161+
rowt{0xAB, 8, 0xABAB, 16}, // smaller-type constant gets replicated
162+
rowt{0xAB, 8, 0xBABAB, 20} // smaller-type constant gets replicated
163+
);
164+
SECTION(
165+
"Testing with output size " + std::to_string(output_size) + " init value " +
166+
to_hex(init_expr_value) + " of size " + std::to_string(init_expr_size))
167+
{
168+
typet output_type = unsignedbv_typet{output_size};
169+
const auto result = duplicate_per_byte(
170+
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
171+
output_type);
172+
const auto expected =
173+
from_integer(output_expected_value, unsignedbv_typet{output_size});
174+
REQUIRE(result == expected);
175+
176+
// Check that signed-bv values are replicated including the sign bit.
177+
const auto result_with_signed_init_type = duplicate_per_byte(
178+
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
179+
output_type);
180+
REQUIRE(result_with_signed_init_type == result);
181+
}
182+
}
183+
184+
TEST_CASE(
185+
"duplicate_per_byte on unsigned_bv with non-constant expr",
186+
"[core][util][duplicate_per_byte]")
187+
{
188+
auto test = expr_initializer_test_environmentt::make();
189+
// elements are init_expr_size, output_size, replication_count
190+
using rowt = std::tuple<std::size_t, std::size_t, std::size_t>;
191+
std::size_t init_expr_size, output_size, replication_count;
192+
std::tie(init_expr_size, output_size, replication_count) = GENERATE(
193+
rowt{8, 8, 1}, // same-type expr no-cast
194+
rowt{2, 2, 1}, // same-type expr no-cast
195+
rowt{3, 8, 1}, // smaller-type gets promoted
196+
rowt{8, 2, 1}, // bigger type gets truncated
197+
rowt{8, 16, 2}, // replicated twice
198+
rowt{8, 20, 3}); // replicated three times and truncated
199+
SECTION(
200+
"Testing with output size " + std::to_string(output_size) + " init size " +
201+
std::to_string(init_expr_size))
202+
{
203+
typet output_type = signedbv_typet{output_size};
204+
205+
const auto init_expr = plus_exprt{
206+
from_integer(1, unsignedbv_typet{init_expr_size}),
207+
from_integer(2, unsignedbv_typet{init_expr_size})};
208+
const auto result = duplicate_per_byte(init_expr, output_type);
209+
210+
const auto casted_init_expr =
211+
typecast_exprt::conditional_cast(init_expr, output_type);
212+
const auto expected =
213+
replicate_expression(casted_init_expr, output_type, replication_count);
214+
215+
REQUIRE(result == expected);
216+
}
217+
}
218+
219+
TEST_CASE("expr_initializer boolean", "[core][util][expr_initializer]")
72220
{
73221
auto test = expr_initializer_test_environmentt::make();
74222
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);
223+
SECTION("nondet_initializer")
224+
{
225+
const auto result = nondet_initializer(input, test.loc, test.ns);
226+
REQUIRE(result.has_value());
227+
const auto expected = side_effect_expr_nondett{bool_typet{}, test.loc};
228+
REQUIRE(result.value() == expected);
229+
}
230+
SECTION("zero_initializer")
231+
{
232+
const auto result = zero_initializer(input, test.loc, test.ns);
233+
REQUIRE(result.has_value());
234+
const auto expected = from_integer(0, bool_typet());
235+
;
236+
REQUIRE(result.value() == expected);
237+
}
238+
SECTION("expr_initializer with same-type constant")
239+
{
240+
const auto result =
241+
expr_initializer(input, test.loc, test.ns, true_exprt{});
242+
REQUIRE(result.has_value());
243+
const auto expected = true_exprt{};
244+
REQUIRE(result.value() == expected);
245+
}
246+
SECTION("expr_initializer with other-type constant")
247+
{
248+
const auto result = expr_initializer(
249+
input, test.loc, test.ns, from_integer(1, signedbv_typet{8}));
250+
REQUIRE(result.has_value());
251+
const auto expected =
252+
typecast_exprt{from_integer(1, signedbv_typet{8}), bool_typet{}};
253+
REQUIRE(result.value() == expected);
254+
}
255+
SECTION("expr_initializer with non-constant expr")
256+
{
257+
const auto result = expr_initializer(
258+
input, test.loc, test.ns, or_exprt{true_exprt(), true_exprt{}});
259+
REQUIRE(result.has_value());
260+
const auto expected = or_exprt{true_exprt{}, true_exprt{}};
261+
REQUIRE(result.value() == expected);
262+
}
79263
}
80264

81-
TEST_CASE("nondet_initializer signed_bv", "[core][util][expr_initializer]")
265+
TEST_CASE(
266+
"nondet_initializer 8-bit signed_bv",
267+
"[core][util][expr_initializer]")
82268
{
83269
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);
270+
const std::size_t input_type_size = 8;
271+
typet input_type = signedbv_typet{input_type_size};
272+
SECTION("nondet_initializer")
273+
{
274+
const auto result = nondet_initializer(input_type, test.loc, test.ns);
275+
REQUIRE(result.has_value());
276+
const auto expected =
277+
side_effect_expr_nondett{signedbv_typet{input_type_size}, test.loc};
278+
REQUIRE(result.value() == expected);
279+
}
280+
SECTION("zero_initializer")
281+
{
282+
const auto result = zero_initializer(input_type, test.loc, test.ns);
283+
REQUIRE(result.has_value());
284+
const auto expected = from_integer(0, signedbv_typet{input_type_size});
285+
REQUIRE(result.value() == expected);
286+
}
287+
SECTION("expr_initializer calls duplicate_per_byte")
288+
{
289+
// TODO: duplicate_per_byte is tested separately. Here we should check that
290+
// expr_initializer calls duplicate_per_byte.
291+
}
89292
}
90293

91294
TEST_CASE("nondet_initializer c_enum", "[core][util][expr_initializer]")

0 commit comments

Comments
 (0)