@Test public void generateMessageForNewError() throws IOException { Set<LinkageProblem> baselineProblems = ImmutableSet.of(classNotFoundProblem); ImmutableSet<LinkageProblem> snapshotProblems = ImmutableSet.of( classNotFoundProblem, methodNotFoundProblemFromA, methodNotFoundProblemFromB); DependencyPath pathToA = new DependencyPath(new DefaultArtifact("foo:bar:1.0.0")) .append( new org.eclipse.aether.graph.Dependency( new DefaultArtifact("foo:a:1.2.3"), "compile", true)); DependencyPath pathToB = new DependencyPath(new DefaultArtifact("foo:b:1.0.0")); String message = LinkageMonitor.messageForNewErrors( snapshotProblems, baselineProblems, new ClassPathResult( ImmutableListMultimap.of(jarA, pathToA, jarB, pathToB), ImmutableList.of())); assertEquals( "Newly introduced problem:\n" + "(foo:b:1.0.0) io.grpc.protobuf.ProtoUtils's method" + " marshaller(com.google.protobuf.Message) is not found\n" + " referenced from com.abc.AAA (foo:a:1.2.3)\n" + " referenced from com.abc.BBB (foo:a:1.2.3)\n" + "\n" + "foo:b:1.0.0 is at:\n" + " foo:b:jar:1.0.0\n" + "foo:a:1.2.3 is at:\n" + " foo:bar:jar:1.0.0 / foo:a:1.2.3 (compile, optional)\n", message); }
@VisibleForTesting static String messageForNewErrors( Set<LinkageProblem> snapshotProblems, Set<LinkageProblem> baselineProblems, ClassPathResult classPathResult) { Set<LinkageProblem> newProblems = Sets.difference(snapshotProblems, baselineProblems); Builder<ClassPathEntry> problematicJars = ImmutableSet.builder(); ImmutableListMultimap<String, LinkageProblem> groupedBySymbolProblem = Multimaps.index(newProblems, problem -> problem.formatSymbolProblem()); StringBuilder message = new StringBuilder( "Newly introduced problem" + (groupedBySymbolProblem.keySet().size() > 1 ? "s" : "") + ":\n"); for (String problem : groupedBySymbolProblem.keySet()) { message.append(problem + "\n"); for (LinkageProblem linkageProblem : groupedBySymbolProblem.get(problem)) { if (linkageProblem.getTargetClass() != null) { problematicJars.add(linkageProblem.getTargetClass().getClassPathEntry()); } ClassFile sourceClass = linkageProblem.getSourceClass(); message.append( String.format( " referenced from %s (%s)\n", sourceClass.getBinaryName(), sourceClass.getClassPathEntry())); problematicJars.add(sourceClass.getClassPathEntry()); } } message.append("\n"); message.append(classPathResult.formatDependencyPaths(problematicJars.build())); return message.toString(); }
LinkageMonitor { @VisibleForTesting static String messageForNewErrors( Set<LinkageProblem> snapshotProblems, Set<LinkageProblem> baselineProblems, ClassPathResult classPathResult) { Set<LinkageProblem> newProblems = Sets.difference(snapshotProblems, baselineProblems); Builder<ClassPathEntry> problematicJars = ImmutableSet.builder(); ImmutableListMultimap<String, LinkageProblem> groupedBySymbolProblem = Multimaps.index(newProblems, problem -> problem.formatSymbolProblem()); StringBuilder message = new StringBuilder( "Newly introduced problem" + (groupedBySymbolProblem.keySet().size() > 1 ? "s" : "") + ":\n"); for (String problem : groupedBySymbolProblem.keySet()) { message.append(problem + "\n"); for (LinkageProblem linkageProblem : groupedBySymbolProblem.get(problem)) { if (linkageProblem.getTargetClass() != null) { problematicJars.add(linkageProblem.getTargetClass().getClassPathEntry()); } ClassFile sourceClass = linkageProblem.getSourceClass(); message.append( String.format( " referenced from %s (%s)\n", sourceClass.getBinaryName(), sourceClass.getClassPathEntry())); problematicJars.add(sourceClass.getClassPathEntry()); } } message.append("\n"); message.append(classPathResult.formatDependencyPaths(problematicJars.build())); return message.toString(); } }
LinkageMonitor { @VisibleForTesting static String messageForNewErrors( Set<LinkageProblem> snapshotProblems, Set<LinkageProblem> baselineProblems, ClassPathResult classPathResult) { Set<LinkageProblem> newProblems = Sets.difference(snapshotProblems, baselineProblems); Builder<ClassPathEntry> problematicJars = ImmutableSet.builder(); ImmutableListMultimap<String, LinkageProblem> groupedBySymbolProblem = Multimaps.index(newProblems, problem -> problem.formatSymbolProblem()); StringBuilder message = new StringBuilder( "Newly introduced problem" + (groupedBySymbolProblem.keySet().size() > 1 ? "s" : "") + ":\n"); for (String problem : groupedBySymbolProblem.keySet()) { message.append(problem + "\n"); for (LinkageProblem linkageProblem : groupedBySymbolProblem.get(problem)) { if (linkageProblem.getTargetClass() != null) { problematicJars.add(linkageProblem.getTargetClass().getClassPathEntry()); } ClassFile sourceClass = linkageProblem.getSourceClass(); message.append( String.format( " referenced from %s (%s)\n", sourceClass.getBinaryName(), sourceClass.getClassPathEntry())); problematicJars.add(sourceClass.getClassPathEntry()); } } message.append("\n"); message.append(classPathResult.formatDependencyPaths(problematicJars.build())); return message.toString(); }  }
LinkageMonitor { @VisibleForTesting static String messageForNewErrors( Set<LinkageProblem> snapshotProblems, Set<LinkageProblem> baselineProblems, ClassPathResult classPathResult) { Set<LinkageProblem> newProblems = Sets.difference(snapshotProblems, baselineProblems); Builder<ClassPathEntry> problematicJars = ImmutableSet.builder(); ImmutableListMultimap<String, LinkageProblem> groupedBySymbolProblem = Multimaps.index(newProblems, problem -> problem.formatSymbolProblem()); StringBuilder message = new StringBuilder( "Newly introduced problem" + (groupedBySymbolProblem.keySet().size() > 1 ? "s" : "") + ":\n"); for (String problem : groupedBySymbolProblem.keySet()) { message.append(problem + "\n"); for (LinkageProblem linkageProblem : groupedBySymbolProblem.get(problem)) { if (linkageProblem.getTargetClass() != null) { problematicJars.add(linkageProblem.getTargetClass().getClassPathEntry()); } ClassFile sourceClass = linkageProblem.getSourceClass(); message.append( String.format( " referenced from %s (%s)\n", sourceClass.getBinaryName(), sourceClass.getClassPathEntry())); problematicJars.add(sourceClass.getClassPathEntry()); } } message.append("\n"); message.append(classPathResult.formatDependencyPaths(problematicJars.build())); return message.toString(); }  static void main(String[] arguments); }
LinkageMonitor { @VisibleForTesting static String messageForNewErrors( Set<LinkageProblem> snapshotProblems, Set<LinkageProblem> baselineProblems, ClassPathResult classPathResult) { Set<LinkageProblem> newProblems = Sets.difference(snapshotProblems, baselineProblems); Builder<ClassPathEntry> problematicJars = ImmutableSet.builder(); ImmutableListMultimap<String, LinkageProblem> groupedBySymbolProblem = Multimaps.index(newProblems, problem -> problem.formatSymbolProblem()); StringBuilder message = new StringBuilder( "Newly introduced problem" + (groupedBySymbolProblem.keySet().size() > 1 ? "s" : "") + ":\n"); for (String problem : groupedBySymbolProblem.keySet()) { message.append(problem + "\n"); for (LinkageProblem linkageProblem : groupedBySymbolProblem.get(problem)) { if (linkageProblem.getTargetClass() != null) { problematicJars.add(linkageProblem.getTargetClass().getClassPathEntry()); } ClassFile sourceClass = linkageProblem.getSourceClass(); message.append( String.format( " referenced from %s (%s)\n", sourceClass.getBinaryName(), sourceClass.getClassPathEntry())); problematicJars.add(sourceClass.getClassPathEntry()); } } message.append("\n"); message.append(classPathResult.formatDependencyPaths(problematicJars.build())); return message.toString(); }  static void main(String[] arguments);  }