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