blob: 0263d6221d1d0f1dd9ef7439b7399c4a30a0fa23 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.parser;
import com.google.dart.compiler.DartCompilationError;
import com.google.dart.compiler.DartCompilerListenerTest;
import com.google.dart.compiler.DartSourceTest;
import com.google.dart.compiler.ast.DartUnit;
public class TruncatedSourceParserTest extends AbstractParserTest {
private static final int RESULTS_TIMEOUT_SECONDS = 10;
private static enum ParseState {
INIT, STARTED_PARSE, STOP,
}
/**
* Performs parsing in a separate thread such that the test can detect infinite loop.
*/
private class ParserThread extends Thread {
private final Object lock = new Object();
private final String srcName;
private ParseState state = ParseState.INIT;
private String srcCode;
private DartUnit result;
/**
* Listener that ignores errors because this is a stress test
*/
private DartCompilerListenerTest listener = new DartCompilerListenerTest("") {
@Override
public void checkAllErrorsReported() {
}
@Override
public void onError(DartCompilationError event) {
}
};
public ParserThread(String srcName) {
super("Parsing " + srcName);
this.srcName = srcName;
}
/**
* Queue the specified source to be parsed on a separate thread. Wait up to 10 seconds for the
* result
*
* @return <code>true</code> if finished parsing
*/
public boolean parse(String srcCode) {
assert (srcCode != null);
assert (state == ParseState.INIT);
synchronized (lock) {
this.srcCode = srcCode;
result = null;
state = ParseState.STARTED_PARSE;
lock.notifyAll();
try {
lock.wait(RESULTS_TIMEOUT_SECONDS * 1000);
} catch (InterruptedException e) {
// Fall through
}
return state == ParseState.INIT;
}
}
/**
* Parse source code in the background
*/
@Override
public void run() {
while (true) {
DartSourceTest src;
synchronized (lock) {
while (state == ParseState.INIT) {
try {
lock.wait();
} catch (InterruptedException e) {
// Fall through
}
}
if (state == ParseState.STOP) {
return;
}
src = new DartSourceTest(srcName, srcCode, null);
}
DartUnit unit = makeParser(src, srcCode, listener).parseUnit();
synchronized (lock) {
if (state == ParseState.STOP) {
return;
}
state = ParseState.INIT;
result = unit;
lock.notifyAll();
}
}
}
/**
* Signal the background thread to terminate
*/
public void stopParsing() {
synchronized (lock) {
state = ParseState.STOP;
lock.notify();
}
}
}
@Override
public void testStringsErrors() {
parseUnit("StringsErrorsNegativeTest.dart");
}
@Override
public void testTiming() {
// Skip
}
@Override
protected DartUnit parseUnit(String srcName, String srcCode, Object... errors) {
if ("true".equals(System.getProperty("analysis_skip_TruncatedSourceParserTest"))) {
return null;
}
if (errors.length > 0) {
throw new RuntimeException("Expected errors not implemented");
}
// System.out.print(srcName);
ParserThread thread = new ParserThread(srcName);
thread.start();
int eol = 0;
for (int index = 0; index < srcCode.length(); index++) {
if (eol == index) {
eol++;
while (eol < srcCode.length()) {
char ch = srcCode.charAt(eol);
if (ch == '\r' || ch == '\n') {
break;
}
eol++;
}
}
String modifiedSrcCode = srcCode.substring(0, index);
if (!thread.parse(modifiedSrcCode)) {
// System.out.println();
fail("Failed to finish parsing " + srcName + "\n" + modifiedSrcCode);
}
modifiedSrcCode += srcCode.substring(eol);
if (!thread.parse(modifiedSrcCode)) {
// System.out.println();
fail("Failed to finish parsing " + srcName + "\n" + modifiedSrcCode);
}
// System.out.print('.');
}
thread.stopParsing();
// System.out.println();
return thread.result;
}
}