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 15.02.2005
25 */
26package org.apache.harmony.jpda.tests.jdwp.ThreadReference;
27
28import java.util.Vector;
29import java.util.Enumeration;
30
31import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
32import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
33import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
34import org.apache.harmony.jpda.tests.framework.jdwp.Location;
35import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
36import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
37import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
38
39/**
40 * JDWP Unit test for ThreadReference.Frames command.
41 */
42public class FramesTest extends JDWPSyncTestCase {
43
44    short err;
45    long threadID;
46
47    class FrameStruct {
48        long frameID;
49        Location loc;
50        FrameStruct(long frameID, Location loc) {
51            this.frameID = frameID;
52            this.loc = loc;
53        }
54    }
55
56    protected String getDebuggeeClassName() {
57        return "org.apache.harmony.jpda.tests.jdwp.ThreadReference.FramesDebuggee";
58    }
59
60    /**
61     * This testcase exercises ThreadReference.Frames command.
62     * <BR>At first the test starts FramesDebuggee which recursively invokes
63     * the method 'FramesDebuggee.recursiveMethod' thereby the specified depth
64     * 'FramesDebuggee.DEPTH' of recursion is reached.
65     * <BR> Then the tests performs the ThreadReference.Frames command
66     * for the main thread with parameters:
67     * <BR>startFrame=0, length=(amount_of_all_frames + 1)
68     * <BR>It is expected the error INVALID_LENGTH is returned.
69     */
70    public void testFrames005() {
71        logWriter.println("==> testFrames005 START ");
72        String testedThreadName = synchronizer.receiveMessage();
73
74        logWriter.println
75        ("==> testedThreadName = |" + testedThreadName +"|");
76        threadID = debuggeeWrapper.vmMirror.getThreadID(testedThreadName);
77        logWriter.println("==> threadID = " + threadID);
78        debuggeeWrapper.vmMirror.suspendThread(threadID);
79
80        Vector allFrames = getFrames(0, -1);
81        if (err != JDWPConstants.Error.NONE) {
82            printErrorAndFail("Unexpected ERROR = " + err
83                    + "(" + JDWPConstants.Error.getName(err) + ")");
84        }
85        String methodName, classSignature;
86        int i = 0;
87        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
88            FrameStruct frame = (FrameStruct )e.nextElement();
89            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
90            classSignature = getClassSignature(frame.loc.classID);
91            logWriter.println("\t" + i + ". frameID=" + frame.frameID
92                    + " - " + classSignature
93                    + methodName
94                    + "(" + frame.loc.index + ")");
95        }
96
97        allFrames = getFrames(0, allFrames.size() + 1);
98        if (err == JDWPConstants.Error.INVALID_LENGTH) {
99            logWriter.println("Caught expected error - " + JDWPConstants.Error.getName(err)
100                    + "(" + err + ")");
101        } else {
102            printErrorAndFail("unexpected behaviour: error is "
103                    + JDWPConstants.Error.getName(err) + "(" + err + ")"
104                    + " but  must be "
105                    + JDWPConstants.Error.getName(JDWPConstants.Error.INVALID_LENGTH)
106                    + "(" + JDWPConstants.Error.INVALID_LENGTH + ")");
107        }
108        logWriter.println("==> testFrames005 OK. ");
109        debuggeeWrapper.vmMirror.resumeThread(threadID);
110
111        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
112    }
113
114    /**
115     * This testcase exercises ThreadReference.Frames command.
116     * <BR>At first the test starts FramesDebuggee which recursively invokes
117     * the method 'FramesDebuggee.recursiveMethod' thereby the specified depth
118     * 'FramesDebuggee.DEPTH' of recursion is reached.
119     * <BR> Then the tests performs the ThreadReference.Frames command
120     * for the main thread with parameters:
121     * <BR>startFrame=(amount_of_all_frames + 1), length=-1
122     * <BR>It is expected the error INVALID_INDEX is returned.
123     */
124    public void testFrames004() {
125        logWriter.println("==> testFrames004 START ");
126        String testedThreadName = synchronizer.receiveMessage();
127
128        logWriter.println
129        ("==> testedThreadName = |" + testedThreadName +"|");
130        threadID = debuggeeWrapper.vmMirror.getThreadID(testedThreadName);
131        logWriter.println("==> threadID = " + threadID);
132        debuggeeWrapper.vmMirror.suspendThread(threadID);
133
134        Vector allFrames = getFrames(0, -1);
135        if (err != JDWPConstants.Error.NONE) {
136            printErrorAndFail("Unexpected ERROR = " + err
137                    + "(" + JDWPConstants.Error.getName(err) + ")");
138        }
139        String methodName, classSignature;
140        int i = 0;
141        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
142            FrameStruct frame = (FrameStruct )e.nextElement();
143            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
144            classSignature = getClassSignature(frame.loc.classID);
145            logWriter.println("\t" + i + ". frameID=" + frame.frameID
146                       + " - " + classSignature
147                    + methodName
148                    + "(" + frame.loc.index + ")");
149        }
150
151        allFrames = getFrames(allFrames.size() + 1, -1);
152        if (err == JDWPConstants.Error.INVALID_INDEX) {
153            logWriter.println("Caught expected error - " + JDWPConstants.Error.getName(err)
154                    + "(" + err + ")");
155        } else {
156            printErrorAndFail("unexpected behaviour: error is "
157                    + JDWPConstants.Error.getName(err) + "(" + err + ")"
158                    + " but  must be "
159                    + JDWPConstants.Error.getName(JDWPConstants.Error.INVALID_INDEX)
160                    + "(" + JDWPConstants.Error.INVALID_INDEX + ")");
161        }
162
163        logWriter.println("==> testFrames004 OK. ");
164        debuggeeWrapper.vmMirror.resumeThread(threadID);
165
166        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
167    }
168
169    /**
170     * This testcase exercises ThreadReference.Frames command.
171     * <BR>At first the test starts FramesDebuggee which recursively invokes
172     * the method 'FramesDebuggee.recursiveMethod' thereby the specified depth
173     * 'FramesDebuggee.DEPTH' of recursion is reached.
174     * <BR> Then the tests performs the ThreadReference.Frames command
175     * for the main thread with parameters:
176     * <BR>startFrame=amount_of_all_frames, length=-1
177     * <BR>It is expected an empty set of frames is returned.
178     */
179    public void testFrames003() {
180        logWriter.println("==> testFrames003 START ");
181        String testedThreadName = synchronizer.receiveMessage();
182
183        logWriter.println
184        ("==> testedThreadName = |" + testedThreadName +"|");
185        threadID = debuggeeWrapper.vmMirror.getThreadID(testedThreadName);
186        logWriter.println("==> threadID = " + threadID);
187        debuggeeWrapper.vmMirror.suspendThread(threadID);
188
189        Vector allFrames = getFrames(0, -1);
190        if (err != JDWPConstants.Error.NONE) {
191            printErrorAndFail("Unexpected ERROR = " + err
192                    + "(" + JDWPConstants.Error.getName(err) + ")");
193        }
194        String methodName, classSignature;
195        int i = 0;
196        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
197            FrameStruct frame = (FrameStruct )e.nextElement();
198            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
199            classSignature = getClassSignature(frame.loc.classID);
200               logWriter.println("\t" + i + ". frameID=" + frame.frameID
201                       + " - " + classSignature
202                    + methodName
203                    + "(" + frame.loc.index + ")");
204        }
205
206        allFrames = getFrames(allFrames.size(), -1);
207        if (err != JDWPConstants.Error.NONE) {
208            printErrorAndFail("Unexpected ERROR = " + err
209                    + "(" + JDWPConstants.Error.getName(err) + ")");
210        }
211        if (allFrames.size() == 0) {
212            logWriter.println("empty set of frames is returned");
213        } else {
214            printErrorAndFail("it is expected an empty set of frames, but frameCount = "
215                    + allFrames.size());
216        }
217
218        logWriter.println("==> testFrames003 OK. ");
219        debuggeeWrapper.vmMirror.resumeThread(threadID);
220
221        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
222    }
223
224    /**
225     * This testcase exercises ThreadReference.Frames command.
226     * <BR>At first the test starts FramesDebuggee which recursively invokes
227     * the method 'FramesDebuggee.recursiveMethod' thereby the specified depth
228     * 'FramesDebuggee.DEPTH' of recursion is reached.
229     * <BR>Then the test by ThreadReference.Frames command
230     * requests all frames and looks for the first frame
231     * which has location in the 'recursiveMethod'.
232     * <BR>The index of such frame is passed as startFrame parameter for
233     * the second invocation of ThreadReference.Frames command.
234     * <BR>The length (the second parameter) is set to 'FramesDebuggee.DEPTH'.
235     * <BR>It is expected that the amount of returned frames is equal to
236     * 'FramesDebuggee.DEPTH' and all returned frames have locations in
237     * 'recursiveMethod'.
238     */
239    public void testFrames002() {
240        logWriter.println("==> testFrames002 START ");
241        String testedThreadName = synchronizer.receiveMessage();
242
243        logWriter.println
244        ("==> testedThreadName = |" + testedThreadName +"|");
245        threadID = debuggeeWrapper.vmMirror.getThreadID(testedThreadName);
246        logWriter.println("==> threadID = " + threadID);
247        debuggeeWrapper.vmMirror.suspendThread(threadID);
248
249        Vector allFrames = getFrames(0, -1);
250        if (err != JDWPConstants.Error.NONE) {
251            printErrorAndFail("Unexpected ERROR = " + err
252                    + "(" + JDWPConstants.Error.getName(err) + ")");
253        }
254        String methodName, classSignature;
255        int frameNumber = -1;
256        int i = 0;
257        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
258            FrameStruct frame = (FrameStruct )e.nextElement();
259            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
260            classSignature = getClassSignature(frame.loc.classID);
261            if (frameNumber < 0 && FramesDebuggee.METHOD_NAME.equals(methodName)) {
262                frameNumber = i;
263            }
264               logWriter.println("\t" + i + ". frameID=" + frame.frameID
265                       + " - " + classSignature
266                    + methodName
267                    + "(" + frame.loc.index + ")");
268        }
269
270        if (frameNumber < 0) {
271            printErrorAndFail("frameNumber is unexpectedly equal to " + frameNumber);
272        }
273
274        allFrames = getFrames(frameNumber, FramesDebuggee.DEPTH);
275        if (err != JDWPConstants.Error.NONE) {
276            printErrorAndFail("Unexpected ERROR = " + err
277                    + "(" + JDWPConstants.Error.getName(err) + ")");
278        }
279        i = frameNumber;
280        int methodCount = 0;
281        String unexpectedMethods = null;
282        String depthError = null;
283        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
284            FrameStruct frame = (FrameStruct )e.nextElement();
285            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
286            classSignature = getClassSignature(frame.loc.classID);
287            logWriter.println("\t" + i + ". frameID=" + frame.frameID
288                    + " - " + classSignature
289                    + methodName
290                    + "(" + frame.loc.index + ")");
291
292               if (methodName.equals(FramesDebuggee.METHOD_NAME)) {
293                   methodCount++;
294               } else {
295                   logWriter.printError("unexpected method - " + methodName);
296                   unexpectedMethods = null == unexpectedMethods ? methodName : unexpectedMethods + "," + methodName;
297               }
298        }
299
300        if (methodCount != FramesDebuggee.DEPTH) {
301            logWriter.printError(depthError = ("Number of " + FramesDebuggee.METHOD_NAME + " in frames "
302                    + methodCount + "  but expected " + FramesDebuggee.DEPTH));
303        }
304
305        debuggeeWrapper.vmMirror.resumeThread(threadID);
306        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
307
308        if (null != unexpectedMethods) {
309            logWriter.println("==> testFrames002 FAILED ");
310            fail("unexpected method(s): " + unexpectedMethods);
311        }
312        else if (null != depthError) {
313            logWriter.println("==> testFrames002 FAILED ");
314            fail(depthError);
315        } else {
316            logWriter.println("==> testFrames002 OK. ");
317        }
318    }
319
320    /**
321     * This testcase exercises ThreadReference.Frames command.
322     * <BR>At first the test starts FramesDebuggee which recursively invokes
323     * the method 'FramesDebuggee.recursiveMethod' thereby the specified depth
324     * 'FramesDebuggee.DEPTH' of recursion is reached.
325     * <BR>Then the test by ThreadReference.Frames command
326     * requests all frames and looks for the first frame
327     * which has location in the 'recursiveMethod'.
328     * <BR>The index of such frame is passed as startFrame parameter for
329     * the second invocation of ThreadReference.Frames command.
330     * <BR>The length (the second parameter) is set to '-1'.
331     * <BR>It is expected that the amount of returned frames which are located in
332     * 'recursiveMethod' is equal to 'FramesDebuggee.DEPTH'.
333     */
334    public void testFrames001() {
335        logWriter.println("==> testFrames001 START ");
336        String testedThreadName = synchronizer.receiveMessage();
337
338        logWriter.println
339        ("==> testedThreadName = |" + testedThreadName +"|");
340        threadID = debuggeeWrapper.vmMirror.getThreadID(testedThreadName);
341        logWriter.println("==> threadID = " + threadID);
342        debuggeeWrapper.vmMirror.suspendThread(threadID);
343
344        Vector allFrames = getFrames(0, -1);
345        if (err != JDWPConstants.Error.NONE) {
346            printErrorAndFail("Unexpected ERROR = " + err
347                    + "(" + JDWPConstants.Error.getName(err) + ")");
348        }
349        String methodName, classSignature;
350        int frameNumber = -1;
351        int i = 0;
352        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
353            FrameStruct frame = (FrameStruct )e.nextElement();
354            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
355            classSignature = getClassSignature(frame.loc.classID);
356            if (frameNumber < 0 && FramesDebuggee.METHOD_NAME.equals(methodName)) {
357                frameNumber = i;
358            }
359            logWriter.println("\t" + i + ". frameID=" + frame.frameID
360                    + " - " + classSignature
361                    + methodName
362                    + "(" + frame.loc.index + ")");
363        }
364
365        if (frameNumber < 0) {
366            logWriter.printError("frameNumber is unexpectedly equal to " + frameNumber);
367            assertTrue("Invalid frameNumber", frameNumber > 0);
368        }
369
370        allFrames = getFrames(frameNumber, -1);
371        if (err != JDWPConstants.Error.NONE) {
372            printErrorAndFail("Unexpected ERROR = " + err
373                    + "(" + JDWPConstants.Error.getName(err) + ")");
374        }
375        i = frameNumber;
376        int methodCount = 0;
377        boolean testCondition;
378        String unexpectedMethods = null;
379        String depthError = null;
380        for (Enumeration e = allFrames.elements(); e.hasMoreElements(); i++) {
381            FrameStruct frame = (FrameStruct )e.nextElement();
382            methodName = getMethodName(frame.loc.classID, frame.loc.methodID);
383            classSignature = getClassSignature(frame.loc.classID);
384            logWriter.println("\t" + i + ". frameID=" + frame.frameID
385                    + " - " + classSignature
386                    + methodName
387                    + "(" + frame.loc.index + ")");
388               testCondition = (i == frameNumber
389                       && !methodName.equals(FramesDebuggee.METHOD_NAME));
390               if (testCondition) {
391                   logWriter.printError("unexpected method name of the first frame - "
392                           + methodName);
393                   unexpectedMethods = null == unexpectedMethods ? methodName : unexpectedMethods + "," + methodName;
394               }
395
396               if (methodName.equals(FramesDebuggee.METHOD_NAME)) {
397                   methodCount++;
398               }
399        }
400
401        if (methodCount != FramesDebuggee.DEPTH) {
402            logWriter.printError(depthError = ("Number of " + FramesDebuggee.METHOD_NAME + " in frames "
403                    + methodCount + "  but expected " + FramesDebuggee.DEPTH));
404        }
405
406        debuggeeWrapper.vmMirror.resumeThread(threadID);
407        synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
408
409        if (null != unexpectedMethods) {
410            logWriter.println("==> testFrames001 FAILED ");
411            fail("unexpected method(s): " + unexpectedMethods);
412        }
413        else if (null != depthError) {
414            logWriter.println("==> testFrames001 FAILED ");
415            fail(depthError);
416        } else {
417            logWriter.println("==> testFrames001 OK. ");
418        }
419    }
420
421    private Vector getFrames(int startFrame, int length) {
422
423        Vector<FrameStruct> frames = new Vector<FrameStruct>();
424
425        logWriter.println("startFrame=" + startFrame
426                + "; length=" + length);
427
428        // getting frames of the thread
429        CommandPacket packet = new CommandPacket(
430                JDWPCommands.ThreadReferenceCommandSet.CommandSetID,
431                JDWPCommands.ThreadReferenceCommandSet.FramesCommand);
432        packet.setNextValueAsThreadID(threadID);
433        packet.setNextValueAsInt(startFrame);
434        packet.setNextValueAsInt(length);
435        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
436        err = reply.getErrorCode();
437        if ( err != JDWPConstants.Error.NONE) {
438            logWriter.println("\tthreadID=" + threadID
439                    + " - " + JDWPConstants.Error.getName(err));
440            return null;
441        }
442        int framesCount = reply.getNextValueAsInt();
443        long frameID;
444        Location loc;
445        logWriter.println("framesCount=" + framesCount);
446        for (int j = 0; j < framesCount; j++) {
447               frameID = reply.getNextValueAsFrameID();
448               loc = reply.getNextValueAsLocation();
449               frames.add(new FrameStruct(frameID, loc));
450           }
451        return frames;
452    }
453}
454