Skip to content

Commit ba8b958

Browse files
thk123Matthias Güdemann
authored andcommitted
Adding tests for static lambdas
1 parent ebdcfb1 commit ba8b958

14 files changed

+354
-0
lines changed
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for parsing generic classes
4+
5+
Author: DiffBlue Limited. All rights reserved.
6+
7+
\*******************************************************************/
8+
9+
#include <algorithm>
10+
#include <util/message.h>
11+
#include <util/config.h>
12+
13+
#include <testing-utils/require_parse_tree.h>
14+
15+
#include <testing-utils/catch.hpp>
16+
#include <java_bytecode/java_bytecode_parser.h>
17+
18+
#include <java_bytecode/java_bytecode_parse_tree.h>
19+
#include <java_bytecode/java_types.h>
20+
21+
typedef java_bytecode_parse_treet::classt::lambda_method_handlet
22+
lambda_method_handlet;
23+
24+
SCENARIO(
25+
"lambda_method_handle_map with static lambdas",
26+
"[core][java_bytecode][java_bytecode_parse_lambda_method_handle]")
27+
{
28+
null_message_handlert message_handler;
29+
GIVEN("A class with a static lambda variables")
30+
{
31+
java_bytecode_parse_treet parse_tree;
32+
java_bytecode_parse(
33+
"./java_bytecode/java_bytecode_parser/lambda_examples/"
34+
"StaticLambdas.class",
35+
parse_tree,
36+
message_handler);
37+
WHEN("Parsing that class")
38+
{
39+
REQUIRE(parse_tree.loading_successful);
40+
const java_bytecode_parse_treet::classt parsed_class =
41+
parse_tree.parsed_class;
42+
REQUIRE(parsed_class.attribute_bootstrapmethods_read);
43+
REQUIRE(parsed_class.lambda_method_handle_map.size() == 12);
44+
45+
// Simple lambdas
46+
THEN(
47+
"There should be an entry for the lambda that has no parameters or "
48+
"returns and the method it references should have an appropriate "
49+
"descriptor")
50+
{
51+
const lambda_method_handlet &lambda_entry =
52+
require_parse_tree::require_lambda_entry_for_descriptor(
53+
parsed_class, "()V");
54+
55+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
56+
57+
const auto lambda_method =
58+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
59+
REQUIRE(id2string(lambda_method.descriptor) == "()V");
60+
}
61+
62+
// Parameter lambdas
63+
THEN(
64+
"There should be an entry for the lambda that takes parameters and the "
65+
"method it references should have an appropriate descriptor")
66+
{
67+
std::string descriptor = "(ILjava/lang/Object;LDummyGeneric;)V";
68+
const lambda_method_handlet &lambda_entry =
69+
require_parse_tree::require_lambda_entry_for_descriptor(
70+
parsed_class, descriptor);
71+
72+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
73+
74+
const auto lambda_method =
75+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
76+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
77+
}
78+
THEN(
79+
"There should be an entry for the lambda that takes array parameters "
80+
"and the method it references should have an appropriate descriptor")
81+
{
82+
std::string descriptor = "([I[Ljava/lang/Object;[LDummyGeneric;)V";
83+
const lambda_method_handlet &lambda_entry =
84+
require_parse_tree::require_lambda_entry_for_descriptor(
85+
parsed_class, descriptor);
86+
87+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
88+
89+
const auto lambda_method =
90+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
91+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
92+
}
93+
94+
// Return lambdas
95+
THEN(
96+
"There should be an entry for the lambda that returns a primitive and "
97+
"the method it references should have an appropriate descriptor")
98+
{
99+
std::string descriptor = "()I";
100+
const lambda_method_handlet &lambda_entry =
101+
require_parse_tree::require_lambda_entry_for_descriptor(
102+
parsed_class, descriptor);
103+
104+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
105+
106+
const auto lambda_method =
107+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
108+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
109+
}
110+
THEN(
111+
"There should be an entry for the lambda that returns a reference type "
112+
"and the method it references should have an appropriate descriptor")
113+
{
114+
std::string descriptor = "()Ljava/lang/Object;";
115+
const lambda_method_handlet &lambda_entry =
116+
require_parse_tree::require_lambda_entry_for_descriptor(
117+
parsed_class, descriptor);
118+
119+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
120+
121+
const auto lambda_method =
122+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
123+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
124+
}
125+
THEN(
126+
"There should be an entry for the lambda that returns a specialised "
127+
"generic type and the method it references should have an appropriate "
128+
"descriptor")
129+
{
130+
std::string descriptor = "()LDummyGeneric;";
131+
const lambda_method_handlet &lambda_entry =
132+
require_parse_tree::require_lambda_entry_for_descriptor(
133+
parsed_class, descriptor);
134+
135+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
136+
137+
const auto lambda_method =
138+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
139+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
140+
}
141+
142+
// Array returning lambdas
143+
THEN(
144+
"There should be an entry for the lambda that returns an array of "
145+
"primitives and the method it references should have an appropriate "
146+
"descriptor")
147+
{
148+
std::string descriptor = "()[I";
149+
const lambda_method_handlet &lambda_entry =
150+
require_parse_tree::require_lambda_entry_for_descriptor(
151+
parsed_class, descriptor);
152+
153+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
154+
155+
const auto lambda_method =
156+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
157+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
158+
}
159+
THEN(
160+
"There should be an entry for the lambda that returns an array of "
161+
"reference types and the method it references should have an "
162+
"appropriate descriptor")
163+
{
164+
std::string descriptor = "()[Ljava/lang/Object;";
165+
const lambda_method_handlet &lambda_entry =
166+
require_parse_tree::require_lambda_entry_for_descriptor(
167+
parsed_class, descriptor);
168+
169+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
170+
171+
const auto lambda_method =
172+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
173+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
174+
}
175+
THEN(
176+
"There should be an entry for the lambda that returns an array of "
177+
"specialised generic types and the method it references should have an "
178+
"appropriate descriptor")
179+
{
180+
std::string descriptor = "()[LDummyGeneric;";
181+
const lambda_method_handlet &lambda_entry =
182+
require_parse_tree::require_lambda_entry_for_descriptor(
183+
parsed_class, descriptor);
184+
185+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
186+
187+
const auto lambda_method =
188+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
189+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
190+
}
191+
192+
// Capturing lamdbas
193+
THEN(
194+
"There should be an entry for the lambda that returns a primitive and "
195+
"the method it references should have an appropriate descriptor")
196+
{
197+
std::string descriptor = "()I";
198+
const lambda_method_handlet &lambda_entry =
199+
require_parse_tree::require_lambda_entry_for_descriptor(
200+
parsed_class, descriptor, 1);
201+
202+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
203+
204+
const auto lambda_method =
205+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
206+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
207+
208+
const typet primitive_type = java_int_type();
209+
210+
fieldref_exprt fieldref{
211+
primitive_type, "staticPrimitive", "java::StaticLambdas"};
212+
213+
std::vector<require_parse_tree::expected_instructiont>
214+
expected_instructions{{"getstatic", {fieldref}}, {"ireturn", {}}};
215+
216+
require_parse_tree::require_instructions_match_expectation(
217+
expected_instructions, lambda_method.instructions);
218+
}
219+
THEN(
220+
"There should be an entry for the lambda that returns a reference type "
221+
"and the method it references should have an appropriate descriptor")
222+
{
223+
std::string descriptor = "()Ljava/lang/Object;";
224+
const lambda_method_handlet &lambda_entry =
225+
require_parse_tree::require_lambda_entry_for_descriptor(
226+
parsed_class, descriptor, 1);
227+
228+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
229+
230+
const auto lambda_method =
231+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
232+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
233+
234+
const reference_typet dummy_generic_reference_type =
235+
java_reference_type(symbol_typet{"java::java.lang.Object"});
236+
237+
fieldref_exprt fieldref{dummy_generic_reference_type,
238+
"staticReference",
239+
"java::StaticLambdas"};
240+
241+
std::vector<require_parse_tree::expected_instructiont>
242+
expected_instructions{{"getstatic", {fieldref}}, {"areturn", {}}};
243+
244+
require_parse_tree::require_instructions_match_expectation(
245+
expected_instructions, lambda_method.instructions);
246+
}
247+
THEN(
248+
"There should be an entry for the lambda that returns a specialised "
249+
"generic type and the method it references should have an appropriate "
250+
"descriptor")
251+
{
252+
std::string descriptor = "()LDummyGeneric;";
253+
const lambda_method_handlet &lambda_entry =
254+
require_parse_tree::require_lambda_entry_for_descriptor(
255+
parsed_class, descriptor, 1);
256+
257+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
258+
259+
const java_bytecode_parse_treet::methodt &lambda_method =
260+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
261+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
262+
263+
const reference_typet dummy_generic_reference_type =
264+
java_reference_type(symbol_typet{"java::DummyGeneric"});
265+
266+
fieldref_exprt fieldref{dummy_generic_reference_type,
267+
"staticSpecalisedGeneric",
268+
"java::StaticLambdas"};
269+
270+
std::vector<require_parse_tree::expected_instructiont>
271+
expected_instructions{{"getstatic", {fieldref}}, {"areturn", {}}};
272+
273+
require_parse_tree::require_instructions_match_expectation(
274+
expected_instructions, lambda_method.instructions);
275+
}
276+
}
277+
}
278+
}
257 Bytes
Binary file not shown.
441 Bytes
Binary file not shown.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
interface SimpleLambda {
2+
public void Execute();
3+
}
4+
5+
interface ParameterLambda {
6+
public void Execute(int primitive, Object reference, DummyGeneric<Integer> specalisedGeneric);
7+
}
8+
9+
interface ArrayParameterLambda {
10+
public void Execute(int[] primitive, Object[] reference, DummyGeneric<Integer>[] specalisedGeneric);
11+
}
12+
13+
interface ReturningLambdaPrimitive {
14+
public int Execute();
15+
}
16+
17+
interface ReturningLambdaReference {
18+
public Object Execute();
19+
}
20+
21+
interface ReturningLambdaSpecalisedGeneric {
22+
public DummyGeneric<Integer> Execute();
23+
}
24+
25+
interface ReturningLambdaPrimitiveArray {
26+
public int[] Execute();
27+
}
28+
29+
interface ReturningLambdaReferenceArray {
30+
public Object[] Execute();
31+
}
32+
33+
interface ReturningLambdaSpecalisedGenericArray {
34+
public DummyGeneric<Integer>[] Execute();
35+
}
36+
37+
class DummyGeneric<T> {
38+
T field;
39+
}
246 Bytes
Binary file not shown.
142 Bytes
Binary file not shown.
148 Bytes
Binary file not shown.
159 Bytes
Binary file not shown.
165 Bytes
Binary file not shown.
223 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)