Skip to content

Commit a86049c

Browse files
author
Enrico Steffinlongo
committed
Added tests for duplicate_per_byte in the BV case
1 parent 73df636 commit a86049c

File tree

1 file changed

+206
-11
lines changed

1 file changed

+206
-11
lines changed

unit/util/expr_initializer.cpp

Lines changed: 206 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,209 @@ 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+
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]")
72212
{
73213
auto test = expr_initializer_test_environmentt::make();
74214
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+
}
79255
}
80256

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]")
82260
{
83261
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+
}
89284
}
90285

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

0 commit comments

Comments
 (0)