/**
* 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.test262;
import static com.github.anba.es6draft.util.Resources.loadConfiguration;
import static com.github.anba.es6draft.util.matchers.ErrorMessageMatcher.hasErrorMessage;
import static com.github.anba.es6draft.util.matchers.PatternMatcher.matchesPattern;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.configuration.Configuration;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestWatcher;
import org.junit.rules.Timeout;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
import com.github.anba.es6draft.runtime.internal.Strings;
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.SystemConsole;
import com.github.anba.es6draft.util.TestConfiguration;
import com.github.anba.es6draft.util.TestGlobals;
import com.github.anba.es6draft.util.rules.ExceptionHandlers.ScriptExceptionHandler;
import com.github.anba.es6draft.util.rules.ExceptionHandlers.StandardErrorHandler;
/**
* The standard test262 test suite
*/
@RunWith(Parallelized.class)
@UseParametersRunnerFactory(ParameterizedRunnerFactory.class)
@TestConfiguration(name = "test262.test.web", file = "resource:/test-configuration.properties")
public final class Test262Web {
private static final Configuration configuration = loadConfiguration(Test262Web.class);
private static final DefaultMode unmarkedDefault = DefaultMode.forName(configuration.getString("unmarked_default"));
private static final Set<String> includeFeatures = stringSet(configuration.getList("include.features"));
private static final Set<String> excludeFeatures = stringSet(configuration.getList("exclude.features"));
public static final Set<String> stringSet(List<?> xs) {
Predicate<String> nonEmpty = ((Predicate<String>) String::isEmpty).negate();
return xs.stream().filter(Objects::nonNull).map(Object::toString).filter(nonEmpty).collect(Collectors.toSet());
}
@Parameters(name = "{0}")
public static List<Test262Info> suiteValues() throws IOException {
return Resources.loadTests(configuration, Test262Info::new);
}
@ClassRule
public static TestGlobals<Test262GlobalObject, Test262Info> globals = new TestGlobals<Test262GlobalObject, Test262Info>(
configuration, Test262GlobalObject::new) {
static final boolean USE_SHARED_EXECUTOR = false;
final ExecutorService shared = USE_SHARED_EXECUTOR ? createDefaultSharedExecutor() : null;
@Override
public void release(Test262GlobalObject global) {
if (!USE_SHARED_EXECUTOR) {
super.release(global);
} else if (global != null) {
// Worker executors are not shared, explicit shutdown required.
global.getRuntimeContext().getWorkerExecutor().shutdown();
}
}
@Override
protected ExecutorService getExecutor() {
return shared;
}
};
@Rule
public TestWatcher watcher = new TestWatcher() {
@Override
protected void starting(Description description) {
isStrictTest = description.getAnnotation(Strict.class) != null;
}
};
private boolean isStrictTest = false;
@Rule
public Timeout maxTime = new Timeout(120, TimeUnit.SECONDS);
@Rule
public StandardErrorHandler errorHandler = StandardErrorHandler.none();
@Rule
public ScriptExceptionHandler exceptionHandler = ScriptExceptionHandler.none();
@Rule
public ExpectedException expected = ExpectedException.none();
@Parameter(0)
public Test262Info test;
private Test262GlobalObject global;
private Test262Async async;
private String sourceCode;
private int preambleLines;
private boolean isValidTestConfiguration() {
return test.hasMode(isStrictTest, unmarkedDefault) && test.hasFeature(includeFeatures, excludeFeatures);
}
@Before
public void setUp() throws Throwable {
// Filter disabled tests
assumeTrue("Test disabled", test.isEnabled());
String fileContent = test.readFile();
if (!isValidTestConfiguration()) {
return;
}
final String preamble;
if (test.isRaw() || test.isModule()) {
preamble = "";
preambleLines = 0;
} else if (isStrictTest) {
preamble = "\"use strict\";\nvar strict_mode = true;\n";
preambleLines = 2;
} else {
preamble = "//\"use strict\";\nvar strict_mode = false;\n";
preambleLines = 2;
}
sourceCode = Strings.concat(preamble, fileContent);
global = globals.newGlobal(new SystemConsole(), test);
exceptionHandler.setExecutionContext(global.getRealm().defaultContext());
if (!test.isNegative()) {
errorHandler.match(StandardErrorHandler.defaultMatcher());
exceptionHandler.match(ScriptExceptionHandler.defaultMatcher());
} else {
expected.expect(
Matchers.either(StandardErrorHandler.defaultMatcher()).or(ScriptExceptionHandler.defaultMatcher()));
String errorType = test.getErrorType();
if (errorType != null) {
expected.expect(hasErrorMessage(global.getRealm().defaultContext(),
matchesPattern(errorType, Pattern.CASE_INSENSITIVE)));
}
}
// Load test includes
for (String name : test.getIncludes()) {
global.include(name);
}
if (test.isAsync()) {
async = global.createGlobalProperties(new Test262Async(), Test262Async.class);
}
}
@After
public void tearDown() {
globals.release(global);
}
@Test
public void runTest() throws Throwable {
if (!isValidTestConfiguration()) {
return;
}
// Evaluate actual test-script
if (test.isModule()) {
global.evalModule(test.toModuleName(), sourceCode, 1 - preambleLines);
} else {
global.eval(test.toFile(), sourceCode, 1 - preambleLines);
}
// Wait for pending tasks to finish
if (test.isAsync()) {
assertFalse(async.isDone());
global.getRealm().getWorld().runEventLoop();
assertTrue(async.isDone());
} else {
global.getRealm().getWorld().runEventLoop();
}
}
@Test
@Strict
public void runTestStrict() throws Throwable {
if (!isValidTestConfiguration()) {
return;
}
// Evaluate actual test-script
if (test.isModule()) {
global.evalModule(test.toModuleName(), sourceCode, 1 - preambleLines);
} else {
global.eval(test.toFile(), sourceCode, 1 - preambleLines);
}
// Wait for pending tasks to finish
if (test.isAsync()) {
assertFalse(async.isDone());
global.getRealm().getWorld().runEventLoop();
assertTrue(async.isDone());
} else {
global.getRealm().getWorld().runEventLoop();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface Strict {
}
}