aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java b/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java
new file mode 100644
index 0000000000..cdc32639b3
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixerTest.java
@@ -0,0 +1,234 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.android.desugar;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.android.desugar.DefaultMethodClassFixer.InterfaceComparator.INSTANCE;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Closer;
+import com.google.devtools.build.android.desugar.Desugar.ThrowingClassLoader;
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/** Unit Test for {@link DefaultMethodClassFixer} */
+@RunWith(JUnit4.class)
+public class DefaultMethodClassFixerTest {
+
+ private ClassReaderFactory classpathReader;
+ private ClassReaderFactory bootclassPath;
+ private ClassLoader classLoader;
+ private Closer closer;
+
+ @Before
+ public void setup() throws IOException {
+ closer = Closer.create();
+ CoreLibraryRewriter rewriter = new CoreLibraryRewriter("");
+
+ IndexedInputs indexedInputs =
+ toIndexedInputs(closer, System.getProperty("DefaultMethodClassFixerTest.input"));
+ IndexedInputs indexedClasspath =
+ toIndexedInputs(closer, System.getProperty("DefaultMethodClassFixerTest.classpath"));
+ IndexedInputs indexedBootclasspath =
+ toIndexedInputs(closer, System.getProperty("DefaultMethodClassFixerTest.bootclasspath"));
+
+ bootclassPath = new ClassReaderFactory(indexedBootclasspath, rewriter);
+ IndexedInputs indexedClasspathAndInputFiles = indexedClasspath.withParent(indexedInputs);
+ classpathReader = new ClassReaderFactory(indexedClasspathAndInputFiles, rewriter);
+ ClassLoader bootclassloader =
+ new HeaderClassLoader(indexedBootclasspath, rewriter, new ThrowingClassLoader());
+ classLoader = new HeaderClassLoader(indexedClasspathAndInputFiles, rewriter, bootclassloader);
+ }
+
+ @After
+ public void teardown() throws IOException {
+ closer.close();
+ }
+
+ private static IndexedInputs toIndexedInputs(Closer closer, String stringPathList)
+ throws IOException {
+ final List<Path> pathList = readPathListFromString(stringPathList);
+ return new IndexedInputs(Desugar.toRegisteredInputFileProvider(closer, pathList));
+ }
+
+ private static List<Path> readPathListFromString(String pathList) {
+ return Arrays.stream(checkNotNull(pathList).split(File.pathSeparator))
+ .map(Paths::get)
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ private byte[] desugar(String classname) {
+ ClassReader reader = classpathReader.readIfKnown(classname);
+ return desugar(reader);
+ }
+
+ private byte[] desugar(ClassReader reader) {
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ DefaultMethodClassFixer fixer =
+ new DefaultMethodClassFixer(writer, classpathReader, bootclassPath, classLoader);
+ reader.accept(fixer, 0);
+ return writer.toByteArray();
+ }
+
+ private byte[] desugar(byte[] classContent) {
+ ClassReader reader = new ClassReader(classContent);
+ return desugar(reader);
+ }
+
+ @Test
+ public void testDesugaringDirectImplementation() {
+ byte[] desugaredClass =
+ desugar(
+ ("com.google.devtools.build.android.desugar.testdata.java8."
+ + "DefaultInterfaceMethodWithStaticInitializer$TestInterfaceSetOne$C")
+ .replace('.', '/'));
+ checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(desugaredClass);
+
+ byte[] desugaredClassAgain = desugar(desugaredClass);
+ checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(
+ desugaredClassAgain);
+
+ desugaredClassAgain = desugar(desugaredClassAgain);
+ checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(
+ desugar(desugaredClassAgain));
+ }
+
+ private void checkClinitForDefaultInterfaceMethodWithStaticInitializerTestInterfaceSetOneC(
+ byte[] classContent) {
+ ClassReader reader = new ClassReader(classContent);
+ reader.accept(
+ new ClassVisitor(Opcodes.ASM5) {
+
+ class ClinitMethod extends MethodNode {
+
+ public ClinitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ super(Opcodes.ASM5, access, name, desc, signature, exceptions);
+ }
+ }
+
+ private ClinitMethod clinit;
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ if ("<clinit>".equals(name)) {
+ assertThat(clinit).isNull();
+ clinit = new ClinitMethod(access, name, desc, signature, exceptions);
+ return clinit;
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ @Override
+ public void visitEnd() {
+ assertThat(clinit).isNotNull();
+ assertThat(clinit.instructions.size()).isEqualTo(3);
+ AbstractInsnNode instruction = clinit.instructions.getFirst();
+ {
+ assertThat(instruction).isInstanceOf(MethodInsnNode.class);
+ MethodInsnNode field = (MethodInsnNode) instruction;
+ assertThat(field.owner)
+ .isEqualTo(
+ "com/google/devtools/build/android/desugar/testdata/java8/"
+ + "DefaultInterfaceMethodWithStaticInitializer"
+ + "$TestInterfaceSetOne$I1$$CC");
+ assertThat(field.name)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME);
+ assertThat(field.desc)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC);
+ }
+ {
+ instruction = instruction.getNext();
+ assertThat(instruction).isInstanceOf(MethodInsnNode.class);
+ MethodInsnNode field = (MethodInsnNode) instruction;
+ assertThat(field.owner)
+ .isEqualTo(
+ "com/google/devtools/build/android/desugar/testdata/java8/"
+ + "DefaultInterfaceMethodWithStaticInitializer"
+ + "$TestInterfaceSetOne$I2$$CC");
+ assertThat(field.name)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME);
+ assertThat(field.desc)
+ .isEqualTo(InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC);
+ }
+ {
+ instruction = instruction.getNext();
+ assertThat(instruction).isInstanceOf(InsnNode.class);
+ assertThat(instruction.getOpcode()).isEqualTo(Opcodes.RETURN);
+ }
+ }
+ },
+ 0);
+ }
+
+ @Test
+ public void testInterfaceComparator() {
+ assertThat(INSTANCE.compare(Runnable.class, Runnable.class)).isEqualTo(0);
+ assertThat(INSTANCE.compare(Runnable.class, MyRunnable1.class)).isEqualTo(1);
+ assertThat(INSTANCE.compare(MyRunnable2.class, Runnable.class)).isEqualTo(-1);
+ assertThat(INSTANCE.compare(MyRunnable3.class, Runnable.class)).isEqualTo(-1);
+ assertThat(INSTANCE.compare(MyRunnable1.class, MyRunnable3.class)).isEqualTo(1);
+ assertThat(INSTANCE.compare(MyRunnable3.class, MyRunnable2.class)).isEqualTo(-1);
+ assertThat(INSTANCE.compare(MyRunnable2.class, MyRunnable1.class)).isGreaterThan(0);
+ assertThat(INSTANCE.compare(Runnable.class, Serializable.class)).isGreaterThan(0);
+ assertThat(INSTANCE.compare(Serializable.class, Runnable.class)).isLessThan(0);
+
+ TreeSet<Class<?>> orderedSet = new TreeSet<>(INSTANCE);
+ orderedSet.add(Serializable.class);
+ orderedSet.add(Runnable.class);
+ orderedSet.add(MyRunnable2.class);
+ orderedSet.add(Callable.class);
+ orderedSet.add(Serializable.class);
+ orderedSet.add(MyRunnable1.class);
+ orderedSet.add(MyRunnable3.class);
+ assertThat(orderedSet)
+ .containsExactly(
+ MyRunnable3.class, // subtype before supertype(s)
+ MyRunnable1.class,
+ MyRunnable2.class,
+ Serializable.class, // java... comes textually after com.google...
+ Runnable.class,
+ Callable.class)
+ .inOrder();
+ }
+
+ private static interface MyRunnable1 extends Runnable {}
+
+ private static interface MyRunnable2 extends Runnable {}
+
+ private static interface MyRunnable3 extends MyRunnable1, MyRunnable2 {}
+}