blob: df6af498ebc4f8f6e8459e3c6352f203c7cd651e [file] [log] [blame]
Clément Béra7fa8a502024-11-27 08:04:12 +01001// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5package backport;
6
7import com.android.tools.r8.TestBase;
8import com.android.tools.r8.TestParameters;
9import com.android.tools.r8.TestRuntime.CfVm;
10import com.android.tools.r8.desugar.backports.AbstractBackportTest;
11import com.android.tools.r8.desugar.backports.IgnoreInvokes;
12import com.android.tools.r8.utils.AndroidApiLevel;
13import java.util.AbstractMap;
14import java.util.Map;
15import org.hamcrest.CoreMatchers;
16import org.junit.Test;
17import org.junit.runner.RunWith;
18import org.junit.runners.Parameterized;
19import org.junit.runners.Parameterized.Parameters;
20
21@RunWith(Parameterized.class)
22public class MapBackportJava9Test extends AbstractBackportTest {
23 @Parameters(name = "{0}")
24 public static Iterable<?> data() {
25 return TestBase.getTestParameters()
26 .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
27 .withDexRuntimes()
28 .withAllApiLevelsAlsoForCf()
29 .build();
30 }
31
32 public MapBackportJava9Test(TestParameters parameters) {
33 super(parameters, Map.class, MapBackportJava9Main.class);
34 // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
35 // an actual API level, migrate these tests to MapBackportTest.
36
37 // Available since API 1 and used to test created maps.
38 ignoreInvokes("entrySet");
39 ignoreInvokes("get");
40 ignoreInvokes("put");
41 ignoreInvokes("size");
42
43 // Map.entry, Map.of and Map.ofEntries added in API 30.
44 registerTarget(AndroidApiLevel.R, 29);
45 }
46
47 @Test
48 public void desugaringApiLevelR() throws Exception {
49 // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
50 // This has now been checked with S, when R testing is added check and remove this.
51 if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
52 testForD8()
53 .setMinApi(AndroidApiLevel.R)
54 .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
55 .addProgramClasses(MapBackportJava9Main.class)
56 .setIncludeClassesChecksum(true)
57 .compile()
58 .run(parameters.getRuntime(), MapBackportJava9Main.class)
59 .assertFailureWithErrorThatMatches(
60 CoreMatchers.containsString("java.lang.NoSuchMethodError"));
61 }
62 }
63
64 public static class MapBackportJava9Main {
65
66 public static void main(String[] args) {
67 testOf0();
68 testOf1();
69 testOf2();
70 testOf10();
71 testOfEntries();
72 testEntry();
73 }
74
75 private static void testOf0() {
76 Map<Object, Object> ofObject = Map.of();
77 assertEquals(0, ofObject.size());
78 assertEquals(null, ofObject.get(new Object()));
79 assertMutationNotAllowed(ofObject);
80
81 Map<Integer, Integer> ofInteger = Map.of();
82 assertEquals(0, ofInteger.size());
83 assertEquals(null, ofInteger.get(0));
84 }
85
86 private static void testOf1() {
87 Object objectKey0 = new Object();
88 Object objectValue0 = new Object();
89 Map<Object, Object> ofObject = Map.of(objectKey0, objectValue0);
90 assertEquals(1, ofObject.size());
91 assertSame(objectValue0, ofObject.get(objectKey0));
92 assertEquals(null, ofObject.get(new Object()));
93 assertMutationNotAllowed(ofObject);
94
95 Map<Integer, Integer> ofInteger = Map.of(0, 0);
96 assertEquals(1, ofInteger.size());
97 assertEquals(0, ofInteger.get(0));
98 assertEquals(null, ofInteger.get(1));
99
100 try {
101 Map.of((Object) null, 1);
102 throw new AssertionError();
103 } catch (NullPointerException expected) {
104 }
105 try {
106 Map.of(1, (Object) null);
107 throw new AssertionError();
108 } catch (NullPointerException expected) {
109 }
110 }
111
112 private static void testOf2() {
113 Object objectKey0 = new Object();
114 Object objectValue0 = new Object();
115 Object objectKey1 = new Object();
116 Object objectValue1 = new Object();
117 Map<Object, Object> ofObject = Map.of(objectKey0, objectValue0, objectKey1, objectValue1);
118 assertEquals(2, ofObject.size());
119 assertSame(objectValue0, ofObject.get(objectKey0));
120 assertSame(objectValue1, ofObject.get(objectKey1));
121 assertEquals(null, ofObject.get(new Object()));
122 assertMutationNotAllowed(ofObject);
123
124 Map<Integer, Integer> ofInteger = Map.of(0, 0, 1, 1);
125 assertEquals(2, ofInteger.size());
126 assertEquals(0, ofInteger.get(0));
127 assertEquals(1, ofInteger.get(1));
128 assertEquals(null, ofInteger.get(3));
129
130 Map<Object, Object> ofMixed = Map.of(objectKey0, 0, objectKey1, 1);
131 assertEquals(2, ofMixed.size());
132 assertEquals(0, ofMixed.get(objectKey0));
133 assertEquals(1, ofMixed.get(objectKey1));
134 assertEquals(null, ofMixed.get(new Object()));
135
136 try {
137 Map.of(1, 1, null, 2);
138 throw new AssertionError();
139 } catch (NullPointerException expected) {
140 }
141 try {
142 Map.of(1, 1, 2, null);
143 throw new AssertionError();
144 } catch (NullPointerException expected) {
145 }
146
147 try {
148 Map.of(1, 1, 1, 2);
149 throw new AssertionError();
150 } catch (IllegalArgumentException expected) {
151 assertEquals("duplicate key: 1", expected.getMessage());
152 }
153 }
154
155 private static void testOf10() {
156 Object objectKey0 = new Object();
157 Object objectValue0 = new Object();
158 Object objectKey6 = new Object();
159 Object objectValue6 = new Object();
160 Object objectKey9 = new Object();
161 Object objectValue9 = new Object();
162 Map<Object, Object> ofObject =
163 Map.of(
164 objectKey0,
165 objectValue0,
166 new Object(),
167 new Object(),
168 new Object(),
169 new Object(),
170 new Object(),
171 new Object(),
172 new Object(),
173 new Object(),
174 new Object(),
175 new Object(),
176 objectKey6,
177 objectValue6,
178 new Object(),
179 new Object(),
180 new Object(),
181 new Object(),
182 objectKey9,
183 objectValue9);
184 assertEquals(10, ofObject.size());
185 assertSame(objectValue0, ofObject.get(objectKey0));
186 assertSame(objectValue6, ofObject.get(objectKey6));
187 assertSame(objectValue9, ofObject.get(objectKey9));
188 assertEquals(null, ofObject.get(new Object()));
189 assertMutationNotAllowed(ofObject);
190
191 Map<Integer, Integer> ofInteger =
192 Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9);
193 assertEquals(10, ofInteger.size());
194 assertEquals(0, ofInteger.get(0));
195 assertEquals(6, ofInteger.get(6));
196 assertEquals(9, ofInteger.get(9));
197 assertEquals(null, ofInteger.get(10));
198
199 Map<Object, Object> ofMixed =
200 Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, objectKey9, objectValue9);
201 assertEquals(10, ofMixed.size());
202 assertEquals(0, ofMixed.get(0));
203 assertEquals(6, ofMixed.get(6));
204 assertSame(objectValue9, ofMixed.get(objectKey9));
205 assertEquals(null, ofMixed.get(9));
206
207 try {
208 Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, null, objectValue9);
209 throw new AssertionError();
210 } catch (NullPointerException expected) {
211 }
212 try {
213 Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, objectKey9, null);
214 throw new AssertionError();
215 } catch (NullPointerException expected) {
216 }
217
218 try {
219 Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 0, 9);
220 throw new AssertionError();
221 } catch (IllegalArgumentException expected) {
222 assertEquals("duplicate key: 0", expected.getMessage());
223 }
224 }
225
226 private static void testOfEntries() {
227 Object objectKey0 = new Object();
228 Object objectValue0 = new Object();
229 Object objectKey1 = new Object();
230 Object objectValue1 = new Object();
231 Map<Object, Object> ofObject =
232 Map.ofEntries(
233 new AbstractMap.SimpleEntry<>(objectKey0, objectValue0),
234 new AbstractMap.SimpleEntry<>(objectKey1, objectValue1));
235 assertEquals(2, ofObject.size());
236 assertSame(objectValue0, ofObject.get(objectKey0));
237 assertSame(objectValue1, ofObject.get(objectKey1));
238 assertEquals(null, ofObject.get(new Object()));
239 assertMutationNotAllowed(ofObject);
240
241 Map<Integer, Integer> ofInteger =
242 Map.ofEntries(new AbstractMap.SimpleEntry<>(0, 0), new AbstractMap.SimpleEntry<>(1, 1));
243 assertEquals(2, ofInteger.size());
244 assertEquals(0, ofInteger.get(0));
245 assertEquals(1, ofInteger.get(1));
246 assertEquals(null, ofInteger.get(2));
247
248 Map<Object, Object> ofMixed =
249 Map.ofEntries(
250 new AbstractMap.SimpleEntry<>(0, objectValue0),
251 new AbstractMap.SimpleEntry<>(objectKey1, 1));
252 assertEquals(2, ofMixed.size());
253 assertSame(objectValue0, ofMixed.get(0));
254 assertEquals(1, ofMixed.get(objectKey1));
255 assertEquals(null, ofMixed.get(1));
256
257 // Ensure the supplied entry objects are not used directly since they are mutable.
258 Map.Entry<Object, Object> mutableEntry =
259 new AbstractMap.SimpleEntry<>(objectKey0, objectValue0);
260 Map<Object, Object> ofMutableEntry = Map.ofEntries(mutableEntry);
261 mutableEntry.setValue(objectValue1);
262 assertSame(objectValue0, ofMutableEntry.get(objectKey0));
263
264 // Ensure the supplied mutable array is not used directly since it is mutable.
265 @SuppressWarnings("unchecked")
266 Map.Entry<Object, Object>[] mutableArray =
267 new Map.Entry[] {new AbstractMap.SimpleEntry<>(objectKey0, objectValue0)};
268 Map<Object, Object> ofArray = Map.ofEntries(mutableArray);
269 mutableArray[0] = new AbstractMap.SimpleEntry<>(objectKey1, objectValue1);
270 assertSame(objectValue0, ofArray.get(objectKey0));
271 assertEquals(null, ofArray.get(objectKey1));
272
273 try {
274 Map.ofEntries(new AbstractMap.SimpleEntry<Object, Integer>(null, 1));
275 throw new AssertionError();
276 } catch (NullPointerException expected) {
277 }
278 try {
279 Map.ofEntries(new AbstractMap.SimpleEntry<Object, Integer>(1, null));
280 throw new AssertionError();
281 } catch (NullPointerException expected) {
282 }
283
284 try {
285 Map.ofEntries(
286 new AbstractMap.SimpleEntry<>(0, objectValue0),
287 new AbstractMap.SimpleEntry<>(0, objectValue1));
288 throw new AssertionError();
289 } catch (IllegalArgumentException expected) {
290 assertEquals("duplicate key: 0", expected.getMessage());
291 }
292 }
293
294 private static void testEntry() {
295 Object key = new Object();
296 Object value = new Object();
297 Map.Entry<Object, Object> entry = Map.entry(key, value);
298 assertSame(key, entry.getKey());
299 assertSame(value, entry.getValue());
300
301 try {
302 entry.setValue(new Object());
303 throw new AssertionError();
304 } catch (UnsupportedOperationException expected) {
305 }
306
307 try {
308 Map.entry(null, value);
309 throw new AssertionError();
310 } catch (NullPointerException expected) {
311 }
312 try {
313 Map.entry(key, null);
314 throw new AssertionError();
315 } catch (NullPointerException expected) {
316 }
317 }
318
319 private static void assertMutationNotAllowed(Map<Object, Object> ofObject) {
320 try {
321 ofObject.put(new Object(), new Object());
322 throw new AssertionError();
323 } catch (UnsupportedOperationException expected) {
324 }
325 for (Map.Entry<Object, Object> entry : ofObject.entrySet()) {
326 try {
327 entry.setValue(new Object());
328 throw new AssertionError();
329 } catch (UnsupportedOperationException expected) {
330 }
331 }
332 }
333
334 private static void assertSame(Object expected, Object actual) {
335 if (expected != actual) {
336 throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
337 }
338 }
339
340 private static void assertEquals(Object expected, Object actual) {
341 if (expected != actual && !expected.equals(actual)) {
342 throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
343 }
344 }
345 }
346}