/* * 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.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.util.DisplayMetrics; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 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 = ""; private static final String SCRIPT = ""; /** TODO: Make it a setting */ private static final String HTML_DETAILS_RELATIVE_PATH = "details.html"; private static final String TXT_SUMMARY_RELATIVE_PATH = "summary.txt"; private int mCrashedTestsCount = 0; private List mFailedNotIgnoredTests = new ArrayList(); private List mIgnoredTests = new ArrayList(); private List mPassedNotIgnoredTests = new ArrayList(); private FileFilter mFileFilter; private String mResultsRootDirPath; private String mTestsRelativePath; private Date mDate; public Summarizer(FileFilter fileFilter, String resultsRootDirPath) { mFileFilter = fileFilter; mResultsRootDirPath = resultsRootDirPath; } public void appendTest(AbstractResult result) { String relativePath = result.getRelativePath(); if (result.getResultCode() == AbstractResult.ResultCode.FAIL_CRASHED) { mCrashedTestsCount++; } if (mFileFilter.isIgnoreRes(relativePath)) { mIgnoredTests.add(result); } else if (result.getResultCode() == AbstractResult.ResultCode.PASS) { mPassedNotIgnoredTests.add(relativePath); } else { mFailedNotIgnoredTests.add(result); } } public void setTestsRelativePath(String testsRelativePath) { mTestsRelativePath = testsRelativePath; } public void summarize() { createHtmlDetails(); createTxtSummary(); } public void reset() { mCrashedTestsCount = 0; mFailedNotIgnoredTests.clear(); mIgnoredTests.clear(); mPassedNotIgnoredTests.clear(); mDate = new Date(); } private void createTxtSummary() { StringBuilder txt = new StringBuilder(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); txt.append(mTestsRelativePath + "\n"); txt.append("Date: " + dateFormat.format(mDate) + "\n"); txt.append("Build fingerprint: " + Build.FINGERPRINT + "\n"); txt.append("WebKit version: " + getWebKitVersionFromUserAgentString() + "\n"); txt.append("TOTAL: " + getTotalTestCount() + "\n"); if (mCrashedTestsCount > 0) { txt.append("CRASHED (total among all tests): " + mCrashedTestsCount + "\n"); txt.append("-------------"); } txt.append("FAILED: " + mFailedNotIgnoredTests.size() + "\n"); txt.append("IGNORED: " + mIgnoredTests.size() + "\n"); txt.append("PASSED: " + mPassedNotIgnoredTests.size() + "\n"); FsUtils.writeDataToStorage(new File(mResultsRootDirPath, TXT_SUMMARY_RELATIVE_PATH), txt.toString().getBytes(), false); } private void createHtmlDetails() { StringBuilder html = new StringBuilder(); html.append(""); html.append(CSS); html.append(SCRIPT); html.append(""); createTopSummaryTable(html); createResultsListWithDiff(html, "Failed", mFailedNotIgnoredTests); createResultsListWithDiff(html, "Ignored", mIgnoredTests); createResultsListNoDiff(html, "Passed", mPassedNotIgnoredTests); html.append(""); FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DETAILS_RELATIVE_PATH), html.toString().getBytes(), false); } private int getTotalTestCount() { return mFailedNotIgnoredTests.size() + mPassedNotIgnoredTests.size() + mIgnoredTests.size(); } private String getWebKitVersionFromUserAgentString() { Resources resources = new Resources(new AssetManager(), new DisplayMetrics(), new Configuration()); String userAgent = resources.getString(com.android.internal.R.string.web_user_agent); Matcher matcher = Pattern.compile("AppleWebKit/([0-9]+?\\.[0-9])").matcher(userAgent); if (matcher.find()) { return matcher.group(1); } return "unknown"; } private void createTopSummaryTable(StringBuilder html) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); html.append("

" + mTestsRelativePath + "

"); html.append("

" + "Date: " + dateFormat.format(new Date()) + "

"); html.append("

" + "Build fingerprint: " + Build.FINGERPRINT + "

"); html.append("

" + "WebKit version: " + getWebKitVersionFromUserAgentString() + "

"); html.append(""); createSummaryTableRow(html, "TOTAL", getTotalTestCount()); createSummaryTableRow(html, "CRASHED", mCrashedTestsCount); createSummaryTableRow(html, "FAILED", mFailedNotIgnoredTests.size()); createSummaryTableRow(html, "IGNORED", mIgnoredTests.size()); createSummaryTableRow(html, "PASSED", mPassedNotIgnoredTests.size()); html.append("
"); } private void createSummaryTableRow(StringBuilder html, String caption, int size) { html.append(""); html.append(" " + caption + ""); html.append(" " + size + ""); html.append(""); } private void createResultsListWithDiff(StringBuilder html, String title, List resultsList) { String relativePath; String id = ""; AbstractResult.ResultCode resultCode; Collections.sort(resultsList); html.append("

" + title + " [" + resultsList.size() + "]

"); for (AbstractResult result : resultsList) { relativePath = result.getRelativePath(); resultCode = result.getResultCode(); html.append("

"); if (resultCode == AbstractResult.ResultCode.PASS) { html.append(""); html.append("" + relativePath + ""); } else { /** * Technically, two different paths could end up being the same, because * ':' is a valid character in a path. However, it is probably not going * to cause any problems in this case */ id = relativePath.replace(File.separator, ":"); html.append(""); html.append(""); html.append("" + relativePath + ""); html.append(""); } html.append(" "); html.append(resultCode.toString()); html.append(""); /** Detect missing LTC function */ String additionalTextOutputString = result.getAdditionalTextOutputString(); if (additionalTextOutputString != null && additionalTextOutputString.contains("com.android.dumprendertree") && additionalTextOutputString.contains("has no method")) { if (additionalTextOutputString.contains("LayoutTestController")) { html.append(" LTC function missing"); } if (additionalTextOutputString.contains("EventSender")) { html.append(" "); html.append("ES function missing"); } } html.append("

"); if (resultCode != AbstractResult.ResultCode.PASS) { html.append("
"); html.append(result.getDiffAsHtml()); html.append("Hide"); html.append("
"); } html.append("
"); } } private void createResultsListNoDiff(StringBuilder html, String title, List resultsList) { Collections.sort(resultsList); html.append("

Passed [" + resultsList.size() + "]

"); for (String result : resultsList) { html.append("

"); html.append(""); html.append("" + result + ""); html.append("

"); html.append("
"); } } }