/*
 * Copyright 2008 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.tools.apichecker;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.dev.javac.impl.StaticJavaResource;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;

import junit.framework.TestCase;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Base class for all the ApiCompatibility Testing. Encapsulates two api
 * containers and a test method.
 * 
 */
public class ApiCompatibilityUnitTest extends TestCase {

  /**
   * Mock class to test if the correct ApiChange(s) are being returned.
   * 
   */
  static class MockApiElement implements ApiElement {

    final String signature;

    public MockApiElement(String signature) {
      this.signature = signature;
    }

    public String getRelativeSignature() {
      return signature;
    }
  }

  private static class FinalKeywordRefactoring {
    private static String getFirstApiSourceForObject() {
      StringBuffer sb = new StringBuffer();
      sb.append("package java.lang;\n");
      sb.append("public final class Object {\n");
      sb.append("\tpublic Object foo;\n");
      sb.append("\tpublic void bar() {}\n");
      sb.append("}\n");
      return sb.toString();
    }

    private static String getSecondApiSourceForObject() {
      StringBuffer sb = new StringBuffer();
      sb.append("package java.lang;\n");
      sb.append("public class Object {\n");
      sb.append("\tpublic final Object foo;\n");
      sb.append("\tpublic final void bar() {}\n");
      sb.append("}\n");
      return sb.toString();
    }

    void testBothWays() throws NotFoundException, UnableToCompleteException {
      Map<String, String> firstApi = new HashMap<String, String>();
      firstApi.put("java.lang.Object", getFirstApiSourceForObject());
      Map<String, String> secondApi = new HashMap<String, String>();
      secondApi.put("java.lang.Object", getSecondApiSourceForObject());

      // firstApi is the reference Api
      Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
      assertEquals(Arrays.asList(new ApiChange[] {new ApiChange(
          new MockApiElement("java.lang.Object::foo"),
          ApiChange.Status.FINAL_ADDED),}), apiChanges);

      // secondApi is the reference Api
      apiChanges = getApiChanges(secondApi, firstApi);
      assertEquals(
          Arrays.asList(new ApiChange[] {new ApiChange(new MockApiElement(
              "java.lang.Object"), ApiChange.Status.FINAL_ADDED),}), apiChanges);
    }
  }

  /**
   * Test when method overloading results in Api incompatibilities.
   * <p>
   * Imagine a class Foo had a method foo(String ..). If in the new Api, a
   * method foo(Integer ..) is added, ApiChecker should output a
   * OVERLOADED_METHOD_CALL Api change (because foo(null) cannot be compiled).
   * However, if foo(Object ..) is added, it should be okay since JLS matches
   * from the most specific to the least specific.
   */
  private static class OverloadedMethodRefactoring {
    private static String getFirstApiSourceForObject() {
      StringBuffer sb = new StringBuffer();
      sb.append("package java.lang;\n");
      sb.append("public class Object {\n");
      sb.append("\tstatic class Foo extends java.lang.Object {\n");
      sb.append("\t}\n");
      sb.append("\tstatic class Bar extends java.lang.Object {\n");
      sb.append("\t}\n");
      sb.append("\tpublic void fooObject(Foo x){}\n");
      sb.append("\tpublic void fooBar(Foo y){}\n");
      sb.append("}\n");
      return sb.toString();
    }

    private static String getSecondApiSourceForObject() {
      StringBuffer sb = new StringBuffer();
      sb.append("package java.lang;\n");
      sb.append("public class Object {\n");
      sb.append("\tstatic class Foo extends java.lang.Object {\n");
      sb.append("\t}\n");
      sb.append("\tstatic class Bar extends java.lang.Object {\n");
      sb.append("\t}\n");
      sb.append("\tpublic void fooObject(Foo x){}\n");
      sb.append("\tpublic void fooObject(Object x){}\n");
      sb.append("\tpublic void fooBar(Foo y){}\n");
      sb.append("\tpublic void fooBar(Bar y){}\n");
      sb.append("}\n");
      return sb.toString();
    }

    void testBothWays() throws NotFoundException, UnableToCompleteException {
      Map<String, String> firstApi = new HashMap<String, String>();
      firstApi.put("java.lang.Object", getFirstApiSourceForObject());
      Map<String, String> secondApi = new HashMap<String, String>();
      secondApi.put("java.lang.Object", getSecondApiSourceForObject());

      // firstApi is the reference Api
      Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
      assertEquals(
          Arrays.asList(new ApiChange[] {new ApiChange(new MockApiElement(
              "java.lang.Object::fooBar(Ljava/lang/Object$Foo;)"),
              ApiChange.Status.OVERLOADED_METHOD_CALL),}), apiChanges);

      // secondApi is the reference Api
      apiChanges = getApiChanges(secondApi, firstApi);
      assertEquals(Arrays.asList(new ApiChange[] {
          new ApiChange(new MockApiElement(
              "java.lang.Object::fooBar(Ljava/lang/Object$Bar;)"),
              ApiChange.Status.MISSING),
          new ApiChange(new MockApiElement(
              "java.lang.Object::fooObject(Ljava/lang/Object;)"),
              ApiChange.Status.MISSING),}), apiChanges);
    }
  }

