/*
 * Copyright 2014 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.cfg.LibraryGroup;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.ResourceLoader;
import com.google.gwt.dev.cfg.ResourceLoaders;
import com.google.gwt.dev.util.UnitTestTreeLogger;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.io.Files;
import com.google.gwt.thirdparty.guava.common.io.Resources;

import junit.framework.TestCase;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Test for {@link IncrementalBuilder}.
 */
public class IncrementalBuilderTest extends TestCase {

  private static void assertBuildResult(String rootModuleName, boolean expectedBuildSuccess,
      String... expectedErrorMessages) throws MalformedURLException {
    UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
    for (String expectedErrorMessage : expectedErrorMessages) {
      loggerBuilder.expectError(expectedErrorMessage, null);
    }
    UnitTestTreeLogger testLogger = loggerBuilder.createLogger();

    IncrementalBuilder incrementalBuilder =
        createIncrementalBuilder(rootModuleName, createGwtClassPathResourceLoader());
    incrementalBuilder.clean();

    boolean actualBuildSuccess = incrementalBuilder.build(testLogger).isSuccess();

    assertEquals(expectedBuildSuccess, actualBuildSuccess);
    testLogger.assertLogEntriesContainExpected();
  }

  private static ResourceLoader createGwtClassPathResourceLoader() throws MalformedURLException {
    String gwtClassPathProperty = System.getProperty("gwt.cp");
    String[] gwtClassPathStrings = gwtClassPathProperty.split(";");
    final List<URL> gwtClassPathEntries = Lists.newArrayList();
    for (String gwtClassPathString : gwtClassPathStrings) {
      gwtClassPathEntries.add(new File(gwtClassPathString).toURI().toURL());
    }
    ResourceLoader gwtClassPathResourceLoader = new ResourceLoader() {
        @Override
      public List<URL> getClassPath() {
        return gwtClassPathEntries;
      }

        @Override
      public URL getResource(String resourceName) {
        return Thread.currentThread().getContextClassLoader().getResource(resourceName);
      }
    };
    return gwtClassPathResourceLoader;
  }

  private static ResourceLoader createGwtClassPathResourceLoaderWithMocks(
      String... mockResourceNames) throws FileNotFoundException, IOException {
    final ResourceLoader gwtClassPathResourceLoader = createGwtClassPathResourceLoader();
    File mockResourcesDirectory = Files.createTempDir();

    for (String mockResourceName : mockResourceNames) {
      File mockFooFile = new File(mockResourcesDirectory, mockResourceName);
      mockFooFile.getParentFile().mkdirs();
      URL realFooResource = gwtClassPathResourceLoader.getResource(mockResourceName);
      Resources.copy(realFooResource, new FileOutputStream(mockFooFile));
    }

    return ResourceLoaders.forPathAndFallback(Lists.newArrayList(mockResourcesDirectory),
        gwtClassPathResourceLoader);
  }

  private static IncrementalBuilder createIncrementalBuilder(String rootModuleName,
      ResourceLoader resourceLoader) {
    String warDir = Files.createTempDir().getAbsolutePath();
    String libDir = "/tmp/gwt/lib";
    String genDir = "/tmp/gwt/gen";
    IncrementalBuilder incrementalBuilder =
        new IncrementalBuilder(rootModuleName, warDir, libDir, genDir, resourceLoader);
    return incrementalBuilder;
  }

