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

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;

import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class R8EntryPointTests extends TestBase {

  private static final String MAPPING = "mapping.txt";
  private static final String SEEDS = "seeds.txt";
  private static final Path INPUT_JAR =
      Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "minification" + FileUtils.JAR_EXTENSION);
  private static final Path PROGUARD_FLAGS =
      Paths.get(ToolHelper.EXAMPLES_DIR, "minification",  "keep-rules.txt");

  private Path testFlags;

  @Before
  public void setup() throws IOException {
    testFlags = temp.newFile("local.flags").toPath();
    FileUtils.writeTextFile(testFlags, ImmutableList.of(
        "-printseeds " + SEEDS,
        "-printmapping " + MAPPING));
  }

  @Test
  public void testRun1Dir() throws Exception {
    Path out = temp.newFolder("outdex").toPath();
    R8.run(getCommand(out));
    Assert.assertTrue(Files.isRegularFile(out.resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }

  @Test
  public void testRun1Zip() throws Exception {
    Path out = temp.newFolder("outdex").toPath().resolve("dex.zip");
    R8.run(getCommand(out));
    Assert.assertTrue(Files.isRegularFile(out));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }

  @Test
  public void testRun2Dir() throws Exception {
    Path out = temp.newFolder("outdex").toPath();
    ExecutorService executor = Executors.newWorkStealingPool(2);
    try {
      R8.run(getCommand(out), executor);
    } finally {
      executor.shutdown();
    }
    Assert.assertTrue(Files.isRegularFile(out.resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }

  @Test
  public void testRun2Zip() throws Exception {
    Path out = temp.newFolder("outdex").toPath().resolve("dex.zip");
    ExecutorService executor = Executors.newWorkStealingPool(2);
    try {
      R8.run(getCommand(out), executor);
    } finally {
      executor.shutdown();
    }
    Assert.assertTrue(Files.isRegularFile(out));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }

  @Test
  public void testMainDir() throws IOException, InterruptedException {
    Path out = temp.newFolder("outdex").toPath();
    ProcessResult r8 = ToolHelper.forkR8(Paths.get("."),
        "--lib", ToolHelper.getDefaultAndroidJar().toString(),
        "--output", out.toString(),
        "--pg-conf", PROGUARD_FLAGS.toString(),
        "--pg-conf", testFlags.toString(),
        INPUT_JAR.toString());
    Assert.assertEquals(0, r8.exitCode);
    Assert.assertTrue(Files.isRegularFile(out.resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }

  @Test
  public void testMainRelativeDir() throws IOException, InterruptedException {
    temp.newFolder("outdex");
    Path out = Paths.get("outdex");
    Path workingDir = temp.getRoot().toPath();
    ProcessResult r8 = ToolHelper.forkR8(workingDir,
        "--lib", ToolHelper.getDefaultAndroidJar().toAbsolutePath().toString(),
        "--output", out.toString(),
        "--pg-conf", PROGUARD_FLAGS.toAbsolutePath().toString(),
        "--pg-conf", testFlags.toAbsolutePath().toString(),
        INPUT_JAR.toAbsolutePath().toString());
    Assert.assertEquals(0, r8.exitCode);
    Assert.assertTrue(
        Files.isRegularFile(workingDir.resolve(out).resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }


  @Test
  public void testMainZip() throws IOException, InterruptedException {
    Path out = temp.newFolder("outdex").toPath().resolve("dex.zip");
    ProcessResult r8 = ToolHelper.forkR8(Paths.get("."),
        "--lib", ToolHelper.getDefaultAndroidJar().toString(),
        "--output", out.toString(),
        "--pg-conf", PROGUARD_FLAGS.toString(),
        "--pg-conf", testFlags.toString(),
        INPUT_JAR.toString());
    Assert.assertEquals(0, r8.exitCode);
    Assert.assertTrue(Files.isRegularFile(out));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
  }

  @Test
  public void testSpecifyClassfile() throws IOException, InterruptedException {
    Path out = temp.newFile("classfile.zip").toPath();
    ProcessResult r8 =
        ToolHelper.forkR8(
            Paths.get("."),
            "--lib",
            ToolHelper.getJava8RuntimeJar().toString(),
            "--classfile",
            "--output",
            out.toString(),
            "--pg-conf",
            PROGUARD_FLAGS.toString(),
            "--pg-conf",
            testFlags.toString(),
            INPUT_JAR.toString());
    Assert.assertEquals(0, r8.exitCode);
  }

  @Test
  public void testSpecifyDex() throws IOException, InterruptedException {
    Path out = temp.newFile("dex.zip").toPath();
    ProcessResult r8 =
        ToolHelper.forkR8(
            Paths.get("."),
            "--lib",
            ToolHelper.getDefaultAndroidJar().toString(),
            "--dex",
            "--output",
            out.toString(),
            "--pg-conf",
            PROGUARD_FLAGS.toString(),
            "--pg-conf",
            testFlags.toString(),
            INPUT_JAR.toString());
    Assert.assertEquals(0, r8.exitCode);
  }

  @Test
  public void testSpecifyDexAndClassfileNotAllowed() throws IOException, InterruptedException {
    Path out = temp.newFile("dex.zip").toPath();
    ProcessResult r8 =
        ToolHelper.forkR8(
            Paths.get("."),
            "--lib",
            ToolHelper.getDefaultAndroidJar().toString(),
            "--dex",
            "--classfile",
            "--output",
            out.toString(),
            "--pg-conf",
            PROGUARD_FLAGS.toString(),
            "--pg-conf",
            testFlags.toString(),
            INPUT_JAR.toString());
    Assert.assertEquals(1, r8.exitCode);
    assertThat(
        r8.stderr, containsString("Cannot compile in both --dex and --classfile output mode"));
  }

  private R8Command getCommand(Path out) throws IOException, CompilationFailedException {
    return R8Command.builder()
        .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
        .addProgramFiles(INPUT_JAR)
        .setOutput(out, OutputMode.DexIndexed)
        .addProguardConfigurationFiles(PROGUARD_FLAGS, testFlags)
        .build();
  }
}
