/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.lcdui;
import com.sun.midp.i3test.TestCase;
import com.sun.midp.util.Baton;
import com.sun.midp.util.LcduiTestMIDlet;
import com.sun.midp.util.LiveTracer;
import com.sun.midp.util.LiveTraceListener;
import com.sun.midp.util.SerialCallback;
/**
* Regression tests for CR 6254765. There are actually two bugs mentioned
* there. Details are provided for each test case.
*/
public class Test6254765 extends TestCase {
Display dpy;
/**
* Checks all of the itemLFs of the given form to see if their layouts are
* valid. Returns true if all are valid, false if any one is invalid.
*/
boolean checkValidLayout(Form form) {
FormLFImpl formLF = (FormLFImpl)form.formLF;
ItemLFImpl itemLF;
boolean anyInvalid = false;
for (int ii = 0; ii < formLF.numOfLFs; ii++) {
itemLF = formLF.itemLFs[ii];
boolean thisInvalid =
itemLF.actualBoundsInvalid[0] ||
itemLF.actualBoundsInvalid[1] ||
itemLF.actualBoundsInvalid[2] ||
itemLF.actualBoundsInvalid[3];
anyInvalid = anyInvalid || thisInvalid;
// System.out.println(
// "item[" + ii + "] bounds (" +
// itemLF.bounds[0] + ", " +
// itemLF.bounds[1] + ", " +
// itemLF.bounds[2] + ", " +
// itemLF.bounds[3] + ")" +
// (thisInvalid ? " INVALID" : ""));
}
return !anyInvalid;
}
/**
* Regression test for the main CR described in CR 6254765. This is a
* race condition between modifying a Form's contents (for example, with
* append) while the Form is in the process of becoming current.
*/
void testScreenChangeAppend() {
StringItem items[] = new StringItem[10];
final Baton baton = new Baton();
for (int ii = 0; ii < items.length; ii++) {
items[ii] = new StringItem(null, Integer.toString(ii % 10));
}
Form form = new Form("Test Form");
// gets called from dpy.callScreenChange() after uCallShow()
dpy.liveTracer.add(
Display.LTR_SCREENCHANGE_AFTERSHOW,
new LiveTraceListener() {
public void call(String tag) {
baton.pass();
}
});
dpy.setCurrent(form);
for (int ii = 0; ii < items.length; ii++) {
form.append(items[ii]);
if (ii == 3) {
baton.start();
}
}
baton.finish();
// wait for queued events to be processed
new SerialCallback(dpy).invokeAndWait();
assertTrue("layout must be valid", checkValidLayout(form));
dpy.liveTracer.clear();
}
/**
* This is a regression test for another CR that is also mentioned in
* 6254765, which occurs when the form is in an inconsistent state such as
* what arose from the initial CR, but which can also arise for other
* reasons.
*
* This case is as follows: traverseIndex == -1 and itemTraverse == false,
* indicating no initial focus; and getNextInteractiveItem returns a value
* >= 0 indicating that there is a focusable item on screen.
*
* The uTraverse() code assumes that if getNextInteractiveItem returns
* some nonnegative value, there must be a currently focused item (that
* is, traverseIndex is also nonnegative). However, this is not always the
* case. This can occur if the form initially has no visible focusable
* items, and the app adds a focusable item, which triggers an invalidate,
* and then the user traverses before the invalidate can be processed.
* This test simulates that case.
*/
void testTraversalInconsistency() {
Form form = new Form("Test Form 2");
FormLFImpl formLF = (FormLFImpl)form.formLF;
final Baton baton = new Baton();
SerialCallback scb = new SerialCallback(dpy);
// can be any interactive item
Item item = new Gauge(null, true, 1, 0);
// Set up a form with no focusable item.
form.append("String 1");
dpy.setCurrent(form);
scb.invokeAndWait();
// Block the event queue to prevent the invalidate from
// being processed.
dpy.callSerially(
new Runnable() {
public void run() {
baton.pass();
}
});
baton.start();
// Append a focusable item to the form, and then call
// uTraverse() directly, as if a key had been pressed at
// exactly the right moment.
form.insert(0, item);
formLF.uTraverse(Canvas.DOWN);
baton.finish();
// Wait for the invalidate to finish processing, then
// check assertions.
scb.invokeAndWait();
assertEquals("item 0 should be focused", 0, formLF.traverseIndex);
}
// main test driver
public void runTests() throws Throwable {
if (!LcduiTestMIDlet.invoke()) {
throw new RuntimeException("can't start LcduiTestMIDlet");
}
try {
dpy = LcduiTestMIDlet.getDisplay();
declare("testScreenChangeAppend");
testScreenChangeAppend();
declare("testTraversalInconsistency");
testTraversalInconsistency();
} finally {
LcduiTestMIDlet.cleanup();
}
}
}
/*
* A mock LayoutManager. Can be inserted into the LayoutManager class in order
* to instrument call to the lLayout method, among other things. To use,
* first save away the normal layout manager:
*
* LayoutManager savedLayoutManager = LayoutManager.instance();
*
* Then install the mock:
*
* LayoutManager.singleInstance = new MockLayoutManager();
*
* After testing, preferably within a finally clause, restore the original
* layout manager:
*
* LayoutManager.singleInstance = savedLayoutManager;
*
* Failure to do this may have side effects on other tests!
*/
// class MockLayoutManager extends LayoutManager {
// int count; // = 0
//
// void lLayout(int layoutMode,
// ItemLFImpl[] itemLFs,
// int numOfLFs,
// int inp_viewportWidth,
// int inp_viewportHeight,
// int[] viewable) {
// count = numOfLFs;
// super.lLayout(
// layoutMode,
// itemLFs,
// numOfLFs,
// inp_viewportWidth,
// inp_viewportHeight,
// viewable);
// }
// }