package eu.dnetlib.iis.common; import static org.junit.Assert.assertEquals; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.junit.Assert; import eu.dnetlib.iis.common.java.io.JsonUtils; /** * Utility class for tests dealing with IO * * @author Mateusz Kobos * */ public class TestsIOUtils { private final static int filesCompareBufferSize = 1024; private final static int dumpRecordsCountlimit = 100; private TestsIOUtils() {} /** * {@code expected} and {@code actual} are equal if they have the same * elements, possibly in different order. */ public static <T> void assertEqualSets(List<T> expected, Iterable<T> actual) { assertEqualSets(expected, actual.iterator()); } /** * {@code expected} and {@code actual} are equal if they have the same * elements, possibly in different order. */ public static <T> void assertEqualSets(List<T> expected, Iterator<T> actual) { List<T> actualList = new ArrayList<T>(); while(actual.hasNext()) { actualList.add(actual.next()); } assertEqualSets(expected, actualList); } /** * {@code expected} and {@code actual} are equal if they have the same * elements, possibly in different order. */ public static <T> void assertEqualSets( List<T> expected, List<T> actual) { assertEqualSets(expected, actual, false); } /** * {@code expected} and {@code actual} are equal if they have the same * elements, possibly in different order. * @param toPrettyJson if the sets are not equal, an error message with * elements of both lists is printed. If this parameter is set to * {@code true}, the string representation of each element is treated as * JSON and printed in a pretty way. */ public static <T> void assertEqualSets( List<T> expected, List<T> actual, boolean toPrettyJson) { Assert.assertEquals(String.format("The number of the "+ "expected elements (%s) is not equal to the number "+ "of the actual elements (%s).\n\n%s", expected.size(), actual.size(), elementsToString(expected, actual, toPrettyJson)), expected.size(), actual.size()); boolean[] actualMatched = new boolean[actual.size()]; for(int i = 0; i < expected.size(); i++) { boolean iMatched = false; for(int j = 0; j < actual.size(); j++) { if (actualMatched[j]) { continue; } if (expected.get(i).equals(actual.get(j))) { actualMatched[j] = true; iMatched = true; break; } } String additionalElementRawStr = expected.get(i).toString(); String additionalElementStr = null; if(!toPrettyJson){ additionalElementStr = String.format( " '%s' ", additionalElementRawStr); } else { additionalElementStr = String.format( "\n%s\n", JsonUtils.toPrettyJSON(additionalElementRawStr)); } Assert.assertTrue(String.format("The element%sthat is " + "present among expected elements was not found among the " + "actual elements.\n\n%s", additionalElementStr, elementsToString(expected, actual, toPrettyJson)), iMatched); } } private static <T> String elementsToString( List<T> expected, List<T> actual, boolean toPrettyJson){ StringBuilder builder = new StringBuilder(); builder.append("Please find a dump of expected and actual records below.\n\n"); builder.append(singleListToString(expected, "\nExpected", toPrettyJson)); builder.append(singleListToString(actual, "\n\nActual", toPrettyJson)); return builder.toString(); } private static <T> String singleListToString( List<T> elems, String name, boolean toPrettyJson){ StringBuilder builder = new StringBuilder(); builder.append(name + " records:\n"); for(int i = 0; i < dumpRecordsCountlimit; i++){ if(i == elems.size()){ break; } String elemString = elems.get(i).toString(); if(toPrettyJson){ elemString = JsonUtils.toPrettyJSON(elemString); } builder.append(elemString+"\n"); } if(elems.size() > dumpRecordsCountlimit){ builder.append("... (more records available but not shown "+ "due to print limit of "+dumpRecordsCountlimit+" records)\n"); } return builder.toString(); } /** * Check whether contents of two files are equal. A utility function. * @param resourcePath * @param otherFile */ public static void assertContentsEqual(String resourcePath, File otherFile) throws FileNotFoundException, IOException{ assertEqual( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourcePath), new FileInputStream(otherFile)); } /** * Checks whether the passed input streams are equal. The input streams are considered to be equal if their content is * the same utf-8 text (windows/unix new line differences do not matter - they are treated as if they were the same). */ public static void assertUtf8TextContentsEqual(InputStream in0, InputStream in1) { String line1 = null; String line2 = null; try (BufferedReader br1 = new BufferedReader(new InputStreamReader(in0, "UTF-8"))) { try (BufferedReader br2 = new BufferedReader(new InputStreamReader(in1, "UTF-8"))) { while ((line1 = br1.readLine()) != null & (line2 = br2.readLine()) != null) { assertEquals(line1, line2); } if (line1 != null || line2 != null) { Assert.fail(); } } } catch (Exception e) { throw new RuntimeException(e); } } /** * Assume that the contents of two input streams is equal. * * The streams are closed after the comparison is made. */ public static void assertEqual(InputStream in0, InputStream in1){ try { Assert.assertTrue(equal(in0, in1)); } catch (IOException e) { throw new RuntimeException(e); } } /** * Check if contents of two input streams is equal. * * The streams are closed after the comparison is made. */ private static boolean equal(InputStream in0, InputStream in1) throws IOException { try { byte[] buffer0 = new byte[filesCompareBufferSize]; byte[] buffer1 = new byte[filesCompareBufferSize]; int bytesRead0 = 0; int bytesRead1 = 0; while (bytesRead0 > -1) { bytesRead0 = in0.read(buffer0); bytesRead1 = in1.read(buffer1); if (bytesRead0 != bytesRead1) return false; if (!Arrays.equals(buffer0, buffer1)) return false; } return true; } finally { if (in0 != null) in0.close(); if (in1 != null) in1.close(); } } }