• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Bazel Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 package com.google.devtools.build.android.desugar;
15 
16 import static com.google.common.truth.Truth.assertThat;
17 import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.devtools.build.android.desugar.testdata.java8.AnnotationsOfDefaultMethodsShouldBeKept.AnnotatedInterface;
21 import com.google.devtools.build.android.desugar.testdata.java8.AnnotationsOfDefaultMethodsShouldBeKept.SomeAnnotation;
22 import com.google.devtools.build.android.desugar.testdata.java8.ConcreteDefaultInterfaceWithLambda;
23 import com.google.devtools.build.android.desugar.testdata.java8.ConcreteOverridesDefaultWithLambda;
24 import com.google.devtools.build.android.desugar.testdata.java8.DefaultInterfaceMethodWithStaticInitializer;
25 import com.google.devtools.build.android.desugar.testdata.java8.DefaultInterfaceWithBridges;
26 import com.google.devtools.build.android.desugar.testdata.java8.DefaultMethodFromSeparateJava8Target;
27 import com.google.devtools.build.android.desugar.testdata.java8.DefaultMethodFromSeparateJava8TargetOverridden;
28 import com.google.devtools.build.android.desugar.testdata.java8.DefaultMethodTransitivelyFromSeparateJava8Target;
29 import com.google.devtools.build.android.desugar.testdata.java8.FunctionWithDefaultMethod;
30 import com.google.devtools.build.android.desugar.testdata.java8.FunctionalInterfaceWithInitializerAndDefaultMethods;
31 import com.google.devtools.build.android.desugar.testdata.java8.GenericDefaultInterfaceWithLambda;
32 import com.google.devtools.build.android.desugar.testdata.java8.InterfaceMethod;
33 import com.google.devtools.build.android.desugar.testdata.java8.InterfaceWithDefaultMethod;
34 import com.google.devtools.build.android.desugar.testdata.java8.InterfaceWithDuplicateMethods.ClassWithDuplicateMethods;
35 import com.google.devtools.build.android.desugar.testdata.java8.InterfaceWithInheritedMethods;
36 import com.google.devtools.build.android.desugar.testdata.java8.Java7InterfaceWithBridges;
37 import com.google.devtools.build.android.desugar.testdata.java8.Named;
38 import com.google.devtools.build.android.desugar.testdata.java8.TwoInheritedDefaultMethods;
39 import com.google.devtools.build.android.desugar.testdata.java8.VisibilityTestClass;
40 import java.lang.annotation.Annotation;
41 import java.lang.reflect.Modifier;
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.function.Function;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.junit.runners.JUnit4;
48 
49 /**
50  * Test that exercises classes in the {@code testdata_java8} package. This is meant to be run
51  * against a desugared version of those classes, which in turn exercise various desugaring features.
52  */
53 @RunWith(JUnit4.class)
54 public class DesugarJava8FunctionalTest extends DesugarFunctionalTest {
55 
DesugarJava8FunctionalTest()56   public DesugarJava8FunctionalTest() {
57     this(true, true);
58   }
59 
DesugarJava8FunctionalTest( boolean expectBridgesFromSeparateTarget, boolean expectDefaultMethods)60   protected DesugarJava8FunctionalTest(
61       boolean expectBridgesFromSeparateTarget, boolean expectDefaultMethods) {
62     super(expectBridgesFromSeparateTarget, expectDefaultMethods);
63   }
64 
65   @Test
testLambdaInDefaultMethod()66   public void testLambdaInDefaultMethod() {
67     assertThat(new ConcreteDefaultInterfaceWithLambda().defaultWithLambda())
68         .containsExactly("0", "1")
69         .inOrder();
70   }
71 
72   @Test
testLambdaInDefaultCallsInterfaceMethod()73   public void testLambdaInDefaultCallsInterfaceMethod() {
74     assertThat(new ConcreteDefaultInterfaceWithLambda().defaultCallsInterfaceMethod())
75         .containsExactly("1", "2")
76         .inOrder();
77   }
78 
79   @Test
testOverrideLambdaInDefault()80   public void testOverrideLambdaInDefault() {
81     assertThat(new ConcreteOverridesDefaultWithLambda().defaultWithLambda())
82         .containsExactly("2", "3")
83         .inOrder();
84   }
85 
86   @Test
testLambdaInDefaultCallsOverrideMethod()87   public void testLambdaInDefaultCallsOverrideMethod() {
88     assertThat(new ConcreteOverridesDefaultWithLambda().defaultCallsInterfaceMethod())
89         .containsExactly("3", "4")
90         .inOrder();
91   }
92 
93   @Test
testDefaultInterfaceMethodReference()94   public void testDefaultInterfaceMethodReference() {
95     InterfaceMethod methodrefUse = new InterfaceMethod.Concrete();
96     List<String> dest =
97         methodrefUse.defaultMethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
98     assertThat(dest).containsExactly("Sergey");
99   }
100 
101   @Test
testStaticInterfaceMethodReference()102   public void testStaticInterfaceMethodReference() {
103     InterfaceMethod methodrefUse = new InterfaceMethod.Concrete();
104     List<String> dest =
105         methodrefUse.staticMethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
106     assertThat(dest).containsExactly("Alex");
107   }
108 
109   @Test
testLambdaCallsDefaultMethod()110   public void testLambdaCallsDefaultMethod() {
111     InterfaceMethod methodrefUse = new InterfaceMethod.Concrete();
112     List<String> dest =
113         methodrefUse.lambdaCallsDefaultMethod(ImmutableList.of("Sergey", "Larry", "Alex"));
114     assertThat(dest).containsExactly("Sergey");
115   }
116 
117   @Test
testBootclasspathMethodInvocations()118   public void testBootclasspathMethodInvocations() {
119     InterfaceMethod concrete = new InterfaceMethod.Concrete();
120     assertThat(concrete.defaultInvokingBootclasspathMethods("Larry")).isEqualTo("Larry");
121   }
122 
123   @Test
testStaticMethodsInInterface_explicitAndLambdaBody()124   public void testStaticMethodsInInterface_explicitAndLambdaBody() {
125     List<Long> result = FunctionWithDefaultMethod.DoubleInts.add(ImmutableList.of(7, 39, 8), 3);
126     assertThat(result).containsExactly(10L, 42L, 11L).inOrder();
127   }
128 
129   @Test
testOverriddenDefaultMethod_inHandwrittenClass()130   public void testOverriddenDefaultMethod_inHandwrittenClass() {
131     FunctionWithDefaultMethod<Integer> doubler = new FunctionWithDefaultMethod.DoubleInts();
132     assertThat(doubler.apply(7)).isEqualTo(14);
133     assertThat(doubler.twice(7)).isEqualTo(35);
134   }
135 
136   @Test
testOverriddenDefaultMethod_inHandwrittenSuperclass()137   public void testOverriddenDefaultMethod_inHandwrittenSuperclass() {
138     FunctionWithDefaultMethod<Integer> doubler = new FunctionWithDefaultMethod.DoubleInts2();
139     assertThat(doubler.apply(7)).isEqualTo(14);
140     assertThat(doubler.twice(7)).isEqualTo(35);
141   }
142 
143   @Test
testInheritedDefaultMethod_inLambda()144   public void testInheritedDefaultMethod_inLambda() {
145     FunctionWithDefaultMethod<Integer> doubler =
146         FunctionWithDefaultMethod.DoubleInts.doubleLambda();
147     assertThat(doubler.apply(7)).isEqualTo(14);
148     assertThat(doubler.twice(7)).isEqualTo(28);
149   }
150 
151   @Test
testDefaultMethodReference_onLambda()152   public void testDefaultMethodReference_onLambda() {
153     FunctionWithDefaultMethod<Integer> plus6 = FunctionWithDefaultMethod.DoubleInts.incTwice(3);
154     assertThat(plus6.apply(18)).isEqualTo(24);
155     assertThat(plus6.twice(18)).isEqualTo(30);
156   }
157 
158   @Test
testDefaultMethodReference_onHandwrittenClass()159   public void testDefaultMethodReference_onHandwrittenClass() {
160     FunctionWithDefaultMethod<Integer> times5 = FunctionWithDefaultMethod.DoubleInts.times5();
161     assertThat(times5.apply(6)).isEqualTo(30);
162     assertThat(times5.twice(6)).isEqualTo(150); // Irrelevant that DoubleInts overrides twice()
163   }
164 
165   @Test
testStaticInterfaceMethodReferenceReturned()166   public void testStaticInterfaceMethodReferenceReturned() {
167     Function<Integer, FunctionWithDefaultMethod<Integer>> factory =
168         FunctionWithDefaultMethod.DoubleInts.incFactory();
169     assertThat(factory.apply(6).apply(7)).isEqualTo(13);
170     assertThat(factory.apply(6).twice(7)).isEqualTo(19);
171   }
172 
173   @Test
testSuperDefaultMethodInvocation()174   public void testSuperDefaultMethodInvocation() {
175     assertThat(new TwoInheritedDefaultMethods().name()).isEqualTo("One:Two");
176     assertThat(new Named.DefaultName().name()).isEqualTo("DefaultName-once");
177     assertThat(new Named.DefaultNameSubclass().name()).isEqualTo("DefaultNameSubclass-once-twice");
178   }
179 
180   @Test
testInheritedPreferredOverDefault()181   public void testInheritedPreferredOverDefault() throws Exception {
182     assertThat(new Named.ExplicitName("hello").name()).isEqualTo("hello");
183     // Make sure AbstractName remains abstract, despite default method from implemented interface
184     assertThat(Modifier.isAbstract(Named.AbstractName.class.getMethod("name").getModifiers()))
185         .isTrue();
186   }
187 
188   @Test
testRedefinedDefaultMethod()189   public void testRedefinedDefaultMethod() throws Exception {
190     assertThat(new InterfaceWithDefaultMethod.Version2().version()).isEqualTo(2);
191   }
192 
193   @Test
testDefaultMethodRedefinedInSubclass()194   public void testDefaultMethodRedefinedInSubclass() throws Exception {
195     assertThat(new InterfaceWithDefaultMethod.AlsoVersion2().version()).isEqualTo(2);
196   }
197 
198   @Test
testDefaultMethodVisibility()199   public void testDefaultMethodVisibility() {
200     assertThat(new VisibilityTestClass().m()).isEqualTo(42);
201   }
202 
203   /** Test for b/38302860 */
204   @Test
testAnnotationsOfDefaultMethodsAreKept()205   public void testAnnotationsOfDefaultMethodsAreKept() throws Exception {
206     {
207       Annotation[] annotations = AnnotatedInterface.class.getAnnotations();
208       assertThat(annotations).hasLength(1);
209       assertThat(annotations[0]).isInstanceOf(SomeAnnotation.class);
210       assertThat(((SomeAnnotation) annotations[0]).value()).isEqualTo(1);
211     }
212     {
213       Annotation[] annotations =
214           AnnotatedInterface.class.getMethod("annotatedAbstractMethod").getAnnotations();
215       assertThat(annotations).hasLength(1);
216       assertThat(annotations[0]).isInstanceOf(SomeAnnotation.class);
217       assertThat(((SomeAnnotation) annotations[0]).value()).isEqualTo(2);
218     }
219     {
220       Annotation[] annotations =
221           AnnotatedInterface.class.getMethod("annotatedDefaultMethod").getAnnotations();
222       assertThat(annotations).hasLength(1);
223       assertThat(annotations[0]).isInstanceOf(SomeAnnotation.class);
224       assertThat(((SomeAnnotation) annotations[0]).value()).isEqualTo(3);
225     }
226   }
227   /** Test for b/38308515 */
228   @Test
testDefaultAndStaticMethodNameClash()229   public void testDefaultAndStaticMethodNameClash() {
230     final ClassWithDuplicateMethods instance = new ClassWithDuplicateMethods();
231     assertThat(instance.getZero()).isEqualTo(0);
232     assertThat(instance.getZeroFromStaticInterfaceMethod()).isEqualTo(1);
233   }
234 
235   /**
236    * Test for b/38257037
237    *
238    * <p>Note that, we intentionally suppress unchecked warnings, because we expect some
239    * ClassCastException to test bridge methods.
240    */
241   @SuppressWarnings("unchecked")
242   @Test
testBridgeAndDefaultMethods()243   public void testBridgeAndDefaultMethods() {
244     {
245       DefaultInterfaceWithBridges object = new DefaultInterfaceWithBridges();
246       Integer one = 1;
247       assertThat(object.copy(one)).isEqualTo(one);
248       assertThat(object.copy((Number) one)).isEqualTo(one);
249       assertThrows(ClassCastException.class, () -> object.copy(Double.valueOf(1)));
250 
251       assertThat(object.getNumber()).isInstanceOf(Double.class);
252       assertThat(object.getNumber()).isEqualTo(Double.valueOf(2.3d));
253       assertThat(object.getDouble()).isEqualTo(Double.valueOf(2.3d));
254     }
255     {
256       Java7InterfaceWithBridges.ClassAddTwo testObject =
257           new Java7InterfaceWithBridges.ClassAddTwo();
258       assertThat(testObject.add(Integer.valueOf(2))).isEqualTo(4);
259 
260       @SuppressWarnings("rawtypes")
261       Java7InterfaceWithBridges top = testObject;
262       assertThat(top.add(Integer.valueOf(2))).isEqualTo(4);
263       assertThrows(ClassCastException.class, () -> top.add(new Object()));
264       assertThrows(ClassCastException.class, () -> top.add(Double.valueOf(1)));
265       assertThrows(ClassCastException.class, () -> top.add(Long.valueOf(1)));
266 
267       @SuppressWarnings("rawtypes")
268       Java7InterfaceWithBridges.LevelOne levelOne = testObject;
269       assertThat(levelOne.add(Integer.valueOf(2))).isEqualTo(4);
270       assertThrows(ClassCastException.class, () -> top.add(new Object()));
271       assertThrows(ClassCastException.class, () -> top.add(Double.valueOf(1)));
272       assertThrows(ClassCastException.class, () -> top.add(Long.valueOf(1)));
273 
274       @SuppressWarnings("rawtypes")
275       Java7InterfaceWithBridges.LevelOne levelTwo = testObject;
276       assertThat(levelTwo.add(Integer.valueOf(2))).isEqualTo(4);
277       assertThrows(ClassCastException.class, () -> levelTwo.add(Double.valueOf(1)));
278       assertThrows(ClassCastException.class, () -> levelTwo.add(Long.valueOf(1)));
279     }
280     {
281       GenericDefaultInterfaceWithLambda.ClassTwo testObject =
282           new GenericDefaultInterfaceWithLambda.ClassTwo();
283 
284       assertThat(testObject.increment(Integer.valueOf(0))).isEqualTo(1);
285       assertThat(testObject.toString(Integer.valueOf(0))).isEqualTo("0");
286       assertThat(testObject.getBaseValue()).isEqualTo(Integer.valueOf(0));
287 
288       assertThat(testObject.toList(0)).isEmpty();
289       assertThat(testObject.toList(1)).containsExactly(0).inOrder();
290       assertThat(testObject.toList(2)).containsExactly(0, 1).inOrder();
291 
292       assertThat(((Function<Integer, ArrayList<Integer>>) testObject.toListSupplier()).apply(0))
293           .isEmpty();
294       assertThat(((Function<Integer, ArrayList<Integer>>) testObject.toListSupplier()).apply(1))
295           .containsExactly(0)
296           .inOrder();
297       assertThat(((Function<Integer, ArrayList<Integer>>) testObject.toListSupplier()).apply(2))
298           .containsExactly(0, 1)
299           .inOrder();
300 
301       assertThat(testObject.convertToStringList(ImmutableList.of(0)))
302           .containsExactly("0")
303           .inOrder();
304       assertThat(testObject.convertToStringList(ImmutableList.of(0, 1)))
305           .containsExactly("0", "1")
306           .inOrder();
307 
308       @SuppressWarnings("rawtypes")
309       GenericDefaultInterfaceWithLambda top = testObject;
310       assertThrows(ClassCastException.class, () -> top.increment(Long.valueOf(1)));
311       assertThrows(ClassCastException.class, () -> top.toString(Long.valueOf(1)));
312       assertThat(top.increment(Integer.valueOf(0))).isEqualTo(1);
313       assertThat(top.toString(Integer.valueOf(0))).isEqualTo("0");
314       assertThat(top.getBaseValue()).isEqualTo(Integer.valueOf(0));
315 
316       assertThat(top.toList(0)).isEmpty();
317       assertThat(top.toList(1)).containsExactly(0).inOrder();
318       assertThat(top.toList(2)).containsExactly(0, 1).inOrder();
319 
320       assertThat(((Function<Integer, ArrayList<Integer>>) top.toListSupplier()).apply(0)).isEmpty();
321       assertThat(((Function<Integer, ArrayList<Integer>>) top.toListSupplier()).apply(1))
322           .containsExactly(0)
323           .inOrder();
324       assertThat(((Function<Integer, ArrayList<Integer>>) top.toListSupplier()).apply(2))
325           .containsExactly(0, 1)
326           .inOrder();
327 
328       assertThat(top.convertToStringList(ImmutableList.of(0))).containsExactly("0").inOrder();
329       assertThat(top.convertToStringList(ImmutableList.of(0, 1)))
330           .containsExactly("0", "1")
331           .inOrder();
332     }
333     {
334       @SuppressWarnings("rawtypes")
335       GenericDefaultInterfaceWithLambda testObject =
336           new GenericDefaultInterfaceWithLambda.ClassThree();
337       assertThat(testObject.getBaseValue()).isEqualTo(Long.valueOf(0));
338       assertThat(testObject.increment(Long.valueOf(0))).isEqualTo(Long.valueOf(0 + 1));
339       assertThat(testObject.toString(Long.valueOf(0))).isEqualTo(Long.valueOf(0).toString());
340       assertThrows(ClassCastException.class, () -> testObject.increment(Integer.valueOf(0)));
341       assertThrows(ClassCastException.class, () -> testObject.toString(Integer.valueOf(0)));
342       assertThat(testObject.toList(2)).containsExactly(Long.valueOf(0), Long.valueOf(1)).inOrder();
343       assertThat(testObject.convertToStringList(testObject.toList(1))).containsExactly("0");
344       assertThat(((Function<Integer, ArrayList<Long>>) testObject.toListSupplier()).apply(2))
345           .containsExactly(Long.valueOf(0), Long.valueOf(1));
346     }
347   }
348 
349   /**
350    * Test for b/62047432.
351    *
352    * <p>When desugaring a functional interface with an executable clinit and default methods, we
353    * erase the body of clinit to avoid executing it during desugaring. This test makes sure that all
354    * the constants defined in the interface are still there after desugaring.
355    */
356   @Test
testFunctionalInterfaceWithExecutableClinitStillWorkAfterDesugar()357   public void testFunctionalInterfaceWithExecutableClinitStillWorkAfterDesugar() {
358     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.CONSTANT.length("").convert())
359         .isEqualTo(0);
360     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.CONSTANT.length("1").convert())
361         .isEqualTo(1);
362     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.BOOLEAN).isFalse();
363     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.CHAR).isEqualTo('h');
364     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.BYTE).isEqualTo(0);
365     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.SHORT).isEqualTo(0);
366 
367     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.INT).isEqualTo(0);
368     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.FLOAT).isEqualTo(0f);
369     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.LONG).isEqualTo(0);
370     assertThat(FunctionalInterfaceWithInitializerAndDefaultMethods.DOUBLE).isEqualTo(0d);
371   }
372 
373   /** Test for b/38255926. */
374   @Test
testDefaultMethodInitializationOrder()375   public void testDefaultMethodInitializationOrder() {
376     {
377       assertThat(new DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetOne.C().sum())
378           .isEqualTo(11); // To trigger loading the class C and its super interfaces.
379       assertThat(
380               DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetOne
381                   .getRealInitializationOrder())
382           .isEqualTo(
383               DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetOne
384                   .getExpectedInitializationOrder());
385     }
386     {
387       assertThat(new DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetTwo.C().sum())
388           .isEqualTo(3);
389       assertThat(
390               DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetTwo
391                   .getRealInitializationOrder())
392           .isEqualTo(
393               DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetTwo
394                   .getExpectedInitializationOrder());
395     }
396     {
397       assertThat(new DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetThree.C().sum())
398           .isEqualTo(11);
399       assertThat(
400               DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetThree
401                   .getRealInitializationOrder())
402           .isEqualTo(
403               DefaultInterfaceMethodWithStaticInitializer.TestInterfaceSetThree
404                   .getExpectedInitializationOrder());
405     }
406   }
407 
408   /**
409    * Tests that default methods on the classpath are correctly handled. We'll also verify the
410    * metadata that's emitted for this case to make sure the binary-wide double-check for correct
411    * desugaring of default and static interface methods keeps working (b/65645388).
412    */
413   @Test
testDefaultMethodsInSeparateTarget()414   public void testDefaultMethodsInSeparateTarget() {
415     assertThat(new DefaultMethodFromSeparateJava8Target().dflt()).isEqualTo("dflt");
416     assertThat(new DefaultMethodTransitivelyFromSeparateJava8Target().dflt()).isEqualTo("dflt");
417     assertThat(new DefaultMethodFromSeparateJava8TargetOverridden().dflt()).isEqualTo("override");
418   }
419 
420   /** Regression test for b/73355452 */
421   @Test
testSuperCallToInheritedDefaultMethod()422   public void testSuperCallToInheritedDefaultMethod() {
423     assertThat(new InterfaceWithInheritedMethods.Impl().name()).isEqualTo("Base");
424     assertThat(new InterfaceWithInheritedMethods.Impl().suffix()).isEqualTo("!");
425   }
426 }
427