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 */
26package org.apache.harmony.jpda.tests.jdwp.share;
27
28import org.apache.harmony.jpda.tests.framework.TestErrorException;
29import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
30import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket;
31import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
32import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
33import org.apache.harmony.jpda.tests.framework.jdwp.Packet;
34import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
35
36/**
37 * Basic class for unit tests which use only one debuggee VM.
38 */
39public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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