// Path: src/main/java/com/google/testing/compile/JavaFileObjects.java
// static ByteSource asByteSource(final JavaFileObject javaFileObject) {
//   return new ByteSource() {
//     @Override public InputStream openStream() throws IOException {
//       return javaFileObject.openInputStream();
//     }
//   };
// }
// 
// Path: src/main/java/com/google/testing/compile/TreeDiffer.java
// static TreeDifference diffCompilationUnits(
//     CompilationUnitTree expected, CompilationUnitTree actual) {
//   return createDiff(checkNotNull(expected), checkNotNull(actual), TreeFilter.KEEP_ALL);
// }
// 
// Path: src/main/java/com/google/testing/compile/TreeDiffer.java
// static TreeDifference matchCompilationUnits(
//     CompilationUnitTree pattern,
//     Trees patternTrees,
//     CompilationUnitTree actual,
//     Trees actualTrees) {
//   checkNotNull(pattern);
//   checkNotNull(actual);
//   return createDiff(
//       pattern, actual, new MatchExpectedTreesFilter(pattern, patternTrees, actual, actualTrees));
// }
// 
// Path: src/main/java/com/google/testing/compile/Parser.java
// static final class ParseResult {
//   private final ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
//       diagnostics;
//   private final ImmutableList<? extends CompilationUnitTree> compilationUnits;
//   private final Trees trees;
// 
//   ParseResult(
//       ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>> diagnostics,
//       Iterable<? extends CompilationUnitTree> compilationUnits,
//       Trees trees) {
//     this.trees = trees;
//     this.compilationUnits = ImmutableList.copyOf(compilationUnits);
//     this.diagnostics = diagnostics;
//   }
// 
//   ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
//       diagnosticsByKind() {
//     return diagnostics;
//   }
// 
//   ImmutableList<? extends CompilationUnitTree> compilationUnits() {
//     return compilationUnits;
//   }
// 
//   Trees trees() {
//     return trees;
//   }
// }


import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.JavaFileObjects.asByteSource;
import static com.google.testing.compile.TreeDiffer.diffCompilationUnits;
import static com.google.testing.compile.TreeDiffer.matchCompilationUnits;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteSource;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.testing.compile.Parser.ParseResult;
import com.sun.source.tree.CompilationUnitTree;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.function.BiFunction;
import javax.tools.JavaFileObject;
import org.checkerframework.checker.nullness.qual.Nullable;
   * modifiers and annotations as the actual AST. Ordering of AST nodes is also important (i.e. a
   * type with identical members in a different order will fail the assertion). Types must match the
   * entire type declaration: type parameters, {@code extends}/{@code implements} clauses, etc.
   * Methods must also match the throws clause as well.
   *
   * <p>The body of a method or constructor, or field initializer in the actual AST must match the
   * pattern in entirety if the member is present in the pattern.
   *
   * <p>Said in another way (from a graph-theoretic perspective): the pattern AST must be a subgraph
   * of the actual AST. If a method, constructor, or field is in the pattern, that entire subtree,
   * including modifiers and annotations, must be equal to the corresponding subtree in the actual
   * AST (no proper subgraphs).
   */
  public void containsElementsIn(JavaFileObject expectedPattern) {
    performTreeDifference(
        expectedPattern,
        "expected to contain elements in",
        "expected pattern",
        (expectedResult, actualResult) ->
            matchCompilationUnits(
                getOnlyElement(expectedResult.compilationUnits()),
                actualResult.trees(),
                getOnlyElement(actualResult.compilationUnits()),
                expectedResult.trees()));
  }

  private void performTreeDifference(
      JavaFileObject expected,
      String failureVerb,
      String expectedTitle,
// Path: src/main/java/com/google/testing/compile/JavaFileObjects.java
// static ByteSource asByteSource(final JavaFileObject javaFileObject) {
//   return new ByteSource() {
//     @Override public InputStream openStream() throws IOException {
//       return javaFileObject.openInputStream();
//     }
//   };
// }
// 
// Path: src/main/java/com/google/testing/compile/TreeDiffer.java
// static TreeDifference diffCompilationUnits(
//     CompilationUnitTree expected, CompilationUnitTree actual) {
//   return createDiff(checkNotNull(expected), checkNotNull(actual), TreeFilter.KEEP_ALL);
// }
// 
// Path: src/main/java/com/google/testing/compile/TreeDiffer.java
// static TreeDifference matchCompilationUnits(
//     CompilationUnitTree pattern,
//     Trees patternTrees,
//     CompilationUnitTree actual,
//     Trees actualTrees) {
//   checkNotNull(pattern);
//   checkNotNull(actual);
//   return createDiff(
//       pattern, actual, new MatchExpectedTreesFilter(pattern, patternTrees, actual, actualTrees));
// }
// 
// Path: src/main/java/com/google/testing/compile/Parser.java
// static final class ParseResult {
//   private final ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
//       diagnostics;
//   private final ImmutableList<? extends CompilationUnitTree> compilationUnits;
//   private final Trees trees;
// 
//   ParseResult(
//       ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>> diagnostics,
//       Iterable<? extends CompilationUnitTree> compilationUnits,
//       Trees trees) {
//     this.trees = trees;
//     this.compilationUnits = ImmutableList.copyOf(compilationUnits);
//     this.diagnostics = diagnostics;
//   }
// 
//   ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
//       diagnosticsByKind() {
//     return diagnostics;
//   }
// 
//   ImmutableList<? extends CompilationUnitTree> compilationUnits() {
//     return compilationUnits;
//   }
// 
//   Trees trees() {
//     return trees;
//   }
// }


// Path: src/main/java/com/google/testing/compile/JavaFileObjectSubject.java
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.JavaFileObjects.asByteSource;
import static com.google.testing.compile.TreeDiffer.diffCompilationUnits;
import static com.google.testing.compile.TreeDiffer.matchCompilationUnits;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteSource;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.testing.compile.Parser.ParseResult;
import com.sun.source.tree.CompilationUnitTree;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.function.BiFunction;
import javax.tools.JavaFileObject;
import org.checkerframework.checker.nullness.qual.Nullable;

   * modifiers and annotations as the actual AST. Ordering of AST nodes is also important (i.e. a
   * type with identical members in a different order will fail the assertion). Types must match the
   * entire type declaration: type parameters, {@code extends}/{@code implements} clauses, etc.
   * Methods must also match the throws clause as well.
   *
   * <p>The body of a method or constructor, or field initializer in the actual AST must match the
   * pattern in entirety if the member is present in the pattern.
   *
   * <p>Said in another way (from a graph-theoretic perspective): the pattern AST must be a subgraph
   * of the actual AST. If a method, constructor, or field is in the pattern, that entire subtree,
   * including modifiers and annotations, must be equal to the corresponding subtree in the actual
   * AST (no proper subgraphs).
   */
  public void containsElementsIn(JavaFileObject expectedPattern) {
    performTreeDifference(
        expectedPattern,
        "expected to contain elements in",
        "expected pattern",
        (expectedResult, actualResult) ->
            matchCompilationUnits(
                getOnlyElement(expectedResult.compilationUnits()),
                actualResult.trees(),
                getOnlyElement(actualResult.compilationUnits()),
                expectedResult.trees()));
  }

  private void performTreeDifference(
      JavaFileObject expected,
      String failureVerb,
      String expectedTitle,
      BiFunction<ParseResult, ParseResult, TreeDifference> differencingFunction) {