Skip to content

Commit 3ff90bc

Browse files
author
Matthias Güdemann
committed
Add unit test
The unit test checks whether the correct function is called. It is therefor more precise than the regression test `virtual10`.
1 parent e67a96e commit 3ff90bc

File tree

9 files changed

+156
-0
lines changed

9 files changed

+156
-0
lines changed

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ SRC += unit_tests.cpp \
4343
util/simplify_expr.cpp \
4444
util/symbol_table.cpp \
4545
catch_example.cpp \
46+
java_bytecode/java_virtual_functions/virtual_functions.cpp \
4647
# Empty last line
4748

4849
INCLUDES= -I ../src/ -I.
104 Bytes
Binary file not shown.
104 Bytes
Binary file not shown.
312 Bytes
Binary file not shown.
364 Bytes
Binary file not shown.
452 Bytes
Binary file not shown.
327 Bytes
Binary file not shown.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
interface A {
2+
public int f();
3+
}
4+
interface B {
5+
public int g();
6+
}
7+
8+
class O {
9+
public String toString() {
10+
return "O";
11+
}
12+
}
13+
14+
class D extends O implements A, B {
15+
public int f() {
16+
return 0;
17+
}
18+
public int g() {
19+
return 1;
20+
}
21+
}
22+
23+
class C extends D {
24+
public String toString() {
25+
return "C";
26+
}
27+
}
28+
29+
class E {
30+
C c;
31+
D d;
32+
String f(Object o) {
33+
return o.toString();
34+
}
35+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for java_types
4+
5+
Author: DiffBlue Limited. All rights reserved.
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
#include <testing-utils/load_java_class.h>
11+
#include <testing-utils/require_goto_statements.h>
12+
13+
#include <goto-programs/goto_convert_functions.h>
14+
#include <goto-programs/remove_virtual_functions.h>
15+
#include <util/config.h>
16+
17+
#include <util/std_expr.h>
18+
19+
void check_function_call(
20+
const equal_exprt &eq_expr,
21+
const irep_idt &class_name,
22+
const irep_idt &function_name,
23+
const goto_programt::targetst &targets)
24+
{
25+
REQUIRE(eq_expr.op0().id() == ID_constant);
26+
REQUIRE(eq_expr.op0().type().id() == ID_string);
27+
REQUIRE(to_constant_expr(eq_expr.op0()).get_value() == class_name);
28+
29+
REQUIRE(targets.size() == 1);
30+
31+
for(const auto &target : targets)
32+
{
33+
REQUIRE(target->type == goto_program_instruction_typet::FUNCTION_CALL);
34+
const code_function_callt call = to_code_function_call(target->code);
35+
REQUIRE(call.function().id() == ID_symbol);
36+
REQUIRE(to_symbol_expr(call.function()).get_identifier() == function_name);
37+
}
38+
}
39+
40+
SCENARIO(
41+
"load class with virtual method call, resolve to all valid calls",
42+
"[core][java_bytecode][virtual_functions]")
43+
{
44+
config.set_arch("none");
45+
GIVEN("A class with a call to java.lang.Object.toString()")
46+
{
47+
const symbol_tablet &symbol_table =
48+
load_java_class("E", "./java_bytecode/java_virtual_functions", "E.f");
49+
50+
const std::string function_name =
51+
"java::E.f:(Ljava/lang/Object;)Ljava/lang/String;";
52+
53+
WHEN("The entry point function is generated")
54+
{
55+
symbol_tablet new_table(symbol_table);
56+
null_message_handlert null_output;
57+
goto_functionst new_goto_functions;
58+
goto_convert(new_table, new_goto_functions, null_output);
59+
remove_virtual_functions(new_table, new_goto_functions);
60+
61+
bool found_function = false;
62+
for(const auto &fun : new_goto_functions.function_map)
63+
{
64+
if(fun.first == function_name)
65+
{
66+
const goto_programt &goto_program = fun.second.body;
67+
found_function = true;
68+
for(const auto &instruction : goto_program.instructions)
69+
{
70+
// There should be two guarded GOTOs with non-constant guards. One
71+
// branching for class C and one for class D or O.
72+
if(instruction.type == goto_program_instruction_typet::GOTO)
73+
{
74+
if(instruction.guard.id() == ID_equal)
75+
{
76+
THEN("Class C should call its specific method")
77+
{
78+
const equal_exprt &eq_expr = to_equal_expr(instruction.guard);
79+
check_function_call(
80+
eq_expr,
81+
"java::C",
82+
"java::C.toString:()Ljava/lang/String;",
83+
instruction.targets);
84+
}
85+
}
86+
87+
else if(instruction.guard.id() == ID_or)
88+
{
89+
THEN("Classes D and O should both call O.toString()")
90+
{
91+
const or_exprt &disjunction = to_or_expr(instruction.guard);
92+
REQUIRE(
93+
(disjunction.op0().id() == ID_equal &&
94+
disjunction.op1().id() == ID_equal));
95+
const equal_exprt &eq_expr0 =
96+
to_equal_expr(disjunction.op0());
97+
const equal_exprt &eq_expr1 =
98+
to_equal_expr(disjunction.op1());
99+
100+
check_function_call(
101+
eq_expr0,
102+
"java::D",
103+
"java::O.toString:()Ljava/lang/String;",
104+
instruction.targets);
105+
check_function_call(
106+
eq_expr1,
107+
"java::O",
108+
"java::O.toString:()Ljava/lang/String;",
109+
instruction.targets);
110+
}
111+
}
112+
}
113+
}
114+
}
115+
}
116+
117+
REQUIRE(found_function);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)