package org.smoothbuild.acceptance;

import static org.smoothbuild.util.Streams.inputStreamToString;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

public class ArrayMatcher extends TypeSafeMatcher<File> {
  private final String[] expectedElements;

  public static Matcher<File> isArrayWith(String... expectedElements) {
    return new ArrayMatcher(expectedElements);
  }

  private ArrayMatcher(String... expectedElements) {
    this.expectedElements = expectedElements;
  }

  @Override
  public void describeTo(Description description) {
    description.appendText("is array dir with elements = " + Arrays.toString(expectedElements));
  }

  @Override
  protected boolean matchesSafely(File item) {
    try {
      return item.isDirectory() && containsExpectedElements(item)
          && item.list().length == expectedElements.length;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private boolean containsExpectedElements(File dir) throws IOException {
    for (int i = 0; i < expectedElements.length; i++) {
      File file = new File(dir, Integer.toString(i));
      if (!expectedElements[i].equals(inputStreamToString(new FileInputStream(file)))) {
        return false;
      }
    }
    return true;
  }
}

@@ -30,16 +30,55 @@
 tance;%0A%0A
+import static java.util.Arrays.stream;%0A
 import s
@@ -227,26 +227,125 @@
 rt java.
-util.Array
+io.UncheckedIOException;%0Aimport java.util.Arrays;%0Aimport java.util.Objects;%0Aimport java.util.stream.Collector
 s;%0A%0Aimpo
@@ -514,22 +514,22 @@
 e final 
-String
+Object
 %5B%5D expec
@@ -531,24 +531,16 @@
 expected
-Elements
 ;%0A%0A  pub
@@ -576,22 +576,22 @@
 rayWith(
-String
+Object
 ... expe
@@ -681,22 +681,22 @@
 Matcher(
-String
+Object
 ... expe
@@ -728,24 +728,16 @@
 expected
-Elements
  = expec
@@ -883,16 +883,15 @@
 %22 + 
-Arrays.t
+objectT
 oStr
@@ -902,24 +902,16 @@
 expected
-Elements
 ));%0A  %7D%0A
@@ -990,126 +990,452 @@
     
-return item.isDirectory() && containsExpectedElements(item)%0A          && item.list().length == expectedElements.length
+Object actual = actual(item);%0A      return actual != null && actual.getClass().isArray() &&%0A          Arrays.deepEquals(expected, (Object%5B%5D) actual);%0A    %7D catch (IOException e) %7B%0A      throw new RuntimeException(e);%0A    %7D%0A  %7D%0A%0A  @Override%0A  protected void describeMismatchSafely(File item, Description mismatchDescription) %7B%0A    try %7B%0A      mismatchDescription%0A          .appendText(%22was%5Cn%22)%0A          .appendText(objectToString(actual(item)))
 ;%0A  
@@ -1470,39 +1470,43 @@
       throw new 
-Runtime
+UncheckedIO
 Exception(e);%0A  
@@ -1528,49 +1528,289 @@
 ate 
-boolean containsExpectedElements
+static Object actual(File file) throws IOException %7B%0A    if (!file.exists()) %7B%0A      return null;%0A    %7D%0A    if (file.isDirectory()) %7B%0A      return actualArray(file);%0A    %7D%0A    return inputStreamToString(new FileInputStream(file));%0A  %7D%0A%0A  private static Object actualArray
 (File 
-dir
+file
 ) th
@@ -1836,78 +1836,144 @@
     
-for (int i = 0; i %3C expectedElements.length; i++) %7B%0A      File file = 
+int count = file.list().length;%0A    Object%5B%5D result = new Object%5Bcount%5D;%0A    for (int i = 0; i %3C count; i++) %7B%0A      result%5Bi%5D = actual(
 new 
@@ -1977,19 +1977,20 @@
 ew File(
-dir
+file
 , Intege
@@ -2007,101 +2007,190 @@
 (i))
+)
 ;%0A    
-  if (!expectedElements%5Bi%5D.equals(inputStreamToString(new FileInputStream(file))
+%7D%0A    return result;%0A  %7D%0A%0A  private static String objectToString(Object object) %7B%0A    if (object == null) %7B%0A      return %22null%22;%0A    %7D else if (object.getClass().isArray(
 )) %7B%0A
-  
     
@@ -2202,44 +2202,283 @@
 urn 
-false
+arrayToString((Object%5B%5D) object);%0A    %7D else %7B%0A      return Objects.toString(object)
 ;%0A    
+%7D%0A
   %7D%0A
+%0A
   
-  %7D%0A    return true
+private static String arrayToString(Object%5B%5D array) %7B%0A    return %22%5B%22 + stream(array)%0A        .map(ArrayMatcher::objectToString)%0A        .collect(Collectors.joining(%22, %22)) + %22%5D%22
 ;%0A  

extend ArrayMatcher to work with arrays of gepth > 1