// Copyright (C) 2014 The Android Open Source Project
//
// 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.gerrit.testing;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.util.stream.Collectors.toSet;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import org.junit.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
import org.junit.rules.TestRule;
import org.junit.runner.Runner;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Suite;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;

/**
 * Suite to run tests with different {@code gerrit.config} values.
 *
 * <p>For each {@link Config} method in the class and base classes, a new group of tests is created
 * with the {@link Parameter} field set to the config.
 *
 * <p>Additional actions can be executed before or after each group of tests using
 * {@literal @}BeforeConfig, {@literal @}AfterConfig or {@literal @}ConfigRule annotations.
 *
 * <pre>
 * {@literal @}RunWith(ConfigSuite.class)
 * public abstract class MyAbstractTest {
 *   {@literal @}ConfigSuite.Parameter
 *   protected Config cfg;
 *
 *   {@literal @}ConfigSuite.Config
 *   public static Config firstConfig() {
 *     Config cfg = new Config();
 *     cfg.setString("gerrit", null, "testValue", "a");
 *     return cfg;
 *   }
 * }
 *
 * public class MyTest extends MyAbstractTest {
 *   {@literal @}ConfigSuite.Config
 *   public static Config secondConfig() {
 *     Config cfg = new Config();
 *     cfg.setString("gerrit", null, "testValue", "b");
 *     return cfg;
 *   }
 *
 *   {@literal @}Test
 *   public void myTest() {
 *     // Test using cfg.
 *   }
 * }
 * </pre>
 *
 * This creates a suite of tests with three groups:
 *
 * <ul>
 *   <li><strong>default</strong>: {@code MyTest.myTest}
 *   <li><strong>firstConfig</strong>: {@code MyTest.myTest[firstConfig]}
 *   <li><strong>secondConfig</strong>: {@code MyTest.myTest[secondConfig]}
 * </ul>
 *
 * Additionally, config values used by <strong>default</strong> can be set in a method annotated
 * with {@code @ConfigSuite.Default}.
 *
 * <p>In addition groups of tests for different configurations can be defined by annotating a method
 * that returns a Map&lt;String, Config&gt; with {@link Configs}. The map keys define the test suite
 * names, while the values define the configurations for the test suites.
 *
 * <pre>
 * {@literal @}ConfigSuite.Configs
 * public static Map&lt;String, Config&gt; configs() {
 *   Config cfgA = new Config();
 *   cfgA.setString("gerrit", null, "testValue", "a");
 *   Config cfgB = new Config();
 *   cfgB.setString("gerrit", null, "testValue", "b");
 *   return ImmutableMap.of("testWithValueA", cfgA, "testWithValueB", cfgB);
 * }
 * </pre>
 *
 * <p>The name of the config method corresponding to the currently-running test can be stored in a
 * field annotated with {@code @ConfigSuite.Name}.
 */
public class ConfigSuite extends Suite {
  public static final String DEFAULT = "default";

  @Target({METHOD})
  @Retention(RUNTIME)
  public static @interface Default {}

  @Target({METHOD})
  @Retention(RUNTIME)
  public static @interface Config {}

  @Target({METHOD})
  @Retention(RUNTIME)
  public static @interface Configs {}

  @Target({FIELD})
  @Retention(RUNTIME)
  public static @interface Parameter {}

  @Target({FIELD})
  @Retention(RUNTIME)
  public static @interface Name {}

