// 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.naming;

import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.DescriptorUtils.isValidJavaType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.code.ConstString;
import com.android.tools.r8.code.ConstStringJumbo;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

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

  private final String appFileName;
  private final List<String> keepRulesFiles;
  private final Consumer<DexInspector> inspection;

  public IdentifierMinifierTest(
      String test,
      List<String> keepRulesFiles,
      Consumer<DexInspector> inspection) {
    this.appFileName = ToolHelper.EXAMPLES_BUILD_DIR + test + "/classes.dex";
    this.keepRulesFiles = keepRulesFiles;
    this.inspection = inspection;
  }

  private AndroidApp processedApp;

  @Before
  public void generateR8ProcessedApp() throws Exception {
    Path out = temp.getRoot().toPath();
    R8Command.Builder builder =
        ToolHelper.addProguardConfigurationConsumer(
            R8Command.builder(),
            pgConfig -> {
              pgConfig.setPrintMapping(true);
              pgConfig.setPrintMappingFile(out.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE));
            })
            .setOutput(out, OutputMode.DexIndexed)
            .addProguardConfigurationFiles(ListUtils.map(keepRulesFiles, Paths::get))
            .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
    ToolHelper.getAppBuilder(builder).addProgramFiles(Paths.get(appFileName));
    processedApp = ToolHelper.runR8(builder.build(), o -> o.debug = false);
  }

  @Test
  public void identiferMinifierTest() throws Exception {
    DexInspector dexInspector = new DexInspector(processedApp);
    inspection.accept(dexInspector);
  }

  @Parameters(name = "test: {0} keep: {1}")
  public static Collection<Object[]> data() {
    List<String> tests = Arrays.asList(
        "adaptclassstrings",
        "atomicfieldupdater",
        "forname",
        "getmembers",
        "identifiernamestring");

    Map<String, Consumer<DexInspector>> inspections = new HashMap<>();
    inspections.put("adaptclassstrings:keep-rules-1.txt", IdentifierMinifierTest::test1_rule1);
    inspections.put("adaptclassstrings:keep-rules-2.txt", IdentifierMinifierTest::test1_rule2);
    inspections.put(
        "atomicfieldupdater:keep-rules.txt", IdentifierMinifierTest::test_atomicfieldupdater);
    inspections.put("forname:keep-rules.txt", IdentifierMinifierTest::test_forname);
    inspections.put("getmembers:keep-rules.txt", IdentifierMinifierTest::test_getmembers);
    inspections.put("identifiernamestring:keep-rules-1.txt", IdentifierMinifierTest::test2_rule1);
    inspections.put("identifiernamestring:keep-rules-2.txt", IdentifierMinifierTest::test2_rule2);
    inspections.put("identifiernamestring:keep-rules-3.txt", IdentifierMinifierTest::test2_rule3);

    return NamingTestBase.createTests(tests, inspections);
  }

  // Without -adaptclassstrings
  private static void test1_rule1(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("adaptclassstrings.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    Code mainCode = main.getMethod().getCode();
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);
    int renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, mainCode.asDexCode().instructions);
    assertEquals(0, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("adaptclassstrings.A");
    MethodSubject bar = aClass.method("void", "bar", ImmutableList.of());
    Code barCode = bar.getMethod().getCode();
    verifyPresenceOfConstString(barCode.asDexCode().instructions);
    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, barCode.asDexCode().instructions);
    assertEquals(0, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexClass().staticFields());
    assertEquals(0, renamedYetFoundIdentifierCount);
  }

  // With -adaptclassstrings *.*A
  private static void test1_rule2(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("adaptclassstrings.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    Code mainCode = main.getMethod().getCode();
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);
    int renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, mainCode.asDexCode().instructions);
    assertEquals(0, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("adaptclassstrings.A");
    MethodSubject bar = aClass.method("void", "bar", ImmutableList.of());
    Code barCode = bar.getMethod().getCode();
    verifyPresenceOfConstString(barCode.asDexCode().instructions);
    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, barCode.asDexCode().instructions);
    assertEquals(1, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexClass().staticFields());
    assertEquals(1, renamedYetFoundIdentifierCount);
  }

  private static void test_atomicfieldupdater(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("atomicfieldupdater.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    Code mainCode = main.getMethod().getCode();
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);

    ClassSubject a = inspector.clazz("atomicfieldupdater.A");
    Set<Instruction> constStringInstructions =
        getRenamedMemberIdentifierConstStrings(a, mainCode.asDexCode().instructions);
    assertEquals(3, constStringInstructions.size());
  }

  private static void test_forname(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("forname.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    Code mainCode = main.getMethod().getCode();
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);
    int renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, mainCode.asDexCode().instructions);
    assertEquals(1, renamedYetFoundIdentifierCount);
  }

  private static void test_getmembers(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("getmembers.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    Code mainCode = main.getMethod().getCode();
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);

    ClassSubject a = inspector.clazz("getmembers.A");
    Set<Instruction> constStringInstructions =
        getRenamedMemberIdentifierConstStrings(a, mainCode.asDexCode().instructions);
    assertEquals(2, constStringInstructions.size());

    ClassSubject b = inspector.clazz("getmembers.B");
    MethodSubject inliner = b.method("java.lang.String", "inliner", ImmutableList.of());
    Code inlinerCode = inliner.getMethod().getCode();
    constStringInstructions =
        getRenamedMemberIdentifierConstStrings(a, inlinerCode.asDexCode().instructions);
    assertEquals(1, constStringInstructions.size());
  }

  // Without -identifiernamestring
  private static void test2_rule1(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    Code mainCode = main.getMethod().getCode();
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);
    int renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, mainCode.asDexCode().instructions);
    assertEquals(0, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("identifiernamestring.A");
    MethodSubject aInit =
        aClass.method("void", "<init>", ImmutableList.of());
    Code initCode = aInit.getMethod().getCode();
    verifyPresenceOfConstString(initCode.asDexCode().instructions);
    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, initCode.asDexCode().instructions);
    assertEquals(0, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexClass().staticFields());
    assertEquals(0, renamedYetFoundIdentifierCount);
  }

  // With -identifiernamestring for annotations and name-based filters
  private static void test2_rule2(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    assertTrue(main.isPresent());
    Code mainCode = main.getMethod().getCode();
    assertTrue(mainCode.isDexCode());
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);
    int renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, mainCode.asDexCode().instructions);
    assertEquals(1, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("identifiernamestring.A");
    MethodSubject aInit =
        aClass.method("void", "<init>", ImmutableList.of());
    Code initCode = aInit.getMethod().getCode();
    verifyPresenceOfConstString(initCode.asDexCode().instructions);
    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, initCode.asDexCode().instructions);
    assertEquals(1, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexClass().staticFields());
    assertEquals(2, renamedYetFoundIdentifierCount);
  }

  // With -identifiernamestring for reflective methods
  private static void test2_rule3(DexInspector inspector) {
    ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
    MethodSubject main = mainClass.method(DexInspector.MAIN);
    assertTrue(main.isPresent());
    Code mainCode = main.getMethod().getCode();
    assertTrue(mainCode.isDexCode());
    verifyPresenceOfConstString(mainCode.asDexCode().instructions);

    ClassSubject b = inspector.clazz("identifiernamestring.B");
    Set<Instruction> constStringInstructions =
        getRenamedMemberIdentifierConstStrings(b, mainCode.asDexCode().instructions);
    assertEquals(2, constStringInstructions.size());
  }

  private static void verifyPresenceOfConstString(Instruction[] instructions) {
    boolean presence =
        Arrays.stream(instructions)
            .anyMatch(instr -> instr instanceof ConstString || instr instanceof ConstStringJumbo);
    assertTrue(presence);
  }

  private static String retrieveString(Instruction instr) {
    if (instr instanceof ConstString) {
      ConstString cnst = (ConstString) instr;
      return cnst.getString().toString();
    } else if (instr instanceof ConstStringJumbo) {
      ConstStringJumbo cnst = (ConstStringJumbo) instr;
      return cnst.getString().toString();
    }
    return null;
  }

  private static Stream<Instruction> getConstStringInstructions(Instruction[] instructions) {
    return Arrays.stream(instructions)
        .filter(instr -> instr instanceof ConstString || instr instanceof ConstStringJumbo);
  }

  private static int countRenamedClassIdentifier(
      DexInspector inspector, Instruction[] instructions) {
    return getConstStringInstructions(instructions)
        .reduce(0, (cnt, instr) -> {
          String cnstString = retrieveString(instr);
          assertNotNull(cnstString);
          if (isValidJavaType(cnstString)) {
            ClassSubject classSubject = inspector.clazz(cnstString);
            if (classSubject.isRenamed()
                && descriptorToJavaType(classSubject.getFinalDescriptor()).equals(cnstString)) {
              return cnt + 1;
            }
          }
          return cnt;
        }, Integer::sum);
  }

  private static int countRenamedClassIdentifier(
      DexInspector inspector, DexEncodedField[] fields) {
    return Arrays.stream(fields)
        .filter(encodedField -> encodedField.getStaticValue() instanceof DexValueString)
        .reduce(0, (cnt, encodedField) -> {
          String cnstString =
              ((DexValueString) encodedField.getStaticValue()).getValue().toString();
          if (isValidJavaType(cnstString)) {
            ClassSubject classSubject = inspector.clazz(cnstString);
            if (classSubject.isRenamed()
                && descriptorToJavaType(classSubject.getFinalDescriptor()).equals(cnstString)) {
              return cnt + 1;
            }
          }
          return cnt;
        }, Integer::sum);
  }

  private static Set<Instruction> getRenamedMemberIdentifierConstStrings(
      ClassSubject clazz, Instruction[] instructions) {
    Set<Instruction> result = Sets.newIdentityHashSet();
    getConstStringInstructions(instructions).forEach(instr -> {
      String cnstString = retrieveString(instr);
      clazz.forAllMethods(foundMethodSubject -> {
        if (foundMethodSubject.getFinalSignature().name.equals(cnstString)) {
          result.add(instr);
        }
      });
      clazz.forAllFields(foundFieldSubject -> {
        if (foundFieldSubject.getFinalSignature().name.equals(cnstString)) {
          result.add(instr);
        }
      });
    });
    return result;
  }

}
