summaryrefslogtreecommitdiffstats
path: root/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java')
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java607
1 files changed, 607 insertions, 0 deletions
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..9521f80
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
@@ -0,0 +1,607 @@
+/*
+ * 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.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Stack;
+
+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.*;
+import android.test.TestRecorder;
+
+// SQLite3 in android has a bunch of bugs which
+// is causing TestRecorder to not record the results
+// properly. This class is a wrapper around it and records
+// results in a file as well.
+class TestRecorderV2 extends TestRecorder {
+ @Override
+ public void passed(String layout_file) {
+ try {
+ mBufferedOutputPassedStream.write(layout_file.getBytes());
+ mBufferedOutputPassedStream.write('\n');
+ mBufferedOutputPassedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ super.passed(layout_file);
+ }
+
+ @Override
+ public void failed(String layout_file, String reason) {
+ try {
+ mBufferedOutputFailedStream.write(layout_file.getBytes());
+ mBufferedOutputFailedStream.write('\n');
+ mBufferedOutputFailedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ super.failed(layout_file, reason);
+ }
+
+ public TestRecorderV2() {
+ super();
+ try {
+ File resultsPassedFile = new File("/sdcard/layout_test_presults.txt");
+ File resultsFailedFile = new File("/sdcard/layout_test_fresults.txt");
+
+ mBufferedOutputPassedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsPassedFile, true));
+ mBufferedOutputFailedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsFailedFile, true));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ mBufferedOutputPassedStream.flush();
+ mBufferedOutputFailedStream.flush();
+ mBufferedOutputPassedStream.close();
+ mBufferedOutputFailedStream.close();
+ }
+
+ private static BufferedOutputStream mBufferedOutputPassedStream;
+ private static BufferedOutputStream mBufferedOutputFailedStream;
+}
+
+public class HTMLHostActivity extends Activity
+ implements LayoutTestController {
+
+ private TestRecorderV2 mResultRecorder = new TestRecorderV2();
+ private HTMLHostCallbackInterface mCallback = null;
+ private CallbackProxy mCallbackProxy;
+
+ public class FileEntry {
+ public FileEntry(String path, int index) {
+ mPath = path; mIndex=index;
+ }
+ String mPath;
+ int mIndex;
+ }
+
+ public class AsyncHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_DUMP) {
+ this.removeMessages(MSG_TIMEOUT);
+ mTimedOut = false;
+ requestWebKitData();
+ return;
+ } else 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);
+ }
+
+ void requestWebKitData() {
+ Message callback = obtainMessage(MSG_WEBKIT_DATA);
+ if (dumpAsText) {
+ 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);
+ eventSender = new WebViewEventSender(mWebView);
+ mCallbackProxy = new CallbackProxy(eventSender, this);
+
+ 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);
+ }
+
+ protected void onResume() {
+ super.onResume();
+ if (mProcessStack == null || mProcessStack.isEmpty() ) {
+ mOutstandingLoads = 0;
+ dumpAsText = false;
+ pageComplete = false;
+
+ mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+
+ mFinishedStack = new Stack();
+
+ Intent intent = getIntent();
+ if (intent.getData() != null) {
+ File f = new File(intent.getData().toString());
+
+ if (f.isDirectory()) {
+ mProcessStack = new Vector();
+ mProcessStack.add(new FileEntry(intent.getData().toString(), 0));
+ Log.v(LOGTAG, "Initial dir: "+intent.getData().toString());
+ loadNextPage();
+ } else {
+ mCurrentFile = intent.getData().toString();
+ mWebView.loadUrl("file://"+intent.getData().toString());
+ }
+
+ }
+ else
+ mWebView.loadUrl("about:");
+ }
+ }
+
+ protected void onStop() {
+ super.onStop();
+ mWebView.stopLoading();
+ }
+
+ protected void onDestroy() {
+ super.onDestroy();
+ mWebView.destroy();
+ mWebView = null;
+ }
+
+ 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);
+ }
+
+ // Functions
+
+ protected void loadNextPage() {
+ dumpAsText = false;
+ pageComplete = false;
+ dumpTitleChanges = false;
+ eventSender.resetMouse();
+ while (!mProcessStack.isEmpty()) {
+ FileEntry fe = (FileEntry)mProcessStack.remove(0);
+ if (fe.mIndex == 0) {
+ System.out.println();
+ System.out.print(fe.mPath);
+ }
+ Log.v(LOGTAG, "Processing dir: "+fe.mPath+" size: "+mProcessStack.size());
+ File f = new File(fe.mPath);
+ String [] files = f.list();
+ for (int i = fe.mIndex; i < files.length; i++) {
+ if (FileFilter.ignoreTest(files[i])) {
+ continue;
+ }
+ File c = new File(f.getPath(), files[i]);
+ if (c.isDirectory()) {
+ Log.v(LOGTAG, "Adding dir: "+fe.mPath+"/"+files[i]);
+ mProcessStack.add(new FileEntry(fe.mPath+"/"+files[i], 0));
+ } else if (files[i].toLowerCase().endsWith("ml")) {
+ mProcessStack.add(0, new FileEntry(fe.mPath, i+1));
+ mCurrentFile = fe.mPath+"/"+files[i];
+ Log.e(LOGTAG, "Processing: "+mCurrentFile);
+ mWebView.loadUrl("file://"+mCurrentFile);
+
+ // Create a timeout timer
+ Message m = mHandler.obtainMessage(MSG_TIMEOUT);
+ // Some tests can take up to 5secs to run.
+ mHandler.sendMessageDelayed(m, 6000);
+ return;
+ }
+ }
+ Log.v(LOGTAG, "Finished dir: "+fe.mPath+" size: "+mProcessStack.size());
+ }
+ // If we got to here, then we must have finished completely
+ finished();
+ }
+
+ public void scheduleDump() {
+ // Only schedule if we really are ready
+ if (waitToDump || mOutstandingLoads > 0 || mDumpRequested) {
+ return;
+ }
+ mDumpRequested = true;
+ mHandler.obtainMessage(MSG_DUMP).sendToTarget();
+ }
+
+ // Dump the page
+ public void dump(boolean timeout, String webkitData) {
+ mDumpRequested = false;
+ System.out.print('.');
+
+ // remove the extension
+ String resultFile = mCurrentFile.substring(0, mCurrentFile.lastIndexOf('.'));
+
+ // store the finished file on the stack so that we can do a diff at the end.
+ mFinishedStack.push(resultFile);
+
+ // dumpAsText version can be directly compared to expected results
+ if (dumpAsText) {
+ resultFile += "-results.txt";
+ } else {
+ resultFile += "-android-results.txt";
+ }
+ try {
+ FileOutputStream os = new FileOutputStream(resultFile);
+ if (timeout) {
+ Log.i("Layout test: Timeout", resultFile);
+ os.write("**Test timeout\n".getBytes());
+ }
+ if (dumpTitleChanges)
+ 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();
+ }
+
+ if (mProcessStack != null)
+ loadNextPage();
+ else
+ finished();
+ }
+
+ // Wrap up
+ public void failedCase(String file, String reason) {
+ Log.i("Layout test:", file + " failed" + reason);
+ mResultRecorder.failed(file, reason);
+
+ file = file + ".html";
+ 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) {
+ // Add the result to the sqlite database
+ Log.i("Layout test:", file + " passed");
+ mResultRecorder.passed(file);
+
+ file = file + ".html";
+ 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 setCallback(HTMLHostCallbackInterface callback) {
+ mCallback = callback;
+ }
+
+ public void finished() {
+ int passed = 0;
+ while (!mFinishedStack.empty()) {
+ Log.v(LOGTAG, "Comparing dump and reference");
+ String file = (String)mFinishedStack.pop();
+
+ // Only check results that we can check, ie dumpAsText results
+ String dumpFile = file + "-results.txt";
+ File f = new File(dumpFile);
+ if (f.exists()) {
+ try {
+ FileInputStream fr = new FileInputStream(file+"-results.txt");
+ FileInputStream fe = new FileInputStream(file+"-expected.txt");
+
+ mResultRecorder.started(file);
+
+ // If the length is different then they are different
+ int diff = fe.available() - fr.available();
+ if (diff > 1 || diff < 0) {
+ failedCase(file, " different length");
+ fr.close();
+ fe.close();
+
+ mResultRecorder.finished(file);
+ continue;
+ }
+ 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(file, " @offset: "+i);
+ fail = true;
+ break;
+ }
+ }
+ if (br.length != be.length && be[be.length-1] == '\n') {
+ Log.d(LOGTAG, "Extra new line being ignore:" + file);
+ }
+ fr.close();
+ fe.close();
+ if (!fail) {
+ passed++;
+ passedCase(file);
+ }
+ } catch (FileNotFoundException ex) {
+ // TODO do something here
+ } catch (IOException ex) {
+ // Failed on available() or read()
+ }
+ mResultRecorder.finished(file);
+ }
+ }
+
+ if (mCallback != null) {
+ mCallback.waitForFinish();
+ }
+
+ finish();
+ }
+
+ // LayoutTestController Functions
+ public void dumpAsText() {
+ dumpAsText = true;
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "dumpAsText called:"+url);
+ if (url.length() > 60)
+ url = url.substring(60);
+ }
+
+ public void waitUntilDone() {
+ waitToDump = true;
+ }
+ public void notifyDone() {
+ waitToDump = 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 (!dumpTitleChanges) {
+ mTitleChanges = new StringBuffer();
+ }
+ dumpTitleChanges = true;
+ }
+
+ public void keepWebHistory() {
+ if (!keepWebHistory) {
+ mWebHistory = new Vector();
+ }
+ keepWebHistory = 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
+ public boolean hasFinishedRunning() {
+ if( mProcessStack == null || mFinishedStack == null)
+ return false;
+
+ if (mProcessStack.isEmpty() && mFinishedStack.empty()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private final WebChromeClient mChromeClient = new WebChromeClient() {
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ if (newProgress == 100) {
+ pageComplete = true;
+ String url = mWebView.getUrl();
+ if (url != null) {
+ Log.v(LOGTAG, "Finished: "+ url);
+ if (url.length() > 60)
+ url = url.substring(60);
+ scheduleDump();
+ }
+ }
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ if (title.length() > 30)
+ title = "..."+title.substring(title.length()-30);
+ setTitle(title);
+ if (dumpTitleChanges) {
+ 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');
+ return false;
+ }
+ };
+
+ private WebView mWebView;
+ private WebViewEventSender eventSender;
+ private Vector mProcessStack;
+ private Stack mFinishedStack;
+ static final String LOGTAG="DumpRenderTree";
+ private String mCurrentFile;
+ private int mOutstandingLoads;
+ private AsyncHandler mHandler;
+ private boolean mDumpRequested;
+
+ private boolean dumpAsText;
+ private boolean waitToDump;
+ private boolean pageComplete;
+
+ private boolean dumpTitleChanges;
+ private StringBuffer mTitleChanges;
+
+ private StringBuffer mDialogStrings;
+
+ private boolean keepWebHistory;
+ private Vector mWebHistory;
+
+ private boolean mTimedOut;
+
+ static final int MSG_DUMP = 0;
+ static final int MSG_TIMEOUT = 1;
+ static final int MSG_WEBKIT_DATA = 2;
+
+}