summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2010-02-22 12:09:51 -0800
committerElliott Hughes <enh@google.com>2010-02-22 12:09:51 -0800
commite2a6f77f112c01109db196d8b19767896ee977ea (patch)
treec18066db46425e09a89b679c3b08153d0480d7e7
parentcb78ba4051c82075119fd3646922a41e6355151b (diff)
parentea6435b142df4aaaf8854b3200b9f442b331f143 (diff)
downloadlibcore-e2a6f77f112c01109db196d8b19767896ee977ea.zip
libcore-e2a6f77f112c01109db196d8b19767896ee977ea.tar.gz
libcore-e2a6f77f112c01109db196d8b19767896ee977ea.tar.bz2
Merge remote branch 'goog/master' into mm
Conflicts: libcore/JavaLibrary.mk
-rw-r--r--JavaLibrary.mk42
-rw-r--r--dalvik/src/main/java/dalvik/system/PathClassLoader.java64
-rw-r--r--dom/src/test/java/org/w3c/domts/EventMonitor.java68
-rw-r--r--include/UniquePtr.h231
-rw-r--r--json/src/test/java/org/json/AllTests.java30
-rw-r--r--json/src/test/java/org/json/JSONArrayTest.java339
-rw-r--r--json/src/test/java/org/json/JSONStringerTest.java356
-rw-r--r--json/src/test/java/org/json/JSONTokenerTest.java565
-rw-r--r--luni/src/test/java/tests/AllTests.java1
-rw-r--r--math/src/main/java/java/math/BigInt.java2
-rw-r--r--security/src/main/files/cacerts.bksbin59144 -> 61391 bytes
-rw-r--r--security/src/main/files/cacerts/2afc57aa.088
-rw-r--r--security/src/main/files/cacerts/5021a0a2.083
-rw-r--r--support/src/test/java/tests/support/resource/Support_Resources.java16
-rw-r--r--tools/runner/Android.mk53
-rw-r--r--tools/runner/java/dalvik/runner/Aapt.java49
-rw-r--r--tools/runner/java/dalvik/runner/ActivityMode.java256
-rw-r--r--tools/runner/java/dalvik/runner/Adb.java55
-rw-r--r--tools/runner/java/dalvik/runner/CaliperFinder.java10
-rw-r--r--tools/runner/java/dalvik/runner/CaliperRunner.java13
-rw-r--r--tools/runner/java/dalvik/runner/Classpath.java12
-rw-r--r--tools/runner/java/dalvik/runner/CodeFinder.java15
-rw-r--r--tools/runner/java/dalvik/runner/Command.java46
-rw-r--r--tools/runner/java/dalvik/runner/DalvikRunner.java60
-rw-r--r--tools/runner/java/dalvik/runner/DeviceDalvikVm.java105
-rw-r--r--tools/runner/java/dalvik/runner/Driver.java34
-rw-r--r--tools/runner/java/dalvik/runner/Dx.java36
-rw-r--r--tools/runner/java/dalvik/runner/Environment.java91
-rw-r--r--tools/runner/java/dalvik/runner/EnvironmentDevice.java73
-rw-r--r--tools/runner/java/dalvik/runner/EnvironmentHost.java45
-rw-r--r--tools/runner/java/dalvik/runner/JUnitFinder.java11
-rw-r--r--tools/runner/java/dalvik/runner/JUnitRunner.java14
-rw-r--r--tools/runner/java/dalvik/runner/JavaVm.java21
-rw-r--r--tools/runner/java/dalvik/runner/JtregFinder.java17
-rw-r--r--tools/runner/java/dalvik/runner/JtregRunner.java13
-rw-r--r--tools/runner/java/dalvik/runner/MainFinder.java10
-rw-r--r--tools/runner/java/dalvik/runner/MainRunner.java24
-rw-r--r--tools/runner/java/dalvik/runner/Md5Cache.java115
-rw-r--r--tools/runner/java/dalvik/runner/Mkdir.java29
-rw-r--r--tools/runner/java/dalvik/runner/Mode.java268
-rw-r--r--tools/runner/java/dalvik/runner/NamingPatternCodeFinder.java9
-rw-r--r--tools/runner/java/dalvik/runner/OptionParser.java3
-rw-r--r--tools/runner/java/dalvik/runner/Rm.java (renamed from luni/src/test/java/org/apache/harmony/luni/tests/java/util/NullBenchmarkSuite.java)30
-rw-r--r--tools/runner/java/dalvik/runner/Runner.java28
-rw-r--r--tools/runner/java/dalvik/runner/TestProperties.java79
-rw-r--r--tools/runner/java/dalvik/runner/TestRun.java50
-rw-r--r--tools/runner/java/dalvik/runner/TestRunner.java81
-rw-r--r--tools/runner/java/dalvik/runner/Vm.java255
-rw-r--r--tools/runner/lib/TestActivity.java105
-rw-r--r--tools/runner/lib/caliper.jarbin0 -> 443323 bytes
-rw-r--r--tools/runner/lib/caliper.jar.txt202
-rw-r--r--tools/runner/lib/guava.jarbin0 -> 579101 bytes
-rw-r--r--tools/runner/lib/guava.jar.txt202
-rw-r--r--tools/runner/lib/jsr305.jarbin0 -> 18308 bytes
-rw-r--r--tools/runner/lib/jsr305.jar.txt28
-rwxr-xr-xtools/runner/test-dalvik-runner.sh53
-rwxr-xr-xtools/runner/vogar21
-rw-r--r--x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java30
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java31
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java23
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java9
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java3
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java28
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java49
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java409
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java5
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java4
-rw-r--r--xml/src/main/java/org/apache/xalan/processor/TransformerFactoryImpl.java2
-rw-r--r--xml/src/main/java/org/apache/xml/utils/DOMHelper.java27
-rw-r--r--xml/src/main/java/org/kxml2/io/KXmlParser.java47
-rw-r--r--xml/src/main/java/org/w3c/dom/Attr.java2
-rw-r--r--xml/src/main/java/org/w3c/dom/events/DocumentEvent.java56
-rw-r--r--xml/src/main/java/org/w3c/dom/events/Event.java141
-rw-r--r--xml/src/main/java/org/w3c/dom/events/EventException.java36
-rw-r--r--xml/src/main/java/org/w3c/dom/events/EventListener.java41
-rw-r--r--xml/src/main/java/org/w3c/dom/events/EventTarget.java102
-rw-r--r--xml/src/main/java/org/w3c/dom/events/MouseEvent.java156
-rw-r--r--xml/src/main/java/org/w3c/dom/events/MutationEvent.java108
-rw-r--r--xml/src/main/java/org/w3c/dom/events/UIEvent.java58
-rw-r--r--xml/src/main/java/org/w3c/dom/ls/LSLoadEvent.java35
-rw-r--r--xml/src/main/java/org/w3c/dom/ls/LSProgressEvent.java48
-rw-r--r--xml/src/main/java/org/w3c/dom/ls/LSSerializer.java8
-rw-r--r--xml/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java2
-rw-r--r--xml/src/main/java/org/w3c/dom/traversal/DocumentTraversal.java93
-rw-r--r--xml/src/main/java/org/w3c/dom/traversal/NodeFilter.java2
-rw-r--r--xml/src/main/java/org/w3c/dom/traversal/NodeIterator.java2
-rw-r--r--xml/src/main/java/org/w3c/dom/traversal/TreeWalker.java179
-rw-r--r--xml/src/main/java/org/w3c/dom/views/AbstractView.java27
-rw-r--r--xml/src/main/java/org/w3c/dom/views/DocumentView.java30
-rw-r--r--xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java240
-rw-r--r--xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java25
-rw-r--r--xml/src/test/java/tests/xml/AllTests.java2
-rw-r--r--xml/src/test/java/tests/xml/DomTest.java623
-rw-r--r--xml/src/test/java/tests/xml/NodeTest.java86
-rw-r--r--xml/src/test/java/tests/xml/NodeTests.java47
95 files changed, 5366 insertions, 1956 deletions
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index eb2f791..70037e8 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -85,7 +85,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,annotation)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-annotation
@@ -95,7 +95,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,archive)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-archive
@@ -105,7 +105,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,concurrent)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-concurrent
@@ -115,7 +115,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,crypto)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-crypto
@@ -125,7 +125,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,dom)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-dom
@@ -135,7 +135,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,icu)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-icu
@@ -145,7 +145,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,logging)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-logging
@@ -155,7 +155,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,luni-kernel)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-luni-kernel
@@ -169,7 +169,7 @@ LOCAL_NO_STANDARD_LIBRARIES := true
# together, so it has compile-time dependencies on all the other test
# libraries.
# TODO: we should have a bogus module that just contains tests.AllTests for speed.
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_JAVA_LIBRARIES += core-tests-annotation core-tests-archive
LOCAL_JAVA_LIBRARIES += core-tests-concurrent core-tests-crypto
LOCAL_JAVA_LIBRARIES += core-tests-dom core-tests-icu core-tests-logging
@@ -186,7 +186,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,math)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-math
@@ -196,7 +196,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,nio)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-nio
@@ -206,7 +206,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,nio_char)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-nio_char
@@ -216,7 +216,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,prefs)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-prefs
@@ -226,7 +226,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,regex)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-regex
@@ -236,7 +236,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,security)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-security
@@ -246,7 +246,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,sql)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-sql
@@ -256,7 +256,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,suncompat)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-suncompat
@@ -266,7 +266,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper
+LOCAL_JAVA_LIBRARIES := core
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-support
@@ -276,7 +276,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,text)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-text
@@ -286,7 +286,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,x-net)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-x-net
@@ -296,7 +296,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,xml)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core caliper core-tests-support
+LOCAL_JAVA_LIBRARIES := core core-tests-support
LOCAL_DX_FLAGS := --core-library
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests-xml
diff --git a/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
index 597eb5b..5d7333e 100644
--- a/dalvik/src/main/java/dalvik/system/PathClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -37,14 +37,14 @@ import dalvik.system.DexFile;
* of files and directories in the local file system, but does not attempt to
* load classes from the network. Android uses this class for its system class
* loader and for its application class loader(s).
- *
+ *
* @since Android 1.0
*/
public class PathClassLoader extends ClassLoader {
private final String path;
private final String libPath;
-
+
private boolean initialized;
private String[] mPaths;
@@ -58,17 +58,17 @@ public class PathClassLoader extends ClassLoader {
* and directories. This method is equivalent to calling
* {@link #PathClassLoader(String, String, ClassLoader)} with a
* {@code null} value for the second argument (see description there).
- *
+ *
* @param path
* the list of files and directories
- *
+ *
* @param parent
* the parent class loader
*/
public PathClassLoader(String path, ClassLoader parent) {
this(path, null, parent);
}
-
+
/**
* Creates a {@code PathClassLoader} that operates on two given lists of
* files and directories. The entries of the first list should be one of the
@@ -81,14 +81,14 @@ public class PathClassLoader extends ClassLoader {
* The entries of the second list should be directories containing native
* library files. Both lists are separated using the character specified by
* the "path.separator" system property, which, on Android, defaults to ":".
- *
+ *
* @param path
* the list of files and directories containing classes and
* resources
- *
+ *
* @param libPath
* the list of directories containing native libraries
- *
+ *
* @param parent
* the parent class loader
*/
@@ -101,23 +101,23 @@ public class PathClassLoader extends ClassLoader {
this.path = path;
this.libPath = libPath;
}
-
+
private synchronized void ensureInit() {
if (initialized) {
return;
}
-
+
initialized = true;
-
+
mPaths = path.split(":");
int length = mPaths.length;
-
+
//System.out.println("PathClassLoader: " + mPaths);
mFiles = new File[length];
mZips = new ZipFile[length];
mDexs = new DexFile[length];
- boolean wantDex =
+ boolean wantDex =
System.getProperty("android.vm.dexfile", "").equals("true");
/* open all Zip and DEX files up front */
@@ -132,7 +132,7 @@ public class PathClassLoader extends ClassLoader {
}
catch (IOException ioex) {
// expecting IOException and ZipException
- //System.out.println("Failed opening '" + archive + "': " + ioex);
+ //System.out.println("Failed opening '" + pathFile + "': " + ioex);
//ioex.printStackTrace();
}
if (wantDex) {
@@ -151,7 +151,7 @@ public class PathClassLoader extends ClassLoader {
String pathList = System.getProperty("java.library.path", ".");
String pathSep = System.getProperty("path.separator", ":");
String fileSep = System.getProperty("file.separator", "/");
-
+
if (libPath != null) {
if (pathList.length() > 0) {
pathList += pathSep + libPath;
@@ -177,7 +177,7 @@ public class PathClassLoader extends ClassLoader {
/**
* Finds a class. This method is called by {@code loadClass()} after the
* parent ClassLoader has failed to find a loaded class of the same name.
- *
+ *
* @param name
* The "binary name" of the class to search for, in a
* human-readable form like "java.lang.String" or
@@ -190,7 +190,7 @@ public class PathClassLoader extends ClassLoader {
protected Class<?> findClass(String name) throws ClassNotFoundException
{
ensureInit();
-
+
//System.out.println("PathClassLoader " + this + ": findClass '" + name + "'");
byte[] data = null;
@@ -234,7 +234,7 @@ public class PathClassLoader extends ClassLoader {
}
}
}
-
+
return defineClass(name, data, 0, data.length);
}
*/
@@ -247,7 +247,7 @@ public class PathClassLoader extends ClassLoader {
* Finds a resource. This method is called by {@code getResource()} after
* the parent ClassLoader has failed to find a loaded resource of the same
* name.
- *
+ *
* @param name
* The name of the resource to find
* @return the location of the resource as a URL, or {@code null} if the
@@ -260,7 +260,7 @@ public class PathClassLoader extends ClassLoader {
//java.util.logging.Logger.global.severe("findResource: " + name);
int length = mPaths.length;
-
+
for (int i = 0; i < length; i++) {
URL result = findResource(name, i);
if(result != null) {
@@ -273,7 +273,7 @@ public class PathClassLoader extends ClassLoader {
/**
* Finds an enumeration of URLs for the resource with the specified name.
- *
+ *
* @param resName
* the name of the resource to find.
* @return an enumeration of {@code URL} objects for the requested resource.
@@ -285,7 +285,7 @@ public class PathClassLoader extends ClassLoader {
int length = mPaths.length;
ArrayList<URL> results = new ArrayList<URL>();
-
+
for (int i = 0; i < length; i++) {
URL result = findResource(resName, i);
if(result != null) {
@@ -294,7 +294,7 @@ public class PathClassLoader extends ClassLoader {
}
return new EnumerateListArray<URL>(results);
}
-
+
private URL findResource(String name, int i) {
File pathFile = mFiles[i];
ZipFile zip = mZips[i];
@@ -317,7 +317,7 @@ public class PathClassLoader extends ClassLoader {
if (dataFile.exists()) {
//System.out.println(" found resource " + name);
try {
- // Same as archive case regarding URL construction.
+ // Same as archive case regarding URL construction.
return dataFile.toURL();
}
catch (MalformedURLException e) {
@@ -414,7 +414,7 @@ public class PathClassLoader extends ClassLoader {
/**
* Finds a native library. This method is called after the parent
* ClassLoader has failed to find a native library of the same name.
- *
+ *
* @param libname
* The name of the library to find
* @return the complete path of the library, or {@code null} if the library
@@ -451,7 +451,7 @@ public class PathClassLoader extends ClassLoader {
* scattered across different JAR files being loaded by different
* ClassLoaders. Rather unlikely, and given that this whole thing is more or
* less a workaround, probably not worth the effort.
- *
+ *
* @param name
* the name of the class
* @return the package information for the class, or {@code null} if there
@@ -462,15 +462,15 @@ public class PathClassLoader extends ClassLoader {
if (name != null && !"".equals(name)) {
synchronized(this) {
Package pack = super.getPackage(name);
-
+
if (pack == null) {
pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", "Unknown", null);
}
-
+
return pack;
- }
+ }
}
-
+
return null;
}
@@ -495,4 +495,8 @@ public class PathClassLoader extends ClassLoader {
return (T) mList.get(i++);
}
};
+
+ public String toString () {
+ return getClass().getName() + "[" + path + "]";
+ }
}
diff --git a/dom/src/test/java/org/w3c/domts/EventMonitor.java b/dom/src/test/java/org/w3c/domts/EventMonitor.java
deleted file mode 100644
index 909ca4e..0000000
--- a/dom/src/test/java/org/w3c/domts/EventMonitor.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2001-2004 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.domts;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.w3c.dom.events.Event;
-import org.w3c.dom.events.EventListener;
-
-/**
- * This is a utility implementation of EventListener
- * that captures all events and provides access
- * to lists of all events by mode
- */
-public class EventMonitor
- implements EventListener {
- private final List atEvents = new ArrayList();
- private final List bubbledEvents = new ArrayList();
- private final List capturedEvents = new ArrayList();
- private final List allEvents = new ArrayList();
-
- public EventMonitor() {
- }
-
- public void handleEvent(Event evt) {
- switch (evt.getEventPhase()) {
- case Event.CAPTURING_PHASE:
- capturedEvents.add(evt);
- break;
-
- case Event.BUBBLING_PHASE:
- bubbledEvents.add(evt);
- break;
-
- case Event.AT_TARGET:
- atEvents.add(evt);
- break;
- }
- allEvents.add(evt);
- }
-
- public List getAllEvents() {
- return new ArrayList(allEvents);
- }
-
- public List getBubbledEvents() {
- return new ArrayList(bubbledEvents);
- }
-
- public List getAtEvents() {
- return new ArrayList(atEvents);
- }
-
- public List getCapturedEvents() {
- return new ArrayList(capturedEvents);
- }
-}
diff --git a/include/UniquePtr.h b/include/UniquePtr.h
new file mode 100644
index 0000000..f5c7c2c
--- /dev/null
+++ b/include/UniquePtr.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef UNIQUE_PTR_H_included
+#define UNIQUE_PTR_H_included
+
+#include <cstdlib> // For NULL.
+
+// Default deleter for pointer types.
+template <typename T>
+struct DefaultDelete {
+ enum { type_must_be_complete = sizeof(T) };
+ DefaultDelete() {}
+ void operator()(T* p) const {
+ delete p;
+ }
+};
+
+// Default deleter for array types.
+template <typename T>
+struct DefaultDelete<T[]> {
+ enum { type_must_be_complete = sizeof(T) };
+ void operator()(T* p) const {
+ delete[] p;
+ }
+};
+
+// A smart pointer that deletes the given pointer on destruction.
+// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
+// and boost::scoped_array).
+// Named to be in keeping with Android style but also to avoid
+// collision with any other implementation, until we can switch over
+// to unique_ptr.
+// Use thus:
+// UniquePtr<C> c(new C);
+template <typename T, typename D = DefaultDelete<T> >
+class UniquePtr {
+public:
+ // Construct a new UniquePtr, taking ownership of the given raw pointer.
+ explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
+ }
+
+ ~UniquePtr() {
+ reset();
+ }
+
+ // Accessors.
+ T& operator*() const { return *mPtr; }
+ T* operator->() const { return mPtr; }
+ T* get() const { return mPtr; }
+
+ // Returns the raw pointer and hands over ownership to the caller.
+ // The pointer will not be deleted by UniquePtr.
+ T* release() {
+ T* result = mPtr;
+ mPtr = NULL;
+ return result;
+ }
+
+ // Takes ownership of the given raw pointer.
+ // If this smart pointer previously owned a different raw pointer, that
+ // raw pointer will be freed.
+ void reset(T* ptr = NULL) {
+ if (ptr != mPtr) {
+ D()(mPtr);
+ mPtr = ptr;
+ }
+ }
+
+private:
+ // The raw pointer.
+ T* mPtr;
+
+ // Comparing unique pointers is probably a mistake, since they're unique.
+ template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
+ template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
+
+ // Disallow copy and assignment.
+ UniquePtr(const UniquePtr&);
+ void operator=(const UniquePtr&);
+};
+
+// Partial specialization for array types. Like std::unique_ptr, this removes
+// operator* and operator-> but adds operator[].
+template <typename T, typename D>
+class UniquePtr<T[], D> {
+public:
+ explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
+ }
+
+ ~UniquePtr() {
+ reset();
+ }
+
+ T& operator[](size_t i) const {
+ return mPtr[i];
+ }
+ T* get() const { return mPtr; }
+
+ T* release() {
+ T* result = mPtr;
+ mPtr = NULL;
+ return result;
+ }
+
+ void reset(T* ptr = NULL) {
+ if (ptr != mPtr) {
+ D()(mPtr);
+ mPtr = ptr;
+ }
+ }
+
+private:
+ T* mPtr;
+
+ // Disallow copy and assignment.
+ UniquePtr(const UniquePtr&);
+ void operator=(const UniquePtr&);
+};
+
+#if UNIQUE_PTR_TESTS
+
+// Run these tests with:
+// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out
+
+#include <stdio.h>
+
+static void assert(bool b) {
+ if (!b) {
+ fprintf(stderr, "FAIL\n");
+ abort();
+ }
+ fprintf(stderr, "OK\n");
+}
+static int cCount = 0;
+struct C {
+ C() { ++cCount; }
+ ~C() { --cCount; }
+};
+static bool freed = false;
+struct Freer {
+ void operator()(int* p) {
+ assert(*p == 123);
+ free(p);
+ freed = true;
+ }
+};
+
+int main(int argc, char* argv[]) {
+ //
+ // UniquePtr<T> tests...
+ //
+
+ // Can we free a single object?
+ {
+ UniquePtr<C> c(new C);
+ assert(cCount == 1);
+ }
+ assert(cCount == 0);
+ // Does release work?
+ C* rawC;
+ {
+ UniquePtr<C> c(new C);
+ assert(cCount == 1);
+ rawC = c.release();
+ }
+ assert(cCount == 1);
+ delete rawC;
+ // Does reset work?
+ {
+ UniquePtr<C> c(new C);
+ assert(cCount == 1);
+ c.reset(new C);
+ assert(cCount == 1);
+ }
+ assert(cCount == 0);
+
+ //
+ // UniquePtr<T[]> tests...
+ //
+
+ // Can we free an array?
+ {
+ UniquePtr<C[]> cs(new C[4]);
+ assert(cCount == 4);
+ }
+ assert(cCount == 0);
+ // Does release work?
+ {
+ UniquePtr<C[]> c(new C[4]);
+ assert(cCount == 4);
+ rawC = c.release();
+ }
+ assert(cCount == 4);
+ delete[] rawC;
+ // Does reset work?
+ {
+ UniquePtr<C[]> c(new C[4]);
+ assert(cCount == 4);
+ c.reset(new C[2]);
+ assert(cCount == 2);
+ }
+ assert(cCount == 0);
+
+ //
+ // Custom deleter tests...
+ //
+ assert(!freed);
+ {
+ UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int))));
+ *i = 123;
+ }
+ assert(freed);
+ return 0;
+}
+#endif
+
+#endif // UNIQUE_PTR_H_included
diff --git a/json/src/test/java/org/json/AllTests.java b/json/src/test/java/org/json/AllTests.java
new file mode 100644
index 0000000..8261a4d
--- /dev/null
+++ b/json/src/test/java/org/json/AllTests.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 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.json;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+ public static Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite();
+ suite.addTestSuite(JSONArrayTest.class);
+ suite.addTestSuite(JSONStringerTest.class);
+ suite.addTestSuite(JSONStringerTest.class);
+ return suite;
+ }
+}
diff --git a/json/src/test/java/org/json/JSONArrayTest.java b/json/src/test/java/org/json/JSONArrayTest.java
new file mode 100644
index 0000000..34e5ff6
--- /dev/null
+++ b/json/src/test/java/org/json/JSONArrayTest.java
@@ -0,0 +1,339 @@
+/**
+ * Copyright (C) 2010 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.json;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * This black box test was written without inspecting the non-free org.json sourcecode.
+ */
+public class JSONArrayTest extends TestCase {
+
+ public void testEmptyArray() throws JSONException {
+ JSONArray array = new JSONArray();
+ assertEquals(0, array.length());
+ assertEquals("", array.join(" AND "));
+ try {
+ array.get(0);
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ array.getBoolean(0);
+ fail();
+ } catch (JSONException e) {
+ }
+
+ assertEquals("[]", array.toString());
+ assertEquals("[]", array.toString(4));
+
+ // out of bounds is co-opted with defaulting
+ assertTrue(array.isNull(0));
+ assertNull(array.opt(0));
+ assertFalse(array.optBoolean(0));
+ assertTrue(array.optBoolean(0, true));
+
+ // bogus (but documented) behaviour: returns null rather than an empty object
+ assertNull(array.toJSONObject(new JSONArray()));
+ }
+
+ public void testEqualsAndHashCode() throws JSONException {
+ JSONArray a = new JSONArray();
+ JSONArray b = new JSONArray();
+ assertTrue(a.equals(b));
+ // bogus behavior: JSONArray overrides equals() but not hashCode().
+ assertEquals(a.hashCode(), b.hashCode());
+
+ a.put(true);
+ a.put(false);
+ b.put(true);
+ b.put(false);
+ assertTrue(a.equals(b));
+ assertEquals(a.hashCode(), b.hashCode());
+
+ b.put(true);
+ assertFalse(a.equals(b));
+ assertTrue(a.hashCode() != b.hashCode());
+ }
+
+ public void testBooleans() throws JSONException {
+ JSONArray array = new JSONArray();
+ array.put(true);
+ array.put(false);
+ array.put(2, false);
+ array.put(3, false);
+ array.put(2, true);
+ assertEquals("[true,false,true,false]", array.toString());
+ assertEquals(4, array.length());
+ assertEquals(Boolean.TRUE, array.get(0));
+ assertEquals(Boolean.FALSE, array.get(1));
+ assertEquals(Boolean.TRUE, array.get(2));
+ assertEquals(Boolean.FALSE, array.get(3));
+ assertFalse(array.isNull(0));
+ assertFalse(array.isNull(1));
+ assertFalse(array.isNull(2));
+ assertFalse(array.isNull(3));
+ assertEquals(true, array.optBoolean(0));
+ assertEquals(false, array.optBoolean(1, true));
+ assertEquals(true, array.optBoolean(2, false));
+ assertEquals(false, array.optBoolean(3));
+ assertEquals("true", array.getString(0));
+ assertEquals("false", array.getString(1));
+ assertEquals("true", array.optString(2));
+ assertEquals("false", array.optString(3, "x"));
+ assertEquals("[\n true,\n false,\n true,\n false\n]", array.toString(5));
+
+ JSONArray other = new JSONArray();
+ other.put(true);
+ other.put(false);
+ other.put(true);
+ other.put(false);
+ assertTrue(array.equals(other));
+ other.put(true);
+ assertFalse(array.equals(other));
+
+ other = new JSONArray();
+ other.put("true");
+ other.put("false");
+ other.put("truE");
+ other.put("FALSE");
+ assertFalse(array.equals(other));
+ assertFalse(other.equals(array));
+ assertEquals(true, other.getBoolean(0));
+ assertEquals(false, other.optBoolean(1, true));
+ assertEquals(true, other.optBoolean(2));
+ assertEquals(false, other.getBoolean(3));
+ }
+
+ public void testNulls() throws JSONException {
+ JSONArray array = new JSONArray();
+ array.put(3, null);
+ array.put(0, JSONObject.NULL);
+ assertEquals(4, array.length());
+ assertEquals("[null,null,null,null]", array.toString());
+
+ // bogus behaviour: there's 2 ways to represent null; each behaves differently!
+ assertEquals(JSONObject.NULL, array.get(0));
+ try {
+ assertEquals(null, array.get(1));
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ assertEquals(null, array.get(2));
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ assertEquals(null, array.get(3));
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals(JSONObject.NULL, array.opt(0));
+ assertEquals(null, array.opt(1));
+ assertEquals(null, array.opt(2));
+ assertEquals(null, array.opt(3));
+ assertTrue(array.isNull(0));
+ assertTrue(array.isNull(1));
+ assertTrue(array.isNull(2));
+ assertTrue(array.isNull(3));
+ assertEquals("null", array.optString(0));
+ assertEquals("", array.optString(1));
+ assertEquals("", array.optString(2));
+ assertEquals("", array.optString(3));
+ }
+
+ public void testNumbers() throws JSONException {
+ JSONArray array = new JSONArray();
+ array.put(Double.MIN_VALUE);
+ array.put(9223372036854775806L);
+ array.put(Double.MAX_VALUE);
+ array.put(-0d);
+ assertEquals(4, array.length());
+
+ // bogus behaviour: toString() and getString(int) return different values for -0d
+ assertEquals("[4.9E-324,9223372036854775806,1.7976931348623157E308,-0]", array.toString());
+
+ assertEquals(Double.MIN_VALUE, array.get(0));
+ assertEquals(9223372036854775806L, array.get(1));
+ assertEquals(Double.MAX_VALUE, array.get(2));
+ assertEquals(-0d, array.get(3));
+ assertEquals(Double.MIN_VALUE, array.getDouble(0));
+ assertEquals(9.223372036854776E18, array.getDouble(1));
+ assertEquals(Double.MAX_VALUE, array.getDouble(2));
+ assertEquals(-0d, array.getDouble(3));
+ assertEquals(0, array.getLong(0));
+ assertEquals(9223372036854775806L, array.getLong(1));
+ assertEquals(Long.MAX_VALUE, array.getLong(2));
+ assertEquals(0, array.getLong(3));
+ assertEquals(0, array.getInt(0));
+ assertEquals(-2, array.getInt(1));
+ assertEquals(Integer.MAX_VALUE, array.getInt(2));
+ assertEquals(0, array.getInt(3));
+ assertEquals(Double.MIN_VALUE, array.opt(0));
+ assertEquals(Double.MIN_VALUE, array.optDouble(0));
+ assertEquals(0, array.optLong(0, 1L));
+ assertEquals(0, array.optInt(0, 1));
+ assertEquals("4.9E-324", array.getString(0));
+ assertEquals("9223372036854775806", array.getString(1));
+ assertEquals("1.7976931348623157E308", array.getString(2));
+ assertEquals("-0.0", array.getString(3));
+
+ JSONArray other = new JSONArray();
+ other.put(Double.MIN_VALUE);
+ other.put(9223372036854775806L);
+ other.put(Double.MAX_VALUE);
+ other.put(-0d);
+ assertTrue(array.equals(other));
+ other.put(0, 0L);
+ assertFalse(array.equals(other));
+ }
+
+ public void testStrings() throws JSONException {
+ JSONArray array = new JSONArray();
+ array.put("true");
+ array.put("5.5");
+ array.put("9223372036854775806");
+ array.put("null");
+ array.put("5\"8' tall");
+ assertEquals(5, array.length());
+ assertEquals("[\"true\",\"5.5\",\"9223372036854775806\",\"null\",\"5\\\"8' tall\"]",
+ array.toString());
+
+ // although the documentation doesn't mention it, join() escapes text and wraps
+ // strings in quotes
+ assertEquals("\"true\" \"5.5\" \"9223372036854775806\" \"null\" \"5\\\"8' tall\"",
+ array.join(" "));
+
+ assertEquals("true", array.get(0));
+ assertEquals("null", array.getString(3));
+ assertEquals("5\"8' tall", array.getString(4));
+ assertEquals("true", array.opt(0));
+ assertEquals("5.5", array.optString(1));
+ assertEquals("9223372036854775806", array.optString(2, null));
+ assertEquals("null", array.optString(3, "-1"));
+ assertFalse(array.isNull(0));
+ assertFalse(array.isNull(3));
+
+ assertEquals(true, array.getBoolean(0));
+ assertEquals(true, array.optBoolean(0));
+ assertEquals(true, array.optBoolean(0, false));
+ assertEquals(0, array.optInt(0));
+ assertEquals(-2, array.optInt(0, -2));
+
+ assertEquals(5.5d, array.getDouble(1));
+ assertEquals(5, array.getLong(1));
+ assertEquals(5, array.getInt(1));
+ assertEquals(5, array.optInt(1, 3));
+
+ // The last digit of the string is a 6 but getLong returns a 7. It's probably parsing as a
+ // double and then converting that to a long. This is consistent with JavaScript.
+ assertEquals(9223372036854775807L, array.getLong(2));
+ assertEquals(9.223372036854776E18, array.getDouble(2));
+ assertEquals(Integer.MAX_VALUE, array.getInt(2));
+
+ assertFalse(array.isNull(3));
+ try {
+ array.getDouble(3);
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals(Double.NaN, array.optDouble(3));
+ assertEquals(-1.0d, array.optDouble(3, -1.0d));
+ }
+
+ public void testToJSONObject() throws JSONException {
+ JSONArray keys = new JSONArray();
+ keys.put("a");
+ keys.put("b");
+
+ JSONArray values = new JSONArray();
+ values.put(5.5d);
+ values.put(false);
+
+ JSONObject object = values.toJSONObject(keys);
+ assertEquals(5.5d, object.get("a"));
+ assertEquals(false, object.get("b"));
+
+ keys.put(0, "a");
+ values.put(0, 11.0d);
+ assertEquals(5.5d, object.get("a"));
+ }
+
+ public void testToJSONObjectWithNulls() throws JSONException {
+ JSONArray keys = new JSONArray();
+ keys.put("a");
+ keys.put("b");
+
+ JSONArray values = new JSONArray();
+ values.put(5.5d);
+ values.put(null);
+
+ // bogus behaviour: null values are stripped
+ JSONObject object = values.toJSONObject(keys);
+ assertEquals(1, object.length());
+ assertFalse(object.has("b"));
+ assertEquals("{\"a\":5.5}", object.toString());
+ }
+
+ public void testPutUnsupportedNumbers() throws JSONException {
+ JSONArray array = new JSONArray();
+
+ try {
+ array.put(Double.NaN);
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ array.put(0, Double.NEGATIVE_INFINITY);
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ array.put(0, Double.POSITIVE_INFINITY);
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testCreateWithUnsupportedNumbers() throws JSONException {
+ JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN));
+ assertEquals(2, array.length());
+ assertEquals(5.5, array.getDouble(0));
+ assertEquals(Double.NaN, array.getDouble(1));
+ }
+
+ public void testToStringWithUnsupportedNumbers() throws JSONException {
+ // bogus behaviour: when the array contains an unsupported number, toString returns null
+ JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN));
+ assertNull(array.toString());
+ }
+
+ public void testCreate() throws JSONException {
+ JSONArray array = new JSONArray(Arrays.asList(5.5, true));
+ assertEquals(2, array.length());
+ assertEquals(5.5, array.getDouble(0));
+ assertEquals(true, array.get(1));
+ assertEquals("[5.5,true]", array.toString());
+ }
+
+ public void testParsingConstructor() {
+ fail("TODO");
+ }
+}
diff --git a/json/src/test/java/org/json/JSONStringerTest.java b/json/src/test/java/org/json/JSONStringerTest.java
new file mode 100644
index 0000000..a30df9e
--- /dev/null
+++ b/json/src/test/java/org/json/JSONStringerTest.java
@@ -0,0 +1,356 @@
+/**
+ * Copyright (C) 2010 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.json;
+
+import junit.framework.TestCase;
+
+/**
+ * This black box test was written without inspecting the non-free org.json sourcecode.
+ */
+public class JSONStringerTest extends TestCase {
+
+ public void testEmptyStringer() {
+ // bogus behaviour: why isn't this the empty string?
+ assertNull(new JSONStringer().toString());
+ }
+
+ public void testValueJSONNull() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.value(JSONObject.NULL);
+ stringer.endArray();
+ assertEquals("[null]", stringer.toString());
+ }
+
+ public void testEmptyObject() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.object();
+ stringer.endObject();
+ assertEquals("{}", stringer.toString());
+ }
+
+ public void testEmptyArray() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.endArray();
+ assertEquals("[]", stringer.toString());
+ }
+
+ public void testArray() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.value(false);
+ stringer.value(5.0);
+ stringer.value(5L);
+ stringer.value("five");
+ stringer.value(null);
+ stringer.endArray();
+ assertEquals("[false,5,5,\"five\",null]", stringer.toString());
+ }
+
+ public void testKeyValue() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.object();
+ stringer.key("a").value(false);
+ stringer.key("b").value(5.0);
+ stringer.key("c").value(5L);
+ stringer.key("d").value("five");
+ stringer.key("e").value(null);
+ stringer.endObject();
+ assertEquals("{\"a\":false," +
+ "\"b\":5," +
+ "\"c\":5," +
+ "\"d\":\"five\"," +
+ "\"e\":null}", stringer.toString());
+ }
+
+ /**
+ * Test what happens when extreme values are emitted. Such values are likely
+ * to be rounded during parsing.
+ */
+ public void testNumericRepresentations() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.value(Long.MAX_VALUE);
+ stringer.value(Double.MIN_VALUE);
+ stringer.endArray();
+ assertEquals("[9223372036854775807,4.9E-324]", stringer.toString());
+ }
+
+ public void testWeirdNumbers() throws JSONException {
+ try {
+ new JSONStringer().array().value(Double.NaN);
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().array().value(Double.NEGATIVE_INFINITY);
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().array().value(Double.POSITIVE_INFINITY);
+ fail();
+ } catch (JSONException e) {
+ }
+
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.value(-0.0d);
+ stringer.value(0.0d);
+ stringer.endArray();
+ assertEquals("[-0,0]", stringer.toString());
+ }
+
+ public void testMismatchedScopes() {
+ try {
+ new JSONStringer().key("a");
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().value("a");
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().endObject();
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().endArray();
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().array().endObject();
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().object().endArray();
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().object().key("a").key("a");
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONStringer().object().value(false);
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testNullKey() {
+ try {
+ new JSONStringer().object().key(null);
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testRepeatedKey() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.object();
+ stringer.key("a").value(true);
+ stringer.key("a").value(false);
+ stringer.endObject();
+ // JSONStringer doesn't attempt to detect duplicates
+ assertEquals("{\"a\":true,\"a\":false}", stringer.toString());
+ }
+
+ public void testEmptyKey() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.object();
+ stringer.key("").value(false);
+ stringer.endObject();
+ assertEquals("{\"\":false}", stringer.toString()); // legit behaviour!
+ }
+
+ public void testEscaping() throws JSONException {
+ assertEscapedAllWays("a", "a");
+ assertEscapedAllWays("a\"", "a\\\"");
+ assertEscapedAllWays("\"", "\\\"");
+ assertEscapedAllWays(":", ":");
+ assertEscapedAllWays(",", ",");
+ assertEscapedAllWays("\n", "\\n");
+ assertEscapedAllWays("\t", "\\t");
+ assertEscapedAllWays(" ", " ");
+ assertEscapedAllWays("\\", "\\\\");
+ assertEscapedAllWays("{", "{");
+ assertEscapedAllWays("}", "}");
+ assertEscapedAllWays("[", "[");
+ assertEscapedAllWays("]", "]");
+
+ // how does it decide which characters to escape?
+ assertEscapedAllWays("\0", "\\u0000");
+ assertEscapedAllWays("\u0019", "\\u0019");
+ assertEscapedAllWays("\u0020", " ");
+ }
+
+ private void assertEscapedAllWays(String original, String escaped) throws JSONException {
+ assertEquals("{\"" + escaped + "\":false}",
+ new JSONStringer().object().key(original).value(false).endObject().toString());
+ assertEquals("{\"a\":\"" + escaped + "\"}",
+ new JSONStringer().object().key("a").value(original).endObject().toString());
+ assertEquals("[\"" + escaped + "\"]",
+ new JSONStringer().array().value(original).endArray().toString());
+ }
+
+ public void testJSONArrayAsValue() throws JSONException {
+ JSONArray array = new JSONArray();
+ array.put(false);
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.value(array);
+ stringer.endArray();
+ assertEquals("[[false]]", stringer.toString());
+ }
+
+ public void testJSONObjectAsValue() throws JSONException {
+ JSONObject object = new JSONObject();
+ object.put("a", false);
+ JSONStringer stringer = new JSONStringer();
+ stringer.object();
+ stringer.key("b").value(object);
+ stringer.endObject();
+ assertEquals("{\"b\":{\"a\":false}}", stringer.toString());
+ }
+
+ public void testArrayNestingMaxDepthIs20() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ for (int i = 0; i < 20; i++) {
+ stringer.array();
+ }
+ for (int i = 0; i < 20; i++) {
+ stringer.endArray();
+ }
+ assertEquals("[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]", stringer.toString());
+
+ stringer = new JSONStringer();
+ for (int i = 0; i < 20; i++) {
+ stringer.array();
+ }
+ try {
+ stringer.array();
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testObjectNestingMaxDepthIs20() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ for (int i = 0; i < 20; i++) {
+ stringer.object();
+ stringer.key("a");
+ }
+ stringer.value(false);
+ for (int i = 0; i < 20; i++) {
+ stringer.endObject();
+ }
+ assertEquals("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":" +
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":false" +
+ "}}}}}}}}}}}}}}}}}}}}", stringer.toString());
+
+ stringer = new JSONStringer();
+ for (int i = 0; i < 20; i++) {
+ stringer.object();
+ stringer.key("a");
+ }
+ try {
+ stringer.object();
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testMixedMaxDepth() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ for (int i = 0; i < 20; i+=2) {
+ stringer.array();
+ stringer.object();
+ stringer.key("a");
+ }
+ stringer.value(false);
+ for (int i = 0; i < 20; i+=2) {
+ stringer.endObject();
+ stringer.endArray();
+ }
+ assertEquals("[{\"a\":[{\"a\":[{\"a\":[{\"a\":[{\"a\":" +
+ "[{\"a\":[{\"a\":[{\"a\":[{\"a\":[{\"a\":false" +
+ "}]}]}]}]}]}]}]}]}]}]", stringer.toString());
+
+ stringer = new JSONStringer();
+ for (int i = 0; i < 20; i+=2) {
+ stringer.array();
+ stringer.object();
+ stringer.key("a");
+ }
+ try {
+ stringer.array();
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testMaxDepthWithArrayValue() throws JSONException {
+ JSONArray array = new JSONArray();
+ array.put(false);
+
+ JSONStringer stringer = new JSONStringer();
+ for (int i = 0; i < 20; i++) {
+ stringer.array();
+ }
+ stringer.value(array);
+ for (int i = 0; i < 20; i++) {
+ stringer.endArray();
+ }
+ assertEquals("[[[[[[[[[[[[[[[[[[[[[false]]]]]]]]]]]]]]]]]]]]]", stringer.toString());
+ }
+
+ public void testMaxDepthWithObjectValue() throws JSONException {
+ JSONObject object = new JSONObject();
+ object.put("a", false);
+ JSONStringer stringer = new JSONStringer();
+ for (int i = 0; i < 20; i++) {
+ stringer.object();
+ stringer.key("b");
+ }
+ stringer.value(object);
+ for (int i = 0; i < 20; i++) {
+ stringer.endObject();
+ }
+ assertEquals("{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":" +
+ "{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":{\"b\":" +
+ "{\"a\":false}}}}}}}}}}}}}}}}}}}}}", stringer.toString());
+ }
+
+ public void testMultipleRoots() throws JSONException {
+ JSONStringer stringer = new JSONStringer();
+ stringer.array();
+ stringer.endArray();
+ try {
+ stringer.object();
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+}
diff --git a/json/src/test/java/org/json/JSONTokenerTest.java b/json/src/test/java/org/json/JSONTokenerTest.java
new file mode 100644
index 0000000..1409a3b
--- /dev/null
+++ b/json/src/test/java/org/json/JSONTokenerTest.java
@@ -0,0 +1,565 @@
+/**
+ * Copyright (C) 2010 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.json;
+
+import junit.framework.TestCase;
+
+/**
+ * This black box test was written without inspecting the non-free org.json sourcecode.
+ */
+public class JSONTokenerTest extends TestCase {
+
+ public void testNulls() throws JSONException {
+ // bogus behaviour: JSONTokener accepts null, only to fail later on almost all APIs.
+ new JSONTokener(null).back();
+
+ try {
+ new JSONTokener(null).more();
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).next();
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).next(3);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).next('A');
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).nextClean();
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).nextString('"');
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).nextTo('A');
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).nextTo("ABC");
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).nextValue();
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).skipPast("ABC");
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ new JSONTokener(null).skipTo('A');
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ assertEquals("foo! at character 0 of null",
+ new JSONTokener(null).syntaxError("foo!").getMessage());
+
+ assertEquals(" at character 0 of null", new JSONTokener(null).toString());
+ }
+
+ public void testEmptyString() throws JSONException {
+ JSONTokener backTokener = new JSONTokener("");
+ backTokener.back();
+ assertEquals(" at character 0 of ", backTokener.toString());
+ assertFalse(new JSONTokener("").more());
+ assertEquals('\0', new JSONTokener("").next());
+ try {
+ new JSONTokener("").next(3);
+ fail();
+ } catch (JSONException expected) {
+ }
+ try {
+ new JSONTokener("").next('A');
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals('\0', new JSONTokener("").nextClean());
+ try {
+ new JSONTokener("").nextString('"');
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals("", new JSONTokener("").nextTo('A'));
+ assertEquals("", new JSONTokener("").nextTo("ABC"));
+ try {
+ new JSONTokener("").nextValue();
+ fail();
+ } catch (JSONException e) {
+ }
+ new JSONTokener("").skipPast("ABC");
+ assertEquals('\0', new JSONTokener("").skipTo('A'));
+ assertEquals("foo! at character 0 of ",
+ new JSONTokener("").syntaxError("foo!").getMessage());
+ assertEquals(" at character 0 of ", new JSONTokener("").toString());
+ }
+
+ public void testCharacterNavigation() throws JSONException {
+ JSONTokener abcdeTokener = new JSONTokener("ABCDE");
+ assertEquals('A', abcdeTokener.next());
+ assertEquals('B', abcdeTokener.next('B'));
+ assertEquals("CD", abcdeTokener.next(2));
+ try {
+ abcdeTokener.next(2);
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals('E', abcdeTokener.nextClean());
+ assertEquals('\0', abcdeTokener.next());
+ try {
+ // bogus behaviour: returning an empty string should be valid
+ abcdeTokener.next(0);
+ fail();
+ } catch (JSONException e) {
+ }
+ assertFalse(abcdeTokener.more());
+ abcdeTokener.back();
+ assertTrue(abcdeTokener.more());
+ assertEquals('E', abcdeTokener.next());
+ }
+
+ public void testBackNextAndMore() throws JSONException {
+ JSONTokener abcTokener = new JSONTokener("ABC");
+ assertTrue(abcTokener.more());
+ abcTokener.next();
+ abcTokener.next();
+ assertTrue(abcTokener.more());
+ abcTokener.next();
+ assertFalse(abcTokener.more());
+ abcTokener.back();
+ assertTrue(abcTokener.more());
+ abcTokener.next();
+ assertFalse(abcTokener.more());
+ abcTokener.back();
+ abcTokener.back();
+ abcTokener.back();
+ abcTokener.back(); // bogus behaviour: you can back up before the beginning of a String
+ assertEquals('A', abcTokener.next());
+ }
+
+ public void testNextMatching() throws JSONException {
+ JSONTokener abcdTokener = new JSONTokener("ABCD");
+ assertEquals('A', abcdTokener.next('A'));
+ try {
+ abcdTokener.next('C'); // although it failed, this op consumes a character of input
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals('C', abcdTokener.next('C'));
+ assertEquals('D', abcdTokener.next('D'));
+ try {
+ abcdTokener.next('E');
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testNextN() throws JSONException {
+ JSONTokener abcdeTokener = new JSONTokener("ABCDEF");
+ assertEquals("", abcdeTokener.next(0));
+ try {
+ abcdeTokener.next(7);
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals("ABC", abcdeTokener.next(3));
+ try {
+ abcdeTokener.next(4);
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ // bogus behaviour: there should be 3 characters left, but there must be an off-by-one
+ // error in the implementation.
+ assertEquals("DEF", abcdeTokener.next(3));
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals("DE", abcdeTokener.next(2));
+ assertEquals('F', abcdeTokener.next());
+ try {
+ // bogus behaviour: returning an empty string should be valid
+ abcdeTokener.next(0);
+ fail();
+ } catch (JSONException e) {
+ }
+ abcdeTokener.back();
+ abcdeTokener.back();
+ abcdeTokener.back();
+ assertEquals("DE", abcdeTokener.next(2));
+ assertEquals('F', abcdeTokener.next());
+ }
+
+ public void testNextCleanComments() throws JSONException {
+ JSONTokener tokener = new JSONTokener(
+ " A /*XX*/B/*XX//XX\n//XX\nXX*/C//X//X//X\nD/*X*///X\n");
+ assertEquals('A', tokener.nextClean());
+ assertEquals('B', tokener.nextClean());
+ assertEquals('C', tokener.nextClean());
+ assertEquals('D', tokener.nextClean());
+ assertEquals('\0', tokener.nextClean());
+ }
+
+ public void testNextCleanTrailingOpenComment() throws JSONException {
+ try {
+ new JSONTokener(" /* ").nextClean();
+ fail();
+ } catch (JSONException e) {
+ }
+ assertEquals('\0', new JSONTokener(" // ").nextClean());
+ }
+
+ public void testNextCleanNewlineDelimiters() throws JSONException {
+ assertEquals('B', new JSONTokener(" // \r\n B ").nextClean());
+ assertEquals('B', new JSONTokener(" // \n B ").nextClean());
+ assertEquals('B', new JSONTokener(" // \r B ").nextClean());
+ }
+
+ /**
+ * Tests which characters tokener treats as ignorable whitespace. See Kevin Bourrillion's
+ * <a href="https://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">list
+ * of whitespace characters</a>.
+ */
+ public void testNextCleanWhitespace() throws JSONException {
+ // This behaviour contradicts the JSON spec. It claims the only space
+ // characters are space, tab, newline and carriage return. But it treats
+ // many characters like whitespace! These are the same whitespace
+ // characters used by String.trim(), with the exception of '\0'.
+ assertEquals("character tabulation", 'A', new JSONTokener("\u0009A").nextClean());
+ assertEquals("line feed", 'A', new JSONTokener("\nA").nextClean());
+ assertEquals("line tabulation", 'A', new JSONTokener("\u000bA").nextClean());
+ assertEquals("form feed", 'A', new JSONTokener("\u000cA").nextClean());
+ assertEquals("carriage return", 'A', new JSONTokener("\rA").nextClean());
+ assertEquals("information separator 4", 'A', new JSONTokener("\u001cA").nextClean());
+ assertEquals("information separator 3", 'A', new JSONTokener("\u001dA").nextClean());
+ assertEquals("information separator 2", 'A', new JSONTokener("\u001eA").nextClean());
+ assertEquals("information separator 1", 'A', new JSONTokener("\u001fA").nextClean());
+ assertEquals("space", 'A', new JSONTokener("\u0020A").nextClean());
+ for (char c = '\u0002'; c < ' '; c++) {
+ assertEquals('A', new JSONTokener(new String(new char[] { ' ', c, 'A' })).nextClean());
+ }
+
+ // These characters are neither whitespace in the JSON spec nor the implementation
+ assertEquals("null", '\u0000', new JSONTokener("\u0000A").nextClean());
+ assertEquals("next line", '\u0085', new JSONTokener("\u0085A").nextClean());
+ assertEquals("non-breaking space", '\u00a0', new JSONTokener("\u00a0A").nextClean());
+ assertEquals("ogham space mark", '\u1680', new JSONTokener("\u1680A").nextClean());
+ assertEquals("mongolian vowel separator", '\u180e', new JSONTokener("\u180eA").nextClean());
+ assertEquals("en quad", '\u2000', new JSONTokener("\u2000A").nextClean());
+ assertEquals("em quad", '\u2001', new JSONTokener("\u2001A").nextClean());
+ assertEquals("en space", '\u2002', new JSONTokener("\u2002A").nextClean());
+ assertEquals("em space", '\u2003', new JSONTokener("\u2003A").nextClean());
+ assertEquals("three-per-em space", '\u2004', new JSONTokener("\u2004A").nextClean());
+ assertEquals("four-per-em space", '\u2005', new JSONTokener("\u2005A").nextClean());
+ assertEquals("six-per-em space", '\u2006', new JSONTokener("\u2006A").nextClean());
+ assertEquals("figure space", '\u2007', new JSONTokener("\u2007A").nextClean());
+ assertEquals("punctuation space", '\u2008', new JSONTokener("\u2008A").nextClean());
+ assertEquals("thin space", '\u2009', new JSONTokener("\u2009A").nextClean());
+ assertEquals("hair space", '\u200a', new JSONTokener("\u200aA").nextClean());
+ assertEquals("zero-width space", '\u200b', new JSONTokener("\u200bA").nextClean());
+ assertEquals("left-to-right mark", '\u200e', new JSONTokener("\u200eA").nextClean());
+ assertEquals("right-to-left mark", '\u200f', new JSONTokener("\u200fA").nextClean());
+ assertEquals("line separator", '\u2028', new JSONTokener("\u2028A").nextClean());
+ assertEquals("paragraph separator", '\u2029', new JSONTokener("\u2029A").nextClean());
+ assertEquals("narrow non-breaking space", '\u202f', new JSONTokener("\u202fA").nextClean());
+ assertEquals("medium mathematical space", '\u205f', new JSONTokener("\u205fA").nextClean());
+ assertEquals("ideographic space", '\u3000', new JSONTokener("\u3000A").nextClean());
+ }
+
+ public void testNextString() throws JSONException {
+ assertEquals("", new JSONTokener("'").nextString('\''));
+ assertEquals("", new JSONTokener("\"").nextString('\"'));
+ assertEquals("ABC", new JSONTokener("ABC'DEF").nextString('\''));
+ assertEquals("ABC", new JSONTokener("ABC'''DEF").nextString('\''));
+
+ // nextString permits slash-escaping of arbitrary characters!
+ assertEquals("ABC", new JSONTokener("A\\B\\C'DEF").nextString('\''));
+
+ JSONTokener tokener = new JSONTokener(" 'abc' 'def' \"ghi\"");
+ tokener.next();
+ assertEquals('\'', tokener.next());
+ assertEquals("abc", tokener.nextString('\''));
+ tokener.next();
+ assertEquals('\'', tokener.next());
+ assertEquals("def", tokener.nextString('\''));
+ tokener.next();
+ assertEquals('"', tokener.next());
+ assertEquals("ghi", tokener.nextString('\"'));
+ assertFalse(tokener.more());
+ }
+
+ public void testNextStringNoDelimiter() throws JSONException {
+ try {
+ new JSONTokener("").nextString('\'');
+ fail();
+ } catch (JSONException e) {
+ }
+
+ JSONTokener tokener = new JSONTokener(" 'abc");
+ tokener.next();
+ tokener.next();
+ try {
+ tokener.next('\'');
+ fail();
+ } catch (JSONException e) {
+ }
+ }
+
+ public void testNextStringEscapedQuote() throws JSONException {
+ try {
+ new JSONTokener("abc\\").nextString('"');
+ fail();
+ } catch (JSONException e) {
+ }
+
+ // we're mixing Java escaping like \" and JavaScript escaping like \\\"
+ // which makes these tests extra tricky to read!
+ assertEquals("abc\"def", new JSONTokener("abc\\\"def\"ghi").nextString('"'));
+ assertEquals("abc\\def", new JSONTokener("abc\\\\def\"ghi").nextString('"'));
+ assertEquals("abc/def", new JSONTokener("abc\\/def\"ghi").nextString('"'));
+ assertEquals("abc\bdef", new JSONTokener("abc\\bdef\"ghi").nextString('"'));
+ assertEquals("abc\fdef", new JSONTokener("abc\\fdef\"ghi").nextString('"'));
+ assertEquals("abc\ndef", new JSONTokener("abc\\ndef\"ghi").nextString('"'));
+ assertEquals("abc\rdef", new JSONTokener("abc\\rdef\"ghi").nextString('"'));
+ assertEquals("abc\tdef", new JSONTokener("abc\\tdef\"ghi").nextString('"'));
+ }
+
+ public void testNextStringUnicodeEscaped() throws JSONException {
+ // we're mixing Java escaping like \\ and JavaScript escaping like \\u
+ assertEquals("abc def", new JSONTokener("abc\\u0020def\"ghi").nextString('"'));
+ assertEquals("abcU0020def", new JSONTokener("abc\\U0020def\"ghi").nextString('"'));
+
+ // JSON requires 4 hex characters after a unicode escape
+ try {
+ new JSONTokener("abc\\u002\"").nextString('"');
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONTokener("abc\\u").nextString('"');
+ fail();
+ } catch (JSONException e) {
+ }
+ try {
+ new JSONTokener("abc\\u \"").nextString('"');
+ fail();
+ } catch (NumberFormatException e) {
+ }
+ assertEquals("abc\"def", new JSONTokener("abc\\u0022def\"ghi").nextString('"'));
+ try {
+ new JSONTokener("abc\\u000G\"").nextString('"');
+ fail();
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ public void testNextStringNonQuote() throws JSONException {
+ assertEquals("AB", new JSONTokener("ABC").nextString('C'));
+ assertEquals("ABCD", new JSONTokener("AB\\CDC").nextString('C'));
+ assertEquals("AB\nC", new JSONTokener("AB\\nCn").nextString('n'));
+ }
+
+ public void testNextTo() throws JSONException {
+ assertEquals("ABC", new JSONTokener("ABCDEFG").nextTo("DHI"));
+ assertEquals("ABCDEF", new JSONTokener("ABCDEF").nextTo(""));
+
+ JSONTokener tokener = new JSONTokener("ABC\rDEF\nGHI\r\nJKL");
+ assertEquals("ABC", tokener.nextTo("M"));
+ assertEquals('\r', tokener.next());
+ assertEquals("DEF", tokener.nextTo("M"));
+ assertEquals('\n', tokener.next());
+ assertEquals("GHI", tokener.nextTo("M"));
+ assertEquals('\r', tokener.next());
+ assertEquals('\n', tokener.next());
+ assertEquals("JKL", tokener.nextTo("M"));
+
+ tokener = new JSONTokener("ABCDEFGHI");
+ assertEquals("ABC", tokener.nextTo("DEF"));
+ assertEquals("", tokener.nextTo("DEF"));
+ assertEquals('D', tokener.next());
+ assertEquals("", tokener.nextTo("DEF"));
+ assertEquals('E', tokener.next());
+ assertEquals("", tokener.nextTo("DEF"));
+ assertEquals('F', tokener.next());
+ assertEquals("GHI", tokener.nextTo("DEF"));
+ assertEquals("", tokener.nextTo("DEF"));
+
+ tokener = new JSONTokener(" \t \fABC \t DEF");
+ assertEquals("ABC", tokener.nextTo("DEF"));
+ assertEquals('D', tokener.next());
+
+ tokener = new JSONTokener(" \t \fABC \n DEF");
+ assertEquals("ABC", tokener.nextTo("\n"));
+ assertEquals("", tokener.nextTo("\n"));
+
+ // Bogus behaviour: the tokener stops after \0 always
+ tokener = new JSONTokener(" \0\t \fABC \n DEF");
+ assertEquals("", tokener.nextTo("D"));
+ assertEquals('\t', tokener.next());
+ assertEquals("ABC", tokener.nextTo("D"));
+ tokener = new JSONTokener("ABC\0DEF");
+ assertEquals("ABC", tokener.nextTo("\0"));
+ assertEquals("DEF", tokener.nextTo("\0"));
+
+ tokener = new JSONTokener("");
+ try {
+ tokener.nextTo(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+
+ public void testSkipPast() {
+ JSONTokener tokener = new JSONTokener("ABCDEF");
+ tokener.skipPast("ABC");
+ assertEquals('D', tokener.next());
+ tokener.skipPast("EF");
+ assertEquals('\0', tokener.next());
+
+ tokener = new JSONTokener("ABCDEF");
+ tokener.skipPast("ABCDEF");
+ assertEquals('\0', tokener.next());
+
+ tokener = new JSONTokener("ABCDEF");
+ tokener.skipPast("G");
+ assertEquals('\0', tokener.next());
+
+ tokener = new JSONTokener("ABC\0ABC");
+ tokener.skipPast("ABC");
+ assertEquals('\0', tokener.next());
+ assertEquals('A', tokener.next());
+
+ tokener = new JSONTokener("\0ABC");
+ tokener.skipPast("ABC");
+ assertEquals('\0', tokener.next());
+
+ tokener = new JSONTokener("ABC\nDEF");
+ tokener.skipPast("DEF");
+ assertEquals('\0', tokener.next());
+
+ tokener = new JSONTokener("ABC");
+ tokener.skipPast("ABCDEF");
+ assertEquals('\0', tokener.next());
+
+ tokener = new JSONTokener("ABCDABCDABCD");
+ tokener.skipPast("ABC");
+ assertEquals('D', tokener.next());
+ tokener.skipPast("ABC");
+ assertEquals('D', tokener.next());
+ tokener.skipPast("ABC");
+ assertEquals('D', tokener.next());
+
+ tokener = new JSONTokener("");
+ try {
+ tokener.skipPast(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+
+ public void testSkipTo() {
+ JSONTokener tokener = new JSONTokener("ABCDEF");
+ tokener.skipTo('A');
+ assertEquals('A', tokener.next());
+ tokener.skipTo('D');
+ assertEquals('D', tokener.next());
+ tokener.skipTo('G');
+ assertEquals('E', tokener.next());
+ tokener.skipTo('A');
+ assertEquals('F', tokener.next());
+
+ tokener = new JSONTokener("ABC\0DEF");
+ tokener.skipTo('F');
+ // bogus behaviour: skipTo gives up when it sees '\0'
+ assertEquals('A', tokener.next());
+
+ tokener = new JSONTokener("ABC\nDEF");
+ tokener.skipTo('F');
+ assertEquals('F', tokener.next());
+
+ tokener = new JSONTokener("ABCfDEF");
+ tokener.skipTo('F');
+ assertEquals('F', tokener.next());
+
+ tokener = new JSONTokener("ABC/* DEF */");
+ tokener.skipTo('D');
+ assertEquals('D', tokener.next());
+ }
+
+ public void testDehexchar() {
+ assertEquals( 0, JSONTokener.dehexchar('0'));
+ assertEquals( 1, JSONTokener.dehexchar('1'));
+ assertEquals( 2, JSONTokener.dehexchar('2'));
+ assertEquals( 3, JSONTokener.dehexchar('3'));
+ assertEquals( 4, JSONTokener.dehexchar('4'));
+ assertEquals( 5, JSONTokener.dehexchar('5'));
+ assertEquals( 6, JSONTokener.dehexchar('6'));
+ assertEquals( 7, JSONTokener.dehexchar('7'));
+ assertEquals( 8, JSONTokener.dehexchar('8'));
+ assertEquals( 9, JSONTokener.dehexchar('9'));
+ assertEquals(10, JSONTokener.dehexchar('A'));
+ assertEquals(11, JSONTokener.dehexchar('B'));
+ assertEquals(12, JSONTokener.dehexchar('C'));
+ assertEquals(13, JSONTokener.dehexchar('D'));
+ assertEquals(14, JSONTokener.dehexchar('E'));
+ assertEquals(15, JSONTokener.dehexchar('F'));
+ assertEquals(10, JSONTokener.dehexchar('a'));
+ assertEquals(11, JSONTokener.dehexchar('b'));
+ assertEquals(12, JSONTokener.dehexchar('c'));
+ assertEquals(13, JSONTokener.dehexchar('d'));
+ assertEquals(14, JSONTokener.dehexchar('e'));
+ assertEquals(15, JSONTokener.dehexchar('f'));
+
+ for (int c = 0; c <= 0xFFFF; c++) {
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
+ continue;
+ }
+ assertEquals("dehexchar " + c, -1, JSONTokener.dehexchar((char) c));
+ }
+ }
+
+ public void testNextValue() {
+ fail("TODO");
+ }
+}
diff --git a/luni/src/test/java/tests/AllTests.java b/luni/src/test/java/tests/AllTests.java
index 0eab77e..3110026 100644
--- a/luni/src/test/java/tests/AllTests.java
+++ b/luni/src/test/java/tests/AllTests.java
@@ -66,6 +66,7 @@ public class AllTests
suite.addTest(java.util.AllTests.suite());
suite.addTest(javax.xml.parsers.AllTests.suite());
suite.addTest(org.apache.harmony.luni.platform.AllTests.suite());
+ suite.addTest(org.json.AllTests.suite());
suite.addTest(tests.api.org.apache.harmony.kernel.dalvik.AllTests.suite());
return suite;
diff --git a/math/src/main/java/java/math/BigInt.java b/math/src/main/java/java/math/BigInt.java
index 4d1e18e..6a1cb97 100644
--- a/math/src/main/java/java/math/BigInt.java
+++ b/math/src/main/java/java/math/BigInt.java
@@ -82,7 +82,6 @@ class BigInt
public static int consumeErrors(StringBuilder sb) {
int cnt = 0;
int e, reason;
- boolean first = true;
while ((e = NativeBN.ERR_get_error()) != 0) {
reason = e & 255;
if (reason == 103) {
@@ -96,7 +95,6 @@ class BigInt
if (reason == 65) {
throw new OutOfMemoryError();
}
- if (!first) { sb.append(" *** "); first = false; }
sb.append(e).append(": ");
String s = NativeBN.ERR_error_string(e);
sb.append(s);
diff --git a/security/src/main/files/cacerts.bks b/security/src/main/files/cacerts.bks
index 4f6fad4..ca45764 100644
--- a/security/src/main/files/cacerts.bks
+++ b/security/src/main/files/cacerts.bks
Binary files differ
diff --git a/security/src/main/files/cacerts/2afc57aa.0 b/security/src/main/files/cacerts/2afc57aa.0
new file mode 100644
index 0000000..31b8092
--- /dev/null
+++ b/security/src/main/files/cacerts/2afc57aa.0
@@ -0,0 +1,88 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 2e:6a:00:01:00:02:1f:d7:52:21:2c:11:5c:3b
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 2 CA, CN=TC TrustCenter Class 2 CA II
+ Validity
+ Not Before: Jan 12 14:38:43 2006 GMT
+ Not After : Dec 31 22:59:59 2025 GMT
+ Subject: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 2 CA, CN=TC TrustCenter Class 2 CA II
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:ab:80:87:9b:8e:f0:c3:7c:87:d7:e8:24:82:11:
+ b3:3c:dd:43:62:ee:f8:c3:45:da:e8:e1:a0:5f:d1:
+ 2a:b2:ea:93:68:df:b4:c8:d6:43:e9:c4:75:59:7f:
+ fc:e1:1d:f8:31:70:23:1b:88:9e:27:b9:7b:fd:3a:
+ d2:c9:a9:e9:14:2f:90:be:03:52:c1:49:cd:f6:fd:
+ e4:08:66:0b:57:8a:a2:42:a0:b8:d5:7f:69:5c:90:
+ 32:b2:97:0d:ca:4a:dc:46:3e:02:55:89:53:e3:1a:
+ 5a:cb:36:c6:07:56:f7:8c:cf:11:f4:4c:bb:30:70:
+ 04:95:a5:f6:39:8c:fd:73:81:08:7d:89:5e:32:1e:
+ 22:a9:22:45:4b:b0:66:2e:30:cc:9f:65:fd:fc:cb:
+ 81:a9:f1:e0:3b:af:a3:86:d1:89:ea:c4:45:79:50:
+ 5d:ae:e9:21:74:92:4d:8b:59:82:8f:94:e3:e9:4a:
+ f1:e7:49:b0:14:e3:f5:62:cb:d5:72:bd:1f:b9:d2:
+ 9f:a0:cd:a8:fa:01:c8:d9:0d:df:da:fc:47:9d:b3:
+ c8:54:df:49:4a:f1:21:a9:fe:18:4e:ee:48:d4:19:
+ bb:ef:7d:e4:e2:9d:cb:5b:b6:6e:ff:e3:cd:5a:e7:
+ 74:82:05:ba:80:25:38:cb:e4:69:9e:af:41:aa:1a:
+ 84:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ E3:AB:54:4C:80:A1:DB:56:43:B7:91:4A:CB:F3:82:7A:13:5C:08:AB
+ X509v3 CRL Distribution Points:
+ URI:http://www.trustcenter.de/crl/v2/tc_class_2_ca_II.crl
+ URI:ldap://www.trustcenter.de/CN=TC%20TrustCenter%20Class%202%20CA%20II,O=TC%20TrustCenter%20GmbH,OU=rootcerts,DC=trustcenter,DC=de?certificateRevocationList?base?
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 8c:d7:df:7e:ee:1b:80:10:b3:83:f5:db:11:ea:6b:4b:a8:92:
+ 18:d9:f7:07:39:f5:2c:be:06:75:7a:68:53:15:1c:ea:4a:ed:
+ 5e:fc:23:b2:13:a0:d3:09:ff:f6:f6:2e:6b:41:71:79:cd:e2:
+ 6d:fd:ae:59:6b:85:1d:b8:4e:22:9a:ed:66:39:6e:4b:94:e6:
+ 55:fc:0b:1b:8b:77:c1:53:13:66:89:d9:28:d6:8b:f3:45:4a:
+ 63:b7:fd:7b:0b:61:5d:b8:6d:be:c3:dc:5b:79:d2:ed:86:e5:
+ a2:4d:be:5e:74:7c:6a:ed:16:38:1f:7f:58:81:5a:1a:eb:32:
+ 88:2d:b2:f3:39:77:80:af:5e:b6:61:75:29:db:23:4d:88:ca:
+ 50:28:cb:85:d2:d3:10:a2:59:6e:d3:93:54:00:7a:a2:46:95:
+ 86:05:9c:a9:19:98:e5:31:72:0c:00:e2:67:d9:40:e0:24:33:
+ 7b:6f:2c:b9:5c:ab:65:9d:2c:ac:76:ea:35:99:f5:97:b9:0f:
+ 24:ec:c7:76:21:28:65:ae:57:e8:07:88:75:4a:56:a0:d2:05:
+ 3a:a4:e6:8d:92:88:2c:f3:f2:e1:c1:c6:61:db:41:c5:c7:9b:
+ f7:0e:1a:51:45:c2:61:6b:dc:64:27:17:8c:5a:b7:da:74:28:
+ cd:97:e4:bd
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
+tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
+uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
+XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
+8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
+5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
+kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
+GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
+ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
+au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
+hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
+dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
+-----END CERTIFICATE-----
diff --git a/security/src/main/files/cacerts/5021a0a2.0 b/security/src/main/files/cacerts/5021a0a2.0
new file mode 100644
index 0000000..ae6c41b
--- /dev/null
+++ b/security/src/main/files/cacerts/5021a0a2.0
@@ -0,0 +1,83 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 1d:a2:00:01:00:02:ec:b7:60:80:78:8d:b6:06
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Universal CA, CN=TC TrustCenter Universal CA I
+ Validity
+ Not Before: Mar 22 15:54:28 2006 GMT
+ Not After : Dec 31 22:59:59 2025 GMT
+ Subject: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Universal CA, CN=TC TrustCenter Universal CA I
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:a4:77:23:96:44:af:90:f4:31:a7:10:f4:26:87:
+ 9c:f3:38:d9:0f:5e:de:cf:41:e8:31:ad:c6:74:91:
+ 24:96:78:1e:09:a0:9b:9a:95:4a:4a:f5:62:7c:02:
+ a8:ca:ac:fb:5a:04:76:39:de:5f:f1:f9:b3:bf:f3:
+ 03:58:55:d2:aa:b7:e3:04:22:d1:f8:94:da:22:08:
+ 00:8d:d3:7c:26:5d:cc:77:79:e7:2c:78:39:a8:26:
+ 73:0e:a2:5d:25:69:85:4f:55:0e:9a:ef:c6:b9:44:
+ e1:57:3d:df:1f:54:22:e5:6f:65:aa:33:84:3a:f3:
+ ce:7a:be:55:97:ae:8d:12:0f:14:33:e2:50:70:c3:
+ 49:87:13:bc:51:de:d7:98:12:5a:ef:3a:83:33:92:
+ 06:75:8b:92:7c:12:68:7b:70:6a:0f:b5:9b:b6:77:
+ 5b:48:59:9d:e4:ef:5a:ad:f3:c1:9e:d4:d7:45:4e:
+ ca:56:34:21:bc:3e:17:5b:6f:77:0c:48:01:43:29:
+ b0:dd:3f:96:6e:e6:95:aa:0c:c0:20:b6:fd:3e:36:
+ 27:9c:e3:5c:cf:4e:81:dc:19:bb:91:90:7d:ec:e6:
+ 97:04:1e:93:cc:22:49:d7:97:86:b6:13:0a:3c:43:
+ 23:77:7e:f0:dc:e6:cd:24:1f:3b:83:9b:34:3a:83:
+ 34:e3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ keyid:92:A4:75:2C:A4:9E:BE:81:44:EB:79:FC:8A:C5:95:A5:EB:10:75:73
+
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 92:A4:75:2C:A4:9E:BE:81:44:EB:79:FC:8A:C5:95:A5:EB:10:75:73
+ Signature Algorithm: sha1WithRSAEncryption
+ 28:d2:e0:86:d5:e6:f8:7b:f0:97:dc:22:6b:3b:95:14:56:0f:
+ 11:30:a5:9a:4f:3a:b0:3a:e0:06:cb:65:f5:ed:c6:97:27:fe:
+ 25:f2:57:e6:5e:95:8c:3e:64:60:15:5a:7f:2f:0d:01:c5:b1:
+ 60:fd:45:35:cf:f0:b2:bf:06:d9:ef:5a:be:b3:62:21:b4:d7:
+ ab:35:7c:53:3e:a6:27:f1:a1:2d:da:1a:23:9d:cc:dd:ec:3c:
+ 2d:9e:27:34:5d:0f:c2:36:79:bc:c9:4a:62:2d:ed:6b:d9:7d:
+ 41:43:7c:b6:aa:ca:ed:61:b1:37:82:15:09:1a:8a:16:30:d8:
+ ec:c9:d6:47:72:78:4b:10:46:14:8e:5f:0e:af:ec:c7:2f:ab:
+ 10:d7:b6:f1:6e:ec:86:b2:c2:e8:0d:92:73:dc:a2:f4:0f:3a:
+ bf:61:23:10:89:9c:48:40:6e:70:00:b3:d3:ba:37:44:58:11:
+ 7a:02:6a:88:f0:37:34:f0:19:e9:ac:d4:65:73:f6:69:8c:64:
+ 94:3a:79:85:29:b0:16:2b:0c:82:3f:06:9c:c7:fd:10:2b:9e:
+ 0f:2c:b6:9e:e3:15:bf:d9:36:1c:ba:25:1a:52:3d:1a:ec:22:
+ 0c:1c:e0:a4:a2:3d:f0:e8:39:cf:81:c0:7b:ed:5d:1f:6f:c5:
+ d0:0b:d7:98
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
+MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
+R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
+VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
+JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
+fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
+jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
+wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
+fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
+VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
+CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
+7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
+8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
+ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
+2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
diff --git a/support/src/test/java/tests/support/resource/Support_Resources.java b/support/src/test/java/tests/support/resource/Support_Resources.java
index 53a8925..67b6001 100644
--- a/support/src/test/java/tests/support/resource/Support_Resources.java
+++ b/support/src/test/java/tests/support/resource/Support_Resources.java
@@ -205,4 +205,20 @@ public class Support_Resources {
throw new RuntimeException("Failed to load resource: " + name);
}
}
+
+ public static File resourceToTempFile(String path) throws IOException {
+ File f = File.createTempFile("out", ".xml");
+ f.deleteOnExit();
+ FileOutputStream out = new FileOutputStream(f);
+
+ InputStream xml = Support_Resources.class.getResourceAsStream(path);
+ int b;
+ while ((b = xml.read()) != -1) {
+ out.write(b);
+ }
+ out.flush();
+ out.close();
+ xml.close();
+ return f;
+ }
}
diff --git a/tools/runner/Android.mk b/tools/runner/Android.mk
index 851214b..b208219 100644
--- a/tools/runner/Android.mk
+++ b/tools/runner/Android.mk
@@ -1,57 +1,22 @@
LOCAL_PATH:= $(call my-dir)
+# build DalvikRunner from the source under java/.
include $(CLEAR_VARS)
-
-ext_dirs := \
- ../../../../external/jsr305/ri/src/main/java \
- ../../../../external/guava/src \
- ../../../../external/caliper/src
-
-ext_src_files := $(call all-java-files-under,$(ext_dirs))
-
-LOCAL_SRC_FILES := \
- $(ext_src_files) \
- java/dalvik/runner/Adb.java \
- java/dalvik/runner/CaliperFinder.java \
- java/dalvik/runner/CaliperRunner.java \
- java/dalvik/runner/Classpath.java \
- java/dalvik/runner/CodeFinder.java \
- java/dalvik/runner/Command.java \
- java/dalvik/runner/CommandFailedException.java \
- java/dalvik/runner/DalvikRunner.java \
- java/dalvik/runner/DeviceDalvikVm.java \
- java/dalvik/runner/Driver.java \
- java/dalvik/runner/Dx.java \
- java/dalvik/runner/ExpectedResult.java \
- java/dalvik/runner/JUnitFinder.java \
- java/dalvik/runner/JUnitRunner.java \
- java/dalvik/runner/JavaVm.java \
- java/dalvik/runner/Javac.java \
- java/dalvik/runner/JtregFinder.java \
- java/dalvik/runner/JtregRunner.java \
- java/dalvik/runner/MainFinder.java \
- java/dalvik/runner/MainRunner.java \
- java/dalvik/runner/NamingPatternCodeFinder.java \
- java/dalvik/runner/Option.java \
- java/dalvik/runner/OptionParser.java \
- java/dalvik/runner/Result.java \
- java/dalvik/runner/Strings.java \
- java/dalvik/runner/TestRun.java \
- java/dalvik/runner/TestRunner.java \
- java/dalvik/runner/Threads.java \
- java/dalvik/runner/Vm.java \
- java/dalvik/runner/XmlReportPrinter.java \
-
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
LOCAL_MODULE:= dalvik_runner
-LOCAL_STATIC_JAVA_LIBRARIES := javatest jh jtreg kxml2-2.3.0
-
+LOCAL_STATIC_JAVA_LIBRARIES := caliper javatest jh jtreg kxml2-2.3.0
# TODO this only works when junit is already built...
LOCAL_JAVA_LIBRARIES := junit
-
+LOCAL_JAVACFLAGS := -Werror -Xlint:unchecked
include $(BUILD_HOST_JAVA_LIBRARY)
include $(call all-subdir-makefiles)
+# prebuilt caliper.jar
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_JAVA_LIBRARIES := caliper:lib/caliper.jar
+include $(BUILD_HOST_PREBUILT)
+
# prebuilt javatest.jar
include $(CLEAR_VARS)
LOCAL_PREBUILT_JAVA_LIBRARIES := javatest:lib/javatest.jar
diff --git a/tools/runner/java/dalvik/runner/Aapt.java b/tools/runner/java/dalvik/runner/Aapt.java
new file mode 100644
index 0000000..4d1a873
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Aapt.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+
+/**
+ * An aapt (Android Asset Packaging Tool) command.
+ */
+final class Aapt {
+
+ public void apk(File apk, File manifest) {
+
+ // TODO: we should be able to work with a shipping SDK, not depend on out/...
+ new Command.Builder()
+ .args("aapt")
+ .args("package")
+ .args("-F")
+ .args(apk)
+ .args("-M")
+ .args(manifest)
+ .args("-I")
+ .args("out/target/common/obj/APPS/framework-res_intermediates/package-export.apk")
+ .execute();
+ }
+ public void add(File apk, File dex) {
+ new Command.Builder()
+ .args("aapt")
+ .args("add")
+ .args("-k")
+ .args(apk)
+ .args(dex)
+ .execute();
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/ActivityMode.java b/tools/runner/java/dalvik/runner/ActivityMode.java
new file mode 100644
index 0000000..b2b4a3b
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/ActivityMode.java
@@ -0,0 +1,256 @@
+/*
+ * 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.runner;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Logger;
+
+/**
+ * Runs a test in the context of an android.app.Activity on a device
+ */
+final class ActivityMode extends Mode {
+
+ private static final Logger logger = Logger.getLogger(ActivityMode.class.getName());
+
+ private static final String TEST_ACTIVITY_CLASS = "dalvik.runner.TestActivity";
+
+ ActivityMode(Integer debugPort, long timeoutSeconds, File sdkJar, File localTemp,
+ boolean cleanBefore, boolean cleanAfter, File deviceRunnerDir) {
+ super(new EnvironmentDevice(cleanBefore, cleanAfter,
+ debugPort, localTemp, deviceRunnerDir),
+ timeoutSeconds, sdkJar);
+ }
+
+ private EnvironmentDevice getEnvironmentDevice() {
+ return (EnvironmentDevice) environment;
+ }
+
+ @Override protected void prepare(Set<File> testRunnerJava, Classpath testRunnerClasspath) {
+ testRunnerJava.add(new File("dalvik/libcore/tools/runner/lib/TestActivity.java"));
+ super.prepare(testRunnerJava, testRunnerClasspath);
+ }
+
+ @Override protected void postCompileTestRunner() {
+ }
+
+ @Override protected void postCompileTest(TestRun testRun) {
+ logger.fine("aapt and push " + testRun.getQualifiedName());
+
+ // Some things of note:
+ // 1. we can't put multiple dex files in one apk
+ // 2. we can't just give dex multiple jars with conflicting class names
+ // 3. dex is slow if we give it too much to chew on
+ // 4. dex can run out of memory if given too much to chew on
+
+ // With that in mind, the APK packaging strategy is as follows:
+ // 1. make an empty classes temporary directory
+ // 2. add test runner classes
+ // 3. find original jar test came from, add contents to classes
+ // 4. add supported runner classes specified by finder
+ // 5. add latest test classes to output
+ // 6. dx to create a dex
+ // 7. aapt the dex to create apk
+ // 8. sign the apk
+ // 9. install the apk
+ File packagingDir = makePackagingDirectory(testRun);
+ addTestRunnerClasses(packagingDir);
+ List<File> found = new ArrayList<File>();
+ File originalTestJar = findOriginalTestJar(testRun);
+ if (originalTestJar != null) {
+ found.add(originalTestJar);
+ }
+ found.addAll(testRun.getRunnerClasspath().getElements());
+ extractJars(packagingDir, found);
+ addTestClasses(testRun, packagingDir);
+ File dex = createDex(testRun, packagingDir);
+ File apkUnsigned = createApk(testRun, dex);
+ File apkSigned = signApk(testRun, apkUnsigned);
+ installApk(testRun, apkSigned);
+ }
+
+ private File makePackagingDirectory(TestRun testRun) {
+ File packagingDir = new File(environment.testCompilationDir(testRun), "packaging");
+ new Rm().directoryTree(packagingDir);
+ new Mkdir().mkdirs(packagingDir);
+ return packagingDir;
+ }
+
+ private void addTestRunnerClasses(File packagingDir) {
+ new Command("rsync", "-a",
+ environment.testRunnerClassesDir() + "/",
+ packagingDir + "/").execute();
+ }
+
+ private File findOriginalTestJar(TestRun testRun) {
+ String testClass = testRun.getTestClass();
+ String testFile = testClass.replace('.', '/') + ".class";
+ for (File element : testClasspath.getElements()) {
+ try {
+ JarFile jar = new JarFile(element);
+ JarEntry jarEntry = jar.getJarEntry(testFile);
+ if (jarEntry != null) {
+ return element;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Could not find element " + element +
+ " of test class path " + testClasspath, e);
+ }
+ }
+ return null;
+ }
+
+ private static void extractJars(File packagingDir, List<File> jars) {
+ for (File jar : jars) {
+ new Command.Builder()
+ .args("unzip")
+ .args("-q")
+ .args("-o")
+ .args(jar)
+ .args("-d")
+ .args(packagingDir).execute();
+ }
+ new Rm().directoryTree(new File(packagingDir, "META-INF"));
+ }
+
+ private void addTestClasses(TestRun testRun, File packagingDir) {
+ File testClassesDir = environment.testClassesDir(testRun);
+ new Command("rsync", "-a",
+ testClassesDir + "/",
+ packagingDir + "/").execute();
+ }
+ private File createDex (TestRun testRun, File packagingDir) {
+ File testClassesDir = environment.testClassesDir(testRun);
+ File dex = new File(testClassesDir + ".dex");
+ new Dx().dex(dex, Classpath.of(packagingDir));
+ return dex;
+ }
+
+ private File createApk (TestRun testRun, File dex) {
+ String androidManifest =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+ " package=\"" + testRun.getQualifiedName() + "\">\n" +
+ " <uses-permission android:name=\"android.permission.INTERNET\" />\n" +
+ " <application>\n" +
+ " <activity android:name=\"" + TEST_ACTIVITY_CLASS + "\">\n" +
+ " <intent-filter>\n" +
+ " <action android:name=\"android.intent.action.MAIN\" />\n" +
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n" +
+ " </intent-filter>\n" +
+ " </activity>\n" +
+ " </application>\n" +
+ "</manifest>\n";
+ File androidManifestFile =
+ new File(environment.testCompilationDir(testRun),
+ "AndroidManifest.xml");
+ try {
+ FileOutputStream androidManifestOut =
+ new FileOutputStream(androidManifestFile);
+ androidManifestOut.write(androidManifest.getBytes("UTF-8"));
+ androidManifestOut.close();
+ } catch (IOException e) {
+ throw new RuntimeException("Problem writing " + androidManifestFile, e);
+ }
+
+ File testClassesDir = environment.testClassesDir(testRun);
+ File apkUnsigned = new File(testClassesDir + ".apk.unsigned");
+ new Aapt().apk(apkUnsigned, androidManifestFile);
+ new Aapt().add(apkUnsigned, dex);
+ new Aapt().add(apkUnsigned, new File(testClassesDir, TestProperties.FILE));
+ return apkUnsigned;
+ }
+
+ private File signApk(TestRun testRun, File apkUnsigned) {
+ File testClassesDir = environment.testClassesDir(testRun);
+ File apkSigned = new File(testClassesDir, testRun.getQualifiedName() + ".apk");
+ // TODO: we should be able to work with a shipping SDK, not depend on out/...
+ // TODO: we should be able to work without hardwired keys, not depend on build/...
+ new Command.Builder()
+ .args("java")
+ .args("-jar")
+ .args("out/host/linux-x86/framework/signapk.jar")
+ .args("build/target/product/security/testkey.x509.pem")
+ .args("build/target/product/security/testkey.pk8")
+ .args(apkUnsigned)
+ .args(apkSigned).execute();
+ new Rm().file(apkUnsigned);
+ return apkSigned;
+ }
+
+ private void installApk(TestRun testRun, File apkSigned) {
+ // install the local apk ona the device
+ getEnvironmentDevice().adb.uninstall(testRun.getQualifiedName());
+ getEnvironmentDevice().adb.install(apkSigned);
+ }
+
+ @Override protected void fillInProperties(Properties properties, TestRun testRun) {
+ super.fillInProperties(properties, testRun);
+ properties.setProperty(TestProperties.DEVICE_RUNNER_DIR, getEnvironmentDevice().runnerDir.getPath());
+ }
+
+ @Override protected List<Command> buildCommands(TestRun testRun) {
+ List<Command> commands = new ArrayList<Command>();
+ commands.add(new Command.Builder()
+ .args("adb")
+ .args("shell")
+ .args("am")
+ .args("start")
+ .args("-a")
+ .args("android.intent.action.MAIN")
+ .args("-n")
+ .args(testRun.getQualifiedName() + "/" + TEST_ACTIVITY_CLASS).build());
+
+ File resultDir = new File(getEnvironmentDevice().runnerDir, testRun.getQualifiedName());
+ File resultFile = new File(resultDir, TestProperties.RESULT_FILE);
+ /*
+ * The follow bash script waits for the result file to
+ * exist. It polls once a second to see if it is there with
+ * "adb shell ls". The "tr" is to remove the carriage return
+ * and newline from the adb output. When it does exist, we
+ * "adb shell cat" it so we can see the SUCCESS/FAILURE
+ * results that are expected by Mode.runTest.
+ */
+ // TODO: move loop to Java
+ commands.add(new Command.Builder()
+ .args("bash")
+ .args("-c")
+ .args(
+ "while [ ! \"`adb shell ls " + resultFile + " | tr -d '\\r\\n'`\" = " +
+ " \"" + resultFile + "\" ] ; do " +
+ " sleep 1; " +
+ "done; " +
+ "adb shell cat " + resultFile).build());
+
+ return commands;
+ }
+
+ @Override void cleanup(TestRun testRun) {
+ super.cleanup(testRun);
+ if (environment.cleanAfter) {
+ getEnvironmentDevice().adb.uninstall(testRun.getQualifiedName());
+ }
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/Adb.java b/tools/runner/java/dalvik/runner/Adb.java
index d265167..075ca5f 100644
--- a/tools/runner/java/dalvik/runner/Adb.java
+++ b/tools/runner/java/dalvik/runner/Adb.java
@@ -17,6 +17,8 @@
package dalvik.runner;
import java.io.File;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
/**
* An adb command.
@@ -24,15 +26,25 @@ import java.io.File;
final class Adb {
public void mkdir(File name) {
- new Command("adb", "shell", "mkdir", name.toString()).execute();
+ new Command("adb", "shell", "mkdir", name.getPath()).execute();
}
public void rm(File name) {
- new Command("adb", "shell", "rm", "-r", name.toString()).execute();
+ new Command("adb", "shell", "rm", "-r", name.getPath()).execute();
}
public void push(File local, File remote) {
- new Command("adb", "push", local.toString(), remote.toString())
+ new Command("adb", "push", local.getPath(), remote.getPath())
+ .execute();
+ }
+
+ public void install(File apk) {
+ new Command("adb", "install", "-r", apk.getPath())
+ .execute();
+ }
+
+ public void uninstall(String packageName) {
+ new Command("adb", "uninstall", packageName)
.execute();
}
@@ -40,4 +52,39 @@ final class Adb {
new Command("adb", "forward", "tcp:" + localPort, "tcp:" + devicePort)
.execute();
}
-} \ No newline at end of file
+
+ public void waitForDevice() {
+ new Command("adb", "wait-for-device").execute();
+ }
+
+ /**
+ * Loop until we see a non-empty directory on the device. For
+ * example, wait until /sdcard is mounted.
+ */
+ public void waitForNonEmptyDirectory(File path, int timeoutSeconds) {
+ final int millisPerSecond = 1000;
+ final long start = System.currentTimeMillis();
+ final long deadline = start + (millisPerSecond * timeoutSeconds);
+
+ while (true) {
+ final long remainingSeconds = ((deadline - System.currentTimeMillis())
+ / millisPerSecond);
+ Command command = new Command("adb", "shell", "ls", path.getPath());
+ List<String> output;
+ try {
+ output = command.executeWithTimeout(remainingSeconds);
+ } catch (TimeoutException e) {
+ throw new RuntimeException("Timed out after " + timeoutSeconds +
+ " seconds waiting for file " + path, e);
+ }
+ try {
+ Thread.sleep(millisPerSecond);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ if (!output.isEmpty()) {
+ return;
+ }
+ }
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/CaliperFinder.java b/tools/runner/java/dalvik/runner/CaliperFinder.java
index 77d85dc..3609471 100644
--- a/tools/runner/java/dalvik/runner/CaliperFinder.java
+++ b/tools/runner/java/dalvik/runner/CaliperFinder.java
@@ -32,7 +32,15 @@ class CaliperFinder extends NamingPatternCodeFinder {
return "caliper";
}
- @Override protected Class<? extends TestRunner> runnerClass() {
+ public Class<? extends Runner> getRunnerClass() {
return CaliperRunner.class;
}
+
+ public File getRunnerJava() {
+ return new File(DalvikRunner.HOME_JAVA, "dalvik/runner/CaliperRunner.java");
+ }
+
+ public Classpath getRunnerClasspath() {
+ return new Classpath();
+ }
}
diff --git a/tools/runner/java/dalvik/runner/CaliperRunner.java b/tools/runner/java/dalvik/runner/CaliperRunner.java
index 514a208..b30644b 100644
--- a/tools/runner/java/dalvik/runner/CaliperRunner.java
+++ b/tools/runner/java/dalvik/runner/CaliperRunner.java
@@ -16,23 +16,22 @@
package dalvik.runner;
+import com.google.caliper.Benchmark;
import com.google.caliper.Runner;
/**
* Runs a <a href="http://code.google.com/p/caliper/">Caliper</a> benchmark.
*/
-public final class CaliperRunner extends TestRunner {
+public final class CaliperRunner implements dalvik.runner.Runner {
- @Override public boolean test() {
+ public void prepareTest(Class<?> testClass) {}
+
+ public boolean test(Class<?> testClass) {
try {
- Runner.main(className);
+ Runner.main(testClass.asSubclass(Benchmark.class), new String[0]);
} catch (Exception ex) {
ex.printStackTrace();
}
return false; // always print benchmarking results
}
-
- public static void main(String[] args) throws Exception {
- new CaliperRunner().run();
- }
}
diff --git a/tools/runner/java/dalvik/runner/Classpath.java b/tools/runner/java/dalvik/runner/Classpath.java
index 86000cb..607615a 100644
--- a/tools/runner/java/dalvik/runner/Classpath.java
+++ b/tools/runner/java/dalvik/runner/Classpath.java
@@ -30,13 +30,21 @@ final class Classpath {
private final List<File> elements = new ArrayList<File>();
public static Classpath of(File... files) {
+ return of(Arrays.asList(files));
+ }
+
+ public static Classpath of(Collection<File> files) {
Classpath result = new Classpath();
- result.elements.addAll(Arrays.asList(files));
+ result.elements.addAll(files);
return result;
}
public void addAll(File... elements) {
- this.elements.addAll(Arrays.asList(elements));
+ addAll(Arrays.asList(elements));
+ }
+
+ public void addAll(Collection<File> elements) {
+ this.elements.addAll(elements);
}
public void addAll(Classpath anotherClasspath) {
diff --git a/tools/runner/java/dalvik/runner/CodeFinder.java b/tools/runner/java/dalvik/runner/CodeFinder.java
index 1d4a95a..f770fa4 100644
--- a/tools/runner/java/dalvik/runner/CodeFinder.java
+++ b/tools/runner/java/dalvik/runner/CodeFinder.java
@@ -29,4 +29,19 @@ public interface CodeFinder {
* is empty, no executable code of this kind were found.
*/
public Set<TestRun> findTests(File file);
+
+ /**
+ * Return the class for the TestRunner
+ */
+ public Class<? extends Runner> getRunnerClass();
+
+ /**
+ * Return the Java file for the TestRunner
+ */
+ public File getRunnerJava();
+
+ /**
+ * Return the compile classpath for the TestRunner
+ */
+ public Classpath getRunnerClasspath();
}
diff --git a/tools/runner/java/dalvik/runner/Command.java b/tools/runner/java/dalvik/runner/Command.java
index 8904711..4319cf9 100644
--- a/tools/runner/java/dalvik/runner/Command.java
+++ b/tools/runner/java/dalvik/runner/Command.java
@@ -25,6 +25,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
/**
@@ -124,11 +131,50 @@ final class Command {
}
}
+ /**
+ * Executes a command with a specified timeout. Output is returned
+ * if the command succeeds. If Otherwise null is returned if the
+ * command timed out.
+ */
+ public List<String> executeWithTimeout(long timeoutSeconds)
+ throws TimeoutException {
+ ExecutorService outputReader
+ = Executors.newFixedThreadPool(1, Threads.daemonThreadFactory());
+ try {
+ start();
+ // run on a different thread to allow a timeout
+ Future<List<String>> future = outputReader.submit(new Callable<List<String>>() {
+ public List<String> call() throws Exception {
+ return gatherOutput();
+ }
+ });
+ return future.get(timeoutSeconds, TimeUnit.SECONDS);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to execute process: " + args, e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while executing process: " + args, e);
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (isStarted()) {
+ getProcess().destroy(); // to release the output reader
+ }
+ outputReader.shutdown();
+ }
+ }
+
static class Builder {
private final List<String> args = new ArrayList<String>();
private File workingDirectory;
private boolean permitNonZeroExitStatus = false;
+ public Builder args(Object... objects) {
+ for (Object object : objects) {
+ args(object.toString());
+ }
+ return this;
+ }
+
public Builder args(String... args) {
return args(Arrays.asList(args));
}
diff --git a/tools/runner/java/dalvik/runner/DalvikRunner.java b/tools/runner/java/dalvik/runner/DalvikRunner.java
index 20e722c..015fb9a 100644
--- a/tools/runner/java/dalvik/runner/DalvikRunner.java
+++ b/tools/runner/java/dalvik/runner/DalvikRunner.java
@@ -35,6 +35,9 @@ import java.util.logging.Logger;
*/
public final class DalvikRunner {
+ static final File HOME = new File("dalvik/libcore/tools/runner");
+ static final File HOME_JAVA = new File(HOME, "java");
+
private static class Options {
private final List<File> testFiles = new ArrayList<File>();
@@ -54,6 +57,12 @@ public final class DalvikRunner {
@Option(names = { "--timeout" })
private long timeoutSeconds = 10 * 60; // default is ten minutes;
+ @Option(names = { "--clean-before" })
+ private boolean cleanBefore = true;
+
+ @Option(names = { "--clean-after" })
+ private boolean cleanAfter = true;
+
@Option(names = { "--clean" })
private boolean clean = true;
@@ -96,9 +105,16 @@ public final class DalvikRunner {
System.out.println(" device within an android.app.Activity.");
System.out.println(" Default is: " + mode);
System.out.println();
- System.out.println(" --clean: remove temporary files (default). Disable with --no-clean");
- System.out.println(" and use with --verbose if you'd like to manually re-run");
- System.out.println(" commands afterwards.");
+ System.out.println(" --clean-before: remove working directories before building and");
+ System.out.println(" running (default). Disable with --no-clean-before if you are");
+ System.out.println(" using interactively with your own temporary input files.");
+ System.out.println();
+ System.out.println(" --clean-after: remove temporary files after running (default).");
+ System.out.println(" Disable with --no-clean-after and use with --verbose if");
+ System.out.println(" you'd like to manually re-run commands afterwards.");
+ System.out.println();
+ System.out.println(" --clean: synonym for --clean-before and --clean-after (default).");
+ System.out.println(" Disable with --no-clean if you want no files removed.");
System.out.println();
System.out.println(" --timeout-seconds <seconds>: maximum execution time of each");
System.out.println(" test before the runner aborts it.");
@@ -181,10 +197,6 @@ public final class DalvikRunner {
System.out.println("Invalid java home: " + javaHome);
return false;
}
- if (debugPort != null) {
- System.out.println("debug port " + debugPort + " should not be specified for mode " + mode);
- return false;
- }
}
// check vm option consistency
@@ -210,6 +222,11 @@ public final class DalvikRunner {
return false;
}
+ if (!clean) {
+ cleanBefore = false;
+ cleanAfter = false;
+ }
+
//
// Post-processing arguments
//
@@ -228,7 +245,7 @@ public final class DalvikRunner {
}
private final Options options = new Options();
- private final File localTemp = new File("/tmp/" + UUID.randomUUID());
+ private final File localTemp = new File("/tmp/dalvikrunner/" + UUID.randomUUID());
private DalvikRunner() {}
@@ -246,29 +263,36 @@ public final class DalvikRunner {
}
private void run() {
- Vm vm;
+ Mode mode;
if (options.mode.equals(Options.MODE_DEVICE)) {
- vm = new DeviceDalvikVm(
+ mode = new DeviceDalvikVm(
options.debugPort,
options.timeoutSeconds,
options.sdkJar,
localTemp,
options.vmArgs,
- options.clean,
+ options.cleanBefore,
+ options.cleanAfter,
options.deviceRunnerDir);
} else if (options.mode.equals(Options.MODE_HOST)) {
- vm = new JavaVm(
+ mode = new JavaVm(
options.debugPort,
options.timeoutSeconds,
options.sdkJar,
localTemp,
options.javaHome,
options.vmArgs,
- options.clean);
+ options.cleanBefore,
+ options.cleanAfter);
} else if (options.mode.equals(Options.MODE_ACTIVITY)) {
- vm = null;
- System.out.println("Mode " + options.mode + " not currently supported.");
- return;
+ mode = new ActivityMode(
+ options.debugPort,
+ options.timeoutSeconds,
+ options.sdkJar,
+ localTemp,
+ options.cleanBefore,
+ options.cleanAfter,
+ options.deviceRunnerDir);
} else {
System.out.println("Unknown mode mode " + options.mode + ".");
return;
@@ -281,7 +305,7 @@ public final class DalvikRunner {
new MainFinder());
Driver driver = new Driver(
localTemp,
- vm,
+ mode,
options.expectationFiles,
options.xmlReportsDirectory,
codeFinders);
@@ -293,7 +317,7 @@ public final class DalvikRunner {
}
driver.buildAndRunAllTests(options.testFiles);
- vm.shutdown();
+ mode.shutdown();
}
public static void main(String[] args) {
diff --git a/tools/runner/java/dalvik/runner/DeviceDalvikVm.java b/tools/runner/java/dalvik/runner/DeviceDalvikVm.java
index 4388565..7bdf482 100644
--- a/tools/runner/java/dalvik/runner/DeviceDalvikVm.java
+++ b/tools/runner/java/dalvik/runner/DeviceDalvikVm.java
@@ -24,91 +24,84 @@ import java.util.logging.Logger;
* Execute tests on a Dalvik VM using an Android device or emulator.
*/
final class DeviceDalvikVm extends Vm {
-
- 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 runnerDir;
- private final File testTemp;
-
- private final Adb adb = new Adb();
DeviceDalvikVm(Integer debugPort, long timeoutSeconds, File sdkJar,
- File localTemp, List<String> additionalVmArgs, boolean clean, File runnerDir) {
- super(debugPort, timeoutSeconds, sdkJar, localTemp, additionalVmArgs, clean);
+ File localTemp, List<String> additionalVmArgs,
+ boolean cleanBefore, boolean cleanAfter, File runnerDir) {
+ super(new EnvironmentDevice(cleanBefore, cleanAfter, debugPort, localTemp, runnerDir),
+ timeoutSeconds, sdkJar, additionalVmArgs);
+ }
- this.runnerDir = runnerDir;
- this.testTemp = new File(this.runnerDir, "/tests.tmp");
+ private EnvironmentDevice getEnvironmentDevice() {
+ return (EnvironmentDevice) environment;
}
- @Override public void prepare() {
- adb.rm(runnerDir);
- adb.mkdir(testTemp);
- if (debugPort != null) {
- adb.forwardTcp(debugPort, debugPort);
+ @Override protected void postCompileTestRunner() {
+ // TODO: does this really need to be a special case?
+ postCompile("testrunner", environment.testRunnerClassesDir());
+
+ // dex everything on the classpath and push it to the device.
+ for (File classpathElement : testClasspath.getElements()) {
+ String name = basenameOfJar(classpathElement);
+ logger.fine("dex and push " + name);
+ // make the local dex (inside a jar)
+ // TODO: this is *really* expensive. we need a cache!
+ File outputFile = getEnvironmentDevice().testDir(name + ".jar");
+ new Dx().dex(outputFile, Classpath.of(classpathElement));
+ // push the local dex to the device
+ getEnvironmentDevice().adb.push(outputFile, deviceDexFile(name));
}
- super.prepare();
}
- @Override protected Classpath postCompile(String name, Classpath targetClasses) {
- logger.fine("dex and push " + name);
-
- // make the local dex
- File localDex = new File(localTemp, name + ".jar");
- new Dx().dex(localDex.toString(), targetClasses);
-
- // post the local dex to the device
- File deviceDex = new File(runnerDir, localDex.getName());
- adb.push(localDex, deviceDex);
-
- return Classpath.of(deviceDex);
+ private String basenameOfJar(File jarFile) {
+ return jarFile.getName().replaceAll("\\.jar$", "");
}
- @Override public void shutdown() {
- super.shutdown();
-
- if (clean) {
- adb.rm(runnerDir);
- }
+ @Override protected void postCompileTest(TestRun testRun) {
+ postCompile(testRun.getQualifiedName(), environment.testClassesDir(testRun));
}
- @Override protected void prepareUserDir(TestRun testRun) {
- File testClassesDirOnDevice = testClassesDirOnDevice(testRun);
- adb.mkdir(testClassesDirOnDevice);
- adb.push(testRun.getTestDirectory(), testClassesDirOnDevice);
- testRun.setUserDir(testClassesDirOnDevice);
- }
+ private void postCompile(String name, File dir) {
+ logger.fine("dex and push " + name);
- @Override public void cleanup(TestRun testRun) {
- super.cleanup(testRun);
+ // make the local dex (inside a jar)
+ File localDex = new File(dir.getPath() + ".jar");
+ new Dx().dex(localDex, Classpath.of(dir));
- if (clean) {
- adb.rm(testClassesDirOnDevice(testRun));
- }
+ // post the local dex to the device
+ File deviceDex = deviceDexFile(name);
+ getEnvironmentDevice().adb.push(localDex, deviceDex);
}
- private File testClassesDirOnDevice(TestRun testRun) {
- return new File(runnerDir, testRun.getQualifiedName());
+ private File deviceDexFile(String name) {
+ return new File(getEnvironmentDevice().runnerDir, name + ".jar");
}
@Override protected VmCommandBuilder newVmCommandBuilder(
File workingDirectory) {
// ignore the working directory; it's device-local and we can't easily
// set the working directory for commands run via adb shell.
+ // TODO: we only *need* to set ANDROID_DATA on production devices.
+ // We set "user.home" to /sdcard because code might reasonably assume it can write to
+ // that directory.
return new VmCommandBuilder()
- .vmCommand("adb", "shell", "dalvikvm")
+ .vmCommand("adb", "shell", "ANDROID_DATA=/sdcard", "dalvikvm")
+ .vmArgs("-Duser.home=/sdcard")
.vmArgs("-Duser.name=root")
.vmArgs("-Duser.language=en")
.vmArgs("-Duser.region=US")
.vmArgs("-Djavax.net.ssl.trustStore=/system/etc/security/cacerts.bks")
- .temp(testTemp);
+ .temp(getEnvironmentDevice().testTemp);
}
- @Override protected Classpath getRuntimeSupportClasspath() {
- return RUNTIME_SUPPORT_CLASSPATH;
+ @Override protected Classpath getRuntimeSupportClasspath(TestRun testRun) {
+ Classpath classpath = new Classpath();
+ classpath.addAll(deviceDexFile(testRun.getQualifiedName()));
+ classpath.addAll(deviceDexFile("testrunner"));
+ for (File testClasspathElement : testClasspath.getElements()) {
+ classpath.addAll(deviceDexFile(basenameOfJar(testClasspathElement)));
+ }
+ return classpath;
}
}
diff --git a/tools/runner/java/dalvik/runner/Driver.java b/tools/runner/java/dalvik/runner/Driver.java
index 81c7d6b..574c8cb 100644
--- a/tools/runner/java/dalvik/runner/Driver.java
+++ b/tools/runner/java/dalvik/runner/Driver.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -42,7 +43,7 @@ final class Driver {
private final File localTemp;
private final Set<File> expectationFiles;
private final List<CodeFinder> codeFinders;
- private final Vm vm;
+ private final Mode mode;
private final File xmlReportsDirectory;
private final Map<String, ExpectedResult> expectedResults = new HashMap<String, ExpectedResult>();
@@ -52,11 +53,11 @@ final class Driver {
*/
private int unsupportedTests = 0;
- public Driver(File localTemp, Vm vm, Set<File> expectationFiles,
+ public Driver(File localTemp, Mode mode, Set<File> expectationFiles,
File xmlReportsDirectory, List<CodeFinder> codeFinders) {
this.localTemp = localTemp;
this.expectationFiles = expectationFiles;
- this.vm = vm;
+ this.mode = mode;
this.xmlReportsDirectory = xmlReportsDirectory;
this.codeFinders = codeFinders;
}
@@ -73,9 +74,7 @@ final class Driver {
* Builds and executes all tests in the test directory.
*/
public void buildAndRunAllTests(Collection<File> testFiles) {
- localTemp.mkdirs();
-
- final BlockingQueue<TestRun> readyToRun = new ArrayBlockingQueue<TestRun>(4);
+ new Mkdir().mkdirs(localTemp);
Set<TestRun> tests = new LinkedHashSet<TestRun>();
for (File testFile : testFiles) {
@@ -94,10 +93,25 @@ final class Driver {
tests.addAll(testsForFile);
}
+ // compute TestRunner java and classpath to pass to mode.prepare
+ Set<File> testRunnerJava = new HashSet<File>();
+ Classpath testRunnerClasspath = new Classpath();
+ for (final TestRun testRun : tests) {
+ testRunnerJava.add(testRun.getRunnerJava());
+ testRunnerClasspath.addAll(testRun.getRunnerClasspath());
+ }
+
+ // mode.prepare before mode.buildAndInstall to ensure test
+ // runner is built. packaging of activity APK files needs the
+ // test runner along with the test specific files.
+ mode.prepare(testRunnerJava, testRunnerClasspath);
+
logger.info("Running " + tests.size() + " tests.");
// build and install tests in a background thread. Using lots of
// threads helps for packages that contain many unsupported tests
+ final BlockingQueue<TestRun> readyToRun = new ArrayBlockingQueue<TestRun>(4);
+
ExecutorService builders = Threads.threadPerCpuExecutor();
int t = 0;
for (final TestRun testRun : tests) {
@@ -114,7 +128,7 @@ final class Driver {
+ " because the expectations file says it is unsupported.");
} else {
- vm.buildAndInstall(testRun);
+ mode.buildAndInstall(testRun);
logger.fine("installed test " + runIndex + "; "
+ readyToRun.size() + " are ready to run");
}
@@ -128,8 +142,6 @@ final class Driver {
}
builders.shutdown();
- vm.prepare();
-
List<TestRun> runs = new ArrayList<TestRun>(tests.size());
for (int i = 0; i < tests.size(); i++) {
logger.fine("executing test " + i + "; "
@@ -149,7 +161,7 @@ final class Driver {
runs.add(testRun);
execute(testRun);
- vm.cleanup(testRun);
+ mode.cleanup(testRun);
}
if (unsupportedTests > 0) {
@@ -197,7 +209,7 @@ final class Driver {
}
if (testRun.isRunnable()) {
- vm.runTest(testRun);
+ mode.runTest(testRun);
}
printResult(testRun);
diff --git a/tools/runner/java/dalvik/runner/Dx.java b/tools/runner/java/dalvik/runner/Dx.java
index d36a99d..393b70d 100644
--- a/tools/runner/java/dalvik/runner/Dx.java
+++ b/tools/runner/java/dalvik/runner/Dx.java
@@ -16,22 +16,46 @@
package dalvik.runner;
+import java.io.File;
+import java.util.logging.Logger;
+
/**
* A dx command.
*/
final class Dx {
+ private static final Logger logger = Logger.getLogger(Dx.class.getName());
+ private static final Md5Cache DEX_CACHE = new Md5Cache("dex");
- public void dex(String output, Classpath classpath) {
- // We pass --core-library so that we can write tests in the same package they're testing,
- // even when that's a core library package. If you're actually just using this tool to
- // execute arbitrary code, this has the unfortunate side-effect of preventing "dx" from
- // protecting you from yourself.
+ /**
+ * Converts all the .class files on 'classpath' into a dex file written to 'output'.
+ */
+ public void dex(File output, Classpath classpath) {
+ File key = DEX_CACHE.makeKey(classpath);
+ if (key != null && key.exists()) {
+ logger.fine("dex cache hit for " + classpath);
+ new Command.Builder().args("cp", key, output).execute();
+ return;
+ }
+ /*
+ * We pass --core-library so that we can write tests in the
+ * same package they're testing, even when that's a core
+ * library package. If you're actually just using this tool to
+ * execute arbitrary code, this has the unfortunate
+ * side-effect of preventing "dx" from protecting you from
+ * yourself.
+ *
+ * Memory options pulled from build/core/definitions.mk to
+ * handle large dx input when building dex for APK.
+ */
new Command.Builder()
.args("dx")
- .args("--core-library")
+ .args("-JXms16M")
+ .args("-JXmx1536M")
.args("--dex")
.args("--output=" + output)
+ .args("--core-library")
.args(Strings.objectsToStrings(classpath.getElements()))
.execute();
+ DEX_CACHE.insert(key, output);
}
}
diff --git a/tools/runner/java/dalvik/runner/Environment.java b/tools/runner/java/dalvik/runner/Environment.java
new file mode 100644
index 0000000..c284a37
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Environment.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+import java.util.logging.Logger;
+
+/**
+ * A target runtime environment such as a remote device or the local host
+ */
+abstract class Environment {
+ private static final Logger logger = Logger.getLogger(Environment.class.getName());
+
+ final boolean cleanBefore;
+ final boolean cleanAfter;
+ final Integer debugPort;
+ private final File localTemp;
+
+ Environment (boolean cleanBefore, boolean cleanAfter, Integer debugPort, File localTemp) {
+ this.cleanBefore = cleanBefore;
+ this.cleanAfter = cleanAfter;
+ this.debugPort = debugPort;
+ this.localTemp = localTemp;
+ }
+
+ /**
+ * Initializes the temporary directories and test harness necessary to run
+ * tests.
+ */
+ abstract void prepare();
+
+ /**
+ * Prepares the directory from which the test will be executed. Some tests
+ * expect to read data files from the current working directory; this step
+ * should ensure such files are available.
+ */
+ abstract void prepareUserDir(TestRun testRun);
+
+ /**
+ * Deletes files and releases any resources required for the execution of
+ * the given test.
+ */
+ void cleanup(TestRun testRun) {
+ if (cleanAfter) {
+ logger.fine("clean " + testRun.getQualifiedName());
+ new Rm().directoryTree(testCompilationDir(testRun));
+ new Rm().directoryTree(testUserDir(testRun));
+ }
+ }
+
+ final File testDir(String name) {
+ return new File(localTemp, name);
+ }
+
+ final File testRunnerDir(String name) {
+ return new File(testDir("testrunner"), name);
+ }
+
+ final File testRunnerClassesDir() {
+ return testRunnerDir("classes");
+ }
+
+ final File testCompilationDir(TestRun testRun) {
+ return new File(localTemp, testRun.getQualifiedName());
+ }
+
+ final File testClassesDir(TestRun testRun) {
+ return new File(testCompilationDir(testRun), "classes");
+ }
+
+ final File testUserDir(TestRun testRun) {
+ File testTemp = new File(localTemp, "userDir");
+ return new File(testTemp, testRun.getQualifiedName());
+ }
+
+ abstract void shutdown();
+}
diff --git a/tools/runner/java/dalvik/runner/EnvironmentDevice.java b/tools/runner/java/dalvik/runner/EnvironmentDevice.java
new file mode 100644
index 0000000..9ac1c64
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/EnvironmentDevice.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+import java.util.logging.Logger;
+
+class EnvironmentDevice extends Environment {
+ private static final Logger logger = Logger.getLogger(EnvironmentDevice.class.getName());
+
+ final Adb adb = new Adb();
+ final File runnerDir;
+ final File testTemp;
+
+ EnvironmentDevice (boolean cleanBefore, boolean cleanAfter,
+ Integer debugPort, File localTemp, File runnerDir) {
+ super(cleanBefore, cleanAfter, debugPort, localTemp);
+ this.runnerDir = runnerDir;
+ this.testTemp = new File(runnerDir, "/tests.tmp");
+ }
+
+ @Override void prepare() {
+ adb.waitForDevice();
+ adb.waitForNonEmptyDirectory(runnerDir.getParentFile(), 5 * 60);
+ if (cleanBefore) {
+ adb.rm(runnerDir);
+ }
+ adb.mkdir(runnerDir);
+ adb.mkdir(testTemp);
+ adb.mkdir(new File("/sdcard/dalvik-cache")); // TODO: only necessary on production devices.
+ if (debugPort != null) {
+ adb.forwardTcp(debugPort, debugPort);
+ }
+ }
+
+ @Override protected void prepareUserDir(TestRun testRun) {
+ File testClassesDirOnDevice = testClassesDirOnDevice(testRun);
+ adb.mkdir(testClassesDirOnDevice);
+ adb.push(testRun.getTestDirectory(), testClassesDirOnDevice);
+ testRun.setUserDir(testClassesDirOnDevice);
+ }
+
+ private File testClassesDirOnDevice(TestRun testRun) {
+ return new File(runnerDir, testRun.getQualifiedName());
+ }
+
+ @Override void cleanup(TestRun testRun) {
+ super.cleanup(testRun);
+ if (cleanAfter) {
+ adb.rm(testClassesDirOnDevice(testRun));
+ }
+ }
+
+ @Override void shutdown() {
+ if (cleanAfter) {
+ adb.rm(runnerDir);
+ }
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/EnvironmentHost.java b/tools/runner/java/dalvik/runner/EnvironmentHost.java
new file mode 100644
index 0000000..d02ea55
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/EnvironmentHost.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+
+class EnvironmentHost extends Environment {
+
+ EnvironmentHost(boolean cleanBefore, boolean cleanAfter,
+ Integer debugPort, File localTemp) {
+ super(cleanBefore, cleanAfter, debugPort, localTemp);
+ }
+
+ @Override void prepare() {}
+
+ @Override protected void prepareUserDir(TestRun testRun) {
+ File testUserDir = testUserDir(testRun);
+
+ // if the user dir exists, cp would copy the files to the wrong place
+ if (testUserDir.exists()) {
+ throw new IllegalStateException();
+ }
+
+ new Mkdir().mkdirs(testUserDir.getParentFile());
+ new Command("cp", "-r", testRun.getTestDirectory().toString(),
+ testUserDir.toString()).execute();
+ testRun.setUserDir(testUserDir);
+ }
+
+ @Override void shutdown() {}
+}
diff --git a/tools/runner/java/dalvik/runner/JUnitFinder.java b/tools/runner/java/dalvik/runner/JUnitFinder.java
index b446a39..131a8cf 100644
--- a/tools/runner/java/dalvik/runner/JUnitFinder.java
+++ b/tools/runner/java/dalvik/runner/JUnitFinder.java
@@ -32,7 +32,16 @@ class JUnitFinder extends NamingPatternCodeFinder {
return "junit";
}
- @Override protected Class<? extends TestRunner> runnerClass() {
+ public Class<? extends Runner> getRunnerClass() {
return JUnitRunner.class;
}
+
+ public File getRunnerJava() {
+ return new File(DalvikRunner.HOME_JAVA, "dalvik/runner/JUnitRunner.java");
+ }
+
+ public Classpath getRunnerClasspath() {
+ // TODO: we should be able to work with a shipping SDK, not depend on out/...
+ return Classpath.of(new File("out/host/common/obj/JAVA_LIBRARIES/junit_intermediates/javalib.jar").getAbsoluteFile());
+ }
}
diff --git a/tools/runner/java/dalvik/runner/JUnitRunner.java b/tools/runner/java/dalvik/runner/JUnitRunner.java
index de5aacd..4891448 100644
--- a/tools/runner/java/dalvik/runner/JUnitRunner.java
+++ b/tools/runner/java/dalvik/runner/JUnitRunner.java
@@ -23,7 +23,7 @@ import junit.runner.TestSuiteLoader;
/**
* Runs a JUnit test.
*/
-public final class JUnitRunner extends TestRunner {
+public final class JUnitRunner implements Runner {
private final junit.textui.TestRunner testRunner;
private Test junitTest;
@@ -46,16 +46,12 @@ public final class JUnitRunner extends TestRunner {
};
}
- @Override public void prepareTest() {
- junitTest = testRunner.getTest(className);
+ public void prepareTest(Class<?> testClass) {
+ junitTest = testRunner.getTest(testClass.getName());
}
- @Override public boolean test() {
+ public boolean test(Class<?> testClass) {
TestResult result = testRunner.doRun(junitTest);
return result.wasSuccessful();
}
-
- public static void main(String[] args) throws Exception {
- new JUnitRunner().run();
- }
-} \ No newline at end of file
+}
diff --git a/tools/runner/java/dalvik/runner/JavaVm.java b/tools/runner/java/dalvik/runner/JavaVm.java
index e29b36b..2dfc3e7 100644
--- a/tools/runner/java/dalvik/runner/JavaVm.java
+++ b/tools/runner/java/dalvik/runner/JavaVm.java
@@ -18,6 +18,7 @@ package dalvik.runner;
import java.io.File;
import java.util.List;
+import java.util.Set;
/**
* A local Java virtual machine like Harmony or the RI.
@@ -27,11 +28,19 @@ final class JavaVm extends Vm {
private final File javaHome;
JavaVm(Integer debugPort, long timeoutSeconds, File sdkJar, File localTemp,
- File javaHome, List<String> additionalVmArgs, boolean clean) {
- super(debugPort, timeoutSeconds, sdkJar, localTemp, additionalVmArgs, clean);
+ File javaHome, List<String> additionalVmArgs,
+ boolean cleanBefore, boolean cleanAfter) {
+ super(new EnvironmentHost(cleanBefore, cleanAfter, debugPort, localTemp),
+ timeoutSeconds, sdkJar, additionalVmArgs);
this.javaHome = javaHome;
}
+ @Override protected void postCompileTestRunner() {
+ }
+
+ @Override protected void postCompileTest(TestRun testRun) {
+ }
+
@Override protected VmCommandBuilder newVmCommandBuilder(
File workingDirectory) {
String java = javaHome == null ? "java" : new File(javaHome, "bin/java").getPath();
@@ -39,4 +48,12 @@ final class JavaVm extends Vm {
.vmCommand(java)
.workingDir(workingDirectory);
}
+ @Override protected Classpath getRuntimeSupportClasspath(TestRun testRun) {
+ Classpath classpath = new Classpath();
+ classpath.addAll(environment.testClassesDir(testRun));
+ classpath.addAll(testClasspath);
+ classpath.addAll(environment.testRunnerClassesDir());
+ classpath.addAll(testRunnerClasspath);
+ return classpath;
+ }
}
diff --git a/tools/runner/java/dalvik/runner/JtregFinder.java b/tools/runner/java/dalvik/runner/JtregFinder.java
index c4e865c..d846ae2 100644
--- a/tools/runner/java/dalvik/runner/JtregFinder.java
+++ b/tools/runner/java/dalvik/runner/JtregFinder.java
@@ -65,7 +65,7 @@ class JtregFinder implements CodeFinder {
try {
logger.fine("scanning " + directoryToScan + " for jtreg tests");
File workDirectory = new File(localTemp, "JTwork");
- workDirectory.mkdirs();
+ new Mkdir().mkdirs(workDirectory);
/*
* This code is capable of extracting test descriptions using jtreg 4.0
@@ -87,7 +87,8 @@ class JtregFinder implements CodeFinder {
String testClass = description.getName();
result.add(new TestRun(description.getDir(), description.getFile(),
testClass, suiteName, testName, qualifiedName,
- description.getTitle(), JtregRunner.class));
+ description.getTitle(),
+ getRunnerClass(), getRunnerJava(), getRunnerClasspath()));
}
return result;
} catch (Exception jtregFailure) {
@@ -123,4 +124,16 @@ class JtregFinder implements CodeFinder {
private String escape(String s) {
return s.replace('/', '.');
}
+
+ public Class<? extends Runner> getRunnerClass() {
+ return JtregRunner.class;
+ }
+
+ public File getRunnerJava() {
+ return new File(DalvikRunner.HOME_JAVA, "dalvik/runner/JtregRunner.java");
+ }
+
+ public Classpath getRunnerClasspath() {
+ return new Classpath();
+ }
}
diff --git a/tools/runner/java/dalvik/runner/JtregRunner.java b/tools/runner/java/dalvik/runner/JtregRunner.java
index 450c058..633a529 100644
--- a/tools/runner/java/dalvik/runner/JtregRunner.java
+++ b/tools/runner/java/dalvik/runner/JtregRunner.java
@@ -21,20 +21,19 @@ import java.lang.reflect.Method;
/**
* Runs a jtreg test.
*/
-public final class JtregRunner extends TestRunner {
+public final class JtregRunner implements Runner {
private Method main;
- @Override public void prepareTest() {
+ public void prepareTest(Class<?> testClass) {
try {
- Class<?> testClass = Class.forName(className);
main = testClass.getMethod("main", String[].class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
- @Override public boolean test() {
+ public boolean test(Class<?> testClass) {
try {
main.invoke(null, new Object[] { new String[0] });
return true;
@@ -43,8 +42,4 @@ public final class JtregRunner extends TestRunner {
return false;
}
}
-
- public static void main(String[] args) {
- new JtregRunner().run();
- }
-} \ No newline at end of file
+}
diff --git a/tools/runner/java/dalvik/runner/MainFinder.java b/tools/runner/java/dalvik/runner/MainFinder.java
index 0ebcb43..282969f 100644
--- a/tools/runner/java/dalvik/runner/MainFinder.java
+++ b/tools/runner/java/dalvik/runner/MainFinder.java
@@ -31,7 +31,15 @@ class MainFinder extends NamingPatternCodeFinder {
return "main";
}
- @Override protected Class<? extends TestRunner> runnerClass() {
+ public Class<? extends Runner> getRunnerClass() {
return MainRunner.class;
}
+
+ public File getRunnerJava() {
+ return new File(DalvikRunner.HOME_JAVA, "dalvik/runner/MainRunner.java");
+ }
+
+ public Classpath getRunnerClasspath() {
+ return new Classpath();
+ }
}
diff --git a/tools/runner/java/dalvik/runner/MainRunner.java b/tools/runner/java/dalvik/runner/MainRunner.java
index 6e993fe..34a4a47 100644
--- a/tools/runner/java/dalvik/runner/MainRunner.java
+++ b/tools/runner/java/dalvik/runner/MainRunner.java
@@ -21,20 +21,24 @@ import java.lang.reflect.Method;
/**
* Runs a Java class with a main method.
*/
-public final class MainRunner extends TestRunner {
+public final class MainRunner implements Runner {
- @Override public boolean test() {
+ private Method main;
+
+ public void prepareTest(Class<?> testClass) {
try {
- Method mainMethod = Class.forName(className)
- .getDeclaredMethod("main", String[].class);
- mainMethod.invoke(null, new Object[] { new String[0] });
- } catch (Exception ex) {
- ex.printStackTrace();
+ main = testClass.getMethod("main", String[].class);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
- return false; // always print main method output
}
- public static void main(String[] args) throws Exception {
- new MainRunner().run();
+ public boolean test(Class<?> testClass) {
+ try {
+ main.invoke(null, new Object[] { new String[0] });
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ }
+ return false; // always print main method output
}
}
diff --git a/tools/runner/java/dalvik/runner/Md5Cache.java b/tools/runner/java/dalvik/runner/Md5Cache.java
new file mode 100644
index 0000000..f6ba85d
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Md5Cache.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.MessageDigest;
+import java.util.logging.Logger;
+
+/**
+ * Caches content by MD5.
+ */
+public final class Md5Cache {
+ private static final Logger logger = Logger.getLogger(Md5Cache.class.getName());
+ private static final File CACHE_ROOT = new File("/tmp/vogar-md5-cache/");
+
+ private final String keyPrefix;
+
+ /**
+ * Creates a new cache accessor. There's only one directory on disk, so 'keyPrefix' is really
+ * just a convenience for humans inspecting the cache.
+ */
+ public Md5Cache(String keyPrefix) {
+ this.keyPrefix = keyPrefix;
+ }
+
+ /**
+ * Returns an ASCII hex representation of the MD5 of the content of 'file'.
+ */
+ private static String md5(File file) {
+ byte[] digest = null;
+ try {
+ MessageDigest digester = MessageDigest.getInstance("MD5");
+ byte[] bytes = new byte[8192];
+ FileInputStream in = new FileInputStream(file);
+ try {
+ int byteCount;
+ while ((byteCount = in.read(bytes)) > 0) {
+ digester.update(bytes, 0, byteCount);
+ }
+ digest = digester.digest();
+ } finally {
+ in.close();
+ }
+ } catch (Exception cause) {
+ throw new RuntimeException("Unable to compute MD5 of \"" + file + "\"", cause);
+ }
+ return (digest == null) ? null : byteArrayToHexString(digest);
+ }
+
+ private static String byteArrayToHexString(byte[] bytes) {
+ StringBuilder result = new StringBuilder();
+ for (byte b : bytes) {
+ result.append(Integer.toHexString((b >> 4) & 0xf));
+ result.append(Integer.toHexString(b & 0xf));
+ }
+ return result.toString();
+ }
+
+ /**
+ * Returns the appropriate key for a dex file corresponding to the contents of 'classpath'.
+ * Returns null if we don't think it's possible to cache the given classpath.
+ */
+ public File makeKey(Classpath classpath) {
+ // Do we have it in cache?
+ String key = keyPrefix;
+ for (File element : classpath.getElements()) {
+ // We only cache dexed .jar files, not directories.
+ if (!element.toString().endsWith(".jar")) {
+ return null;
+ }
+ key += "-" + md5(element);
+ }
+ return new File(CACHE_ROOT, key);
+ }
+
+ /**
+ * Copy the file 'content' into the cache with the given 'key'.
+ * This method assumes you're using the appropriate key for the content (and has no way to
+ * check because the key is a function of the inputs that made the content, not the content
+ * itself).
+ * We accept a null so the caller doesn't have to pay attention to whether we think we can
+ * cache the content or not.
+ */
+ public void insert(File key, File content) {
+ if (key == null) {
+ return;
+ }
+ logger.fine("inserting " + key);
+ if (!key.toString().startsWith(CACHE_ROOT.toString())) {
+ throw new IllegalArgumentException("key '" + key + "' not a valid cache key");
+ }
+ // Make sure the cache exists first.
+ new Mkdir().mkdirs(CACHE_ROOT);
+ // Copy it onto the same file system first, then atomically move it into place.
+ // That way, if we fail, we don't leave anything dangerous lying around.
+ File temporary = new File(key + ".tmp");
+ new Command.Builder().args("cp", content, temporary).execute();
+ new Command.Builder().args("mv", temporary, key).execute();
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/Mkdir.java b/tools/runner/java/dalvik/runner/Mkdir.java
new file mode 100644
index 0000000..46dcf08
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Mkdir.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+
+/**
+ * A mkdir command.
+ */
+final class Mkdir {
+
+ public void mkdirs(File directory) {
+ new Command("mkdir", "-p", directory.getPath()).execute();
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/Mode.java b/tools/runner/java/dalvik/runner/Mode.java
new file mode 100644
index 0000000..c2d6b14
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Mode.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+/**
+ * A Mode for running tests. Examples including running in a virtual
+ * machine either on the host or a device or within a specific context
+ * such as within an Activity.
+ */
+abstract class Mode {
+
+ private static final Pattern JAVA_TEST_PATTERN = Pattern.compile("\\/(\\w)+\\.java$");
+
+ private static final Logger logger = Logger.getLogger(Mode.class.getName());
+
+ protected final Environment environment;
+ protected final long timeoutSeconds;
+ protected final File sdkJar;
+
+ /**
+ * Set of Java files needed to built to tun the currently selected
+ * set of tests. We build a subset rather than all the files all
+ * the time to reduce dex packaging costs in the activity mode
+ * case.
+ */
+ protected final Set<File> testRunnerJava = new HashSet<File>();
+
+ /**
+ * Classpath of testRunner on the host side including any
+ * supporting libraries for testRunnerJava. Useful for compiling
+ * testRunnerJava as well as executing it on the host. Execution
+ * on the device requires further packaging typically done by
+ * postCompileTestRunner.
+ */
+ protected final Classpath testRunnerClasspath = new Classpath();
+
+ // TODO: this should be an immutable collection.
+ protected final Classpath testClasspath = Classpath.of(
+ new File("dalvik/libcore/tools/runner/lib/jsr305.jar"),
+ new File("dalvik/libcore/tools/runner/lib/guava.jar"),
+ new File("dalvik/libcore/tools/runner/lib/caliper.jar"),
+ // TODO: we should be able to work with a shipping SDK, not depend on out/...
+ // dalvik/libcore/**/test/ for junit
+ // TODO: jar up just the junit classes and drop the jar in our lib/ directory.
+ new File("out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jar").getAbsoluteFile());
+
+ Mode(Environment environment, long timeoutSeconds, File sdkJar) {
+ this.environment = environment;
+ this.timeoutSeconds = timeoutSeconds;
+ this.sdkJar = sdkJar;
+ }
+
+ /**
+ * Initializes the temporary directories and test harness necessary to run
+ * tests.
+ */
+ protected void prepare(Set<File> testRunnerJava, Classpath testRunnerClasspath) {
+ this.testRunnerJava.add(new File(DalvikRunner.HOME_JAVA, "dalvik/runner/TestRunner.java"));
+ this.testRunnerJava.addAll(dalvikAnnotationSourceFiles());
+ this.testRunnerJava.addAll(testRunnerJava);
+ this.testRunnerClasspath.addAll(testRunnerClasspath);
+ environment.prepare();
+ compileTestRunner();
+ }
+
+ private List<File> dalvikAnnotationSourceFiles() {
+ // Hopefully one day we'll strip the dalvik annotations out, but until then we need to make
+ // them available to javac(1).
+ File sourceDir = new File("dalvik/libcore/dalvik/src/main/java/dalvik/annotation");
+ File[] javaSourceFiles = sourceDir.listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String filename) {
+ return filename.endsWith(".java");
+ }
+ });
+ return Arrays.asList(javaSourceFiles);
+ }
+
+ private void compileTestRunner() {
+ logger.fine("build testrunner");
+
+ Classpath classpath = new Classpath();
+ classpath.addAll(testClasspath);
+ classpath.addAll(testRunnerClasspath);
+
+ File base = environment.testRunnerClassesDir();
+ new Mkdir().mkdirs(base);
+ new Javac()
+ .bootClasspath(sdkJar)
+ .classpath(classpath)
+ .sourcepath(DalvikRunner.HOME_JAVA)
+ .destination(base)
+ .compile(testRunnerJava);
+ postCompileTestRunner();
+ }
+
+ /**
+ * Hook method called after TestRunner compilation.
+ */
+ abstract protected void postCompileTestRunner();
+
+ /**
+ * Compiles classes for the given test and makes them ready for execution.
+ * If the test could not be compiled successfully, it will be updated with
+ * the appropriate test result.
+ */
+ public void buildAndInstall(TestRun testRun) {
+ logger.fine("build " + testRun.getQualifiedName());
+
+ boolean testCompiled;
+ try {
+ testCompiled = compileTest(testRun);
+ if (!testCompiled) {
+ testRun.setResult(Result.UNSUPPORTED, Collections.<String>emptyList());
+ return;
+ }
+ } catch (CommandFailedException e) {
+ testRun.setResult(Result.COMPILE_FAILED, e.getOutputLines());
+ return;
+ } catch (IOException e) {
+ testRun.setResult(Result.ERROR, e);
+ return;
+ }
+ testRun.setTestCompiled(testCompiled);
+ environment.prepareUserDir(testRun);
+ }
+
+ /**
+ * Compiles the classes for the described test.
+ *
+ * @return the path to the compiled classes (directory or jar), or {@code
+ * null} if the test could not be compiled.
+ * @throws CommandFailedException if javac fails
+ */
+ private boolean compileTest(TestRun testRun) throws IOException {
+ if (!JAVA_TEST_PATTERN.matcher(testRun.getTestJava().toString()).find()) {
+ return false;
+ }
+
+ String qualifiedName = testRun.getQualifiedName();
+ File testClassesDir = environment.testClassesDir(testRun);
+ new Mkdir().mkdirs(testClassesDir);
+ FileOutputStream propertiesOut = new FileOutputStream(
+ new File(testClassesDir, TestProperties.FILE));
+ Properties properties = new Properties();
+ fillInProperties(properties, testRun);
+ properties.store(propertiesOut, "generated by " + Mode.class.getName());
+ propertiesOut.close();
+
+ Classpath classpath = new Classpath();
+ classpath.addAll(testClasspath);
+ classpath.addAll(testRun.getRunnerClasspath());
+
+ Set<File> sourceFiles = new HashSet<File>();
+ sourceFiles.add(testRun.getTestJava());
+ sourceFiles.addAll(dalvikAnnotationSourceFiles());
+
+ // compile the test case
+ new Javac()
+ .bootClasspath(sdkJar)
+ .classpath(classpath)
+ .sourcepath(testRun.getTestDirectory())
+ .destination(testClassesDir)
+ .compile(sourceFiles);
+ postCompileTest(testRun);
+ return true;
+ }
+
+ /**
+ * Hook method called after test compilation.
+ *
+ * @param testRun The test being compiled
+ */
+ abstract protected void postCompileTest(TestRun testRun);
+
+
+ /**
+ * Fill in properties for running in this mode
+ */
+ protected void fillInProperties(Properties properties, TestRun testRun) {
+ properties.setProperty(TestProperties.TEST_CLASS, testRun.getTestClass());
+ properties.setProperty(TestProperties.QUALIFIED_NAME, testRun.getQualifiedName());
+ properties.setProperty(TestProperties.RUNNER_CLASS, testRun.getRunnerClass().getName());
+ }
+
+ /**
+ * Runs the test, and updates its test result.
+ */
+ void runTest(TestRun testRun) {
+ if (!testRun.isRunnable()) {
+ throw new IllegalArgumentException();
+ }
+
+ final List<Command> commands = buildCommands(testRun);
+
+ List<String> output = null;
+ for (final Command command : commands) {
+ try {
+ output = command.executeWithTimeout(timeoutSeconds);
+ } catch (TimeoutException e) {
+ testRun.setResult(Result.EXEC_TIMEOUT,
+ Collections.singletonList("Exceeded timeout! (" + timeoutSeconds + "s)"));
+ return;
+ } catch (Exception e) {
+ testRun.setResult(Result.ERROR, e);
+ return;
+ }
+ }
+ // we only look at the output of the last command
+ if (output.isEmpty()) {
+ testRun.setResult(Result.ERROR,
+ Collections.singletonList("No output returned!"));
+ return;
+ }
+
+ Result result = TestProperties.RESULT_SUCCESS.equals(output.get(output.size() - 1))
+ ? Result.SUCCESS
+ : Result.EXEC_FAILED;
+ testRun.setResult(result, output.subList(0, output.size() - 1));
+ }
+
+ /**
+ * Returns commands for test execution.
+ */
+ protected abstract List<Command> buildCommands(TestRun testRun);
+
+ /**
+ * Deletes files and releases any resources required for the execution of
+ * the given test.
+ */
+ void cleanup(TestRun testRun) {
+ environment.cleanup(testRun);
+ }
+
+ /**
+ * Cleans up after all test runs have completed.
+ */
+ void shutdown() {
+ environment.shutdown();
+ }
+}
diff --git a/tools/runner/java/dalvik/runner/NamingPatternCodeFinder.java b/tools/runner/java/dalvik/runner/NamingPatternCodeFinder.java
index d0b6459..19c9df2 100644
--- a/tools/runner/java/dalvik/runner/NamingPatternCodeFinder.java
+++ b/tools/runner/java/dalvik/runner/NamingPatternCodeFinder.java
@@ -32,7 +32,7 @@ abstract class NamingPatternCodeFinder implements CodeFinder {
private final String PACKAGE_PATTERN = "(?m)^\\s*package\\s+(\\S+)\\s*;";
private final String TYPE_DECLARATION_PATTERN
- = "(?m)\\b(?:public|private)\\s+(?:interface|class|enum)\\b";
+ = "(?m)\\b(?:public|private)\\s+(?:final\\s+)?(?:interface|class|enum)\\b";
public Set<TestRun> findTests(File testDirectory) {
Set<TestRun> result = new LinkedHashSet<TestRun>();
@@ -49,8 +49,6 @@ abstract class NamingPatternCodeFinder implements CodeFinder {
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()) {
@@ -68,7 +66,8 @@ abstract class NamingPatternCodeFinder implements CodeFinder {
String testName = testName(file);
String testDescription = null;
sink.add(new TestRun(testDirectory, file, className, className,
- testName, className, testDescription, runnerClass()));
+ testName, className, testDescription,
+ getRunnerClass(), getRunnerJava(), getRunnerClasspath()));
}
/**
@@ -100,7 +99,7 @@ abstract class NamingPatternCodeFinder implements CodeFinder {
if (Pattern.compile(TYPE_DECLARATION_PATTERN).matcher(content).find()) {
return className;
}
- throw new IllegalArgumentException("Not a .java file: '" + file + "'\n"+content);
+ throw new IllegalArgumentException("Not a .java file: '" + file + "'\n" + content);
}
String packageName = packageMatcher.group(1);
return packageName + "." + className;
diff --git a/tools/runner/java/dalvik/runner/OptionParser.java b/tools/runner/java/dalvik/runner/OptionParser.java
index 64af51c..3516264 100644
--- a/tools/runner/java/dalvik/runner/OptionParser.java
+++ b/tools/runner/java/dalvik/runner/OptionParser.java
@@ -288,6 +288,7 @@ public class OptionParser {
}
}
+ @SuppressWarnings("unchecked")
private static void setValue(Object object, Field field, String arg, Handler handler, String valueText) {
Object value = handler.translate(valueText);
@@ -298,7 +299,7 @@ public class OptionParser {
try {
field.setAccessible(true);
if (Collection.class.isAssignableFrom(field.getType())) {
- Collection collection = (Collection)field.get(object);
+ Collection collection = (Collection) field.get(object);
collection.add(value);
} else {
field.set(object, value);
diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/util/NullBenchmarkSuite.java b/tools/runner/java/dalvik/runner/Rm.java
index 52f383c..1fc11d9 100644
--- a/luni/src/test/java/org/apache/harmony/luni/tests/java/util/NullBenchmarkSuite.java
+++ b/tools/runner/java/dalvik/runner/Rm.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010 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.
@@ -14,20 +14,28 @@
* limitations under the License.
*/
-package org.apache.harmony.luni.tests.java.util;
+package dalvik.runner;
-import com.google.caliper.Benchmark;
-import com.google.caliper.SimpleBenchmark;
+import java.io.File;
/**
- * This class exists only to force a dependency from our libraries on Caliper,
- * our micro benchmarking framework.
+ * A rm command.
*/
-public class NullBenchmarkSuite extends SimpleBenchmark {
+final class Rm {
- public void timeNullBenchmark(int trials) throws Exception {
- for (int i = 0; i < trials; i++) {
- // code under test goes here!
- }
+ public void file(File file) {
+ new Command.Builder()
+ .args("rm")
+ .args("-f")
+ .args(file)
+ .execute();
+ }
+
+ public void directoryTree(File directory) {
+ new Command.Builder()
+ .args("rm")
+ .args("-rf")
+ .args(directory)
+ .execute();
}
}
diff --git a/tools/runner/java/dalvik/runner/Runner.java b/tools/runner/java/dalvik/runner/Runner.java
new file mode 100644
index 0000000..7d7b0ee
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/Runner.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+/**
+ * Interface between the generic TestRunner and the more specific
+ * backend implementations that know about specific types of tests.
+ */
+public interface Runner {
+
+ public void prepareTest(Class<?> testClass);
+
+ public boolean test(Class<?> testClass);
+}
diff --git a/tools/runner/java/dalvik/runner/TestProperties.java b/tools/runner/java/dalvik/runner/TestProperties.java
new file mode 100644
index 0000000..1e90799
--- /dev/null
+++ b/tools/runner/java/dalvik/runner/TestProperties.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+/**
+ * TestProperties is a common class of constants shared between the
+ * DalvikRunner on the host and TestRunner classes potentially running
+ * on other devices.
+ */
+final public class TestProperties {
+
+ /**
+ * The name of the test properties file within the {@code .jar} file.
+ */
+ public static final String FILE = "test.properties";
+
+ /**
+ * Name of the property giving the test's main class name. This class should
+ * have a {@code public static void main(String[] args)} method.
+ */
+ public static final String TEST_CLASS = "testClass";
+
+ /**
+ * Name of the property giving the test's name, such as {@code
+ * java.math.BigDecimal.PowTests}.
+ */
+ public static final String QUALIFIED_NAME = "qualifiedName";
+
+ /**
+ * Name of the property used by TestRunner to determine which
+ * class to use as the Runner name. This class should implement
+ * Runner.
+ */
+ public static final String RUNNER_CLASS = "runnerClass";
+
+ /**
+ * Name of the property used by TestActivity to the test directory.
+ */
+ public static final String DEVICE_RUNNER_DIR = "deviceRunnerDir";
+
+
+ /**
+ * The output file written by TestActivity
+ */
+ public static final String RESULT_FILE = "result.txt";
+
+ /**
+ * Result value for successful test
+ */
+ public static final String RESULT_SUCCESS = "SUCCESS";
+
+ /**
+ * Result value for failed test
+ */
+ public static final String RESULT_FAILURE = "FAILURE";
+
+ public static String result(boolean success) {
+ return success ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+ /**
+ * This class should not be instantiated
+ */
+ private TestProperties() {}
+}
diff --git a/tools/runner/java/dalvik/runner/TestRun.java b/tools/runner/java/dalvik/runner/TestRun.java
index 3e85d92..c610b25 100644
--- a/tools/runner/java/dalvik/runner/TestRun.java
+++ b/tools/runner/java/dalvik/runner/TestRun.java
@@ -35,33 +35,38 @@ import java.util.List;
public final class TestRun {
private final File testDirectory;
- private final File javaFile;
+ private final File testJava;
private final String testClass;
- private final Class<? extends TestRunner> testRunner;
+ private final Class<? extends Runner> runnerClass;
+ private final File runnerJava;
+ private final Classpath runnerClasspath;
private final String suiteName;
private final String testName;
private final String qualifiedName;
private final String description;
- private Classpath testClasspath;
+ private boolean testCompiled;
private File userDir = new File(System.getProperty("user.dir"));
private ExpectedResult expectedResult = ExpectedResult.SUCCESS;
private Result result;
private List<String> outputLines;
- public TestRun(File testDirectory, File javaFile, String testClass,
+ public TestRun(File testDirectory, File testJava, String testClass,
String suiteName, String testName, String qualifiedName,
- String description, Class<? extends TestRunner> testRunner) {
+ String description, Class<? extends Runner> runnerClass,
+ File runnerJava, Classpath runnerClasspath) {
this.qualifiedName = qualifiedName;
this.suiteName = suiteName;
this.testName = testName;
this.testDirectory = testDirectory;
- this.javaFile = javaFile;
+ this.testJava = testJava;
this.description = description;
this.testClass = testClass;
- this.testRunner = testRunner;
+ this.runnerClass = runnerClass;
+ this.runnerJava = runnerJava;
+ this.runnerClasspath = runnerClasspath;
}
/**
@@ -71,8 +76,8 @@ public final class TestRun {
return testDirectory;
}
- public File getJavaFile() {
- return javaFile;
+ public File getTestJava() {
+ return testJava;
}
/**
@@ -118,15 +123,14 @@ public final class TestRun {
}
/**
- * Initializes the path to the jar file or directory containing test
- * classes.
+ * Set when the test is successfully compiled.
*/
- public void setTestClasspath(Classpath classpath) {
- this.testClasspath = classpath;
+ public void setTestCompiled(boolean testCompiled) {
+ this.testCompiled = testCompiled;
}
- public Classpath getTestClasspath() {
- return testClasspath;
+ public boolean getTestCompiled() {
+ return testCompiled;
}
/**
@@ -145,7 +149,7 @@ public final class TestRun {
* classpath prepared and have not yet been assigned a result.
*/
public boolean isRunnable() {
- return testClasspath != null && result == null;
+ return testCompiled && result == null;
}
public void setResult(Result result, Throwable e) {
@@ -154,7 +158,7 @@ public final class TestRun {
public void setResult(Result result, List<String> outputLines) {
if (this.result != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("result already set");
}
this.result = result;
@@ -176,8 +180,16 @@ public final class TestRun {
return outputLines;
}
- public Class<? extends TestRunner> getTestRunner() {
- return testRunner;
+ public Class<? extends Runner> getRunnerClass() {
+ return runnerClass;
+ }
+
+ public File getRunnerJava() {
+ return runnerJava;
+ }
+
+ public Classpath getRunnerClasspath() {
+ return runnerClasspath;
}
/**
diff --git a/tools/runner/java/dalvik/runner/TestRunner.java b/tools/runner/java/dalvik/runner/TestRunner.java
index af811d0..a706d40 100644
--- a/tools/runner/java/dalvik/runner/TestRunner.java
+++ b/tools/runner/java/dalvik/runner/TestRunner.java
@@ -23,57 +23,68 @@ import java.util.Properties;
/**
* Runs a test.
*/
-public abstract class TestRunner {
+public class TestRunner {
- /**
- * The name of the test properties file within the {@code .jar} file.
- */
- static final String TEST_PROPERTIES_FILE = "test.properties";
+ protected final Properties properties;
- /**
- * Property identifier for the test's main class name. This class should
- * have a {@code public static void main(String[] args)} method.
- */
- static final String CLASS_NAME = "className";
+ protected final String qualifiedName;
+ protected final Class<?> testClass;
+ protected final Class<?> runnerClass;
- /**
- * Property identifier for the test's name, such as {@code
- * java.math.BigDecimal.PowTests}.
- */
- static final String QUALIFIED_NAME = "qualifiedName";
-
- protected String className;
- protected String qualifiedName;
+ protected TestRunner () {
+ properties = loadProperties();
+ qualifiedName = properties.getProperty(TestProperties.QUALIFIED_NAME);
+ testClass = classProperty(TestProperties.TEST_CLASS, Object.class);
+ runnerClass = classProperty(TestProperties.RUNNER_CLASS, Runner.class);
+ }
- protected Properties loadProperties() {
+ protected static Properties loadProperties() {
Properties properties = new Properties();
try {
InputStream propertiesStream = TestRunner.class.getResourceAsStream(
- "/" + TEST_PROPERTIES_FILE);
+ "/" + TestProperties.FILE);
if (propertiesStream == null) {
- throw new RuntimeException(TEST_PROPERTIES_FILE + " missing!");
+ throw new RuntimeException(TestProperties.FILE + " missing!");
}
-
properties.load(propertiesStream);
+ return properties;
} catch (IOException e) {
throw new RuntimeException(e);
}
-
- className = properties.getProperty(CLASS_NAME);
- qualifiedName = properties.getProperty(QUALIFIED_NAME);
- return properties;
}
- public void prepareTest() {}
-
- public abstract boolean test();
+ private Class<?> classProperty(String propertyName, Class<?> superClass) {
+ String className = properties.getProperty(propertyName);
+ if (className == null) {
+ throw new IllegalArgumentException("Could not find property for " +
+ propertyName);
+ }
+ try {
+ Class<?> klass = Class.forName(className);
+ if (!superClass.isAssignableFrom(klass)) {
+ throw new IllegalArgumentException(
+ className + " can not be assigned to " + Runner.class);
+ }
+ return klass;
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
- public void run() {
- loadProperties();
- prepareTest();
+ public boolean run() {
+ Runner runner;
+ try {
+ runner = (Runner) runnerClass.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ runner.prepareTest(testClass);
+ return runner.test(testClass);
+ }
- System.out.println("Executing " + qualifiedName);
- boolean success = test();
- System.out.println(success ? "SUCCESS" : "FAILURE");
+ public static void main(String[] args) {
+ System.out.println(TestProperties.result(new TestRunner().run()));
}
}
diff --git a/tools/runner/java/dalvik/runner/Vm.java b/tools/runner/java/dalvik/runner/Vm.java
index 3afd7ae..9f96ec5 100644
--- a/tools/runner/java/dalvik/runner/Vm.java
+++ b/tools/runner/java/dalvik/runner/Vm.java
@@ -27,249 +27,34 @@ import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
-import java.util.regex.Pattern;
/**
* A Java-like virtual machine for compiling and running tests.
*/
-public abstract class Vm {
-
- static final String DALVIK_RUNNER_HOME = "dalvik/libcore/tools/runner";
-
- static final Set<File> TEST_RUNNER_JAVA_FILES = new HashSet<File>(Arrays.asList(
- new File(DALVIK_RUNNER_HOME + "/java/dalvik/runner/CaliperRunner.java"),
- new File(DALVIK_RUNNER_HOME + "/java/dalvik/runner/JUnitRunner.java"),
- new File(DALVIK_RUNNER_HOME + "/java/dalvik/runner/JtregRunner.java"),
- new File(DALVIK_RUNNER_HOME + "/java/dalvik/runner/MainRunner.java"),
- new File(DALVIK_RUNNER_HOME + "/java/dalvik/runner/TestRunner.java")));
-
- 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").getAbsoluteFile(),
- new File("out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jar").getAbsoluteFile(),
- new File("out/target/common/obj/JAVA_LIBRARIES/jsr305_intermediates/classes.jar").getAbsoluteFile(),
- new File("out/target/common/obj/JAVA_LIBRARIES/guava_intermediates/classes.jar").getAbsoluteFile(),
- new File("out/target/common/obj/JAVA_LIBRARIES/caliper_intermediates/classes.jar").getAbsoluteFile());
+public abstract class Vm extends Mode {
private static final Logger logger = Logger.getLogger(Vm.class.getName());
- protected final ExecutorService outputReaders
- = Executors.newFixedThreadPool(1, Threads.daemonThreadFactory());
-
- protected final Integer debugPort;
protected final List<String> additionalVmArgs;
- protected final long timeoutSeconds;
- protected final File sdkJar;
- protected final File localTemp;
- protected final boolean clean;
-
- /** The path of the test runner's compiled classes */
- private Classpath testRunnerClasses;
- Vm(Integer debugPort, long timeoutSeconds, File sdkJar, File localTemp,
- List<String> additionalVmArgs, boolean clean) {
- this.debugPort = debugPort;
- this.timeoutSeconds = timeoutSeconds;
- this.sdkJar = sdkJar;
- this.localTemp = localTemp;
+ Vm(Environment environment, long timeoutSeconds, File sdkJar,
+ List<String> additionalVmArgs) {
+ super(environment, timeoutSeconds, sdkJar);
this.additionalVmArgs = additionalVmArgs;
- this.clean = clean;
- }
-
- /**
- * Initializes the temporary directories and test harness necessary to run
- * tests.
- */
- public void prepare() {
- testRunnerClasses = compileTestRunner();
- }
-
- private Classpath compileTestRunner() {
- logger.fine("build testrunner");
-
- File base = new File(localTemp, "testrunner");
- base.mkdirs();
- new Javac()
- .classpath(COMPILATION_CLASSPATH)
- .destination(base)
- .compile(TEST_RUNNER_JAVA_FILES);
-
- return postCompile("testrunner", Classpath.of(base));
}
/**
- * Cleans up after all test runs have completed.
- */
- public void shutdown() {
- outputReaders.shutdown();
- }
-
- /**
- * Compiles classes for the given test and makes them ready for execution.
- * If the test could not be compiled successfully, it will be updated with
- * the appropriate test result.
- */
- public void buildAndInstall(TestRun testRun) {
- logger.fine("build " + testRun.getQualifiedName());
-
- Classpath testClasses;
- try {
- testClasses = compileTest(testRun);
- if (testClasses == null) {
- testRun.setResult(Result.UNSUPPORTED, Collections.<String>emptyList());
- return;
- }
- } catch (CommandFailedException e) {
- testRun.setResult(Result.COMPILE_FAILED, e.getOutputLines());
- return;
- } catch (IOException e) {
- testRun.setResult(Result.ERROR, e);
- return;
- }
- testRun.setTestClasspath(testClasses);
- prepareUserDir(testRun);
- }
-
- /**
- * Prepares the directory from which the test will be executed. Some tests
- * expect to read data files from the current working directory; this step
- * should ensure such files are available.
- */
- protected void prepareUserDir(TestRun testRun) {
- File testUserDir = testUserDir(testRun);
-
- // if the user dir exists, cp would copy the files to the wrong place
- if (testUserDir.exists()) {
- throw new IllegalStateException();
- }
-
- testUserDir.getParentFile().mkdirs();
- new Command("cp", "-r", testRun.getTestDirectory().toString(),
- testUserDir.toString()).execute();
- testRun.setUserDir(testUserDir);
- }
-
- /**
- * Deletes files and releases any resources required for the execution of
- * the given test.
- */
- public void cleanup(TestRun testRun) {
- if (clean) {
- logger.fine("clean " + testRun.getQualifiedName());
-
- new Command.Builder().args("rm", "-rf", testClassesDir(testRun).getPath())
- .execute();
- new Command.Builder().args("rm", "-rf", testUserDir(testRun).getPath())
- .execute();
- }
- }
-
- /**
- * Compiles the classes for the described test.
- *
- * @return the path to the compiled classes (directory or jar), or {@code
- * null} if the test could not be compiled.
- * @throws CommandFailedException if javac fails
- */
- private Classpath compileTest(TestRun testRun) throws IOException {
- if (!JAVA_TEST_PATTERN.matcher(testRun.getJavaFile().toString()).find()) {
- return null;
- }
-
- String qualifiedName = testRun.getQualifiedName();
- File testClassesDir = testClassesDir(testRun);
- testClassesDir.mkdirs();
-
- FileOutputStream propertiesOut = new FileOutputStream(
- new File(testClassesDir, TestRunner.TEST_PROPERTIES_FILE));
- toProperties(testRun).store(propertiesOut, "generated by " + getClass().getName());
- propertiesOut.close();
-
- // write a test descriptor
- new Javac()
- .bootClasspath(sdkJar)
- .classpath(COMPILATION_CLASSPATH)
- .sourcepath(testRun.getTestDirectory())
- .destination(testClassesDir)
- .compile(testRun.getJavaFile());
- return postCompile(qualifiedName, Classpath.of(testClassesDir));
- }
-
- private File testClassesDir(TestRun testRun) {
- return new File(localTemp, testRun.getQualifiedName());
- }
-
- private File testUserDir(TestRun testRun) {
- File testTemp = new File(localTemp, "userDir");
- return new File(testTemp, testRun.getQualifiedName());
- }
-
- /**
- * Returns a properties object for the given test description.
- */
- static Properties toProperties(TestRun testRun) {
- Properties result = new Properties();
- result.setProperty(TestRunner.CLASS_NAME, testRun.getTestClass());
- result.setProperty(TestRunner.QUALIFIED_NAME, testRun.getQualifiedName());
- return result;
- }
-
- /**
- * Runs the test, and updates its test result.
+ * Returns a VM for test execution.
*/
- public void runTest(TestRun testRun) {
- if (!testRun.isRunnable()) {
- throw new IllegalArgumentException();
- }
-
- final Command command = newVmCommandBuilder(testRun.getUserDir())
- .classpath(testRun.getTestClasspath())
- .classpath(testRunnerClasses)
- .classpath(getRuntimeSupportClasspath())
+ @Override protected List<Command> buildCommands(TestRun testRun) {
+ return Collections.singletonList(newVmCommandBuilder(testRun.getUserDir())
+ .classpath(getRuntimeSupportClasspath(testRun))
.userDir(testRun.getUserDir())
- .debugPort(debugPort)
+ .debugPort(environment.debugPort)
.vmArgs(additionalVmArgs)
- .mainClass(testRun.getTestRunner().getName())
- .build();
-
- logger.fine("executing " + command.getArgs());
-
- try {
- command.start();
-
- // run on a different thread to allow a timeout
- List<String> output = outputReaders.submit(new Callable<List<String>>() {
- public List<String> call() throws Exception {
- return command.gatherOutput();
- }
- }).get(timeoutSeconds, TimeUnit.SECONDS);
-
- if (output.isEmpty()) {
- testRun.setResult(Result.ERROR,
- Collections.singletonList("No output returned!"));
- return;
- }
-
- Result result = "SUCCESS".equals(output.get(output.size() - 1))
- ? Result.SUCCESS
- : Result.EXEC_FAILED;
- testRun.setResult(result, output.subList(0, output.size() - 1));
- } catch (TimeoutException e) {
- testRun.setResult(Result.EXEC_TIMEOUT,
- Collections.singletonList("Exceeded timeout! (" + timeoutSeconds + "s)"));
- } catch (Exception e) {
- testRun.setResult(Result.ERROR, e);
- } finally {
- if (command.isStarted()) {
- command.getProcess().destroy(); // to release the output reader
- }
- }
+ .mainClass(TestRunner.class.getName())
+ .build());
}
/**
@@ -281,23 +66,7 @@ public abstract class Vm {
* Returns the classpath containing JUnit and the dalvik annotations
* required for test execution.
*/
- protected Classpath getRuntimeSupportClasspath() {
- return COMPILATION_CLASSPATH;
- }
-
- /**
- * Hook method called after each compilation.
- *
- * @param name the name of this compilation unit. Usually a qualified test
- * name like java.lang.Math.PowTests.
- * @param targetClasses the full set of classes that make up this target.
- * This will include the newly compiled classes, plus optional other
- * classes that complete the target (such as library jars).
- * @return the new result file.
- */
- protected Classpath postCompile(String name, Classpath targetClasses) {
- return targetClasses;
- }
+ protected abstract Classpath getRuntimeSupportClasspath(TestRun testRun);
/**
* Builds a virtual machine command.
diff --git a/tools/runner/lib/TestActivity.java b/tools/runner/lib/TestActivity.java
new file mode 100644
index 0000000..15206f8
--- /dev/null
+++ b/tools/runner/lib/TestActivity.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.TextView;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Runs a user-supplied {@code main(String[] args)} method
+ * in the context of an Android activity. The result of the method
+ * (success or exception) is reported to a file where Dalvik
+ * Runner can pick it up.
+ */
+public class TestActivity extends Activity {
+
+ private final static String TAG = "TestActivity";
+
+ private TextView view;
+
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ this.view = new TextView(this);
+ log("TestActivity starting...");
+ setContentView(view);
+ ActivityRunner activityRunner = new ActivityRunner();
+ activityRunner.run();
+ }
+
+ private void log(String message, Throwable ex) {
+ log(message + "\n" + Log.getStackTraceString(ex));
+ }
+ private void log(String message) {
+ Log.i(TAG, message);
+ view.append(message + "\n");
+ }
+
+ class ActivityRunner extends TestRunner {
+
+ private final File runnerDir;
+ private final Thread shutdownHook = new Thread(new ShutdownHook());
+
+ ActivityRunner() {
+ runnerDir = new File(properties.getProperty(TestProperties.DEVICE_RUNNER_DIR));
+ }
+
+ @Override public boolean run() {
+ log("Using " + runnerClass + " to run " + qualifiedName);
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+ boolean success = super.run();
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ writeResultFile(success);
+ return success;
+ }
+
+ private void writeResultFile (boolean success) {
+ String result = TestProperties.result(success);
+ File resultDir = new File(runnerDir, qualifiedName);
+ File resultTemp = new File(resultDir, TestProperties.RESULT_FILE + ".temp");
+ File resultFile = new File(resultDir, TestProperties.RESULT_FILE);
+ log("TestActivity " + result + " " + resultFile);
+ try {
+ FileOutputStream resultOut = new FileOutputStream(resultTemp);
+ resultOut.write(result.getBytes("UTF-8"));
+ resultOut.close();
+ // atomically rename since DalvikRunner will be polling for this
+ resultTemp.renameTo(resultFile);
+ } catch (IOException e) {
+ log("TestActivity could not create result file", e);
+ }
+ }
+
+ /**
+ * Used to trap tests that try to exit on the their own. We
+ * treat this as a failure since they usually are calling
+ * System.exit with a non-zero value.
+ */
+ class ShutdownHook implements Runnable {
+ public void run() {
+ writeResultFile(false);
+ }
+ }
+ }
+}
diff --git a/tools/runner/lib/caliper.jar b/tools/runner/lib/caliper.jar
new file mode 100644
index 0000000..63a156a
--- /dev/null
+++ b/tools/runner/lib/caliper.jar
Binary files differ
diff --git a/tools/runner/lib/caliper.jar.txt b/tools/runner/lib/caliper.jar.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/tools/runner/lib/caliper.jar.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/tools/runner/lib/guava.jar b/tools/runner/lib/guava.jar
new file mode 100644
index 0000000..39adc7f
--- /dev/null
+++ b/tools/runner/lib/guava.jar
Binary files differ
diff --git a/tools/runner/lib/guava.jar.txt b/tools/runner/lib/guava.jar.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/tools/runner/lib/guava.jar.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/tools/runner/lib/jsr305.jar b/tools/runner/lib/jsr305.jar
new file mode 100644
index 0000000..57a62c1
--- /dev/null
+++ b/tools/runner/lib/jsr305.jar
Binary files differ
diff --git a/tools/runner/lib/jsr305.jar.txt b/tools/runner/lib/jsr305.jar.txt
new file mode 100644
index 0000000..6736681
--- /dev/null
+++ b/tools/runner/lib/jsr305.jar.txt
@@ -0,0 +1,28 @@
+Copyright (c) 2007-2009, JSR305 expert group
+All rights reserved.
+
+http://www.opensource.org/licenses/bsd-license.php
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the JSR305 expert group nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/runner/test-dalvik-runner.sh b/tools/runner/test-dalvik-runner.sh
new file mode 100755
index 0000000..1b9c35d
--- /dev/null
+++ b/tools/runner/test-dalvik-runner.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 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.
+#
+
+# Test Dalvik Runner by exercising the various modes and various types of tests
+#
+# You can run this as follows
+
+# $ANDROID_BUILD_TOP/dalvik/libcore/tools/runner/test-dalvik-runner.sh
+
+modes="host device activity"
+
+# TODO: include dummy examples of each kind of 'runnable' we support,
+# for test purposes instead of relying on external paths.
+test_jtreg=/home/dalvik-prebuild/openjdk-6/jdk/test/java/util/HashMap/
+test_junit=dalvik/libcore/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/FilterTest.java
+test_caliper=/home/bdc/benchmarks/caliper/caliper-read-only/src/examples/ArraySortBenchmark.java
+test_main=external/junit/src/junit/textui/TestRunner.java
+tests="$test_jtreg $test_junit $test_caliper $test_main"
+
+cd $ANDROID_BUILD_TOP
+. ./build/envsetup.sh
+m core-tests junit caliper snod && adb reboot bootloader && fastboot flashall && adb wait-for-device
+# when the device first comes up /sdcard is not mounted
+while [ -z "`adb shell ls /sdcard | tr -d '\r\n'`" ] ; do sleep 1; done
+mmm dalvik/libcore/tools/runner
+
+#verbose=--verbose
+#clean=--no-clean-after
+extras="$verbose $clean"
+
+dalvik_runner="java -cp out/host/linux-x86/framework/dalvik_runner.jar dalvik.runner.DalvikRunner"
+
+for mode in $modes; do
+ for test in $tests; do
+ command="$dalvik_runner --mode $mode $extras $test"
+ echo RUNNING $command
+ $command
+ done
+done
diff --git a/tools/runner/vogar b/tools/runner/vogar
new file mode 100755
index 0000000..e5a6ad0
--- /dev/null
+++ b/tools/runner/vogar
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 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.
+
+# m core-tests junit caliper snod && adb reboot bootloader && fastboot flashall && adb wait-for-device
+# mmm dalvik/libcore/tools/runner
+
+classpath=`dirname $0`/../../../../out/host/linux-x86/framework/dalvik_runner.jar
+exec java -cp $classpath dalvik.runner.DalvikRunner "$@"
diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index d287bbd..8006757 100644
--- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -68,6 +68,9 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
private ArrayList<HandshakeCompletedListener> listeners;
private long ssl_op_no = 0x00000000L;
private int timeout = 0;
+ // BEGIN android-added
+ private int handshakeTimeout = -1; // -1 = same as timeout; 0 = infinite
+ // END android-added
private InetSocketAddress address;
private static final String[] supportedProtocols = new String[] {
@@ -298,6 +301,14 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
if (session == null && !sslParameters.getEnableSessionCreation()) {
throw new SSLHandshakeException("SSL Session may not be created");
} else {
+ // BEGIN android-added
+ // Temporarily use a different timeout for the handshake process
+ int savedTimeout = timeout;
+ if (handshakeTimeout >= 0) {
+ setSoTimeout(handshakeTimeout);
+ }
+ // END android-added
+
Socket socket = this.socket != null ? this.socket : this;
int sessionId = session != null ? session.session : 0;
boolean reusedSession;
@@ -360,6 +371,13 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
throw new SSLException("Not trusted server certificate", e);
}
}
+
+ // BEGIN android-added
+ // Restore the original timeout now that the handshake is complete
+ if (handshakeTimeout >= 0) {
+ setSoTimeout(savedTimeout);
+ }
+ // END android-added
}
if (listeners != null) {
@@ -882,6 +900,18 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
this.timeout = timeout;
}
+ // BEGIN android-added
+ /**
+ * Set the handshake timeout on this socket. This timeout is specified in
+ * milliseconds and will be used only during the handshake process.
+ *
+ * @param timeout the handshake timeout value
+ */
+ public synchronized void setHandshakeTimeout(int timeout) throws SocketException {
+ this.handshakeTimeout = timeout;
+ }
+ // END android-added
+
private native void nativeinterrupt() throws IOException;
private native void nativeclose() throws IOException;
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
index 9c19835..4e689fb 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
@@ -73,7 +73,7 @@ public class AttrImpl extends NodeImpl implements Attr {
throw new DOMException(DOMException.NAMESPACE_ERR, localName);
}
- if (!document.isXMLIdentifier(localName)) {
+ if (!DocumentImpl.isXMLIdentifier(localName)) {
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, localName);
}
@@ -90,11 +90,11 @@ public class AttrImpl extends NodeImpl implements Attr {
String prefix = name.substring(0, prefixSeparator);
String localName = name.substring(prefixSeparator + 1);
- if (!document.isXMLIdentifier(prefix) || !document.isXMLIdentifier(localName)) {
+ if (!DocumentImpl.isXMLIdentifier(prefix) || !DocumentImpl.isXMLIdentifier(localName)) {
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
}
} else {
- if (!document.isXMLIdentifier(name)) {
+ if (!DocumentImpl.isXMLIdentifier(name)) {
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
}
}
@@ -108,7 +108,9 @@ public class AttrImpl extends NodeImpl implements Attr {
}
public String getName() {
- return (prefix != null ? prefix + ":" : "") + localName;
+ return prefix != null
+ ? prefix + ":" + localName
+ : localName;
}
@Override
@@ -148,27 +150,8 @@ public class AttrImpl extends NodeImpl implements Attr {
}
@Override
- public void setNodeValue(String value) throws DOMException {
- setValue(value);
- }
-
- @Override
public void setPrefix(String prefix) {
- if (!namespaceAware) {
- throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
- }
-
- if (prefix != null) {
- if (namespaceURI == null || !document.isXMLIdentifier(prefix) || "xmlns".equals(prefix)) {
- throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
- }
-
- if ("xml".equals(prefix) && !"http://www.w3.org/XML/1998/namespace".equals(namespaceURI)) {
- throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
- }
- }
-
- this.prefix = prefix;
+ this.prefix = validatePrefix(prefix, namespaceAware, namespaceURI);
}
public void setValue(String value) throws DOMException {
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
index 861f0a3..834cc47 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
@@ -50,17 +50,24 @@ public class DOMImplementationImpl implements DOMImplementation {
}
public boolean hasFeature(String feature, String version) {
- // We claim to support DOM Core Level 1 & 2, nothing else.
+ boolean anyVersion = version == null || version.length() == 0;
+ if (feature.startsWith("+")) {
+ feature = feature.substring(1);
+ }
- // TODO
+ // TODO: fully implement these APIs:
+ // "LS" (org.w3c.dom.ls) versions "3.0"
+ // "ElementTraversal" (org.w3c.dom.traversal) versions "1.0"
- if ("Core".equalsIgnoreCase(feature) || "XML".equalsIgnoreCase(feature)) {
- if (version == null || "".equals(version) || "1.0".equals(version) || "2.0".equals(version)) {
- return true;
- }
+ if (feature.equalsIgnoreCase("Core")) {
+ return anyVersion || version.equals("1.0") || version.equals("2.0") || version.equals("3.0");
+ } else if (feature.equalsIgnoreCase("XML")) {
+ return anyVersion || version.equals("1.0") || version.equals("2.0") || version.equals("3.0");
+ } else if (feature.equalsIgnoreCase("XMLVersion")) {
+ return anyVersion || version.equals("1.0") || version.equals("1.1");
+ } else {
+ return false;
}
-
- return false;
}
/**
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index 499f518..c8819cb 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -100,6 +100,8 @@ public class DocumentImpl extends InnerNodeImpl implements Document {
* @return The new node.
*/
Node cloneNode(Node node, boolean deep) throws DOMException {
+ // TODO: callback the UserDataHandler with a NODE_CLONED event
+
Node target;
switch (node.getNodeType()) {
@@ -279,6 +281,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document {
}
public Node importNode(Node importedNode, boolean deep) throws DOMException {
+ // TODO: callback the UserDataHandler with a NODE_IMPORTED event
return cloneNode(importedNode, deep);
}
@@ -296,6 +299,10 @@ public class DocumentImpl extends InnerNodeImpl implements Document {
return super.insertChildAt(newChild, index);
}
+ @Override public String getTextContent() throws DOMException {
+ return null;
+ }
+
public String getInputEncoding() {
throw new UnsupportedOperationException(); // TODO
}
@@ -337,6 +344,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document {
}
public Node adoptNode(Node source) throws DOMException {
+ // TODO: callback the UserDataHandler with a NODE_ADOPTED event
throw new UnsupportedOperationException(); // TODO
}
@@ -350,6 +358,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document {
public Node renameNode(Node n, String namespaceURI, String qualifiedName)
throws DOMException {
+ // TODO: callback the UserDataHandler with a NODE_RENAMED event
throw new UnsupportedOperationException(); // TODO
}
}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java
index df40d4b..67947b7 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java
@@ -107,4 +107,7 @@ public class DocumentTypeImpl extends LeafNodeImpl implements DocumentType {
return systemId;
}
+ @Override public String getTextContent() throws DOMException {
+ return null;
+ }
}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
index 230e444..df1383d 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
@@ -65,7 +65,7 @@ public class ElementImpl extends InnerNodeImpl implements Element {
qualifiedName = qualifiedName.substring(p + 1);
}
- if (!document.isXMLIdentifier(qualifiedName)) {
+ if (!DocumentImpl.isXMLIdentifier(qualifiedName)) {
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, qualifiedName);
}
@@ -82,11 +82,11 @@ public class ElementImpl extends InnerNodeImpl implements Element {
String prefix = name.substring(0, p);
String localName = name.substring(p + 1);
- if (!document.isXMLIdentifier(prefix) || !document.isXMLIdentifier(localName)) {
+ if (!DocumentImpl.isXMLIdentifier(prefix) || !DocumentImpl.isXMLIdentifier(localName)) {
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
}
} else {
- if (!document.isXMLIdentifier(name)) {
+ if (!DocumentImpl.isXMLIdentifier(name)) {
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
}
}
@@ -241,7 +241,9 @@ public class ElementImpl extends InnerNodeImpl implements Element {
}
public String getTagName() {
- return (prefix != null ? prefix + ":" : "") + localName;
+ return prefix != null
+ ? prefix + ":" + localName
+ : localName;
}
public boolean hasAttribute(String name) {
@@ -281,7 +283,7 @@ public class ElementImpl extends InnerNodeImpl implements Element {
throw new DOMException(DOMException.NOT_FOUND_ERR, null);
}
- attributes.remove(oldAttr);
+ attributes.remove(oldAttrImpl);
oldAttrImpl.ownerElement = null;
return oldAttrImpl;
@@ -362,21 +364,7 @@ public class ElementImpl extends InnerNodeImpl implements Element {
@Override
public void setPrefix(String prefix) {
- if (!namespaceAware) {
- throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
- }
-
- if (prefix != null) {
- if (namespaceURI == null || !document.isXMLIdentifier(prefix)) {
- throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
- }
-
- if ("xml".equals(prefix) && !"http://www.w3.org/XML/1998/namespace".equals(namespaceURI)) {
- throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
- }
- }
-
- this.prefix = prefix;
+ this.prefix = validatePrefix(prefix, namespaceAware, namespaceURI);
}
public class ElementAttrNamedNodeMapImpl implements NamedNodeMap {
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
index f8ed85e..275bbf3 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
@@ -28,14 +28,16 @@ import java.util.List;
* Provides a straightforward implementation of the corresponding W3C DOM
* interface. The class is used internally only, thus only notable members that
* are not in the original interface are documented (the W3C docs are quite
- * extensive). Hope that's ok.
- * <p>
- * Some of the fields may have package visibility, so other classes belonging to
- * the DOM implementation can easily access them while maintaining the DOM tree
- * structure.
- * <p>
- * This class represents a Node that has a parent Node as well as (potentially)
- * a number of children.
+ * extensive).
+ *
+ * <p>Some of the fields may have package visibility, so other classes belonging
+ * to the DOM implementation can easily access them while maintaining the DOM
+ * tree structure.
+ *
+ * <p>This class represents a Node that has a parent Node as well as
+ * (potentially) a number of children.
+ *
+ * <p>Some code was adapted from Apache Xerces.
*/
public abstract class InnerNodeImpl extends LeafNodeImpl {
@@ -218,4 +220,35 @@ public abstract class InnerNodeImpl extends LeafNodeImpl {
return oldChildImpl;
}
+ public String getTextContent() throws DOMException {
+ Node child = getFirstChild();
+ if (child == null) {
+ return "";
+ }
+
+ Node next = child.getNextSibling();
+ if (next == null) {
+ return hasTextContent(child) ? child.getTextContent() : "";
+ }
+
+ StringBuilder buf = new StringBuilder();
+ getTextContent(buf);
+ return buf.toString();
+ }
+
+ void getTextContent(StringBuilder buf) throws DOMException {
+ Node child = getFirstChild();
+ while (child != null) {
+ if (hasTextContent(child)) {
+ ((NodeImpl) child).getTextContent(buf);
+ }
+ child = child.getNextSibling();
+ }
+ }
+
+ final boolean hasTextContent(Node child) {
+ // TODO: skip text nodes with ignorable whitespace?
+ return child.getNodeType() != Node.COMMENT_NODE
+ && child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE;
+ }
}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
index bf4d791..ebfdd52 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
@@ -16,24 +16,30 @@
package org.apache.harmony.xml.dom;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CharacterData;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.UserDataHandler;
+import java.util.ArrayList;
+import java.util.List;
+
/**
- * Provides a straightforward implementation of the corresponding W3C DOM
- * interface. The class is used internally only, thus only notable members that
- * are not in the original interface are documented (the W3C docs are quite
- * extensive). Hope that's ok.
- * <p>
- * Some of the fields may have package visibility, so other classes belonging to
- * the DOM implementation can easily access them while maintaining the DOM tree
- * structure.
- * <p>
- * This class represents a Node that has neither a parent nor children.
+ * A straightforward implementation of the corresponding W3C DOM node.
+ *
+ * <p>Some fields have package visibility so other classes can access them while
+ * maintaining the DOM structure.
+ *
+ * <p>This class represents a Node that has neither a parent nor children.
+ * Subclasses may have either.
+ *
+ * <p>Some code was adapted from Apache Xerces.
*/
public abstract class NodeImpl implements Node {
@@ -135,13 +141,64 @@ public abstract class NodeImpl implements Node {
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
}
- public void setNodeValue(String nodeValue) throws DOMException {
+ public final void setNodeValue(String nodeValue) throws DOMException {
+ switch (getNodeType()) {
+ case CDATA_SECTION_NODE:
+ case COMMENT_NODE:
+ case TEXT_NODE:
+ ((CharacterData) this).setData(nodeValue);
+ return;
+
+ case PROCESSING_INSTRUCTION_NODE:
+ ((ProcessingInstruction) this).setData(nodeValue);
+ return;
+
+ case ATTRIBUTE_NODE:
+ ((Attr) this).setValue(nodeValue);
+ return;
+
+ case ELEMENT_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case ENTITY_NODE:
+ case DOCUMENT_NODE:
+ case DOCUMENT_TYPE_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case NOTATION_NODE:
+ return; // do nothing!
+
+ default:
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+ "Unsupported node type " + getNodeType());
+ }
}
public void setPrefix(String prefix) throws DOMException {
}
/**
+ * Validates the element or attribute namespace prefix on this node.
+ *
+ * @param namespaceAware whether this node is namespace aware
+ * @param namespaceURI this node's namespace URI
+ */
+ protected String validatePrefix(String prefix, boolean namespaceAware, String namespaceURI) {
+ if (!namespaceAware) {
+ throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+ }
+
+ if (prefix != null) {
+ if (namespaceURI == null
+ || !DocumentImpl.isXMLIdentifier(prefix)
+ || "xml".equals(prefix) && !"http://www.w3.org/XML/1998/namespace".equals(namespaceURI)
+ || "xmlns".equals(prefix) && !"http://www.w3.org/2000/xmlns/".equals(namespaceURI)) {
+ throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+ }
+ }
+
+ return prefix;
+ }
+
+ /**
* Checks whether a required string matches an actual string. This utility
* method is used for comparing namespaces and such. It takes into account
* null arguments and the "*" special case.
@@ -190,7 +247,34 @@ public abstract class NodeImpl implements Node {
}
public String getBaseURI() {
- throw new UnsupportedOperationException(); // TODO
+ /*
+ * TODO: implement. For reference, here's Xerces' behaviour:
+ *
+ * In all cases, the returned URI should be sanitized before it is
+ * returned. If the URI is malformed, null should be returned instead.
+ *
+ * For document nodes, this should return a member field that's
+ * initialized by the parser.
+ *
+ * For element nodes, this should first look for the xml:base attribute.
+ * if that exists and is absolute, it should be returned.
+ * if that exists and is relative, it should be resolved to the parent's base URI
+ * if it doesn't exist, the parent's baseURI should be returned
+ *
+ * For entity nodes, if a base URI exists that should be returned.
+ * Otherwise the document's base URI should be returned
+ *
+ * For entity references, if a base URI exists that should be returned
+ * otherwise it dereferences the entity (via the document) and uses the
+ * entity's base URI.
+ *
+ * For notations, it returns the base URI field.
+ *
+ * For processing instructions, it returns the parent's base URI.
+ *
+ * For all other node types, it returns null.
+ */
+ return null;
}
public short compareDocumentPosition(Node other)
@@ -199,35 +283,308 @@ public abstract class NodeImpl implements Node {
}
public String getTextContent() throws DOMException {
- throw new UnsupportedOperationException(); // TODO
+ return getNodeValue();
}
- public void setTextContent(String textContent) throws DOMException {
- throw new UnsupportedOperationException(); // TODO
+ void getTextContent(StringBuilder buf) throws DOMException {
+ String content = getNodeValue();
+ if (content != null) {
+ buf.append(content);
+ }
+ }
+
+ public final void setTextContent(String textContent) throws DOMException {
+ switch (getNodeType()) {
+ case DOCUMENT_TYPE_NODE:
+ case DOCUMENT_NODE:
+ return; // do nothing!
+
+ case ELEMENT_NODE:
+ case ENTITY_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ // remove all existing children
+ Node child;
+ while ((child = getFirstChild()) != null) {
+ removeChild(child);
+ }
+ // create a text node to hold the given content
+ if (textContent != null && textContent.length() != 0){
+ appendChild(getOwnerDocument().createTextNode(textContent));
+ }
+ return;
+
+ case ATTRIBUTE_NODE:
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ case COMMENT_NODE:
+ case NOTATION_NODE:
+ setNodeValue(textContent);
+ return;
+
+ default:
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+ "Unsupported node type " + getNodeType());
+ }
}
public boolean isSameNode(Node other) {
- throw new UnsupportedOperationException(); // TODO
+ return this == other;
}
- public String lookupPrefix(String namespaceURI) {
- throw new UnsupportedOperationException(); // TODO
+ /**
+ * Returns the element whose namespace definitions apply to this node. Use
+ * this element when mapping prefixes to URIs and vice versa.
+ */
+ private NodeImpl getNamespacingElement() {
+ switch (this.getNodeType()) {
+ case ELEMENT_NODE:
+ return this;
+
+ case DOCUMENT_NODE:
+ return (NodeImpl) ((Document) this).getDocumentElement();
+
+ case ENTITY_NODE:
+ case NOTATION_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case DOCUMENT_TYPE_NODE:
+ return null;
+
+ case ATTRIBUTE_NODE:
+ return (NodeImpl) ((Attr) this).getOwnerElement();
+
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ case COMMENT_NODE:
+ return getContainingElement();
+
+ default:
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+ "Unsupported node type " + getNodeType());
+ }
}
- public boolean isDefaultNamespace(String namespaceURI) {
- throw new UnsupportedOperationException(); // TODO
+ /**
+ * Returns the nearest ancestor element that contains this node.
+ */
+ private NodeImpl getContainingElement() {
+ for (Node p = getParentNode(); p != null; p = p.getParentNode()) {
+ if (p.getNodeType() == ELEMENT_NODE) {
+ return (NodeImpl) p;
+ }
+ }
+ return null;
}
- public String lookupNamespaceURI(String prefix) {
- throw new UnsupportedOperationException(); // TODO
+ public final String lookupPrefix(String namespaceURI) {
+ if (namespaceURI == null) {
+ return null;
+ }
+
+ // the XML specs define some prefixes (like "xml" and "xmlns") but this
+ // API is explicitly defined to ignore those.
+
+ NodeImpl target = getNamespacingElement();
+ for (NodeImpl node = target; node != null; node = node.getContainingElement()) {
+ // check this element's namespace first
+ if (namespaceURI.equals(node.getNamespaceURI())
+ && target.isPrefixMappedToUri(node.getPrefix(), namespaceURI)) {
+ return node.getPrefix();
+ }
+
+ // search this element for an attribute of this form:
+ // xmlns:foo="http://namespaceURI"
+ if (!node.hasAttributes()) {
+ continue;
+ }
+ NamedNodeMap attributes = node.getAttributes();
+ for (int i = 0, length = attributes.getLength(); i < length; i++) {
+ Node attr = attributes.item(i);
+ if (!"http://www.w3.org/2000/xmlns/".equals(attr.getNamespaceURI())
+ || !"xmlns".equals(attr.getPrefix())
+ || !namespaceURI.equals(attr.getNodeValue())) {
+ continue;
+ }
+ if (target.isPrefixMappedToUri(attr.getLocalName(), namespaceURI)) {
+ return attr.getLocalName();
+ }
+ }
+ }
+
+ return null;
}
- public boolean isEqualNode(Node arg) {
- throw new UnsupportedOperationException(); // TODO
+ /**
+ * Returns true if the given prefix is mapped to the given URI on this
+ * element. Since child elements can redefine prefixes, this check is
+ * necessary: {@code
+ * <foo xmlns:a="http://good">
+ * <bar xmlns:a="http://evil">
+ * <a:baz />
+ * </bar>
+ * </foo>}
+ *
+ * @param prefix the prefix to find. Nullable.
+ * @param uri the URI to match. Non-null.
+ */
+ boolean isPrefixMappedToUri(String prefix, String uri) {
+ if (prefix == null) {
+ return false;
+ }
+
+ String actual = lookupNamespaceURI(prefix);
+ return uri.equals(actual);
+ }
+
+ public final boolean isDefaultNamespace(String namespaceURI) {
+ String actual = lookupNamespaceURI(null); // null yields the default namespace
+ return namespaceURI == null
+ ? actual == null
+ : namespaceURI.equals(actual);
+ }
+
+ public final String lookupNamespaceURI(String prefix) {
+ NodeImpl target = getNamespacingElement();
+ for (NodeImpl node = target; node != null; node = node.getContainingElement()) {
+ // check this element's namespace first
+ String nodePrefix = node.getPrefix();
+ if (node.getNamespaceURI() != null) {
+ if (prefix == null // null => default prefix
+ ? nodePrefix == null
+ : prefix.equals(nodePrefix)) {
+ return node.getNamespaceURI();
+ }
+ }
+
+ // search this element for an attribute of the appropriate form.
+ // default namespace: xmlns="http://resultUri"
+ // non default: xmlns:specifiedPrefix="http://resultUri"
+ if (!node.hasAttributes()) {
+ continue;
+ }
+ NamedNodeMap attributes = node.getAttributes();
+ for (int i = 0, length = attributes.getLength(); i < length; i++) {
+ Node attr = attributes.item(i);
+ if (!"http://www.w3.org/2000/xmlns/".equals(attr.getNamespaceURI())) {
+ continue;
+ }
+ if (prefix == null // null => default prefix
+ ? "xmlns".equals(attr.getNodeName())
+ : "xmlns".equals(attr.getPrefix()) && prefix.equals(attr.getLocalName())) {
+ String value = attr.getNodeValue();
+ return value.length() > 0 ? value : null;
+ }
+ }
+ }
+
+ return null;
}
- public Object getFeature(String feature, String version) {
- throw new UnsupportedOperationException(); // TODO
+ /**
+ * Returns a list of objects such that two nodes are equal if their lists
+ * are equal. Be careful: the lists may contain NamedNodeMaps and Nodes,
+ * neither of which override Object.equals(). Such values must be compared
+ * manually.
+ */
+ private static List<Object> createEqualityKey(Node node) {
+ List<Object> values = new ArrayList<Object>();
+ values.add(node.getNodeType());
+ values.add(node.getNodeName());
+ values.add(node.getLocalName());
+ values.add(node.getNamespaceURI());
+ values.add(node.getPrefix());
+ values.add(node.getNodeValue());
+ for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+ values.add(child);
+ }
+
+ switch (node.getNodeType()) {
+ case DOCUMENT_TYPE_NODE:
+ DocumentTypeImpl doctype = (DocumentTypeImpl) node;
+ values.add(doctype.getPublicId());
+ values.add(doctype.getSystemId());
+ values.add(doctype.getInternalSubset());
+ values.add(doctype.getEntities());
+ values.add(doctype.getNotations());
+ break;
+
+ case ELEMENT_NODE:
+ Element element = (Element) node;
+ values.add(element.getAttributes());
+ break;
+ }
+
+ return values;
+ }
+
+ public final boolean isEqualNode(Node arg) {
+ if (arg == this) {
+ return true;
+ }
+
+ List<Object> listA = createEqualityKey(this);
+ List<Object> listB = createEqualityKey(arg);
+
+ if (listA.size() != listB.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < listA.size(); i++) {
+ Object a = listA.get(i);
+ Object b = listB.get(i);
+
+ if (a == b) {
+ continue;
+
+ } else if (a == null || b == null) {
+ return false;
+
+ } else if (a instanceof String || a instanceof Short) {
+ if (!a.equals(b)) {
+ return false;
+ }
+
+ } else if (a instanceof NamedNodeMap) {
+ if (!(b instanceof NamedNodeMap)
+ || !namedNodeMapsEqual((NamedNodeMap) a, (NamedNodeMap) b)) {
+ return false;
+ }
+
+ } else if (a instanceof Node) {
+ if (!(b instanceof Node)
+ || !((Node) a).isEqualNode((Node) b)) {
+ return false;
+ }
+
+ } else {
+ throw new AssertionError(); // unexpected type
+ }
+ }
+
+ return true;
+ }
+
+ private boolean namedNodeMapsEqual(NamedNodeMap a, NamedNodeMap b) {
+ if (a.getLength() != b.getLength()) {
+ return false;
+ }
+ for (int i = 0; i < a.getLength(); i++) {
+ Node aNode = a.item(i);
+ Node bNode = aNode.getLocalName() == null
+ ? b.getNamedItem(aNode.getNodeName())
+ : b.getNamedItemNS(aNode.getNamespaceURI(), aNode.getLocalName());
+ if (bNode == null || !aNode.isEqualNode(bNode)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public final Object getFeature(String feature, String version) {
+ return isSupported(feature, version) ? this : null;
}
public Object setUserData(String key, Object data,
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java
index 3905865..5c9d123 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java
@@ -46,11 +46,6 @@ public class TextImpl extends CharacterDataImpl implements Text {
return Node.TEXT_NODE;
}
- @Override
- public String getNodeValue() {
- return getData();
- }
-
public Text splitText(int offset) throws DOMException {
Text newText = getOwnerDocument().createTextNode(
substringData(offset, getLength() - offset));
diff --git a/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
index 5a3c48c..52240aa 100644
--- a/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
@@ -115,8 +115,8 @@ class DocumentBuilderImpl extends DocumentBuilder {
Document document = newDocument();
try {
- XmlPullParser parser = new KXmlParser();
-
+ KXmlParser parser = new KXmlParser();
+ parser.keepNamespaceAttributes();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
namespaceAware);
diff --git a/xml/src/main/java/org/apache/xalan/processor/TransformerFactoryImpl.java b/xml/src/main/java/org/apache/xalan/processor/TransformerFactoryImpl.java
index 78d0cc5..618b412 100644
--- a/xml/src/main/java/org/apache/xalan/processor/TransformerFactoryImpl.java
+++ b/xml/src/main/java/org/apache/xalan/processor/TransformerFactoryImpl.java
@@ -792,7 +792,7 @@ public class TransformerFactoryImpl extends SAXTransformerFactory
try
{
m_errorListener.fatalError( ex );
- return null;
+ return null; // TODO: but the API promises to never return null...
}
catch( TransformerConfigurationException ex1 )
{
diff --git a/xml/src/main/java/org/apache/xml/utils/DOMHelper.java b/xml/src/main/java/org/apache/xml/utils/DOMHelper.java
index 76721d0..53d0adc 100644
--- a/xml/src/main/java/org/apache/xml/utils/DOMHelper.java
+++ b/xml/src/main/java/org/apache/xml/utils/DOMHelper.java
@@ -85,16 +85,23 @@ public class DOMHelper
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setNamespaceAware(true);
- dfactory.setValidating(true);
-
- if (isSecureProcessing)
- {
- try
- {
- dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
- }
- catch (ParserConfigurationException pce) {}
- }
+ // BEGIN android-removed
+ // If set, DocumentBuilderFactoryImpl.newDocumentBuilder() fails
+ // because we haven't implemented validation
+ // dfactory.setValidating(true);
+ // BEGIN android-removed
+
+ // BEGIN android-removed
+ // We haven't implemented secure processing
+ // if (isSecureProcessing)
+ // {
+ // try
+ // {
+ // dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ // }
+ // catch (ParserConfigurationException pce) {}
+ // }
+ // END android-removed
DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
Document outNode = docBuilder.newDocument();
diff --git a/xml/src/main/java/org/kxml2/io/KXmlParser.java b/xml/src/main/java/org/kxml2/io/KXmlParser.java
index c4d8f3d..99eb03b 100644
--- a/xml/src/main/java/org/kxml2/io/KXmlParser.java
+++ b/xml/src/main/java/org/kxml2/io/KXmlParser.java
@@ -45,6 +45,7 @@ public class KXmlParser implements XmlPullParser {
private boolean processNsp;
private boolean relaxed;
+ private boolean keepNamespaceAttributes; // android-added
private Hashtable entityMap;
private int depth;
private String[] elementStack = new String[16];
@@ -80,6 +81,14 @@ public class KXmlParser implements XmlPullParser {
private boolean degenerated;
private int attributeCount;
+
+ /**
+ * The current element's attributes arranged in groups of 4:
+ * i + 0 = attribute namespace URI
+ * i + 1 = attribute namespace prefix
+ * i + 2 = attribute qualified name (may contain ":", as in "html:h1")
+ * i + 3 = attribute value
+ */
private String[] attributes = new String[16];
// private int stackMismatch = 0;
private String error;
@@ -100,6 +109,19 @@ public class KXmlParser implements XmlPullParser {
new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128];
}
+ // BEGIN android-added
+ /**
+ * Retains namespace attributes like {@code xmlns="http://foo"} or {@code
+ * xmlns:foo="http:foo"} in pulled elements. Most applications will only be
+ * interested in the effective namespaces of their elements, so these
+ * attributes aren't useful. But for structure preserving wrappers like DOM,
+ * it is necessary to keep the namespace data around.
+ */
+ public void keepNamespaceAttributes() {
+ this.keepNamespaceAttributes = true;
+ }
+ // END android-added
+
private final boolean isProp(String n1, boolean prop, String n2) {
if (!n1.startsWith("http://xmlpull.org/v1/doc/"))
return false;
@@ -148,14 +170,23 @@ public class KXmlParser implements XmlPullParser {
//System.out.println (prefixMap);
- System.arraycopy(
- attributes,
- i + 4,
- attributes,
- i,
- ((--attributeCount) << 2) - i);
-
- i -= 4;
+ // BEGIN android-changed
+ if (keepNamespaceAttributes) {
+ // explicitly set the namespace for unprefixed attributes
+ // such as xmlns="http://foo"
+ attributes[i] = "http://www.w3.org/2000/xmlns/";
+ any = true;
+ } else {
+ System.arraycopy(
+ attributes,
+ i + 4,
+ attributes,
+ i,
+ ((--attributeCount) << 2) - i);
+
+ i -= 4;
+ }
+ // END android-changed
}
}
diff --git a/xml/src/main/java/org/w3c/dom/Attr.java b/xml/src/main/java/org/w3c/dom/Attr.java
index d9ed6ff..bd7267b 100644
--- a/xml/src/main/java/org/w3c/dom/Attr.java
+++ b/xml/src/main/java/org/w3c/dom/Attr.java
@@ -176,7 +176,7 @@ public interface Attr extends Node {
/**
* On retrieval, the value of the attribute is returned as a string.
* Character and general entity references are replaced with their
- * values. See also the method <code>getAttribute</code> on the
+ * values. See also the method <code>getAttribute</code> on the
* <code>Element</code> interface.
* <br>On setting, this creates a <code>Text</code> node with the unparsed
* contents of the string, i.e. any characters that an XML processor
diff --git a/xml/src/main/java/org/w3c/dom/events/DocumentEvent.java b/xml/src/main/java/org/w3c/dom/events/DocumentEvent.java
deleted file mode 100644
index 76644bc..0000000
--- a/xml/src/main/java/org/w3c/dom/events/DocumentEvent.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-import org.w3c.dom.DOMException;
-
-/**
- * The <code>DocumentEvent</code> interface provides a mechanism by which the
- * user can create an Event of a type supported by the implementation. It is
- * expected that the <code>DocumentEvent</code> interface will be
- * implemented on the same object which implements the <code>Document</code>
- * interface in an implementation which supports the Event model.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface DocumentEvent {
- /**
- *
- * @param eventType The <code>eventType</code> parameter specifies the
- * type of <code>Event</code> interface to be created. If the
- * <code>Event</code> interface specified is supported by the
- * implementation this method will return a new <code>Event</code> of
- * the interface type requested. If the <code>Event</code> is to be
- * dispatched via the <code>dispatchEvent</code> method the
- * appropriate event init method must be called after creation in
- * order to initialize the <code>Event</code>'s values. As an example,
- * a user wishing to synthesize some kind of <code>UIEvent</code>
- * would call <code>createEvent</code> with the parameter "UIEvents".
- * The <code>initUIEvent</code> method could then be called on the
- * newly created <code>UIEvent</code> to set the specific type of
- * UIEvent to be dispatched and set its context information.The
- * <code>createEvent</code> method is used in creating
- * <code>Event</code>s when it is either inconvenient or unnecessary
- * for the user to create an <code>Event</code> themselves. In cases
- * where the implementation provided <code>Event</code> is
- * insufficient, users may supply their own <code>Event</code>
- * implementations for use with the <code>dispatchEvent</code> method.
- * @return The newly created <code>Event</code>
- * @exception DOMException
- * NOT_SUPPORTED_ERR: Raised if the implementation does not support the
- * type of <code>Event</code> interface requested
- */
- public Event createEvent(String eventType)
- throws DOMException;
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/Event.java b/xml/src/main/java/org/w3c/dom/events/Event.java
deleted file mode 100644
index 14a9239..0000000
--- a/xml/src/main/java/org/w3c/dom/events/Event.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-/**
- * The <code>Event</code> interface is used to provide contextual information
- * about an event to the handler processing the event. An object which
- * implements the <code>Event</code> interface is generally passed as the
- * first parameter to an event handler. More specific context information is
- * passed to event handlers by deriving additional interfaces from
- * <code>Event</code> which contain information directly relating to the
- * type of event they accompany. These derived interfaces are also
- * implemented by the object passed to the event listener.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface Event {
- // PhaseType
- /**
- * The current event phase is the capturing phase.
- */
- public static final short CAPTURING_PHASE = 1;
- /**
- * The event is currently being evaluated at the target
- * <code>EventTarget</code>.
- */
- public static final short AT_TARGET = 2;
- /**
- * The current event phase is the bubbling phase.
- */
- public static final short BUBBLING_PHASE = 3;
-
- /**
- * The name of the event (case-insensitive). The name must be an XML name.
- */
- public String getType();
-
- /**
- * Used to indicate the <code>EventTarget</code> to which the event was
- * originally dispatched.
- */
- public EventTarget getTarget();
-
- /**
- * Used to indicate the <code>EventTarget</code> whose
- * <code>EventListeners</code> are currently being processed. This is
- * particularly useful during capturing and bubbling.
- */
- public EventTarget getCurrentTarget();
-
- /**
- * Used to indicate which phase of event flow is currently being
- * evaluated.
- */
- public short getEventPhase();
-
- /**
- * Used to indicate whether or not an event is a bubbling event. If the
- * event can bubble the value is true, else the value is false.
- */
- public boolean getBubbles();
-
- /**
- * Used to indicate whether or not an event can have its default action
- * prevented. If the default action can be prevented the value is true,
- * else the value is false.
- */
- public boolean getCancelable();
-
- /**
- * Used to specify the time (in milliseconds relative to the epoch) at
- * which the event was created. Due to the fact that some systems may
- * not provide this information the value of <code>timeStamp</code> may
- * be not available for all events. When not available, a value of 0
- * will be returned. Examples of epoch time are the time of the system
- * start or 0:0:0 UTC 1st January 1970.
- */
- public long getTimeStamp();
-
- /**
- * The <code>stopPropagation</code> method is used prevent further
- * propagation of an event during event flow. If this method is called
- * by any <code>EventListener</code> the event will cease propagating
- * through the tree. The event will complete dispatch to all listeners
- * on the current <code>EventTarget</code> before event flow stops. This
- * method may be used during any stage of event flow.
- */
- public void stopPropagation();
-
- /**
- * If an event is cancelable, the <code>preventDefault</code> method is
- * used to signify that the event is to be canceled, meaning any default
- * action normally taken by the implementation as a result of the event
- * will not occur. If, during any stage of event flow, the
- * <code>preventDefault</code> method is called the event is canceled.
- * Any default action associated with the event will not occur. Calling
- * this method for a non-cancelable event has no effect. Once
- * <code>preventDefault</code> has been called it will remain in effect
- * throughout the remainder of the event's propagation. This method may
- * be used during any stage of event flow.
- */
- public void preventDefault();
-
- /**
- * The <code>initEvent</code> method is used to initialize the value of an
- * <code>Event</code> created through the <code>DocumentEvent</code>
- * interface. This method may only be called before the
- * <code>Event</code> has been dispatched via the
- * <code>dispatchEvent</code> method, though it may be called multiple
- * times during that phase if necessary. If called multiple times the
- * final invocation takes precedence. If called from a subclass of
- * <code>Event</code> interface only the values specified in the
- * <code>initEvent</code> method are modified, all other attributes are
- * left unchanged.
- * @param eventTypeArg Specifies the event type. This type may be any
- * event type currently defined in this specification or a new event
- * type.. The string must be an XML name. Any new event type must not
- * begin with any upper, lower, or mixed case version of the string
- * "DOM". This prefix is reserved for future DOM event sets. It is
- * also strongly recommended that third parties adding their own
- * events use their own prefix to avoid confusion and lessen the
- * probability of conflicts with other new events.
- * @param canBubbleArg Specifies whether or not the event can bubble.
- * @param cancelableArg Specifies whether or not the event's default
- * action can be prevented.
- */
- public void initEvent(String eventTypeArg,
- boolean canBubbleArg,
- boolean cancelableArg);
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/EventException.java b/xml/src/main/java/org/w3c/dom/events/EventException.java
deleted file mode 100644
index 7a6ff26..0000000
--- a/xml/src/main/java/org/w3c/dom/events/EventException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-/**
- * Event operations may throw an <code>EventException</code> as specified in
- * their method descriptions.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public class EventException extends RuntimeException {
- public EventException(short code, String message) {
- super(message);
- this.code = code;
- }
- public short code;
- // EventExceptionCode
- /**
- * If the <code>Event</code>'s type was not specified by initializing the
- * event before the method was called. Specification of the Event's type
- * as <code>null</code> or an empty string will also trigger this
- * exception.
- */
- public static final short UNSPECIFIED_EVENT_TYPE_ERR = 0;
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/EventListener.java b/xml/src/main/java/org/w3c/dom/events/EventListener.java
deleted file mode 100644
index 1df8020..0000000
--- a/xml/src/main/java/org/w3c/dom/events/EventListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-/**
- * The <code>EventListener</code> interface is the primary method for
- * handling events. Users implement the <code>EventListener</code> interface
- * and register their listener on an <code>EventTarget</code> using the
- * <code>AddEventListener</code> method. The users should also remove their
- * <code>EventListener</code> from its <code>EventTarget</code> after they
- * have completed using the listener.
- * <p> When a <code>Node</code> is copied using the <code>cloneNode</code>
- * method the <code>EventListener</code>s attached to the source
- * <code>Node</code> are not attached to the copied <code>Node</code>. If
- * the user wishes the same <code>EventListener</code>s to be added to the
- * newly created copy the user must add them manually.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface EventListener {
- /**
- * This method is called whenever an event occurs of the type for which
- * the <code> EventListener</code> interface was registered.
- * @param evt The <code>Event</code> contains contextual information
- * about the event. It also contains the <code>stopPropagation</code>
- * and <code>preventDefault</code> methods which are used in
- * determining the event's flow and default action.
- */
- public void handleEvent(Event evt);
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/EventTarget.java b/xml/src/main/java/org/w3c/dom/events/EventTarget.java
deleted file mode 100644
index f076636..0000000
--- a/xml/src/main/java/org/w3c/dom/events/EventTarget.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-/**
- * The <code>EventTarget</code> interface is implemented by all
- * <code>Nodes</code> in an implementation which supports the DOM Event
- * Model. Therefore, this interface can be obtained by using
- * binding-specific casting methods on an instance of the <code>Node</code>
- * interface. The interface allows registration and removal of
- * <code>EventListeners</code> on an <code>EventTarget</code> and dispatch
- * of events to that <code>EventTarget</code>.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface EventTarget {
- /**
- * This method allows the registration of event listeners on the event
- * target. If an <code>EventListener</code> is added to an
- * <code>EventTarget</code> while it is processing an event, it will not
- * be triggered by the current actions but may be triggered during a
- * later stage of event flow, such as the bubbling phase.
- * <br> If multiple identical <code>EventListener</code>s are registered
- * on the same <code>EventTarget</code> with the same parameters the
- * duplicate instances are discarded. They do not cause the
- * <code>EventListener</code> to be called twice and since they are
- * discarded they do not need to be removed with the
- * <code>removeEventListener</code> method.
- * @param type The event type for which the user is registering
- * @param listener The <code>listener</code> parameter takes an interface
- * implemented by the user which contains the methods to be called
- * when the event occurs.
- * @param useCapture If true, <code>useCapture</code> indicates that the
- * user wishes to initiate capture. After initiating capture, all
- * events of the specified type will be dispatched to the registered
- * <code>EventListener</code> before being dispatched to any
- * <code>EventTargets</code> beneath them in the tree. Events which
- * are bubbling upward through the tree will not trigger an
- * <code>EventListener</code> designated to use capture.
- */
- public void addEventListener(String type,
- EventListener listener,
- boolean useCapture);
-
- /**
- * This method allows the removal of event listeners from the event
- * target. If an <code>EventListener</code> is removed from an
- * <code>EventTarget</code> while it is processing an event, it will not
- * be triggered by the current actions. <code>EventListener</code>s can
- * never be invoked after being removed.
- * <br>Calling <code>removeEventListener</code> with arguments which do
- * not identify any currently registered <code>EventListener</code> on
- * the <code>EventTarget</code> has no effect.
- * @param type Specifies the event type of the <code>EventListener</code>
- * being removed.
- * @param listener The <code>EventListener</code> parameter indicates the
- * <code>EventListener </code> to be removed.
- * @param useCapture Specifies whether the <code>EventListener</code>
- * being removed was registered as a capturing listener or not. If a
- * listener was registered twice, one with capture and one without,
- * each must be removed separately. Removal of a capturing listener
- * does not affect a non-capturing version of the same listener, and
- * vice versa.
- */
- public void removeEventListener(String type,
- EventListener listener,
- boolean useCapture);
-
- /**
- * This method allows the dispatch of events into the implementations
- * event model. Events dispatched in this manner will have the same
- * capturing and bubbling behavior as events dispatched directly by the
- * implementation. The target of the event is the
- * <code> EventTarget</code> on which <code>dispatchEvent</code> is
- * called.
- * @param evt Specifies the event type, behavior, and contextual
- * information to be used in processing the event.
- * @return The return value of <code>dispatchEvent</code> indicates
- * whether any of the listeners which handled the event called
- * <code>preventDefault</code>. If <code>preventDefault</code> was
- * called the value is false, else the value is true.
- * @exception EventException
- * UNSPECIFIED_EVENT_TYPE_ERR: Raised if the <code>Event</code>'s type
- * was not specified by initializing the event before
- * <code>dispatchEvent</code> was called. Specification of the
- * <code>Event</code>'s type as <code>null</code> or an empty string
- * will also trigger this exception.
- */
- public boolean dispatchEvent(Event evt)
- throws EventException;
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/MouseEvent.java b/xml/src/main/java/org/w3c/dom/events/MouseEvent.java
deleted file mode 100644
index be78035..0000000
--- a/xml/src/main/java/org/w3c/dom/events/MouseEvent.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-import org.w3c.dom.views.AbstractView;
-
-/**
- * The <code>MouseEvent</code> interface provides specific contextual
- * information associated with Mouse events.
- * <p>The <code>detail</code> attribute inherited from <code>UIEvent</code>
- * indicates the number of times a mouse button has been pressed and
- * released over the same screen location during a user action. The
- * attribute value is 1 when the user begins this action and increments by 1
- * for each full sequence of pressing and releasing. If the user moves the
- * mouse between the mousedown and mouseup the value will be set to 0,
- * indicating that no click is occurring.
- * <p>In the case of nested elements mouse events are always targeted at the
- * most deeply nested element. Ancestors of the targeted element may use
- * bubbling to obtain notification of mouse events which occur within its
- * descendent elements.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface MouseEvent extends UIEvent {
- /**
- * The horizontal coordinate at which the event occurred relative to the
- * origin of the screen coordinate system.
- */
- public int getScreenX();
-
- /**
- * The vertical coordinate at which the event occurred relative to the
- * origin of the screen coordinate system.
- */
- public int getScreenY();
-
- /**
- * The horizontal coordinate at which the event occurred relative to the
- * DOM implementation's client area.
- */
- public int getClientX();
-
- /**
- * The vertical coordinate at which the event occurred relative to the DOM
- * implementation's client area.
- */
- public int getClientY();
-
- /**
- * Used to indicate whether the 'ctrl' key was depressed during the firing
- * of the event.
- */
- public boolean getCtrlKey();
-
- /**
- * Used to indicate whether the 'shift' key was depressed during the
- * firing of the event.
- */
- public boolean getShiftKey();
-
- /**
- * Used to indicate whether the 'alt' key was depressed during the firing
- * of the event. On some platforms this key may map to an alternative
- * key name.
- */
- public boolean getAltKey();
-
- /**
- * Used to indicate whether the 'meta' key was depressed during the firing
- * of the event. On some platforms this key may map to an alternative
- * key name.
- */
- public boolean getMetaKey();
-
- /**
- * During mouse events caused by the depression or release of a mouse
- * button, <code>button</code> is used to indicate which mouse button
- * changed state. The values for <code>button</code> range from zero to
- * indicate the left button of the mouse, one to indicate the middle
- * button if present, and two to indicate the right button. For mice
- * configured for left handed use in which the button actions are
- * reversed the values are instead read from right to left.
- */
- public short getButton();
-
- /**
- * Used to identify a secondary <code>EventTarget</code> related to a UI
- * event. Currently this attribute is used with the mouseover event to
- * indicate the <code>EventTarget</code> which the pointing device
- * exited and with the mouseout event to indicate the
- * <code>EventTarget</code> which the pointing device entered.
- */
- public EventTarget getRelatedTarget();
-
- /**
- * The <code>initMouseEvent</code> method is used to initialize the value
- * of a <code>MouseEvent</code> created through the
- * <code>DocumentEvent</code> interface. This method may only be called
- * before the <code>MouseEvent</code> has been dispatched via the
- * <code>dispatchEvent</code> method, though it may be called multiple
- * times during that phase if necessary. If called multiple times, the
- * final invocation takes precedence.
- * @param typeArg Specifies the event type.
- * @param canBubbleArg Specifies whether or not the event can bubble.
- * @param cancelableArg Specifies whether or not the event's default
- * action can be prevented.
- * @param viewArg Specifies the <code>Event</code>'s
- * <code>AbstractView</code>.
- * @param detailArg Specifies the <code>Event</code>'s mouse click count.
- * @param screenXArg Specifies the <code>Event</code>'s screen x
- * coordinate
- * @param screenYArg Specifies the <code>Event</code>'s screen y
- * coordinate
- * @param clientXArg Specifies the <code>Event</code>'s client x
- * coordinate
- * @param clientYArg Specifies the <code>Event</code>'s client y
- * coordinate
- * @param ctrlKeyArg Specifies whether or not control key was depressed
- * during the <code>Event</code>.
- * @param altKeyArg Specifies whether or not alt key was depressed during
- * the <code>Event</code>.
- * @param shiftKeyArg Specifies whether or not shift key was depressed
- * during the <code>Event</code>.
- * @param metaKeyArg Specifies whether or not meta key was depressed
- * during the <code>Event</code>.
- * @param buttonArg Specifies the <code>Event</code>'s mouse button.
- * @param relatedTargetArg Specifies the <code>Event</code>'s related
- * <code>EventTarget</code>.
- */
- public void initMouseEvent(String typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- AbstractView viewArg,
- int detailArg,
- int screenXArg,
- int screenYArg,
- int clientXArg,
- int clientYArg,
- boolean ctrlKeyArg,
- boolean altKeyArg,
- boolean shiftKeyArg,
- boolean metaKeyArg,
- short buttonArg,
- EventTarget relatedTargetArg);
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/MutationEvent.java b/xml/src/main/java/org/w3c/dom/events/MutationEvent.java
deleted file mode 100644
index 3db4003..0000000
--- a/xml/src/main/java/org/w3c/dom/events/MutationEvent.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-import org.w3c.dom.Node;
-
-/**
- * The <code>MutationEvent</code> interface provides specific contextual
- * information associated with Mutation events.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface MutationEvent extends Event {
- // attrChangeType
- /**
- * The <code>Attr</code> was modified in place.
- */
- public static final short MODIFICATION = 1;
- /**
- * The <code>Attr</code> was just added.
- */
- public static final short ADDITION = 2;
- /**
- * The <code>Attr</code> was just removed.
- */
- public static final short REMOVAL = 3;
-
- /**
- * <code>relatedNode</code> is used to identify a secondary node related
- * to a mutation event. For example, if a mutation event is dispatched
- * to a node indicating that its parent has changed, the
- * <code>relatedNode</code> is the changed parent. If an event is
- * instead dispatched to a subtree indicating a node was changed within
- * it, the <code>relatedNode</code> is the changed node. In the case of
- * the DOMAttrModified event it indicates the <code>Attr</code> node
- * which was modified, added, or removed.
- */
- public Node getRelatedNode();
-
- /**
- * <code>prevValue</code> indicates the previous value of the
- * <code>Attr</code> node in DOMAttrModified events, and of the
- * <code>CharacterData</code> node in DOMCharacterDataModified events.
- */
- public String getPrevValue();
-
- /**
- * <code>newValue</code> indicates the new value of the <code>Attr</code>
- * node in DOMAttrModified events, and of the <code>CharacterData</code>
- * node in DOMCharacterDataModified events.
- */
- public String getNewValue();
-
- /**
- * <code>attrName</code> indicates the name of the changed
- * <code>Attr</code> node in a DOMAttrModified event.
- */
- public String getAttrName();
-
- /**
- * <code>attrChange</code> indicates the type of change which triggered
- * the DOMAttrModified event. The values can be <code>MODIFICATION</code>
- * , <code>ADDITION</code>, or <code>REMOVAL</code>.
- */
- public short getAttrChange();
-
- /**
- * The <code>initMutationEvent</code> method is used to initialize the
- * value of a <code>MutationEvent</code> created through the
- * <code>DocumentEvent</code> interface. This method may only be called
- * before the <code>MutationEvent</code> has been dispatched via the
- * <code>dispatchEvent</code> method, though it may be called multiple
- * times during that phase if necessary. If called multiple times, the
- * final invocation takes precedence.
- * @param typeArg Specifies the event type.
- * @param canBubbleArg Specifies whether or not the event can bubble.
- * @param cancelableArg Specifies whether or not the event's default
- * action can be prevented.
- * @param relatedNodeArg Specifies the <code>Event</code>'s related Node.
- * @param prevValueArg Specifies the <code>Event</code>'s
- * <code>prevValue</code> attribute. This value may be null.
- * @param newValueArg Specifies the <code>Event</code>'s
- * <code>newValue</code> attribute. This value may be null.
- * @param attrNameArg Specifies the <code>Event</code>'s
- * <code>attrName</code> attribute. This value may be null.
- * @param attrChangeArg Specifies the <code>Event</code>'s
- * <code>attrChange</code> attribute
- */
- public void initMutationEvent(String typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- Node relatedNodeArg,
- String prevValueArg,
- String newValueArg,
- String attrNameArg,
- short attrChangeArg);
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/events/UIEvent.java b/xml/src/main/java/org/w3c/dom/events/UIEvent.java
deleted file mode 100644
index 15affe8..0000000
--- a/xml/src/main/java/org/w3c/dom/events/UIEvent.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.events;
-
-import org.w3c.dom.views.AbstractView;
-
-/**
- * The <code>UIEvent</code> interface provides specific contextual information
- * associated with User Interface events.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113'>Document Object Model (DOM) Level 2 Events Specification</a>.
- * @since DOM Level 2
- */
-public interface UIEvent extends Event {
- /**
- * The <code>view</code> attribute identifies the <code>AbstractView</code>
- * from which the event was generated.
- */
- public AbstractView getView();
-
- /**
- * Specifies some detail information about the <code>Event</code>,
- * depending on the type of event.
- */
- public int getDetail();
-
- /**
- * The <code>initUIEvent</code> method is used to initialize the value of
- * a <code>UIEvent</code> created through the <code>DocumentEvent</code>
- * interface. This method may only be called before the
- * <code>UIEvent</code> has been dispatched via the
- * <code>dispatchEvent</code> method, though it may be called multiple
- * times during that phase if necessary. If called multiple times, the
- * final invocation takes precedence.
- * @param typeArg Specifies the event type.
- * @param canBubbleArg Specifies whether or not the event can bubble.
- * @param cancelableArg Specifies whether or not the event's default
- * action can be prevented.
- * @param viewArg Specifies the <code>Event</code>'s
- * <code>AbstractView</code>.
- * @param detailArg Specifies the <code>Event</code>'s detail.
- */
- public void initUIEvent(String typeArg,
- boolean canBubbleArg,
- boolean cancelableArg,
- AbstractView viewArg,
- int detailArg);
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/ls/LSLoadEvent.java b/xml/src/main/java/org/w3c/dom/ls/LSLoadEvent.java
deleted file mode 100644
index 601a5be..0000000
--- a/xml/src/main/java/org/w3c/dom/ls/LSLoadEvent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2004 World Wide Web Consortium,
- *
- * (Massachusetts Institute of Technology, European Research Consortium for
- * Informatics and Mathematics, Keio University). All Rights Reserved. This
- * work is distributed under the W3C(r) Software License [1] in the hope that
- * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
- */
-
-package org.w3c.dom.ls;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.events.Event;
-
-/**
- * This interface represents a load event object that signals the completion
- * of a document load.
- * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
-and Save Specification</a>.
- */
-public interface LSLoadEvent extends Event {
- /**
- * The document that finished loading.
- */
- public Document getNewDocument();
-
- /**
- * The input source that was parsed.
- */
- public LSInput getInput();
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/ls/LSProgressEvent.java b/xml/src/main/java/org/w3c/dom/ls/LSProgressEvent.java
deleted file mode 100644
index da98e14..0000000
--- a/xml/src/main/java/org/w3c/dom/ls/LSProgressEvent.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2004 World Wide Web Consortium,
- *
- * (Massachusetts Institute of Technology, European Research Consortium for
- * Informatics and Mathematics, Keio University). All Rights Reserved. This
- * work is distributed under the W3C(r) Software License [1] in the hope that
- * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
- */
-
-package org.w3c.dom.ls;
-
-import org.w3c.dom.events.Event;
-
-/**
- * This interface represents a progress event object that notifies the
- * application about progress as a document is parsed. It extends the
- * <code>Event</code> interface defined in [<a href='http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107'>DOM Level 3 Events</a>]
- * .
- * <p> The units used for the attributes <code>position</code> and
- * <code>totalSize</code> are not specified and can be implementation and
- * input dependent.
- * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
-and Save Specification</a>.
- */
-public interface LSProgressEvent extends Event {
- /**
- * The input source that is being parsed.
- */
- public LSInput getInput();
-
- /**
- * The current position in the input source, including all external
- * entities and other resources that have been read.
- */
- public int getPosition();
-
- /**
- * The total size of the document including all external resources, this
- * number might change as a document is being parsed if references to
- * more external resources are seen. A value of <code>0</code> is
- * returned if the total size cannot be determined or estimated.
- */
- public int getTotalSize();
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/ls/LSSerializer.java b/xml/src/main/java/org/w3c/dom/ls/LSSerializer.java
index e7b6350..33b094a 100644
--- a/xml/src/main/java/org/w3c/dom/ls/LSSerializer.java
+++ b/xml/src/main/java/org/w3c/dom/ls/LSSerializer.java
@@ -330,7 +330,9 @@ public interface LSSerializer {
* <br> The filter is invoked after the operations requested by the
* <code>DOMConfiguration</code> parameters have been applied. For
* example, CDATA sections won't be passed to the filter if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-cdata-sections'>
- * cdata-sections</a>" is set to <code>false</code>.
+ * cdata-sections</a>" is set to <code>false</code>.
+ *
+ * @hide
*/
public LSSerializerFilter getFilter();
/**
@@ -341,7 +343,9 @@ public interface LSSerializer {
* <br> The filter is invoked after the operations requested by the
* <code>DOMConfiguration</code> parameters have been applied. For
* example, CDATA sections won't be passed to the filter if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-cdata-sections'>
- * cdata-sections</a>" is set to <code>false</code>.
+ * cdata-sections</a>" is set to <code>false</code>.
+ *
+ * @hide
*/
public void setFilter(LSSerializerFilter filter);
diff --git a/xml/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java b/xml/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java
index 049459c..9e76b37 100644
--- a/xml/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java
+++ b/xml/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java
@@ -41,6 +41,8 @@ import org.w3c.dom.traversal.NodeFilter;
* document.
* <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load
and Save Specification</a>.
+ *
+ * @hide
*/
public interface LSSerializerFilter extends NodeFilter {
/**
diff --git a/xml/src/main/java/org/w3c/dom/traversal/DocumentTraversal.java b/xml/src/main/java/org/w3c/dom/traversal/DocumentTraversal.java
deleted file mode 100644
index bc45ad9..0000000
--- a/xml/src/main/java/org/w3c/dom/traversal/DocumentTraversal.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.traversal;
-
-import org.w3c.dom.Node;
-import org.w3c.dom.DOMException;
-
-/**
- * <code>DocumentTraversal</code> contains methods that create
- * <code>NodeIterators</code> and <code>TreeWalkers</code> to traverse a
- * node and its children in document order (depth first, pre-order
- * traversal, which is equivalent to the order in which the start tags occur
- * in the text representation of the document). In DOMs which support the
- * Traversal feature, <code>DocumentTraversal</code> will be implemented by
- * the same objects that implement the Document interface.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document Object Model (DOM) Level 2 Traversal and Range Specification</a>.
- * @since DOM Level 2
- */
-public interface DocumentTraversal {
- /**
- * Create a new <code>NodeIterator</code> over the subtree rooted at the
- * specified node.
- * @param root The node which will be iterated together with its
- * children. The <code>NodeIterator</code> is initially positioned
- * just before this node. The <code>whatToShow</code> flags and the
- * filter, if any, are not considered when setting this position. The
- * root must not be <code>null</code>.
- * @param whatToShow This flag specifies which node types may appear in
- * the logical view of the tree presented by the
- * <code>NodeIterator</code>. See the description of
- * <code>NodeFilter</code> for the set of possible <code>SHOW_</code>
- * values.These flags can be combined using <code>OR</code>.
- * @param filter The <code>NodeFilter</code> to be used with this
- * <code>NodeIterator</code>, or <code>null</code> to indicate no
- * filter.
- * @param entityReferenceExpansion The value of this flag determines
- * whether entity reference nodes are expanded.
- * @return The newly created <code>NodeIterator</code>.
- * @exception DOMException
- * NOT_SUPPORTED_ERR: Raised if the specified <code>root</code> is
- * <code>null</code>.
- */
- public NodeIterator createNodeIterator(Node root,
- int whatToShow,
- NodeFilter filter,
- boolean entityReferenceExpansion)
- throws DOMException;
-
- /**
- * Create a new <code>TreeWalker</code> over the subtree rooted at the
- * specified node.
- * @param root The node which will serve as the <code>root</code> for the
- * <code>TreeWalker</code>. The <code>whatToShow</code> flags and the
- * <code>NodeFilter</code> are not considered when setting this value;
- * any node type will be accepted as the <code>root</code>. The
- * <code>currentNode</code> of the <code>TreeWalker</code> is
- * initialized to this node, whether or not it is visible. The
- * <code>root</code> functions as a stopping point for traversal
- * methods that look upward in the document structure, such as
- * <code>parentNode</code> and nextNode. The <code>root</code> must
- * not be <code>null</code>.
- * @param whatToShow This flag specifies which node types may appear in
- * the logical view of the tree presented by the
- * <code>TreeWalker</code>. See the description of
- * <code>NodeFilter</code> for the set of possible <code>SHOW_</code>
- * values.These flags can be combined using <code>OR</code>.
- * @param filter The <code>NodeFilter</code> to be used with this
- * <code>TreeWalker</code>, or <code>null</code> to indicate no filter.
- * @param entityReferenceExpansion If this flag is false, the contents of
- * <code>EntityReference</code> nodes are not presented in the logical
- * view.
- * @return The newly created <code>TreeWalker</code>.
- * @exception DOMException
- * NOT_SUPPORTED_ERR: Raised if the specified <code>root</code> is
- * <code>null</code>.
- */
- public TreeWalker createTreeWalker(Node root,
- int whatToShow,
- NodeFilter filter,
- boolean entityReferenceExpansion)
- throws DOMException;
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/traversal/NodeFilter.java b/xml/src/main/java/org/w3c/dom/traversal/NodeFilter.java
index b9beac4..4d179e7 100644
--- a/xml/src/main/java/org/w3c/dom/traversal/NodeFilter.java
+++ b/xml/src/main/java/org/w3c/dom/traversal/NodeFilter.java
@@ -31,6 +31,8 @@ import org.w3c.dom.Node;
* encouraging code reuse.
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document Object Model (DOM) Level 2 Traversal and Range Specification</a>.
* @since DOM Level 2
+ *
+ * @hide
*/
public interface NodeFilter {
// Constants returned by acceptNode
diff --git a/xml/src/main/java/org/w3c/dom/traversal/NodeIterator.java b/xml/src/main/java/org/w3c/dom/traversal/NodeIterator.java
index d1f0d08..e55cd9f 100644
--- a/xml/src/main/java/org/w3c/dom/traversal/NodeIterator.java
+++ b/xml/src/main/java/org/w3c/dom/traversal/NodeIterator.java
@@ -27,6 +27,8 @@ import org.w3c.dom.DOMException;
* <code>DocumentTraversal</code><code>.createNodeIterator()</code>.
* <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document Object Model (DOM) Level 2 Traversal and Range Specification</a>.
* @since DOM Level 2
+ *
+ * @hide
*/
public interface NodeIterator {
/**
diff --git a/xml/src/main/java/org/w3c/dom/traversal/TreeWalker.java b/xml/src/main/java/org/w3c/dom/traversal/TreeWalker.java
deleted file mode 100644
index f5fff86..0000000
--- a/xml/src/main/java/org/w3c/dom/traversal/TreeWalker.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.traversal;
-
-import org.w3c.dom.Node;
-import org.w3c.dom.DOMException;
-
-/**
- * <code>TreeWalker</code> objects are used to navigate a document tree or
- * subtree using the view of the document defined by their
- * <code>whatToShow</code> flags and filter (if any). Any function which
- * performs navigation using a <code>TreeWalker</code> will automatically
- * support any view defined by a <code>TreeWalker</code>.
- * <p>Omitting nodes from the logical view of a subtree can result in a
- * structure that is substantially different from the same subtree in the
- * complete, unfiltered document. Nodes that are siblings in the
- * <code>TreeWalker</code> view may be children of different, widely
- * separated nodes in the original view. For instance, consider a
- * <code>NodeFilter</code> that skips all nodes except for Text nodes and
- * the root node of a document. In the logical view that results, all text
- * nodes will be siblings and appear as direct children of the root node, no
- * matter how deeply nested the structure of the original document.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document Object Model (DOM) Level 2 Traversal and Range Specification</a>.
- * @since DOM Level 2
- */
-public interface TreeWalker {
- /**
- * The <code>root</code> node of the <code>TreeWalker</code>, as specified
- * when it was created.
- */
- public Node getRoot();
-
- /**
- * This attribute determines which node types are presented via the
- * <code>TreeWalker</code>. The available set of constants is defined in
- * the <code>NodeFilter</code> interface. Nodes not accepted by
- * <code>whatToShow</code> will be skipped, but their children may still
- * be considered. Note that this skip takes precedence over the filter,
- * if any.
- */
- public int getWhatToShow();
-
- /**
- * The filter used to screen nodes.
- */
- public NodeFilter getFilter();
-
- /**
- * The value of this flag determines whether the children of entity
- * reference nodes are visible to the <code>TreeWalker</code>. If false,
- * these children and their descendants will be rejected. Note that
- * this rejection takes precedence over <code>whatToShow</code> and the
- * filter, if any.
- * <br> To produce a view of the document that has entity references
- * expanded and does not expose the entity reference node itself, use
- * the <code>whatToShow</code> flags to hide the entity reference node
- * and set <code>expandEntityReferences</code> to true when creating the
- * <code>TreeWalker</code>. To produce a view of the document that has
- * entity reference nodes but no entity expansion, use the
- * <code>whatToShow</code> flags to show the entity reference node and
- * set <code>expandEntityReferences</code> to false.
- */
- public boolean getExpandEntityReferences();
-
- /**
- * The node at which the <code>TreeWalker</code> is currently positioned.
- * <br>Alterations to the DOM tree may cause the current node to no longer
- * be accepted by the <code>TreeWalker</code>'s associated filter.
- * <code>currentNode</code> may also be explicitly set to any node,
- * whether or not it is within the subtree specified by the
- * <code>root</code> node or would be accepted by the filter and
- * <code>whatToShow</code> flags. Further traversal occurs relative to
- * <code>currentNode</code> even if it is not part of the current view,
- * by applying the filters in the requested direction; if no traversal
- * is possible, <code>currentNode</code> is not changed.
- */
- public Node getCurrentNode();
- /**
- * The node at which the <code>TreeWalker</code> is currently positioned.
- * <br>Alterations to the DOM tree may cause the current node to no longer
- * be accepted by the <code>TreeWalker</code>'s associated filter.
- * <code>currentNode</code> may also be explicitly set to any node,
- * whether or not it is within the subtree specified by the
- * <code>root</code> node or would be accepted by the filter and
- * <code>whatToShow</code> flags. Further traversal occurs relative to
- * <code>currentNode</code> even if it is not part of the current view,
- * by applying the filters in the requested direction; if no traversal
- * is possible, <code>currentNode</code> is not changed.
- * @exception DOMException
- * NOT_SUPPORTED_ERR: Raised if an attempt is made to set
- * <code>currentNode</code> to <code>null</code>.
- */
- public void setCurrentNode(Node currentNode)
- throws DOMException;
-
- /**
- * Moves to and returns the closest visible ancestor node of the current
- * node. If the search for <code>parentNode</code> attempts to step
- * upward from the <code>TreeWalker</code>'s <code>root</code> node, or
- * if it fails to find a visible ancestor node, this method retains the
- * current position and returns <code>null</code>.
- * @return The new parent node, or <code>null</code> if the current node
- * has no parent in the <code>TreeWalker</code>'s logical view.
- */
- public Node parentNode();
-
- /**
- * Moves the <code>TreeWalker</code> to the first visible child of the
- * current node, and returns the new node. If the current node has no
- * visible children, returns <code>null</code>, and retains the current
- * node.
- * @return The new node, or <code>null</code> if the current node has no
- * visible children in the <code>TreeWalker</code>'s logical view.
- */
- public Node firstChild();
-
- /**
- * Moves the <code>TreeWalker</code> to the last visible child of the
- * current node, and returns the new node. If the current node has no
- * visible children, returns <code>null</code>, and retains the current
- * node.
- * @return The new node, or <code>null</code> if the current node has no
- * children in the <code>TreeWalker</code>'s logical view.
- */
- public Node lastChild();
-
- /**
- * Moves the <code>TreeWalker</code> to the previous sibling of the
- * current node, and returns the new node. If the current node has no
- * visible previous sibling, returns <code>null</code>, and retains the
- * current node.
- * @return The new node, or <code>null</code> if the current node has no
- * previous sibling. in the <code>TreeWalker</code>'s logical view.
- */
- public Node previousSibling();
-
- /**
- * Moves the <code>TreeWalker</code> to the next sibling of the current
- * node, and returns the new node. If the current node has no visible
- * next sibling, returns <code>null</code>, and retains the current node.
- * @return The new node, or <code>null</code> if the current node has no
- * next sibling. in the <code>TreeWalker</code>'s logical view.
- */
- public Node nextSibling();
-
- /**
- * Moves the <code>TreeWalker</code> to the previous visible node in
- * document order relative to the current node, and returns the new
- * node. If the current node has no previous node, or if the search for
- * <code>previousNode</code> attempts to step upward from the
- * <code>TreeWalker</code>'s <code>root</code> node, returns
- * <code>null</code>, and retains the current node.
- * @return The new node, or <code>null</code> if the current node has no
- * previous node in the <code>TreeWalker</code>'s logical view.
- */
- public Node previousNode();
-
- /**
- * Moves the <code>TreeWalker</code> to the next visible node in document
- * order relative to the current node, and returns the new node. If the
- * current node has no next node, or if the search for nextNode attempts
- * to step upward from the <code>TreeWalker</code>'s <code>root</code>
- * node, returns <code>null</code>, and retains the current node.
- * @return The new node, or <code>null</code> if the current node has no
- * next node in the <code>TreeWalker</code>'s logical view.
- */
- public Node nextNode();
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/views/AbstractView.java b/xml/src/main/java/org/w3c/dom/views/AbstractView.java
deleted file mode 100644
index 97e8f0e..0000000
--- a/xml/src/main/java/org/w3c/dom/views/AbstractView.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.views;
-
-/**
- * A base interface that all views shall derive from.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Views-20001113'>Document Object Model (DOM) Level 2 Views Specification</a>.
- * @since DOM Level 2
- */
-public interface AbstractView {
- /**
- * The source <code>DocumentView</code> of which this is an
- * <code>AbstractView</code>.
- */
- public DocumentView getDocument();
-
-}
diff --git a/xml/src/main/java/org/w3c/dom/views/DocumentView.java b/xml/src/main/java/org/w3c/dom/views/DocumentView.java
deleted file mode 100644
index 2cb9eeb..0000000
--- a/xml/src/main/java/org/w3c/dom/views/DocumentView.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2000 World Wide Web Consortium,
- * (Massachusetts Institute of Technology, Institut National de
- * Recherche en Informatique et en Automatique, Keio University). All
- * Rights Reserved. This program is distributed under the W3C's Software
- * Intellectual Property License. This program is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.
- * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
- */
-
-package org.w3c.dom.views;
-
-/**
- * The <code>DocumentView</code> interface is implemented by
- * <code>Document</code> objects in DOM implementations supporting DOM
- * Views. It provides an attribute to retrieve the default view of a
- * document.
- * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Views-20001113'>Document Object Model (DOM) Level 2 Views Specification</a>.
- * @since DOM Level 2
- */
-public interface DocumentView {
- /**
- * The default <code>AbstractView</code> for this <code>Document</code>,
- * or <code>null</code> if none available.
- */
- public AbstractView getDefaultView();
-
-}
diff --git a/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java b/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
index da37c45..3f0d2cb 100644
--- a/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
+++ b/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
@@ -22,15 +22,16 @@ import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.w3c.dom.Attr;
-import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
-import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
@@ -38,17 +39,25 @@ import org.xmlpull.v1.XmlSerializer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.ErrorListener;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -60,13 +69,23 @@ import java.util.List;
* XSLT conformance test suite</a>, adapted for use by JUnit. To run these tests
* on a device:
* <ul>
- * <li>Obtain the <a href="http://www.oasis-open.org/committees/download.php/12171/XSLT-testsuite-04.ZIP">test
- * suite zip file from the OASIS project site.</li>
- * <li>Unzip.
- * <li>Copy the files to a device: <code>adb shell mkdir /data/oasis ;
- * adb push ./XSLT-Conformance-TC /data/oasis</code>.
- * <li>Invoke this class' main method, passing the on-device path to the test
- * suite's <code>catalog.xml</code> file as an argument.
+ * <li>Obtain the <a href="http://www.oasis-open.org/committees/download.php/12171/XSLT-testsuite-04.ZIP">test
+ * suite zip file from the OASIS project site.</li>
+ * <li>Unzip.
+ * <li>Copy the files to a device: <code>adb shell mkdir /data/oasis ;
+ * adb push ./XSLT-Conformance-TC /data/oasis</code>.
+ * <li>Invoke this class' main method, passing the on-device path to the test
+ * suite's <code>catalog.xml</code> file as an argument.
+ * </ul>
+ *
+ * <p>Unfortunately, some of the tests in the OASIS suite will fail when
+ * executed outside of their original development environment:
+ * <ul>
+ * <li>The tests assume case insensitive filesystems. Some will fail with
+ * "Couldn't open file" errors due to a mismatch in file name casing.
+ * <li>The tests assume certain network hosts will exist and serve
+ * stylesheet files. In particular, "http://webxtest/" isn't generally
+ * available.
* </ul>
*/
public class XsltXPathConformanceTestSuite {
@@ -77,7 +96,7 @@ public class XsltXPathConformanceTestSuite {
/** Orders element attributes by optional URI and name. */
private static final Comparator<Attr> orderByName = new Comparator<Attr>() {
public int compare(Attr a, Attr b) {
- int result = compareNullsFirst(a.getBaseURI(), b.getBaseURI());
+ int result = compareNullsFirst(a.getNamespaceURI(), b.getNamespaceURI());
return result == 0 ? result
: compareNullsFirst(a.getName(), b.getName());
}
@@ -163,7 +182,7 @@ public class XsltXPathConformanceTestSuite {
/**
* Returns a JUnit test for the test described by the given element.
*/
- private Test create(File base, Element testCaseElement) {
+ private TestCase create(File base, Element testCaseElement) {
/*
* Extract the XSLT test from a DOM entity with the following structure:
@@ -290,7 +309,6 @@ public class XsltXPathConformanceTestSuite {
* the result to an expected output file.
*/
public class XsltTest extends TestCase {
- // TODO: include these in toString
private final String category;
private final String id;
private final String purpose;
@@ -303,7 +321,10 @@ public class XsltXPathConformanceTestSuite {
/** either "standard" or "execution-error" */
private final String operation;
- /** the syntax to compare the output file using, such as "XML" or "HTML" */
+ /**
+ * The syntax to compare the output file using, such as "XML", "HTML",
+ * "manual", or null for expected execution errors.
+ */
private final String compareAs;
XsltTest(String category, String id, String purpose, String spec,
@@ -321,6 +342,11 @@ public class XsltXPathConformanceTestSuite {
this.compareAs = compareAs;
}
+ XsltTest(File principalData, File principalStylesheet, File principal) {
+ this("standalone", "test", "", "",
+ principalData, principalStylesheet, principal, "standard", "XML");
+ }
+
public void test() throws Exception {
if (purpose != null) {
System.out.println("Purpose: " + purpose);
@@ -329,37 +355,50 @@ public class XsltXPathConformanceTestSuite {
System.out.println("Spec: " + spec);
}
- Source xslt = new StreamSource(principalStylesheet);
- Source in = new StreamSource(principalData);
+ Result result;
+ if ("XML".equals(compareAs)) {
+ DOMResult domResult = new DOMResult();
+ domResult.setNode(documentBuilder.newDocument().createElementNS("", "result"));
+ result = domResult;
+ } else {
+ result = new StreamResult(new StringWriter());
+ }
+
+ ErrorRecorder errorRecorder = new ErrorRecorder();
+ transformerFactory.setErrorListener(errorRecorder);
Transformer transformer;
try {
+ Source xslt = new StreamSource(principalStylesheet);
transformer = transformerFactory.newTransformer(xslt);
- assertEquals("Expected transformer creation to fail",
- "standard", operation);
+ if (errorRecorder.error == null) {
+ transformer.setErrorListener(errorRecorder);
+ transformer.transform(new StreamSource(principalData), result);
+ }
} catch (TransformerConfigurationException e) {
- if (operation.equals("execution-error")) {
- return; // expected, such as in XSLT-Result-Tree.Attributes__78369
+ errorRecorder.fatalError(e);
+ }
+
+ if (operation.equals("standard")) {
+ if (errorRecorder.error != null) {
+ throw errorRecorder.error;
}
- AssertionFailedError failure = new AssertionFailedError();
- failure.initCause(e);
- throw failure;
+ } else if (operation.equals("execution-error")) {
+ if (errorRecorder.error != null) {
+ return;
+ }
+ fail("Expected " + operation + ", but transform completed normally."
+ + " (Warning=" + errorRecorder.warning + ")");
+ } else {
+ throw new UnsupportedOperationException("Unexpected operation: " + operation);
}
- Result result;
- if (compareAs.equals("XML")) {
- result = new DOMResult();
+ if ("XML".equals(compareAs)) {
+ assertNodesAreEquivalent(principal, ((DOMResult) result).getNode());
} else {
// TODO: implement support for comparing HTML etc.
throw new UnsupportedOperationException("Cannot compare as " + compareAs);
}
-
- transformer.transform(in, result);
-
- if (compareAs.equals("XML")) {
- DOMResult domResult = (DOMResult) result;
- assertNodesAreEquivalent(principal, domResult.getNode());
- }
}
@Override public String getName() {
@@ -370,19 +409,65 @@ public class XsltXPathConformanceTestSuite {
/**
* Ensures both XML documents represent the same semantic data. Non-semantic
* data such as namespace prefixes, comments, and whitespace is ignored.
+ *
+ * @param actual an XML document whose root is a {@code <result>} element.
+ * @param expected a file containing an XML document fragment.
*/
private void assertNodesAreEquivalent(File expected, Node actual)
throws ParserConfigurationException, IOException, SAXException,
XmlPullParserException {
- Document expectedDocument = documentBuilder.parse(new FileInputStream(expected));
- String expectedString = nodeToNormalizedString(expectedDocument);
+ Node expectedNode = fileToResultNode(expected);
+ String expectedString = nodeToNormalizedString(expectedNode);
String actualString = nodeToNormalizedString(actual);
Assert.assertEquals("Expected XML to match file " + expected,
expectedString, actualString);
}
+ /**
+ * Returns the given file's XML fragment as a single node, wrapped in
+ * {@code <result>} tags. This takes care of normalizing the following
+ * conditions:
+ *
+ * <ul>
+ * <li>Files containing XML document fragments with multiple elements:
+ * {@code <SPAN style="color=blue">Smurfs!</SPAN><br />}
+ *
+ * <li>Files containing XML document fragments with no elements:
+ * {@code Smurfs!}
+ *
+ * <li>Files containing proper XML documents with a single element and an
+ * XML declaration:
+ * {@code <?xml version="1.0"?><doc />}
+ *
+ * <li>Files prefixed with a byte order mark header, such as 0xEFBBBF.
+ * </ul>
+ */
+ private Node fileToResultNode(File file) throws IOException, SAXException {
+ String rawContents = fileToString(file);
+ String fragment = rawContents;
+
+ // If the file had an XML declaration, strip that. Otherwise wrapping
+ // it in <result> tags would result in a malformed XML document.
+ if (fragment.startsWith("<?xml")) {
+ int declarationEnd = fragment.indexOf("?>");
+ fragment = fragment.substring(declarationEnd + 2);
+ }
+
+ // Parse it as document fragment wrapped in <result> tags.
+ try {
+ fragment = "<result>" + fragment + "</result>";
+ return documentBuilder.parse(new InputSource(new StringReader(fragment)))
+ .getDocumentElement();
+ } catch (SAXParseException e) {
+ Error error = new AssertionFailedError(
+ "Failed to parse XML: " + file + "\n" + rawContents);
+ error.initCause(e);
+ throw error;
+ }
+ }
+
private String nodeToNormalizedString(Node node)
throws XmlPullParserException, IOException {
StringWriter writer = new StringWriter();
@@ -395,14 +480,18 @@ public class XsltXPathConformanceTestSuite {
}
private void emitNode(XmlSerializer serializer, Node node) throws IOException {
- if (node instanceof Element) {
+ if (node == null) {
+ throw new UnsupportedOperationException("Cannot emit null nodes");
+
+ } else if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
- serializer.startTag(element.getBaseURI(), element.getLocalName());
+ serializer.startTag(element.getNamespaceURI(), element.getLocalName());
emitAttributes(serializer, element);
emitChildren(serializer, element);
- serializer.endTag(element.getBaseURI(), element.getLocalName());
+ serializer.endTag(element.getNamespaceURI(), element.getLocalName());
- } else if (node instanceof Text) {
+ } else if (node.getNodeType() == Node.TEXT_NODE
+ || node.getNodeType() == Node.CDATA_SECTION_NODE) {
// TODO: is it okay to trim whitespace in general? This may cause
// false positives for elements like HTML's <pre> tag
String trimmed = node.getTextContent().trim();
@@ -410,25 +499,28 @@ public class XsltXPathConformanceTestSuite {
serializer.text(trimmed);
}
- } else if (node instanceof Document) {
+ } else if (node.getNodeType() == Node.DOCUMENT_NODE) {
Document document = (Document) node;
serializer.startDocument("UTF-8", true);
emitNode(serializer, document.getDocumentElement());
serializer.endDocument();
- } else if (node instanceof ProcessingInstruction) {
+ } else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
ProcessingInstruction processingInstruction = (ProcessingInstruction) node;
String data = processingInstruction.getData();
String target = processingInstruction.getTarget();
serializer.processingInstruction(target + " " + data);
- } else if (node instanceof Comment) {
+ } else if (node.getNodeType() == Node.COMMENT_NODE) {
// ignore!
+ } else if (node.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ EntityReference entityReference = (EntityReference) node;
+ serializer.entityRef(entityReference.getNodeName());
+
} else {
- Object nodeClass = node != null ? node.getClass() : null;
throw new UnsupportedOperationException(
- "Cannot serialize nodes of type " + nodeClass);
+ "Cannot emit " + node + " of type " + node.getNodeType());
}
}
@@ -457,7 +549,7 @@ public class XsltXPathConformanceTestSuite {
* generate one for us, using a predictable pattern.
*/
} else {
- serializer.attribute(attr.getBaseURI(), attr.getLocalName(), attr.getValue());
+ serializer.attribute(attr.getNamespaceURI(), attr.getLocalName(), attr.getValue());
}
}
}
@@ -480,4 +572,64 @@ public class XsltXPathConformanceTestSuite {
}
return result;
}
+
+ /**
+ * Reads the given file into a string. If the file contains a byte order
+ * mark, the corresponding character set will be used. Otherwise the system
+ * default charset will be used.
+ */
+ private String fileToString(File file) throws IOException {
+ InputStream in = new BufferedInputStream(new FileInputStream(file), 1024);
+
+ // Read the byte order mark to determine the charset.
+ // TODO: use a built-in API for this...
+ Reader reader;
+ in.mark(3);
+ int byte1 = in.read();
+ int byte2 = in.read();
+ if (byte1 == 0xFF && byte2 == 0xFE) {
+ reader = new InputStreamReader(in, "UTF-16LE");
+ } else if (byte1 == 0xFF && byte2 == 0xFF) {
+ reader = new InputStreamReader(in, "UTF-16BE");
+ } else {
+ int byte3 = in.read();
+ if (byte1 == 0xEF && byte2 == 0xBB && byte3 == 0xBF) {
+ reader = new InputStreamReader(in, "UTF-8");
+ } else {
+ in.reset();
+ reader = new InputStreamReader(in);
+ }
+ }
+
+ StringWriter out = new StringWriter();
+ char[] buffer = new char[1024];
+ int count;
+ while ((count = reader.read(buffer)) != -1) {
+ out.write(buffer, 0, count);
+ }
+ return out.toString();
+ }
+
+ static class ErrorRecorder implements ErrorListener {
+ Exception warning;
+ Exception error;
+
+ public void warning(TransformerException exception) {
+ if (this.warning == null) {
+ this.warning = exception;
+ }
+ }
+
+ public void error(TransformerException exception) {
+ if (this.error == null) {
+ this.error = exception;
+ }
+ }
+
+ public void fatalError(TransformerException exception) {
+ if (this.error == null) {
+ this.error = exception;
+ }
+ }
+ }
}
diff --git a/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java b/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java
index 7318ad0..cfa62dc 100644
--- a/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java
+++ b/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java
@@ -34,6 +34,7 @@ import org.xml.sax.SAXParseException;
import tests.api.org.xml.sax.support.MethodLogger;
import tests.api.org.xml.sax.support.MockHandler;
import tests.api.org.xml.sax.support.MockResolver;
+import tests.support.resource.Support_Resources;
import tests.util.TestEnvironment;
import javax.xml.parsers.DocumentBuilder;
@@ -41,8 +42,6 @@ import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -271,7 +270,7 @@ public class DocumentBuilderTest extends TestCase {
args = {java.io.File.class}
)
public void testGetBaseURI() throws IOException, SAXException {
- File f = resourceToTmpFile("/simple.xml");
+ File f = Support_Resources.resourceToTempFile("/simple.xml");
Document d = db.parse(f);
assertTrue(d.getDocumentElement().getBaseURI().startsWith("file://"));
}
@@ -290,7 +289,7 @@ public class DocumentBuilderTest extends TestCase {
args = {java.io.File.class}
)
public void test_parseLjava_io_File() throws IOException {
- File f = resourceToTmpFile("/simple.xml");
+ File f = Support_Resources.resourceToTempFile("/simple.xml");
// case 1: Trivial use.
try {
@@ -332,7 +331,7 @@ public class DocumentBuilderTest extends TestCase {
}
// case 4: Try to parse incorrect xml file
- f = resourceToTmpFile("/wrong.xml");
+ f = Support_Resources.resourceToTempFile("/wrong.xml");
try {
db.parse(f);
fail("Expected SAXException was not thrown");
@@ -343,22 +342,6 @@ public class DocumentBuilderTest extends TestCase {
}
}
- private File resourceToTmpFile(String path) throws IOException,
- FileNotFoundException {
- File f = File.createTempFile("out", ".xml");
- f.deleteOnExit();
- FileOutputStream out = new FileOutputStream(f);
-
- InputStream xml = getClass().getResourceAsStream(path);
- while (xml.available() > 0) {
- out.write(xml.read());
- }
- out.flush();
- out.close();
- xml.close();
- return f;
- }
-
/**
* @tests javax.xml.parsers.DocumentBuilder#parse(java.io.InputStream)
* Case 1: Try to parse correct xml document.
diff --git a/xml/src/test/java/tests/xml/AllTests.java b/xml/src/test/java/tests/xml/AllTests.java
index 8a4b4a9..0042967 100644
--- a/xml/src/test/java/tests/xml/AllTests.java
+++ b/xml/src/test/java/tests/xml/AllTests.java
@@ -26,7 +26,7 @@ public class AllTests {
suite.addTestSuite(SimpleParserTest.class);
suite.addTestSuite(SimpleBuilderTest.class);
- suite.addTestSuite(NodeTests.class);
+ suite.addTestSuite(NodeTest.class);
//suite.addTest(tests.org.w3c.dom.AllTests.suite());
suite.addTest(tests.api.javax.xml.parsers.AllTests.suite());
diff --git a/xml/src/test/java/tests/xml/DomTest.java b/xml/src/test/java/tests/xml/DomTest.java
new file mode 100644
index 0000000..5f0a19a
--- /dev/null
+++ b/xml/src/test/java/tests/xml/DomTest.java
@@ -0,0 +1,623 @@
+/*
+ * Copyright (C) 2010 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 tests.xml;
+
+import junit.framework.TestCase;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Entity;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Node;
+import org.w3c.dom.Notation;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Construct a DOM and then interrogate it.
+ */
+public class DomTest extends TestCase {
+
+ private Transformer transformer;
+ private DocumentBuilder builder;
+ private DOMImplementation domImplementation;
+
+ private final String xml
+ = "<!DOCTYPE menu ["
+ + " <!ENTITY sp \"Maple Syrup\">"
+ + " <!NOTATION png SYSTEM \"image/png\">"
+ + "]>"
+ + "<menu>\n"
+ + " <item xmlns=\"http://food\" xmlns:a=\"http://addons\">\n"
+ + " <name a:standard=\"strawberry\" deluxe=\"&sp;\">Waffles</name>\n"
+ + " <description xmlns=\"http://marketing\">Belgian<![CDATA[ waffles & strawberries (< 5g ]]>of fat)</description>\n"
+ + " <a:option>Whipped Cream</a:option>\n"
+ + " <a:option>&sp;</a:option>\n"
+ + " <?wafflemaker square shape?>\n"
+ + " <nutrition>\n"
+ + " <a:vitamins xmlns:a=\"http://usda\">\n"
+ + " <!-- add other vitamins? --> \n"
+ + " <a:vitaminc>60%</a:vitaminc>\n"
+ + " </a:vitamins>\n"
+ + " </nutrition>\n"
+ + " </item>\n"
+ + "</menu>";
+
+ private Document document;
+ private DocumentType doctype;
+ private Entity sp;
+ private Notation png;
+ private Element menu;
+ private Element item;
+ private Attr itemXmlns;
+ private Attr itemXmlnsA;
+ private Element name;
+ private Attr standard;
+ private Attr deluxe;
+ private Element description;
+ private Text descriptionText1;
+ private CDATASection descriptionText2;
+ private Text descriptionText3;
+ private Element option1;
+ private Element option2;
+ private Node option2Reference; // resolved to Text on RI, an EntityReference on Dalvik
+ private ProcessingInstruction wafflemaker;
+ private Element nutrition;
+ private Element vitamins;
+ private Attr vitaminsXmlnsA;
+ private Comment comment;
+ private Element vitaminc;
+ private Text vitamincText;
+ private List<Node> allNodes;
+
+ @Override protected void setUp() throws Exception {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ builder = factory.newDocumentBuilder();
+ domImplementation = builder.getDOMImplementation();
+
+ document = builder.parse(new InputSource(new StringReader(xml)));
+
+ // doctype nodes
+ doctype = document.getDoctype();
+ if (doctype.getEntities() != null) {
+ sp = (Entity) doctype.getEntities().item(0);
+ }
+ if (doctype.getNotations() != null) {
+ png = (Notation) doctype.getNotations().item(0);
+ }
+
+ // document nodes
+ menu = document.getDocumentElement();
+ item = (Element) menu.getChildNodes().item(1);
+ itemXmlns = item.getAttributeNode("xmlns");
+ itemXmlnsA = item.getAttributeNode("xmlns:a");
+ name = (Element) item.getChildNodes().item(1);
+ standard = name.getAttributeNode("a:standard");
+ deluxe = name.getAttributeNode("deluxe");
+ description = (Element) item.getChildNodes().item(3);
+ descriptionText1 = (Text) description.getChildNodes().item(0);
+ descriptionText2 = (CDATASection) description.getChildNodes().item(1);
+ descriptionText3 = (Text) description.getChildNodes().item(2);
+ option1 = (Element) item.getChildNodes().item(5);
+ option2 = (Element) item.getChildNodes().item(7);
+ option2Reference = option2.getChildNodes().item(0);
+ wafflemaker = (ProcessingInstruction) item.getChildNodes().item(9);
+ nutrition = (Element) item.getChildNodes().item(11);
+ vitamins = (Element) nutrition.getChildNodes().item(1);
+ vitaminsXmlnsA = vitamins.getAttributeNode("xmlns:a");
+ comment = (Comment) vitamins.getChildNodes().item(1);
+ vitaminc = (Element) vitamins.getChildNodes().item(3);
+ vitamincText = (Text) vitaminc.getChildNodes().item(0);
+
+ allNodes = new ArrayList<Node>();
+
+ if (sp != null) {
+ allNodes.add(sp);
+ }
+ if (png != null) {
+ allNodes.add(png);
+ }
+
+ allNodes.addAll(Arrays.asList(document, doctype, menu, item, itemXmlns,
+ itemXmlnsA, name, standard, deluxe, description,
+ descriptionText1, descriptionText2, descriptionText3, option1,
+ option2, option2Reference, wafflemaker, nutrition, vitamins,
+ vitaminsXmlnsA, comment, vitaminc, vitamincText));
+ }
+
+ /**
+ * Android's parsed DOM doesn't include entity declarations. These nodes will
+ * only be tested for implementations that support them.
+ */
+ public void testEntityDeclarations() {
+ assertNotNull("This implementation does not parse entity declarations", sp);
+ }
+
+ /**
+ * Android's parsed DOM doesn't include notations. These nodes will only be
+ * tested for implementations that support them.
+ */
+ public void testNotations() {
+ assertNotNull("This implementation does not parse notations", png);
+ }
+
+ public void testLookupNamespaceURIByPrefix() {
+ assertEquals(null, doctype.lookupNamespaceURI("a"));
+ if (sp != null) {
+ assertEquals(null, sp.lookupNamespaceURI("a"));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupNamespaceURI("a"));
+ }
+ assertEquals(null, document.lookupNamespaceURI("a"));
+ assertEquals(null, menu.lookupNamespaceURI("a"));
+ assertEquals("http://addons", item.lookupNamespaceURI("a"));
+ assertEquals("http://addons", itemXmlns.lookupNamespaceURI("a"));
+ assertEquals("http://addons", itemXmlnsA.lookupNamespaceURI("a"));
+ assertEquals("http://addons", name.lookupNamespaceURI("a"));
+ assertEquals("http://addons", standard.lookupNamespaceURI("a"));
+ assertEquals("http://addons", deluxe.lookupNamespaceURI("a"));
+ assertEquals("http://addons", description.lookupNamespaceURI("a"));
+ assertEquals("http://addons", descriptionText1.lookupNamespaceURI("a"));
+ assertEquals("http://addons", descriptionText2.lookupNamespaceURI("a"));
+ assertEquals("http://addons", descriptionText3.lookupNamespaceURI("a"));
+ assertEquals("http://addons", option1.lookupNamespaceURI("a"));
+ assertEquals("http://addons", option2.lookupNamespaceURI("a"));
+ assertEquals("http://addons", option2Reference.lookupNamespaceURI("a"));
+ assertEquals("http://addons", wafflemaker.lookupNamespaceURI("a"));
+ assertEquals("http://addons", nutrition.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitamins.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitaminsXmlnsA.lookupNamespaceURI("a"));
+ assertEquals("http://usda", comment.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitaminc.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitamincText.lookupNamespaceURI("a"));
+ }
+
+ public void testLookupNamespaceURIWithNullPrefix() {
+ assertEquals(null, document.lookupNamespaceURI(null));
+ assertEquals(null, doctype.lookupNamespaceURI(null));
+ if (sp != null) {
+ assertEquals(null, sp.lookupNamespaceURI(null));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupNamespaceURI(null));
+ }
+ assertEquals(null, menu.lookupNamespaceURI(null));
+ assertEquals("http://food", item.lookupNamespaceURI(null));
+ assertEquals("http://food", itemXmlns.lookupNamespaceURI(null));
+ assertEquals("http://food", itemXmlnsA.lookupNamespaceURI(null));
+ assertEquals("http://food", name.lookupNamespaceURI(null));
+ assertEquals("http://food", standard.lookupNamespaceURI(null));
+ assertEquals("http://food", deluxe.lookupNamespaceURI(null));
+ assertEquals("http://marketing", description.lookupNamespaceURI(null));
+ assertEquals("http://marketing", descriptionText1.lookupNamespaceURI(null));
+ assertEquals("http://marketing", descriptionText2.lookupNamespaceURI(null));
+ assertEquals("http://marketing", descriptionText3.lookupNamespaceURI(null));
+ assertEquals("http://food", option1.lookupNamespaceURI(null));
+ assertEquals("http://food", option2.lookupNamespaceURI(null));
+ assertEquals("http://food", option2Reference.lookupNamespaceURI(null));
+ assertEquals("http://food", wafflemaker.lookupNamespaceURI(null));
+ assertEquals("http://food", nutrition.lookupNamespaceURI(null));
+ assertEquals("http://food", vitamins.lookupNamespaceURI(null));
+ assertEquals("http://food", vitaminsXmlnsA.lookupNamespaceURI(null));
+ assertEquals("http://food", comment.lookupNamespaceURI(null));
+ assertEquals("http://food", vitaminc.lookupNamespaceURI(null));
+ assertEquals("http://food", vitamincText.lookupNamespaceURI(null));
+ }
+
+ public void testLookupNamespaceURIWithXmlnsPrefix() {
+ for (Node node : allNodes) {
+ assertEquals(null, node.lookupNamespaceURI("xmlns"));
+ }
+ }
+
+ public void testLookupPrefixWithShadowedUri() {
+ assertEquals(null, document.lookupPrefix("http://addons"));
+ assertEquals(null, doctype.lookupPrefix("http://addons"));
+ if (sp != null) {
+ assertEquals(null, sp.lookupPrefix("http://addons"));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupPrefix("http://addons"));
+ }
+ assertEquals(null, menu.lookupPrefix("http://addons"));
+ assertEquals("a", item.lookupPrefix("http://addons"));
+ assertEquals("a", itemXmlns.lookupPrefix("http://addons"));
+ assertEquals("a", itemXmlnsA.lookupPrefix("http://addons"));
+ assertEquals("a", name.lookupPrefix("http://addons"));
+ assertEquals("a", standard.lookupPrefix("http://addons"));
+ assertEquals("a", deluxe.lookupPrefix("http://addons"));
+ assertEquals("a", description.lookupPrefix("http://addons"));
+ assertEquals("a", descriptionText1.lookupPrefix("http://addons"));
+ assertEquals("a", descriptionText2.lookupPrefix("http://addons"));
+ assertEquals("a", descriptionText3.lookupPrefix("http://addons"));
+ assertEquals("a", option1.lookupPrefix("http://addons"));
+ assertEquals("a", option2.lookupPrefix("http://addons"));
+ assertEquals("a", option2Reference.lookupPrefix("http://addons"));
+ assertEquals("a", wafflemaker.lookupPrefix("http://addons"));
+ assertEquals("a", nutrition.lookupPrefix("http://addons"));
+ assertEquals(null, vitamins.lookupPrefix("http://addons"));
+ assertEquals(null, vitaminsXmlnsA.lookupPrefix("http://addons"));
+ assertEquals(null, comment.lookupPrefix("http://addons"));
+ assertEquals(null, vitaminc.lookupPrefix("http://addons"));
+ assertEquals(null, vitamincText.lookupPrefix("http://addons"));
+ }
+
+ public void testLookupPrefixWithUnusedUri() {
+ for (Node node : allNodes) {
+ assertEquals(null, node.lookupPrefix("http://unused"));
+ }
+ }
+
+ public void testLookupPrefixWithNullUri() {
+ for (Node node : allNodes) {
+ assertEquals(null, node.lookupPrefix(null));
+ }
+ }
+
+ public void testLookupPrefixWithShadowingUri() {
+ assertEquals(null, document.lookupPrefix("http://usda"));
+ assertEquals(null, doctype.lookupPrefix("http://usda"));
+ if (sp != null) {
+ assertEquals(null, sp.lookupPrefix("http://usda"));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupPrefix("http://usda"));
+ }
+ assertEquals(null, menu.lookupPrefix("http://usda"));
+ assertEquals(null, item.lookupPrefix("http://usda"));
+ assertEquals(null, itemXmlns.lookupPrefix("http://usda"));
+ assertEquals(null, itemXmlnsA.lookupPrefix("http://usda"));
+ assertEquals(null, name.lookupPrefix("http://usda"));
+ assertEquals(null, standard.lookupPrefix("http://usda"));
+ assertEquals(null, deluxe.lookupPrefix("http://usda"));
+ assertEquals(null, description.lookupPrefix("http://usda"));
+ assertEquals(null, descriptionText1.lookupPrefix("http://usda"));
+ assertEquals(null, descriptionText2.lookupPrefix("http://usda"));
+ assertEquals(null, descriptionText3.lookupPrefix("http://usda"));
+ assertEquals(null, option1.lookupPrefix("http://usda"));
+ assertEquals(null, option2.lookupPrefix("http://usda"));
+ assertEquals(null, option2Reference.lookupPrefix("http://usda"));
+ assertEquals(null, wafflemaker.lookupPrefix("http://usda"));
+ assertEquals(null, nutrition.lookupPrefix("http://usda"));
+ assertEquals("a", vitamins.lookupPrefix("http://usda"));
+ assertEquals("a", vitaminsXmlnsA.lookupPrefix("http://usda"));
+ assertEquals("a", comment.lookupPrefix("http://usda"));
+ assertEquals("a", vitaminc.lookupPrefix("http://usda"));
+ assertEquals("a", vitamincText.lookupPrefix("http://usda"));
+ }
+
+ public void testIsDefaultNamespace() {
+ assertFalse(document.isDefaultNamespace("http://food"));
+ assertFalse(doctype.isDefaultNamespace("http://food"));
+ if (sp != null) {
+ assertFalse(sp.isDefaultNamespace("http://food"));
+ }
+ if (png != null) {
+ assertFalse(png.isDefaultNamespace("http://food"));
+ }
+ assertFalse(menu.isDefaultNamespace("http://food"));
+ assertTrue(item.isDefaultNamespace("http://food"));
+ assertTrue(itemXmlns.isDefaultNamespace("http://food"));
+ assertTrue(itemXmlnsA.isDefaultNamespace("http://food"));
+ assertTrue(name.isDefaultNamespace("http://food"));
+ assertTrue(standard.isDefaultNamespace("http://food"));
+ assertTrue(deluxe.isDefaultNamespace("http://food"));
+ assertFalse(description.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText1.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText2.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText3.isDefaultNamespace("http://food"));
+ assertTrue(option1.isDefaultNamespace("http://food"));
+ assertTrue(option2.isDefaultNamespace("http://food"));
+ assertTrue(option2Reference.isDefaultNamespace("http://food"));
+ assertTrue(wafflemaker.isDefaultNamespace("http://food"));
+ assertTrue(nutrition.isDefaultNamespace("http://food"));
+ assertTrue(vitamins.isDefaultNamespace("http://food"));
+ assertTrue(vitaminsXmlnsA.isDefaultNamespace("http://food"));
+ assertTrue(comment.isDefaultNamespace("http://food"));
+ assertTrue(vitaminc.isDefaultNamespace("http://food"));
+ assertTrue(vitamincText.isDefaultNamespace("http://food"));
+ }
+
+ /**
+ * Xerces fails this test. It returns false always for entity, notation,
+ * document fragment and document type nodes. This contradicts its own
+ * behaviour on lookupNamespaceURI(null).
+ */
+ public void testIsDefaultNamespaceNull_XercesBugs() {
+ String message = "isDefaultNamespace() should be consistent with lookupNamespaceURI(null)";
+ assertTrue(message, doctype.isDefaultNamespace(null));
+ if (sp != null) {
+ assertTrue(message, sp.isDefaultNamespace(null));
+ }
+ if (png != null) {
+ assertTrue(message, png.isDefaultNamespace(null));
+ }
+ }
+
+ public void testIsDefaultNamespaceNull() {
+ assertTrue(document.isDefaultNamespace(null));
+ assertTrue(menu.isDefaultNamespace(null));
+ assertFalse(item.isDefaultNamespace(null));
+ assertFalse(itemXmlns.isDefaultNamespace(null));
+ assertFalse(itemXmlnsA.isDefaultNamespace(null));
+ assertFalse(name.isDefaultNamespace(null));
+ assertFalse(standard.isDefaultNamespace(null));
+ assertFalse(deluxe.isDefaultNamespace(null));
+ assertFalse(description.isDefaultNamespace(null));
+ assertFalse(descriptionText1.isDefaultNamespace(null));
+ assertFalse(descriptionText2.isDefaultNamespace(null));
+ assertFalse(descriptionText3.isDefaultNamespace(null));
+ assertFalse(option1.isDefaultNamespace(null));
+ assertFalse(option2.isDefaultNamespace(null));
+ assertFalse(option2Reference.isDefaultNamespace(null));
+ assertFalse(wafflemaker.isDefaultNamespace(null));
+ assertFalse(nutrition.isDefaultNamespace(null));
+ assertFalse(vitamins.isDefaultNamespace(null));
+ assertFalse(vitaminsXmlnsA.isDefaultNamespace(null));
+ assertFalse(comment.isDefaultNamespace(null));
+ assertFalse(vitaminc.isDefaultNamespace(null));
+ assertFalse(vitamincText.isDefaultNamespace(null));
+ }
+
+ public void testDoctypeSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ doctype.setTextContent("foobar"); // strangely, this is specified to no-op
+ assertEquals(original, domToString(document));
+ }
+
+ public void testDocumentSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ document.setTextContent("foobar"); // strangely, this is specified to no-op
+ assertEquals(original, domToString(document));
+ }
+
+ public void testElementSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ nutrition.setTextContent("foobar");
+ String expected = original.replaceFirst(
+ "(?s)<nutrition>.*</nutrition>", "<nutrition>foobar</nutrition>");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testEntitySetTextContent() throws TransformerException {
+ if (sp == null) {
+ return;
+ }
+ try {
+ sp.setTextContent("foobar");
+ fail(); // is this implementation-specific behaviour?
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testNotationSetTextContent() throws TransformerException {
+ if (png == null) {
+ return;
+ }
+ String original = domToString(document);
+ png.setTextContent("foobar");
+ String expected = original.replace("image/png", "foobar");
+ assertEquals(expected, domToString(document));
+ }
+
+ /**
+ * Tests setTextContent on entity references. Although the other tests can
+ * act on a parsed DOM, this needs to use a programmatically constructed DOM
+ * because the parser may have replaced the entity reference with the
+ * corresponding text.
+ */
+ public void testEntityReferenceSetTextContent() throws TransformerException {
+ document = builder.newDocument();
+ Element root = document.createElement("menu");
+ document.appendChild(root);
+
+ EntityReference entityReference = document.createEntityReference("sp");
+ entityReference.setNodeValue("Maple Syrup");
+ root.appendChild(entityReference);
+
+ try {
+ entityReference.setTextContent("Lite Syrup");
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testAttributeSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ standard.setTextContent("foobar");
+ String expected = original.replaceFirst(
+ "standard=\"strawberry\"", "standard=\"foobar\"");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testTextSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ descriptionText1.setTextContent("foobar");
+ String expected = original.replace(">Belgian<!", ">foobar<!");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testCdataSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ descriptionText2.setTextContent("foobar");
+ String expected = original.replace(
+ " waffles & strawberries (< 5g ", "foobar");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testProcessingInstructionSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ wafflemaker.setTextContent("foobar");
+ String expected = original.replace(" square shape?>", " foobar?>");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testCommentSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ comment.setTextContent("foobar");
+ String expected = original.replace("-- add other vitamins? --", "--foobar--");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testCoreFeature() {
+ assertTrue(domImplementation.hasFeature("Core", null));
+ assertTrue(domImplementation.hasFeature("Core", ""));
+ assertTrue(domImplementation.hasFeature("Core", "1.0"));
+ assertTrue(domImplementation.hasFeature("Core", "2.0"));
+ assertTrue(domImplementation.hasFeature("Core", "3.0"));
+ assertTrue(domImplementation.hasFeature("CORE", "3.0"));
+ assertTrue(domImplementation.hasFeature("+Core", "3.0"));
+ assertFalse(domImplementation.hasFeature("Core", "4.0"));
+ }
+
+ public void testXmlFeature() {
+ assertTrue(domImplementation.hasFeature("XML", null));
+ assertTrue(domImplementation.hasFeature("XML", ""));
+ assertTrue(domImplementation.hasFeature("XML", "1.0"));
+ assertTrue(domImplementation.hasFeature("XML", "2.0"));
+ assertTrue(domImplementation.hasFeature("XML", "3.0"));
+ assertTrue(domImplementation.hasFeature("Xml", "3.0"));
+ assertTrue(domImplementation.hasFeature("+XML", "3.0"));
+ assertFalse(domImplementation.hasFeature("XML", "4.0"));
+ }
+
+ /**
+ * The RI fails this test.
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Document3-version
+ */
+ public void testXmlVersionFeature() {
+ String message = "This implementation does not support the XMLVersion feature";
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", null));
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", ""));
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", "1.0"));
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", "1.1"));
+ assertTrue(message, domImplementation.hasFeature("XMLVERSION", "1.1"));
+ assertTrue(message, domImplementation.hasFeature("+XMLVersion", "1.1"));
+ assertFalse(domImplementation.hasFeature("XMLVersion", "1.2"));
+ assertFalse(domImplementation.hasFeature("XMLVersion", "2.0"));
+ assertFalse(domImplementation.hasFeature("XMLVersion", "2.0"));
+ }
+
+ public void testLsFeature() {
+ assertTrue("This implementation does not support the LS feature",
+ domImplementation.hasFeature("LS", "3.0"));
+ }
+
+ public void testElementTraversalFeature() {
+ assertTrue("This implementation does not support the ElementTraversal feature",
+ domImplementation.hasFeature("ElementTraversal", "1.0"));
+ }
+
+ public void testIsSupported() {
+ // we don't independently test the features; instead just assume the
+ // implementation calls through to hasFeature (as tested above)
+ for (Node node : allNodes) {
+ assertTrue(node.isSupported("XML", null));
+ assertTrue(node.isSupported("XML", "3.0"));
+ assertFalse(node.isSupported("foo", null));
+ assertFalse(node.isSupported("foo", "bar"));
+ }
+ }
+
+ public void testGetFeature() {
+ // we don't independently test the features; instead just assume the
+ // implementation calls through to hasFeature (as tested above)
+ for (Node node : allNodes) {
+ assertSame(node, node.getFeature("XML", null));
+ assertSame(node, node.getFeature("XML", "3.0"));
+ assertNull(node.getFeature("foo", null));
+ assertNull(node.getFeature("foo", "bar"));
+ }
+ }
+
+ public void testNodeEqualsPositive() throws Exception {
+ DomTest copy = new DomTest();
+ copy.setUp();
+
+ for (int i = 0; i < allNodes.size(); i++) {
+ Node a = allNodes.get(i);
+ Node b = copy.allNodes.get(i);
+ assertTrue(a.isEqualNode(b));
+ }
+ }
+
+ public void testNodeEqualsNegative() throws Exception {
+ for (Node a : allNodes) {
+ for (Node b : allNodes) {
+ assertEquals(a == b, a.isEqualNode(b));
+ }
+ }
+ }
+
+ public void testNodeEqualsNegativeRecursive() throws Exception {
+ DomTest copy = new DomTest();
+ copy.setUp();
+ copy.vitaminc.setTextContent("55%");
+
+ // changing anything about a node should break equality for all parents
+ assertFalse(document.isEqualNode(copy.document));
+ assertFalse(menu.isEqualNode(copy.menu));
+ assertFalse(item.isEqualNode(copy.item));
+ assertFalse(nutrition.isEqualNode(copy.nutrition));
+ assertFalse(vitamins.isEqualNode(copy.vitamins));
+ assertFalse(vitaminc.isEqualNode(copy.vitaminc));
+
+ // but not siblings
+ assertTrue(doctype.isEqualNode(copy.doctype));
+ assertTrue(description.isEqualNode(copy.description));
+ assertTrue(option1.isEqualNode(copy.option1));
+ }
+
+ public void testNodeEqualsNull() {
+ for (Node node : allNodes) {
+ try {
+ node.isEqualNode(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+ }
+
+ private String domToString(Document document)
+ throws TransformerException {
+ StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(document), new StreamResult(writer));
+ return writer.toString();
+ }
+}
diff --git a/xml/src/test/java/tests/xml/NodeTest.java b/xml/src/test/java/tests/xml/NodeTest.java
new file mode 100644
index 0000000..dc3a333
--- /dev/null
+++ b/xml/src/test/java/tests/xml/NodeTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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 tests.xml;
+
+import dalvik.annotation.TestTargetClass;
+import junit.framework.TestCase;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import tests.support.resource.Support_Resources;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+@TestTargetClass(Node.class)
+public class NodeTest extends TestCase {
+
+ /**
+ * For bug 779: Node#getNextSibling throws IndexOutOfBoundsException.
+ */
+ public void test_getNextSibling() throws Exception {
+ // Calling getNextSibling when there is no next sibling should return null.
+ // From http://code.google.com/p/android/issues/detail?id=779.
+ ByteArrayInputStream bis = new ByteArrayInputStream("<root/>".getBytes());
+ Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(bis);
+ Node root = document.getDocumentElement();
+ assertNull(root.getNextSibling());
+ }
+
+ public void testGetBaseUri() throws Exception {
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ File file = Support_Resources.resourceToTempFile("/simple.xml");
+ Document document = builder.parse(file);
+
+ String baseUri = "file:" + file.getPath();
+ assertEquals(baseUri, document.getBaseURI());
+
+ Element documentElement = document.getDocumentElement();
+ for (Node node : flattenSubtree(documentElement)) {
+ if (node.getNodeType() == Node.ELEMENT_NODE
+ || node.getNodeType() == Node.DOCUMENT_NODE) {
+ assertEquals("Unexpected base URI for " + node, baseUri, node.getBaseURI());
+ } else {
+ assertNull("Unexpected base URI for " + node, node.getBaseURI());
+ }
+ }
+
+ // TODO: test other node types
+ // TODO: test resolution of relative paths
+ // TODO: test URI santization
+ }
+
+ private List<Node> flattenSubtree(Node subtree) {
+ List<Node> result = new ArrayList<Node>();
+ traverse(subtree, result);
+ return result;
+ }
+
+ private void traverse(Node node, List<Node> sink) {
+ sink.add(node);
+
+ NodeList children = node.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ traverse(children.item(i), sink);
+ }
+ }
+}
diff --git a/xml/src/test/java/tests/xml/NodeTests.java b/xml/src/test/java/tests/xml/NodeTests.java
deleted file mode 100644
index e46e216..0000000
--- a/xml/src/test/java/tests/xml/NodeTests.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 tests.xml;
-
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetNew;
-import dalvik.annotation.TestTargetClass;
-
-import junit.framework.TestCase;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import java.io.ByteArrayInputStream;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-@TestTargetClass(Node.class)
-public class NodeTests extends TestCase {
- @TestTargetNew(
- level = TestLevel.PARTIAL,
- notes = "Issue #779: org.w3c.dom.Node#getNextSibling throws IndexOutOfBoundsException.",
- method = "getNextSibling",
- args = {}
- )
- public void test_getNextSibling() throws Exception {
- // Calling getNextSibling when there is no next sibling should return null.
- // From http://code.google.com/p/android/issues/detail?id=779.
- ByteArrayInputStream bis = new ByteArrayInputStream("<root/>".getBytes());
- Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(bis);
- Node root = document.getDocumentElement();
- assertNull(root.getNextSibling());
- }
-}