/*
 * 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.dev.javac.typemodel;

import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;

import junit.framework.TestCase;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Comparator;

/**
 * Base test cases for all {@link JDelegatingClassType}s.
 */
public abstract class JDelegatingClassTypeTestBase extends TestCase {

  private static final Comparator<? super Annotation> ANNOTATION_COMPARATOR = new Comparator<Annotation>() {
    @Override
    public int compare(Annotation o1, Annotation o2) {
      // Just use toString, it contains all info.
      return o1.toString().compareTo(o2.toString());
    }
  };

  protected static void assertArraysEqual(Object[] expected, Object[] actual) {
    assertTrue("Expected: \n" + Arrays.toString(expected) + ",\n Actual: \n"
        + Arrays.toString(actual), Arrays.equals(expected, actual));
  }

  protected static void validateAbstractMethodSubstitution(
      JAbstractMethod preSubMethod, JAbstractMethod postSubMethod,
      Substitution substitution) {

    assertEquals(preSubMethod.getName(), postSubMethod.getName());

    assertEquals(preSubMethod.getModifierBits(),
        postSubMethod.getModifierBits());

    validateAnnotations(preSubMethod.getAnnotations(),
        postSubMethod.getAnnotations());

    JParameter[] preSubParams = preSubMethod.getParameters();
    JParameter[] postSubParams = postSubMethod.getParameters();

    assertEquals(preSubParams.length, postSubParams.length);

    for (int j = 0; j < preSubParams.length; ++j) {
      JParameter preSubParam = preSubParams[j];
      JParameter postSubParam = postSubParams[j];

      validateAnnotations(preSubParam.getAnnotations(),
          postSubParam.getAnnotations());

      assertEquals(substitute(substitution, preSubParam.getType()),
          postSubParam.getType());

      assertEquals(preSubParam.getName(), postSubParam.getName());
    }

    JClassType[] preSubThrows = preSubMethod.getThrows();
    JClassType[] postSubThrows = postSubMethod.getThrows();
    assertArraysEqual(preSubThrows, postSubThrows);
  }

  private static JType substitute(Substitution substitution, JType type) {
    if (!(type instanceof JClassType)) {
      return type;
    }
    JClassType t2 = (JClassType) type;
    JType substitution2 = substitution.getSubstitution(t2);
    return substitution2;
  }

  protected static void validateAnnotations(Annotation[] expected,
      Annotation[] actual) {
    Arrays.sort(expected, ANNOTATION_COMPARATOR);
    Arrays.sort(actual, ANNOTATION_COMPARATOR);
    assertArraysEqual(expected, actual);
  }

  protected static void validateConstructorSubstitutions(
      JClassType preSubstitution, JClassType postSubstituion,
      Substitution substitution) {
    // Check the constructors
    JConstructor[] preSubCtors = preSubstitution.getConstructors();
    JConstructor[] postSubCtors = postSubstituion.getConstructors();
    assertEquals(preSubCtors.length, postSubCtors.length);
    for (int i = 0; i < preSubCtors.length; ++i) {
      validateAbstractMethodSubstitution(preSubCtors[i], postSubCtors[i],
          substitution);
    }
  }

  protected static void validateDeclaredAnnotations(Annotation[] expected,
      Annotation[] actual) {
    Arrays.sort(expected, ANNOTATION_COMPARATOR);
    Arrays.sort(actual, ANNOTATION_COMPARATOR);
    assertArraysEqual(expected, actual);
  }

  protected static void validateEquals(JClassType[] expectedTypes,
      JClassType actualTypes[]) {
    TypeOracle.sort(expectedTypes);
    TypeOracle.sort(actualTypes);

    assertArraysEqual(expectedTypes, actualTypes);
  }

  protected static void validateFieldSubstitutions(JClassType preSubstitution,
      JClassType postSubstituion, Substitution substitution) {
    // Check the fields
    JField[] preSubfields = preSubstitution.getFields();
    JField[] postSubFields = postSubstituion.getFields();
    assertEquals(preSubfields.length, postSubFields.length);
    for (int i = 0; i < preSubfields.length; ++i) {
      JField postSubField = postSubstituion.getField(preSubfields[i].getName());
      assertNotNull(postSubField);
      assertEquals(substitute(substitution, preSubfields[i].getType()),
          postSubField.getType());
    }
  }

