From ad8a1ac1d45d7626686bfb431f1039e12d5f5794 Mon Sep 17 00:00:00 2001 From: Sebastien Hertz Date: Tue, 3 Nov 2015 16:33:13 +0100 Subject: JDWP: test java.lang.String construction Tests the creation of java.lang.String with ClassType.NewInstance command (for all public constructors). Bug: 25439464 Change-Id: I0a2f43d41c1d8505340d03fc523b9f6a6b3a1ca6 --- .../jdwp/ClassType/NewInstanceStringDebuggee.java | 65 ++++ .../jdwp/ClassType/NewInstanceStringTest.java | 369 +++++++++++++++++++++ .../jpda/tests/jdwp/share/JDWPTestCase.java | 31 ++ .../apache/harmony/jpda/tests/share/AllTests.java | 3 +- 4 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringDebuggee.java create mode 100644 jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringTest.java diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringDebuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringDebuggee.java new file mode 100644 index 0000000..4c62220 --- /dev/null +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringDebuggee.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.jpda.tests.jdwp.ClassType; + +import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer; +import org.apache.harmony.jpda.tests.share.SyncDebuggee; + +import java.nio.charset.Charset; + +public class NewInstanceStringDebuggee extends SyncDebuggee { + // Fields used as constructor arguments during the test. + public static final String TEST_STRING = "my test string"; + public static final byte[] BYTE_ARRAY = TEST_STRING.getBytes(); + public static final char[] CHAR_ARRAY = new char[TEST_STRING.length()]; + public static final int[] INT_ARRAY = new int[TEST_STRING.length()]; + public static final Charset CHARSET = Charset.defaultCharset(); + public static final String STRING_CHARSET = CHARSET.displayName(); + public static final StringBuffer STRING_BUFFER = new StringBuffer(TEST_STRING); + public static final StringBuilder STRING_BUILDER = new StringBuilder(TEST_STRING); + + static { + TEST_STRING.getChars(0, TEST_STRING.length(), CHAR_ARRAY, 0); + for (int i = 0; i < INT_ARRAY.length; ++i) { + INT_ARRAY[i] = TEST_STRING.codePointAt(i); + } + } + + @Override + public void run() { + logWriter.println("NewInstanceStringDebuggee starts"); + + synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY); + // ... Let debugger prepare breakpoint request ... + synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); + + // Suspend the debuggee on breakpoint so the test can send ClassType.NewInstance command. + breakpointMethod(); + + logWriter.println("NewInstanceStringDebuggee ends"); + } + + void breakpointMethod() { + logWriter.println("NewInstanceStringDebuggee.breakpointMethod()"); + } + + public static void main(String[] args) { + runDebuggee(NewInstanceStringDebuggee.class); + } +} diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringTest.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringTest.java new file mode 100644 index 0000000..e2f3e95 --- /dev/null +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/ClassType/NewInstanceStringTest.java @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.jpda.tests.jdwp.ClassType; + +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.framework.jdwp.TaggedObject; +import org.apache.harmony.jpda.tests.framework.jdwp.Value; +import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase; +import org.apache.harmony.jpda.tests.jdwp.share.JDWPTestConstants; +import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer; + +import java.util.ArrayList; +import java.util.List; + +/** + * JDWP unit test for ClassType.NewInstance command with java.lang.String class. + */ +public class NewInstanceStringTest extends JDWPSyncTestCase { + private static final String CONSTRUCTOR_NAME = ""; + + /** + * A provider is responsible for giving the arguments passed to the tested + * constructor. + */ + private static interface ConstructorArgumentsProvider { + /** + * This method is called to provide the arguments to the constructor + * called to create the java.lang.String instance. This is called when + * the debuggee is suspended on a breakpoint. + * + * @param constructorArguments + * the list of arguments passed to the constructor + */ + public void provideConstructorArguments(List constructorArguments); + } + + @Override + protected String getDebuggeeClassName() { + return NewInstanceStringDebuggee.class.getName(); + } + + /** + * Test ClassType.NewInstance using the constructor java.lang.String(). + */ + public void testNewInstanceString_NoArgConstructor() { + runTestNewInstanceString("()V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // No argument. + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(byte[]). + */ + public void testNewInstanceString_ByteArrayArgConstructor() { + runTestNewInstanceString("([B)V", new ConstructorArgumentsProvider() { + + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to BYTE_ARRAY static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value byteArrayValue = getStaticFieldValue(debuggeeClassId, "BYTE_ARRAY"); + constructorArguments.add(byteArrayValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(byte[], int, int). + */ + public void testNewInstanceString_ByteArrayIntIntConstructor() { + runTestNewInstanceString("([BII)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to BYTE_ARRAY static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value byteArrayValue = getStaticFieldValue(debuggeeClassId, "BYTE_ARRAY"); + constructorArguments.add(byteArrayValue); + constructorArguments.add(new Value(0)); + constructorArguments.add(new Value(1)); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(byte[], int, int, java.lang.String). + */ + public void testNewInstanceString_ByteArrayIntIntStringConstructor() { + runTestNewInstanceString("([BIILjava/lang/String;)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to BYTE_ARRAY and STRING_CHARSET static + // fields. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value byteArrayValue = getStaticFieldValue(debuggeeClassId, "BYTE_ARRAY"); + Value stringCharsetValue = getStaticFieldValue(debuggeeClassId, "STRING_CHARSET"); + constructorArguments.add(byteArrayValue); + constructorArguments.add(new Value(0)); + constructorArguments.add(new Value(1)); + constructorArguments.add(stringCharsetValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(byte[], java.lang.String). + */ + public void testNewInstanceString_ByteArrayStringConstructor() { + runTestNewInstanceString("([BLjava/lang/String;)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to BYTE_ARRAY and STRING_CHARSET static + // fields. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value byteArrayValue = getStaticFieldValue(debuggeeClassId, "BYTE_ARRAY"); + Value stringCharsetValue = getStaticFieldValue(debuggeeClassId, "STRING_CHARSET"); + constructorArguments.add(byteArrayValue); + constructorArguments.add(stringCharsetValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(byte[], int, int, java.nio.charset.Charset). + */ + public void testNewInstanceString_ByteArrayIntIntCharsetConstructor() { + runTestNewInstanceString("([BIILjava/nio/charset/Charset;)V", + new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to BYTE_ARRAY and CHARSET static + // fields. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value byteArrayValue = getStaticFieldValue(debuggeeClassId, "BYTE_ARRAY"); + Value charsetValue = getStaticFieldValue(debuggeeClassId, "CHARSET"); + constructorArguments.add(byteArrayValue); + constructorArguments.add(new Value(0)); + constructorArguments.add(new Value(1)); + constructorArguments.add(charsetValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(byte[], java.nio.charset.Charset). + */ + public void testNewInstanceString_ByteArrayCharsetConstructor() { + runTestNewInstanceString("([BLjava/nio/charset/Charset;)V", + new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to BYTE_ARRAY and CHARSET static + // fields. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value byteArrayValue = getStaticFieldValue(debuggeeClassId, "BYTE_ARRAY"); + Value charsetValue = getStaticFieldValue(debuggeeClassId, "CHARSET"); + constructorArguments.add(byteArrayValue); + constructorArguments.add(charsetValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(char[]). + */ + public void testNewInstanceString_CharArrayConstructor() { + runTestNewInstanceString("([C)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to CHAR_ARRAY static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value charArrayValue = getStaticFieldValue(debuggeeClassId, "CHAR_ARRAY"); + constructorArguments.add(charArrayValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(char[], int, int). + */ + public void testNewInstanceString_CharArrayIntIntConstructor() { + runTestNewInstanceString("([CII)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to CHAR_ARRAY static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value charArrayValue = getStaticFieldValue(debuggeeClassId, "CHAR_ARRAY"); + constructorArguments.add(charArrayValue); + constructorArguments.add(new Value(0)); + constructorArguments.add(new Value(1)); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(java.lang.String). + */ + public void testNewInstanceString_StringConstructor() { + runTestNewInstanceString("(Ljava/lang/String;)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to TEST_STRING static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value testStringValue = getStaticFieldValue(debuggeeClassId, "TEST_STRING"); + constructorArguments.add(testStringValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(java.lang.StringBuffer). + */ + public void testNewInstanceString_StringBufferConstructor() { + runTestNewInstanceString("(Ljava/lang/StringBuffer;)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to STRING_BUFFER static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value stringBufferValue = getStaticFieldValue(debuggeeClassId, "STRING_BUFFER"); + constructorArguments.add(stringBufferValue); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(int[], * int, int). + */ + public void testNewInstanceString_IntArrayIntIntConstructor() { + runTestNewInstanceString("([III)V", new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to INT_ARRAY static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value intArrayValue = getStaticFieldValue(debuggeeClassId, "INT_ARRAY"); + constructorArguments.add(intArrayValue); + constructorArguments.add(new Value(0)); + constructorArguments.add(new Value(1)); + } + }); + } + + /** + * Test ClassType.NewInstance using the constructor + * java.lang.String(java.lang.StringBuilder). + */ + public void testNewInstanceString_StringBuilderConstructor() { + runTestNewInstanceString("(Ljava/lang/StringBuilder;)V", + new ConstructorArgumentsProvider() { + @Override + public void provideConstructorArguments(List constructorArguments) { + // Pass a reference to STRING_BUILDER static field. + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + Value stringBuilderValue = getStaticFieldValue(debuggeeClassId, + "STRING_BUILDER"); + constructorArguments.add(stringBuilderValue); + } + }); + } + + /** + * This testcase exercises ClassType.NewInstance command for + * java.lang.String. At first, the test starts debuggee. Then request a + * breakpoint and wait for it. Once the debuggee is suspended on the + * breakpoint, send ClassType.NewInstance command for the java.lang.String + * class using the constructor whose signature is given as parameter. A + * provider is responsible to provide the arguments for the specified + * constructor as JDWP values. Finally, the test verifies that the returned + * object is not null and the exception object is null. + */ + private void runTestNewInstanceString(String constructorSignature, + ConstructorArgumentsProvider provider) { + synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); + + long debuggeeClassId = getClassIDBySignature(getDebuggeeClassSignature()); + logWriter.println("Debuggee class: " + getDebuggeeClassSignature()); + logWriter.println("Debuggee class ID: " + debuggeeClassId); + + // Request breakpoint. + int breakpointRequestId = debuggeeWrapper.vmMirror + .setBreakpointAtMethodBegin(debuggeeClassId, "breakpointMethod"); + + // Continue debuggee. + synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); + + // Wait for breakpoint. + long threadId = debuggeeWrapper.vmMirror.waitForBreakpoint(breakpointRequestId); + + long javaLangStringId = getClassIDBySignature("Ljava/lang/String;"); + assertTrue("Failed to find java.lang.String class", javaLangStringId != -1); + logWriter.println("java.lang.String class ID: " + javaLangStringId); + + final String methodName = CONSTRUCTOR_NAME; + final String methodSignature = constructorSignature; + final String fullMethodName = methodName + methodSignature; + long constructorId = getMethodID(javaLangStringId, methodName, methodSignature); + assertTrue("Failed to find constructor " + fullMethodName, constructorId != -1); + logWriter.println(fullMethodName + " method ID: " + constructorId); + + // Request provider to fill the arguments list. + List argumentsList = new ArrayList(); + provider.provideConstructorArguments(argumentsList); + + logWriter + .println("Sending ClassType.NewInstance command for constructor " + fullMethodName); + CommandPacket packet = new CommandPacket(JDWPCommands.ClassTypeCommandSet.CommandSetID, + JDWPCommands.ClassTypeCommandSet.NewInstanceCommand); + packet.setNextValueAsReferenceTypeID(javaLangStringId); + packet.setNextValueAsThreadID(threadId); + packet.setNextValueAsMethodID(constructorId); + packet.setNextValueAsInt(argumentsList.size()); // argCount + for (Value value : argumentsList) { + packet.setNextValueAsValue(value); + } + packet.setNextValueAsInt(0); // invoke options + ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet); + checkReplyPacket(reply, "ClassType.NewInstance command"); + + // Check result. + TaggedObject stringResult = reply.getNextValueAsTaggedObject(); + TaggedObject exceptionResult = reply.getNextValueAsTaggedObject(); + assertAllDataRead(reply); + + assertNotNull("stringResult is null", stringResult); + assertNotNull("exceptionResult is null", exceptionResult); + assertTrue(stringResult.objectID != JDWPTestConstants.NULL_OBJECT_ID); + assertTrue(exceptionResult.tag == JDWPConstants.Tag.OBJECT_TAG); + assertEquals(exceptionResult.objectID, JDWPTestConstants.NULL_OBJECT_ID); + + // Debuggee is suspended on the breakpoint: resume it now. + resumeDebuggee(); + } + + private Value getStaticFieldValue(long classId, String fieldName) { + long fieldId = checkField(classId, fieldName); + return debuggeeWrapper.vmMirror.getReferenceTypeValue(classId, fieldId); + } +} diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPTestCase.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPTestCase.java index d240b80..7646b83 100644 --- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPTestCase.java +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPTestCase.java @@ -205,6 +205,37 @@ public abstract class JDWPTestCase extends JDWPRawTestCase { return -1; } + /** + * Helper for getting method ID of corresponding class, method name and signature. + * + * @param classID - + * class ID + * @param methodName - + * method name + * @param methodSignature - + * method signature + * @return method ID + */ + protected long getMethodID(long classID, String methodName, String methodSignature) { + CommandPacket command = new CommandPacket( + JDWPCommands.ReferenceTypeCommandSet.CommandSetID, + JDWPCommands.ReferenceTypeCommandSet.MethodsCommand); + command.setNextValueAsClassID(classID); + ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(command); + checkReplyPacket(reply, "ReferenceType::Methods command"); + int methods = reply.getNextValueAsInt(); + for (int i = 0; i < methods; i++) { + long methodID = reply.getNextValueAsMethodID(); + String name = reply.getNextValueAsString(); // method name + String signature = reply.getNextValueAsString(); + reply.getNextValueAsInt(); // method modifiers + if (name.equals(methodName) && signature.equals(methodSignature)) { + return methodID; + } + } + return -1; + } + /** * Issues LineTable command. * diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java index 3776bcf..f596ad3 100644 --- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java @@ -74,8 +74,9 @@ public class AllTests { suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodWithSuspensionTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.InvokeMethodTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstance002Test.class); - suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceAfterMultipleThreadSuspensionTest.class); + suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest.class); + suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceWithSuspensionTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.SetValues002Test.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.ClassType.SetValuesTest.class); -- cgit v1.2.3