  /**
   * Annotation for methods which should be run after executing group of tests with a new
   * configuration.
   *
   * <p>Works similar to {@link org.junit.AfterClass}, but a method can be executed multiple times
   * if a test class provides multiple configs.
   */
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.METHOD)
  public @interface AfterConfig {}

  /**
   * Annotation for methods which should be run before executing group of tests with a new
   * configuration.
   *
   * <p>Works similar to {@link org.junit.BeforeClass}, but a method can be executed multiple times
   * if a test class provides multiple configs.
   */
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.METHOD)
  public @interface BeforeConfig {}

  /**
   * Annotation for fields or methods which wraps all tests with the same config
   *
   * <p>Works similar to {@link org.junit.ClassRule}, but Statement evaluates multiple time - ones
   * for each config provided by a test class.
   */
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.FIELD, ElementType.METHOD})
  public @interface ConfigRule {}

  private static class ConfigRunner extends BlockJUnit4ClassRunner {
    private final org.eclipse.jgit.lib.Config cfg;
    private final Field parameterField;
    private final Field nameField;
    private final String name;

    private ConfigRunner(
        Class<?> clazz,
        Field parameterField,
        Field nameField,
        String name,
        org.eclipse.jgit.lib.Config cfg)
        throws InitializationError {
      super(clazz);
      this.parameterField = parameterField;
      this.nameField = nameField;
      this.name = name;
      this.cfg = cfg;
    }

    @Override
    public Object createTest() throws Exception {
      Object test = getTestClass().getJavaClass().getDeclaredConstructor().newInstance();
      parameterField.set(test, new org.eclipse.jgit.lib.Config(cfg));
      if (nameField != null) {
        nameField.set(test, name);
      }
      return test;
    }

    @Override
    protected String getName() {
      return MoreObjects.firstNonNull(name, DEFAULT);
    }

    @Override
    protected String testName(FrameworkMethod method) {
      String n = method.getName();
      return name == null ? n : n + "[" + name + "]";
    }

    @Override
    protected Statement withBeforeClasses(Statement statement) {
      List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(BeforeConfig.class);
      return befores.isEmpty() ? statement : new RunBefores(statement, befores, null);
    }

    @Override
    protected Statement withAfterClasses(Statement statement) {
      List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods(AfterConfig.class);
      return afters.isEmpty() ? statement : new RunAfters(statement, afters, null);
    }

    @Override
    protected List<TestRule> classRules() {
      List<TestRule> result =
          getTestClass().getAnnotatedMethodValues(null, ConfigRule.class, TestRule.class);
      result.addAll(getTestClass().getAnnotatedFieldValues(null, ConfigRule.class, TestRule.class));
      return result;
    }
  }

  private static List<Runner> runnersFor(Class<?> clazz) {
    Method defaultConfig = getDefaultConfig(clazz);
    List<Method> configs = getConfigs(clazz);
    Map<String, org.eclipse.jgit.lib.Config> configMap =
        callConfigMapMethod(getConfigMap(clazz), configs);

    Field parameterField = getOnlyField(clazz, Parameter.class);
    checkArgument(parameterField != null, "No @ConfigSuite.Parameter found");
    Field nameField = getOnlyField(clazz, Name.class);
    List<Runner> result = Lists.newArrayListWithCapacity(configs.size() + 1);
    try {
      result.add(
          new ConfigRunner(
              clazz, parameterField, nameField, null, callConfigMethod(defaultConfig)));
      for (Method m : configs) {
        result.add(
            new ConfigRunner(clazz, parameterField, nameField, m.getName(), callConfigMethod(m)));
      }
      for (Map.Entry<String, org.eclipse.jgit.lib.Config> e : configMap.entrySet()) {
        result.add(new ConfigRunner(clazz, parameterField, nameField, e.getKey(), e.getValue()));
      }
      return result;
    } catch (InitializationError e) {
      System.err.println("Errors initializing runners:");
      for (Throwable t : e.getCauses()) {
        t.printStackTrace();
      }
      throw new RuntimeException(e);
    }
  }

  private static Method getDefaultConfig(Class<?> clazz) {
    return getAnnotatedMethod(clazz, Default.class);
  }

  private static Method getConfigMap(Class<?> clazz) {
    return getAnnotatedMethod(clazz, Configs.class);
  }

  private static <T extends Annotation> Method getAnnotatedMethod(
      Class<?> clazz, Class<T> annotationClass) {
    Method result = null;
    for (Method m : clazz.getMethods()) {
      T ann = m.getAnnotation(annotationClass);
      if (ann != null) {
        checkArgument(result == null, "Multiple methods annotated with %s: %s, %s", ann, result, m);
        result = m;
      }
    }
    return result;
  }

  private static List<Method> getConfigs(Class<?> clazz) {
    List<Method> result = Lists.newArrayListWithExpectedSize(3);
    for (Method m : clazz.getMethods()) {
      Config ann = m.getAnnotation(Config.class);
      if (ann != null) {
        checkArgument(!m.getName().equals(DEFAULT), "%s cannot be named %s", ann, DEFAULT);
        result.add(m);
      }
    }
    return result;
  }

  private static org.eclipse.jgit.lib.Config callConfigMethod(Method m) {
    if (m == null) {
      return new org.eclipse.jgit.lib.Config();
    }
    checkArgument(
        org.eclipse.jgit.lib.Config.class.isAssignableFrom(m.getReturnType()),
        "%s must return Config",
        m);
    checkArgument((m.getModifiers() & Modifier.STATIC) != 0, "%s must be static", m);
    checkArgument(m.getParameterTypes().length == 0, "%s must take no parameters", m);
    try {
      return (org.eclipse.jgit.lib.Config) m.invoke(null);
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      throw new IllegalArgumentException(e);
    }
  }

  private static Map<String, org.eclipse.jgit.lib.Config> callConfigMapMethod(
      Method m, List<Method> configs) {
    if (m == null) {
      return ImmutableMap.of();
    }
    checkArgument(Map.class.isAssignableFrom(m.getReturnType()), "%s must return Map", m);
    Type[] types = ((ParameterizedType) m.getGenericReturnType()).getActualTypeArguments();
    checkArgument(
        String.class.isAssignableFrom((Class<?>) types[0]),
        "The map returned by %s must have String as key",
        m);
    checkArgument(
        org.eclipse.jgit.lib.Config.class.isAssignableFrom((Class<?>) types[1]),
        "The map returned by %s must have Config as value",
        m);
    checkArgument((m.getModifiers() & Modifier.STATIC) != 0, "%s must be static", m);
    checkArgument(m.getParameterTypes().length == 0, "%s must take no parameters", m);
    try {
      @SuppressWarnings("unchecked")
      Map<String, org.eclipse.jgit.lib.Config> configMap =
          (Map<String, org.eclipse.jgit.lib.Config>) m.invoke(null);
      checkArgument(
          !configMap.containsKey(DEFAULT),
          "The map returned by %s cannot contain key %s (duplicate test suite name)",
          m,
          DEFAULT);
      for (String name : configs.stream().map(Method::getName).collect(toSet())) {
        checkArgument(
            !configMap.containsKey(name),
            "The map returned by %s cannot contain key %s (duplicate test suite name)",
            m,
            name);
      }
      return configMap;
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      throw new IllegalArgumentException(e);
    }
  }

  private static Field getOnlyField(Class<?> clazz, Class<? extends Annotation> ann) {
    List<Field> fields = Lists.newArrayListWithExpectedSize(1);
    for (Field f : clazz.getFields()) {
      if (f.getAnnotation(ann) != null) {
        fields.add(f);
      }
    }
    checkArgument(
        fields.size() <= 1,
        "expected 1 @ConfigSuite.%s field, found: %s",
        ann.getSimpleName(),
        fields);
    return Iterables.getFirst(fields, null);
  }

  public ConfigSuite(Class<?> clazz) throws InitializationError {
    super(clazz, runnersFor(clazz));
  }
}
