diff --git a/tests/DumpRenderTree2/AndroidManifest.xml b/tests/DumpRenderTree2/AndroidManifest.xml index baa365c976474..3454316495b44 100644 --- a/tests/DumpRenderTree2/AndroidManifest.xml +++ b/tests/DumpRenderTree2/AndroidManifest.xml @@ -24,5 +24,12 @@ limitations under the License. + + + + + + \ No newline at end of file diff --git a/tests/DumpRenderTree2/res/values/strings.xml b/tests/DumpRenderTree2/res/values/strings.xml index 2dcd3caf5cee0..5fd1eb9a5b406 100644 --- a/tests/DumpRenderTree2/res/values/strings.xml +++ b/tests/DumpRenderTree2/res/values/strings.xml @@ -23,4 +23,6 @@ limitations under the License. Loading items. Please wait... + + Preloading tests... \ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java new file mode 100644 index 0000000000000..f545840acd694 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +/** + * A class that represent a result of the test. It is responsible for returning the result's + * raw data and generating its own diff in HTML format. + */ +public abstract class AbstractResult { + + public enum TestType { + TEXT, + PIXEL + } + + public enum ResultCode { + PASS("Passed"), + FAIL_RESULT_DIFFERS("Failed: different results"), + FAIL_NO_EXPECTED_RESULT("Failed: no expected result"), + FAIL_TIMED_OUT("Failed: timed out"), + FAIL_CRASHED("Failed: crashed"); + + private String mTitle; + + private ResultCode(String title) { + mTitle = title; + } + + @Override + public String toString() { + return mTitle; + } + } + + /** + * Returns result's raw data that can be written to the disk. + * + * @return + * results raw data + */ + public abstract byte[] getData(); + + /** + * Returns the code of this result. + * + * @return + * the code of this result + */ + public abstract ResultCode getCode(); + + /** + * Return the type of the result data. + * + * @return + * the type of the result data. + */ + public abstract TestType getType(); + + /** + * Returns a piece of HTML code that presents a visual diff between a result and + * the expected result. + * + * @return + * a piece of HTML code with a visual diff between the result and the expected result + */ + public abstract String getDiffAsHtml(); +} \ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java index 64ef8a4ad49f7..cf82d24044a8a 100644 --- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java @@ -61,8 +61,6 @@ public class FileFilter { } public void reloadConfiguration() { - Log.d(LOG_TAG + "::reloadConfiguration", "Begin."); - File txt_exp = new File(mRootDirPath, TEST_EXPECTATIONS_TXT_PATH); BufferedReader bufferedReader; @@ -222,8 +220,7 @@ public class FileFilter { */ public static boolean isTestDir(String dirName) { return (!dirName.equals("script-tests") - && !dirName.equals("resources") - && !dirName.startsWith(".")); + && !dirName.equals("resources") && !dirName.startsWith(".")); } /** @@ -237,4 +234,55 @@ public class FileFilter { public static boolean isTestFile(String testName) { return testName.endsWith(".html") || testName.endsWith(".xhtml"); } -} + + /** + * Return the path to the file relative to the tests root dir + * + * @param filePath + * @return + * the path relative to the tests root dir + */ + public String getRelativePath(String filePath) { + File rootDir = new File(mRootDirPath); + return filePath.replaceFirst(rootDir.getPath() + File.separator, ""); + } + + /** + * Return the path to the file relative to the tests root dir + * + * @param filePath + * @return + * the path relative to the tests root dir + */ + public String getRelativePath(File file) { + return getRelativePath(file.getAbsolutePath()); + } + + public File getAbsoluteFile(String relativePath) { + return new File(mRootDirPath, relativePath); + } + + public String getAboslutePath(String relativePath) { + return getAbsoluteFile(relativePath).getAbsolutePath(); + } + + /** + * If the path contains extension (e.g .foo at the end of the file) then it changes + * this (.foo) into newEnding (so it has to contain the dot if we want to preserve it). + * + *

If the path doesn't contain an extension, it adds the ending to the path. + * + * @param relativePath + * @param newEnding + * @return + * a new path, containing the newExtension + */ + public static String setPathEnding(String relativePath, String newEnding) { + int dotPos = relativePath.lastIndexOf('.'); + if (dotPos == -1) { + return relativePath + newEnding; + } + + return relativePath.substring(0, dotPos) + newEnding; + } +} \ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java new file mode 100644 index 0000000000000..68daaf0d0a0a6 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + */ +public class FsUtils { + public static final String LOG_TAG = "FsUtils"; + + public static void writeDataToStorage(File file, byte[] bytes, boolean append) { + Log.d(LOG_TAG + "::writeDataToStorage", file.getAbsolutePath()); + try { + OutputStream outputStream = null; + try { + file.getParentFile().mkdirs(); + file.createNewFile(); + Log.d(LOG_TAG + "::writeDataToStorage", "File created."); + outputStream = new FileOutputStream(file, append); + outputStream.write(bytes); + } finally { + if (outputStream != null) { + outputStream.close(); + } + } + } catch (IOException e) { + Log.e(LOG_TAG + "::writeDataToStorage", e.getMessage()); + } + } +} diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java new file mode 100644 index 0000000000000..605afab66a136 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.os.Handler; + +/** + * A class that represents a single layout test. It is responsible for running the test, + * checking its result and creating an AbstractResult object. + */ +public class LayoutTest { + + private String mRelativePath; + private Handler mCallbackHandler; + private AbstractResult mResult; + + public LayoutTest(String relativePath, Handler callbackHandler) { + mRelativePath = relativePath; + mCallbackHandler = callbackHandler; + } + + public void run() { + /** TODO: This is just a stub! */ + mCallbackHandler.obtainMessage(LayoutTestsRunnerThread.MSG_TEST_FINISHED).sendToTarget(); + } + + public AbstractResult getResult() { + return mResult; + } + + public String getRelativePath() { + return mRelativePath; + } +} \ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java new file mode 100644 index 0000000000000..c18abcccb5f83 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.Window; + +/** + * An Activity that is responsible only for updating the UI features, like titles, progress bars, + * etc. + * + *

Also, the webview form the test must be running in this activity's thread if we want + * to be able to display it on the screen. + */ +public class LayoutTestsRunner extends Activity { + + public static final int MSG_UPDATE_PROGRESS = 1; + public static final int MSG_SHOW_PROGRESS_DIALOG = 2; + public static final int MSG_DISMISS_PROGRESS_DIALOG = 3; + + /** Constants for adding extras to an intent */ + public static final String EXTRA_TEST_PATH = "TestPath"; + + private static ProgressDialog sProgressDialog; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_PROGRESS: + int i = msg.arg1; + int size = msg.arg2; + getWindow().setFeatureInt(Window.FEATURE_PROGRESS, + i * Window.PROGRESS_END / size); + setTitle(i * 100 / size + "% (" + i + "/" + size + ")"); + break; + + case MSG_SHOW_PROGRESS_DIALOG: + sProgressDialog.show(); + break; + + case MSG_DISMISS_PROGRESS_DIALOG: + sProgressDialog.dismiss(); + break; + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + /** Prepare the progress dialog */ + sProgressDialog = new ProgressDialog(LayoutTestsRunner.this); + sProgressDialog.setCancelable(false); + sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); + sProgressDialog.setTitle(R.string.dialog_progress_title); + sProgressDialog.setMessage(getText(R.string.dialog_progress_msg)); + + requestWindowFeature(Window.FEATURE_PROGRESS); + + /** Execute the intent */ + Intent intent = getIntent(); + if (!intent.getAction().equals(Intent.ACTION_RUN)) { + return; + } + String path = intent.getStringExtra(EXTRA_TEST_PATH); + + new LayoutTestsRunnerThread(path, mHandler).start(); + } +} \ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java new file mode 100644 index 0000000000000..d75579e70b1e4 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import java.io.File; +import java.util.LinkedList; + +/** + * A Thread that is responsible for finding and loading the tests, starting them and + * generating summaries. The actual running of the test is delegated to LayoutTestsRunner + * activity (a UI thread) because of a WebView object that need to be created in UI thread + * so it can be displayed on the screen. However, the logic for doing this remains in + * this class (in handler created in constructor). + */ +public class LayoutTestsRunnerThread extends Thread { + + private static final String LOG_TAG = "LayoutTestsRunnerThread"; + + /** Messages for handler on this thread */ + public static final int MSG_TEST_FINISHED = 0; + + /** Messages for our handler running on UI thread */ + public static final int MSG_RUN_TEST = 0; + + /** TODO: make it a setting */ + private static final String TESTS_ROOT_DIR_PATH = + Environment.getExternalStorageDirectory() + + File.separator + "android" + + File.separator + "LayoutTests"; + + /** TODO: make it a setting */ + private static final String RESULTS_ROOT_DIR_PATH = + Environment.getExternalStorageDirectory() + + File.separator + "android" + + File.separator + "LayoutTests-results"; + + /** A list containing relative paths of tests to run */ + private LinkedList mTestsList = new LinkedList(); + + private FileFilter mFileFilter; + private Summarizer mSummarizer; + + /** Our handler running on this thread. Created in run() method. */ + private Handler mHandler; + + /** Our handler running on UI thread. Created in constructor of this thread. */ + private Handler mHandlerOnUiThread; + + /** + * A relative path to the folder with the tests we want to run or particular test. + * Used up to and including preloadTests(). + */ + private String mRelativePath; + + /** A handler obtained from UI thread to handle messages concerning updating the display */ + private Handler mUiDisplayHandler; + + private LayoutTest mCurrentTest; + private String mCurrentTestPath; + private int mCurrentTestCount = 0; + private int mTotalTestCount; + + /** + * The given path must be relative to the root dir. The given handler must be + * able to handle messages that update the display (UI thread). + * + * @param path + * @param uiDisplayHandler + */ + public LayoutTestsRunnerThread(String path, Handler uiDisplayHandler) { + mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH); + mRelativePath = path; + mUiDisplayHandler = uiDisplayHandler; + + /** This creates a handler that runs on the thread that _created_ this thread */ + mHandlerOnUiThread = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_RUN_TEST: + ((LayoutTest) msg.obj).run(); + break; + } + } + }; + } + + @Override + public void run() { + Looper.prepare(); + + mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH); + + /** Creates a new handler in _this_ thread */ + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_TEST_FINISHED: + onTestFinished(mCurrentTest); + mUiDisplayHandler.obtainMessage(LayoutTestsRunner.MSG_UPDATE_PROGRESS, + mCurrentTestCount, mTotalTestCount).sendToTarget(); + runNextTest(); + break; + } + } + }; + + /** Check if the path is correct */ + File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath); + if (!file.exists()) { + Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath); + return; + } + + /** Populate the tests' list accordingly */ + if (file.isDirectory()) { + mUiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_SHOW_PROGRESS_DIALOG); + preloadTests(mRelativePath); + mUiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_DISMISS_PROGRESS_DIALOG); + } else { + mTestsList.addLast(mRelativePath); + mTotalTestCount = 1; + } + + runNextTest(); + Looper.loop(); + } + + /** + * Loads all the tests from the given folders and all the subfolders + * into mTestsList. + * + * @param dirRelativePath + */ + private void preloadTests(String dirRelativePath) { + LinkedList foldersList = new LinkedList(); + foldersList.add(dirRelativePath); + + String relativePath; + String currentDirRelativePath; + String itemName; + File[] items; + while (!foldersList.isEmpty()) { + currentDirRelativePath = foldersList.removeFirst(); + items = new File(TESTS_ROOT_DIR_PATH, currentDirRelativePath).listFiles(); + for (File item : items) { + itemName = item.getName(); + relativePath = currentDirRelativePath + File.separator + itemName; + + if (item.isDirectory() && FileFilter.isTestDir(itemName)) { + foldersList.add(relativePath); + continue; + } + + if (FileFilter.isTestFile(itemName)) { + if (!mFileFilter.isSkip(relativePath)) { + mTestsList.addLast(relativePath); + } else { + mSummarizer.addSkippedTest(relativePath); + } + } + } + } + + mTotalTestCount = mTestsList.size(); + } + + private void runNextTest() { + if (mTestsList.isEmpty()) { + onFinishedTests(); + return; + } + + mCurrentTestCount++; + mCurrentTestPath = mTestsList.removeFirst(); + mCurrentTest = new LayoutTest(mCurrentTestPath, mHandler); + + /** + * This will run the test on UI thread. The reason why we need to run the test + * on UI thread is because of the WebView. If we want to display the webview on + * the screen it needs to be in the UI thread. WebView should be created as + * part of the LayoutTest.run() method. + */ + mHandlerOnUiThread.obtainMessage(MSG_RUN_TEST, mCurrentTest).sendToTarget(); + } + + private void onTestFinished(LayoutTest test) { + String testPath = test.getRelativePath(); + + /** Obtain the result */ + AbstractResult result = test.getResult(); + if (result == null) { + Log.e(LOG_TAG + "::runTests", testPath + ": result NULL!!"); + return; + } + + dumpResultData(result, testPath); + + mSummarizer.appendTest(test); + } + + private void dumpResultData(AbstractResult result, String testPath) { + String resultPath = null; + + switch (result.getType()) { + case TEXT: + resultPath = FileFilter.setPathEnding(testPath, "-actual.txt"); + break; + + case PIXEL: + /** TODO: Check if it is for sure *.bmp */ + resultPath = FileFilter.setPathEnding(testPath, "-actual.bmp"); + break; + } + + /** Dump the result */ + FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), + result.getData(), false); + } + + private void onFinishedTests() { + Log.d(LOG_TAG + "::onFinishedTests", "Begin."); + Looper.myLooper().quit(); + mSummarizer.summarize(); + /** TODO: Present some kind of notification to the user that + * allows to chose next action, e.g: + * - go to html view of results + * - zip results + * - run more tests before zipping */ + } +} diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java new file mode 100644 index 0000000000000..9b28fcda97c9a --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.util.Log; + +import java.io.File; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + * A class that collects information about tests that ran and can create HTML + * files with summaries and easy navigation. + */ +public class Summarizer { + + private static final String LOG_TAG = "Summarizer"; + + private static final String CSS = + "body {font-family: Verdana;} a {font-size: 12px; color: black; } h3" + + "{ font-size: 20px; padding: 0; margin: 0; margin-bottom: 10px; } " + + ".space { margin-top:30px; } table.diff_both, table.diff_both tr, " + + "table.diff_both td { border: 0; padding: 0; margin: 0; } " + + "table.diff_both { width: 600px; } table.diff_both td.dleft, " + + "table.diff_both td.dright { border: 0; width: 50%; } " + + "table.diff " + "table.diff_both caption { text-align: left; margin-bottom: 3px;}" + + "{ border:1px solid black; border-collapse: collapse; width: 100%; } " + + "table.diff tr { vertical-align: top; border-bottom: 1px dashed black; " + + "border-top: 1px dashed black; font-size: 15px; } table.diff td.linecount " + + "{ border-right: 1px solid; background-color: #aaa; width: 20px; text-align: " + + "right; padding-right: 1px; padding-top: 2px; padding-bottom: 2px; } " + + "table.diff td.line { padding-left: 3px; padding-top: 2px; " + + "padding-bottom: 2px; } span.eql { background-color: #f3f3f3;} " + + "span.del { background-color: #ff8888; } span.ins { background-color: #88ff88; }"; + private static final String HTML_DIFF_BEGINNING = ""; + private static final String HTML_DIFF_ENDING = ""; + + /** TODO: Make it a setting */ + private static final String HTML_DIFF_RELATIVE_PATH = "_diff.html"; + private static final String HTML_DIFF_INDEX_RELATIVE_PATH = "_diff-index.html"; + + /** A list containing relatives paths of tests that were skipped */ + private LinkedList mSkippedTestsList = new LinkedList(); + + /** Collection of tests grouped according to result. Sets are initialized lazily. */ + private Map> mResults = + new EnumMap>(AbstractResult.ResultCode.class); + + /** + * Collection of tests for which results are ignored grouped according to result. Sets are + * initialized lazily. + */ + private Map> mResultsIgnored = + new EnumMap>(AbstractResult.ResultCode.class); + + private FileFilter mFileFilter; + private String mResultsRootDirPath; + + public Summarizer(FileFilter fileFilter, String resultsRootDirPath) { + mFileFilter = fileFilter; + mResultsRootDirPath = resultsRootDirPath; + createHtmlDiff(); + } + + private void createHtmlDiff() { + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_RELATIVE_PATH), + HTML_DIFF_BEGINNING.getBytes(), false); + } + + private void appendHtmlDiff(String relativePath, String diff) { + StringBuilder html = new StringBuilder(); + html.append("

"); + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_RELATIVE_PATH), + html.toString().getBytes(), true); + } + + private void finalizeHtmlDiff() { + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_RELATIVE_PATH), + HTML_DIFF_ENDING.getBytes(), true); + } + + /** TODO: Add settings method, like setIndexSkippedTests(), setIndexTimedOutTests(), etc */ + + public void addSkippedTest(String relativePath) { + mSkippedTestsList.addLast(relativePath); + } + + public void appendTest(LayoutTest test) { + String testPath = test.getRelativePath(); + + /** Obtain the result */ + AbstractResult result = test.getResult(); + if (result == null) { + Log.e(LOG_TAG + "::appendTest", testPath + ": result NULL!!"); + return; + } + + AbstractResult.ResultCode resultCode = result.getCode(); + + /** Add the test to correct collection according to its result code */ + if (mFileFilter.isIgnoreRes(testPath)) { + /** Lazy initialization */ + if (mResultsIgnored.get(resultCode) == null) { + mResultsIgnored.put(resultCode, new HashSet()); + } + + mResultsIgnored.get(resultCode).add(testPath); + } else { + /** Lazy initialization */ + if (mResults.get(resultCode) == null) { + mResults.put(resultCode, new HashSet()); + } + + mResults.get(resultCode).add(testPath); + } + + if (resultCode != AbstractResult.ResultCode.PASS) { + appendHtmlDiff(testPath, result.getDiffAsHtml()); + } + } + + public void summarize() { + finalizeHtmlDiff(); + createHtmlDiffIndex(); + } + + private void createHtmlDiffIndex() { + StringBuilder html = new StringBuilder(); + html.append(HTML_DIFF_BEGINNING); + Set results; + html.append("

Tests that were _not_ ignored

"); + appendResultsMap(mResults, html); + html.append("

Tests that _were_ ignored

"); + appendResultsMap(mResultsIgnored, html); + html.append(HTML_DIFF_ENDING); + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_INDEX_RELATIVE_PATH), + html.toString().getBytes(), false); + } + + private void appendResultsMap(Map> resultsMap, + StringBuilder html) { + Set results; + for (AbstractResult.ResultCode resultCode : AbstractResult.ResultCode.values()) { + results = resultsMap.get(resultCode); + if (results != null) { + html.append("

"); + html.append(resultCode.toString()); + html.append(""); + html.append(relativePath); + html.append("
"); + } + } + } + } +} diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java index d8509c12b37e1..790d1d36429be 100644 --- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java @@ -17,6 +17,7 @@ package com.android.dumprendertree2.ui; import com.android.dumprendertree2.FileFilter; +import com.android.dumprendertree2.LayoutTestsRunner; import com.android.dumprendertree2.R; import android.app.Activity; @@ -25,6 +26,7 @@ import android.app.Dialog; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.DialogInterface; +import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.os.Environment; @@ -80,6 +82,8 @@ public class DirListActivity extends ListActivity { */ private String mRootDirPath = ROOT_DIR_PATH; + private FileFilter mFileFilter; + /** * A thread responsible for loading the contents of the directory from sd card * and sending them via Message to main thread that then loads them into @@ -186,6 +190,7 @@ public class DirListActivity extends ListActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mFileFilter = new FileFilter(ROOT_DIR_PATH); mListView = getListView(); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @@ -196,7 +201,12 @@ public class DirListActivity extends ListActivity { if (item.isDirectory()) { showDir(item.getRelativePath()); } else { - /** TODO: run the test */ + /** Run the test */ + Intent intent = new Intent(); + intent.setClass(DirListActivity.this, LayoutTestsRunner.class); + intent.setAction(Intent.ACTION_RUN); + intent.putExtra(LayoutTestsRunner.EXTRA_TEST_PATH, item.getRelativePath()); + startActivity(intent); } } }); @@ -249,7 +259,7 @@ public class DirListActivity extends ListActivity { } @Override - protected Dialog onCreateDialog(int id, Bundle args) { + protected Dialog onCreateDialog(int id, final Bundle args) { Dialog dialog = null; AlertDialog.Builder builder = new AlertDialog.Builder(this); @@ -264,8 +274,14 @@ public class DirListActivity extends ListActivity { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - /** TODO: Run tests from the dir */ removeDialog(DIALOG_RUN_ABORT_DIR); + /** Run the tests */ + Intent intent = new Intent(); + intent.setClass(DirListActivity.this, LayoutTestsRunner.class); + intent.setAction(Intent.ACTION_RUN); + intent.putExtra(LayoutTestsRunner.EXTRA_TEST_PATH, + args.getString("relativePath")); + startActivity(intent); } }); @@ -367,9 +383,9 @@ public class DirListActivity extends ListActivity { for (File item : dir.listFiles()) { if (item.isDirectory() && FileFilter.isTestDir(item.getName())) { - subDirs.add(new ListItem(getRelativePath(item), true)); + subDirs.add(new ListItem(mFileFilter.getRelativePath(item), true)); } else if (FileFilter.isTestFile(item.getName())) { - subFiles.add(new ListItem(getRelativePath(item), false)); + subFiles.add(new ListItem(mFileFilter.getRelativePath(item), false)); } } @@ -381,9 +397,4 @@ public class DirListActivity extends ListActivity { return subDirs.toArray(new ListItem[subDirs.size()]); } - - private String getRelativePath(File file) { - File rootDir = new File(mRootDirPath); - return file.getAbsolutePath().replaceFirst(rootDir.getPath() + File.separator, ""); - } } \ No newline at end of file