  public void testBuildRebuildEditRebuild() throws FileNotFoundException, IOException {
    // Setup logging expectations for a full compile with no caching.
    UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage("com.google.gwt.core.Core"),
        null);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleBottom"), null);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleMid"), null);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleTop"), null);
    UnitTestTreeLogger testLogger = loggerBuilder.createLogger();

    // Prepare the compiler.
    ResourceLoader resourceLoader = createGwtClassPathResourceLoaderWithMocks(
        "com/google/gwt/dev/testdata/incrementalbuildsystem/Foo.java");
    IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleTop", resourceLoader);
    incrementalBuilder.clean();

    // Compile.
    boolean actualBuildSuccess = incrementalBuilder.build(testLogger).isSuccess();

    // Assert compile succeeded and was a full compile with no caching.
    assertEquals(true, actualBuildSuccess);
    testLogger.assertLogEntriesContainExpected();

    // Setup logging expectations for a fully cached compile.
    loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
    loggerBuilder.expectInfo(IncrementalBuilder.NO_FILES_HAVE_CHANGED, null);
    testLogger = loggerBuilder.createLogger();

    // Recompile without changes.
    actualBuildSuccess = incrementalBuilder.rebuild(testLogger).isSuccess();

    // Assert compile succeeded and was fully cached.
    assertEquals(true, actualBuildSuccess);
    testLogger.assertLogEntriesContainExpected();

    // Change modification date of the Foo.java seen by SimpleMid.gwt.xml
    File fooFile = new File(resourceLoader.getResource(
        "com/google/gwt/dev/testdata/incrementalbuildsystem/Foo.java").getPath());
    fooFile.setLastModified(System.currentTimeMillis() + 60 * 1000);

    // Setup logging expectations for partially cached recompile.
    loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.SPAM);
    loggerBuilder.expectSpam(
        BuildTarget.formatReusingCachedLibraryMessage("com.google.gwt.core.Core"), null);
    loggerBuilder.expectSpam(BuildTarget.formatReusingCachedLibraryMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleBottom"), null);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleMid"), null);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SimpleTop"), null);
    testLogger = loggerBuilder.createLogger();

    // Recompile with changes.
    actualBuildSuccess = incrementalBuilder.rebuild(testLogger).isSuccess();

    // Assert compile succeeded and was partially cached.
    assertEquals(true, actualBuildSuccess);
    testLogger.assertLogEntriesContainExpected();
  }

  public void testCircularReference() throws MalformedURLException {
    List<String> circularModulePath = Arrays.asList(new String[] {
        "com.google.gwt.dev.testdata.incrementalbuildsystem.CircularRoot",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.CircularB <loop>",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.CircularC",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.CircularFilesetD <fileset>",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.CircularB <loop>"});
    assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.CircularRoot", false,
        IncrementalBuilder.formatCircularModulePathMessage(circularModulePath));
  }

  public void testContinuesAfterFirstFailure() throws MalformedURLException {
    UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.INFO);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.MultipleFailLeft"), null);
    loggerBuilder.expectInfo(BuildTarget.formatCompilingModuleMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.MultipleFailRight"), null);
    UnitTestTreeLogger testLogger = loggerBuilder.createLogger();

    IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.MultipleFailTop",
        createGwtClassPathResourceLoader());
    incrementalBuilder.clean();

    boolean buildSucceeded = incrementalBuilder.build(testLogger).isSuccess();
    assertFalse(buildSucceeded);
    testLogger.assertLogEntriesContainExpected();
  }

  // TODO: Behavior depends on the generator running multiple times. Re-enable after we introduce
  // @RunsLocal again.
  public void _disabled_testDuplicateGeneratorOutput() throws MalformedURLException {
    String duplicateCompilationUnitError = LibraryGroup.formatDuplicateCompilationUnitMessage(
        "com.google.gwt.dev.Bar", "com.google.gwt.dev.testdata.incrementalbuildsystem.ParallelLeft",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.ParallelRight");
    assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.ParallelRoot", false,
        duplicateCompilationUnitError);
  }

  public void testDuplicateSourceInclusion() throws MalformedURLException {
    String duplicateCompilationUnitError = LibraryGroup.formatDuplicateCompilationUnitMessage(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.Foo",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.DuplicateLeft",
        "com.google.gwt.dev.testdata.incrementalbuildsystem.DuplicateRight");
    assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.DuplicateRoot", false,
        duplicateCompilationUnitError);
  }

  public void testEntryPointWithFailedCrossModuleTypeReference() throws MalformedURLException {
    String victimTypeName =
        "com.google.gwt.dev.testdata.incrementalbuildsystem.EntryPointCompileFails";

    UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.TRACE);
    loggerBuilder.expectTrace("Tracing compile failure path for type '" + victimTypeName + "'",
        null);
    loggerBuilder.expectError(Pattern.compile("Errors in '.*EntryPointCompileFails\\.java'"), null);
    loggerBuilder.expectError("Line 24: ImmediateCompileFails cannot be resolved to a type", null);
    loggerBuilder.expectError(Pattern.compile("Errors in '.*ImmediateCompileFails\\.java'"), null);
    loggerBuilder.expectError("Line 20: List cannot be resolved to a type", null);
    UnitTestTreeLogger testLogger = loggerBuilder.createLogger();

    IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.CrossModuleCompileFails",
        createGwtClassPathResourceLoader());
    incrementalBuilder.clean();

    boolean buildSucceeded = incrementalBuilder.build(testLogger).isSuccess();
    assertFalse(buildSucceeded);
    testLogger.assertLogEntriesContainExpected();
  }

  public void testEntryPointWithFailedSameModuleTypeReference() throws MalformedURLException {
    String victimTypeName =
        "com.google.gwt.dev.testdata.incrementalbuildsystem.EntryPointCompileFails";
    String causeTypeName =
        "com.google.gwt.dev.testdata.incrementalbuildsystem.ImmediateCompileFails";

    UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder();
    loggerBuilder.setLowestLogLevel(TreeLogger.TRACE);
    loggerBuilder.expectTrace("Tracing compile failure path for type '" + victimTypeName + "'",
        null);
    loggerBuilder.expectError(Pattern.compile("Errors in '.*EntryPointCompileFails\\.java'"), null);
    loggerBuilder.expectError(causeTypeName + " cannot be resolved to a type", null);
    loggerBuilder.expectError(Pattern.compile("Errors in '.*ImmediateCompileFails\\.java'"), null);
    loggerBuilder.expectError("Line 20: List cannot be resolved to a type", null);
    UnitTestTreeLogger testLogger = loggerBuilder.createLogger();

    IncrementalBuilder incrementalBuilder = createIncrementalBuilder(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.SameModuleCompileFails",
        createGwtClassPathResourceLoader());
    incrementalBuilder.clean();

    boolean buildSucceeded = incrementalBuilder.build(testLogger).isSuccess();
    assertFalse(buildSucceeded);
    testLogger.assertLogEntriesContainExpected();
  }

  public void testIgnoresCompileFailuresInUnreachableTypes() throws MalformedURLException {
    assertBuildResult(
        "com.google.gwt.dev.testdata.incrementalbuildsystem.UnreachableTypeCompileFails", true);
  }

  public void testUnableToFindModule() throws MalformedURLException {
    String unableToFindModuleMessage = ModuleDefLoader.formatUnableToFindModuleMessage(
        "com/google/gwt/dev/testdata/incrementalbuildsystem/NoSuchModule.gwt.xml");
    assertBuildResult("com.google.gwt.dev.testdata.incrementalbuildsystem.NoSuchModule", false,
        unableToFindModuleMessage);
  }
}
