// Copyright 2007 Google Inc. All Rights Reserved.

package com.google.inject;

import static com.google.inject.Asserts.assertContains;
import junit.framework.TestCase;

import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

/**
 * Tests the error messages produced by Guice.
 *
 * @author Kevin Bourrillion
 */
public class ErrorMessagesTest extends TestCase {

  private class InnerClass {}

  public void testInjectInnerClass() throws Exception {
    Injector injector = Guice.createInjector();
    try {
      injector.getInstance(InnerClass.class);
      fail();
    } catch (Exception expected) {
      // TODO(kevinb): why does the source come out as unknown??
      assertContains(expected.getMessage(), "Injecting into inner classes is not supported.");
    }
  }

  public void testInjectLocalClass() throws Exception {
    class LocalClass {}

    Injector injector = Guice.createInjector();
    try {
      injector.getInstance(LocalClass.class);
      fail();
    } catch (Exception expected) {
      // TODO(kevinb): why does the source come out as unknown??
      assertContains(expected.getMessage(), "Injecting into inner classes is not supported.");
    }
  }

  public void testExplicitBindingOfAnAbstractClass() {
    try {
      Guice.createInjector(new AbstractModule() {
        protected void configure() {
          bind(AbstractClass.class);
        }
      });
      fail();
    } catch(CreationException expected) {
      assertContains(expected.getMessage(), "Injecting into abstract types is not supported.");
    }
  }
  
  public void testGetInstanceOfAnAbstractClass() {
    Injector injector = Guice.createInjector();
    try {
      injector.getInstance(AbstractClass.class);
      fail();
    } catch(ConfigurationException expected) {
      assertContains(expected.getMessage(), "Injecting into abstract types is not supported.");
    }
  }

  static abstract class AbstractClass {
    @Inject AbstractClass() { }
  }

  public void testScopingAnnotationsOnAbstractTypes() {
    try {
      Guice.createInjector(new AbstractModule() {
        protected void configure() {
          bind(A.class).to(AImpl.class);
        }
      });
      fail();
    } catch (CreationException expected) {
      assertContains(expected.getMessage(),
          "Scope annotations on abstract types are not supported.");
    }
  }

  @Singleton
  interface A {}
  class AImpl implements A {}

  public void testBindingAnnotationsOnMethodsAndConstructors() {
    try {
      Guice.createInjector().getInstance(B.class);
      fail();
    } catch (CreationException expected) {
      assertContains(expected.getMessage(),
          "Binding annotations on injected methods are not supported. "
              + "Annotate the parameter instead?");
    }

    try {
      Guice.createInjector().getInstance(C.class);
      fail();
    } catch (CreationException expected) {
      assertContains(expected.getMessage(),
          "Binding annotations on injected constructors are not supported. "
              + "Annotate the parameter instead?");
    }
  }

  static class B {
    @Inject @Green void injectMe(String greenString) {}
  }

  static class C {
    @Inject @Green C(String greenString) {}
  }

  @Retention(RUNTIME)
  @Target({ FIELD, PARAMETER, CONSTRUCTOR, METHOD })
  @BindingAnnotation
  @interface Green {}


  // TODO(kevinb): many many more

}

@@ -140,34 +140,169 @@
 ort 
-junit.framework.TestCase;%0A
+static java.lang.annotation.ElementType.CONSTRUCTOR;%0Aimport static java.lang.annotation.ElementType.FIELD;%0Aimport static java.lang.annotation.ElementType.METHOD;
 %0Aimp
@@ -345,17 +345,25 @@
 entType.
-*
+PARAMETER
 ;%0Aimport
@@ -455,16 +455,16 @@
 UNTIME;%0A
-
 import j
@@ -490,16 +490,49 @@
 .Target;
+%0Aimport junit.framework.TestCase;
 %0A%0A/**%0A *
@@ -2651,16 +2651,492 @@
  %7D%0A  %7D%0A%0A
+  /** Demonstrates issue 64, when setAccessible() fails. */%0A  public void testGetUninjectableClass() %7B%0A    try %7B%0A      Guice.createInjector(new AbstractModule() %7B%0A        protected void configure() %7B%0A          bind(Class.class);%0A        %7D%0A      %7D);%0A      fail();%0A    %7D catch (CreationException expected) %7B%0A      assertContains(expected.getMessage(),%0A          %22Failed to inject java.lang.Class%22);%0A      assertTrue(expected.getCause() instanceof SecurityException);%0A    %7D%0A  %7D%0A%0A
   @Singl

Adding a testcase for issue 64.