  protected static void validateFindConstructor(JClassType preSubstitution,
      JClassType postSubstitution, Substitution substitution) {

    JConstructor[] constructors = preSubstitution.getConstructors();
    for (JConstructor constructor : constructors) {
      JParameter[] params = constructor.getParameters();
      JType[] paramTypes = new JType[params.length];

      for (int i = 0; i < params.length; ++i) {
        paramTypes[i] = substitute(substitution, params[i].getType());
      }

      assertNotNull(postSubstitution.findConstructor(paramTypes));
    }
  }

  /**
   *
   */
  protected static void validateFindField(JClassType preSubstitution,
      JClassType postSubstitution) {
    JField[] fields = preSubstitution.getFields();
    for (JField field : fields) {
      assertNotNull(postSubstitution.findField(field.getName()));
    }
  }

  protected static void validateFindMethod(JClassType preSubstitution,
      JClassType postSubstitution, Substitution substitution) {

    JMethod[] methods = preSubstitution.getMethods();
    for (JMethod method : methods) {
      JParameter[] params = method.getParameters();
      JType[] paramTypes = new JType[params.length];

      for (int i = 0; i < params.length; ++i) {
        paramTypes[i] = substitute(substitution, params[i].getType());
      }

      assertNotNull(postSubstitution.findMethod(method.getName(), paramTypes));
    }
  }

  protected static void validateGetConstructor(JClassType preSubstitution,
      JClassType postSubstitution, Substitution substitution)
      throws NotFoundException {

    JConstructor[] constructors = preSubstitution.getConstructors();
    for (JConstructor constructor : constructors) {
      JParameter[] params = constructor.getParameters();
      JType[] paramTypes = new JType[params.length];

      for (int i = 0; i < params.length; ++i) {
        paramTypes[i] = substitute(substitution, params[i].getType());
      }

      assertNotNull(postSubstitution.getConstructor(paramTypes));
    }
  }

  /**
   *
   */
  protected static void validateGetField(JClassType preSubstitution,
      JClassType postSubstitution) {
    JField[] fields = preSubstitution.getFields();
    for (JField field : fields) {
      assertNotNull(postSubstitution.getField(field.getName()));
    }
  }

  protected static void validateGetMethod(JClassType preSubstitution,
      JClassType postSubstitution, Substitution substitution)
      throws NotFoundException {

    JMethod[] methods = preSubstitution.getMethods();
    for (JMethod method : methods) {
      JParameter[] params = method.getParameters();
      JType[] paramTypes = new JType[params.length];

      for (int i = 0; i < params.length; ++i) {
        paramTypes[i] = substitute(substitution, params[i].getType());
      }

      assertNotNull(postSubstitution.getMethod(method.getName(), paramTypes));
    }
  }

  protected static void validateGetOverloads(JClassType preSubstitution,
      JClassType postSubstitution) {
    JMethod[] methods = preSubstitution.getMethods();
    for (JMethod method : methods) {
      assertEquals(preSubstitution.getOverloads(method.getName()).length,
          postSubstitution.getOverloads(method.getName()).length);
    }
  }

  protected static void validateImplementedInterfaceSubstitution(
      JClassType preSubstitution, JClassType postSubstituion,
      Substitution substitution) {
    JClassType[] preSubIntfs = preSubstitution.getImplementedInterfaces();
    JClassType[] postSubIntfs = postSubstituion.getImplementedInterfaces();

    assertEquals(preSubIntfs.length, postSubIntfs.length);

    for (int i = 0; i < preSubIntfs.length; ++i) {
      assertEquals(postSubIntfs[i],
          substitution.getSubstitution(postSubIntfs[i]));
    }
  }

  protected static void validateMethodSubstitution(JMethod preSubMethod,
      JMethod postSubMethod, Substitution substitution) {

    assertEquals(substitute(substitution, preSubMethod.getReturnType()),
        postSubMethod.getReturnType());

    validateAbstractMethodSubstitution(preSubMethod, postSubMethod,
        substitution);
  }

