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

import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static com.android.tools.r8.ToolHelper.EXAMPLES_BUILD_DIR;
import static com.android.tools.r8.ToolHelper.EXAMPLES_DIR;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;

import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
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 TreeShakingSpecificTest extends TestBase {

  private Backend backend;

  @Parameters(name = "Backend: {1}")
  public static List<Object[]> data() {
    return buildParameters(
        TestParametersBuilder.builder().withNoneRuntime().build(), Backend.values());
  }

  public TreeShakingSpecificTest(TestParameters parameters, Backend backend) {
    this.backend = backend;
    parameters.assertNoneRuntime();
  }

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

  private Path getProgramFiles(String test) {
    return Paths.get(EXAMPLES_BUILD_DIR, test + ".jar");
  }

  private byte[] getProgramDexFileData(String test) throws IOException {
    return Files.readAllBytes(Paths.get(EXAMPLES_BUILD_DIR, test, "classes.dex"));
  }

  private void finishBuild(R8Command.Builder builder, Path out, String test) throws IOException {
    Path input;
    if (backend == Backend.DEX) {
      builder.setOutput(out, OutputMode.DexIndexed);
      input = Paths.get(EXAMPLES_BUILD_DIR, test, "classes.dex");
    } else {
      builder.setOutput(out, OutputMode.ClassFile);
      input = Paths.get(EXAMPLES_BUILD_DIR, test + ".jar");
    }
    ToolHelper.getAppBuilder(builder).addProgramFiles(input);
  }

  @Test
  public void testIgnoreWarnings() throws Exception {
    // Generate R8 processed version without library option.
    String test = "shaking2";
    testForR8(backend)
        .applyIf(
            backend.isCf(),
            builder -> builder.addProgramFiles(getProgramFiles(test)),
            builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
        .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
        .addIgnoreWarnings()
        .compile();
  }

  @Test(expected = CompilationFailedException.class)
  public void testMissingLibrary() throws Exception {
    // Generate R8 processed version without library option.
    String test = "shaking2";
    testForR8(backend)
        .applyIf(
            backend.isCf(),
            builder -> builder.addProgramFiles(getProgramFiles(test)),
            builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
        .addLibraryFiles()
        .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
        .allowDiagnosticErrorMessages()
        .compileWithExpectedDiagnostics(
            diagnostics -> {
              diagnostics
                  .assertOnlyErrors()
                  .assertErrorsMatch(diagnosticType(MissingDefinitionsDiagnostic.class));

              MissingDefinitionsDiagnostic diagnostic =
                  (MissingDefinitionsDiagnostic) diagnostics.getErrors().get(0);
              assertThat(
                  diagnostic.getDiagnosticMessage(),
                  allOf(
                      containsString("Missing class java.io.PrintStream"),
                      containsString("Missing class java.lang.Object"),
                      containsString("Missing class java.lang.String"),
                      containsString("Missing class java.lang.StringBuilder"),
                      containsString("Missing class java.lang.System")));
            });
  }

  @Test
  public void testPrintMapping() throws Throwable {
    // Generate R8 processed version without library option.
    String test = "shaking1";
    testForR8(backend)
        .applyIf(
            backend.isCf(),
            builder -> builder.addProgramFiles(getProgramFiles(test)),
            builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
        .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
        .addOptionsModification(options -> options.enableInlining = false)
        .compile()
        .inspectProguardMap(
            proguardMap -> {
              // Remove comments.
              String actualMapping =
                  Stream.of(proguardMap.split("\n"))
                      .filter(line -> !line.startsWith("#"))
                      .collect(Collectors.joining("\n"));
              String refMapping =
                  new String(
                      Files.readAllBytes(
                          Paths.get(
                              EXAMPLES_DIR,
                              "shaking1",
                              "print-mapping-" + backend.name().toLowerCase() + ".ref")),
                      StandardCharsets.UTF_8);
              assertEquals(sorted(refMapping), sorted(actualMapping));
            });
  }

  private static String sorted(String str) {
    return new BufferedReader(new StringReader(str))
        .lines().sorted().filter(s -> !s.isEmpty()).collect(Collectors.joining("\n"));
  }
}
