// 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.ListUtils;
import com.android.tools.r8.utils.dexinspector.ClassSubject;
import com.android.tools.r8.utils.dexinspector.DexInspector;
import com.android.tools.r8.utils.dexinspector.MethodSubject;
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.Test;
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;
  }

}
