Skip to content

Commit ba8b958

Browse files
thk123Matthias Güdemann
thk123
authored and
Matthias Güdemann
committed
Adding tests for static lambdas
1 parent ebdcfb1 commit ba8b958

14 files changed

+354
-0
lines changed
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+
}
Binary file not shown.
Binary file not shown.
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+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public class StaticLambdas {
2+
3+
static int staticPrimitive;
4+
static Object staticReference;
5+
static DummyGeneric<Integer> staticSpecalisedGeneric;
6+
7+
static SimpleLambda simpleLambda = () -> { /*NOP*/ };
8+
static ParameterLambda paramLambda = (int primitive, Object reference, DummyGeneric<Integer> specalisedGeneric) -> {};
9+
static ArrayParameterLambda arrayParamLambda = (int[] primitive, Object[] reference, DummyGeneric<Integer>[] specalisedGeneric) -> {};
10+
static ReturningLambdaPrimitive returnPrimitiveLambda = () -> { return 1; };
11+
static ReturningLambdaReference returnReferenceLambda = () -> { return null; };
12+
static ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambda = () -> { return null; };
13+
static ReturningLambdaPrimitiveArray returnPrimitiveArrayLambda = () -> { return null; };
14+
static ReturningLambdaReferenceArray returnReferenceArrayLambda = () -> { return null; };
15+
static ReturningLambdaSpecalisedGenericArray returningSpecalisedGenericArrayLambda = () -> { return null; };
16+
17+
static ReturningLambdaPrimitive returnPrimitiveLambdaCapture = () -> { return staticPrimitive; };
18+
static ReturningLambdaReference returnReferenceLambdaCapture = () -> { return staticReference; };
19+
static ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambdaCapture = () -> { return staticSpecalisedGeneric; };
20+
21+
22+
public static void testMethod() {
23+
simpleLambda.Execute();
24+
paramLambda.Execute(4, null, null);
25+
arrayParamLambda.Execute(null, null, null);
26+
returnPrimitiveLambda.Execute();
27+
returnReferenceLambda.Execute();
28+
returningSpecalisedGenericLambda.Execute();
29+
returnPrimitiveArrayLambda.Execute();
30+
returnReferenceArrayLambda.Execute();
31+
returningSpecalisedGenericArrayLambda.Execute();
32+
33+
returnPrimitiveLambdaCapture.Execute();
34+
returnReferenceLambdaCapture.Execute();
35+
returningSpecalisedGenericLambdaCapture.Execute();
36+
}
37+
}

0 commit comments

Comments
 (0)