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     * Helper for checking reply packet error code. Calls junit fail if packet
551     * error code does not equal to expected error code.
552     *
553     * @param reply -
554     *            returned from debuggee packet
555     * @param message -
556     *            additional message
557     * @param errorCodeExpected -
558     *            array of expected error codes
559     */
560    protected void checkReplyPacket(ReplyPacket reply, String message,
561            int errorCodeExpected) {
562        checkReplyPacket(reply, message, new int[] { errorCodeExpected });
563    }
564
565    /**
566     * Helper for checking reply packet error code. Calls junit fail if packet
567     * error code does not equal NONE.
568     *
569     * @param reply -
570     *            returned from debuggee packet
571     * @param message -
572     *            additional message
573     */
574    protected void checkReplyPacket(ReplyPacket reply, String message) {
575        checkReplyPacket(reply, message, JDWPConstants.Error.NONE);
576    }
577
578    /**
579     * Helper for checking reply packet error code. Calls junit fail if packet
580     * error code does not equal to expected error code.
581     *
582     * @param reply -
583     *            returned from debuggee packet
584     * @param message -
585     *            additional message
586     * @param expected -
587     *            array of expected error codes
588     */
589    protected void checkReplyPacket(ReplyPacket reply, String message,
590            int[] expected) {
591        checkReplyPacket(reply, message, expected, true /* failSign */);
592    }
593
594    /**
595     * Helper for checking reply packet error code. If reply packet does not
596     * have error - returns true. Otherwise does not call junit fail - simply
597     * prints error message and returns false. if packet error code does not
598     * equal NONE.
599     *
600     * @param reply -
601     *            returned from debuggee packet
602     * @param message -
603     *            additional message
604     * @return true if error is not found, or false otherwise
605     */
606    protected boolean checkReplyPacketWithoutFail(ReplyPacket reply,
607            String message) {
608        return checkReplyPacket(reply, message,
609                new int[] { JDWPConstants.Error.NONE }, false /* failSign */);
610    }
611
612    /**
613     * Helper for checking reply packet error code. If reply packet does not
614     * have unexpected error - returns true. If reply packet has got unexpected
615     * error: If failSign param = true - calls junit fail. Otherwise prints
616     * message about error and returns false.
617     *
618     * @param reply -
619     *            returned from debuggee packet
620     * @param message -
621     *            additional message
622     * @param expected -
623     *            array of expected error codes
624     * @param failSign -
625     *            defines to call junit fail or not
626     * @return true if unexpected errors are not found, or false otherwise
627     */
628    protected boolean checkReplyPacket(ReplyPacket reply, String message,
629            int[] expected, boolean failSign) {
630        // check reply code against expected
631        int errorCode = reply.getErrorCode();
632        for (int i = 0; i < expected.length; i++) {
633            if (reply.getErrorCode() == expected[i]) {
634                return true; // OK
635            }
636        }
637
638        // replay code validation failed
639        // start error message composition
640        if (null == message) {
641            message = "";
642        } else {
643            message = message + ", ";
644        }
645
646        // format error message
647        if (expected.length == 1 && JDWPConstants.Error.NONE == expected[0]) {
648            message = message + "Error Code:<" + errorCode + "("
649                    + JDWPConstants.Error.getName(errorCode) + ")>";
650        } else {
651            message = message + "Unexpected error code:<" + errorCode + "("
652                    + JDWPConstants.Error.getName(errorCode) + ")>"
653                    + ", Expected error code"
654                    + (expected.length == 1 ? ":" : "s:");
655            for (int i = 0; i < expected.length; i++) {
656                message = message + (i > 0 ? ",<" : "<") + expected[i] + "("
657                        + JDWPConstants.Error.getName(expected[i]) + ")>";
658            }
659        }
660
661        if (failSign) {
662            printErrorAndFail(message);
663        }
664        logWriter.printError(message);
665        return false;
666    }
667
668    /**
669     * Helper for comparison numbers and printing string equivalents.
670     *
671     * @param message -
672     *            user message
673     * @param expected -
674     *            expected value
675     * @param actual -
676     *            actual value
677     * @param strExpected -
678     *            string equivalent of expected value
679     * @param strActual -
680     *            string equivalent of actual value
681     */
682    protected void assertEquals(String message, long expected, long actual,
683            String strExpected, String strActual) {
684        if (expected == actual) {
685            return; // OK
686        }
687
688        if (null == message) {
689            message = "";
690        }
691
692        if (null == strExpected) {
693            strExpected = expected + "";
694        } else {
695            strExpected = expected + "(" + strExpected + ")";
696        }
697
698        if (null == strActual) {
699            strActual = actual + "";
700        } else {
701            strActual = actual + "(" + strActual + ")";
702        }
703
704        printErrorAndFail(message + " expected:<" + strExpected + "> but was:<"
705                + strActual + ">");
706    }
707
708    /**
709     * Asserts that two strings are equal.
710     *
711     * @param message -
712     *            user message
713     * @param expected -
714     *            expected string
715     * @param actual -
716     *            actual string
717     */
718    protected void assertString(String message, String expected, String actual) {
719        if (null == expected) {
720            expected = "";
721        }
722        if (null == actual) {
723            actual = "";
724        }
725        if (expected.equals(actual)) {
726            return; // OK
727        }
728        printErrorAndFail(message + " expected:<" + expected + "> but was:<"
729                + actual + ">");
730    }
731
732    /**
733     * Helper for checking reply packet data has been read.
734     *
735     * @param reply -
736     *            reply packet from debuggee
737     */
738    protected void assertAllDataRead(Packet reply) {
739        if (reply.isAllDataRead()) {
740            return; // OK
741        }
742        printErrorAndFail("Not all data has been read");
743    }
744
745    /**
746     * Prints error message in log writer and in junit fail.
747     *
748     * @param message -
749     *            error message
750     */
751    protected void printErrorAndFail(String message) {
752        logWriter.printError(message);
753        fail(message);
754    }
755
756    /**
757     * Helper for setting static int field in class with new value.
758     *
759     * @param classSignature -
760     *            String defining signature of class
761     * @param fieldName -
762     *            String defining field name in specified class
763     * @param newValue -
764     *            int value to set for specified field
765     * @return true, if setting is successfully, or false otherwise
766     */
767    protected boolean setStaticIntField(String classSignature,
768            String fieldName, int newValue) {
769
770        long classID = debuggeeWrapper.vmMirror.getClassID(classSignature);
771        if (classID == -1) {
772            logWriter
773                    .println("## setStaticIntField(): Can NOT get classID for class signature = '"
774                            + classSignature + "'");
775            return false;
776        }
777
778        long fieldID = debuggeeWrapper.vmMirror.getFieldID(classID, fieldName);
779        if (fieldID == -1) {
780            logWriter
781                    .println("## setStaticIntField(): Can NOT get fieldID for field = '"
782                            + fieldName + "'");
783            return false;
784        }
785
786        CommandPacket packet = new CommandPacket(
787                JDWPCommands.ClassTypeCommandSet.CommandSetID,
788                JDWPCommands.ClassTypeCommandSet.SetValuesCommand);
789        packet.setNextValueAsReferenceTypeID(classID);
790        packet.setNextValueAsInt(1);
791        packet.setNextValueAsFieldID(fieldID);
792        packet.setNextValueAsInt(newValue);
793
794        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
795        int errorCode = reply.getErrorCode();
796        if (errorCode != JDWPConstants.Error.NONE) {
797            logWriter
798                    .println("## setStaticIntField(): Can NOT set value for field = '"
799                            + fieldName
800                            + "' in class = '"
801                            + classSignature
802                            + "'; ClassType.SetValues command reurns error = "
803                            + errorCode);
804            return false;
805        }
806        return true;
807    }
808
809    /**
810     * Removes breakpoint of the given event kind corresponding to the given
811     * request id.
812     *
813     * @param eventKind
814     *            request event kind
815     * @param requestID
816     *            request id
817     * @param verbose
818     *            print or don't extra log info
819     */
820    protected void clearEvent(byte eventKind, int requestID, boolean verbose) {
821        CommandPacket packet = new CommandPacket(
822                JDWPCommands.EventRequestCommandSet.CommandSetID,
823                JDWPCommands.EventRequestCommandSet.ClearCommand);
824        packet.setNextValueAsByte(eventKind);
825        packet.setNextValueAsInt(requestID);
826        if (verbose) {
827            logWriter.println("Clearing event: "
828                    + JDWPConstants.EventKind.getName(eventKind) + ", id: "
829                    + requestID);
830        }
831        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
832        checkReplyPacket(reply, "EventRequest::Clear command");
833        assertAllDataRead(reply);
834    }
835}
836