1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 /** 20 * @author Anton V. Karnachuk 21 */ 22 23 /** 24 * Created on 11.04.2005 25 */ 26 package org.apache.harmony.jpda.tests.jdwp.Events; 27 28 import org.apache.harmony.jpda.tests.framework.Breakpoint; 29 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants; 30 import org.apache.harmony.jpda.tests.framework.jdwp.Location; 31 import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent; 32 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket; 33 import org.apache.harmony.jpda.tests.framework.jdwp.TaggedObject; 34 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer; 35 36 37 38 /** 39 * JDWP Unit test for caught EXCEPTION event. 40 */ 41 public class ExceptionCaughtTest extends ExceptionBaseTest { 42 getDebuggeeClassName()43 protected String getDebuggeeClassName() { 44 return ExceptionCaughtDebuggee.class.getName(); 45 } 46 47 /** 48 * This testcase is for caught EXCEPTION event thrown from Java code. It tests 49 * the reported exception object. 50 * <BR>It runs ExceptionDebuggee that throws and catches a DebuggeeException with 51 * native and interpreter frames in between. It verifies the following: 52 * <ul> 53 * <li>the requested EXCEPTION event occurs</li> 54 * <li>the reported exception object is not null</li> 55 * <li>the reported exception object is instance of expected class with expected tag</li> 56 * </ul> 57 */ testExceptionEvent_ExceptionObject_FromJava()58 public void testExceptionEvent_ExceptionObject_FromJava() { 59 runExceptionObjectTest(false); 60 } 61 62 /** 63 * This testcase is for caught EXCEPTION event thrown from native code. It tests 64 * the reported exception object. 65 * <BR>It runs ExceptionDebuggee that throws an exception from a native method 66 * and catches it. It verifies the following: 67 * <ul> 68 * <li>the requested EXCEPTION event occurs</li> 69 * <li>the reported exception object is not null</li> 70 * <li>the reported exception object is instance of expected class with expected tag</li> 71 * </ul> 72 */ testExceptionEvent_ExceptionObject_FromNative()73 public void testExceptionEvent_ExceptionObject_FromNative() { 74 runExceptionObjectTest(true); 75 } 76 77 /** 78 * This testcase is for caught EXCEPTION event thrown from Java code. It tests 79 * the reported throw location. 80 * <BR>It runs ExceptionDebuggee that throws and catches a DebuggeeException with 81 * native and interpreter frames in between. It verifies the following: 82 * <ul> 83 * <li>the requested EXCEPTION event occurs</li> 84 * <li>the reported thread is not null</li> 85 * <li>the reported throw location is not null</li> 86 * <li>the reported throw location is equal to location of the top stack frame</li> 87 * </ul> 88 */ testExceptionEvent_ThrowLocation_FromJava()89 public void testExceptionEvent_ThrowLocation_FromJava() { 90 runThrowLocationTest(false); 91 } 92 93 /** 94 * This testcase is for caught EXCEPTION event thrown from native code. It tests 95 * the reported throw location. 96 * <BR>It runs ExceptionDebuggee that throws an exception from a native method 97 * and catches it. It verifies the following: 98 * <ul> 99 * <li>the requested EXCEPTION event occurs</li> 100 * <li>the reported thread is not null</li> 101 * <li>the reported throw location is not null</li> 102 * <li>the reported throw location is equal to location of the top stack frame</li> 103 * </ul> 104 */ testExceptionEvent_ThrowLocation_FromNative()105 public void testExceptionEvent_ThrowLocation_FromNative() { 106 runThrowLocationTest(true); 107 } 108 109 /** 110 * This testcase is for caught EXCEPTION event thrown from Java code. It tests 111 * the reported catch location. 112 * <BR>It runs ExceptionDebuggee that throws and catches a DebuggeeException with 113 * native and interpreter frames in between. It verifies the following: 114 * <ul> 115 * <li>the requested EXCEPTION event occurs</li> 116 * <li>the reported thread is not null</li> 117 * <li>the reported catch location is not null</li> 118 * <li>the reported catch location is different than the top stack frame</li> 119 * </ul> 120 */ testExceptionEvent_CatchLocation_FromJava()121 public void testExceptionEvent_CatchLocation_FromJava() { 122 runCatchLocationTest(false); 123 } 124 125 /** 126 * This testcase is for caught EXCEPTION event thrown from native code. It tests 127 * the reported catch location. 128 * <BR>It runs ExceptionDebuggee that throws an exception from a native method 129 * and catches it. It verifies the following: 130 * <ul> 131 * <li>the requested EXCEPTION event occurs</li> 132 * <li>the reported thread is not null</li> 133 * <li>the reported catch location is not null</li> 134 * <li>the reported catch location is different than the top stack frame</li> 135 * </ul> 136 */ testExceptionEvent_CatchLocation_FromNative()137 public void testExceptionEvent_CatchLocation_FromNative() { 138 runCatchLocationTest(true); 139 } 140 141 /** 142 * Requests and receives EXCEPTION event then checks reported exception object. 143 */ runExceptionObjectTest(boolean fromNative)144 private void runExceptionObjectTest(boolean fromNative) { 145 printTestLog("STARTED..."); 146 147 ParsedEvent.Event_EXCEPTION exceptionEvent = requestAndReceiveExceptionEvent(fromNative); 148 TaggedObject returnedException = exceptionEvent.getException(); 149 150 // assert that exception ObjectID is not null 151 printTestLog("returnedException.objectID = " + returnedException.objectID); 152 assertTrue("Returned exception object is null.", returnedException.objectID != 0); 153 154 // assert that exception tag is OBJECT 155 printTestLog("returnedException.tag = " + returnedException.objectID); 156 assertEquals("Returned exception tag is not OBJECT.", 157 JDWPConstants.Tag.OBJECT_TAG, returnedException.tag); 158 159 // assert that exception class is the expected one 160 long typeID = getObjectReferenceType(returnedException.objectID); 161 String returnedExceptionSignature = getClassSignature(typeID); 162 printTestLog("returnedExceptionSignature = |" + returnedExceptionSignature+"|"); 163 assertString("Invalid signature of returned exception,", 164 getExpectedExceptionSignature(fromNative), returnedExceptionSignature); 165 166 // resume debuggee 167 printTestLog("resume debuggee..."); 168 debuggeeWrapper.vmMirror.resume(); 169 } 170 171 /** 172 * Requests and receives EXCEPTION event then checks reported throw location. 173 */ runThrowLocationTest(boolean fromNative)174 private void runThrowLocationTest(boolean fromNative) { 175 printTestLog("STARTED..."); 176 177 ParsedEvent.Event_EXCEPTION exceptionEvent = requestAndReceiveExceptionEvent(fromNative); 178 long returnedThread = exceptionEvent.getThreadID(); 179 Location throwLocation = exceptionEvent.getLocation(); 180 181 // assert that exception thread is not null 182 printTestLog("returnedThread = " + returnedThread); 183 assertTrue("Returned exception ThreadID is null,", returnedThread != 0); 184 185 // assert that exception location is not null 186 printTestLog("returnedExceptionLoc = " + throwLocation); 187 assertNotNull("Returned exception location is null,", throwLocation); 188 189 // assert that top stack frame location is not null 190 Location topFrameLoc = getTopFrameLocation(returnedThread); 191 printTestLog("topFrameLoc = " + topFrameLoc); 192 assertNotNull("Returned top stack frame location is null,", topFrameLoc); 193 194 // assert that locations of exception and top frame are equal 195 assertEquals("Different exception and top frame location tag,", topFrameLoc, throwLocation); 196 197 // check throw location's method 198 String expectedThrowLocationClassSignature = 199 getThrowLocationMethodClassSignature(fromNative); 200 String expectedThrowLocationMethodName = getThrowLocationMethodName(fromNative); 201 long debuggeeClassID = getClassIDBySignature(expectedThrowLocationClassSignature); 202 long debuggeeThrowMethodID = getMethodID(debuggeeClassID, expectedThrowLocationMethodName); 203 if (debuggeeClassID != throwLocation.classID || 204 debuggeeThrowMethodID != throwLocation.methodID) { 205 StringBuilder builder = new StringBuilder("Invalid method for throw location:"); 206 builder.append(" expected "); 207 builder.append(expectedThrowLocationClassSignature); 208 builder.append('.'); 209 builder.append(expectedThrowLocationMethodName); 210 builder.append(" but got "); 211 builder.append(dumpLocation(throwLocation)); 212 fail(builder.toString()); 213 } 214 215 // resume debuggee 216 printTestLog("resume debuggee..."); 217 debuggeeWrapper.vmMirror.resume(); 218 } 219 220 /** 221 * Requests and receives EXCEPTION event then checks reported catch location. 222 */ runCatchLocationTest(boolean fromNative)223 private void runCatchLocationTest(boolean fromNative) { 224 printTestLog("STARTED..."); 225 226 ParsedEvent.Event_EXCEPTION exceptionEvent = requestAndReceiveExceptionEvent(fromNative); 227 long returnedThread = exceptionEvent.getThreadID(); 228 229 // assert that exception thread is not null 230 printTestLog("returnedThread = " + returnedThread); 231 assertTrue("Returned exception ThreadID is null,", returnedThread != 0); 232 233 // assert that exception catch location is not null 234 Location catchLocation = exceptionEvent.getCatchLocation(); 235 printTestLog("returnedExceptionLoc = " + catchLocation); 236 assertNotNull("Returned exception catch location is null,", catchLocation); 237 238 // assert that top stack frame location is not null 239 Location topFrameLoc = getTopFrameLocation(returnedThread); 240 printTestLog("topFrameLoc = " + topFrameLoc); 241 assertNotNull("Returned top stack frame location is null,", topFrameLoc); 242 assertFalse("Same throw and catch locations", catchLocation.equals(topFrameLoc)); 243 244 // check catch location's method 245 String expectedCatchLocationClassSignature = getDebuggeeClassSignature(); 246 String expectedCatchLocationMethodName = getCatchLocationMethodName(fromNative); 247 long debuggeeClassID = getClassIDBySignature(expectedCatchLocationClassSignature); 248 long debuggeeThrowMethodID = getMethodID(debuggeeClassID, expectedCatchLocationMethodName); 249 if (debuggeeClassID != catchLocation.classID || 250 debuggeeThrowMethodID != catchLocation.methodID) { 251 StringBuilder builder = new StringBuilder("Invalid method for catch location:"); 252 builder.append(" expected "); 253 builder.append(expectedCatchLocationClassSignature); 254 builder.append('.'); 255 builder.append(expectedCatchLocationMethodName); 256 builder.append(" but got "); 257 builder.append(dumpLocation(catchLocation)); 258 fail(builder.toString()); 259 } 260 261 // resume debuggee 262 printTestLog("resume debuggee..."); 263 debuggeeWrapper.vmMirror.resume(); 264 } 265 266 /** 267 * Requests and receives EXCEPTION event then checks the received event kind, 268 * the received event request ID and the thread state. 269 * @return the exception event 270 */ requestAndReceiveExceptionEvent(boolean fromNative)271 private ParsedEvent.Event_EXCEPTION requestAndReceiveExceptionEvent(boolean fromNative) { 272 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 273 274 boolean isCatch = true; 275 boolean isUncatch = true; 276 printTestLog("=> setException(...)..."); 277 String exceptionSignature = getExpectedExceptionSignature(fromNative); 278 ReplyPacket replyPacket = debuggeeWrapper.vmMirror.setException(exceptionSignature, 279 isCatch, isUncatch); 280 int requestID = replyPacket.getNextValueAsInt(); 281 assertAllDataRead(replyPacket); 282 283 printTestLog("setException(...) DONE"); 284 285 if (!fromNative) { 286 // We want native and interpreter frames between the throw and the catch 287 // to check that we properly compute the catch location. We insert a native 288 // frame by using reflection in the code. To insert an interpreter frame, 289 // we install a breakpoint. 290 // Note: we use a Count modifier to avoid suspending on the breakpoint. This 291 // prevents from handling a suspend/resume sequence. 292 Breakpoint breakpoint = new Breakpoint(getDebuggeeClassSignature(), 293 "throwDebuggeeExceptionWithTransition", 0); 294 debuggeeWrapper.vmMirror.setCountableBreakpoint(JDWPConstants.TypeTag.CLASS, 295 breakpoint, JDWPConstants.SuspendPolicy.ALL, 10); 296 } 297 298 printTestLog("send to Debuggee SGNL_CONTINUE..."); 299 300 String signalToSend = getSignalMessage(fromNative); 301 synchronizer.sendMessage(signalToSend); 302 303 return receiveAndCheckExceptionEvent(requestID); 304 } 305 getExpectedExceptionSignature(boolean fromNative)306 static String getExpectedExceptionSignature(boolean fromNative) { 307 Class<?> c = fromNative ? NullPointerException.class : DebuggeeException.class; 308 return getClassSignature(c); 309 } 310 getThrowLocationMethodName(boolean fromNative)311 static String getThrowLocationMethodName(boolean fromNative) { 312 return fromNative ? "arraycopy" : "throwDebuggeeException"; 313 } 314 getThrowLocationMethodClassSignature(boolean fromNative)315 String getThrowLocationMethodClassSignature(boolean fromNative) { 316 return fromNative ? getClassSignature(System.class) : getDebuggeeClassSignature(); 317 } 318 getCatchLocationMethodName(boolean fromNative)319 static String getCatchLocationMethodName(boolean fromNative) { 320 return fromNative ? "testThrowAndCatchExceptionFromNative" 321 : "testThrowAndCatchDebuggeeExceptionFromJava"; 322 } 323 getSignalMessage(boolean fromNative)324 static String getSignalMessage(boolean fromNative) { 325 return fromNative ? ExceptionCaughtDebuggee.TEST_EXCEPTION_FROM_NATIVE_METHOD 326 : JPDADebuggeeSynchronizer.SGNL_CONTINUE; 327 } 328 } 329