/**
  * Generates the test cases for the state machine in {@link StateMachine#getInstance()} and writes
  * the file to the given output path.
  *
  * @param outputClassName The simple name of the generate class containing the generated test
  *     cases
  * @return The source code for the generated test class
  */
 public static String generate(String outputClassName) {
   final StateMachine machine = StateMachine.getInstance();
   final RoundTripPathTreeNode tree = RoundTripPathTreeNode.build(machine.getStartState());
   final List<BodyDeclaration> methods = generateTestMethods(tree);
   final ClassOrInterfaceDeclaration testClass =
       new ClassOrInterfaceDeclaration(ModifierSet.PUBLIC, false, outputClassName);
   testClass.setMembers(methods);
   final CompilationUnit file =
       new CompilationUnit(
           new PackageDeclaration(new NameExpr(machine.getPackageName())),
           generateImports(Assert.class, Test.class),
           Collections.<TypeDeclaration>singletonList(testClass));
   return file.toString();
 }
 private TypeDeclaration getOuterClass(CompilationUnit unit) {
   for (TypeDeclaration type : unit.getTypes()) {
     if (type instanceof ClassOrInterfaceDeclaration || type instanceof EnumDeclaration)
       return type;
   }
   throw new RuntimeException("Couldn't find class, is your java file empty?");
 }
  @Nullable
  private static String extractClassName(String code, PrintStream err) {
    InputStream inputStream = new ByteArrayInputStream(code.getBytes(StandardCharsets.UTF_8));
    try {
      CompilationUnit compilationUnit = JavaParser.parse(inputStream);
      List<TypeDeclaration> types = compilationUnit.getTypes();
      if (types.size() == 1) {
        String simpleType = types.get(0).getName();
        return Optional.ofNullable(compilationUnit.getPackage())
            .map(PackageDeclaration::getPackageName)
            .map(it -> it + "." + simpleType)
            .orElse(simpleType);
      } else if (types.size() == 0) {
        err.println("No class definition found");
      } else {
        err.println("Too many class definitions found. Only one class can be defined at a time.");
      }
    } catch (ParseException e) {
      // ignore error, let the compiler provide an error message
      return "Err";
    }

    return null;
  }
  @Override
  public Boolean visit(final CompilationUnit n1, final Node arg) {
    final CompilationUnit n2 = (CompilationUnit) arg;

    if (!nodeEquals(n1.getPackage(), n2.getPackage())) {
      return Boolean.FALSE;
    }

    if (!nodesEquals(n1.getImports(), n2.getImports())) {
      return Boolean.FALSE;
    }

    if (!nodesEquals(n1.getTypes(), n2.getTypes())) {
      return Boolean.FALSE;
    }

    if (!nodesEquals(n1.getComments(), n2.getComments())) {
      return Boolean.FALSE;
    }

    return Boolean.TRUE;
  }
 @Override
 public void visit(final CompilationUnit n, final A arg) {
   visitComment(n.getComment(), arg);
   if (n.getPackage() != null) {
     n.getPackage().accept(this, arg);
   }
   if (n.getImports() != null) {
     for (final ImportDeclaration i : n.getImports()) {
       i.accept(this, arg);
     }
   }
   if (n.getTypes() != null) {
     for (final TypeDeclaration<?> typeDeclaration : n.getTypes()) {
       typeDeclaration.accept(this, arg);
     }
   }
 }