package notaql; import junit.framework.Assert; import notaql.datamodel.*; import notaql.engines.json.datamodel.ValueConverter; import notaql.model.EvaluationException; import org.json.JSONObject; import org.json.JSONArray; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import static org.junit.Assert.*; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * Created by thomas on 23.05.15. */ @RunWith(Parameterized.class) public class TransformationTest { private static final String BASE_PATH = "/test/transformations"; private Path inputPath; private Path outputPath; private Path expectedOutputPath; private String transformation; public TransformationTest(File inputPath, File expectedOutputPath, File transformation, String name) throws IOException { this.inputPath = convertToRows(inputPath.toPath()); this.expectedOutputPath = convertToRows(expectedOutputPath.toPath()); this.outputPath = Files.createTempFile("temp_output", ".json"); outputPath.toFile().delete(); this.transformation = "IN-ENGINE: json(path <- '" + this.inputPath.toAbsolutePath().toString() + "'),\n" + "OUT-ENGINE: json(path <- '" + this.outputPath.toAbsolutePath().toString() + "'),\n" + Files.lines(transformation.toPath()).collect(Collectors.joining("\n")); } @Test public void executionTest() throws Exception { NotaQL.evaluate(transformation); final Set<JSONObject> expectedObjects = readRows(expectedOutputPath); final Set<JSONObject> actualObjects = readSplitRows(outputPath); assertJSONEquals(expectedObjects, actualObjects); } private static Object normalize(Object o) { // complex values if(o instanceof JSONArray) { final JSONArray array = (JSONArray) o; final Set<Object> set = new HashSet<>(); IntStream.range(0, array.length()) .forEach(i -> set.add(normalize(array.get(i)))); return set; } if(o instanceof JSONObject) { final JSONObject jsonObject = (JSONObject) o; final SortedMap<String, Object> map = new TreeMap<>(); for (String key : jsonObject.keySet()) { final Object value = normalize(jsonObject.get(key)); map.put(key, value); } return map; } return o; } public void assertJSONEquals(Set<JSONObject> expected, Set<JSONObject> actual) { final Set<Object> normalizedExpected = expected.stream().map(TransformationTest::normalize).collect(Collectors.toSet()); final Set<Object> normalizedActual = actual.stream().map(TransformationTest::normalize).collect(Collectors.toSet()); if(!normalizedExpected.equals(normalizedActual)) fail("Objects are not equal:\nExpected:\t" + expected.toString() + "\nActual:\t\t" + actual.toString()); } @Parameterized.Parameters(name= "{index}: {3}") public static Collection<Object[]> data() throws URISyntaxException, IOException { URL basePath = NotaQL.class.getResource(BASE_PATH); final List<File> dirs = Files .list(Paths.get(basePath.toURI())) .map(Path::toFile) .filter(File::isDirectory) .collect(Collectors.toList()); Collection<Object[]> data = new ArrayList<Object[]>(); for (File dir : dirs) { final List<File> files = Arrays.asList(dir.listFiles()); final Optional<File> input = files.stream().filter(f -> f.getName().equals("input.json")).findAny(); final Optional<File> output = files.stream().filter(f -> f.getName().equals("output.json")).findAny(); final Optional<File> transformation = files.stream().filter(f -> f.getName().equals("transformation.notaql")).findAny(); if(!input.isPresent() || !output.isPresent() || !transformation.isPresent()) continue; data.add(new Object[]{input.get(), output.get(), transformation.get(), dir.getName() }); } return data; } private static Set<JSONObject> readSplitRows(Path path) throws IOException { Set<JSONObject> objects = new HashSet<>(); final List<Path> files = Files.list(path) .filter(p -> p.getFileName().toString().startsWith("part-")) .collect(Collectors.toList()); for (Path file : files) { Files.lines(file) .map(JSONObject::new) .forEach(objects::add); } return objects; } private static Set<JSONObject> readRows(Path path) throws IOException { Set<JSONObject> objects = new HashSet<>(); Files.lines(path) .map(JSONObject::new) .forEach(objects::add); return objects; } private static Set<JSONObject> readArray(Path path) throws IOException { final String input = Files.lines(path).collect(Collectors.joining()); final JSONArray jsonArray = new JSONArray(input); final HashSet<JSONObject> elements = new HashSet<>(); for(int i = 0; i < jsonArray.length(); i++) { final Object element = jsonArray.get(i); if(!(element instanceof JSONObject)) throw new IOException("Expecting an array of objects as input."); elements.add((JSONObject)element); } return elements; } private static Path convertToRows(Path input) throws IOException { final Set<JSONObject> objects = readArray(input); final Path path = Files.createTempFile("temp_input", ".json"); Files.write( path, objects.stream() .map(JSONObject::toString) .collect(Collectors.toSet()) ); return path; } }