private void compare(
      String name,
      LombokTestSource expected,
      String actualFile,
      LinkedHashSet<CompilerMessage> actualMessages,
      boolean printErrors,
      boolean skipCompareContent)
      throws Throwable {
    if (!skipCompareContent)
      try {
        compareContent(name, expected.getContent(), actualFile);
      } catch (Throwable e) {
        if (printErrors) {
          System.out.println("***** " + name + " *****");
          System.out.println(e.getMessage());
          System.out.println("**** Expected ******");
          System.out.println(expected.getContent());
          System.out.println("****  Actual  ******");
          System.out.println(actualFile);
          if (actualMessages != null && !actualMessages.isEmpty()) {
            System.out.println("**** Actual Errors *****");
            for (CompilerMessage actualMessage : actualMessages) {
              System.out.println(actualMessage);
            }
          }
          System.out.println("*******************");
        }
        if (dumpActualFilesHere != null) {
          dumpToFile(new File(dumpActualFilesHere, name), actualFile);
        }
        throw e;
      }

    try {
      compareMessages(name, expected.getMessages(), actualMessages);
    } catch (Throwable e) {
      if (printErrors) {
        System.out.println("***** " + name + " *****");
        System.out.println(e.getMessage());
        System.out.println("**** Expected ******");
        for (CompilerMessageMatcher expectedMessage : expected.getMessages()) {
          System.out.println(expectedMessage);
        }
        System.out.println("****  Actual  ******");
        for (CompilerMessage actualMessage : actualMessages) {
          System.out.println(actualMessage);
        }
        System.out.println("*******************");
      }
      if (dumpActualFilesHere != null) {
        dumpToFile(new File(dumpActualFilesHere, name + ".messages"), actualMessages);
      }
      throw e;
    }
  }
  public final FileTester createTester(final DirectoryRunner.TestParams params, final File file)
      throws IOException {
    ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys();
    AssertionError directiveFailure = null;
    LombokTestSource sourceDirectives = null;
    try {
      sourceDirectives = LombokTestSource.readDirectives(file);
      if (sourceDirectives.isIgnore()) return null;
      if (!sourceDirectives.versionWithinLimit(params.getVersion())) return null;
      if (!sourceDirectives.versionWithinLimit(getClasspathVersion())) return null;
    } catch (AssertionError ae) {
      directiveFailure = ae;
    }

    String fileName = file.getName();
    final LombokTestSource expected =
        LombokTestSource.read(params.getAfterDirectory(), params.getMessagesDirectory(), fileName);

    if (expected.isIgnore()) return null;
    if (!expected.versionWithinLimit(params.getVersion())) return null;

    final LombokTestSource sourceDirectives_ = sourceDirectives;
    final AssertionError directiveFailure_ = directiveFailure;
    return new FileTester() {
      @Override
      public void runTest() throws Throwable {
        if (directiveFailure_ != null) throw directiveFailure_;
        LinkedHashSet<CompilerMessage> messages = new LinkedHashSet<CompilerMessage>();
        StringWriter writer = new StringWriter();

        LombokConfiguration.overrideConfigurationResolverFactory(
            new ConfigurationResolverFactory() {
              @Override
              public ConfigurationResolver createResolver(AST<?, ?, ?> ast) {
                return sourceDirectives_.getConfiguration();
              }
            });

        boolean changed =
            transformCode(
                messages,
                writer,
                file,
                sourceDirectives_.getSpecifiedEncoding(),
                sourceDirectives_.getFormatPreferences());
        boolean forceUnchanged =
            sourceDirectives_.forceUnchanged() || sourceDirectives_.isSkipCompareContent();
        if (params.expectChanges() && !forceUnchanged && !changed)
          messages.add(new CompilerMessage(-1, -1, true, "not flagged modified"));
        if (!params.expectChanges() && changed)
          messages.add(new CompilerMessage(-1, -1, true, "unexpected modification"));

        compare(
            file.getName(),
            expected,
            writer.toString(),
            messages,
            params.printErrors(),
            sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent());
      }
    };
  }