/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.tools.oth;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jikesrvm.classloader.ApplicationClassLoader;
import org.jikesrvm.classloader.Atom;
import org.jikesrvm.classloader.NormalMethod;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.OptOptions;
import org.jikesrvm.junit.runners.RequiresBuiltJikesRVM;
import org.jikesrvm.junit.runners.RequiresLackOfOptCompiler;
import org.jikesrvm.junit.runners.RequiresOptCompiler;
import org.jikesrvm.junit.runners.VMRequirements;
import org.jikesrvm.tests.util.TestingTools;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
@RunWith(VMRequirements.class)
@Category(RequiresBuiltJikesRVM.class)
public class OptTestHarnessTest {
private static final String lineEnd = System.getProperty("line.separator");
private static final PrintStream standardSysOut = System.out;
private static final PrintStream standardSysErr = System.err;
private static final String baselineMethodCompileString = "Compiling X methods baseline" + lineEnd;
private static final String optMethodCompileString = "Compiling X methods opt" + lineEnd;
private static final String EMPTY_CLASS = "org.jikesrvm.tools.oth.EmptyClass";
private static final String ABSTRACT_CLASS_WITH_EMPTY_METHOD = "org.jikesrvm.tools.oth.AbstractClassWithEmptyMethod";
private static final String CLASS_WITH_STATIC_METHOD = "org.jikesrvm.tools.oth.ClassWithStaticMethod";
private static final String CLASS_OVERLOADED_METHODS = "org.jikesrvm.tools.oth.ClassWithOverloadedMethods";
private static final String CLASS_WITH_MAIN_METHOD = "org.jikesrvm.tools.oth.ClassWithMainMethod";
private static final String CLASS_WITHOUT_MAIN_METHOD = "org.jikesrvm.tools.oth.ClassWithoutMainMethod";
private static final String CLASS_WITH_INSTANCE_METHOD = "org.jikesrvm.tools.oth.ClassWithInstanceMethod";
private static final String CLASS_WITH_PRIVATE_CONSTRUCTOR = "org.jikesrvm.tools.oth.ClassWithPrivateConstructor";
private TestOutput output;
private TestFileAccess fileAccess;
private void redirectStandardStreams() {
System.setOut(output.getSystemOut());
System.setErr(output.getSystemErr());
}
private void resetStandardStreams() {
System.setOut(standardSysOut);
System.setErr(standardSysErr);
}
@Test
@Category(RequiresLackOfOptCompiler.class)
public void doesNotCrashWhenNoOptCompilerIsAvailable() throws InvocationTargetException, IllegalAccessException {
String[] emptyArgs = {};
executeOptTestHarness(emptyArgs);
}
private OptTestHarness executeOptTestHarness(String[] commandLineArguments)
throws InvocationTargetException, IllegalAccessException {
output = new TestOutput();
fileAccess = new TestFileAccess();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), fileAccess);
oth.mainMethod(commandLineArguments);
return oth;
}
@Test
public void emptyArgsLeadToNoCompiles() throws InvocationTargetException, IllegalAccessException {
String[] emptyArgs = new String[0];
executeOptTestHarness(emptyArgs);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatRemainingOutputIsEmptyWhenTrimmed();
assertThatNoAdditionalErrorsHaveOccurred();
}
private void assertNumberOfCompiledMethodsIsCorrect(String s, int i) {
String expected = s.replace("X", Integer.toString(i));
int expectedLength = expected.length();
int startIndex = getStandardOutput().indexOf(expected);
if (startIndex == -1) {
assertThat(getStandardOutput(), equalTo(expected));
}
getStandardStream().replace(startIndex, startIndex + expectedLength, "");
}
private void assertThatNumberOfBaselineCompiledMethodsIs(int i) {
assertNumberOfCompiledMethodsIsCorrect(baselineMethodCompileString, i);
}
private void assertThatNumberOfOptCompiledMethodsIs(int i) {
assertNumberOfCompiledMethodsIsCorrect(optMethodCompileString, i);
}
@Test
public void incompleteArgsLeadToErrorMessage() throws Exception {
String[] incompleteArgs = {"-load"};
executeOptTestHarness(incompleteArgs);
String incompleteArgsMsg = "Uncaught ArrayIndexOutOfBoundsException, possibly" +
" not enough command-line arguments - aborting" + lineEnd;
assertThat(getErrorOutput().startsWith(incompleteArgsMsg), is(true));
removeMessageFromErrorOutput(incompleteArgsMsg);
String formatStringMsg = "Format: rvm org.jikesrvm.tools.oth.OptTestHarness { <command> }" + lineEnd;
assertThat(getErrorOutput().startsWith(formatStringMsg), is(true));
removeMessageFromErrorOutput(formatStringMsg);
assertThat(getErrorOutput().isEmpty(), is(false));
}
private StringBuilder getStandardStream() {
return output.getStandardOutput();
}
private String getStandardOutput() {
return getStandardStream().toString();
}
private String getErrorOutput() {
return output.getStandardError().toString();
}
private void removeMessageFromErrorOutput(String msg) {
int index = getErrorOutput().indexOf(msg);
if (index == -1) {
assertThat(getErrorOutput(), equalTo(msg));
}
output.getStandardError().replace(index, index + msg.length(), "");
}
@Test
public void singleUnknownArgIsIgnored() throws Exception {
String arg = "-foo";
String[] unknownArg = {arg};
executeOptTestHarness(unknownArg);
assertThatErrorForUnrecognizedArgumentOccurred(arg);
assertThatNoAdditionalErrorsHaveOccurred();
}
private void assertThatErrorForUnrecognizedArgumentOccurred(
String unrecognizedArgument) {
String unknownArgMsg = "Unrecognized argument: " + unrecognizedArgument + " - ignored" + lineEnd;
assertThat(getErrorOutput().startsWith(unknownArgMsg), is(true));
removeMessageFromErrorOutput(unknownArgMsg);
}
@Test
public void allUnknownArgsAreIgnored() throws Exception {
String firstUnknownArg = "-foo";
String secondUnknownArg = "-bar";
String[] multipleUnknownArgs = {firstUnknownArg, secondUnknownArg};
executeOptTestHarness(multipleUnknownArgs);
assertThatErrorForUnrecognizedArgumentOccurred(firstUnknownArg);
assertThatErrorForUnrecognizedArgumentOccurred(secondUnknownArg);
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
@Category(RequiresOptCompiler.class)
public void knownArgumentsAreProcessedEvenIfUnknownArgumentsAppear() throws Exception {
String unknownArgument = "-foo";
String[] arguments = {unknownArgument, "+baseline"};
OptTestHarness oth = executeOptTestHarness(arguments);
assertThatErrorForUnrecognizedArgumentOccurred(unknownArgument);
assertThatNoAdditionalErrorsHaveOccurred();
assertThat(oth.useBaselineCompiler, is(true));
}
@Test
public void canLoadAClassByItsClassname() throws Exception {
String className = EMPTY_CLASS;
assertClassIsNotLoaded(className);
String[] loadClass = {"-load", className};
executeOptTestHarness(loadClass);
assertClassIsLoaded(className);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
private void assertThatRemainingOutputIsEmptyWhenTrimmed() {
assertThat(getStandardOutput().trim(), equalTo(""));
}
private void assertClassIsLoaded(String className) {
TypeReference tRef = getTypeReferenceForClass(className);
assertNotNull(tRef.peekType());
}
private TypeReference getTypeReferenceForClass(String className) {
Atom classDescriptorAsAtom = Atom.findAsciiAtom(className).descriptorFromClassName();
ClassLoader appCl = ApplicationClassLoader.getSystemClassLoader();
return TypeReference.findOrCreate(appCl, classDescriptorAsAtom);
}
@Test
public void loadClassThatDoesNotExist() throws Exception {
String className = "com.ibm.jikesrvm.DoesNotExist";
assertClassIsNotLoaded(className);
String[] loadClass = {"-load", className};
executeOptTestHarness(loadClass);
String classNotFoundFirstLineStart = "java.lang.ClassNotFoundException: ";
String classNotFoundFirstLineEnd = " not found in SystemAppCL";
String firstLineOfStackTrace = classNotFoundFirstLineStart + className + classNotFoundFirstLineEnd;
assertThat(getErrorOutput().startsWith(firstLineOfStackTrace), is(true));
}
@Test
public void convertToClassNameWorksForDescriptors() throws Exception {
String result = replacePointsWithSlashes("org.jikesrvm.tools.oth.TestClass2");
String classDescriptor = "Lorg/jikesrvm/tools/oth/TestClass2;";
assertThat(OptTestHarness.convertToClassName(classDescriptor),is(result));
}
@Test
public void convertToClassNameWorksForFullyQualifiedClassNames() throws Exception {
String result = "org.jikesrvm.tools.oth.TestClass2";
assertThat(OptTestHarness.convertToClassName(result), is(result));
}
@Test
public void convertToClassNameWorksForSourceFileNames() throws Exception {
String className = "TestClass3";
String classSourcefile = className + ".java";
assertThat(OptTestHarness.convertToClassName(classSourcefile),is(className));
}
@Test
public void convertToClassNameWorksForClassfileName() throws Exception {
String className = "TestClass4";
String classClassFile = className + ".class";
assertThat(OptTestHarness.convertToClassName(classClassFile),is(className));
}
@Test
public void convertToClassNameWorksForASimplePathString() throws Exception {
String className = "TestClass5";
String pathOfClass = "./" + className;
assertThat(OptTestHarness.convertToClassName(pathOfClass),is(className));
}
@Test
public void convertToClassNameDoesNotWorkForComplexPathstrings() throws Exception {
String className = "org.jikesrvm.tools.oth.TestClass7";
String pathOfClass = "../.." + className;
assertThat(OptTestHarness.convertToClassName(pathOfClass),is(pathOfClass));
}
private String replacePointsWithSlashes(String s) {
return s.replace(".", "/");
}
private void assertClassIsNotLoaded(String className) {
TypeReference tRef = getTypeReferenceForClass(className);
assertNull(tRef.peekType());
}
private void assertThatNoAdditionalErrorsHaveOccurred() {
assertThat(getErrorOutput(), equalTo(""));
}
@Test
@Category(RequiresOptCompiler.class)
public void methodsAreOptCompiledByDefault() throws Exception {
String[] compileClass = {"-class", ABSTRACT_CLASS_WITH_EMPTY_METHOD};
executeOptTestHarness(compileClass);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(2);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> testClass2 = Class.forName(ABSTRACT_CLASS_WITH_EMPTY_METHOD);
NormalMethod emptyMethod = TestingTools.getNormalMethod(testClass2, "emptyMethod");
assertThatOutputContainsMessageForCompiledMethod(emptyMethod);
removeCompiledMethodMessageFromStandardOutput(emptyMethod);
NormalMethod constructor = TestingTools.getNoArgumentConstructor(testClass2);
assertThatOutputContainsMessageForCompiledMethod(constructor);
removeCompiledMethodMessageFromStandardOutput(constructor);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
private void removeCompiledMethodMessageFromStandardOutput(NormalMethod nm) {
String compiledMethodMessage = OptTestHarness.compiledMethodMessage(nm);
removeMessageFromStandardOutput(compiledMethodMessage);
}
private void removeMessageFromStandardOutput(String msg) {
int index = output.getStandardOutput().indexOf(msg);
if (index == -1) {
assertThat(getStandardOutput(), equalTo(msg));
}
output.getStandardOutput().replace(index, index + msg.length(), "");
}
private void assertThatOutputContainsMessageForCompiledMethod(
NormalMethod normalMethod) {
String messageForCompiledMethod = OptTestHarness.compiledMethodMessage(normalMethod);
assertThat(getStandardOutput().contains(messageForCompiledMethod), is(true));
}
@Test
@Category(RequiresOptCompiler.class)
public void methodsAreBaselineCompiledIfRequested() throws Exception {
String[] compileClass = {"+baseline", "-class", ABSTRACT_CLASS_WITH_EMPTY_METHOD};
executeOptTestHarness(compileClass);
assertThatBothMethodsOfTestClass2HaveBeenBaselineCompiled();
}
@Test
@Category(RequiresLackOfOptCompiler.class)
public void defaultCompilerIsBaselineWhenVMIsBuildWithoutOptCompiler() throws Exception {
String[] compileClass = {"-class", ABSTRACT_CLASS_WITH_EMPTY_METHOD};
executeOptTestHarness(compileClass);
assertThatBothMethodsOfTestClass2HaveBeenBaselineCompiled();
}
private void assertThatBothMethodsOfTestClass2HaveBeenBaselineCompiled()
throws ClassNotFoundException, Exception {
assertThatNumberOfBaselineCompiledMethodsIs(2);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> testClass2 = Class.forName(ABSTRACT_CLASS_WITH_EMPTY_METHOD);
NormalMethod emptyMethod = TestingTools.getNormalMethod(testClass2, "emptyMethod");
assertThatOutputContainsMessageForCompiledMethod(emptyMethod);
removeCompiledMethodMessageFromStandardOutput(emptyMethod);
NormalMethod constructor = TestingTools.getNoArgumentConstructor(testClass2);
assertThatOutputContainsMessageForCompiledMethod(constructor);
removeCompiledMethodMessageFromStandardOutput(constructor);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
public void baselineCompilationCanBeSwitchedOnAndOff() throws Exception {
String[] args = { "+baseline" };
OptTestHarness oth = executeOptTestHarness(args);
assertThat(oth.useBaselineCompiler, is(true));
String[] useOpt = { "+baseline" , "-baseline" };
oth = executeOptTestHarness(useOpt);
assertThat(oth.useBaselineCompiler, is(false));
}
@Test
@Category(RequiresOptCompiler.class)
public void methodsAreOptCompiledByDefaultWhenSingleMethodIsCompiled() throws Exception {
String[] compileClass = {"-method", ABSTRACT_CLASS_WITH_EMPTY_METHOD, "emptyMethod", "-"};
executeOptTestHarness(compileClass);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(1);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> testClass2 = Class.forName(ABSTRACT_CLASS_WITH_EMPTY_METHOD);
NormalMethod emptyMethod = TestingTools.getNormalMethod(testClass2, "emptyMethod");
assertThatOutputContainsMessageForCompiledMethod(emptyMethod);
removeCompiledMethodMessageFromStandardOutput(emptyMethod);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
@Category(RequiresOptCompiler.class)
public void methodsWillBeBaselineCompiledIfRequested() throws Exception {
String[] compileClass = {"-methodBase", ABSTRACT_CLASS_WITH_EMPTY_METHOD, "emptyMethod", "-"};
executeOptTestHarness(compileClass);
assertThatNumberOfBaselineCompiledMethodsIs(1);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> testClass2 = Class.forName(ABSTRACT_CLASS_WITH_EMPTY_METHOD);
NormalMethod emptyMethod = TestingTools.getNormalMethod(testClass2, "emptyMethod");
assertThatOutputContainsMessageForCompiledMethod(emptyMethod);
removeCompiledMethodMessageFromStandardOutput(emptyMethod);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
@Category(RequiresOptCompiler.class)
public void methodsWillOptCompiledIfRequested() throws Exception {
String[] compileClass = {"+baseline", "-methodOpt", ABSTRACT_CLASS_WITH_EMPTY_METHOD, "emptyMethod", "-"};
executeOptTestHarness(compileClass);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(1);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> testClass2 = Class.forName(ABSTRACT_CLASS_WITH_EMPTY_METHOD);
NormalMethod emptyMethod = TestingTools.getNormalMethod(testClass2, "emptyMethod");
assertThatOutputContainsMessageForCompiledMethod(emptyMethod);
removeCompiledMethodMessageFromStandardOutput(emptyMethod);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
@Category(RequiresLackOfOptCompiler.class)
public void defaultCompilerForMethodsIsBaselineWhenVMIsBuildWithoutOptCompiler() throws Exception {
String[] compileClass = {"-method", ABSTRACT_CLASS_WITH_EMPTY_METHOD, "emptyMethod", "-"};
executeOptTestHarness(compileClass);
assertThatNumberOfBaselineCompiledMethodsIs(1);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> testClass2 = Class.forName(ABSTRACT_CLASS_WITH_EMPTY_METHOD);
NormalMethod emptyMethod = TestingTools.getNormalMethod(testClass2, "emptyMethod");
assertThatOutputContainsMessageForCompiledMethod(emptyMethod);
removeCompiledMethodMessageFromStandardOutput(emptyMethod);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
public void complainsWhenClassForMethodIsNotFound() throws Exception {
String wrongClassName = "com.ibm.jikesrvm.TestClass";
String wrongMethodName = "printWithWrongName";
String useFirstMethod = "-";
String[] compilePrintIntMethod = {"-method", wrongClassName, wrongMethodName,
useFirstMethod};
executeOptTestHarness(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "WARNING: Skipping method from " + wrongClassName +
lineEnd;
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatErrorForUnrecognizedArgumentOccurred(wrongMethodName);
assertThatErrorForUnrecognizedArgumentOccurred(useFirstMethod);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
public void complainsWhenMethodWithNameIsNotFound() throws Exception {
String wrongMethodName = "printWithWrongName";
String[] compilePrintIntMethod = {"-method", CLASS_OVERLOADED_METHODS, wrongMethodName, "-"};
executeOptTestHarness(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "No method named " + wrongMethodName + " found in class " +
CLASS_OVERLOADED_METHODS + lineEnd + "WARNING: Skipping method " + CLASS_OVERLOADED_METHODS + "." +
wrongMethodName + lineEnd;
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
public void complainsWhenMethodWithDescriptorIsNotFound() throws Exception {
String wrongDescriptor = "(BBB)I";
String method = "print";
String[] compilePrintIntMethod = {"-method", CLASS_OVERLOADED_METHODS, method, wrongDescriptor};
executeOptTestHarness(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "No method matching " + method + " " + wrongDescriptor + " found in class " +
CLASS_OVERLOADED_METHODS + lineEnd + "WARNING: Skipping method " + CLASS_OVERLOADED_METHODS + "." +
method + lineEnd;
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
public void methodOptionsCanDistinguishMethodsBasedOnDescriptors() throws Exception {
String[] compilePrintIntMethod = {"-methodBase", CLASS_OVERLOADED_METHODS, "print", "(I)V"};
executeOptTestHarness(compilePrintIntMethod);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatNumberOfBaselineCompiledMethodsIs(1);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> classWithOverloadedMethods = Class.forName(CLASS_OVERLOADED_METHODS);
NormalMethod printMethod = TestingTools.getNormalMethod(classWithOverloadedMethods, "print", int.class);
assertThatOutputContainsMessageForCompiledMethod(printMethod);
removeCompiledMethodMessageFromStandardOutput(printMethod);
assertThatRemainingOutputIsEmptyWhenTrimmed();
}
@Test
public void testHarnessCanExecuteStaticMethods() throws Exception {
String[] executeMethod = {"-er", CLASS_WITH_STATIC_METHOD, "printMessage", "-"};
executeOTHWithStreamRedirection(executeMethod);
assertThatNoAdditionalErrorsHaveOccurred();
assertThat(getStandardOutput().contains(ClassWithStaticMethod.PRINTOUT), is(true));
}
@Test
public void testHarnessCanExecuteInstanceMethods() throws Exception {
String[] executeInstanceMethod = {"-er", CLASS_WITH_INSTANCE_METHOD, "printItWorks", "-"};
executeOTHWithStreamRedirection(executeInstanceMethod);
assertThatNoAdditionalErrorsHaveOccurred();
assertThat(getStandardOutput().contains(ClassWithInstanceMethod.PRINTOUT), is(true));
}
private void executeOTHWithStreamRedirection(String[] othArguments)
throws InvocationTargetException, IllegalAccessException {
try {
output = new TestOutput();
fileAccess = new TestFileAccess();
redirectStandardStreams();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), fileAccess);
oth.mainMethod(othArguments);
} finally {
resetStandardStreams();
}
}
@Test
public void methodsCompiledUsingExecutedAndRunAreNotCounted() throws Exception {
String[] executeAndRun = {"-er", CLASS_WITH_STATIC_METHOD, "printMessage", "-"};
executeOTHWithStreamRedirection(executeAndRun);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
Class<?> testClass3 = Class.forName(CLASS_WITH_STATIC_METHOD);
NormalMethod printMessage = TestingTools.getNormalMethod(testClass3, "printMessage");
assertThatOutputContainsMessageForCompiledMethod(printMessage);
removeCompiledMethodMessageFromStandardOutput(printMessage);
String output = getStandardOutput();
String expectedOutput = lineEnd + OptTestHarness.startOfExecutionString(printMessage) + lineEnd +
ClassWithStaticMethod.PRINTOUT + lineEnd + OptTestHarness.endOfExecutionString(printMessage) + lineEnd +
OptTestHarness.resultString(null) + lineEnd;
assertThat(output, equalTo(expectedOutput));
}
@Test
public void executeAndRunCanDistinguishMethodsBasedOnDescriptors() throws Exception {
double d = -1.5d;
String numberString = Double.toString(d);
String[] compilePrintIntMethod = {"-er", CLASS_OVERLOADED_METHODS, "print", "(D)V", numberString};
executeOTHWithStreamRedirection(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> classWithOverloadedMethods = Class.forName(CLASS_OVERLOADED_METHODS);
NormalMethod printMethod = TestingTools.getNormalMethod(classWithOverloadedMethods, "print", double.class);
assertThatOutputContainsMessageForCompiledMethod(printMethod);
removeCompiledMethodMessageFromStandardOutput(printMethod);
String output = getStandardOutput();
String expectedOutput = lineEnd + OptTestHarness.startOfExecutionString(printMethod) + lineEnd +
numberString + lineEnd + OptTestHarness.endOfExecutionString(printMethod) + lineEnd +
OptTestHarness.resultString(null) + lineEnd;
assertThat(output, equalTo(expectedOutput));
}
@Test
public void executeAndRunPrintsErrorMessageWhenMethodIsNotFound() throws Exception {
String notExistingMethod = "printDoesNotExist";
String[] executeMethodThatDoesNotExist = {"-er", CLASS_OVERLOADED_METHODS,
notExistingMethod, "-"};
executeOptTestHarness(executeMethodThatDoesNotExist);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "No method named " + notExistingMethod +
" found in class " + CLASS_OVERLOADED_METHODS + lineEnd +
"Canceling further option processing to prevent assertion failures." + lineEnd;
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
public void executeAndRunPrintsErrorMessageWhenMethodWithDescriptorIsNotFound() throws Exception {
String existingMethod = "print";
String descriptorThatDoesNotMatchAPrintMethod = "(IIII)V";
String[] executeMethodThatDoesNotExist = {"-er", CLASS_OVERLOADED_METHODS,
existingMethod, descriptorThatDoesNotMatchAPrintMethod};
executeOptTestHarness(executeMethodThatDoesNotExist);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "No method matching " + existingMethod + " " +
descriptorThatDoesNotMatchAPrintMethod + " found in class " +
CLASS_OVERLOADED_METHODS + lineEnd +
"Canceling further option processing to prevent assertion failures." +
lineEnd;
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
public void executeAndRunCannotParseNormalClassTypes() throws Exception {
String aString = "aStringPrintout";
String[] compilePrintIntMethod = {"-er", CLASS_OVERLOADED_METHODS, "print", "(Ljava/lang/String;)V", aString};
executeOTHWithStreamRedirection(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "Parsing args of type < BootstrapCL, Ljava/lang/String; > not implemented\n";
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatErrorForUnrecognizedArgumentOccurred(aString);
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
public void executeAndRunCannotParseGeneralArrays() throws Exception {
String anInt = "5";
String[] compilePrintIntMethod = {"-er", CLASS_OVERLOADED_METHODS, "print", "([I)V", anInt};
executeOptTestHarness(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String expectedErrorOutput = "Parsing args of array of < BootstrapCL, I > not implemented\n";
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatErrorForUnrecognizedArgumentOccurred(anInt);
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
public void executeAndRunCanParseStringArrays() throws Exception {
String firstString = "test";
String secondString = "success";
String[] compilePrintIntMethod = {"-er", CLASS_OVERLOADED_METHODS, "print", "([Ljava/lang/String;)V",
firstString, secondString};
executeOTHWithStreamRedirection(compilePrintIntMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatNoAdditionalErrorsHaveOccurred();
Class<?> classWithOverloadedMethods = Class.forName(CLASS_OVERLOADED_METHODS);
NormalMethod printMethod = TestingTools.getNormalMethod(classWithOverloadedMethods, "print", String[].class);
assertThatOutputContainsMessageForCompiledMethod(printMethod);
removeCompiledMethodMessageFromStandardOutput(printMethod);
String output = getStandardOutput();
String expectedOutput = lineEnd + OptTestHarness.startOfExecutionString(printMethod) + lineEnd +
firstString + lineEnd + secondString + lineEnd + OptTestHarness.endOfExecutionString(printMethod) + lineEnd +
OptTestHarness.resultString(null) + lineEnd;
assertThat(output, equalTo(expectedOutput));
}
@Test(expected = InternalError.class)
public void executeAndRunThrowsInternalErrorWhenNotEnoughArgumentsAreProvided() throws Exception {
String[] compilePrintIntMethod = {"-er", CLASS_OVERLOADED_METHODS, "print", "(I)V"};
executeOptTestHarness(compilePrintIntMethod);
}
@Test
public void executeAndRunPrintsErrorMessageWhenExceptionOccursWhenInvokingDefaultConstructor() throws Exception {
String[] executeInstanceMethod = {"-er", CLASS_WITH_PRIVATE_CONSTRUCTOR, "printItWorks", "-"};
executeOptTestHarness(executeInstanceMethod);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String invocationFailedMessage = "Invocation of default constructor failed for method";
assertThat(getErrorOutput().startsWith(invocationFailedMessage), is(true));
}
@Test
public void canReadCommandLineArgumentsFromFile() throws Exception {
String fileName = "commandLineArgsForLongCommandLineTest";
fileAccess = new TestFileAccess();
String fileContent = "-er\n" + CLASS_WITH_STATIC_METHOD + lineEnd +
"printMessage\n" + "-\n";
fileAccess.putContentForFile(fileName, fileContent);
String[] longCommandLine = {"-longcommandline", fileName};
try {
output = new TestOutput();
redirectStandardStreams();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), fileAccess);
oth.mainMethod(longCommandLine);
} finally {
resetStandardStreams();
}
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
public void readingNonExistingFileCausesError() throws Exception {
String fileName = "fileWhichWillNeverExist";
fileAccess = new TestFileAccess();
String[] longCommandLine = {"-longcommandline", fileName};
output = new TestOutput();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), fileAccess);
oth.mainMethod(longCommandLine);
String fileNotFoundLineStart = "java.io.FileNotFoundException: ";
String firstLineOfStackTrace = fileNotFoundLineStart + fileName + lineEnd;
assertThat(getErrorOutput().startsWith(firstLineOfStackTrace), is(true));
}
@Test
public void readingEmptyFilesDoesNotCauseProblems() throws Exception {
String fileName = "emptyFile";
fileAccess = new TestFileAccess();
fileAccess.putContentForFile(fileName, "");
String[] longCommandLine = {"-longcommandline", fileName};
output = new TestOutput();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), fileAccess);
oth.mainMethod(longCommandLine);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatRemainingOutputIsEmptyWhenTrimmed();
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
@Category(RequiresOptCompiler.class)
public void commandLineArgumentFileSupportsComments() throws Exception {
fileAccess = new TestFileAccess();
String fileName = "commandLineArgsForLongCommandLineTestWithComments";
String fileContent = "-baseline\n" + "#" + "+baseline\n";
fileAccess.putContentForFile(fileName, fileContent);
String[] longCommandLine = {"-longcommandline", fileName};
output = new TestOutput();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), fileAccess);
oth.mainMethod(longCommandLine);
assertThatNoAdditionalErrorsHaveOccurred();
assertThat(oth.useBaselineCompiler, is(false));
}
@Test
public void supportsPerformanceMeasurements() throws Exception {
String[] args = { "-performance"};
output = new TestOutput();
OptTestHarness oth = new OptTestHarness(output, new OptOptions(), new TestFileAccess());
oth.addCallbackForPerformancePrintout = false;
oth.mainMethod(args);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
String output = getStandardOutput();
String patternString = "\nPerformance of executed method\n" +
"------------------------------\n" + "Elapsed wallclock time: ";
patternString += "(\\d+\\.\\d+E\\d+)";
patternString += " msec\n";
Pattern p = Pattern.compile(patternString);
Matcher m = p.matcher(output);
assertThat(m.matches(), is(true));
}
@Test // Note: this test will break when the bootimage options change
@Category(RequiresOptCompiler.class)
public void usesSameOptionsAsBootimageCompilerWhenRequested() throws Exception {
String[] useBootimageCompilerOptions = {"-useBootOptions"};
output = new TestOutput();
OptOptions optOptions = new OptOptions();
optOptions.INLINE_GUARDED = !optOptions.guardWithCodePatch();
OptTestHarness oth = new OptTestHarness(output, optOptions, new TestFileAccess());
oth.mainMethod(useBootimageCompilerOptions);
assertThatNoAdditionalErrorsHaveOccurred();
assertThat(oth.options.INLINE_GUARDED, is(optOptions.guardWithCodePatch()));
}
@Test
public void canRunAndExecuteMainMethod() throws Exception {
String firstArg = "abc";
String secondArg = "123";
String[] args = { "-main", CLASS_WITH_MAIN_METHOD, firstArg, secondArg };
executeOTHWithStreamRedirection(args);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
Class<?> classWithMain = Class.forName(CLASS_WITH_MAIN_METHOD);
NormalMethod mainMethod = TestingTools.getNormalMethod(classWithMain, "main", String[].class);
String expectedOutput = OptTestHarness.startOfExecutionString(mainMethod) + lineEnd +
firstArg + lineEnd + secondArg + lineEnd + OptTestHarness.endOfExecutionString(mainMethod) +
lineEnd;
assertThat(getStandardOutput(), equalTo(expectedOutput));
removeMessageFromStandardOutput(expectedOutput);
assertThatRemainingOutputIsEmptyWhenTrimmed();
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
public void complainsWhenNoMainMethodExists() throws Exception {
String[] useMainForClassWithoutMain = { "-main", CLASS_WITHOUT_MAIN_METHOD};
executeOTHWithStreamRedirection(useMainForClassWithoutMain);
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(0);
assertThatRemainingOutputIsEmptyWhenTrimmed();
String expectedErrorOutput = CLASS_WITHOUT_MAIN_METHOD +
" doesn't have a \"public static void main(String[])\" method to execute\n\n";
removeMessageFromErrorOutput(expectedErrorOutput);
assertThatNoAdditionalErrorsHaveOccurred();
}
@Test
@Category(RequiresOptCompiler.class)
public void argumentsAreEagerlyEvaluatedFromLeftToRight() throws Exception {
String[] args = { "-class", ABSTRACT_CLASS_WITH_EMPTY_METHOD, "+baseline" };
OptTestHarness oth = executeOptTestHarness(args);
assertThatNoAdditionalErrorsHaveOccurred();
assertThatNumberOfBaselineCompiledMethodsIs(0);
assertThatNumberOfOptCompiledMethodsIs(2);
assertThat(oth.useBaselineCompiler, is(true));
}
@Ignore("not enabled by default because it may interfere with other tests")
@Test
public void disableClassLoadingWorksOnlyInConjunctionWithExecuteAndRun() throws Exception {
String[] args = { "-er", "org.jikesrvm.tools.oth.OptTestHarness",
"convertToClassName", "-", "LTest;", "-disableClassLoading"};
assertThat(RVMClass.isClassLoadingDisabled(), is(false));
try {
executeOptTestHarness(args);
assertThat(RVMClass.isClassLoadingDisabled(), is(true));
} catch (Exception ignore) {
// exceptions don't matter in this test, we care only about the assertions
} finally {
RVMClass.setClassLoadingDisabled(false);
}
}
}