/**
   * Loads a GrailsApplication using the given ResourceLocator instance which will search for
   * appropriate class names
   */
  public DefaultGrailsApplication(org.codehaus.groovy.grails.io.support.Resource[] resources) {
    this();
    for (org.codehaus.groovy.grails.io.support.Resource resource : resources) {

      Class<?> aClass;
      try {
        aClass =
            cl.loadClass(
                org.codehaus.groovy.grails.io.support.GrailsResourceUtils.getClassName(
                    resource.getFile().getAbsolutePath()));
      } catch (ClassNotFoundException e) {
        throw new GrailsConfigurationException(
            "Class not found loading Grails application: " + e.getMessage(), e);
      } catch (IOException e) {
        throw new GrailsConfigurationException(
            "Class not found loading Grails application: " + e.getMessage(), e);
      }
      loadedClasses.add(aClass);
    }
  }
  @Override
  public void visit(ASTNode[] astNodes, SourceUnit source) {
    if (!(astNodes[0] instanceof AnnotationNode) || !(astNodes[1] instanceof AnnotatedNode)) {
      throw new RuntimeException("Internal error: wrong types: $node.class / $parent.class");
    }

    AnnotatedNode parent = (AnnotatedNode) astNodes[1];
    AnnotationNode node = (AnnotationNode) astNodes[0];
    if (!MY_TYPE.equals(node.getClassNode()) || !(parent instanceof ClassNode)) {
      return;
    }

    ClassNode classNode = (ClassNode) parent;
    if (classNode.isInterface() || Modifier.isAbstract(classNode.getModifiers())) {
      return;
    }

    boolean junit3Test = isJunit3Test(classNode);
    boolean spockTest = isSpockTest(classNode);
    boolean isJunit = classNode.getName().endsWith("Tests");

    if (!junit3Test && !spockTest && !isJunit) return;

    Expression value = node.getMember("value");
    ClassExpression ce;
    if (value instanceof ClassExpression) {
      ce = (ClassExpression) value;
      testFor(classNode, ce);
    } else {
      if (!junit3Test) {
        List<AnnotationNode> annotations = classNode.getAnnotations(MY_TYPE);
        if (annotations.size() > 0)
          return; // bail out, in this case it was already applied as a local transform
        // no explicit class specified try by convention
        String fileName = source.getName();
        String className = GrailsResourceUtils.getClassName(new FileSystemResource(fileName));
        if (className != null) {
          boolean isSpock = className.endsWith("Spec");
          String targetClassName = null;

          if (isJunit) {
            targetClassName = className.substring(0, className.indexOf("Tests"));
          } else if (isSpock) {
            targetClassName = className.substring(0, className.indexOf("Spec"));
          }

          if (targetClassName != null) {
            Resource targetResource =
                getResourceLocator().findResourceForClassName(targetClassName);
            if (targetResource != null) {
              try {
                if (GrailsResourceUtils.isDomainClass(targetResource.getURL())) {
                  testFor(
                      classNode,
                      new ClassExpression(
                          new ClassNode(targetClassName, 0, ClassHelper.OBJECT_TYPE)));
                } else {
                  for (String artefactType : artefactTypeToTestMap.keySet()) {
                    if (targetClassName.endsWith(artefactType)) {
                      testFor(
                          classNode,
                          new ClassExpression(
                              new ClassNode(targetClassName, 0, ClassHelper.OBJECT_TYPE)));
                      break;
                    }
                  }
                }
              } catch (IOException e) {
                // ignore
              }
            }
          }
        }
      }
    }
  }