Skip to content

Commit a694533

Browse files
committed
Add unit tests for restrict function pointers feature
1 parent aa4ed95 commit a694533

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ SRC += analyses/ai/ai.cpp \
3333
goto-programs/is_goto_binary.cpp \
3434
goto-programs/label_function_pointer_call_sites.cpp \
3535
goto-programs/osx_fat_reader.cpp \
36+
goto-programs/restrict_function_pointers.cpp \
3637
goto-programs/remove_returns.cpp \
3738
goto-programs/xml_expr.cpp \
3839
goto-symex/apply_condition.cpp \
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*******************************************************************\
2+
3+
Module: Restrict function pointers unit tests
4+
5+
Author: Daniel Poetzl
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/message.h>
10+
#include <testing-utils/use_catch.h>
11+
12+
#include <goto-programs/restrict_function_pointers.h>
13+
14+
#include <json/json_parser.h>
15+
16+
class fp_restrictionst : public function_pointer_restrictionst
17+
{
18+
friend void restriction_parsing_test();
19+
friend void merge_restrictions_test();
20+
};
21+
22+
void restriction_parsing_test()
23+
{
24+
{
25+
const auto res =
26+
fp_restrictionst::parse_function_pointer_restriction("func1/func2");
27+
REQUIRE(res.first == "func1");
28+
REQUIRE(res.second.size() == 1);
29+
REQUIRE(res.second.find("func2") != res.second.end());
30+
}
31+
32+
{
33+
const auto res =
34+
fp_restrictionst::parse_function_pointer_restriction("func1/func2,func3");
35+
REQUIRE(res.first == "func1");
36+
REQUIRE(res.second.size() == 2);
37+
REQUIRE(res.second.find("func2") != res.second.end());
38+
REQUIRE(res.second.find("func3") != res.second.end());
39+
}
40+
41+
REQUIRE_THROWS_AS(
42+
fp_restrictionst::parse_function_pointer_restriction("func"),
43+
invalid_command_line_argument_exceptiont);
44+
45+
REQUIRE_THROWS_AS(
46+
fp_restrictionst::parse_function_pointer_restriction("/func"),
47+
invalid_command_line_argument_exceptiont);
48+
49+
REQUIRE_THROWS_AS(
50+
fp_restrictionst::parse_function_pointer_restriction("func/"),
51+
invalid_command_line_argument_exceptiont);
52+
53+
REQUIRE_THROWS_AS(
54+
fp_restrictionst::parse_function_pointer_restriction("func/,"),
55+
invalid_command_line_argument_exceptiont);
56+
57+
REQUIRE_THROWS_AS(
58+
fp_restrictionst::parse_function_pointer_restriction("func1/func2,"),
59+
invalid_command_line_argument_exceptiont);
60+
61+
REQUIRE_THROWS_AS(
62+
fp_restrictionst::parse_function_pointer_restriction("func1/,func2"),
63+
invalid_command_line_argument_exceptiont);
64+
}
65+
66+
void merge_restrictions_test()
67+
{
68+
fp_restrictionst::restrictionst r1;
69+
r1.emplace("fp1", std::unordered_set<irep_idt>{"func1", "func2"});
70+
r1.emplace("fp2", std::unordered_set<irep_idt>{"func1"});
71+
72+
fp_restrictionst::restrictionst r2;
73+
r2.emplace("fp1", std::unordered_set<irep_idt>{"func1", "func3"});
74+
75+
fp_restrictionst::restrictionst result =
76+
fp_restrictionst::merge_function_pointer_restrictions(r1, r2);
77+
78+
REQUIRE(result.size() == 2);
79+
80+
const auto &fp1_restrictions = result.at("fp1");
81+
REQUIRE(fp1_restrictions.size() == 3);
82+
REQUIRE(fp1_restrictions.count("func1") == 1);
83+
REQUIRE(fp1_restrictions.count("func2") == 1);
84+
REQUIRE(fp1_restrictions.count("func3") == 1);
85+
86+
const auto &fp2_restrictions = result.at("fp2");
87+
REQUIRE(fp2_restrictions.size() == 1);
88+
REQUIRE(fp2_restrictions.count("func1") == 1);
89+
}
90+
91+
TEST_CASE("Restriction parsing", "[core]")
92+
{
93+
restriction_parsing_test();
94+
}
95+
96+
TEST_CASE("Merge function pointer restrictions", "[core]")
97+
{
98+
merge_restrictions_test();
99+
}
100+
101+
TEST_CASE("Json conversion", "[core]")
102+
{
103+
// conversion json1 -> restrictions1 -> json2 -> restrictions2
104+
// then check that restrictions1 == restrictions2
105+
//
106+
// we use json as a starting point as it is easy to write, and we compare the
107+
// restrictions as it is a canonical representation (in contrast, the json
108+
// representation for the same restrictions can differ, due to the array
109+
// elements appearing in different orders)
110+
111+
std::istringstream ss(
112+
"{"
113+
" \"use_f.function_pointer_call.1\": [\"f\", \"g\"],"
114+
" \"use_f.function_pointer_call.2\": [\"h\"]"
115+
"}");
116+
117+
jsont json1;
118+
119+
parse_json(ss, "", null_message_handler, json1);
120+
121+
// json1 -> restrictions1
122+
const auto function_pointer_restrictions1 =
123+
function_pointer_restrictionst::from_json(json1);
124+
125+
const auto &restrictions = function_pointer_restrictions1.restrictions;
126+
127+
REQUIRE(restrictions.size() == 2);
128+
129+
const auto &fp1_restrictions =
130+
restrictions.at("use_f.function_pointer_call.1");
131+
REQUIRE(fp1_restrictions.size() == 2);
132+
REQUIRE(fp1_restrictions.count("f") == 1);
133+
REQUIRE(fp1_restrictions.count("g") == 1);
134+
135+
const auto &fp2_restrictions =
136+
restrictions.at("use_f.function_pointer_call.2");
137+
REQUIRE(fp2_restrictions.size() == 1);
138+
REQUIRE(fp2_restrictions.count("h") == 1);
139+
140+
// restrictions1 -> json2
141+
const auto json2 = function_pointer_restrictions1.to_json();
142+
143+
// json2 -> restrictions2
144+
const auto function_pointer_restrictions2 =
145+
function_pointer_restrictionst::from_json(json2);
146+
147+
REQUIRE(
148+
function_pointer_restrictions1.restrictions ==
149+
function_pointer_restrictions2.restrictions);
150+
}

0 commit comments

Comments
 (0)