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 package org.apache.harmony.jpda.tests.jdwp.Events;
20 
21 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
22 import org.apache.harmony.jpda.tests.framework.jdwp.Location;
23 import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
24 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
25 import org.apache.harmony.jpda.tests.framework.jdwp.TaggedObject;
26 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
27 
28 /**
29  * JDWP Unit test for uncaught EXCEPTION event.
30  */
31 public class ExceptionUncaughtTest extends ExceptionBaseTest {
32     private static final String EXCEPTION_SIGNATURE = getClassSignature(DebuggeeException.class);
33 
34     private static final String THROW_EXCEPTION_METHOD = "throwDebuggeeException";
35 
getDebuggeeClassName()36     protected String getDebuggeeClassName() {
37         return ExceptionUncaughtDebuggee.class.getName();
38     }
39 
40     /**
41      * This testcase is for uncaught EXCEPTION event and reported exception object.
42      * <BR>It runs ExceptionUncaughtDebuggee that throws an uncaught DebuggeeException.
43      * It verifies the following:
44      * <ul>
45      * <li>the requested EXCEPTION event occurs</li>
46      * <li>the reported exception object is not null</li>
47      * <li>the reported exception object is instance of expected class with expected tag</li>
48      * </ul>
49      */
testExceptionUncaughtEvent_ExceptionObject()50     public void testExceptionUncaughtEvent_ExceptionObject() {
51         printTestLog("STARTED...");
52 
53         ParsedEvent.Event_EXCEPTION exceptionEvent = requestAndReceiveExceptionEvent();
54         TaggedObject returnedException = exceptionEvent.getException();
55 
56         // assert that exception ObjectID is not null
57         printTestLog("returnedException.objectID = " + returnedException.objectID);
58         assertTrue("Returned exception object is null.", returnedException.objectID != 0);
59 
60         // assert that exception tag is OBJECT
61         printTestLog("returnedException.tag = " + returnedException.objectID);
62         assertEquals("Returned exception tag is not OBJECT.",
63                 JDWPConstants.Tag.OBJECT_TAG, returnedException.tag);
64 
65         // assert that exception class is the expected one
66         long typeID = getObjectReferenceType(returnedException.objectID);
67         String returnedExceptionSignature = getClassSignature(typeID);
68         printTestLog("returnedExceptionSignature = |" + returnedExceptionSignature+"|");
69         assertString("Invalid signature of returned exception,",
70                 EXCEPTION_SIGNATURE, returnedExceptionSignature);
71 
72         // resume debuggee
73         printTestLog("resume debuggee...");
74         debuggeeWrapper.vmMirror.resume();
75     }
76 
77     /**
78      * This testcase is for uncaught EXCEPTION event and reported throw location.
79      * <BR>It runs ExceptionUncaughtDebuggee that throws an uncaught DebuggeeException.
80      * It verifies the following:
81      * <ul>
82      * <li>the requested EXCEPTION event occurs</li>
83      * <li>the reported thread is not null</li>
84      * <li>the reported throw location is not null</li>
85      * <li>the reported throw location is equal to location of the top stack frame</li>
86      * </ul>
87      */
testExceptionUncaughtEvent_ThrowLocation()88     public void testExceptionUncaughtEvent_ThrowLocation() {
89         printTestLog("STARTED...");
90 
91         ParsedEvent.Event_EXCEPTION exceptionEvent = requestAndReceiveExceptionEvent();
92         long returnedThread = exceptionEvent.getThreadID();
93         Location throwLocation = exceptionEvent.getLocation();
94 
95         // assert that exception thread is not null
96         printTestLog("returnedThread = " + returnedThread);
97         assertTrue("Returned exception ThreadID is null,", returnedThread != 0);
98 
99         // assert that exception location is not null
100         printTestLog("returnedExceptionLoc = " + throwLocation);
101         assertNotNull("Returned exception location is null,", throwLocation);
102 
103         // assert that top stack frame location is not null
104         Location topFrameLoc = getTopFrameLocation(returnedThread);
105         printTestLog("topFrameLoc = " + topFrameLoc);
106         assertNotNull("Returned top stack frame location is null,", topFrameLoc);
107 
108         // assert that locations of exception and top frame are equal
109         assertTrue("Different exception and top frame location tag,",
110                 throwLocation.equals(topFrameLoc));
111 
112         // check throw location's method
113         long debuggeeClassID = getClassIDBySignature(getDebuggeeClassSignature());
114         long debuggeeThrowMethodID = getMethodID(debuggeeClassID, THROW_EXCEPTION_METHOD);
115         if (debuggeeClassID != throwLocation.classID ||
116             debuggeeThrowMethodID != throwLocation.methodID) {
117             StringBuilder builder = new StringBuilder("Invalid method for throw location:");
118             builder.append(" expected ");
119             builder.append(getDebuggeeClassSignature());
120             builder.append('.');
121             builder.append(THROW_EXCEPTION_METHOD);
122             builder.append(" but got ");
123             builder.append(dumpLocation(throwLocation));
124             fail(builder.toString());
125         }
126 
127         // resume debuggee
128         printTestLog("resume debuggee...");
129         debuggeeWrapper.vmMirror.resume();
130     }
131 
132     /**
133      * This testcase is for uncaught EXCEPTION event and reported catch location.
134      * <BR>It runs ExceptionUncaughtDebuggee that throws an uncaught DebuggeeException.
135      * It verifies the following:
136      * <ul>
137      * <li>the requested EXCEPTION event occurs</li>
138      * <li>the reported thread is not null</li>
139      * <li>the reported catch location is null</li>
140      * </ul>
141      */
testExceptionUncaughtEvent_CatchLocation()142     public void testExceptionUncaughtEvent_CatchLocation() {
143         printTestLog("STARTED...");
144 
145         ParsedEvent.Event_EXCEPTION exceptionEvent = requestAndReceiveExceptionEvent();
146         long returnedThread = exceptionEvent.getThreadID();
147 
148         // assert that exception thread is not null
149         printTestLog("returnedThread = " + returnedThread);
150         assertTrue("Returned exception ThreadID is null,", returnedThread != 0);
151 
152         // assert that exception catch location is not null
153         Location catchLocation = exceptionEvent.getCatchLocation();
154         printTestLog("returnedExceptionLoc = " + catchLocation);
155         assertNotNull("Returned exception catch location is null,", catchLocation);
156 
157         // check catch location's method
158         if (!isNullLocation(catchLocation)) {
159             fail("Invalid catch location: expected null but got " + dumpLocation(catchLocation));
160         }
161 
162         // resume debuggee
163         printTestLog("resume debuggee...");
164         debuggeeWrapper.vmMirror.resume();
165     }
166 
167     /**
168      * Indicates whether the location is "null" or "0". Note: we don't test the type tag as it
169      * can only be CLASS.
170      *
171      * @param location the location to test
172      * @return true if the location is "null", false otherwise
173      */
isNullLocation(Location location)174     private static boolean isNullLocation(Location location) {
175         return location.classID == 0 && location.methodID == 0
176                 && location.index == 0;
177     }
178 
179     /**
180      * Requests and receives EXCEPTION event then checks the received event kind,
181      * the received event request ID and the thread state.
182      * @return the exception event
183      */
requestAndReceiveExceptionEvent()184     private ParsedEvent.Event_EXCEPTION requestAndReceiveExceptionEvent() {
185         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
186 
187         boolean isCatch = true;
188         boolean isUncatch = true;
189         printTestLog("=> setException(...)...");
190         ReplyPacket replyPacket = debuggeeWrapper.vmMirror.setException(EXCEPTION_SIGNATURE,
191                 isCatch, isUncatch);
192         int requestID = replyPacket.getNextValueAsInt();
193         assertAllDataRead(replyPacket);
194 
195         printTestLog("setException(...) DONE");
196 
197         printTestLog("send to Debuggee SGNL_CONTINUE...");
198         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
199 
200         return receiveAndCheckExceptionEvent(requestID);
201     }
202 
203 }
204