### Question:
LinkageProblem { public static String formatLinkageProblems( Set<LinkageProblem> linkageProblems, @Nullable ClassPathResult classPathResult) { StringBuilder output = new StringBuilder(); ImmutableSet.Builder<AbstractMethodProblem> abstractMethodProblems = ImmutableSet.builder(); ImmutableSet.Builder<LinkageProblem> problemsToGroupBySymbols = ImmutableSet.builder(); for (LinkageProblem linkageProblem : linkageProblems) { if (linkageProblem instanceof AbstractMethodProblem) { abstractMethodProblems.add((AbstractMethodProblem) linkageProblem); } else { problemsToGroupBySymbols.add(linkageProblem); } } ImmutableListMultimap<Symbol, LinkageProblem> groupBySymbols = Multimaps.index(problemsToGroupBySymbols.build(), problem -> problem.getSymbol()); groupBySymbols .asMap() .forEach( (symbol, problems) -> { LinkageProblem firstProblem = Iterables.getFirst(problems, null); int referenceCount = problems.size(); output.append(firstProblem.formatSymbolProblemWithReferenceCount(referenceCount)); ImmutableSet.Builder<LinkageProblemCause> causesBuilder = ImmutableSet.builder(); problems.forEach( problem -> { ClassFile sourceClassFile = problem.getSourceClass(); output.append(" " + sourceClassFile.getBinaryName()); output.append(" (" + sourceClassFile.getClassPathEntry() + ")\n"); LinkageProblemCause cause = problem.getCause(); if (cause != null) { causesBuilder.add(cause); } }); ImmutableSet<LinkageProblemCause> causes = causesBuilder.build(); if (!causes.isEmpty()) { output.append(" Cause:\n"); for (LinkageProblemCause cause : causes) { String causeWithIndent = cause.toString().replaceAll("\n", "\n "); output.append(" " + causeWithIndent + "\n"); } } }); for (AbstractMethodProblem abstractMethodProblem : abstractMethodProblems.build()) { output.append(abstractMethodProblem + "\n"); output.append(" Cause:\n"); LinkageProblemCause cause = abstractMethodProblem.getCause(); String causeWithIndent = cause.toString().replaceAll("\n", "\n "); output.append(" " + causeWithIndent + "\n"); } if (classPathResult != null) { String dependencyPaths = dependencyPathsOfProblematicJars(classPathResult, linkageProblems); output.append(dependencyPaths); } return output.toString(); } LinkageProblem(
      String symbolProblemMessage, ClassFile sourceClass, Symbol symbol, ClassFile targetClass); Symbol getSymbol(); ClassFile getSourceClass(); @Nullable ClassFile getTargetClass(); @Override boolean equals(Object other); @Override int hashCode(); @Override String toString(); String formatSymbolProblem(); static ImmutableMap<String, ImmutableSet<String>> groupBySymbolProblem(
      Iterable<LinkageProblem> linkageProblems); static String formatLinkageProblems(
      Set<LinkageProblem> linkageProblems, @Nullable ClassPathResult classPathResult);  }### Answer:
@Test public void testFormatLinkageProblems() { assertEquals( "(" + path + ") " + "io.grpc.protobuf.ProtoUtils.marshaller's method " + "marshaller(com.google.protobuf.Message) is not found;\n" + " referenced by 1 class file\n" + " java.lang.Object (com.google:foo:0.0.1)\n" + "Class java.lang.Integer is not found;\n" + " referenced by 2 class files\n" + " java.lang.Object (com.google:foo:0.0.1)\n" + " java.lang.Integer (com.google:bar:0.0.1)\n" + "(com.google:ccc:1.2.3) java.lang.Integer's field MAX_VALUE is not found;\n" + " referenced by 1 class file\n" + " java.lang.Integer (com.google:bar:0.0.1)\n", LinkageProblem.formatLinkageProblems(linkageProblems, null)); }