  protected static void validateMethodSubstitutions(JClassType preSubstitution,
      JClassType postSubstituion, Substitution substitution)
      throws NotFoundException {
    // Check the methods
    JMethod[] preSubMethods = preSubstitution.getMethods();
    JMethod[] postSubMethods = postSubstituion.getMethods();
    assertEquals(preSubMethods.length, postSubMethods.length);

    for (int i = 0; i < preSubMethods.length; ++i) {
      JMethod preSubMethod = preSubMethods[i];

      JParameter[] preSubParams = preSubMethod.getParameters();
      JType[] postSubParamTypes = new JType[preSubParams.length];
      for (int j = 0; j < preSubParams.length; ++j) {
        postSubParamTypes[j] = substitute(substitution,
            preSubParams[j].getType());
      }
      JMethod postSubMethod = postSubstituion.getMethod(preSubMethod.getName(),
          postSubParamTypes);

      validateMethodSubstitution(preSubMethod, postSubMethod, substitution);
    }
  }

  protected static void validateTypeSubstitution(JClassType preSubstitution,
      JClassType postSubstituion, Substitution substitution)
      throws NotFoundException {
    if (preSubstitution.isGenericType() == null) {
      return;
    }

    assertEquals(preSubstitution.getModifierBits(),
        postSubstituion.getModifierBits());

    validateAnnotations(preSubstitution.getAnnotations(),
        postSubstituion.getAnnotations());

    assertEquals(preSubstitution.getName(), postSubstituion.getName());
    // assertEquals(preSubstitution.getSubstitution(substitution),
    // postSubstituion);

    // Check superclass
    JClassType superClass = preSubstitution.getSuperclass();
    if (superClass != null) {
      validateTypeSubstitution(superClass, postSubstituion.getSuperclass(),
          substitution);
    }

    // Check interfaces
    validateImplementedInterfaceSubstitution(preSubstitution, postSubstituion,
        substitution);

    validateFieldSubstitutions(preSubstitution, postSubstituion, substitution);

    validateConstructorSubstitutions(preSubstitution, postSubstituion,
        substitution);

    validateMethodSubstitutions(preSubstitution, postSubstituion, substitution);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findConstructor(JType[])}
   * .
   */
  public void testFindConstructor() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateFindConstructor(baseType, testType, getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findField(java.lang.String)}
   * .
   */
  public void testFindField() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateFindField(baseType, testType);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findMethod(java.lang.String, JType[])}
   * .
   */
  public void testFindMethod() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateFindMethod(baseType, testType, getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#findNestedType(java.lang.String)}
   * .
   */
  public abstract void testFindNestedType() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getAnnotation(java.lang.Class)}
   * .
   */
  public void testGetAnnotation() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    Annotation[] annotations = baseType.getAnnotations();
    for (Annotation annotation : annotations) {
      assertNotNull(testType.getAnnotation(annotation.annotationType()));
    }
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getAnnotations()}
   * .
   */
  public void testGetAnnotations() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateAnnotations(baseType.getAnnotations(), testType.getAnnotations());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getBaseType()}
   * .
   */
  public void testGetBaseType() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    assertNotNull(testType.getBaseType());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getConstructor(JType[])}
   * .
   */
  public void testGetConstructor() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();
    baseType.getConstructors();
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getConstructors()}
   * .
   */
  public void testGetConstructors() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateConstructorSubstitutions(baseType, testType, getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getDeclaredAnnotations()}
   * .
   */
  public void testGetDeclaredAnnotations() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateDeclaredAnnotations(baseType.getDeclaredAnnotations(),
        testType.getDeclaredAnnotations());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getEnclosingType()}
   * .
   */
  public abstract void testGetEnclosingType() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getErasedType()}
   * .
   */
  public void testGetErasedType() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.getErasedType(), testType.getErasedType());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getField(java.lang.String)}
   * .
   */
  public void testGetField() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateGetField(baseType, testType);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getFields()}.
   */
  public void testGetFields() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateFieldSubstitutions(baseType, testType, getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getImplementedInterfaces()}
   * .
   */
  public void testGetImplementedInterfaces() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateImplementedInterfaceSubstitution(baseType, testType,
        getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getInheritableMethods()}
   * .
   */
  public abstract void testGetInheritableMethods() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getJNISignature()}
   * .
   */
  public void testGetJNISignature() {
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getMethod(java.lang.String, JType[])}
   * .
   */
  public void testGetMethod() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateGetMethod(baseType, testType, getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getMethods()}.
   */
  public void testGetMethods() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateMethodSubstitutions(baseType, testType, getSubstitution());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getModifierBits()}
   * .
   */
  public void testGetModifierBits() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.getModifierBits(), testType.getModifierBits());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getName()}.
   */
  public void testGetName() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.getName(), testType.getName());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getNestedType(java.lang.String)}
   * .
   */
  public abstract void testGetNestedType() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getNestedTypes()}
   * .
   */
  public abstract void testGetNestedTypes() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getOracle()}.
   */
  public void testGetOracle() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.getOracle(), testType.getOracle());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getOverloads(java.lang.String)}
   * .
   */
  public void testGetOverloads() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    validateGetOverloads(baseType, testType);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getOverridableMethods()}
   * .
   */
  public abstract void testGetOverridableMethods() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getPackage()}.
   */
  public void testGetPackage() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.getPackage(), testType.getPackage());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getSubtypes()}
   * .
   */
  public abstract void testGetSubtypes() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#getSuperclass()}
   * .
   */
  public void testGetSuperclass() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.getSuperclass() != null,
        testType.getSuperclass() != null);

    /*
     * TODO: need to check that the super classes are consistent, if base super
     * is generic then test type super should be parameterized with same super,
     * etc.
     */
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAbstract()}.
   */
  public void testIsAbstract() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isAbstract(), testType.isAbstract());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAnnotationPresent(java.lang.Class)}
   * .
   */
  public void testIsAnnotationPresent() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    Annotation[] annotations = baseType.getAnnotations();
    for (Annotation annotation : annotations) {
      assertTrue(testType.isAnnotationPresent(annotation.annotationType()));
    }
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isArray()}.
   */
  public void testIsArray() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isArray(), testType.isArray());

    // TODO: check parameterized arrays
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAssignableFrom(com.google.gwt.core.ext.typeinfo.JClassType)}
   * .
   */
  public abstract void testIsAssignableFrom() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isAssignableTo(com.google.gwt.core.ext.typeinfo.JClassType)}
   * .
   */
  public abstract void testIsAssignableTo() throws NotFoundException;

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isClass()}.
   */
  public void testIsClass() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isClass() != null, testType.isClass() != null);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isClassOrInterface()}
   * .
   */
  public void testIsClassOrInterface() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isClassOrInterface() != null,
        testType.isClassOrInterface() != null);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isDefaultInstantiable()}
   * .
   */
  public void testIsDefaultInstantiable() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isDefaultInstantiable(),
        testType.isDefaultInstantiable());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isEnum()}.
   */
  public void testIsEnum() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isEnum() != null, testType.isEnum() != null);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isInterface()}
   * .
   */
  public void testIsInterface() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isInterface() != null, testType.isInterface() != null);
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isMemberType()}
   * .
   */
  public void testIsMemberType() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isMemberType(), testType.isMemberType());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isPrimitive()}
   * .
   */
  public void testIsPrimitive() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertNull(testType.isPrimitive());
    assertNull(baseType.isPrimitive());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isPrivate()}.
   */
  public void testIsPrivate() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isPrivate(), testType.isPrivate());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isProtected()}
   * .
   */
  public void testIsProtected() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isProtected(), testType.isProtected());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isPublic()}.
   */
  public void testIsPublic() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isPublic(), testType.isPublic());
  }

  /**
   * Test method for
   * {@link com.google.gwt.core.ext.typeinfo.JDelegatingClassType#isStatic()}.
   */
  public void testIsStatic() throws NotFoundException {
    JDelegatingClassType testType = getTestType();
    JClassType baseType = testType.getBaseType();

    assertEquals(baseType.isStatic(), testType.isStatic());
  }

  protected abstract Substitution getSubstitution() throws NotFoundException;

  protected abstract JDelegatingClassType getTestType()
      throws NotFoundException;
}
