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        return Event.builder(eventKind, TEST_SUSPEND_POLICY)
64                .setLocationOnly(new Location(typeTag, typeID, methodID, breakpoint.index));
65    }
66
67    /**
68     * Creates an {@link EventBuilder} for EXCEPTION event and sets an
69     * ExceptionOnly modifier.
70     *
71     * @param exceptionClassSignature the signature of the exception class
72     * @param caught whether the exception must be caught
73     * @param uncaught whether the exception must be uncaught
74     * @return a new {@link EventBuilder}
75     */
76    protected EventBuilder createExceptionEventBuilder(
77            String exceptionClassSignature, boolean caught, boolean uncaught) {
78        byte eventKind = JDWPConstants.EventKind.EXCEPTION;
79        long exceptionClassID = debuggeeWrapper.vmMirror.getClassID(
80                exceptionClassSignature);
81        assertTrue("Failed to find type ID " + exceptionClassSignature,
82                exceptionClassID != 1);
83        return Event.builder(eventKind, TEST_SUSPEND_POLICY).setExceptionOnly(exceptionClassID,
84                caught, uncaught);
85    }
86
87    /**
88     * Creates an {@link EventBuilder} for METHOD_ENTRY event and sets a
89     * ClassMatch modifier.
90     *
91     * @param className a regular expression of class names matching the method
92     * entry events.
93     * @return a new {@link EventBuilder}
94     */
95    protected EventBuilder createMethodEntryEventBuilder(String className) {
96        return Event.builder(JDWPConstants.EventKind.METHOD_ENTRY, TEST_SUSPEND_POLICY)
97                .setClassMatch(className);
98    }
99
100    /**
101     * Creates an {@link EventBuilder} for METHOD_EXIT event and sets a
102     * ClassMatch modifier.
103     *
104     * @param className a regular expression of class names matching the method
105     * exit events.
106     * @return a new {@link EventBuilder}
107     */
108    protected EventBuilder createMethodExitEventBuilder(String className) {
109        return Event.builder(JDWPConstants.EventKind.METHOD_EXIT, TEST_SUSPEND_POLICY)
110                .setClassMatch(className);
111    }
112
113    /**
114     * Creates an {@link EventBuilder} for METHOD_EXIT_WITH_RETURN_VALUE event
115     * and sets a ClassMatch modifier.
116     *
117     * @param className a regular expression of class names matching the method
118     * exit events.
119     * @return a new {@link EventBuilder}
120     */
121    protected EventBuilder createMethodExitWithReturnValueEventBuilder(String className) {
122        return Event
123                .builder(JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE, TEST_SUSPEND_POLICY)
124                .setClassMatch(className);
125    }
126
127    /**
128     * Creates an {@link EventBuilder} for THREAD_START event.
129     *
130     * @return a new {@link EventBuilder}
131     */
132    protected EventBuilder createThreadStartBuilder() {
133        return Event.builder(JDWPConstants.EventKind.THREAD_START, TEST_SUSPEND_POLICY);
134    }
135
136    /**
137     * Creates an {@link EventBuilder} for THREAD_END event.
138     *
139     * @return a new {@link EventBuilder}
140     */
141    protected EventBuilder createThreadEndBuilder() {
142        return Event.builder(JDWPConstants.EventKind.THREAD_END, TEST_SUSPEND_POLICY);
143    }
144
145    /**
146     * Creates an {@link EventBuilder} for FIELD_ACCESS event and sets a
147     * FieldOnly modifier.
148     *
149     * @param typeTag the type tag of the field's declaring class
150     * @param classSignature the field's declaring class signature
151     * @param fieldName the field name
152     * @return a new {@link EventBuilder}
153     */
154    protected EventBuilder createFieldAccessEventBuilder(byte typeTag,
155            String classSignature, String fieldName) {
156        return createFieldEventBuilder(typeTag, classSignature, fieldName, false);
157    }
158
159    /**
160     * Creates an {@link EventBuilder} for FIELD_MODIFICATION event and sets a
161     * FieldOnly modifier.
162     *
163     * @param typeTag the type tag of the field's declaring class
164     * @param classSignature the field's declaring class signature
165     * @param fieldName the field name
166     * @return a new {@link EventBuilder}
167     */
168    protected EventBuilder createFieldModificationEventBuilder(byte typeTag,
169            String classSignature, String fieldName) {
170        return createFieldEventBuilder(typeTag, classSignature, fieldName, true);
171    }
172
173    private EventBuilder createFieldEventBuilder(byte typeTag,
174                                                String typeSignature,
175                                                String fieldName,
176                                                boolean modification) {
177        byte eventKind;
178        if (modification) {
179            eventKind = JDWPConstants.EventKind.FIELD_MODIFICATION;
180        } else {
181            eventKind = JDWPConstants.EventKind.FIELD_ACCESS;
182        }
183        long typeID = debuggeeWrapper.vmMirror.getTypeID(typeSignature, typeTag);
184        assertTrue("Failed to find type ID " + typeSignature, typeID != 1);
185        long fieldID = debuggeeWrapper.vmMirror.getFieldID(typeID, fieldName);
186        assertTrue("Failed to find field ID " + typeSignature + "." + fieldName,
187                fieldID != 1);
188        return Event.builder(eventKind, TEST_SUSPEND_POLICY).setFieldOnly(typeID, fieldID);
189    }
190
191    /**
192     * Sends a request for the given event.
193     *
194     * @param event the event to request
195     * @return the request ID
196     */
197    protected int requestEvent(Event event) {
198        String eventName = JDWPConstants.EventKind.getName(event.eventKind);
199        logWriter.println("Requesting " + eventName);
200        ReplyPacket reply = debuggeeWrapper.vmMirror.setEvent(event);
201        checkReplyPacket(reply, "Failed to request " + eventName);
202        int requestID = reply.getNextValueAsInt();
203        assertAllDataRead(reply);
204        return requestID;
205    }
206
207    /**
208     * Waits for the first corresponding event.
209     *
210     * @param eventKind the event kind
211     * @param requestID the event request ID
212     * @return the event
213     */
214    protected EventThread waitForEvent(byte eventKind, int requestID) {
215        logWriter.println("Signaling debuggee to continue");
216        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
217
218        String eventName = JDWPConstants.EventKind.getName(eventKind);
219        logWriter.println(
220                "Waiting for " + eventName + " with requestID " + requestID + " ...");
221        EventPacket eventPacket = debuggeeWrapper.vmMirror.receiveCertainEvent(
222                eventKind);
223        ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(eventPacket);
224        assertNotNull(parsedEvents);
225        assertTrue(parsedEvents.length > 0);
226        ParsedEvent event = parsedEvents[0];
227        assertEquals(eventKind, event.getEventKind());
228        assertEquals(requestID, event.getRequestID());
229        logWriter.println("Received " + eventName + " event");
230        return (EventThread) event;
231    }
232
233    /**
234     * Clears the corresponding event and resumes the VM.
235     *
236     * @param eventKind the event kind
237     * @param requestID the event request ID
238     */
239    protected void clearAndResume(byte eventKind, int requestID) {
240        clearEvent(eventKind, requestID, true);
241        resumeDebuggee();
242    }
243
244    /**
245     * Warns about an unsupported capability by printing a message in the
246     * console.
247     *
248     * @param capabilityName the capability name
249     */
250    protected void logCapabilityWarning(String capabilityName) {
251        // Build the message to prompt.
252        StringBuilder messageBuilder =
253                new StringBuilder("# WARNING: this VM doesn't possess capability: ");
254        messageBuilder.append(capabilityName);
255        messageBuilder.append(' ');
256        messageBuilder.append('#');
257        String message = messageBuilder.toString();
258
259        // Build a sharp string long enough.
260        int sharpLineLength = message.length();
261        StringBuilder sharpLineBuilder = new StringBuilder(sharpLineLength);
262        for (int i = 0; i < sharpLineLength; ++i) {
263            sharpLineBuilder.append('#');
264        }
265        String sharpLine = sharpLineBuilder.toString();
266
267        // Print warning message.
268        logWriter.println(sharpLine);
269        logWriter.println(message);
270        logWriter.println(sharpLine);
271    }
272}
273