// 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.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.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 {

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

  @Rule
  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();

  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;
  }

  @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));
    ToolHelper.runR8(builder.build());
  }

  @Test
  public void identiferMinifierTest() throws Exception {
    Path out = temp.getRoot().toPath();
    DexInspector dexInspector =
        new DexInspector(
            out.resolve("classes.dex"),
            out.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE).toString());
    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());
  }

  // 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.staticValue instanceof DexValueString)
        .reduce(0, (cnt, encodedField) -> {
          String cnstString = ((DexValueString) encodedField.staticValue).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;
  }

}
