JDWP Tests: More GetClassLoader tests
First, ensure that the returned object (in the success case) is
a classloader.
Second, add a negative test that ensures we get the right failure
value when the supplied ID is not a reference type. Note: this only
works if reference type IDs and object type IDs share their domain.
Otherwise a valid object ID may be a valid reference type ID.
Bug: 26349019
Change-Id: Ia33dac3f8b8fd158dec9f229f796263c8c985eab
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ReferenceType/ClassLoaderTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ReferenceType/ClassLoaderTest.java
index 5d1aa7d..7fc7d61 100644
--- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ReferenceType/ClassLoaderTest.java
+++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ReferenceType/ClassLoaderTest.java
@@ -27,6 +27,7 @@
import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
@@ -68,7 +69,44 @@
}
/**
- * Implementation of the tests, using the given parameters.
+ * Test that supplying a general object that is not a class returns
+ * a class error.
+ */
+ public void testClassLoader003() {
+ String thisTestName = "testClassLoader003";
+ logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": START...");
+ synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
+
+ // It's easer to just ask for an instance of String (as we know the runtime has
+ // created some during startup), rather than collecting all the constructor data
+ // for a class like the debuggee.
+ long stringClassRefTypeID = getClassIDBySignature("Ljava/lang/String;");
+
+ CommandPacket stringInstanceCommand = new CommandPacket(
+ JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
+ JDWPCommands.ReferenceTypeCommandSet.InstancesCommand);
+ stringInstanceCommand.setNextValueAsReferenceTypeID(stringClassRefTypeID);
+ stringInstanceCommand.setNextValueAsInt(1); // One instance is enough.
+ ReplyPacket stringInstanceReply =
+ debuggeeWrapper.vmMirror.performCommand(stringInstanceCommand);
+ checkReplyPacket(stringInstanceReply, "ReferenceType.Instances");
+ int stringInstanceCount = stringInstanceReply.getNextValueAsInt();
+ assertTrue("Expected to get one string instance", stringInstanceCount == 1);
+ long stringInstanceID = stringInstanceReply.getNextValueAsTaggedObject().objectID;
+
+ CommandPacket classLoaderCommand = new CommandPacket(
+ JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
+ JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
+ classLoaderCommand.setNextValueAsReferenceTypeID(stringInstanceID);
+ ReplyPacket classLoaderReply = debuggeeWrapper.vmMirror.performCommand(classLoaderCommand);
+ checkReplyPacket(classLoaderReply, thisCommandName, JDWPConstants.Error.INVALID_CLASS);
+
+ synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
+ logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
+ }
+
+ /**
+ * Implementation of tests 001 and 002, using the given parameters.
*/
private void classLoaderTest(String thisTestName, String signature, boolean expectZero) {
logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": START...");
@@ -99,7 +137,51 @@
assertAllDataRead(classLoaderReply);
+ assertTrue("Result should be a classloader",
+ isClassLoader(returnedClassLoaderID, thisCommandName));
+
synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
}
+
+ /**
+ * Helper to check whether an object is a classloader. Works by getting the class and
+ * the reference ID of java.lang.ClassLoader, then following the superclass chain and
+ * comparing.
+ */
+ private boolean isClassLoader(long classLoaderObjectID, String thisCommandName) {
+ if (classLoaderObjectID == 0) {
+ // 0 = null = bootstrap classloader.
+ return true;
+ }
+
+ CommandPacket refTypeCommand = new CommandPacket(
+ JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
+ JDWPCommands.ObjectReferenceCommandSet.ReferenceTypeCommand);
+ refTypeCommand.setNextValueAsObjectID(classLoaderObjectID);
+ ReplyPacket refTypeReply = debuggeeWrapper.vmMirror.performCommand(refTypeCommand);
+ checkReplyPacket(refTypeReply, "ObjectReference.ReferenceType");
+ refTypeReply.getNextValueAsByte(); // kind.
+ long classLoaderClassRefTypeID = refTypeReply.getNextValueAsReferenceTypeID();
+
+ long baseClassLoaderRefTypeID = getClassIDBySignature("Ljava/lang/ClassLoader;");
+
+ while (classLoaderClassRefTypeID != 0) {
+ if (classLoaderClassRefTypeID == baseClassLoaderRefTypeID) {
+ // This is a classloader...
+ return true;
+ }
+ CommandPacket superclassCommand = new CommandPacket(
+ JDWPCommands.ClassTypeCommandSet.CommandSetID,
+ JDWPCommands.ClassTypeCommandSet.SuperclassCommand);
+ superclassCommand.setNextValueAsObjectID(classLoaderClassRefTypeID);
+ ReplyPacket superclassReply =
+ debuggeeWrapper.vmMirror.performCommand(superclassCommand);
+ checkReplyPacket(superclassReply, "ClassType.Superclass");
+ classLoaderClassRefTypeID = superclassReply.getNextValueAsClassID();
+ }
+
+ // None of the superclasses was java.lang.ClassLoader, so it's not a classloader.
+ return false;
+ }
}