diff options
20 files changed, 514 insertions, 195 deletions
diff --git a/JavaLibrary.mk b/JavaLibrary.mk index d1015f5..b12b47d 100644 --- a/JavaLibrary.mk +++ b/JavaLibrary.mk @@ -75,7 +75,7 @@ LOCAL_SRC_FILES := $(test_src_files) LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs) LOCAL_NO_STANDARD_LIBRARIES := true -LOCAL_JAVA_LIBRARIES := core +LOCAL_JAVA_LIBRARIES := core caliper LOCAL_DX_FLAGS := --core-library LOCAL_MODULE_TAGS := tests diff --git a/logging/src/main/java/java/util/logging/LogRecord.java b/logging/src/main/java/java/util/logging/LogRecord.java index 0a8e257..f810e12 100644 --- a/logging/src/main/java/java/util/logging/LogRecord.java +++ b/logging/src/main/java/java/util/logging/LogRecord.java @@ -364,26 +364,25 @@ public class LogRecord implements Serializable { * Init the sourceClass and sourceMethod fields. */ private void initSource() { - if (!sourceInited) { - StackTraceElement[] elements = (new Throwable()).getStackTrace(); - int i = 0; - String current = null; - FINDLOG: for (; i < elements.length; i++) { - current = elements[i].getClassName(); - if (current.equals(Logger.class.getName())) { - break FINDLOG; - } - } - while (++i < elements.length - && elements[i].getClassName().equals(current)) { - // do nothing - } - if (i < elements.length) { - this.sourceClassName = elements[i].getClassName(); - this.sourceMethodName = elements[i].getMethodName(); + // BEGIN android-changed + if (sourceInited) { + return; + } + + boolean sawLogger = false; + for (StackTraceElement element : new Throwable().getStackTrace()) { + String current = element.getClassName(); + if (current.startsWith(Logger.class.getName())) { + sawLogger = true; + } else if (sawLogger) { + this.sourceClassName = element.getClassName(); + this.sourceMethodName = element.getMethodName(); + break; } - sourceInited = true; } + + sourceInited = true; + // END android-changed } /** diff --git a/luni/src/main/java/java/io/File.java b/luni/src/main/java/java/io/File.java index 62ca603..553206d 100644 --- a/luni/src/main/java/java/io/File.java +++ b/luni/src/main/java/java/io/File.java @@ -948,28 +948,13 @@ public class File implements Serializable, Comparable<File> { if (security != null) { security.checkRead(path); } - if (path.length() == 0) { return null; } - - // TODO: rewrite the JNI so the rest of this method is just "return listImpl(pathBytes);" - if (!isDirectoryImpl(pathBytes) || !existsImpl(pathBytes) || !isReadableImpl(pathBytes)) { - return null; - } - byte[][] implList = listImpl(pathBytes); - if (implList == null) { - // empty list - return new String[0]; - } - String[] result = new String[implList.length]; - for (int index = 0; index < implList.length; index++) { - result[index] = Util.toUTF8String(implList[index]); - } - return result; + return listImpl(pathBytes); } - private synchronized static native byte[][] listImpl(byte[] path); + private native String[] listImpl(byte[] path); /** * Gets a list of the files in the directory represented by this file. This diff --git a/luni/src/main/native/java_io_File.cpp b/luni/src/main/native/java_io_File.cpp index 905eae2..ed25ce7 100644 --- a/luni/src/main/native/java_io_File.cpp +++ b/luni/src/main/native/java_io_File.cpp @@ -171,103 +171,143 @@ static jboolean java_io_File_setReadOnlyImpl(JNIEnv* env, jobject recv, jbyteArr return (chmod(&path[0], sb.st_mode & ~0222) == 0); } -struct ScopedReaddir { - ScopedReaddir(DIR* dirp) : dirp(dirp) { +// Iterates over the filenames in the given directory. +class ScopedReaddir { +public: + ScopedReaddir(const char* path) { + mDirStream = opendir(path); + mIsBad = (mDirStream == NULL); } + ~ScopedReaddir() { - if (dirp != NULL) { - closedir(dirp); + if (mDirStream != NULL) { + closedir(mDirStream); + } + } + + // Returns the next filename, or NULL. + const char* next() { + dirent* result = NULL; + int rc = readdir_r(mDirStream, &mEntry, &result); + if (rc != 0) { + mIsBad = true; + return NULL; } + return (result != NULL) ? result->d_name : NULL; } - dirent* next() { - return readdir(dirp); + + // Has an error occurred on this stream? + bool isBad() const { + return mIsBad; + } + +private: + DIR* mDirStream; + dirent mEntry; + bool mIsBad; +}; + +// DirEntry and DirEntries is a minimal equivalent of std::forward_list +// for the filenames. +struct DirEntry { + DirEntry(const char* filename) : name(strlen(filename)) { + strcpy(&name[0], filename); + next = NULL; } - DIR* dirp; + // On Linux, the ext family all limit the length of a directory entry to + // less than 256 characters. + LocalArray<256> name; + DirEntry* next; }; -// TODO: this is a literal translation of the old code. we should remove the fixed-size buffers here. -#define MaxPath 1024 +class DirEntries { +public: + DirEntries() : mSize(0), mHead(NULL) { + } + + ~DirEntries() { + while (mHead) { + pop_front(); + } + } + + bool push_front(const char* name) { + DirEntry* oldHead = mHead; + mHead = new DirEntry(name); + if (mHead == NULL) { + return false; + } + mHead->next = oldHead; + ++mSize; + return true; + } -// TODO: Java doesn't guarantee any specific ordering, and with some file systems you will get results in non-alphabetical order, so I've just done the most convenient thing for the native code, but I wonder if we shouldn't pass down an ArrayList<String> and fill it? -struct LinkedDirEntry { - static void addFirst(LinkedDirEntry** list, LinkedDirEntry* newEntry) { - newEntry->next = *list; - *list = newEntry; + const char* front() const { + return &mHead->name[0]; } - LinkedDirEntry() : next(NULL) { + void pop_front() { + DirEntry* popped = mHead; + if (popped != NULL) { + mHead = popped->next; + --mSize; + delete popped; + } } - ~LinkedDirEntry() { - delete next; + size_t size() const { + return mSize; } - char pathEntry[MaxPath]; - LinkedDirEntry* next; +private: + size_t mSize; + DirEntry* mHead; }; -static jobject java_io_File_listImpl(JNIEnv* env, jclass clazz, jbyteArray pathBytes) { +// Reads the directory referred to by 'pathBytes', adding each directory entry +// to 'entries'. +static bool readDirectory(JNIEnv* env, jbyteArray pathBytes, DirEntries& entries) { ScopedByteArray path(env, pathBytes); - - ScopedReaddir dir(opendir(&path[0])); - if (dir.dirp == NULL) { - // TODO: shouldn't we throw an IOException? - return NULL; - } - - // TODO: merge this into the loop below. - dirent* entry = dir.next(); - if (entry == NULL) { - return NULL; + ScopedReaddir dir(&path[0]); + if (dir.isBad()) { + return false; } - char filename[MaxPath]; - strcpy(filename, entry->d_name); - - size_t fileCount = 0; - LinkedDirEntry* files = NULL; - while (entry != NULL) { - if (strcmp(".", filename) != 0 && strcmp("..", filename) != 0) { - LinkedDirEntry* newEntry = new LinkedDirEntry; - if (newEntry == NULL) { + const char* filename; + while ((filename = dir.next()) != NULL) { + if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0) { + if (!entries.push_front(filename)) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); - return NULL; + return false; } - strcpy(newEntry->pathEntry, filename); - - LinkedDirEntry::addFirst(&files, newEntry); - ++fileCount; - } - - entry = dir.next(); - if (entry != NULL) { - strcpy(filename, entry->d_name); } } - - // TODO: we should kill the ScopedReaddir about here, since we no longer need it. - - // TODO: we're supposed to use null to signal errors. we should return "new String[0]" here (or an empty byte[][]). - if (fileCount == 0) { + return true; +} + +static jobjectArray java_io_File_listImpl(JNIEnv* env, jobject, jbyteArray pathBytes) { + // Read the directory entries into an intermediate form. + DirEntries files; + if (!readDirectory(env, pathBytes, files)) { return NULL; } - - // Create a byte[][]. - // TODO: since the callers all want a String[], why do we return a byte[][]? - jclass byteArrayClass = env->FindClass("[B"); - if (byteArrayClass == NULL) { + // Translate the intermediate form into a Java String[]. + jclass stringClass = env->FindClass("java/lang/String"); + if (stringClass == NULL) { return NULL; } - jobjectArray answer = env->NewObjectArray(fileCount, byteArrayClass, NULL); - int arrayIndex = 0; - for (LinkedDirEntry* file = files; file != NULL; file = file->next) { - jsize entrylen = strlen(file->pathEntry); - jbyteArray entrypath = env->NewByteArray(entrylen); - env->SetByteArrayRegion(entrypath, 0, entrylen, (jbyte *) file->pathEntry); - env->SetObjectArrayElement(answer, arrayIndex, entrypath); - env->DeleteLocalRef(entrypath); - ++arrayIndex; + jobjectArray result = env->NewObjectArray(files.size(), stringClass, NULL); + for (int i = 0; files.size() != 0; files.pop_front(), ++i) { + jstring javaFilename = env->NewStringUTF(files.front()); + if (env->ExceptionCheck()) { + return NULL; + } + env->SetObjectArrayElement(result, i, javaFilename); + if (env->ExceptionCheck()) { + return NULL; + } + env->DeleteLocalRef(javaFilename); } - return answer; + return result; } static jboolean java_io_File_mkdirImpl(JNIEnv* env, jobject, jbyteArray pathBytes) { @@ -311,7 +351,7 @@ static JNINativeMethod gMethods[] = { { "isWritableImpl", "([B)Z", (void*) java_io_File_isWritableImpl }, { "lastModifiedImpl", "([B)J", (void*) java_io_File_lastModifiedImpl }, { "lengthImpl", "([B)J", (void*) java_io_File_lengthImpl }, - { "listImpl", "([B)[[B",(void*) java_io_File_listImpl }, + { "listImpl", "([B)[Ljava/lang/String;", (void*) java_io_File_listImpl }, { "mkdirImpl", "([B)Z", (void*) java_io_File_mkdirImpl }, { "renameToImpl", "([B[B)Z",(void*) java_io_File_renameToImpl }, { "setLastModifiedImpl","([BJ)Z", (void*) java_io_File_setLastModifiedImpl }, diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/util/NullBenchmarkSuite.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/util/NullBenchmarkSuite.java new file mode 100644 index 0000000..0d739c2 --- /dev/null +++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/util/NullBenchmarkSuite.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.tests.java.util; + +import com.google.caliper.Benchmark; +import com.google.caliper.DefaultBenchmarkSuite; + +/** + * This class exists only to force a dependency from our libraries on Caliper, + * our micro benchmarking framework. + */ +public class NullBenchmarkSuite extends DefaultBenchmarkSuite { + + class NullBenchmark extends Benchmark { + @Override public Object run(int trials) throws Exception { + for (int i = 0; i < trials; i++) { + // code under test goes here! + } + return null; + } + } +} diff --git a/tools/dalvik_jtreg/Android.mk b/tools/dalvik_jtreg/Android.mk index 5dbe9e6..fd6fe73 100644 --- a/tools/dalvik_jtreg/Android.mk +++ b/tools/dalvik_jtreg/Android.mk @@ -4,6 +4,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ java/dalvik/jtreg/Adb.java \ + java/dalvik/jtreg/CaliperFinder.java \ + java/dalvik/jtreg/CaliperRunner.java \ java/dalvik/jtreg/Classpath.java \ java/dalvik/jtreg/Command.java \ java/dalvik/jtreg/CommandFailedException.java \ @@ -12,21 +14,22 @@ LOCAL_SRC_FILES := \ java/dalvik/jtreg/Dx.java \ java/dalvik/jtreg/ExpectedResult.java \ java/dalvik/jtreg/Harness.java \ - java/dalvik/jtreg/JUnit.java \ + java/dalvik/jtreg/JUnitFinder.java \ java/dalvik/jtreg/JUnitRunner.java \ java/dalvik/jtreg/JavaVm.java \ java/dalvik/jtreg/Javac.java \ - java/dalvik/jtreg/Jtreg.java \ + java/dalvik/jtreg/JtregFinder.java \ java/dalvik/jtreg/JtregRunner.java \ java/dalvik/jtreg/Result.java \ java/dalvik/jtreg/Strings.java \ java/dalvik/jtreg/TestRun.java \ + java/dalvik/jtreg/TestFinder.java \ java/dalvik/jtreg/TestRunner.java \ java/dalvik/jtreg/Vm.java \ java/dalvik/jtreg/XmlReportPrinter.java \ LOCAL_MODULE:= dalvik_jtreg -LOCAL_STATIC_JAVA_LIBRARIES := javatest jh jtreg kxml2-2.3.0 +LOCAL_STATIC_JAVA_LIBRARIES := javatest jh jtreg kxml2-2.3.0 caliper # TODO this only works when junit is already built... LOCAL_JAVA_LIBRARIES := junit diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/CaliperFinder.java b/tools/dalvik_jtreg/java/dalvik/jtreg/CaliperFinder.java new file mode 100644 index 0000000..0fa173d --- /dev/null +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/CaliperFinder.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dalvik.jtreg; + +import java.io.File; + +/** + * Create {@link TestRun}s for {@code .java} files with Caliper benchmarks in + * them. + */ +class CaliperFinder extends TestFinder { + + @Override protected boolean matches(File file) { + return file.getName().endsWith("BenchmarkSuite.java"); + } + + @Override protected String testName(File file) { + return "caliper"; + } + + @Override protected Class<? extends TestRunner> runnerClass() { + return CaliperRunner.class; + } +} diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/CaliperRunner.java b/tools/dalvik_jtreg/java/dalvik/jtreg/CaliperRunner.java new file mode 100644 index 0000000..ace92f0 --- /dev/null +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/CaliperRunner.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dalvik.jtreg; + +import com.google.caliper.Runner; + +/** + * Runs a <a href="http://code.google.com/p/caliper/">Caliper</a> benchmark. + */ +public final class CaliperRunner extends TestRunner { + + @Override public boolean test() { + Runner.main(className); + return false; // always print benchmarking results + } + + public static void main(String[] args) throws Exception { + new CaliperRunner().run(); + } +} diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/DeviceDalvikVm.java b/tools/dalvik_jtreg/java/dalvik/jtreg/DeviceDalvikVm.java index f574cff..73a64c9 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/DeviceDalvikVm.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/DeviceDalvikVm.java @@ -25,8 +25,11 @@ import java.util.logging.Logger; */ final class DeviceDalvikVm extends Vm { - private static final File DEVICE_SUPPORT_JAR - = new File("/system/framework/core-tests.jar"); + private static final Classpath RUNTIME_SUPPORT_CLASSPATH = Classpath.of( + new File("/system/framework/core-tests.jar"), + new File("/system/framework/caliper.jar"), + new File("/system/framework/guava.jar"), + new File("/system/framework/jsr305.jar")); private static final Logger logger = Logger.getLogger(DeviceDalvikVm.class.getName()); private final File deviceTemp = new File("/data/jtreg" + UUID.randomUUID()); @@ -86,7 +89,7 @@ final class DeviceDalvikVm extends Vm { .temp(testTemp); } - @Override protected Classpath getRuntimeSupportClasses() { - return Classpath.of(DEVICE_SUPPORT_JAR); + @Override protected Classpath getRuntimeSupportClasspath() { + return RUNTIME_SUPPORT_CLASSPATH; } } diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/Driver.java b/tools/dalvik_jtreg/java/dalvik/jtreg/Driver.java index 89382ca..0f23d4d 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/Driver.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/Driver.java @@ -40,19 +40,22 @@ final class Driver { private final File localTemp; private final Set<File> expectationDirs; - private final Jtreg jtreg; - private final JUnit junit; + private final JtregFinder jtregFinder; + private final JUnitFinder junitFinder; + private final CaliperFinder caliperFinder; private final Vm vm; private final File xmlReportsDirectory; public Driver(File localTemp, Vm vm, Set<File> expectationDirs, - File xmlReportsDirectory, Jtreg jtreg, JUnit junit) { + File xmlReportsDirectory, JtregFinder jtregFinder, + JUnitFinder junit, CaliperFinder caliperFinder) { this.localTemp = localTemp; this.expectationDirs = expectationDirs; this.vm = vm; this.xmlReportsDirectory = xmlReportsDirectory; - this.jtreg = jtreg; - this.junit = junit; + this.jtregFinder = jtregFinder; + this.junitFinder = junit; + this.caliperFinder = caliperFinder; } /** @@ -67,15 +70,18 @@ final class Driver { for (File testFile : testFiles) { Set<TestRun> testsForFile = Collections.emptySet(); - // Look for Jtreg tests. If we don't find any, look for JUnit tests. if (testFile.isDirectory()) { - testsForFile = jtreg.findTests(testFile); + testsForFile = jtregFinder.findTests(testFile); logger.fine("found " + testsForFile.size() + " jtreg tests for " + testFile); } if (testsForFile.isEmpty()) { - testsForFile = junit.findTests(testFile); + testsForFile = junitFinder.findTests(testFile); logger.fine("found " + testsForFile.size() + " JUnit tests for " + testFile); } + if (testsForFile.isEmpty()) { + testsForFile = caliperFinder.findTests(testFile); + logger.fine("found " + testsForFile.size() + " Caliper benchmarks for " + testFile); + } tests.addAll(testsForFile); } diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/Harness.java b/tools/dalvik_jtreg/java/dalvik/jtreg/Harness.java index 5347a37..fa4959d 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/Harness.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/Harness.java @@ -162,10 +162,12 @@ public final class Harness { Vm vm = javaHome != null ? new JavaVm(debugPort, timeoutSeconds, sdkJar, localTemp, javaHome) : new DeviceDalvikVm(debugPort, timeoutSeconds, sdkJar, localTemp); - Jtreg jtreg = new Jtreg(localTemp); - JUnit jUnit = new JUnit(); + JtregFinder jtregFinder = new JtregFinder(localTemp); + JUnitFinder jUnitFinder = new JUnitFinder(); + CaliperFinder caliperFinder = new CaliperFinder(); Driver driver = new Driver(localTemp, - vm, expectationDirs, xmlReportsDirectory, jtreg, jUnit); + vm, expectationDirs, xmlReportsDirectory, jtregFinder, + jUnitFinder, caliperFinder); driver.buildAndRunAllTests(testFiles); vm.shutdown(); } diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/JUnitFinder.java b/tools/dalvik_jtreg/java/dalvik/jtreg/JUnitFinder.java new file mode 100644 index 0000000..0f801cc --- /dev/null +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/JUnitFinder.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dalvik.jtreg; + +import java.io.File; + +/** + * Create {@link TestRun}s for {@code .java} files with JUnit tests in them. + */ +class JUnitFinder extends TestFinder { + + @Override protected boolean matches(File file) { + return file.getName().endsWith("Test.java"); + } + + // TODO: try to get names for each method? + @Override protected String testName(File file) { + return "junit"; + } + + @Override protected Class<? extends TestRunner> runnerClass() { + return JUnitRunner.class; + } +} diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/Jtreg.java b/tools/dalvik_jtreg/java/dalvik/jtreg/JtregFinder.java index 3fdab78..1bbf1f1 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/Jtreg.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/JtregFinder.java @@ -33,9 +33,9 @@ import java.util.logging.Logger; /** * Create {@link TestRun}s for {@code .java} files with jtreg tests in them. */ -class Jtreg { +class JtregFinder { - private static final Logger logger = Logger.getLogger(Jtreg.class.getName()); + private static final Logger logger = Logger.getLogger(JtregFinder.class.getName()); /** * The subpath of a platform implementation under which tests live. Used to @@ -46,7 +46,7 @@ class Jtreg { private final File localTemp; - Jtreg(File localTemp) { + JtregFinder(File localTemp) { this.localTemp = localTemp; } diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/JUnit.java b/tools/dalvik_jtreg/java/dalvik/jtreg/TestFinder.java index fbcf9c0..03c24be 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/JUnit.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/TestFinder.java @@ -19,14 +19,11 @@ package dalvik.jtreg; import java.io.File; import java.util.LinkedHashSet; import java.util.Set; -import java.util.logging.Logger; /** - * Create {@link TestRun}s for {@code .java} files with JUnit tests in them. + * A pluggable strategy for converting files into test runs. */ -class JUnit { - - private static final Logger logger = Logger.getLogger(JUnit.class.getName()); +abstract class TestFinder { public Set<TestRun> findTests(File testDirectory) { Set<TestRun> result = new LinkedHashSet<TestRun>(); @@ -34,21 +31,35 @@ class JUnit { return result; } + /** + * Returns true if {@code file} contains a test class of this type. + */ + protected boolean matches(File file) { + return file.getName().endsWith(".java"); + } + + protected abstract String testName(File file); + + protected abstract Class<? extends TestRunner> runnerClass(); + private void findTestsRecursive(Set<TestRun> sink, File file) { if (file.isDirectory()) { for (File child : file.listFiles()) { findTestsRecursive(sink, child); } - } else if (file.getName().endsWith(".java")) { - String className = fileToClass(file); - File testDirectory = file.getParentFile(); - String testName = "junit"; // TODO: try to get names for each method? - String testDescription = null; - sink.add(new TestRun(testDirectory, file, className, className, - testName, className, testDescription, JUnitRunner.class)); - } else { - logger.fine("skipping " + file); + return; } + + if (!matches(file)) { + return; + } + + String className = fileToClass(file); + File testDirectory = file.getParentFile(); + String testName = testName(file); + String testDescription = null; + sink.add(new TestRun(testDirectory, file, className, className, + testName, className, testDescription, runnerClass())); } /** diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java b/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java index 31df7ed..fce8aa8 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java @@ -64,7 +64,8 @@ public abstract class TestRunner { return properties; } - public abstract void prepareTest(); + public void prepareTest() {} + public abstract boolean test(); public void run() { diff --git a/tools/dalvik_jtreg/java/dalvik/jtreg/Vm.java b/tools/dalvik_jtreg/java/dalvik/jtreg/Vm.java index e85eae1..09a75de 100644 --- a/tools/dalvik_jtreg/java/dalvik/jtreg/Vm.java +++ b/tools/dalvik_jtreg/java/dalvik/jtreg/Vm.java @@ -41,6 +41,7 @@ public abstract class Vm { static final String DALVIK_JTREG_HOME = "dalvik/libcore/tools/dalvik_jtreg"; static final Set<File> TEST_RUNNER_JAVA_FILES = new HashSet<File>(Arrays.asList( + new File(DALVIK_JTREG_HOME + "/java/dalvik/jtreg/CaliperRunner.java"), new File(DALVIK_JTREG_HOME + "/java/dalvik/jtreg/JUnitRunner.java"), new File(DALVIK_JTREG_HOME + "/java/dalvik/jtreg/JtregRunner.java"), new File(DALVIK_JTREG_HOME + "/java/dalvik/jtreg/TestRunner.java"))); @@ -48,7 +49,10 @@ public abstract class Vm { private final Pattern JAVA_TEST_PATTERN = Pattern.compile("\\/(\\w)+\\.java$"); static final Classpath COMPILATION_CLASSPATH = Classpath.of( new File("out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar"), - new File("out/host/common/core-tests.jar")); + new File("out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jar"), + new File("out/target/common/obj/JAVA_LIBRARIES/jsr305_intermediates/classes.jar"), + new File("out/target/common/obj/JAVA_LIBRARIES/guava_intermediates/classes.jar"), + new File("out/target/common/obj/JAVA_LIBRARIES/caliper_intermediates/classes.jar")); private static final Logger logger = Logger.getLogger(Vm.class.getName()); @@ -86,6 +90,7 @@ public abstract class Vm { .classpath(COMPILATION_CLASSPATH) .destination(base) .compile(TEST_RUNNER_JAVA_FILES); + return postCompile("testrunner", Classpath.of(base)); } @@ -174,7 +179,7 @@ public abstract class Vm { final Command command = newVmCommandBuilder() .classpath(testRun.getTestClasses()) .classpath(testRunnerClasses) - .classpath(getRuntimeSupportClasses()) + .classpath(getRuntimeSupportClasspath()) .userDir(testRun.getUserDir()) .debugPort(debugPort) .mainClass(testRun.getTestRunner().getName()) @@ -225,7 +230,7 @@ public abstract class Vm { * Returns the classpath containing JUnit and the dalvik annotations * required for test execution. */ - protected Classpath getRuntimeSupportClasses() { + protected Classpath getRuntimeSupportClasspath() { return COMPILATION_CLASSPATH; } diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java b/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java index 60d74b8..be933ca 100644 --- a/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java +++ b/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java @@ -18,6 +18,7 @@ package org.apache.harmony.xml; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.Locator; @@ -226,6 +227,20 @@ class ExpatParser { } } + /*package*/ void notationDecl(String name, String publicId, String systemId) throws SAXException { + DTDHandler dtdHandler = xmlReader.dtdHandler; + if (dtdHandler != null) { + dtdHandler.notationDecl(name, publicId, systemId); + } + } + + /*package*/ void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { + DTDHandler dtdHandler = xmlReader.dtdHandler; + if (dtdHandler != null) { + dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName); + } + } + /** * Handles an external entity. * @@ -791,4 +806,3 @@ class ExpatParser { } } } - diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java b/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java index a6a83a0..dbe3a3a 100644 --- a/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java +++ b/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java @@ -37,15 +37,12 @@ import java.util.logging.Logger; * Does not support {@link DTDHandler}. */ public class ExpatReader implements XMLReader { - - private static final Logger logger - = Logger.getLogger(ExpatReader.class.getName()); - /* * ExpatParser accesses these fields directly during parsing. The user * should be able to safely change them during parsing. */ /*package*/ ContentHandler contentHandler; + /*package*/ DTDHandler dtdHandler; /*package*/ EntityResolver entityResolver; /*package*/ ErrorHandler errorHandler; /*package*/ LexicalHandler lexicalHandler; @@ -170,18 +167,12 @@ public class ExpatReader implements XMLReader { return entityResolver; } - /** - * Not implemented. - */ - public void setDTDHandler(DTDHandler ignored) { - logger.warning("DTD handlers aren't supported."); + public void setDTDHandler(DTDHandler dtdHandler) { + this.dtdHandler = dtdHandler; } - /** - * Always returns null. - */ public DTDHandler getDTDHandler() { - return null; + return dtdHandler; } public void setContentHandler(ContentHandler handler) { diff --git a/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp index 701dbd9..f16e905 100644 --- a/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp +++ b/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp @@ -31,7 +31,7 @@ /** * Wrapper around an interned string. */ -typedef struct { +struct InternedString { /** The interned string itself. */ jstring interned; @@ -41,22 +41,22 @@ typedef struct { /** Hash code of the interned string. */ int hash; -} InternedString; +}; /** * Keeps track of strings between start and end events. */ -typedef struct { +struct StringStack { jstring* array; int capacity; int size; -} StringStack; +}; /** * Data passed to parser handler method by the parser. */ -typedef struct { +struct ParsingContext { /** * The JNI environment for the current thread. This should only be used @@ -87,21 +87,23 @@ typedef struct { /** Cache of interned strings. */ InternedString** internedStrings[BUCKET_COUNT]; -} ParsingContext; +}; -static jmethodID startElementMethod; -static jmethodID endElementMethod; -static jmethodID textMethod; static jmethodID commentMethod; -static jmethodID startCdataMethod; static jmethodID endCdataMethod; -static jmethodID startDtdMethod; static jmethodID endDtdMethod; -static jmethodID startNamespaceMethod; +static jmethodID endElementMethod; static jmethodID endNamespaceMethod; -static jmethodID processingInstructionMethod; static jmethodID handleExternalEntityMethod; static jmethodID internMethod; +static jmethodID notationDeclMethod; +static jmethodID processingInstructionMethod; +static jmethodID startCdataMethod; +static jmethodID startDtdMethod; +static jmethodID startElementMethod; +static jmethodID startNamespaceMethod; +static jmethodID textMethod; +static jmethodID unparsedEntityDeclMethod; static jclass stringClass; static jstring emptyString; @@ -879,6 +881,53 @@ static int handleExternalEntity(XML_Parser parser, const char* context, return env->ExceptionCheck() ? XML_STATUS_ERROR : XML_STATUS_OK; } +static void unparsedEntityDecl(void* data, const char* name, const char* base, const char* systemId, const char* publicId, const char* notationName) { + ParsingContext* parsingContext = reinterpret_cast<ParsingContext*>(data); + jobject javaParser = parsingContext->object; + JNIEnv* env = parsingContext->env; + + // Bail out if a previously called handler threw an exception. + if (env->ExceptionCheck()) return; + + jstring javaName = env->NewStringUTF(name); + if (env->ExceptionCheck()) return; + jstring javaPublicId = env->NewStringUTF(publicId); + if (env->ExceptionCheck()) return; + jstring javaSystemId = env->NewStringUTF(systemId); + if (env->ExceptionCheck()) return; + jstring javaNotationName = env->NewStringUTF(notationName); + if (env->ExceptionCheck()) return; + + env->CallVoidMethod(javaParser, unparsedEntityDeclMethod, javaName, javaPublicId, javaSystemId, javaNotationName); + + env->DeleteLocalRef(javaName); + env->DeleteLocalRef(javaPublicId); + env->DeleteLocalRef(javaSystemId); + env->DeleteLocalRef(javaNotationName); +} + +static void notationDecl(void* data, const char* name, const char* base, const char* systemId, const char* publicId) { + ParsingContext* parsingContext = reinterpret_cast<ParsingContext*>(data); + jobject javaParser = parsingContext->object; + JNIEnv* env = parsingContext->env; + + // Bail out if a previously called handler threw an exception. + if (env->ExceptionCheck()) return; + + jstring javaName = env->NewStringUTF(name); + if (env->ExceptionCheck()) return; + jstring javaPublicId = env->NewStringUTF(publicId); + if (env->ExceptionCheck()) return; + jstring javaSystemId = env->NewStringUTF(systemId); + if (env->ExceptionCheck()) return; + + env->CallVoidMethod(javaParser, notationDeclMethod, javaName, javaPublicId, javaSystemId); + + env->DeleteLocalRef(javaName); + env->DeleteLocalRef(javaPublicId); + env->DeleteLocalRef(javaSystemId); +} + /** * Releases the parsing context. */ @@ -945,15 +994,15 @@ static jint initialize(JNIEnv* env, jobject object, jstring javaEncoding, XML_SetNamespaceDeclHandler(parser, startNamespace, endNamespace); } - XML_SetCommentHandler(parser, comment); XML_SetCdataSectionHandler(parser, startCdata, endCdata); - - XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, text); + XML_SetCommentHandler(parser, comment); XML_SetDoctypeDeclHandler(parser, startDtd, endDtd); - XML_SetProcessingInstructionHandler(parser, processingInstruction); + XML_SetElementHandler(parser, startElement, endElement); XML_SetExternalEntityRefHandler(parser, handleExternalEntity); - + XML_SetNotationDeclHandler(parser, notationDecl); + XML_SetProcessingInstructionHandler(parser, processingInstruction); + XML_SetUnparsedEntityDeclHandler(parser, unparsedEntityDecl); XML_SetUserData(parser, context); } else { releaseParsingContext(env, context); @@ -1358,51 +1407,60 @@ static void freeAttributes(JNIEnv* env, jobject clazz, jint pointer) { * * @param clazz Java ExpatParser class */ -static void staticInitialize(JNIEnv* env, jobject clazz, jstring empty) { - startElementMethod = env->GetMethodID((jclass) clazz, "startElement", +static void staticInitialize(JNIEnv* env, jobject classObject, jstring empty) { + jclass clazz = reinterpret_cast<jclass>(classObject); + startElementMethod = env->GetMethodID(clazz, "startElement", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V"); if (startElementMethod == NULL) return; - endElementMethod = env->GetMethodID((jclass) clazz, "endElement", + endElementMethod = env->GetMethodID(clazz, "endElement", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); if (endElementMethod == NULL) return; - textMethod = env->GetMethodID((jclass) clazz, "text", "([CI)V"); + textMethod = env->GetMethodID(clazz, "text", "([CI)V"); if (textMethod == NULL) return; - commentMethod = env->GetMethodID((jclass) clazz, "comment", "([CI)V"); + commentMethod = env->GetMethodID(clazz, "comment", "([CI)V"); if (commentMethod == NULL) return; - startCdataMethod = env->GetMethodID((jclass) clazz, "startCdata", "()V"); + startCdataMethod = env->GetMethodID(clazz, "startCdata", "()V"); if (startCdataMethod == NULL) return; - endCdataMethod = env->GetMethodID((jclass) clazz, "endCdata", "()V"); + endCdataMethod = env->GetMethodID(clazz, "endCdata", "()V"); if (endCdataMethod == NULL) return; - startDtdMethod = env->GetMethodID((jclass) clazz, "startDtd", + startDtdMethod = env->GetMethodID(clazz, "startDtd", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); if (startDtdMethod == NULL) return; - endDtdMethod = env->GetMethodID((jclass) clazz, "endDtd", "()V"); + endDtdMethod = env->GetMethodID(clazz, "endDtd", "()V"); if (endDtdMethod == NULL) return; - startNamespaceMethod = env->GetMethodID((jclass) clazz, "startNamespace", + startNamespaceMethod = env->GetMethodID(clazz, "startNamespace", "(Ljava/lang/String;Ljava/lang/String;)V"); if (startNamespaceMethod == NULL) return; - endNamespaceMethod = env->GetMethodID((jclass) clazz, "endNamespace", + endNamespaceMethod = env->GetMethodID(clazz, "endNamespace", "(Ljava/lang/String;)V"); if (endNamespaceMethod == NULL) return; - processingInstructionMethod = env->GetMethodID((jclass) clazz, + processingInstructionMethod = env->GetMethodID(clazz, "processingInstruction", "(Ljava/lang/String;Ljava/lang/String;)V"); if (processingInstructionMethod == NULL) return; - handleExternalEntityMethod = env->GetMethodID((jclass) clazz, + handleExternalEntityMethod = env->GetMethodID(clazz, "handleExternalEntity", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); if (handleExternalEntityMethod == NULL) return; + notationDeclMethod = env->GetMethodID(clazz, "notationDecl", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (notationDeclMethod == NULL) return; + + unparsedEntityDeclMethod = env->GetMethodID(clazz, "unparsedEntityDecl", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (unparsedEntityDeclMethod == NULL) return; + // Look up String class. stringClass = env->FindClass("java/lang/String"); diff --git a/xml/src/test/java/org/apache/harmony/xml/ExpatParserTest.java b/xml/src/test/java/org/apache/harmony/xml/ExpatParserTest.java index 480bca3..f781611 100644 --- a/xml/src/test/java/org/apache/harmony/xml/ExpatParserTest.java +++ b/xml/src/test/java/org/apache/harmony/xml/ExpatParserTest.java @@ -501,27 +501,67 @@ public class ExpatParserTest extends TestCase { } } - public void testDtd() throws Exception { - Reader in = new StringReader( - "<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee'><a></a>"); + private TestDtdHandler runDtdTest(String s) throws Exception { + Reader in = new StringReader(s); ExpatReader reader = new ExpatReader(); TestDtdHandler handler = new TestDtdHandler(); reader.setContentHandler(handler); + reader.setDTDHandler(handler); reader.setLexicalHandler(handler); reader.parse(new InputSource(in)); + return handler; + } + public void testDtdDoctype() throws Exception { + TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee'><a></a>"); assertEquals("foo", handler.name); assertEquals("bar", handler.publicId); assertEquals("tee", handler.systemId); - assertTrue(handler.ended); } + public void testDtdUnparsedEntity_system() throws Exception { + TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!ENTITY ent SYSTEM 'blah' NDATA poop> ]><a></a>"); + assertEquals("ent", handler.ueName); + assertEquals(null, handler.uePublicId); + assertEquals("blah", handler.ueSystemId); + assertEquals("poop", handler.ueNotationName); + } + + public void testDtdUnparsedEntity_public() throws Exception { + TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!ENTITY ent PUBLIC 'a' 'b' NDATA poop> ]><a></a>"); + assertEquals("ent", handler.ueName); + assertEquals("a", handler.uePublicId); + assertEquals("b", handler.ueSystemId); + assertEquals("poop", handler.ueNotationName); + } + + public void testDtdNotation_system() throws Exception { + TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!NOTATION sn SYSTEM 'nf2'> ]><a></a>"); + assertEquals("sn", handler.ndName); + assertEquals(null, handler.ndPublicId); + assertEquals("nf2", handler.ndSystemId); + } + + public void testDtdNotation_public() throws Exception { + TestDtdHandler handler = runDtdTest("<?xml version=\"1.0\"?><!DOCTYPE foo PUBLIC 'bar' 'tee' [ <!NOTATION pn PUBLIC 'nf1'> ]><a></a>"); + assertEquals("pn", handler.ndName); + assertEquals("nf1", handler.ndPublicId); + assertEquals(null, handler.ndSystemId); + } + static class TestDtdHandler extends DefaultHandler2 { String name; String publicId; String systemId; + String ndName; + String ndPublicId; + String ndSystemId; + String ueName; + String uePublicId; + String ueSystemId; + String ueNotationName; boolean ended; @@ -543,6 +583,21 @@ public class ExpatParserTest extends TestCase { public void setDocumentLocator(Locator locator) { this.locator = locator; } + + @Override + public void notationDecl(String name, String publicId, String systemId) { + this.ndName = name; + this.ndPublicId = publicId; + this.ndSystemId = systemId; + } + + @Override + public void unparsedEntityDecl(String entityName, String publicId, String systemId, String notationName) { + this.ueName = entityName; + this.uePublicId = publicId; + this.ueSystemId = systemId; + this.ueNotationName = notationName; + } } public void testCdata() throws Exception { |