Added the LayoutTestsRunner class that is responsible for running the tests. Also, added some methods to FileFilter.
It preloads the tests from the given path, runs them and asks for dumps and diffs. It will also prepare summaries in the future. It delegates most of the work of actually running the individual tests to LayoutTest class and AbstractResult (and its subclasses in the future). Change-Id: I483bf26a380b539e4769e61b4a09fa270ab0e8e9
This commit is contained in:
@@ -24,5 +24,12 @@ limitations under the License.
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".LayoutTestsRunner"
|
||||
android:label="Layout tests' runner">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_SDCARD" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
</manifest>
|
||||
@@ -23,4 +23,6 @@ limitations under the License.
|
||||
|
||||
<string name="dialog_progress_title">Loading items.</string>
|
||||
<string name="dialog_progress_msg">Please wait...</string>
|
||||
|
||||
<string name="runner_preloading_title">Preloading tests...</string>
|
||||
</resources>
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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).
|
||||
*
|
||||
* <p>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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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();
|
||||
}
|
||||
}
|
||||
@@ -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<String> mTestsList = new LinkedList<String>();
|
||||
|
||||
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<String> foldersList = new LinkedList<String>();
|
||||
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 */
|
||||
}
|
||||
}
|
||||
@@ -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 = "<html><head><style type=\"text/css\">" +
|
||||
CSS + "</style></head><body>";
|
||||
private static final String HTML_DIFF_ENDING = "</body></html>";
|
||||
|
||||
/** 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<String> mSkippedTestsList = new LinkedList<String>();
|
||||
|
||||
/** Collection of tests grouped according to result. Sets are initialized lazily. */
|
||||
private Map<AbstractResult.ResultCode, Set<String>> mResults =
|
||||
new EnumMap<AbstractResult.ResultCode, Set<String>>(AbstractResult.ResultCode.class);
|
||||
|
||||
/**
|
||||
* Collection of tests for which results are ignored grouped according to result. Sets are
|
||||
* initialized lazily.
|
||||
*/
|
||||
private Map<AbstractResult.ResultCode, Set<String>> mResultsIgnored =
|
||||
new EnumMap<AbstractResult.ResultCode, Set<String>>(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("<label id=\"" + relativePath + "\" />");
|
||||
html.append(diff);
|
||||
html.append("<a href=\"" + HTML_DIFF_INDEX_RELATIVE_PATH + "\">Back to index</a>");
|
||||
html.append("<div class=\"space\"></div>");
|
||||
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<String>());
|
||||
}
|
||||
|
||||
mResultsIgnored.get(resultCode).add(testPath);
|
||||
} else {
|
||||
/** Lazy initialization */
|
||||
if (mResults.get(resultCode) == null) {
|
||||
mResults.put(resultCode, new HashSet<String>());
|
||||
}
|
||||
|
||||
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<String> results;
|
||||
html.append("<h1>Tests that were _not_ ignored</h1>");
|
||||
appendResultsMap(mResults, html);
|
||||
html.append("<h1>Tests that _were_ ignored</h1>");
|
||||
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<AbstractResult.ResultCode, Set<String>> resultsMap,
|
||||
StringBuilder html) {
|
||||
Set<String> results;
|
||||
for (AbstractResult.ResultCode resultCode : AbstractResult.ResultCode.values()) {
|
||||
results = resultsMap.get(resultCode);
|
||||
if (results != null) {
|
||||
html.append("<h2>");
|
||||
html.append(resultCode.toString());
|
||||
html.append("</h2");
|
||||
for (String relativePath : results) {
|
||||
html.append("<a href=\"");
|
||||
html.append(HTML_DIFF_RELATIVE_PATH);
|
||||
html.append("#");
|
||||
html.append(relativePath);
|
||||
html.append("\">");
|
||||
html.append(relativePath);
|
||||
html.append("</a><br />");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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, "");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user