Skip to content

Commit 62675bb

Browse files
author
Thomas Kiley
authored
Merge pull request diffblue#1494 from thk123/tests/adding-generic-unit-tests
Readding generic unit tests
2 parents 5191170 + 69d67ab commit 62675bb

File tree

2 files changed

+329
-0
lines changed

2 files changed

+329
-0
lines changed

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SRC += unit_tests.cpp \
1717
analyses/does_remove_const/does_type_preserve_const_correctness.cpp \
1818
analyses/does_remove_const/is_type_at_least_as_const_as.cpp \
1919
java_bytecode/java_bytecode_convert_class/convert_abstract_class.cpp \
20+
java_bytecode/java_bytecode_parse_generics/parse_generic_class.cpp \
2021
miniBDD_new.cpp \
2122
java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp \
2223
java_bytecode/java_utils_test.cpp \
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for parsing generic classes
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+
12+
#include <istream>
13+
#include <memory>
14+
15+
#include <util/config.h>
16+
#include <util/language.h>
17+
#include <util/message.h>
18+
#include <java_bytecode/java_bytecode_language.h>
19+
20+
SCENARIO(
21+
"java_bytecode_parse_generics",
22+
"[core][java_bytecode][java_bytecode_parse_generics]")
23+
{
24+
const symbol_tablet &new_symbol_table=
25+
load_java_class("generics", "./java_bytecode/java_bytecode_parse_generics");
26+
27+
GIVEN("Some class files with Generics")
28+
{
29+
WHEN("Parsing a class with type variable")
30+
{
31+
REQUIRE(new_symbol_table.has_symbol("java::generics$element"));
32+
THEN("The symbol type should be generic")
33+
{
34+
const symbolt &class_symbol=
35+
new_symbol_table.lookup_ref("java::generics$element");
36+
const typet &symbol_type=class_symbol.type;
37+
38+
REQUIRE(symbol_type.id()==ID_struct);
39+
class_typet class_type=to_class_type(symbol_type);
40+
REQUIRE(class_type.is_class());
41+
java_class_typet java_class_type=to_java_class_type(class_type);
42+
REQUIRE(is_java_generics_class_type(java_class_type));
43+
java_generics_class_typet java_generics_class_type=
44+
to_java_generics_class_type(java_class_type);
45+
46+
const struct_union_typet::componentt &elem=
47+
java_generics_class_type.get_component("elem");
48+
const typet &elem_type=java_class_type.component_type("elem");
49+
50+
REQUIRE(is_java_generic_parameter(elem_type));
51+
52+
REQUIRE(java_generics_class_type.generic_types().size()==1);
53+
THEN("Type variable is named 'E'")
54+
{
55+
typet &type_var=java_generics_class_type.generic_types().front();
56+
REQUIRE(is_java_generic_parameter(type_var));
57+
java_generic_parametert generic_type_var=
58+
to_java_generic_parameter(type_var);
59+
REQUIRE(
60+
generic_type_var.type_variable().get_identifier()==
61+
"java::generics$element::E");
62+
typet &sub_type=generic_type_var.subtype();
63+
REQUIRE(sub_type.id()==ID_symbol);
64+
symbol_typet &bound_type=to_symbol_type(sub_type);
65+
REQUIRE(bound_type.get_identifier()=="java::java.lang.Object");
66+
}
67+
}
68+
}
69+
}
70+
71+
GIVEN("Some class files with generic type variable")
72+
{
73+
WHEN("Parsing a class with bounded type variable")
74+
{
75+
REQUIRE(new_symbol_table.has_symbol("java::generics$bound_element"));
76+
THEN("The symbol type should be generic")
77+
{
78+
const symbolt &class_symbol=
79+
new_symbol_table.lookup_ref("java::generics$bound_element");
80+
const typet &symbol_type=class_symbol.type;
81+
82+
REQUIRE(symbol_type.id()==ID_struct);
83+
class_typet class_type=to_class_type(symbol_type);
84+
REQUIRE(class_type.is_class());
85+
java_class_typet java_class_type=to_java_class_type(class_type);
86+
REQUIRE(is_java_generics_class_type(java_class_type));
87+
java_generics_class_typet java_generics_class_type=
88+
to_java_generics_class_type(java_class_type);
89+
REQUIRE(java_generics_class_type.generic_types().size()==1);
90+
typet &type_var=java_generics_class_type.generic_types().front();
91+
REQUIRE(is_java_generic_parameter(type_var));
92+
java_generic_parametert generic_type_var=
93+
to_java_generic_parameter(type_var);
94+
95+
REQUIRE(
96+
generic_type_var.type_variable().get_identifier()==
97+
"java::generics$bound_element::NUM");
98+
REQUIRE(
99+
java_generics_class_type_var(0, java_generics_class_type)==
100+
"java::generics$bound_element::NUM");
101+
THEN("Bound must be Number")
102+
{
103+
typet &sub_type=generic_type_var.subtype();
104+
REQUIRE(sub_type.id()==ID_symbol);
105+
symbol_typet &bound_type=to_symbol_type(sub_type);
106+
REQUIRE(bound_type.get_identifier()=="java::java.lang.Number");
107+
REQUIRE(
108+
to_symbol_type(
109+
java_generics_class_type_bound(0, java_generics_class_type))
110+
.get_identifier()=="java::java.lang.Number");
111+
}
112+
113+
const struct_union_typet::componentt &elem=
114+
java_generics_class_type.get_component("elem");
115+
const typet &elem_type=java_class_type.component_type("elem");
116+
117+
REQUIRE(is_java_generic_parameter(elem_type));
118+
}
119+
}
120+
}
121+
122+
GIVEN("Some class files with generic type variable")
123+
{
124+
WHEN("Parsing a class with bounded type variable")
125+
{
126+
REQUIRE(new_symbol_table.has_symbol("java::generics"));
127+
128+
THEN("The generic fields should be annotated with concrete types")
129+
{
130+
const symbolt &class_symbol=
131+
new_symbol_table.lookup_ref("java::generics");
132+
const typet &symbol_type=class_symbol.type;
133+
134+
REQUIRE(symbol_type.id()==ID_struct);
135+
class_typet class_type=to_class_type(symbol_type);
136+
REQUIRE(class_type.is_class());
137+
java_class_typet java_class_type=to_java_class_type(class_type);
138+
REQUIRE(!is_java_generics_class_type(java_class_type));
139+
140+
const struct_union_typet::componentt &belem=
141+
java_class_type.get_component("belem");
142+
const typet &belem_type=java_class_type.component_type("belem");
143+
144+
REQUIRE(belem_type!=nil_typet());
145+
REQUIRE(is_java_generic_type(belem_type));
146+
THEN("Field has instantiated type variable")
147+
{
148+
const java_generic_typet &container=
149+
to_java_generic_type(belem_type);
150+
151+
const std::vector<java_generic_parametert> &generic_types=
152+
container.generic_type_variables();
153+
REQUIRE(generic_types.size()==1);
154+
155+
const typet& inst_type=java_generic_get_inst_type(0, container);
156+
157+
REQUIRE(inst_type.id()==ID_pointer);
158+
const typet &inst_type_symbol=inst_type.subtype();
159+
REQUIRE(inst_type_symbol.id()==ID_symbol);
160+
REQUIRE(
161+
to_symbol_type(inst_type_symbol).get_identifier()==
162+
"java::java.lang.Integer");
163+
}
164+
}
165+
}
166+
}
167+
168+
GIVEN("Some class files with Generics")
169+
{
170+
WHEN("Methods with generic signatures")
171+
{
172+
REQUIRE(
173+
new_symbol_table
174+
.has_symbol("java::generics$bound_element.f:()Ljava/lang/Number;"));
175+
176+
// TODO: methods should have generic return type (the tests needs to be
177+
// extended), reintroduce when the issue of signature/descriptor for methods is
178+
// resolved
179+
// THEN("The method should have generic return type")
180+
// {
181+
// const symbolt &method_symbol=
182+
// new_symbol_table
183+
// .lookup("java::generics$bound_element.f:()Ljava/lang/Number;")
184+
// .value().get();
185+
// const typet &symbol_type=method_symbol.type;
186+
//
187+
// REQUIRE(symbol_type.id()==ID_code);
188+
//
189+
// const code_typet &code=to_code_type(symbol_type);
190+
// }
191+
192+
REQUIRE(
193+
new_symbol_table
194+
.has_symbol("java::generics$bound_element.g:(Ljava/lang/Number;)V"));
195+
196+
// TODO: methods are not recognized as generic, reintroduce when
197+
// the issue of signature/descriptor for methods is resolved
198+
// THEN("The method should have a generic parameter.")
199+
// {
200+
// const symbolt &method_symbol=
201+
// new_symbol_table
202+
// .lookup("java::generics$bound_element.g:(Ljava/lang/Number;)V");
203+
// const typet &symbol_type=method_symbol.type;
204+
//
205+
// REQUIRE(symbol_type.id()==ID_code);
206+
//
207+
// const code_typet &code=to_code_type(symbol_type);
208+
//
209+
// bool found=false;
210+
// for(const auto &p : code.parameters())
211+
// {
212+
// if(p.get_identifier()==
213+
// "java::generics$bound_element.g:(Ljava/lang/Number;)V::e")
214+
// {
215+
// found=true;
216+
// const typet &t=p.type();
217+
// REQUIRE(is_java_generic_parameter(p.type()));
218+
// const java_generic_parametert &gen_type=
219+
// to_java_generic_parameter(p.type());
220+
// const symbol_typet &type_var=gen_type.type_variable();
221+
// REQUIRE(type_var.get_identifier()==
222+
// "java::generics$bound_element::NUM");
223+
// break;
224+
// }
225+
// }
226+
// REQUIRE(found);
227+
// }
228+
}
229+
}
230+
GIVEN("A class with multiple bounds")
231+
{
232+
THEN("The bounds should be encoded")
233+
{
234+
REQUIRE(
235+
new_symbol_table.has_symbol("java::generics$double_bound_element"));
236+
THEN("The symbol should have a generic parameter")
237+
{
238+
const symbolt &class_symbol=
239+
new_symbol_table.lookup_ref("java::generics$double_bound_element");
240+
const typet &symbol_type=class_symbol.type;
241+
242+
REQUIRE(symbol_type.id()==ID_struct);
243+
class_typet class_type=to_class_type(symbol_type);
244+
REQUIRE(class_type.is_class());
245+
java_class_typet java_class_type=to_java_class_type(class_type);
246+
REQUIRE_FALSE(is_java_generics_class_type(java_class_type));
247+
248+
// TODO (tkiley): Extend this unit test when bounds are correctly
249+
// parsed.
250+
#if 0
251+
java_generics_class_typet java_generics_class_type=
252+
to_java_generics_class_type(java_class_type);
253+
REQUIRE(java_generics_class_type.generic_types().size()==1);
254+
typet &type_var=java_generics_class_type.generic_types().front();
255+
REQUIRE(is_java_generic_parameter(type_var));
256+
java_generic_parametert generic_type_var=
257+
to_java_generic_parameter(type_var);
258+
259+
REQUIRE(
260+
generic_type_var.type_variable().get_identifier()==
261+
"java::generics$double_bound_element::T");
262+
REQUIRE(
263+
java_generics_class_type_var(0, java_generics_class_type)==
264+
"java::generics$double_bound_element::T");
265+
THEN("Bound must be Number and dummyInterface")
266+
{
267+
268+
}
269+
#endif
270+
}
271+
}
272+
}
273+
GIVEN("A class with multiple generic parameters")
274+
{
275+
THEN("Both generic parameters should be encoded")
276+
{
277+
const symbolt &class_symbol=
278+
new_symbol_table.lookup_ref("java::generics$two_elements");
279+
const typet &symbol_type=class_symbol.type;
280+
281+
REQUIRE(symbol_type.id()==ID_struct);
282+
class_typet class_type=to_class_type(symbol_type);
283+
REQUIRE(class_type.is_class());
284+
java_class_typet java_class_type=to_java_class_type(class_type);
285+
REQUIRE(is_java_generics_class_type(java_class_type));
286+
287+
java_generics_class_typet java_generics_class_type=
288+
to_java_generics_class_type(java_class_type);
289+
REQUIRE(java_generics_class_type.generic_types().size()==2);
290+
291+
auto generic_param_iterator=
292+
java_generics_class_type.generic_types().cbegin();
293+
294+
// The first parameter should be called K
295+
{
296+
const typet &first_param=*generic_param_iterator;
297+
REQUIRE(is_java_generic_parameter(first_param));
298+
java_generic_parametert generic_type_var=
299+
to_java_generic_parameter(first_param);
300+
301+
REQUIRE(
302+
generic_type_var.type_variable().get_identifier()==
303+
"java::generics$two_elements::K");
304+
REQUIRE(
305+
java_generics_class_type_var(0, java_generics_class_type)==
306+
"java::generics$two_elements::K");
307+
}
308+
309+
++generic_param_iterator;
310+
311+
312+
// The second parameter should be called V
313+
{
314+
const typet &second_param=*generic_param_iterator;
315+
REQUIRE(is_java_generic_parameter(second_param));
316+
java_generic_parametert generic_type_var=
317+
to_java_generic_parameter(second_param);
318+
319+
REQUIRE(
320+
generic_type_var.type_variable().get_identifier()==
321+
"java::generics$two_elements::V");
322+
REQUIRE(
323+
java_generics_class_type_var(1, java_generics_class_type)==
324+
"java::generics$two_elements::V");
325+
}
326+
}
327+
}
328+
}

0 commit comments

Comments
 (0)