1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dumprendertree2; 18 19 import android.os.Bundle; 20 import android.os.Handler; 21 import android.os.Message; 22 import android.webkit.WebView; 23 import android.webkit.WebViewClassic; 24 25 import name.fraser.neil.plaintext.diff_match_patch; 26 27 import java.util.LinkedList; 28 29 /** 30 * A result object for which the expected output is text. It does not have an image 31 * expected result. 32 * 33 * <p>Created if layoutTestController.dumpAsText() was called. 34 */ 35 public class TextResult extends AbstractResult { 36 37 private static final int MSG_DOCUMENT_AS_TEXT = 0; 38 39 private String mExpectedResult; 40 private String mExpectedResultPath; 41 private String mActualResult; 42 private String mRelativePath; 43 private boolean mDidTimeOut; 44 private ResultCode mResultCode; 45 transient private Message mResultObtainedMsg; 46 47 private boolean mDumpChildFramesAsText; 48 49 transient private Handler mHandler = new Handler() { 50 @Override 51 public void handleMessage(Message msg) { 52 if (msg.what == MSG_DOCUMENT_AS_TEXT) { 53 mActualResult = (String)msg.obj; 54 mResultObtainedMsg.sendToTarget(); 55 } 56 } 57 }; 58 TextResult(String relativePath)59 public TextResult(String relativePath) { 60 mRelativePath = relativePath; 61 } 62 setDumpChildFramesAsText(boolean dumpChildFramesAsText)63 public void setDumpChildFramesAsText(boolean dumpChildFramesAsText) { 64 mDumpChildFramesAsText = dumpChildFramesAsText; 65 } 66 67 /** 68 * Used to recreate the Result when received by the service. 69 * 70 * @param bundle 71 * bundle with data used to recreate the result 72 */ TextResult(Bundle bundle)73 public TextResult(Bundle bundle) { 74 mExpectedResult = bundle.getString("expectedTextualResult"); 75 mExpectedResultPath = bundle.getString("expectedTextualResultPath"); 76 mActualResult = bundle.getString("actualTextualResult"); 77 setAdditionalTextOutputString(bundle.getString("additionalTextOutputString")); 78 mRelativePath = bundle.getString("relativePath"); 79 mDidTimeOut = bundle.getBoolean("didTimeOut"); 80 } 81 82 @Override clearResults()83 public void clearResults() { 84 super.clearResults(); 85 mExpectedResult = null; 86 mActualResult = null; 87 } 88 89 @Override getResultCode()90 public ResultCode getResultCode() { 91 if (mResultCode == null) { 92 mResultCode = resultsMatch() ? AbstractResult.ResultCode.RESULTS_MATCH 93 : AbstractResult.ResultCode.RESULTS_DIFFER; 94 } 95 return mResultCode; 96 } 97 resultsMatch()98 private boolean resultsMatch() { 99 assert mExpectedResult != null; 100 assert mActualResult != null; 101 // Trim leading and trailing empty lines, as other WebKit platforms do. 102 String leadingEmptyLines = "^\\n+"; 103 String trailingEmptyLines = "\\n+$"; 104 String trimmedExpectedResult = mExpectedResult.replaceFirst(leadingEmptyLines, "") 105 .replaceFirst(trailingEmptyLines, ""); 106 String trimmedActualResult = mActualResult.replaceFirst(leadingEmptyLines, "") 107 .replaceFirst(trailingEmptyLines, ""); 108 return trimmedExpectedResult.equals(trimmedActualResult); 109 } 110 111 @Override didCrash()112 public boolean didCrash() { 113 return false; 114 } 115 116 @Override didTimeOut()117 public boolean didTimeOut() { 118 return mDidTimeOut; 119 } 120 121 @Override setDidTimeOut()122 public void setDidTimeOut() { 123 mDidTimeOut = true; 124 } 125 126 @Override getActualImageResult()127 public byte[] getActualImageResult() { 128 return null; 129 } 130 131 @Override getActualTextResult()132 public String getActualTextResult() { 133 String additionalTextResultString = getAdditionalTextOutputString(); 134 if (additionalTextResultString != null) { 135 return additionalTextResultString + mActualResult; 136 } 137 138 return mActualResult; 139 } 140 141 @Override setExpectedImageResult(byte[] expectedResult)142 public void setExpectedImageResult(byte[] expectedResult) { 143 /** This method is not applicable to this type of result */ 144 } 145 146 @Override setExpectedImageResultPath(String relativePath)147 public void setExpectedImageResultPath(String relativePath) { 148 /** This method is not applicable to this type of result */ 149 } 150 151 @Override getExpectedImageResultPath()152 public String getExpectedImageResultPath() { 153 /** This method is not applicable to this type of result */ 154 return null; 155 } 156 157 @Override setExpectedTextResultPath(String relativePath)158 public void setExpectedTextResultPath(String relativePath) { 159 mExpectedResultPath = relativePath; 160 } 161 162 @Override getExpectedTextResultPath()163 public String getExpectedTextResultPath() { 164 return mExpectedResultPath; 165 } 166 167 @Override setExpectedTextResult(String expectedResult)168 public void setExpectedTextResult(String expectedResult) { 169 // For text results, we use an empty string for the expected result when none is 170 // present, as other WebKit platforms do. 171 mExpectedResult = expectedResult == null ? "" : expectedResult; 172 } 173 174 @Override getDiffAsHtml()175 public String getDiffAsHtml() { 176 assert mExpectedResult != null; 177 assert mActualResult != null; 178 179 StringBuilder html = new StringBuilder(); 180 html.append("<table class=\"visual_diff\">"); 181 html.append(" <tr class=\"headers\">"); 182 html.append(" <td colspan=\"2\">Expected result:</td>"); 183 html.append(" <td class=\"space\"></td>"); 184 html.append(" <td colspan=\"2\">Actual result:</td>"); 185 html.append(" </tr>"); 186 187 appendDiffHtml(html); 188 189 html.append(" <tr class=\"footers\">"); 190 html.append(" <td colspan=\"2\"></td>"); 191 html.append(" <td class=\"space\"></td>"); 192 html.append(" <td colspan=\"2\"></td>"); 193 html.append(" </tr>"); 194 html.append("</table>"); 195 196 return html.toString(); 197 } 198 appendDiffHtml(StringBuilder html)199 private void appendDiffHtml(StringBuilder html) { 200 LinkedList<diff_match_patch.Diff> diffs = 201 new diff_match_patch().diff_main(mExpectedResult, mActualResult); 202 203 diffs = VisualDiffUtils.splitDiffsOnNewline(diffs); 204 205 LinkedList<String> expectedLines = new LinkedList<String>(); 206 LinkedList<Integer> expectedLineNums = new LinkedList<Integer>(); 207 LinkedList<String> actualLines = new LinkedList<String>(); 208 LinkedList<Integer> actualLineNums = new LinkedList<Integer>(); 209 210 VisualDiffUtils.generateExpectedResultLines(diffs, expectedLineNums, expectedLines); 211 VisualDiffUtils.generateActualResultLines(diffs, actualLineNums, actualLines); 212 // TODO: We should use a map for each line number and lines pair. 213 assert expectedLines.size() == expectedLineNums.size(); 214 assert actualLines.size() == actualLineNums.size(); 215 assert expectedLines.size() == actualLines.size(); 216 217 html.append(VisualDiffUtils.getHtml(expectedLineNums, expectedLines, 218 actualLineNums, actualLines)); 219 } 220 221 @Override getType()222 public TestType getType() { 223 return TestType.TEXT; 224 } 225 226 @Override obtainActualResults(WebView webview, Message resultObtainedMsg)227 public void obtainActualResults(WebView webview, Message resultObtainedMsg) { 228 mResultObtainedMsg = resultObtainedMsg; 229 Message msg = mHandler.obtainMessage(MSG_DOCUMENT_AS_TEXT); 230 231 /** 232 * arg1 - should dump top frame as text 233 * arg2 - should dump child frames as text 234 */ 235 msg.arg1 = 1; 236 msg.arg2 = mDumpChildFramesAsText ? 1 : 0; 237 WebViewClassic.fromWebView(webview).documentAsText(msg); 238 } 239 240 @Override getBundle()241 public Bundle getBundle() { 242 Bundle bundle = new Bundle(); 243 bundle.putString("expectedTextualResult", mExpectedResult); 244 bundle.putString("expectedTextualResultPath", mExpectedResultPath); 245 bundle.putString("actualTextualResult", getActualTextResult()); 246 bundle.putString("additionalTextOutputString", getAdditionalTextOutputString()); 247 bundle.putString("relativePath", mRelativePath); 248 bundle.putBoolean("didTimeOut", mDidTimeOut); 249 bundle.putString("type", getType().name()); 250 return bundle; 251 } 252 253 @Override getRelativePath()254 public String getRelativePath() { 255 return mRelativePath; 256 } 257 } 258