diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /tests/DumpRenderTree/src/com/android/dumprendertree | |
parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
download | frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'tests/DumpRenderTree/src/com/android/dumprendertree')
12 files changed, 2110 insertions, 0 deletions
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java new file mode 100644 index 0000000..a389461 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import android.os.Handler; +import android.os.Message; + +import java.util.HashMap; + +public class CallbackProxy extends Handler implements EventSender, LayoutTestController { + + private EventSender mEventSender; + private LayoutTestController mLayoutTestController; + + private static final int EVENT_DOM_LOG = 1; + private static final int EVENT_FIRE_KBD = 2; + private static final int EVENT_KEY_DOWN_1 = 3; + private static final int EVENT_KEY_DOWN_2 = 4; + private static final int EVENT_LEAP = 5; + private static final int EVENT_MOUSE_CLICK = 6; + private static final int EVENT_MOUSE_DOWN = 7; + private static final int EVENT_MOUSE_MOVE = 8; + private static final int EVENT_MOUSE_UP = 9; + + private static final int LAYOUT_CLEAR_LIST = 20; + private static final int LAYOUT_DISPLAY = 21; + private static final int LAYOUT_DUMP_TEXT = 22; + private static final int LAYOUT_DUMP_HISTORY = 23; + private static final int LAYOUT_DUMP_CHILD_SCROLL = 24; + private static final int LAYOUT_DUMP_EDIT_CB = 25; + private static final int LAYOUT_DUMP_SEL_RECT = 26; + private static final int LAYOUT_DUMP_TITLE_CHANGES = 27; + private static final int LAYOUT_KEEP_WEB_HISTORY = 28; + private static final int LAYOUT_NOTIFY_DONE = 29; + private static final int LAYOUT_QUEUE_BACK_NAV = 30; + private static final int LAYOUT_QUEUE_FWD_NAV = 31; + private static final int LAYOUT_QUEUE_LOAD = 32; + private static final int LAYOUT_QUEUE_RELOAD = 33; + private static final int LAYOUT_QUEUE_SCRIPT = 34; + private static final int LAYOUT_REPAINT_HORZ = 35; + private static final int LAYOUT_SET_ACCEPT_EDIT = 36; + private static final int LAYOUT_MAIN_FIRST_RESP = 37; + private static final int LAYOUT_SET_WINDOW_KEY = 38; + private static final int LAYOUT_TEST_REPAINT = 39; + private static final int LAYOUT_WAIT_UNTIL_DONE = 40; + + CallbackProxy(EventSender eventSender, + LayoutTestController layoutTestController) { + mEventSender = eventSender; + mLayoutTestController = layoutTestController; + } + + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_DOM_LOG: + mEventSender.enableDOMUIEventLogging(msg.arg1); + break; + case EVENT_FIRE_KBD: + mEventSender.fireKeyboardEventsToElement(msg.arg1); + break; + case EVENT_KEY_DOWN_1: + HashMap map = (HashMap) msg.obj; + mEventSender.keyDown((String) map.get("character"), + (String[]) map.get("withModifiers")); + break; + + case EVENT_KEY_DOWN_2: + mEventSender.keyDown((String)msg.obj); + break; + + case EVENT_LEAP: + mEventSender.leapForward(msg.arg1); + break; + + case EVENT_MOUSE_CLICK: + mEventSender.mouseClick(); + break; + + case EVENT_MOUSE_DOWN: + mEventSender.mouseDown(); + break; + + case EVENT_MOUSE_MOVE: + mEventSender.mouseMoveTo(msg.arg1, msg.arg2); + break; + + case EVENT_MOUSE_UP: + mEventSender.mouseUp(); + break; + + case LAYOUT_CLEAR_LIST: + mLayoutTestController.clearBackForwardList(); + break; + + case LAYOUT_DISPLAY: + mLayoutTestController.display(); + break; + + case LAYOUT_DUMP_TEXT: + mLayoutTestController.dumpAsText(); + break; + + case LAYOUT_DUMP_HISTORY: + mLayoutTestController.dumpBackForwardList(); + break; + + case LAYOUT_DUMP_CHILD_SCROLL: + mLayoutTestController.dumpChildFrameScrollPositions(); + break; + + case LAYOUT_DUMP_EDIT_CB: + mLayoutTestController.dumpEditingCallbacks(); + break; + + case LAYOUT_DUMP_SEL_RECT: + mLayoutTestController.dumpSelectionRect(); + break; + + case LAYOUT_DUMP_TITLE_CHANGES: + mLayoutTestController.dumpTitleChanges(); + break; + + case LAYOUT_KEEP_WEB_HISTORY: + mLayoutTestController.keepWebHistory(); + break; + + case LAYOUT_NOTIFY_DONE: + mLayoutTestController.notifyDone(); + break; + + case LAYOUT_QUEUE_BACK_NAV: + mLayoutTestController.queueBackNavigation(msg.arg1); + break; + + case LAYOUT_QUEUE_FWD_NAV: + mLayoutTestController.queueForwardNavigation(msg.arg1); + break; + + case LAYOUT_QUEUE_LOAD: + HashMap<String, String> loadMap = + (HashMap<String, String>) msg.obj; + mLayoutTestController.queueLoad(loadMap.get("Url"), + loadMap.get("frameTarget")); + break; + + case LAYOUT_QUEUE_RELOAD: + mLayoutTestController.queueReload(); + break; + + case LAYOUT_QUEUE_SCRIPT: + mLayoutTestController.queueScript((String)msg.obj); + break; + + case LAYOUT_REPAINT_HORZ: + mLayoutTestController.repaintSweepHorizontally(); + break; + + case LAYOUT_SET_ACCEPT_EDIT: + mLayoutTestController.setAcceptsEditing( + msg.arg1 == 1 ? true : false); + break; + case LAYOUT_MAIN_FIRST_RESP: + mLayoutTestController.setMainFrameIsFirstResponder( + msg.arg1 == 1 ? true : false); + break; + + case LAYOUT_SET_WINDOW_KEY: + mLayoutTestController.setWindowIsKey( + msg.arg1 == 1 ? true : false); + break; + + case LAYOUT_TEST_REPAINT: + mLayoutTestController.testRepaint(); + break; + + case LAYOUT_WAIT_UNTIL_DONE: + mLayoutTestController.waitUntilDone(); + break; + } + } + + // EventSender Methods + + public void enableDOMUIEventLogging(int DOMNode) { + obtainMessage(EVENT_DOM_LOG, DOMNode, 0).sendToTarget(); + } + + public void fireKeyboardEventsToElement(int DOMNode) { + obtainMessage(EVENT_FIRE_KBD, DOMNode, 0).sendToTarget(); + } + + public void keyDown(String character, String[] withModifiers) { + // TODO Auto-generated method stub + HashMap map = new HashMap(); + map.put("character", character); + map.put("withModifiers", withModifiers); + obtainMessage(EVENT_KEY_DOWN_1, map).sendToTarget(); + } + + public void keyDown(String character) { + obtainMessage(EVENT_KEY_DOWN_2, character).sendToTarget(); + } + + public void leapForward(int milliseconds) { + obtainMessage(EVENT_LEAP, milliseconds, 0).sendToTarget(); + } + + public void mouseClick() { + obtainMessage(EVENT_MOUSE_CLICK).sendToTarget(); + } + + public void mouseDown() { + obtainMessage(EVENT_MOUSE_DOWN).sendToTarget(); + } + + public void mouseMoveTo(int X, int Y) { + obtainMessage(EVENT_MOUSE_MOVE, X, Y).sendToTarget(); + } + + public void mouseUp() { + obtainMessage(EVENT_MOUSE_UP).sendToTarget(); + } + + // LayoutTestController Methods + + public void clearBackForwardList() { + obtainMessage(LAYOUT_CLEAR_LIST).sendToTarget(); + } + + public void display() { + obtainMessage(LAYOUT_DISPLAY).sendToTarget(); + } + + public void dumpAsText() { + obtainMessage(LAYOUT_DUMP_TEXT).sendToTarget(); + } + + public void dumpBackForwardList() { + obtainMessage(LAYOUT_DUMP_HISTORY).sendToTarget(); + } + + public void dumpChildFrameScrollPositions() { + obtainMessage(LAYOUT_DUMP_CHILD_SCROLL).sendToTarget(); + } + + public void dumpEditingCallbacks() { + obtainMessage(LAYOUT_DUMP_EDIT_CB).sendToTarget(); + } + + public void dumpSelectionRect() { + obtainMessage(LAYOUT_DUMP_SEL_RECT).sendToTarget(); + } + + public void dumpTitleChanges() { + obtainMessage(LAYOUT_DUMP_TITLE_CHANGES).sendToTarget(); + } + + public void keepWebHistory() { + obtainMessage(LAYOUT_KEEP_WEB_HISTORY).sendToTarget(); + } + + public void notifyDone() { + obtainMessage(LAYOUT_NOTIFY_DONE).sendToTarget(); + } + + public void queueBackNavigation(int howfar) { + obtainMessage(LAYOUT_QUEUE_BACK_NAV, howfar, 0).sendToTarget(); + } + + public void queueForwardNavigation(int howfar) { + obtainMessage(LAYOUT_QUEUE_FWD_NAV, howfar, 0).sendToTarget(); + } + + public void queueLoad(String Url, String frameTarget) { + HashMap <String, String>map = new HashMap<String, String>(); + map.put("Url", Url); + map.put("frameTarget", frameTarget); + obtainMessage(LAYOUT_QUEUE_LOAD, map).sendToTarget(); + } + + public void queueReload() { + obtainMessage(LAYOUT_QUEUE_RELOAD).sendToTarget(); + } + + public void queueScript(String scriptToRunInCurrentContext) { + obtainMessage(LAYOUT_QUEUE_SCRIPT, + scriptToRunInCurrentContext).sendToTarget(); + } + + public void repaintSweepHorizontally() { + obtainMessage(LAYOUT_REPAINT_HORZ).sendToTarget(); + } + + public void setAcceptsEditing(boolean b) { + obtainMessage(LAYOUT_SET_ACCEPT_EDIT, b ? 1 : 0, 0).sendToTarget(); + } + + public void setMainFrameIsFirstResponder(boolean b) { + obtainMessage(LAYOUT_MAIN_FIRST_RESP, b ? 1 : 0, 0).sendToTarget(); + } + + public void setWindowIsKey(boolean b) { + obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget(); + } + + public void testRepaint() { + obtainMessage(LAYOUT_TEST_REPAINT).sendToTarget(); + } + + public void waitUntilDone() { + obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget(); + } + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java new file mode 100644 index 0000000..82fd8d8 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +public interface EventSender { + public void mouseDown(); + public void mouseUp(); + public void mouseClick(); + public void mouseMoveTo(int X, int Y); + public void leapForward(int milliseconds); + public void keyDown (String character, String[] withModifiers); + public void keyDown (String character); + public void enableDOMUIEventLogging(int DOMNode); + public void fireKeyboardEventsToElement(int DOMNode); +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java new file mode 100644 index 0000000..9be33db --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import java.util.HashSet; +import java.util.Hashtable; +import android.util.*; + +public class FileFilter { + + public static boolean ignoreTest(String file) { + // treat files like directories for the time being. + for (int i = 0; i < ignoreTestList.length; i ++) { + if (file.endsWith(ignoreTestList[i])) { + Log.e("FileFilter", "File path in IgnoreTest: " + file); + return true; + } + } + for (int i = 0; i < ignoreTestDirs.length; i++) { + if (file.endsWith(ignoreTestDirs[i])) { + Log.e("FileFilter", "File path in ignore list: " + file); + return true; + } + } + + return false; + } + + public static boolean ignoreResults(String file) { + int index = file.indexOf("fast"); + if (index != -1) { + String sub = file.substring(index); + if (ignoreResultList.contains(sub)) + return true; + } + return false; + + } + + public static String isKnownBug(String file) { + int index = file.indexOf("fast"); + if (index != -1) { + String sub = file.substring(index); + // Log.e("FileFilter", "Looking for:"+sub); + if (bugList.containsKey(sub)) + return bugList.get(sub); + } + return null; + } + + final static HashSet<String> ignoreResultList = new HashSet<String>(); + final static Hashtable<String, String> bugList = + new Hashtable<String, String>(); + + static { + fillIgnoreResultSet(); + fillBugTable(); + } + + static final String[] ignoreTestDirs = { + ".", // ignore hidden directories and files + "resources", // ignore resource directories + "AppleScript", // AppleScript not supported + "xpath", // xpath requires libxml2, not supported + "xsl", //xsl requires libxml2 & libxslt, not sup. + "kde", // don't run kde tests. + ".svn", // don't run anything under .svn folder + "gradients", // known crash + "profiler" // profiler is not supported + }; + + static final String [] ignoreTestList = { + "toString-stack-overflow.html", // Crashes #606688 + "frame-limit.html", // generates too many GREFs + "css-insert-import-rule.html", // Crashes, #717414 + "input-text-enter.html", // Crashes. #735088 + "text-shadow-extreme-value.html", // Crashes #571671 + "reflection-masks.html", + "frame-creation-removal.html", + "large-expressions.html", + "null-page-show-modal-dialog-crash.html", + "font-face-implicit-local-font.html", + "font-face-locally-installed.html", + "beforeSelectorOnCodeElement.html", + "cssTarget-crash.html", + "searchfield-heights.html", // Bug 1570692 + "tabindex-focus-blur-all.html", + "search-rtl.html" // fast/forms/search-rtl.html + }; + + static void fillIgnoreResultSet() { + // need test plugin + ignoreResultList.add("fast/dom/Window/Plug-ins.html"); + // pixel depth + ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); + // missing space in textrun, ok as text is wrapped. ignore. #714933 + ignoreResultList.add("fast/events/onload-webkit-before-webcore.html"); + // missing support for textInputController.makeAttributedString() + ignoreResultList.add("fast/forms/attributed-strings.html"); + // charset convert. #516936 ignore, won't fix + ignoreResultList.add("fast/forms/form-data-encoding-2.html"); + // charset convert. #516936 ignore, won't fix + ignoreResultList.add("fast/forms/form-data-encoding.html"); + // execCommand "insertText" not supported + ignoreResultList.add("fast/forms/input-appearance-maxlength.html"); + // Copy&Paste commands not supported + ignoreResultList.add("fast/forms/input-truncate-newline.html"); + ignoreResultList.add("fast/forms/textarea-paste-newline.html"); + // requires eventSender.mouseMoveTo, mouseDown & mouseUp and + // abs. position of mouse to select a word. ignore, won't fix #716583 + ignoreResultList.add("fast/forms/onselect-textarea.html"); + // requires eventSender.mouseMoveTo, mouseDown & mouseUp and + // abs. position of mouse to select a word. ignore, won't fix #716583 + ignoreResultList.add("fast/forms/onselect-textfield.html"); + // not implemented queryCommandEnabled:BackColor, Undo & Redo + ignoreResultList.add("fast/forms/plaintext-mode-1.html"); + // Our text areas are a little thinner than Apples. Also RTL test failes + ignoreResultList.add("fast/forms/textarea-appearance-wrap.html"); + // Our text areas are a little thinner than Apples + ignoreResultList.add("fast/forms/textarea-hard-linewrap.html"); + // screen width&height are different + ignoreResultList.add("fast/frames/frameElement-widthheight.html"); + ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html"); + // requires JS test API, textInputController + ignoreResultList.add("fast/text/attributed-substring-from-range.html"); + ignoreResultList.add("fast/text/attributed-substring-from-range-001.html"); + // will not fix #619707 + ignoreResultList.add("fast/css/case-transform.html"); + // different platform defaults for font and different screen size + ignoreResultList.add("fast/css/computed-style.html"); + // different screen size result in extra spaces in Apple compared to us + ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); + // xslt and xpath elements missing from property list + ignoreResultList.add("fast/dom/Window/window-properties.html"); + // requires textInputController.characterIndexForPoint + ignoreResultList.add("fast/dom/character-index-for-point.html"); + // requires xpath support + ignoreResultList.add("fast/dom/gc-9.html"); + // requires xslt and xpath support + ignoreResultList.add("fast/dom/global-constructors.html"); + // dynamic plugins not supported + ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); + ignoreResultList.add("fast/js/navigator-mimeTypes-length.html"); + // there is extra spacing in the file due to multiple input boxes + // fitting on one line on Apple, ours are wrapped. Space at line ends + // are stripped. + ignoreResultList.add("fast/dom/tabindex-clamp.html"); + + // requires eventSender.mouseDown(),mouseUp() + ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); + ignoreResultList.add("fast/events/window-events-bubble.html"); + ignoreResultList.add("fast/events/window-events-bubble2.html"); + ignoreResultList.add("fast/events/window-events-capture.html"); + ignoreResultList.add("fast/forms/select-empty-list.html"); + ignoreResultList.add("fast/replaced/image-map.html"); + ignoreResultList.add("fast/events/capture-on-target.html"); + ignoreResultList.add("fast/events/dblclick-addEventListener.html"); + ignoreResultList.add("fast/events/drag-in-frames.html"); + ignoreResultList.add("fast/events/drag-outside-window.html"); + ignoreResultList.add("fast/events/event-sender-mouse-click.html"); + ignoreResultList.add("fast/events/event-view-toString.html"); + ignoreResultList.add("fast/events/frame-click-focus.html"); + ignoreResultList.add("fast/events/input-image-scrolled-x-y.html"); + ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); + ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html"); + ignoreResultList.add("fast/events/mouseover-mouseout.html"); + ignoreResultList.add("fast/events/mouseover-mouseout2.html"); + ignoreResultList.add("fast/events/mouseup-outside-button.html"); + ignoreResultList.add("fast/events/mouseup-outside-document.html"); + ignoreResultList.add("fast/events/onclick-list-marker.html"); + ignoreResultList.add("fast/events/ondragenter.html"); + ignoreResultList.add("fast/forms/drag-into-textarea.html"); + ignoreResultList.add("fast/forms/input-select-on-click.html"); + ignoreResultList.add("fast/forms/listbox-onchange.html"); + ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html"); + ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html"); + + // there is extra spacing in the file due to multiple frame boxes + // fitting on one line on Apple, ours are wrapped. Space at line ends + // are stripped. + ignoreResultList.add("fast/events/iframe-object-onload.html"); + // eventSender.mouseDown(), mouseUp() and objc API missing + ignoreResultList.add("fast/events/mouseup-outside-document.html"); + ignoreResultList.add("fast/events/objc-keyboard-event-creation.html"); + ignoreResultList.add("fast/events/objc-event-api.html"); + // not capturing the console messages + ignoreResultList.add("fast/forms/selected-index-assert.html"); + ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html"); + // there is extra spacing as the text areas and input boxes fit next + // to each other on Apple, but are wrapped on our screen. + ignoreResultList.add("fast/forms/selection-functions.html"); + // Text selection done differently on our platform. When a inputbox + // gets focus, the entire block is selected. + ignoreResultList.add("fast/forms/textarea-initial-caret-position.html"); + ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html"); + // Requires LayoutTests to exist at /tmp/LayoutTests + ignoreResultList.add("fast/loader/local-JavaScript-from-local.html"); + ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html"); + // extra spacing because iFrames rendered next to each other on Apple + ignoreResultList.add("fast/loader/opaque-base-url.html"); + // RegExp is too large, causing OOM + ignoreResultList.add("fast/js/regexp-charclass-crash.html"); + ignoreResultList.add("fast/text/plain-text-line-breaks.html"); + + + } + + static void fillBugTable() { + bugList.put("fast/forms/check-box-enter-key.html", "716715"); + bugList.put("fast/forms/focus-control-to-page.html", "716638"); + bugList.put("fast/html/tab-order.html", "719289"); + bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229"); + bugList.put("fast/dom/location-hash.html", "733822"); + bugList.put("fast/dom/set-innerHTML.html", "733823"); + bugList.put("fast/dom/xmlhttprequest-get.html", "733846"); + bugList.put("fast/encoding/css-charset-default.html", "733856"); + bugList.put("fast/encoding/default-xhtml-encoding.html", "733882"); + bugList.put("fast/encoding/meta-in-xhtml.html", "733882"); + bugList.put("fast/events/frame-tab-focus.html", "734308"); + bugList.put("fast/events/keydown-keypress-focus-change.html", "653224"); + bugList.put("fast/events/keypress-focus-change.html", "653224"); + bugList.put("fast/events/option-tab.html", "734308"); + bugList.put("fast/forms/focus2.html", "735111"); + bugList.put("fast/forms/listbox-selection.html", "735116"); + bugList.put("fast/forms/search-event-delay.html", "735120"); + bugList.put("fast/frames/iframe-window-focus.html", "735140"); + bugList.put("fast/innerHTML/004.html", "733882"); + bugList.put("fast/js/date-DST-time-cusps.html", "735144"); + bugList.put("fast/js/string-capitalization.html", "516936"); + bugList.put("fast/js/string-concatenate-outofmemory.html","735152"); + bugList.put("fast/parser/external-entities.html", "735176"); + bugList.put("fast/events/div-focus.html", "735185"); + bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196"); + bugList.put("fast/events/arrow-navigation.html", "735233"); + bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244"); + bugList.put("fast/events/js-keyboard-event-creation.html", "735255"); + + } + + + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java new file mode 100644 index 0000000..d685f5d --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.io.File; + +import android.app.ListActivity; +import android.view.KeyEvent; +import android.view.View; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.os.Bundle; + + +public abstract class FileList extends ListActivity +{ + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) + { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (mPath.length() > mBaseLength) { + File f = new File(mPath); + mFocusFile = f.getName(); + mFocusIndex = 0; + f = f.getParentFile(); + mPath = f.getPath(); + updateList(); + return true; + } + break; + + case KeyEvent.KEYCODE_DPAD_RIGHT: + { + Map map = (Map) getListView().getItemAtPosition(getListView().getSelectedItemPosition()); + String path = (String)map.get("path"); + if ((new File(path)).isDirectory()) { + mPath = path; + mFocusFile = null; + updateList(); + } else { + processFile(path, false); + } + return true; + } + + default: + break; + } + return super.onKeyDown(keyCode, event); + } + + public void onCreate(Bundle icicle) + { + super.onCreate(icicle); + setupPath(); + updateList(); + } + + protected List getData() + { + List myData = new ArrayList<HashMap>(); + + File f = new File(mPath); + if (!f.exists()) { + addItem(myData, "!LayoutTests path missing!", ""); + return myData; + } + String[] files = f.list(); + + for (int i = 0; i < files.length; i++) { + StringBuilder sb = new StringBuilder(mPath); + sb.append(File.separatorChar); + sb.append(files[i]); + String path = sb.toString(); + File c = new File(path); + if (fileFilter(c)) { + if (c.isDirectory()) { + addItem(myData, "<"+files[i]+">", path); + if (mFocusFile != null && mFocusFile.equals(files[i])) + mFocusIndex = myData.size()-1; + } + else + addItem(myData, files[i], path); + } + } + + return myData; + } + + protected void addItem(List<Map> data, String name, String path) + { + HashMap temp = new HashMap(); + temp.put("title", name); + temp.put("path", path); + data.add(temp); + } + + protected void onListItemClick(ListView l, View v, int position, long id) + { + Map map = (Map) l.getItemAtPosition(position); + String path = (String)map.get("path"); + + if ((new File(path)).isDirectory()) { + mPath = path; + mFocusFile = null; + updateList(); + } else { + processFile(path, false); + } + } + + /* + * This function is called when the user has selected a file in the + * file list. The selected file could be a file or a directory. + * The flag indicates if this was from a selection or not. + */ + abstract void processFile(String filename, boolean selection); + + /* + * This function is called when the file list is being built. Return + * true if the file is to be added to the file list. + */ + abstract boolean fileFilter(File f); + + protected void updateList() { + setListAdapter(new SimpleAdapter(this, + getData(), + android.R.layout.simple_list_item_1, + new String[] {"title"}, + new int[] {android.R.id.text1})); + String title = mPath; //.substring(mBaseLength-11); // show the word LayoutTests + setTitle(title); + getListView().setSelection(mFocusIndex); + } + + protected void setupPath() + { + mPath = "/sdcard/android/layout_tests"; + mBaseLength = mPath.length(); + } + + protected String mPath; + protected int mBaseLength; + protected String mFocusFile; + protected int mFocusIndex; + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java new file mode 100644 index 0000000..86bfad7 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java @@ -0,0 +1,726 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.List; +import java.util.Vector; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.KeyEvent; +import android.view.ViewGroup; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.LinearLayout; +import android.os.*; + +// TestRecorder creates two files, one for passing tests +// and another for failing tests and writes the paths to +// layout tests one line at a time. TestRecorder does not +// have ability to clear the results. +class TestRecorder { + public void passed(String layout_file) { + try { + mBufferedOutputPassedStream.write(layout_file.getBytes()); + mBufferedOutputPassedStream.write('\n'); + mBufferedOutputPassedStream.flush(); + } catch(Exception e) { + e.printStackTrace(); + } + } + + public void failed(String layout_file, String reason) { + try { + mBufferedOutputFailedStream.write(layout_file.getBytes()); + mBufferedOutputFailedStream.write(" : ".getBytes()); + mBufferedOutputFailedStream.write(reason.getBytes()); + mBufferedOutputFailedStream.write('\n'); + mBufferedOutputFailedStream.flush(); + } catch(Exception e) { + e.printStackTrace(); + } + } + + public void nontext(String layout_file, boolean has_results) { + try { + mBufferedOutputNontextStream.write(layout_file.getBytes()); + if (has_results) { + mBufferedOutputNontextStream.write(" : has expected results".getBytes()); + } + mBufferedOutputNontextStream.write('\n'); + mBufferedOutputNontextStream.flush(); + } catch(Exception e) { + e.printStackTrace(); + } + } + + public TestRecorder(boolean resume) { + try { + File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt"); + File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt"); + File resultsNontextFile = new File("/sdcard/layout_tests_nontext.txt"); + + mBufferedOutputPassedStream = + new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume)); + mBufferedOutputFailedStream = + new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume)); + mBufferedOutputNontextStream = + new BufferedOutputStream(new FileOutputStream(resultsNontextFile, resume)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void close() { + try { + mBufferedOutputPassedStream.close(); + mBufferedOutputFailedStream.close(); + mBufferedOutputNontextStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + private BufferedOutputStream mBufferedOutputPassedStream; + private BufferedOutputStream mBufferedOutputFailedStream; + private BufferedOutputStream mBufferedOutputNontextStream; +} + +public class HTMLHostActivity extends Activity + implements LayoutTestController { + + public class AsyncHandler extends Handler { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_TIMEOUT) { + mTimedOut = true; + requestWebKitData(); + return; + } else if (msg.what == MSG_WEBKIT_DATA) { + HTMLHostActivity.this.dump(mTimedOut, (String)msg.obj); + return; + } + + super.handleMessage(msg); + } + } + + public void requestWebKitData() { + Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA); + + if (mRequestedWebKitData) + throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl()); + + mRequestedWebKitData = true; + if (mDumpAsText) { + mWebView.documentAsText(callback); + } else { + mWebView.externalRepresentation(callback); + } + } + // Activity methods + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + LinearLayout contentView = new LinearLayout(this); + contentView.setOrientation(LinearLayout.VERTICAL); + setContentView(contentView); + + mWebView = new WebView(this); + mWebView.getSettings().setJavaScriptEnabled(true); + mWebView.setWebChromeClient(mChromeClient); + mEventSender = new WebViewEventSender(mWebView); + mCallbackProxy = new CallbackProxy(mEventSender, this); + mFinishedRunning = false; + + mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController"); + mWebView.addJavascriptInterface(mCallbackProxy, "eventSender"); + contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f)); + + mHandler = new AsyncHandler(); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + } + + private void getTestList() { + // Read test list. + try { + BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE)); + String line = inReader.readLine(); + while (line != null) { + if (line.startsWith(mTestPathPrefix)) + mTestList.add(line); + line = inReader.readLine(); + } + inReader.close(); + Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s)."); + } catch (Exception e) { + Log.e(LOGTAG, "Error while reading test list : " + e.getMessage()); + } + } + + private void resumeTestList() { + // read out the test name it stoped last time. + try { + BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE)); + String line = inReader.readLine(); + for (int i = 0; i < mTestList.size(); i++) { + if (mTestList.elementAt(i).equals(line)) { + mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size())); + break; + } + } + inReader.close(); + } catch (Exception e) { + Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE); + } + } + + private void clearTestStatus() { + // Delete TEST_STATUS_FILE + try { + File f = new File(TEST_STATUS_FILE); + if (f.delete()) + Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE); + else + Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE); + } catch (Exception e) { + Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage()); + } + } + + private void updateTestStatus(String s) { + // Write TEST_STATUS_FILE + try { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE)); + bos.write(s.getBytes()); + bos.close(); + } catch (Exception e) { + Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE); + } + } + + protected void onResume() { + super.onResume(); + if (mTestList == null) + mTestList = new Vector<String>(); + + if (mTestList.isEmpty()) { + // Read settings + Intent intent = getIntent(); + mTestPathPrefix = intent.getStringExtra(TEST_PATH_PREFIX); + mSingleTestMode = intent.getBooleanExtra(SINGLE_TEST_MODE, false); + boolean resume = intent.getBooleanExtra(RESUME_FROM_CRASH, false); + mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 8000); + + mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); + + if (mTestPathPrefix == null) + throw new AssertionError("mTestPathPrefix cannot be null"); + + Log.v(LOGTAG, "Run tests with prefix: " + mTestPathPrefix); + + mResultRecorder = new TestRecorder(resume); + + if (!resume) + clearTestStatus(); + + if (!mSingleTestMode) { + getTestList(); + if (resume) + resumeTestList(); + } else { + mTestList.add(mTestPathPrefix); + } + + if (!mTestList.isEmpty()) + runTestAtIndex(0); + else + mWebView.loadUrl("about:"); + } + } + + protected void onStop() { + super.onStop(); + mWebView.stopLoading(); + } + + protected void onDestroy() { + super.onDestroy(); + mResultRecorder.close(); + mWebView.destroy(); + mWebView = null; + } + + public void onLowMemory() { + super.onLowMemory(); + // Simulate a crash + Log.e(LOGTAG, "Low memory, killing self"); + System.exit(1); + } + + public boolean dispatchKeyEvent(KeyEvent event) { + // Log key strokes as they don't seem to be matched + //Log.e(LOGTAG, "Event: "+event); + return super.dispatchKeyEvent(event); + } + + // Run a test at specified index in the test list. + // Stops activity if run out of tests. + protected void runTestAtIndex(int testIndex) { + mTestIndex = testIndex; + + resetTestStatus(); + + if (testIndex == mTestList.size()) { + if (!mSingleTestMode) { + updateTestStatus("#DONE"); + } + finished(); + return; + } + String s = mTestList.elementAt(testIndex); + if (!mSingleTestMode) + updateTestStatus(s); + + Log.v(LOGTAG, " Running test: "+s); + mWebView.loadUrl("file://"+s); + + if (!mSingleTestMode) { + // Create a timeout timer + Message m = mHandler.obtainMessage(MSG_TIMEOUT); + mHandler.sendMessageDelayed(m, mTimeoutInMillis); + } + } + + // Dump the page + public void dump(boolean timeout, String webkitData) { + String currentTest = mTestList.elementAt(mTestIndex); + String resultFile = currentTest.substring(0, currentTest.lastIndexOf('.')); + + // dumpAsText version can be directly compared to expected results + if (mDumpAsText) { + resultFile += "-results.txt"; + } else { + resultFile += "-android-results.txt"; + } + + try { + FileOutputStream os = new FileOutputStream(resultFile); + if (timeout) { + Log.w("Layout test: Timeout", resultFile); + os.write(TIMEOUT_STR.getBytes()); + os.write('\n'); + } + if (mDumpTitleChanges) + os.write(mTitleChanges.toString().getBytes()); + if (mDialogStrings != null) + os.write(mDialogStrings.toString().getBytes()); + mDialogStrings = null; + os.write(webkitData.getBytes()); + os.flush(); + os.close(); + } catch (FileNotFoundException ex) { + ex.printStackTrace(); + } catch (IOException ex) { + ex.printStackTrace(); + } + + processResult(timeout, currentTest); + runTestAtIndex(mTestIndex + 1); + } + + // Wrap up + public void failedCase(String file, String reason) { + Log.w("Layout test: ", file + " failed " + reason); + mResultRecorder.failed(file, reason); + + String bugNumber = FileFilter.isKnownBug(file); + if (bugNumber != null) { + System.out.println("FAIL known:"+bugNumber+ " "+file+reason); + return; + } + if (FileFilter.ignoreResults(file)) { + return; + } + System.out.println("FAIL: "+file+reason); + } + + public void passedCase(String file) { + Log.v("Layout test:", file + " passed"); + mResultRecorder.passed(file); + + String bugNumber = FileFilter.isKnownBug(file); + if (bugNumber != null) { + System.out.println("Bug Fixed: "+bugNumber+ " "+file); + return; + } + + if (FileFilter.ignoreResults(file)) { + System.out.println("Ignored test passed: "+file); + return; + } + } + + public void nontextCase(String file, boolean has_expected_results) { + Log.v("Layout test:", file + " nontext"); + mResultRecorder.nontext(file, has_expected_results); + } + + public void setCallback(HTMLHostCallbackInterface callback) { + mCallback = callback; + } + + public void processResult(boolean timeout, String test_path) { + Log.v(LOGTAG, " Processing result: " + test_path); + // remove the extension + String short_file = test_path.substring(0, test_path.lastIndexOf('.')); + if (timeout) { + failedCase(test_path, "TIMEDOUT"); + return; + } + // Only check results that we can check, ie dumpAsText results + String dumpFile = short_file + "-results.txt"; + File f = new File(dumpFile); + if (f.exists()) { + try { + FileInputStream fr = new FileInputStream(short_file+"-results.txt"); + FileInputStream fe = new FileInputStream(short_file+"-expected.txt"); + + // If the length is different then they are different + int diff = fe.available() - fr.available(); + if (diff > 1 || diff < 0) { + failedCase(test_path, " different length"); + fr.close(); + fe.close(); + return; + } + byte[] br = new byte[fr.available()]; + byte[] be = new byte[fe.available()]; + fr.read(br); + fe.read(be); + boolean fail = false; + for (int i = 0; i < br.length; i++) { + if (br[i] != be[i]) { + failedCase(test_path, " @offset: "+i); + fr.close(); + fe.close(); + return; + } + } + if (br.length != be.length && be[be.length-1] == '\n') { + Log.d(LOGTAG, "Extra new line being ignore:" + test_path); + } + fr.close(); + fe.close(); + passedCase(test_path); + } catch (FileNotFoundException ex) { + // TODO do something here + } catch (IOException ex) { + // Failed on available() or read() + } + + return; + } + + File nontext_result = new File(short_file + "-android-results.txt"); + if (nontext_result.exists()) { + // Check if the test has expected results. + File expected = new File(short_file + "-expected.txt"); + nontextCase(test_path, expected.exists()); + } + } + + public void finished() { + if (mCallback != null) { + mCallback.waitForFinish(); + } + + mFinishedRunning = true; + finish(); + } + + // LayoutTestController Functions + public void dumpAsText() { + mDumpAsText = true; + if (mWebView != null) { + String url = mWebView.getUrl(); + Log.v(LOGTAG, "dumpAsText called: "+url); + } + } + + public void waitUntilDone() { + mWaitUntilDone = true; + String url = mWebView.getUrl(); + Log.v(LOGTAG, "waitUntilDone called: " + url); + } + public void notifyDone() { + String url = mWebView.getUrl(); + Log.v(LOGTAG, "notifyDone called: " + url); + if (mWaitUntilDone) { + mWaitUntilDone = false; + mChromeClient.onProgressChanged(mWebView, 100); + } + } + + public void display() { + mWebView.invalidate(); + } + + public void clearBackForwardList() { + mWebView.clearHistory(); + + } + + public void dumpBackForwardList() { + //printf("\n============== Back Forward List ==============\n"); + // mWebHistory + //printf("===============================================\n"); + + } + + public void dumpChildFrameScrollPositions() { + // TODO Auto-generated method stub + + } + + public void dumpEditingCallbacks() { + // TODO Auto-generated method stub + + } + + public void dumpSelectionRect() { + // TODO Auto-generated method stub + + } + + public void dumpTitleChanges() { + if (!mDumpTitleChanges) { + mTitleChanges = new StringBuffer(); + } + mDumpTitleChanges = true; + } + + public void keepWebHistory() { + if (!mKeepWebHistory) { + mWebHistory = new Vector(); + } + mKeepWebHistory = true; + } + + public void queueBackNavigation(int howfar) { + // TODO Auto-generated method stub + + } + + public void queueForwardNavigation(int howfar) { + // TODO Auto-generated method stub + + } + + public void queueLoad(String Url, String frameTarget) { + // TODO Auto-generated method stub + + } + + public void queueReload() { + mWebView.reload(); + } + + public void queueScript(String scriptToRunInCurrentContext) { + mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext); + } + + public void repaintSweepHorizontally() { + // TODO Auto-generated method stub + + } + + public void setAcceptsEditing(boolean b) { + // TODO Auto-generated method stub + + } + + public void setMainFrameIsFirstResponder(boolean b) { + // TODO Auto-generated method stub + + } + + public void setWindowIsKey(boolean b) { + // This is meant to show/hide the window. The best I can find + // is setEnabled() + mWebView.setEnabled(b); + } + + public void testRepaint() { + mWebView.invalidate(); + } + + // Instrumentation calls this to find + // if the activity has finished running the layout tests + // TODO(fqian): need to sync on mFinisheRunning + public boolean hasFinishedRunning() { + return mFinishedRunning; + } + + private final WebChromeClient mChromeClient = new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + if (newProgress == 100) { + if (!mSingleTestMode && !mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) { + String url = mWebView.getUrl(); + Log.v(LOGTAG, "Finished: "+ url); + mHandler.removeMessages(MSG_TIMEOUT); + requestWebKitData(); + } else { + String url = mWebView.getUrl(); + if (mSingleTestMode) { + Log.v(LOGTAG, "Single test mode: " + url); + } else if (mTimedOut) { + Log.v(LOGTAG, "Timed out before finishing: " + url); + } else if (mWaitUntilDone) { + Log.v(LOGTAG, "Waiting for notifyDone: " + url); + } else if (mRequestedWebKitData) { + Log.v(LOGTAG, "Requested webkit data ready: " + url); + } + } + } + } + + @Override + public void onReceivedTitle(WebView view, String title) { + if (title.length() > 30) + title = "..."+title.substring(title.length()-30); + setTitle(title); + if (mDumpTitleChanges) { + mTitleChanges.append("TITLE CHANGED: "); + mTitleChanges.append(title); + mTitleChanges.append("\n"); + } + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, + JsResult result) { + if (mDialogStrings == null) { + mDialogStrings = new StringBuffer(); + } + mDialogStrings.append("ALERT: "); + mDialogStrings.append(message); + mDialogStrings.append('\n'); + result.confirm(); + return true; + } + + @Override + public boolean onJsConfirm(WebView view, String url, String message, + JsResult result) { + if (mDialogStrings == null) { + mDialogStrings = new StringBuffer(); + } + mDialogStrings.append("CONFIRM: "); + mDialogStrings.append(message); + mDialogStrings.append('\n'); + result.confirm(); + return true; + } + + @Override + public boolean onJsPrompt(WebView view, String url, String message, + String defaultValue, JsPromptResult result) { + if (mDialogStrings == null) { + mDialogStrings = new StringBuffer(); + } + mDialogStrings.append("PROMPT: "); + mDialogStrings.append(message); + mDialogStrings.append(", default text: "); + mDialogStrings.append(defaultValue); + mDialogStrings.append('\n'); + result.confirm(); + return true; + } + }; + + private void resetTestStatus() { + mWaitUntilDone = false; + mDumpAsText = false; + mTimedOut = false; + mDumpTitleChanges = false; + mRequestedWebKitData = false; + mEventSender.resetMouse(); + } + + private TestRecorder mResultRecorder; + private HTMLHostCallbackInterface mCallback = null; + private CallbackProxy mCallbackProxy; + + private WebView mWebView; + private WebViewEventSender mEventSender; + + private Vector<String> mTestList; + private int mTestIndex; + + private int mTimeoutInMillis; + private String mTestPathPrefix; + private boolean mSingleTestMode; + + private AsyncHandler mHandler; + private boolean mFinishedRunning; + + private boolean mTimedOut; + private boolean mRequestedWebKitData; + private boolean mDumpAsText; + private boolean mWaitUntilDone; + private boolean mDumpTitleChanges; + + private StringBuffer mTitleChanges; + private StringBuffer mDialogStrings; + + private boolean mKeepWebHistory; + private Vector mWebHistory; + + static final String TIMEOUT_STR = "**Test timeout"; + + static final int MSG_TIMEOUT = 0; + static final int MSG_WEBKIT_DATA = 1; + + static final String LOGTAG="DumpRenderTree"; + + static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/"; + static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/layout_tests_list.txt"; + static final String TEST_STATUS_FILE = "/sdcard/running_test.txt"; + + static final String RESUME_FROM_CRASH = "ResumeFromCrash"; + static final String TEST_PATH_PREFIX = "TestPathPrefix"; + static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis"; + static final String SINGLE_TEST_MODE = "SingleTestMode"; +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java new file mode 100644 index 0000000..f610f5a --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import android.app.Application; + +public class HTMLHostApp extends Application { + + public HTMLHostApp() { + } + + public void onCreate() { + } + + public void onTerminate() { + } + +} + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java new file mode 100644 index 0000000..60a2915 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +public interface HTMLHostCallbackInterface { + public void waitForFinish(); +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java new file mode 100644 index 0000000..6166dd0 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +public interface LayoutTestController { + + public void dumpAsText(); + public void waitUntilDone(); + public void notifyDone(); + + // Force a redraw of the page + public void display(); + // Used with pixel dumps of content + public void testRepaint(); + + // If the page title changes, add the information to the output. + public void dumpTitleChanges(); + public void dumpBackForwardList(); + public void dumpChildFrameScrollPositions(); + public void dumpEditingCallbacks(); + + // Show/Hide window for window.onBlur() testing + public void setWindowIsKey(boolean b); + // Mac function, used to disable events going to the window + public void setMainFrameIsFirstResponder(boolean b); + + public void dumpSelectionRect(); + + // invalidate and draw one line at a time of the web view. + public void repaintSweepHorizontally(); + + // History testing functions + public void keepWebHistory(); + public void clearBackForwardList(); + // navigate after page load has finished + public void queueBackNavigation(int howfar); + public void queueForwardNavigation(int howfar); + + // Reload when the page load has finished + public void queueReload(); + // Execute the provided script in current context when page load has finished. + public void queueScript(String scriptToRunInCurrentContext); + // Load the provided URL into the provided frame + public void queueLoad(String Url, String frameTarget); + + public void setAcceptsEditing(boolean b); + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java new file mode 100755 index 0000000..1f37405 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import junit.framework.TestSuite; +import com.android.dumprendertree.LayoutTestsAutoTest; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; +import android.util.Log; +import android.content.Intent; +import android.os.Bundle; + + +/** + * Instrumentation Test Runner for all MediaPlayer tests. + * + * Running all tests: + * + * adb shell am instrument \ + * -w com.android.dumprendertree.LayoutTestsAutoRunner + */ + +public class LayoutTestsAutoRunner extends InstrumentationTestRunner { + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(LayoutTestsAutoTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return LayoutTestsAutoRunner.class.getClassLoader(); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + String path = (String) icicle.get("path"); + LayoutTestsAutoTest.setLayoutTestDir(path); + String timeout_str = (String) icicle.get("timeout"); + int timeout = 0; // default value + if (timeout_str != null) { + try { + timeout = Integer.parseInt(timeout_str); + } catch (Exception e) { + e.printStackTrace(); + } + } + LayoutTestsAutoTest.setTimeoutInMillis(timeout); + } +} + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java new file mode 100644 index 0000000..3e65f03 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import android.app.Activity; +import android.app.Instrumentation; +import android.app.Instrumentation.ActivityMonitor; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Intent; + +import android.util.Log; +import android.view.KeyEvent; + +import android.os.Bundle; +import android.os.Message; +import android.test.ActivityInstrumentationTestCase; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import com.android.dumprendertree.HTMLHostActivity; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase<Menu> { + + private final static String LOGTAG = "LayoutTests"; + private final static int DEFAULT_TIMEOUT_IN_MILLIS = 6000; + private static String layoutTestDir = null; + private static int mTimeoutInMillis = 0; + + public LayoutTestsAutoTest() { + super("com.android.dumprendertree", Menu.class); + } + + // This function writes the result of the layout test to + // Am status so that it can be picked up from a script. + public void passOrFailCallback(String file, boolean result) { + Instrumentation inst = getInstrumentation(); + Bundle bundle = new Bundle(); + bundle.putBoolean(file, result); + inst.sendStatus(0, bundle); + } + + public static void setTimeoutInMillis(int millis) { + mTimeoutInMillis = (millis > 0) ? millis : DEFAULT_TIMEOUT_IN_MILLIS; + } + + public static void setLayoutTestDir(String name) { + if (name == null) + throw new AssertionError("Layout test directory cannot be null."); + layoutTestDir = HTMLHostActivity.LAYOUT_TESTS_ROOT + name; + Log.v("LayoutTestsAutoTest", " Only running the layout tests : " + layoutTestDir); + } + + // Invokes running of layout tests + // and waits till it has finished running. + public void executeLayoutTests(boolean resume) { + Instrumentation inst = getInstrumentation(); + + { + Activity activity = getActivity(); + Intent intent = new Intent(); + intent.setClass(activity, HTMLHostActivity.class); + intent.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, resume); + intent.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, false); + intent.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, layoutTestDir); + intent.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, mTimeoutInMillis); + activity.startActivity(intent); + } + + ActivityMonitor htmlHostActivityMonitor = + inst.addMonitor("com.android.dumprendertree.HTMLHostActivity", null, false); + + HTMLHostActivity activity = + (HTMLHostActivity) htmlHostActivityMonitor.waitForActivity(); + + while (!activity.hasFinishedRunning()) { + // Poll every 5 seconds to determine if the layout + // tests have finished running + try {Thread.sleep(5000); } catch(Exception e){} + } + + // Wait few more seconds so that results are + // flushed to the /sdcard + try {Thread.sleep(5000); } catch(Exception e){} + + // Clean up the HTMLHostActivity activity + activity.finish(); + } + + public void generateTestList() { + try { + File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE); + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false)); + findTestsRecursively(bos, layoutTestDir); + bos.flush(); + bos.close(); + } catch (Exception e) { + Log.e(LOGTAG, "Error when creating test list: " + e.getMessage()); + } + } + + private void findTestsRecursively(BufferedOutputStream bos, String dir) throws IOException { + Log.v(LOGTAG, "Searching tests under " + dir); + + File d = new File(dir); + if (!d.isDirectory()) { + throw new AssertionError("A directory expected, but got " + dir); + } + + String[] files = d.list(); + for (int i = 0; i < files.length; i++) { + String s = dir + "/" + files[i]; + if (FileFilter.ignoreTest(s)) { + Log.v(LOGTAG, " Ignoring: " + s); + continue; + } + if (s.toLowerCase().endsWith(".html") + || s.toLowerCase().endsWith(".xml")) { + bos.write(s.getBytes()); + bos.write('\n'); + continue; + } + + File f = new File(s); + if (f.isDirectory()) { + findTestsRecursively(bos, s); + continue; + } + + Log.v(LOGTAG, "Skipping " + s); + } + } + + // Running all the layout tests at once sometimes + // causes the dumprendertree to run out of memory. + // So, additional tests are added to run the tests + // in chunks. + public void startLayoutTests() { + try { + File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE); + if (!tests_list.exists()) + generateTestList(); + } catch (Exception e) { + e.printStackTrace(); + } + + executeLayoutTests(false); + } + + public void resumeLayoutTests() { + executeLayoutTests(true); + } +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java new file mode 100644 index 0000000..de0da61 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; + +import java.io.File; + +public class Menu extends FileList { + + public void onCreate(Bundle icicle) + { + super.onCreate(icicle); + } + + boolean fileFilter(File f) { + if (f.getName().startsWith(".")) + return false; + if (f.getName().equalsIgnoreCase("resources")) + return false; + if (f.isDirectory()) + return true; + if (f.getPath().toLowerCase().endsWith("ml")) + return true; + return false; + } + + void processFile(String filename, boolean selection) + { + Intent result = new Intent(); + result.setClass(this, HTMLHostActivity.class); + result.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, false); + result.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, true); + result.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, filename); + result.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, 8000); + startActivity(result); + } + +} + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java new file mode 100644 index 0000000..eea6346 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree; + +import android.webkit.WebView; +import android.view.KeyEvent; +import android.util.*; + +import java.util.Arrays; + +public class WebViewEventSender implements EventSender { + + WebViewEventSender(WebView webView) { + mWebView = webView; + } + + public void resetMouse() { + mouseX = mouseY = 0; + } + + public void enableDOMUIEventLogging(int DOMNode) { + // TODO Auto-generated method stub + + } + + public void fireKeyboardEventsToElement(int DOMNode) { + // TODO Auto-generated method stub + + } + + public void keyDown(String character, String[] withModifiers) { + Log.e("EventSender", "KeyDown: " + character + "(" + + character.getBytes()[0] + ") Modifiers: " + + Arrays.toString(withModifiers)); + KeyEvent modifier = null; + if (withModifiers != null && withModifiers.length > 0) { + for (int i = 0; i < withModifiers.length; i++) { + int keyCode = modifierMapper(withModifiers[i]); + modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + mWebView.onKeyDown(modifier.getKeyCode(), modifier); + } + } + int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]); + KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + mWebView.onKeyDown(event.getKeyCode(), event); + + } + + public void keyDown(String character) { + keyDown(character, null); + } + + public void leapForward(int milliseconds) { + // TODO Auto-generated method stub + + } + + public void mouseClick() { + mouseDown(); + mouseUp(); + } + + public void mouseDown() { + /* KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER); + mWebView.onKeyDown(event.getKeyCode(), event); */ + } + + public void mouseMoveTo(int X, int Y) { + if (X > mouseX) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } else if ( X < mouseX ) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } + if (Y > mouseY) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } else if (Y < mouseY ) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } + mouseX= X; + mouseY= Y; + + } + + public void mouseUp() { + /* KeyEvent event = new KeyEvent( + KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER); + mWebView.onKeyDown(event.getKeyCode(), event);*/ + + } + + // Assumes lowercase chars, case needs to be + // handled by calling function. + static int keyMapper(char c) { + // handle numbers + if (c >= '0' && c<= '9') { + int offset = c - '0'; + return KeyEvent.KEYCODE_0 + offset; + } + + // handle characters + if (c >= 'a' && c <= 'z') { + int offset = c - 'a'; + return KeyEvent.KEYCODE_A + offset; + } + + // handle all others + switch (c) { + case '*': + return KeyEvent.KEYCODE_STAR; + case '#': + return KeyEvent.KEYCODE_POUND; + case ',': + return KeyEvent.KEYCODE_COMMA; + case '.': + return KeyEvent.KEYCODE_PERIOD; + case '\t': + return KeyEvent.KEYCODE_TAB; + case ' ': + return KeyEvent.KEYCODE_SPACE; + case '\n': + return KeyEvent.KEYCODE_ENTER; + case '\b': + case 0x7F: + return KeyEvent.KEYCODE_DEL; + case '~': + return KeyEvent.KEYCODE_GRAVE; + case '-': + return KeyEvent.KEYCODE_MINUS; + case '=': + return KeyEvent.KEYCODE_EQUALS; + case '(': + return KeyEvent.KEYCODE_LEFT_BRACKET; + case ')': + return KeyEvent.KEYCODE_RIGHT_BRACKET; + case '\\': + return KeyEvent.KEYCODE_BACKSLASH; + case ';': + return KeyEvent.KEYCODE_SEMICOLON; + case '\'': + return KeyEvent.KEYCODE_APOSTROPHE; + case '/': + return KeyEvent.KEYCODE_SLASH; + default: + break; + } + + return c; + } + + static int modifierMapper(String modifier) { + if (modifier.equals("ctrlKey")) { + return KeyEvent.KEYCODE_ALT_LEFT; + } else if (modifier.equals("shiftKey")) { + return KeyEvent.KEYCODE_SHIFT_LEFT; + } else if (modifier.equals("altKey")) { + return KeyEvent.KEYCODE_SYM; + } else if (modifier.equals("metaKey")) { + return KeyEvent.KEYCODE_UNKNOWN; + } + return KeyEvent.KEYCODE_UNKNOWN; + } + + private WebView mWebView = null; + private int mouseX; + private int mouseY; + +} |