/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.chakra; import static com.github.anba.es6draft.util.Resources.loadConfiguration; import static com.github.anba.es6draft.util.Resources.loadTests; import static org.junit.Assume.assumeTrue; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UncheckedIOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import org.apache.commons.configuration.Configuration; import org.apache.commons.io.ByteOrderMark; import org.apache.commons.io.input.BOMInputStream; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; import org.junit.rules.Timeout; import org.junit.runner.RunWith; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.junit.runners.Parameterized.UseParametersRunnerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.github.anba.es6draft.runtime.internal.Properties.Function; import com.github.anba.es6draft.util.NullConsole; import com.github.anba.es6draft.util.Parallelized; import com.github.anba.es6draft.util.ParameterizedRunnerFactory; import com.github.anba.es6draft.util.Resources; import com.github.anba.es6draft.util.TestConfiguration; import com.github.anba.es6draft.util.TestGlobals; import com.github.anba.es6draft.util.TestInfo; import com.github.anba.es6draft.util.rules.ExceptionHandlers.ScriptExceptionHandler; import com.github.anba.es6draft.util.rules.ExceptionHandlers.StandardErrorHandler; /** * Test suite for the ChakraCore tests. */ @RunWith(Parallelized.class) @UseParametersRunnerFactory(ParameterizedRunnerFactory.class) @TestConfiguration(name = "chakra.test", file = "resource:/test-configuration.properties") public final class ChakraTest { private static final Configuration configuration = loadConfiguration(ChakraTest.class); @Parameters(name = "{0}") public static List<ChakraTestInfo> suiteValues() throws IOException { return loadTests(configuration, createTestFunction()); } @BeforeClass public static void setUpClass() throws IOException { ChakraTestGlobalObject.testLoadInitializationScript(); } @ClassRule public static TestGlobals<ChakraTestGlobalObject, TestInfo> globals = new TestGlobals<>(configuration, ChakraTestGlobalObject::new); @Rule public Timeout maxTime = new Timeout(120, TimeUnit.SECONDS); @Rule public ErrorCollector collector = new ErrorCollector(); @Rule public StandardErrorHandler errorHandler = new StandardErrorHandler(); @Rule public ScriptExceptionHandler exceptionHandler = new ScriptExceptionHandler(); @Parameter(0) public ChakraTestInfo test; private static final class ChakraTestInfo extends TestInfo { String baseline; Iterator<String> expected = Collections.emptyIterator(); public ChakraTestInfo(Path basedir, Path file) { super(basedir, file); } } private ChakraTestGlobalObject global; @Before public void setUp() throws Throwable { assumeTrue("Test disabled", test.isEnabled()); global = globals.newGlobal(new NullConsole(), test); exceptionHandler.setExecutionContext(global.getRealm().defaultContext()); if (test.baseline != null && !test.baseline.isEmpty()) { global.createGlobalProperties(new MessageProducer(), MessageProducer.class); test.expected = lineIterator(test.toFile().resolveSibling(test.baseline)); } } @After public void tearDown() { globals.release(global); } @Test public void runTest() throws Throwable { // Evaluate actual test-script global.eval(test.getScript(), test.toFile()); // Wait for pending tasks to finish global.getRealm().getWorld().runEventLoop(); } public final class MessageProducer { @Function(name = "$MESSAGE", arity = 0) public String message() { if (test.expected.hasNext()) { return test.expected.next(); } return null; } } private static final class TestSetting { String baseline; boolean disabled; } private static BiFunction<Path, Path, ChakraTestInfo> createTestFunction() { HashMap<Path, Map<String, TestSetting>> settingsMapping = new HashMap<>(); return (basedir, file) -> { ChakraTestInfo testInfo = new ChakraTestInfo(basedir, file); Path dir = basedir.resolve(file).getParent(); Map<String, TestSetting> map = settingsMapping.computeIfAbsent(dir, ChakraTest::readSettings); TestSetting setting = map.get(file.getFileName().toString()); if (setting != null) { testInfo.baseline = setting.baseline; testInfo.setEnabled(!setting.disabled); } return testInfo; }; } private static Map<String, TestSetting> readSettings(Path dir) { Path settingsFile = dir.resolve("rlexe.xml"); if (Files.isRegularFile(settingsFile)) { try (Reader reader = bomReader(Files.newInputStream(settingsFile))) { Document doc = Resources.xml(reader); NodeList elements = doc.getElementsByTagName("default"); HashMap<String, TestSetting> settingMap = new HashMap<>(); for (int i = 0, length = elements.getLength(); i < length; ++i) { Element element = (Element) elements.item(i); String files = element.getElementsByTagName("files").item(0).getTextContent(); TestSetting setting = new TestSetting(); NodeList baseline = element.getElementsByTagName("baseline"); if (baseline.getLength() > 0) { setting.baseline = baseline.item(0).getTextContent(); } NodeList compileFlags = element.getElementsByTagName("compile-flags"); if (compileFlags.getLength() > 0) { String flags = compileFlags.item(0).getTextContent(); setting.disabled = flags.contains("-verbose") || flags.contains("-dump:") || flags.contains("-trace:") || flags.contains("-testtrace:") || flags.contains("-testTrace:"); } settingMap.putIfAbsent(files, setting); } return settingMap; } catch (IOException e) { throw new UncheckedIOException(e); } } return Collections.emptyMap(); } private static Iterator<String> lineIterator(Path p) throws IOException { try (BufferedReader reader = bomReader(Files.newInputStream(p))) { ArrayList<String> list = new ArrayList<>(); for (;;) { String line = reader.readLine(); if (line == null) break; list.add(line); } return list.iterator(); } } private static BufferedReader bomReader(InputStream is) throws IOException { BOMInputStream bis = new BOMInputStream(is); Charset cs = charsetFor(bis, StandardCharsets.UTF_8); return new BufferedReader(new InputStreamReader(bis, cs)); } private static Charset charsetFor(BOMInputStream bis, Charset defaultCharset) throws IOException { ByteOrderMark bom = bis.getBOM(); if (ByteOrderMark.UTF_8.equals(bom)) { return StandardCharsets.UTF_8; } if (ByteOrderMark.UTF_16LE.equals(bom)) { return StandardCharsets.UTF_16LE; } if (ByteOrderMark.UTF_16BE.equals(bom)) { return StandardCharsets.UTF_16BE; } return defaultCharset; } }