// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

package com.android.tools.r8.shaking.forceproguardcompatibility;

import static com.android.tools.r8.references.Reference.classFromClass;
import static com.android.tools.r8.references.Reference.methodFromMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import com.android.tools.r8.CompatProguardCommandBuilder;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.invokesuper.Consumer;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.CollectingGraphConsumer;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.shaking.forceproguardcompatibility.defaultmethods.ClassImplementingInterface;
import com.android.tools.r8.shaking.forceproguardcompatibility.defaultmethods.InterfaceWithDefaultMethods;
import com.android.tools.r8.shaking.forceproguardcompatibility.defaultmethods.TestClass;
import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FieldSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.android.tools.r8.utils.graphinspector.GraphInspector;
import com.android.tools.r8.utils.graphinspector.GraphInspector.QueryNode;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class ForceProguardCompatibilityTest extends TestBase {

  private Backend backend;

  @Parameterized.Parameters(name = "Backend: {0}")
  public static Backend[] data() {
    return ToolHelper.getBackends();
  }

  public ForceProguardCompatibilityTest(Backend backend) {
    this.backend = backend;
  }

  private void test(Class mainClass, Class mentionedClass, boolean forceProguardCompatibility)
      throws Exception {
    String proguardConfig = keepMainProguardConfiguration(mainClass, true, false);
    CodeInspector inspector =
        new CodeInspector(
            compileWithR8(
                readClasses(ImmutableList.of(mainClass, mentionedClass)),
                proguardConfig,
                options -> options.forceProguardCompatibility = forceProguardCompatibility,
                backend));
    assertTrue(inspector.clazz(mainClass.getCanonicalName()).isPresent());
    ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(mentionedClass));
    assertTrue(clazz.isPresent());
    MethodSubject defaultInitializer = clazz.method(MethodSignature.initializer(new String[]{}));
    assertEquals(forceProguardCompatibility, defaultInitializer.isPresent());
  }

  @Test
  public void testKeepDefaultInitializer() throws Exception {
    test(TestMain.class, TestMain.MentionedClass.class, true);
    test(TestMain.class, TestMain.MentionedClass.class, false);
  }

  @Test
  public void testKeepDefaultInitializerArrayType() throws Exception {
    test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true);
    test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, false);
  }

  private void runAnnotationsTest(boolean forceProguardCompatibility, boolean keepAnnotations)
      throws Exception {
    R8Command.Builder builder = new CompatProguardCommandBuilder(forceProguardCompatibility);
    // Add application classes including the annotation class.
    Class mainClass = TestMain.class;
    Class mentionedClassWithAnnotations = TestMain.MentionedClassWithAnnotation.class;
    Class annotationClass = TestAnnotation.class;
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestMain.MentionedClass.class));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mentionedClassWithAnnotations));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(annotationClass));
    // Keep main class and the annotation class.
    builder.addProguardConfiguration(
        ImmutableList.of(keepMainProguardConfiguration(mainClass, true, false)), Origin.unknown());
    builder.addProguardConfiguration(
        ImmutableList.of("-keep class " + annotationClass.getCanonicalName() + " { *; }"),
        Origin.unknown());
    if (keepAnnotations) {
      builder.addProguardConfiguration(ImmutableList.of("-keepattributes *Annotation*"),
          Origin.unknown());
    }

    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
    CodeInspector inspector = new CodeInspector(ToolHelper.runR8(builder.build()));
    assertTrue(inspector.clazz(mainClass.getCanonicalName()).isPresent());
    ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(mentionedClassWithAnnotations));
    assertTrue(clazz.isPresent());

    // The test contains only a member class so the enclosing-method attribute will be null.
    assertEquals(
        forceProguardCompatibility,
        !clazz.getDexClass().getInnerClasses().isEmpty());
    assertEquals(forceProguardCompatibility || keepAnnotations,
        clazz.annotation(annotationClass.getCanonicalName()).isPresent());
  }

  @Test
  public void testAnnotations() throws Exception {
    runAnnotationsTest(true, true);
    runAnnotationsTest(true, false);
    runAnnotationsTest(false, true);
    runAnnotationsTest(false, false);
  }

  private void runDefaultConstructorTest(boolean forceProguardCompatibility,
      Class<?> testClass, boolean hasDefaultConstructor) throws Exception {
    CompatProguardCommandBuilder builder =
        new CompatProguardCommandBuilder(forceProguardCompatibility);
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(testClass));
    List<String> proguardConfig = ImmutableList.of(
        "-keep class " + testClass.getCanonicalName() + " {",
        "  public void method();",
        "}");
    builder.addProguardConfiguration(proguardConfig, Origin.unknown());

    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));

    CollectingGraphConsumer graphConsumer = new CollectingGraphConsumer(null);
    builder.setKeptGraphConsumer(graphConsumer);

    GraphInspector inspector =
        new GraphInspector(graphConsumer, new CodeInspector(ToolHelper.runR8(builder.build())));
    QueryNode clazzNode = inspector.clazz(classFromClass(testClass)).assertPresent();
    if (hasDefaultConstructor) {
      QueryNode initNode = inspector.method(methodFromMethod(testClass.getConstructor()));
      if (forceProguardCompatibility) {
        initNode.assertPureCompatKeptBy(clazzNode);
      } else {
        initNode.assertAbsent();
      }
    }

    if (isRunProguard()) {
      Path proguardedJar = File.createTempFile("proguarded", ".jar", temp.getRoot()).toPath();
      Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
      Path proguardMapFile = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
      FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
      ToolHelper.runProguard(jarTestClasses(testClass),
          proguardedJar, proguardConfigFile, proguardMapFile);
    }
  }

  @Test
  public void testDefaultConstructor() throws Exception {
    runDefaultConstructorTest(true, TestClassWithDefaultConstructor.class, true);
    runDefaultConstructorTest(true, TestClassWithoutDefaultConstructor.class, false);
    runDefaultConstructorTest(false, TestClassWithDefaultConstructor.class, true);
    runDefaultConstructorTest(false, TestClassWithoutDefaultConstructor.class, false);
  }

  public void testCheckCast(boolean forceProguardCompatibility, Class mainClass,
      Class instantiatedClass, boolean containsCheckCast)
      throws Exception {
    R8Command.Builder builder = new CompatProguardCommandBuilder(forceProguardCompatibility);
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(instantiatedClass));
    List<String> proguardConfig = ImmutableList.of(
        "-keep class " + mainClass.getCanonicalName() + " {",
        "  public static void main(java.lang.String[]);",
        "}",
        "-dontobfuscate");
    builder.addProguardConfiguration(proguardConfig, Origin.unknown());

    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
    CodeInspector inspector = new CodeInspector(ToolHelper.runR8(builder.build()));
    assertTrue(inspector.clazz(getJavacGeneratedClassName(mainClass)).isPresent());
    ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(instantiatedClass));
    assertEquals(containsCheckCast, clazz.isPresent());
    assertEquals(containsCheckCast, clazz.isPresent());
    if (clazz.isPresent()) {
      assertEquals(forceProguardCompatibility && containsCheckCast, !clazz.isAbstract());
    }

    if (isRunProguard()) {
      Path proguardedJar = File.createTempFile("proguarded", ".jar", temp.getRoot()).toPath();
      Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
      FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
      ToolHelper.runProguard(jarTestClasses(ImmutableList.of(mainClass, instantiatedClass)),
          proguardedJar, proguardConfigFile, null);
      CodeInspector proguardInspector = new CodeInspector(readJar(proguardedJar));
      assertTrue(proguardInspector.clazz(mainClass).isPresent());
      assertEquals(
          containsCheckCast, proguardInspector.clazz(instantiatedClass).isPresent());
    }
  }

  @Test
  public void checkCastTest() throws Exception {
    testCheckCast(true, TestMainWithCheckCast.class, TestClassWithDefaultConstructor.class, true);
    testCheckCast(
        true, TestMainWithoutCheckCast.class, TestClassWithDefaultConstructor.class, false);
    testCheckCast(
        false, TestMainWithCheckCast.class, TestClassWithDefaultConstructor.class, true);
    testCheckCast(
        false, TestMainWithoutCheckCast.class, TestClassWithDefaultConstructor.class, false);
  }

  public void testClassForName(
      boolean forceProguardCompatibility, boolean allowObfuscation) throws Exception {
    CompatProguardCommandBuilder builder =
        new CompatProguardCommandBuilder(forceProguardCompatibility);
    Class mainClass = TestMainWithClassForName.class;
    Class forNameClass1 = TestClassWithDefaultConstructor.class;
    Class forNameClass2 = TestClassWithoutDefaultConstructor.class;
    List<Class> forNameClasses = ImmutableList.of(forNameClass1, forNameClass2);
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(forNameClass1));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(forNameClass2));
    ImmutableList.Builder<String> proguardConfigurationBuilder = ImmutableList.builder();
    proguardConfigurationBuilder.add(
        "-keep class " + mainClass.getCanonicalName() + " {",
        "  <init>();",  // Add <init>() so it does not become a compatibility rule below.
        "  public static void main(java.lang.String[]);",
        "}");
    if (!allowObfuscation) {
      proguardConfigurationBuilder.add("-dontobfuscate");
    }
    List<String> proguardConfig = proguardConfigurationBuilder.build();
    builder.addProguardConfiguration(proguardConfig, Origin.unknown());
    if (allowObfuscation) {
      builder.setProguardMapOutputPath(temp.newFile().toPath());
    }

    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
    CodeInspector inspector = new CodeInspector(ToolHelper.runR8(builder.build()));
    assertTrue(inspector.clazz(getJavacGeneratedClassName(mainClass)).isPresent());
    forNameClasses.forEach(clazz -> {
      ClassSubject subject = inspector.clazz(getJavacGeneratedClassName(clazz));
      assertTrue(subject.isPresent());
      assertEquals(subject.isPresent() && allowObfuscation, subject.isRenamed());
    });

    if (isRunProguard()) {
      Path proguardedJar = File.createTempFile("proguarded", ".jar", temp.getRoot()).toPath();
      Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
      Path proguardMapFile = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
      FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
      ToolHelper.runProguard(jarTestClasses(
          ImmutableList.of(mainClass, forNameClass1, forNameClass2)),
          proguardedJar, proguardConfigFile, proguardMapFile);
      CodeInspector proguardedInspector = new CodeInspector(readJar(proguardedJar), proguardMapFile);
      assertEquals(3, proguardedInspector.allClasses().size());
      assertTrue(proguardedInspector.clazz(mainClass).isPresent());
      for (Class clazz : ImmutableList.of(forNameClass1, forNameClass2)) {
        assertTrue(proguardedInspector.clazz(clazz).isPresent());
        assertEquals(allowObfuscation, proguardedInspector.clazz(clazz).isRenamed());
      }
    }
  }

  @Test
  public void classForNameTest() throws Exception {
    testClassForName(true, false);
    testClassForName(false, false);
    testClassForName(true, true);
    testClassForName(false, true);
  }

  public void testClassGetMembers(
      boolean forceProguardCompatibility, boolean allowObfuscation) throws Exception {
    CompatProguardCommandBuilder builder =
        new CompatProguardCommandBuilder(forceProguardCompatibility);
    Class mainClass = TestMainWithGetMembers.class;
    Class withMemberClass = TestClassWithMembers.class;
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(withMemberClass));
    ImmutableList.Builder<String> proguardConfigurationBuilder = ImmutableList.builder();
    proguardConfigurationBuilder.add(
        "-keep class " + mainClass.getCanonicalName() + " {",
        "  <init>();",  // Add <init>() so it does not become a compatibility rule below.
        "  public static void main(java.lang.String[]);",
        "}");
    if (!allowObfuscation) {
      proguardConfigurationBuilder.add("-dontobfuscate");
    }
    List<String> proguardConfig = proguardConfigurationBuilder.build();
    builder.addProguardConfiguration(proguardConfig, Origin.unknown());
    if (allowObfuscation) {
      builder.setProguardMapOutputPath(temp.newFile().toPath());
    }

    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
    CodeInspector inspector = new CodeInspector(ToolHelper.runR8(builder.build()));
    assertTrue(inspector.clazz(getJavacGeneratedClassName(mainClass)).isPresent());
    ClassSubject classSubject = inspector.clazz(getJavacGeneratedClassName(withMemberClass));
    // Due to the direct usage of .class
    assertTrue(classSubject.isPresent());
    assertEquals(allowObfuscation, classSubject.isRenamed());
    FieldSubject foo = classSubject.field("java.lang.String", "foo");
    assertTrue(foo.isPresent());
    assertEquals(foo.isPresent() && allowObfuscation, foo.isRenamed());
    MethodSubject bar =
        classSubject.method("java.lang.String", "bar", ImmutableList.of("java.lang.String"));
    assertTrue(bar.isPresent());
    assertEquals(bar.isPresent() && allowObfuscation, bar.isRenamed());

    if (isRunProguard()) {
      Path proguardedJar = File.createTempFile("proguarded", ".jar", temp.getRoot()).toPath();
      Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
      Path proguardMapFile = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
      FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
      ToolHelper.runProguard(jarTestClasses(
          ImmutableList.of(mainClass, withMemberClass)),
          proguardedJar, proguardConfigFile, proguardMapFile);
      CodeInspector proguardedInspector = new CodeInspector(readJar(proguardedJar), proguardMapFile);
      assertEquals(2, proguardedInspector.allClasses().size());
      assertTrue(proguardedInspector.clazz(mainClass).isPresent());
      classSubject = proguardedInspector.clazz(withMemberClass);
      assertTrue(classSubject.isPresent());
      assertEquals(allowObfuscation, classSubject.isRenamed());
      foo = classSubject.field("java.lang.String", "foo");
      assertTrue(foo.isPresent());
      assertEquals(allowObfuscation, foo.isRenamed());
      bar = classSubject.method("java.lang.String", "bar", ImmutableList.of("java.lang.String"));
      assertTrue(bar.isPresent());
      assertEquals(allowObfuscation, bar.isRenamed());
    }
  }

  @Test
  public void classGetMembersTest() throws Exception {
    testClassGetMembers(true, false);
    testClassGetMembers(false, false);
    testClassGetMembers(true, true);
    testClassGetMembers(false, true);
  }

  public void testAtomicFieldUpdaters(
      boolean forceProguardCompatibility, boolean allowObfuscation) throws Exception {
    CompatProguardCommandBuilder builder =
        new CompatProguardCommandBuilder(forceProguardCompatibility);
    Class mainClass = TestMainWithAtomicFieldUpdater.class;
    Class withVolatileFields = TestClassWithVolatileFields.class;
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(withVolatileFields));
    ImmutableList.Builder<String> proguardConfigurationBuilder = ImmutableList.builder();
    proguardConfigurationBuilder.add(
        "-keep class " + mainClass.getCanonicalName() + " {",
        "  <init>();",  // Add <init>() so it does not become a compatibility rule below.
        "  public static void main(java.lang.String[]);",
        "}");
    if (!allowObfuscation) {
      proguardConfigurationBuilder.add("-dontobfuscate");
    }
    List<String> proguardConfig = proguardConfigurationBuilder.build();
    builder.addProguardConfiguration(proguardConfig, Origin.unknown());
    if (allowObfuscation) {
      builder.setProguardMapOutputPath(temp.newFile().toPath());
    }

    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
    CodeInspector inspector = new CodeInspector(ToolHelper.runR8(builder.build()));
    assertTrue(inspector.clazz(getJavacGeneratedClassName(mainClass)).isPresent());
    ClassSubject classSubject = inspector.clazz(getJavacGeneratedClassName(withVolatileFields));
    // Due to the direct usage of .class
    assertTrue(classSubject.isPresent());
    assertEquals(allowObfuscation, classSubject.isRenamed());
    FieldSubject f = classSubject.field("int", "intField");
    assertTrue(f.isPresent());
    assertEquals(f.isPresent() && allowObfuscation, f.isRenamed());
    f = classSubject.field("long", "longField");
    assertTrue(f.isPresent());
    assertEquals(f.isPresent() && allowObfuscation, f.isRenamed());
    f = classSubject.field("java.lang.Object", "objField");
    assertTrue(f.isPresent());
    assertEquals(f.isPresent() && allowObfuscation, f.isRenamed());

    if (isRunProguard()) {
      Path proguardedJar = File.createTempFile("proguarded", ".jar", temp.getRoot()).toPath();
      Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
      Path proguardMapFile = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
      FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
      ToolHelper.runProguard(jarTestClasses(
          ImmutableList.of(mainClass, withVolatileFields)),
          proguardedJar, proguardConfigFile, proguardMapFile);
      CodeInspector proguardedInspector = new CodeInspector(readJar(proguardedJar), proguardMapFile);
      assertEquals(2, proguardedInspector.allClasses().size());
      assertTrue(proguardedInspector.clazz(mainClass).isPresent());
      classSubject = proguardedInspector.clazz(withVolatileFields);
      assertTrue(classSubject.isPresent());
      assertEquals(allowObfuscation, classSubject.isRenamed());
      f = classSubject.field("int", "intField");
      assertTrue(f.isPresent());
      assertEquals(allowObfuscation, f.isRenamed());
      f = classSubject.field("long", "longField");
      assertTrue(f.isPresent());
      assertEquals(allowObfuscation, f.isRenamed());
      f = classSubject.field("java.lang.Object", "objField");
      assertTrue(f.isPresent());
      assertEquals(allowObfuscation, f.isRenamed());
    }
  }

  @Test
  public void atomicFieldUpdaterTest() throws Exception {
    testAtomicFieldUpdaters(true, false);
    testAtomicFieldUpdaters(false, false);
    testAtomicFieldUpdaters(true, true);
    testAtomicFieldUpdaters(false, true);
  }

  public void testKeepAttributes(
      boolean forceProguardCompatibility, boolean innerClasses, boolean enclosingMethod)
      throws Exception {
    String keepRules = "";
    if (innerClasses || enclosingMethod) {
      List<String> attributes = new ArrayList<>();
      if (innerClasses) {
        attributes.add(ProguardKeepAttributes.INNER_CLASSES);
      }
      if (enclosingMethod) {
        attributes.add(ProguardKeepAttributes.ENCLOSING_METHOD);
      }
      keepRules = "-keepattributes " + String.join(",", attributes);
    }
    CodeInspector inspector;

    try {
      inspector =
          testForR8Compat(backend, forceProguardCompatibility)
              .addProgramFiles(
                  ToolHelper.getClassFilesForTestPackage(TestKeepAttributes.class.getPackage()))
              .addKeepRules(
                  "-keep class " + TestKeepAttributes.class.getTypeName() + " {",
                  "  <init>();", // Add <init>() so it does not become a compatibility rule below.
                  "  public static void main(java.lang.String[]);",
                  "}",
                  keepRules)
              .addOptionsModification(options -> options.enableClassInlining = false)
              .enableSideEffectAnnotations()
              .compile()
              .run(TestKeepAttributes.class)
              .assertSuccessWithOutput(innerClasses || enclosingMethod ? "1" : "0")
              .inspector();
    } catch (CompilationFailedException e) {
      assertTrue(!forceProguardCompatibility && (!innerClasses || !enclosingMethod));
      return;
    }

    ClassSubject clazz = inspector.clazz(TestKeepAttributes.class);
    assertThat(clazz, isPresent());
    if (innerClasses || enclosingMethod) {
      assertFalse(clazz.getDexClass().getInnerClasses().isEmpty());
    } else {
      assertTrue(clazz.getDexClass().getInnerClasses().isEmpty());
    }
  }

  @Test
  public void keepAttributesTest() throws Exception {
    testKeepAttributes(true, false, false);
    testKeepAttributes(true, true, false);
    testKeepAttributes(true, false, true);
    testKeepAttributes(true, true, true);
    testKeepAttributes(false, false, false);
    testKeepAttributes(false, true, false);
    testKeepAttributes(false, false, true);
    testKeepAttributes(false, true, true);
  }

  private void runKeepDefaultMethodsTest(
      List<String> additionalKeepRules,
      Consumer<CodeInspector> inspection,
      Consumer<GraphInspector> compatInspection)
      throws Exception {
    Class mainClass = TestClass.class;
    CompatProguardCommandBuilder builder = new CompatProguardCommandBuilder();
    builder.addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()));
    builder.addProguardConfiguration(ImmutableList.of(
        "-keep class " + mainClass.getCanonicalName() + "{",
        "  public <init>();",
        "  public static void main(java.lang.String[]);",
        "}",
        "-dontobfuscate"),
        Origin.unknown());
    builder.addProguardConfiguration(additionalKeepRules, Origin.unknown());
    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
    CollectingGraphConsumer graphConsumer = new CollectingGraphConsumer(null);
    builder.setKeptGraphConsumer(graphConsumer);
    if (backend == Backend.DEX) {
      builder.setMinApiLevel(AndroidApiLevel.O.getLevel());
    }
    AndroidApp app =
        ToolHelper.runR8(
            builder.build(),
            o -> {
              o.enableClassInlining = false;

              // Prevent InterfaceWithDefaultMethods from being merged into
              // ClassImplementingInterface.
              o.enableVerticalClassMerging = false;
            });

    CodeInspector inspector = new CodeInspector(app);
    GraphInspector graphInspector = new GraphInspector(graphConsumer, inspector);
    inspection.accept(inspector);
    compatInspection.accept(graphInspector);
  }

  private void noCompatibilityRules(GraphInspector inspector) {
    inspector.assertNoPureCompatibilityEdges();
  }

  private void defaultMethodKept(CodeInspector inspector) {
    ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
    assertTrue(clazz.isPresent());
    MethodSubject method = clazz.method("int", "method", ImmutableList.of());
    assertTrue(method.isPresent());
    assertFalse(method.isAbstract());
  }

  private void defaultMethodCompatibilityRules(GraphInspector inspector) {
    // The enqueuer does not add an edge for the referenced => kept edges so we cant check compat.
  }

  private void defaultMethod2Kept(CodeInspector inspector) {
    ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
    assertTrue(clazz.isPresent());
    MethodSubject method =
        clazz.method("void", "method2", ImmutableList.of("java.lang.String", "int"));
    assertTrue(method.isPresent());
    assertFalse(method.isAbstract());
  }

  private void defaultMethod2CompatibilityRules(GraphInspector inspector) {
    // The enqueuer does not add an edge for the referenced => kept edges so we cant check compat.
  }

  @Test
  public void keepDefaultMethodsTest() throws Exception {
    runKeepDefaultMethodsTest(ImmutableList.of(
        "-keep interface " + InterfaceWithDefaultMethods.class.getCanonicalName() + "{",
        "  public int method();",
        "}"
    ), this::defaultMethodKept, this::noCompatibilityRules);
    runKeepDefaultMethodsTest(ImmutableList.of(
        "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
        "  <methods>;",
        "}",
        "-keep class " + TestClass.class.getCanonicalName() + "{",
        "  public void useInterfaceMethod();",
        "}"
    ), this::defaultMethodKept, this::defaultMethodCompatibilityRules);
    runKeepDefaultMethodsTest(ImmutableList.of(
        "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
        "  <methods>;",
        "}",
        "-keep class " + TestClass.class.getCanonicalName() + "{",
        "  public void useInterfaceMethod2();",
        "}"
    ), this::defaultMethod2Kept, this::defaultMethod2CompatibilityRules);
  }
}
