package arez.test;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import jdepend.framework.DependencyConstraint;
import jdepend.framework.JDepend;
import jdepend.framework.JavaPackage;
import jdepend.framework.PackageFilter;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class JDependTest
{
  @Test
  public void dependencyAnalysis()
    throws Exception
  {
    final JDepend jdepend = new JDepend( PackageFilter.all().excluding( "java.*", "javax.*" ) );
    jdepend.addDirectory( compileTargetDir() );
    jdepend.analyze();

    final DependencyConstraint constraint = new DependencyConstraint();

    final JavaPackage arez = constraint.addPackage( "arez" );
    final JavaPackage spy = constraint.addPackage( "arez.spy" );
    constraint.addPackage( "arez.annotations" );
    final JavaPackage component = constraint.addPackage( "arez.component" );
    final JavaPackage braincheck = constraint.addPackage( "org.realityforge.braincheck" );
    final JavaPackage jsinterop = constraint.addPackage( "jsinterop.annotations" );

    arez.dependsUpon( jsinterop );
    arez.dependsUpon( braincheck );
    /*
     * The arez.spy and arez packages form a loop but rather than squashing spy into arez
     * it was decided to keep them separate as everything in arez.spy should be optimized out
     * during production builds and keeping them in separate packages makes it easy to verify
     * this constraint.
     */
    spy.dependsUpon( arez );
    arez.dependsUpon( spy );

    component.dependsUpon( braincheck );
    component.dependsUpon( arez );
    component.dependsUpon( spy );

    final DependencyConstraint.MatchResult result = jdepend.analyzeDependencies( constraint );

    final List<JavaPackage> undefinedPackages = result.getUndefinedPackages();
    if ( !undefinedPackages.isEmpty() )
    {
      fail( "Undefined Packages: " +
            undefinedPackages.stream().map( Object::toString ).collect( Collectors.joining( ", " ) ) );
    }

    assertTrue( result.matches(),
                "NonMatchingPackages: " +
                result.getNonMatchingPackages().stream().map( Arrays::asList ).collect( Collectors.toList() ) );
  }

  @Nonnull
  private String compileTargetDir()
  {
    final String fixtureDir = System.getProperty( "arez.core.compile_target" );
    assertNotNull( fixtureDir, "Expected System.getProperty( \"arez.core.compile_target\" ) to return directory" );
    return new File( fixtureDir ).getAbsolutePath();
  }
}

@@ -34,16 +34,44 @@
 o.File;%0A
+import java.util.ArrayList;%0A
 import j
@@ -2111,192 +2111,1244 @@
     
-assertTrue( result.match
+final List%3CJavaPackage%5B%5D%3E nonMatchingPackages = result.getNonMatchingPackag
 es()
-,
+;
 %0A    
-  
+if ( !nonMatchingPackages.isEmpty() )%0A
     
+%7B%0A
       
-%22NonMatchingPackages: %22 +%0A                result.getNonMatchingPackages().stre
+final StringBuilder sb = new StringBuilder();%0A      sb.append( %22Discovered packages where relationships do not align.%5Cn%22 );%0A      for ( final JavaPackage%5B%5D packages : nonMatchingPackages )%0A      %7B%0A        final JavaPackage expected = packages%5B 0 %5D;%0A        final JavaPackage actual = packages%5B 1 %5D;%0A%0A        final ArrayList%3CJavaPackage%3E oldAfferents = new ArrayList%3C%3E( expected.getAfferents() );%0A        oldAfferents.removeAll( actual.getAfferents() );%0A%0A        oldAfferents.forEach( p -%3E sb%0A          .append( %22Package %22 )%0A          .append( p.getName() )%0A          .append( %22 no longer depends upon %22 )%0A          .append( expected.getN
 am
+e
 ()
-.map( Arrays::asList ).collect( Collectors.toList() ) );
+ )%0A          .append( %22%5Cn%22 )%0A        );%0A%0A        final ArrayList%3CJavaPackage%3E newAfferents = new ArrayList%3C%3E( actual.getAfferents() );%0A        newAfferents.removeAll( expected.getAfferents() );%0A%0A        newAfferents.forEach( p -%3E sb%0A          .append( %22Package %22 )%0A          .append( p.getName() )%0A          .append( %22 now depends upon %22 )%0A          .append( expected.getName() )%0A          .append( %22%5Cn%22 )%0A        );%0A      %7D%0A      fail( sb.toString() );%0A    %7D
 %0A  %7D

Improve error messages from test