package com.episode6.hackit.mockspresso.plugin.javax;

import com.episode6.hackit.mockspresso.DefaultTestRunner;
import com.episode6.hackit.mockspresso.exception.MultipleInjectConstructorException;
import com.episode6.hackit.mockspresso.reflect.TypeToken;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.inject.Inject;
import javax.inject.Provider;
import java.lang.reflect.Constructor;

import static org.fest.assertions.api.Assertions.assertThat;

/**
 * Tests {@link JavaxInjectionConfig}
 */
@SuppressWarnings("unchecked")
@RunWith(DefaultTestRunner.class)
public class JavaxInjectionConfigTest {

  private final JavaxInjectionConfig mInjectionConfig = JavaxInjectionConfig.getInstance();

  @Test
  public void testHasOnlyInjectAnnotation() {
    assertThat(mInjectionConfig.provideInjectableFieldAnnotations()).containsOnly(Inject.class);
  }

  @Test
  public void testFindInjectConstructor() {
    Constructor<TestClassWithMultipleConstructorsButOnlyOneInject> constructor = mInjectionConfig.provideConstructorSelector()
        .chooseConstructor(TypeToken.of(TestClassWithMultipleConstructorsButOnlyOneInject.class));

    assertThat(constructor).isNotNull();
    assertThat(constructor.isAnnotationPresent(Inject.class)).isTrue();
    assertThat(constructor.getParameterCount()).isEqualTo(2);
  }

  @Test(expected = MultipleInjectConstructorException.class)
  public void testMultipleInjectConstructors() {
    Constructor<TestClassWithTwoInjectAnnotations> constructor = mInjectionConfig.provideConstructorSelector()
        .chooseConstructor(TypeToken.of(TestClassWithTwoInjectAnnotations.class));
  }

  @Test
  public void testFindFallbackConstructor() {
    Constructor<TestClassWithEmptyFallback> constructor = mInjectionConfig.provideConstructorSelector()
        .chooseConstructor(TypeToken.of(TestClassWithEmptyFallback.class));

    assertThat(constructor).isNotNull();
    assertThat(constructor.isAnnotationPresent(Inject.class)).isFalse();
    assertThat(constructor.getParameterCount()).isEqualTo(0);
  }

  @Test
  public void testNoValidConstructor() {
    Constructor<TestClassWithNoValidConstructor> constructor = mInjectionConfig.provideConstructorSelector()
        .chooseConstructor(TypeToken.of(TestClassWithNoValidConstructor.class));

    assertThat(constructor).isNull();
  }

  public static class TestClassWithMultipleConstructorsButOnlyOneInject {

    public TestClassWithMultipleConstructorsButOnlyOneInject() {}
    public TestClassWithMultipleConstructorsButOnlyOneInject(String testString) {}
    public TestClassWithMultipleConstructorsButOnlyOneInject(Runnable runnable) {}

    @Inject
    public TestClassWithMultipleConstructorsButOnlyOneInject(Runnable runnable, Provider<Runnable> runnableProvider) {}
  }

  public static class TestClassWithTwoInjectAnnotations {
    @Inject public TestClassWithTwoInjectAnnotations() {}
    @Inject public TestClassWithTwoInjectAnnotations(Runnable runnable) {}
  }

  public static class TestClassWithEmptyFallback {
    public TestClassWithEmptyFallback(Runnable runnable) {}
    public TestClassWithEmptyFallback() {}
    public TestClassWithEmptyFallback(Runnable runnable, String string) {}
  }

  public static class TestClassWithNoValidConstructor {
    public TestClassWithNoValidConstructor(Runnable runnable) {}
    public TestClassWithNoValidConstructor(Runnable runnable, String string) {}
    public TestClassWithNoValidConstructor(Runnable runnable, String string, Provider<String> stringProvider) {}
  }
}

@@ -2329,24 +2329,472 @@
 ull();%0A  %7D%0A%0A
+  @Test%0A  public void testFindFallbackConstructorWhenNoneDeclared() %7B%0A    Constructor%3CTestClassWithNoDefinedConstructors%3E constructor = mInjectionConfig.provideConstructorSelector()%0A        .chooseConstructor(TypeToken.of(TestClassWithNoDefinedConstructors.class));%0A%0A    assertThat(constructor).isNotNull();%0A    assertThat(constructor.isAnnotationPresent(Inject.class)).isFalse();%0A    assertThat(constructor.getParameterCount()).isEqualTo(0);%0A  %7D%0A%0A
   public sta
@@ -3973,11 +3973,72 @@
 ) %7B%7D%0A  %7D
+%0A%0A  public static class TestClassWithNoDefinedConstructors %7B%7D
 %0A%7D%0A

add a JavaxInjectionConfigTest to ensure we can get empty inherited constructors