1package org.apache.harmony.jpda.tests.jdwp.EventModifiers;
2
3import org.apache.harmony.jpda.tests.framework.Breakpoint;
4import org.apache.harmony.jpda.tests.framework.jdwp.Event;
5import org.apache.harmony.jpda.tests.framework.jdwp.EventBuilder;
6import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket;
7import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
8import org.apache.harmony.jpda.tests.framework.jdwp.Location;
9import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
10import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent.EventThread;
11import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
12import org.apache.harmony.jpda.tests.framework.jdwp.Value;
13import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
14import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
15
16/**
17 * This base class provides utilities for all event modifier tests.
18 */
19abstract class JDWPEventModifierTestCase extends JDWPSyncTestCase {
20    /**
21     * The suspend policy used for all events in the tests.
22     */
23    protected static final byte
24            TEST_SUSPEND_POLICY = JDWPConstants.SuspendPolicy.ALL;
25
26    /**
27     * Returns value of the requested field.
28     *
29     * @param classSignature the signature of the field's declaring class
30     * @param fieldName the field name.
31     * @return the value of the field
32     */
33    protected Value getFieldValue(String classSignature, String fieldName) {
34        long classID = debuggeeWrapper.vmMirror.getClassID(classSignature);
35        assertTrue("Failed to find debuggee class " + classSignature,
36                classID != 0);
37        long fieldID = debuggeeWrapper.vmMirror.getFieldID(classID, fieldName);
38        assertTrue("Failed to find field " + classSignature + "." + fieldName,
39                fieldID != 0);
40
41        long[] fieldIDs = new long[] { fieldID };
42        Value[] fieldValues = debuggeeWrapper.vmMirror.getReferenceTypeValues(
43                classID, fieldIDs);
44        assertNotNull("Failed to get field values for class " + classSignature,
45                fieldValues);
46        assertEquals("Invalid number of field values", 1, fieldValues.length);
47        return fieldValues[0];
48    }
49
50    /**
51     * Creates an {@link EventBuilder} for BREAKPOINT event and sets a
52     * LocationOnly modifier.
53     *
54     * @param typeTag the type tag of the location's class
55     * @param breakpoint the breakpoint info
56     * @return a new {@link EventBuilder}
57     */
58    protected EventBuilder createBreakpointEventBuilder(byte typeTag,
59            Breakpoint breakpoint) {
60        long typeID = debuggeeWrapper.vmMirror.getTypeID(breakpoint.className, typeTag);
61        long methodID = getMethodID(typeID, breakpoint.methodName);
62        byte eventKind = JDWPConstants.EventKind.BREAKPOINT;
63        EventBuilder builder = new EventBuilder(eventKind, TEST_SUSPEND_POLICY);
64        builder.setLocationOnly(new Location(typeTag, typeID, methodID,
65                breakpoint.index));
66        return builder;
67    }
68
69    /**
70     * Creates an {@link EventBuilder} for EXCEPTION event and sets an
71     * ExceptionOnly modifier.
72     *
73     * @param exceptionClassSignature the signature of the exception class
74     * @param caught whether the exception must be caught
75     * @param uncaught whether the exception must be uncaught
76     * @return a new {@link EventBuilder}
77     */
78    protected EventBuilder createExceptionEventBuilder(
79            String exceptionClassSignature, boolean caught, boolean uncaught) {
80        byte eventKind = JDWPConstants.EventKind.EXCEPTION;
81        EventBuilder builder = new EventBuilder(eventKind, TEST_SUSPEND_POLICY);
82        long exceptionClassID = debuggeeWrapper.vmMirror.getClassID(
83                exceptionClassSignature);
84        assertTrue("Failed to find type ID " + exceptionClassSignature,
85                exceptionClassID != 1);
86        builder.setExceptionOnly(exceptionClassID, caught, uncaught);
87        return builder;
88    }
89
90    /**
91     * Creates an {@link EventBuilder} for METHOD_ENTRY event and sets a
92     * ClassMatch modifier.
93     *
94     * @param className a regular expression of class names matching the method
95     * entry events.
96     * @return a new {@link EventBuilder}
97     */
98    protected EventBuilder createMethodEntryEventBuilder(String className) {
99        EventBuilder builder = new EventBuilder(
100                JDWPConstants.EventKind.METHOD_ENTRY, TEST_SUSPEND_POLICY);
101        return builder.setClassMatch(className);
102    }
103
104    /**
105     * Creates an {@link EventBuilder} for METHOD_EXIT event and sets a
106     * ClassMatch modifier.
107     *
108     * @param className a regular expression of class names matching the method
109     * exit events.
110     * @return a new {@link EventBuilder}
111     */
112    protected EventBuilder createMethodExitEventBuilder(String className) {
113        EventBuilder builder = new EventBuilder(
114                JDWPConstants.EventKind.METHOD_EXIT, TEST_SUSPEND_POLICY);
115        return builder.setClassMatch(className);
116    }
117
118    /**
119     * Creates an {@link EventBuilder} for METHOD_EXIT_WITH_RETURN_VALUE event
120     * and sets a ClassMatch modifier.
121     *
122     * @param className a regular expression of class names matching the method
123     * exit events.
124     * @return a new {@link EventBuilder}
125     */
126    protected EventBuilder createMethodExitWithReturnValueEventBuilder(String className) {
127        EventBuilder builder = new EventBuilder(
128                JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE,
129                TEST_SUSPEND_POLICY);
130        return builder.setClassMatch(className);
131    }
132
133    /**
134     * Creates an {@link EventBuilder} for THREAD_START event.
135     *
136     * @return a new {@link EventBuilder}
137     */
138    protected EventBuilder createThreadStartBuilder() {
139        return new EventBuilder(JDWPConstants.EventKind.THREAD_START,
140                TEST_SUSPEND_POLICY);
141    }
142
143    /**
144     * Creates an {@link EventBuilder} for THREAD_END event.
145     *
146     * @return a new {@link EventBuilder}
147     */
148    protected EventBuilder createThreadEndBuilder() {
149        return new EventBuilder(JDWPConstants.EventKind.THREAD_END,
150                TEST_SUSPEND_POLICY);
151    }
152
153    /**
154     * Creates an {@link EventBuilder} for FIELD_ACCESS event and sets a
155     * FieldOnly modifier.
156     *
157     * @param typeTag the type tag of the field's declaring class
158     * @param classSignature the field's declaring class signature
159     * @param fieldName the field name
160     * @return a new {@link EventBuilder}
161     */
162    protected EventBuilder createFieldAccessEventBuilder(byte typeTag,
163            String classSignature, String fieldName) {
164        return createFieldEventBuilder(typeTag, classSignature, fieldName, false);
165    }
166
167    /**
168     * Creates an {@link EventBuilder} for FIELD_MODIFICATION event and sets a
169     * FieldOnly modifier.
170     *
171     * @param typeTag the type tag of the field's declaring class
172     * @param classSignature the field's declaring class signature
173     * @param fieldName the field name
174     * @return a new {@link EventBuilder}
175     */
176    protected EventBuilder createFieldModificationEventBuilder(byte typeTag,
177            String classSignature, String fieldName) {
178        return createFieldEventBuilder(typeTag, classSignature, fieldName, true);
179    }
180
181    private EventBuilder createFieldEventBuilder(byte typeTag,
182                                                String typeSignature,
183                                                String fieldName,
184                                                boolean modification) {
185        byte eventKind;
186        if (modification) {
187            eventKind = JDWPConstants.EventKind.FIELD_MODIFICATION;
188        } else {
189            eventKind = JDWPConstants.EventKind.FIELD_ACCESS;
190        }
191        EventBuilder builder = new EventBuilder(eventKind, TEST_SUSPEND_POLICY);
192        long typeID = debuggeeWrapper.vmMirror.getTypeID(typeSignature, typeTag);
193        assertTrue("Failed to find type ID " + typeSignature, typeID != 1);
194        long fieldID = debuggeeWrapper.vmMirror.getFieldID(typeID, fieldName);
195        assertTrue("Failed to find field ID " + typeSignature + "." + fieldName,
196                fieldID != 1);
197        builder.setFieldOnly(typeID, fieldID);
198        return builder;
199    }
200
201    /**
202     * Sends a request for the given event.
203     *
204     * @param event the event to request
205     * @return the request ID
206     */
207    protected int requestEvent(Event event) {
208        String eventName = JDWPConstants.EventKind.getName(event.eventKind);
209        logWriter.println("Requesting " + eventName);
210        ReplyPacket reply = debuggeeWrapper.vmMirror.setEvent(event);
211        checkReplyPacket(reply, "Failed to request " + eventName);
212        int requestID = reply.getNextValueAsInt();
213        assertAllDataRead(reply);
214        return requestID;
215    }
216
217    /**
218     * Waits for the first corresponding event.
219     *
220     * @param eventKind the event kind
221     * @param requestID the event request ID
222     * @return the event
223     */
224    protected EventThread waitForEvent(byte eventKind, int requestID) {
225        logWriter.println("Signaling debuggee to continue");
226        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
227
228        String eventName = JDWPConstants.EventKind.getName(eventKind);
229        logWriter.println(
230                "Waiting for " + eventName + " with requestID " + requestID + " ...");
231        EventPacket eventPacket = debuggeeWrapper.vmMirror.receiveCertainEvent(
232                eventKind);
233        ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(eventPacket);
234        assertNotNull(parsedEvents);
235        assertTrue(parsedEvents.length > 0);
236        ParsedEvent event = parsedEvents[0];
237        assertEquals(eventKind, event.getEventKind());
238        assertEquals(requestID, event.getRequestID());
239        logWriter.println("Received " + eventName + " event");
240        return (EventThread) event;
241    }
242
243    /**
244     * Clears the corresponding event and resumes the VM.
245     *
246     * @param eventKind the event kind
247     * @param requestID the event request ID
248     */
249    protected void clearAndResume(byte eventKind, int requestID) {
250        clearEvent(eventKind, requestID, true);
251        resumeDebuggee();
252    }
253
254    /**
255     * Checks the VM supports the canWatchFieldAccess capability. If it does
256     * not, prints a warning in the console.
257     *
258     * @return true if the VM supports the canWatchFieldAccess capability, false
259     * otherwise.
260     */
261    protected boolean canWatchFieldAccessCapability() {
262        logWriter.println("Checking canWatchFieldAccess capability");
263        boolean result = debuggeeWrapper.vmMirror.canWatchFieldAccess();
264        if (!result) {
265            logCapabilityWarning("canWatchFieldAccess");
266        }
267        return result;
268    }
269
270    /**
271     * Checks the VM supports the canWatchFieldModification capability. If it
272     * does not, prints a warning in the console.
273     *
274     * @return true if the VM supports the canWatchFieldModification capability,
275     * false otherwise.
276     */
277    protected boolean canWatchFieldModificationCapability() {
278        logWriter.println("Checking canWatchFieldModification capability");
279        boolean result = debuggeeWrapper.vmMirror.canWatchFieldModification();
280        if (!result) {
281            logCapabilityWarning("canWatchFieldModification");
282        }
283        return result;
284    }
285
286    /**
287     * Warns about an unsupported capability by printing a message in the
288     * console.
289     *
290     * @param capabilityName the capability name
291     */
292    protected void logCapabilityWarning(String capabilityName) {
293        // Build the message to prompt.
294        StringBuilder messageBuilder =
295                new StringBuilder("# WARNING: this VM doesn't possess capability: ");
296        messageBuilder.append(capabilityName);
297        messageBuilder.append(' ');
298        messageBuilder.append('#');
299        String message = messageBuilder.toString();
300
301        // Build a sharp string long enough.
302        int sharpLineLength = message.length();
303        StringBuilder sharpLineBuilder = new StringBuilder(sharpLineLength);
304        for (int i = 0; i < sharpLineLength; ++i) {
305            sharpLineBuilder.append('#');
306        }
307        String sharpLine = sharpLineBuilder.toString();
308
309        // Print warning message.
310        logWriter.println(sharpLine);
311        logWriter.println(message);
312        logWriter.println(sharpLine);
313    }
314}
315