  /**
   * Test whether the ApiChecker correctly identifies moving fields and methods
   * to a super class.
   * 
   */
  private static class SuperClassRefactoring {
    private static String getFirstApiSourceForObject() {
      StringBuffer sb = new StringBuffer();
      sb.append("package java.lang;\n");
      sb.append("public class Object {\n");
      sb.append("\t\tpublic static void staticMethod(){}\n");
      sb.append("\t\tpublic static int staticField = 1;\n");
      sb.append("\t\tpublic int instanceField = 2;\n");
      sb.append("\tpublic static class Foo extends java.lang.Object {\n");
      sb.append("\t}\n");
      sb.append("}\n");
      return sb.toString();
    }

    private static String getSecondApiSourceForObject() {
      StringBuffer sb = new StringBuffer();
      sb.append("package java.lang;\n");
      sb.append("public class Object {\n");
      sb.append("\tpublic static class Foo extends java.lang.Object {\n");
      sb.append("\t\tpublic static void staticMethod(){}\n");
      sb.append("\t\tpublic static int staticField = 1;\n");
      sb.append("\t\tpublic int instanceField = 2;\n");
      sb.append("\t}\n");
      sb.append("}\n");
      return sb.toString();
    }

    void testBothWays() throws NotFoundException, UnableToCompleteException {
      Map<String, String> firstApi = new HashMap<String, String>();
      firstApi.put("java.lang.Object", getFirstApiSourceForObject());
      Map<String, String> secondApi = new HashMap<String, String>();
      secondApi.put("java.lang.Object", getSecondApiSourceForObject());

      // firstApi is the reference Api
      Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
      assertEquals(Arrays.asList(new ApiChange[] {
          new ApiChange(new MockApiElement("java.lang.Object::instanceField"),
              ApiChange.Status.MISSING),
          new ApiChange(new MockApiElement("java.lang.Object::staticField"),
              ApiChange.Status.MISSING),
          new ApiChange(new MockApiElement("java.lang.Object::staticMethod()"),
              ApiChange.Status.MISSING),}), apiChanges);

      // secondApi is the reference Api
      apiChanges = getApiChanges(secondApi, firstApi);
      assertEquals(0, apiChanges.size());
    }
  }

  /**
   * Assert that two ApiChanges are equal.
   */
  static void assertEquals(ApiChange apiChange1, ApiChange apiChange2) {
    assert apiChange1 != null;
    assert apiChange2 != null;
    assertEquals(apiChange1.getStatus(), apiChange2.getStatus());
    assertEquals(apiChange1.getApiElement().getRelativeSignature(),
        apiChange2.getApiElement().getRelativeSignature());
  }

  /**
   * Assert that two sets of ApiChanges are equal.
   */
  static void assertEquals(Collection<ApiChange> collection1,
      Collection<ApiChange> collection2) {
    assertEquals(collection1.size(), collection2.size());

    List<ApiChange> list1 = new ArrayList<ApiChange>();
    list1.addAll(collection1);
    Collections.sort(list1);

    List<ApiChange> list2 = new ArrayList<ApiChange>();
    list2.addAll(collection2);
    Collections.sort(list2);

    for (int i = 0; i < list1.size(); i++) {
      assertEquals(list1.get(i), list2.get(i));
    }
  }

  /**
   * Returns the apiChanges from moving to an existing api to a new Api.
   * 
   * @param existingTypesToSourcesMap existing Api
   * @param newTypesToSourcesMap new Api
   * @return A collection of ApiChange
   */
  static Collection<ApiChange> getApiChanges(
      Map<String, String> existingTypesToSourcesMap,
      Map<String, String> newTypesToSourcesMap)
      throws UnableToCompleteException, NotFoundException {

    AbstractTreeLogger logger = new PrintWriterTreeLogger();
    logger.setMaxDetail(TreeLogger.ERROR);

    Set<Resource> set1 = new HashSet<Resource>();
    for (Map.Entry<String, String> entry : existingTypesToSourcesMap.entrySet()) {
      set1.add(new StaticJavaResource(entry.getKey(), entry.getValue()));
    }
    Set<String> emptyList = Collections.emptySet();
    Set<Resource> set2 = new HashSet<Resource>();
    for (String type : existingTypesToSourcesMap.keySet()) {
      set2.add(new StaticJavaResource(type, newTypesToSourcesMap.get(type)));
    }

    ApiContainer existingApi = new ApiContainer("existingApi", set1, emptyList,
        logger);
    ApiContainer newApi = new ApiContainer("newApi", set2, emptyList, logger);
    return ApiCompatibilityChecker.getApiDiff(newApi, existingApi, emptyList);
  }

  public void testFinalKeywordRefactoring() throws NotFoundException,
      UnableToCompleteException {
    new FinalKeywordRefactoring().testBothWays();
  }

  public void testMethodOverloading() throws NotFoundException,
      UnableToCompleteException {
    new OverloadedMethodRefactoring().testBothWays();
  }

  public void testSuperClassRefactoring() throws NotFoundException,
      UnableToCompleteException {
    new SuperClassRefactoring().testBothWays();
  }

}
