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 Vitaly A. Provodin
21  */
22 
23 /**
24  * Created on 29.01.2005
25  */
26 package org.apache.harmony.jpda.tests.jdwp.share;
27 
28 import org.apache.harmony.jpda.tests.framework.TestErrorException;
29 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
30 import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket;
31 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
32 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
33 import org.apache.harmony.jpda.tests.framework.jdwp.Packet;
34 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
35 
36 /**
37  * Basic class for unit tests which use only one debuggee VM.
38  */
39 public abstract class JDWPTestCase extends JDWPRawTestCase {
40 
41     /**
42      * DebuggeeWrapper instance for launched debuggee VM.
43      */
44     protected JDWPUnitDebuggeeWrapper debuggeeWrapper;
45 
46     /**
47      * EventPacket instance with received VM_START event.
48      */
49     protected EventPacket initialEvent = null;
50 
51     /**
52      * Overrides inherited method to launch one debuggee VM, establish JDWP
53      * connection, and wait for VM_START event.
54      */
internalSetUp()55     protected void internalSetUp() throws Exception {
56         super.internalSetUp();
57 
58         // launch debuggee process
59         debuggeeWrapper = createDebuggeeWrapper();
60         beforeConnectionSetUp();
61         setUpDebuggeeWrapperConnection();
62         beforeDebuggeeStart();
63         startDebuggeeWrapper();
64 
65         // receive and handle initial event
66         receiveInitialEvent();
67 
68         // adjust JDWP types length
69         debuggeeWrapper.vmMirror.adjustTypeLength();
70         logWriter.println("Adjusted VM-dependent type lengths");
71     }
72 
73     /**
74      * Creates wrapper for debuggee process.
75      */
createDebuggeeWrapper()76     protected JDWPUnitDebuggeeWrapper createDebuggeeWrapper() {
77         if (settings.getDebuggeeLaunchKind().equals("manual")) {
78             return new JDWPManualDebuggeeWrapper(settings, logWriter);
79         } else {
80             return new JDWPUnitDebuggeeWrapper(settings, logWriter);
81         }
82     }
83 
84     /**
85      * Set up server side JDWP connection.
86      */
setUpDebuggeeWrapperConnection()87     protected void setUpDebuggeeWrapperConnection() {
88         debuggeeWrapper.setUpConnection();
89         logWriter.println("Set up server side JDWP connection.");
90     }
91 
92     /**
93      * Starts wrapper for debuggee process.
94      */
startDebuggeeWrapper()95     protected void startDebuggeeWrapper() {
96         debuggeeWrapper.start();
97         logWriter.println("Established JDWP connection with debuggee VM");
98     }
99 
100     /**
101      * Receives initial VM_INIT event if debuggee is suspended on event.
102      */
receiveInitialEvent()103     protected void receiveInitialEvent() {
104         if (settings.isDebuggeeSuspend()) {
105             initialEvent =
106                 debuggeeWrapper.vmMirror.receiveCertainEvent(JDWPConstants.EventKind.VM_INIT);
107             logWriter.println("Received inital VM_INIT event");
108         }
109     }
110 
111     /**
112      * Overrides inherited method to stop started debuggee VM and close all
113      * connections.
114      */
internalTearDown()115     protected void internalTearDown() {
116         if (debuggeeWrapper != null) {
117             debuggeeWrapper.stop();
118             logWriter.println("Closed JDWP connection with debuggee VM");
119         }
120         super.internalTearDown();
121     }
122 
123     /**
124      * This method is invoked right before setting up the server side JDWP connection.
125      */
beforeConnectionSetUp()126     protected void beforeConnectionSetUp() {
127       // Empty.
128     }
129 
130     /**
131      * This method is invoked right before starting debuggee VM.
132      */
beforeDebuggeeStart()133     protected void beforeDebuggeeStart() {
134       // Empty.
135     }
136 
137     /**
138      * Opens JDWP connection with debuggee (doesn't run debuggee and doesn't
139      * establish synchronize connection).
140      */
openConnection()141     public void openConnection() {
142         debuggeeWrapper.openConnection();
143         logWriter.println("Opened transport connection");
144         debuggeeWrapper.vmMirror.adjustTypeLength();
145         logWriter.println("Adjusted VM-dependent type lengths");
146     }
147 
148     /**
149      * Closes JDWP connection with debuggee (doesn't terminate debuggee and
150      * doesn't stop synchronize connection).
151      */
closeConnection()152     public void closeConnection() {
153         if (debuggeeWrapper != null) {
154             debuggeeWrapper.disposeConnection();
155             try {
156                 debuggeeWrapper.vmMirror.closeConnection();
157             } catch (Exception e) {
158                 throw new TestErrorException(e);
159             }
160             logWriter.println("Closed transport connection");
161         }
162     }
163 
164     /**
165      * Helper that returns reference type signature of input object ID.
166      *
167      * @param objectID -
168      *            debuggee object ID
169      * @return object signature of reference type
170      */
getObjectSignature(long objectID)171     protected String getObjectSignature(long objectID) {
172         long classID = getObjectReferenceType(objectID);
173         return getClassSignature(classID);
174     }
175 
176     /**
177      * Helper that returns reference type ID for input object ID.
178      *
179      * @param objectID -
180      *            debuggee object ID
181      * @return reference type ID
182      */
getObjectReferenceType(long objectID)183     protected long getObjectReferenceType(long objectID) {
184         CommandPacket command = new CommandPacket(
185                 JDWPCommands.ObjectReferenceCommandSet.CommandSetID,
186                 JDWPCommands.ObjectReferenceCommandSet.ReferenceTypeCommand);
187         command.setNextValueAsReferenceTypeID(objectID);
188         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(command);
189         checkReplyPacket(reply, "ObjectReference::ReferenceType command");
190         // byte refTypeTag =
191         reply.getNextValueAsByte();
192         long objectRefTypeID = reply.getNextValueAsReferenceTypeID();
193         return objectRefTypeID;
194     }
195 
196     /**
197      * Helper for getting method ID of corresponding class and method name.
198      *
199      * @param classID -
200      *            class ID
201      * @param methodName -
202      *            method name
203      * @return method ID
204      */
getMethodID(long classID, String methodName)205     protected long getMethodID(long classID, String methodName) {
206         CommandPacket command = new CommandPacket(
207                 JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
208                 JDWPCommands.ReferenceTypeCommandSet.MethodsCommand);
209         command.setNextValueAsClassID(classID);
210         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(command);
211         checkReplyPacket(reply, "ReferenceType::Methods command");
212         int methods = reply.getNextValueAsInt();
213         for (int i = 0; i < methods; i++) {
214             long methodID = reply.getNextValueAsMethodID();
215             String name = reply.getNextValueAsString(); // method name
216             reply.getNextValueAsString(); // method signature
217             reply.getNextValueAsInt(); // method modifiers
218             if (name.equals(methodName)) {
219                 return methodID;
220             }
221         }
222         return -1;
223     }
224 
225     /**
226      * Helper for getting method ID of corresponding class, method name and signature.
227      *
228      * @param classID -
229      *            class ID
230      * @param methodName -
231      *            method name
232      * @param methodSignature -
233      *            method signature
234      * @return method ID
235      */
getMethodID(long classID, String methodName, String methodSignature)236     protected long getMethodID(long classID, String methodName, String methodSignature) {
237         CommandPacket command = new CommandPacket(
238                 JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
239                 JDWPCommands.ReferenceTypeCommandSet.MethodsCommand);
240         command.setNextValueAsClassID(classID);
241         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(command);
242         checkReplyPacket(reply, "ReferenceType::Methods command");
243         int methods = reply.getNextValueAsInt();
244         for (int i = 0; i < methods; i++) {
245             long methodID = reply.getNextValueAsMethodID();
246             String name = reply.getNextValueAsString(); // method name
247             String signature = reply.getNextValueAsString();
248             reply.getNextValueAsInt(); // method modifiers
249             if (name.equals(methodName) && signature.equals(methodSignature)) {
250                 return methodID;
251             }
252         }
253         return -1;
254     }
255 
256     /**
257      * Issues LineTable command.
258      *
259      * @param classID -
260      *            class ID
261      * @param methodID -
262      *            method ID
263      * @return reply packet
264      */
getLineTable(long classID, long methodID)265     protected ReplyPacket getLineTable(long classID, long methodID) {
266         CommandPacket lineTableCommand = new CommandPacket(
267                 JDWPCommands.MethodCommandSet.CommandSetID,
268                 JDWPCommands.MethodCommandSet.LineTableCommand);
269         lineTableCommand.setNextValueAsReferenceTypeID(classID);
270         lineTableCommand.setNextValueAsMethodID(methodID);
271         ReplyPacket lineTableReply = debuggeeWrapper.vmMirror
272                 .performCommand(lineTableCommand);
273         checkReplyPacket(lineTableReply, "Method::LineTable command");
274         return lineTableReply;
275     }
276 
277     /**
278      * Helper for getting method name of corresponding class and method ID.
279      *
280      * @param classID class id
281      * @param methodID method id
282      * @return String
283      */
getMethodName(long classID, long methodID)284     protected String getMethodName(long classID, long methodID) {
285         CommandPacket packet = new CommandPacket(
286                 JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
287                 JDWPCommands.ReferenceTypeCommandSet.MethodsCommand);
288         packet.setNextValueAsClassID(classID);
289         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
290         checkReplyPacket(reply, "ReferenceType::Methods command");
291         int methods = reply.getNextValueAsInt();
292         for (int i = 0; i < methods; i++) {
293             long mid = reply.getNextValueAsMethodID();
294             String name = reply.getNextValueAsString();
295             reply.getNextValueAsString();
296             reply.getNextValueAsInt();
297             if (mid == methodID) {
298                 return name;
299             }
300         }
301         return "unknown";
302     }
303 
304     /**
305      * Returns jni signature for selected classID
306      *
307      * @param classID
308      * @return jni signature for selected classID
309      */
getClassSignature(long classID)310     protected String getClassSignature(long classID) {
311         CommandPacket command = new CommandPacket(
312                 JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
313                 JDWPCommands.ReferenceTypeCommandSet.SignatureCommand);
314         command.setNextValueAsReferenceTypeID(classID);
315         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(command);
316         checkReplyPacket(reply, "ReferenceType::Signature command");
317         String signature = reply.getNextValueAsString();
318         return signature;
319     }
320 
321     /**
322      * Returns classID for the selected jni signature
323      *
324      * @param signature
325      * @return classID for the selected jni signature
326      */
getClassIDBySignature(String signature)327     protected long getClassIDBySignature(String signature) {
328         logWriter.println("=> Getting reference type ID for class: "
329                 + signature);
330         CommandPacket packet = new CommandPacket(
331                 JDWPCommands.VirtualMachineCommandSet.CommandSetID,
332                 JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand);
333         packet.setNextValueAsString(signature);
334         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
335         checkReplyPacket(reply, "VirtualMachine::ClassesBySignature command");
336         int classes = reply.getNextValueAsInt();
337         logWriter.println("=> Returned number of classes: " + classes);
338         long classID = 0;
339         for (int i = 0; i < classes; i++) {
340             reply.getNextValueAsByte();
341             classID = reply.getNextValueAsReferenceTypeID();
342             reply.getNextValueAsInt();
343             // we need the only class, even if there were multiply ones
344             break;
345         }
346         assertTrue(
347                 "VirtualMachine::ClassesBySignature command returned invalid classID:<"
348                         + classID + "> for signature " + signature, classID > 0);
349         return classID;
350     }
351 
352     /**
353      * Returns reference type ID.
354      *
355      * @param signature
356      * @return type ID for the selected jni signature
357      */
getReferenceTypeID(String signature)358     protected long getReferenceTypeID(String signature) {
359         CommandPacket packet = new CommandPacket(
360                 JDWPCommands.VirtualMachineCommandSet.CommandSetID,
361                 JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand);
362         packet.setNextValueAsString(signature);
363         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
364         checkReplyPacket(reply, "VirtualMachine::ClassesBySignature command");
365         int classes = reply.getNextValueAsInt();
366         // this class may be loaded only once
367         assertEquals("Invalid number of classes for reference type: "
368                 + signature + ",", 1, classes);
369         byte refTypeTag = reply.getNextValueAsByte();
370         long classID = reply.getNextValueAsReferenceTypeID();
371         int status = reply.getNextValueAsInt();
372         logWriter.println("VirtualMachine.ClassesBySignature: classes="
373                 + classes + " refTypeTag=" + refTypeTag + " typeID= " + classID
374                 + " status=" + status);
375         assertAllDataRead(reply);
376         assertEquals("", JDWPConstants.TypeTag.CLASS, refTypeTag);
377         return classID;
378     }
379 
380     /**
381      * Helper function for resuming debuggee.
382      */
resumeDebuggee()383     protected void resumeDebuggee() {
384         logWriter.println("=> Resume debuggee");
385         CommandPacket packet = new CommandPacket(
386                 JDWPCommands.VirtualMachineCommandSet.CommandSetID,
387                 JDWPCommands.VirtualMachineCommandSet.ResumeCommand);
388         logWriter.println("Sending VirtualMachine::Resume command...");
389         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
390         checkReplyPacket(reply, "VirtualMachine::Resume command");
391         assertAllDataRead(reply);
392     }
393 
394     /**
395      * Performs string creation in debuggee.
396      *
397      * @param value -
398      *            content for new string
399      * @return StringID of new created string
400      */
createString(String value)401     protected long createString(String value) {
402         CommandPacket packet = new CommandPacket(
403                 JDWPCommands.VirtualMachineCommandSet.CommandSetID,
404                 JDWPCommands.VirtualMachineCommandSet.CreateStringCommand);
405         packet.setNextValueAsString(value);
406         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
407         checkReplyPacket(reply, "VirtualMachine::CreateString command");
408         long stringID = reply.getNextValueAsStringID();
409         return stringID;
410     }
411 
412     /**
413      * Returns corresponding string from string ID.
414      *
415      * @param stringID -
416      *            string ID
417      * @return string value
418      */
getStringValue(long stringID)419     protected String getStringValue(long stringID) {
420         CommandPacket packet = new CommandPacket(
421                 JDWPCommands.StringReferenceCommandSet.CommandSetID,
422                 JDWPCommands.StringReferenceCommandSet.ValueCommand);
423         packet.setNextValueAsObjectID(stringID);
424         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
425         checkReplyPacket(reply, "StringReference::Value command");
426         String returnedTestString = reply.getNextValueAsString();
427         return returnedTestString;
428     }
429 
430     /**
431      * Multiple field verification routine.
432      *
433      * @param refTypeID -
434      *            reference type ID
435      * @param checkedFieldNames -
436      *            list of field names to be checked
437      * @return list of field IDs
438      */
checkFields(long refTypeID, String checkedFieldNames[])439     protected long[] checkFields(long refTypeID, String checkedFieldNames[]) {
440         return checkFields(refTypeID, checkedFieldNames, null, null);
441     }
442 
443     /**
444      * Single field verification routine.
445      *
446      * @param refTypeID -
447      *            reference type ID
448      * @param fieldName -
449      *            name of single field
450      * @return filed ID
451      */
checkField(long refTypeID, String fieldName)452     protected long checkField(long refTypeID, String fieldName) {
453         return checkFields(refTypeID, new String[] { fieldName }, null, null)[0];
454     }
455 
456     /**
457      * Multiple field verification routine.
458      *
459      * @param refTypeID -
460      *            reference type ID
461      * @param checkedFieldNames -
462      *            list of field names to be checked
463      * @param expectedSignatures -
464      *            list of expected field signatures
465      * @param expectedModifiers -
466      *            list of expected field modifiers
467      * @return list of field IDs
468      */
checkFields(long refTypeID, String checkedFieldNames[], String expectedSignatures[], int expectedModifiers[])469     protected long[] checkFields(long refTypeID, String checkedFieldNames[],
470             String expectedSignatures[], int expectedModifiers[]) {
471 
472         boolean checkedFieldFound[] = new boolean[checkedFieldNames.length];
473         long checkedFieldIDs[] = new long[checkedFieldNames.length];
474 
475         logWriter
476                 .println("=> Send ReferenceType::Fields command and get field ID(s)");
477 
478         CommandPacket fieldsCommand = new CommandPacket(
479                 JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
480                 JDWPCommands.ReferenceTypeCommandSet.FieldsCommand);
481         fieldsCommand.setNextValueAsReferenceTypeID(refTypeID);
482         ReplyPacket fieldsReply = debuggeeWrapper.vmMirror
483                 .performCommand(fieldsCommand);
484         fieldsCommand = null;
485         checkReplyPacket(fieldsReply, "ReferenceType::Fields command");
486 
487         int returnedFieldsNumber = fieldsReply.getNextValueAsInt();
488         logWriter
489                 .println("=> Returned fields number = " + returnedFieldsNumber);
490 
491         int checkedFieldsNumber = checkedFieldNames.length;
492         final int fieldSyntheticFlag = 0xf0000000;
493 
494         int nameDuplicated = 0;
495         String fieldNameDuplicated = null; // <= collects all duplicated fields
496         int nameMissing = 0;
497         String fieldNameMissing = null; // <= collects all missed fields
498 
499         for (int i = 0; i < returnedFieldsNumber; i++) {
500             long returnedFieldID = fieldsReply.getNextValueAsFieldID();
501             String returnedFieldName = fieldsReply.getNextValueAsString();
502             String returnedFieldSignature = fieldsReply.getNextValueAsString();
503             int returnedFieldModifiers = fieldsReply.getNextValueAsInt();
504             logWriter.println("");
505             logWriter.println("=> Field ID: " + returnedFieldID);
506             logWriter.println("=> Field name: " + returnedFieldName);
507             logWriter.println("=> Field signature: " + returnedFieldSignature);
508             logWriter.println("=> Field modifiers: 0x"
509                     + Integer.toHexString(returnedFieldModifiers));
510             if ((returnedFieldModifiers & fieldSyntheticFlag) == fieldSyntheticFlag) {
511                 continue; // do not check synthetic fields
512             }
513             for (int k = 0; k < checkedFieldsNumber; k++) {
514                 if (!checkedFieldNames[k].equals(returnedFieldName)) {
515                     continue;
516                 }
517                 if (checkedFieldFound[k]) {
518                     logWriter.println("");
519                     logWriter
520                             .println("## FAILURE: The field is found repeatedly in the list");
521                     logWriter.println("## Field Name: " + returnedFieldName);
522                     logWriter.println("## Field ID: " + returnedFieldID);
523                     logWriter.println("## Field Signature: "
524                             + returnedFieldSignature);
525                     logWriter.println("## Field Modifiers: 0x"
526                             + Integer.toHexString(returnedFieldModifiers));
527                     fieldNameDuplicated = (0 == nameDuplicated ? returnedFieldName
528                             : fieldNameDuplicated + "," + returnedFieldName);
529                     nameDuplicated++;
530                     break;
531                 }
532                 checkedFieldFound[k] = true;
533                 checkedFieldIDs[k] = returnedFieldID;
534                 if (null != expectedSignatures) {
535                     assertString(
536                             "Invalid field signature is returned for field:"
537                                     + returnedFieldName + ",",
538                             expectedSignatures[k], returnedFieldSignature);
539                 }
540                 if (null != expectedModifiers) {
541                     assertEquals(
542                             "Invalid field modifiers are returned for field:"
543                                     + returnedFieldName + ",",
544                             expectedModifiers[k], returnedFieldModifiers);
545                 }
546                 break;
547             }
548         }
549 
550         for (int k = 0; k < checkedFieldsNumber; k++) {
551             if (!checkedFieldFound[k]) {
552                 logWriter.println("");
553                 logWriter
554                         .println("\n## FAILURE: Expected field is NOT found in the list of retuned fields:");
555                 logWriter.println("## Field name = " + checkedFieldNames[k]);
556                 fieldNameMissing = 0 == nameMissing ? checkedFieldNames[k]
557                         : fieldNameMissing + "," + checkedFieldNames[k];
558                 nameMissing++;
559                 // break;
560             }
561         }
562 
563         // String thisTestName = this.getClass().getName();
564         // logWriter.println("==> " + thisTestName + " for " + thisCommandName +
565         // ": FAILED");
566 
567         if (nameDuplicated > 1) {
568             fail("Duplicated fields are found in the retuned by FieldsCommand list: "
569                     + fieldNameDuplicated);
570         }
571         if (nameDuplicated > 0) {
572             fail("Duplicated field is found in the retuned by FieldsCommand list: "
573                     + fieldNameDuplicated);
574         }
575         if (nameMissing > 1) {
576             fail("Expected fields are NOT found in the retuned by FieldsCommand list: "
577                     + fieldNameMissing);
578         }
579         if (nameMissing > 0) {
580             fail("Expected field is NOT found in the retuned by FieldsCommand list: "
581                     + fieldNameMissing);
582         }
583 
584         logWriter.println("");
585         if (1 == checkedFieldsNumber) {
586             logWriter
587                     .println("=> Expected field was found and field ID was got");
588         } else {
589             logWriter
590                     .println("=> Expected fields were found and field IDs were got");
591         }
592 
593         assertAllDataRead(fieldsReply);
594         return checkedFieldIDs;
595     }
596 
597     /**
598      * Checks thread status and suspend status of a thread
599      *
600      * @param eventThreadID
601      *          the thread ID to check
602      * @param expectedThreadStatus
603      *          the expected thread status
604      * @param expectedSuspendStatus
605      *          the expected suspend status
606      */
checkThreadState(long eventThreadID, byte expectedThreadStatus, byte expectedSuspendStatus)607     protected void checkThreadState(long eventThreadID, byte expectedThreadStatus,
608             byte expectedSuspendStatus) {
609         CommandPacket commandPacket = new CommandPacket(
610                 JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
611                 JDWPCommands.ThreadReferenceCommandSet.StatusCommand);
612         commandPacket.setNextValueAsThreadID(eventThreadID);
613         ReplyPacket replyPacket = debuggeeWrapper.vmMirror.performCommand(commandPacket);
614         debuggeeWrapper.vmMirror.checkReply(replyPacket);
615 
616         int threadStatus = replyPacket.getNextValueAsInt();
617         int suspendStatus = replyPacket.getNextValueAsInt();
618         assertAllDataRead(replyPacket);
619 
620         assertEquals("Invalid thread status", threadStatus, expectedThreadStatus,
621                 JDWPConstants.ThreadStatus.getName(expectedThreadStatus),
622                 JDWPConstants.ThreadStatus.getName(threadStatus));
623         assertEquals("Invalid suspend status", suspendStatus, expectedSuspendStatus,
624                 JDWPConstants.SuspendStatus.getName(expectedSuspendStatus),
625                 JDWPConstants.SuspendStatus.getName(suspendStatus));
626     }
627 
628     /**
629      * Helper for checking reply packet error code. Calls junit fail if packet
630      * error code does not equal to expected error code.
631      *
632      * @param reply -
633      *            returned from debuggee packet
634      * @param message -
635      *            additional message
636      * @param errorCodeExpected -
637      *            array of expected error codes
638      */
checkReplyPacket(ReplyPacket reply, String message, int errorCodeExpected)639     protected void checkReplyPacket(ReplyPacket reply, String message,
640             int errorCodeExpected) {
641         checkReplyPacket(reply, message, new int[] { errorCodeExpected });
642     }
643 
644     /**
645      * Helper for checking reply packet error code. Calls junit fail if packet
646      * error code does not equal NONE.
647      *
648      * @param reply -
649      *            returned from debuggee packet
650      * @param message -
651      *            additional message
652      */
checkReplyPacket(ReplyPacket reply, String message)653     protected void checkReplyPacket(ReplyPacket reply, String message) {
654         checkReplyPacket(reply, message, JDWPConstants.Error.NONE);
655     }
656 
657     /**
658      * Helper for checking reply packet error code. Calls junit fail if packet
659      * error code does not equal to expected error code.
660      *
661      * @param reply -
662      *            returned from debuggee packet
663      * @param message -
664      *            additional message
665      * @param expected -
666      *            array of expected error codes
667      */
checkReplyPacket(ReplyPacket reply, String message, int[] expected)668     protected void checkReplyPacket(ReplyPacket reply, String message,
669             int[] expected) {
670         checkReplyPacket(reply, message, expected, true /* failSign */);
671     }
672 
673     /**
674      * Helper for checking reply packet error code. If reply packet does not
675      * have error - returns true. Otherwise does not call junit fail - simply
676      * prints error message and returns false. if packet error code does not
677      * equal NONE.
678      *
679      * @param reply -
680      *            returned from debuggee packet
681      * @param message -
682      *            additional message
683      * @return true if error is not found, or false otherwise
684      */
checkReplyPacketWithoutFail(ReplyPacket reply, String message)685     protected boolean checkReplyPacketWithoutFail(ReplyPacket reply,
686             String message) {
687         return checkReplyPacket(reply, message,
688                 new int[] { JDWPConstants.Error.NONE }, false /* failSign */);
689     }
690 
691     /**
692      * Helper for checking reply packet error code. If reply packet does not
693      * have unexpected error - returns true. If reply packet has got unexpected
694      * error: If failSign param = true - calls junit fail. Otherwise prints
695      * message about error and returns false.
696      *
697      * @param reply -
698      *            returned from debuggee packet
699      * @param message -
700      *            additional message
701      * @param expected -
702      *            array of expected error codes
703      * @param failSign -
704      *            defines to call junit fail or not
705      * @return true if unexpected errors are not found, or false otherwise
706      */
checkReplyPacket(ReplyPacket reply, String message, int[] expected, boolean failSign)707     protected boolean checkReplyPacket(ReplyPacket reply, String message,
708             int[] expected, boolean failSign) {
709         // check reply code against expected
710         int errorCode = reply.getErrorCode();
711         for (int i = 0; i < expected.length; i++) {
712             if (reply.getErrorCode() == expected[i]) {
713                 return true; // OK
714             }
715         }
716 
717         // replay code validation failed
718         // start error message composition
719         if (null == message) {
720             message = "";
721         } else {
722             message = message + ", ";
723         }
724 
725         // format error message
726         if (expected.length == 1 && JDWPConstants.Error.NONE == expected[0]) {
727             message = message + "Error Code:<" + errorCode + "("
728                     + JDWPConstants.Error.getName(errorCode) + ")>";
729         } else {
730             message = message + "Unexpected error code:<" + errorCode + "("
731                     + JDWPConstants.Error.getName(errorCode) + ")>"
732                     + ", Expected error code"
733                     + (expected.length == 1 ? ":" : "s:");
734             for (int i = 0; i < expected.length; i++) {
735                 message = message + (i > 0 ? ",<" : "<") + expected[i] + "("
736                         + JDWPConstants.Error.getName(expected[i]) + ")>";
737             }
738         }
739 
740         if (failSign) {
741             printErrorAndFail(message);
742         }
743         logWriter.printError(message);
744         return false;
745     }
746 
747     /**
748      * Helper for comparison numbers and printing string equivalents.
749      *
750      * @param message -
751      *            user message
752      * @param expected -
753      *            expected value
754      * @param actual -
755      *            actual value
756      * @param strExpected -
757      *            string equivalent of expected value
758      * @param strActual -
759      *            string equivalent of actual value
760      */
assertEquals(String message, long expected, long actual, String strExpected, String strActual)761     protected void assertEquals(String message, long expected, long actual,
762             String strExpected, String strActual) {
763         if (expected == actual) {
764             return; // OK
765         }
766 
767         if (null == message) {
768             message = "";
769         }
770 
771         if (null == strExpected) {
772             strExpected = expected + "";
773         } else {
774             strExpected = expected + "(" + strExpected + ")";
775         }
776 
777         if (null == strActual) {
778             strActual = actual + "";
779         } else {
780             strActual = actual + "(" + strActual + ")";
781         }
782 
783         printErrorAndFail(message + " expected:<" + strExpected + "> but was:<"
784                 + strActual + ">");
785     }
786 
787     /**
788      * Asserts that two strings are equal.
789      *
790      * @param message -
791      *            user message
792      * @param expected -
793      *            expected string
794      * @param actual -
795      *            actual string
796      */
assertString(String message, String expected, String actual)797     protected void assertString(String message, String expected, String actual) {
798         if (null == expected) {
799             expected = "";
800         }
801         if (null == actual) {
802             actual = "";
803         }
804         if (expected.equals(actual)) {
805             return; // OK
806         }
807         printErrorAndFail(message + " expected:<" + expected + "> but was:<"
808                 + actual + ">");
809     }
810 
811     /**
812      * Helper for checking reply packet data has been read.
813      *
814      * @param reply -
815      *            reply packet from debuggee
816      */
assertAllDataRead(Packet reply)817     protected void assertAllDataRead(Packet reply) {
818         if (reply.isAllDataRead()) {
819             return; // OK
820         }
821         printErrorAndFail("Not all data has been read");
822     }
823 
824     /**
825      * Asserts that two JDWP event kinds are equal.
826      *
827      * @param message
828      *          user message
829      * @param expected
830      *          expected event kind
831      * @param actual
832      *          actual event kind
833      */
assertEventKindEquals(String message, byte expected, byte actual)834     protected void assertEventKindEquals(String message, byte expected, byte actual) {
835         if (expected != actual) {
836             StringBuilder builder = new StringBuilder(message);
837             builder.append(": expected ");
838             builder.append(expected);
839             builder.append(" (");
840             builder.append(JDWPConstants.EventKind.getName(expected));
841             builder.append(") but was ");
842             builder.append(actual);
843             builder.append(" (");
844             builder.append(JDWPConstants.EventKind.getName(actual));
845             builder.append(")");
846             printErrorAndFail(builder.toString());
847         }
848     }
849 
850     /**
851      * Asserts that two JDWP tags are equal.
852      *
853      * @param message
854      *          user message
855      * @param expected
856      *          expected tag
857      * @param actual
858      *          actual tag
859      */
assertTagEquals(String message, byte expected, byte actual)860     protected void assertTagEquals(String message, byte expected, byte actual) {
861         if (expected != actual) {
862             StringBuilder builder = new StringBuilder(message);
863             builder.append(": expected ");
864             builder.append(expected);
865             builder.append(" (");
866             builder.append(JDWPConstants.Tag.getName(expected));
867             builder.append(") but was ");
868             builder.append(actual);
869             builder.append(" (");
870             builder.append(JDWPConstants.Tag.getName(actual));
871             builder.append(")");
872             printErrorAndFail(builder.toString());
873         }
874     }
875 
876     /**
877      * Prints error message in log writer and in junit fail.
878      *
879      * @param message -
880      *            error message
881      */
printErrorAndFail(String message)882     protected void printErrorAndFail(String message) {
883         logWriter.printError(message);
884         fail(message);
885     }
886 
887     /**
888      * Helper for setting static int field in class with new value.
889      *
890      * @param classSignature -
891      *            String defining signature of class
892      * @param fieldName -
893      *            String defining field name in specified class
894      * @param newValue -
895      *            int value to set for specified field
896      * @return true, if setting is successfully, or false otherwise
897      */
setStaticIntField(String classSignature, String fieldName, int newValue)898     protected boolean setStaticIntField(String classSignature,
899             String fieldName, int newValue) {
900 
901         long classID = debuggeeWrapper.vmMirror.getClassID(classSignature);
902         if (classID == -1) {
903             logWriter
904                     .println("## setStaticIntField(): Can NOT get classID for class signature = '"
905                             + classSignature + "'");
906             return false;
907         }
908 
909         long fieldID = debuggeeWrapper.vmMirror.getFieldID(classID, fieldName);
910         if (fieldID == -1) {
911             logWriter
912                     .println("## setStaticIntField(): Can NOT get fieldID for field = '"
913                             + fieldName + "'");
914             return false;
915         }
916 
917         CommandPacket packet = new CommandPacket(
918                 JDWPCommands.ClassTypeCommandSet.CommandSetID,
919                 JDWPCommands.ClassTypeCommandSet.SetValuesCommand);
920         packet.setNextValueAsReferenceTypeID(classID);
921         packet.setNextValueAsInt(1);
922         packet.setNextValueAsFieldID(fieldID);
923         packet.setNextValueAsInt(newValue);
924 
925         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
926         int errorCode = reply.getErrorCode();
927         if (errorCode != JDWPConstants.Error.NONE) {
928             logWriter
929                     .println("## setStaticIntField(): Can NOT set value for field = '"
930                             + fieldName
931                             + "' in class = '"
932                             + classSignature
933                             + "'; ClassType.SetValues command reurns error = "
934                             + errorCode);
935             return false;
936         }
937         return true;
938     }
939 
940     /**
941      * Removes breakpoint of the given event kind corresponding to the given
942      * request id.
943      *
944      * @param eventKind
945      *            request event kind
946      * @param requestID
947      *            request id
948      * @param verbose
949      *            print or don't extra log info
950      */
clearEvent(byte eventKind, int requestID, boolean verbose)951     protected void clearEvent(byte eventKind, int requestID, boolean verbose) {
952         CommandPacket packet = new CommandPacket(
953                 JDWPCommands.EventRequestCommandSet.CommandSetID,
954                 JDWPCommands.EventRequestCommandSet.ClearCommand);
955         packet.setNextValueAsByte(eventKind);
956         packet.setNextValueAsInt(requestID);
957         if (verbose) {
958             logWriter.println("Clearing event: "
959                     + JDWPConstants.EventKind.getName(eventKind) + ", id: "
960                     + requestID);
961         }
962         ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
963         checkReplyPacket(reply, "EventRequest::Clear command");
964         assertAllDataRead(reply);
965     }
966 }
967