TextResult.java revision c0f90a8f93546f4e9a708c44ac610f36b5e9b1f8
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
17package com.android.dumprendertree2;
18
19import android.os.Bundle;
20import android.os.Handler;
21import android.os.Message;
22import android.webkit.WebView;
23
24import name.fraser.neil.plaintext.diff_match_patch;
25
26import java.util.LinkedList;
27
28/**
29 * A result object for which the expected output is text. It does not have an image
30 * expected result.
31 *
32 * <p>Created if layoutTestController.dumpAsText() was called.
33 */
34public class TextResult extends AbstractResult {
35
36    private static final int MSG_DOCUMENT_AS_TEXT = 0;
37
38    private String mExpectedResult;
39    private String mExpectedResultPath;
40    private String mActualResult;
41    private String mRelativePath;
42    private boolean mDidTimeOut;
43    private ResultCode mResultCode;
44    transient private Message mResultObtainedMsg;
45
46    private boolean mDumpChildFramesAsText;
47
48    transient private Handler mHandler = new Handler() {
49        @Override
50        public void handleMessage(Message msg) {
51            if (msg.what == MSG_DOCUMENT_AS_TEXT) {
52                mActualResult = (String)msg.obj;
53                mResultObtainedMsg.sendToTarget();
54            }
55        }
56    };
57
58    public TextResult(String relativePath) {
59        mRelativePath = relativePath;
60    }
61
62    public void setDumpChildFramesAsText(boolean dumpChildFramesAsText) {
63        mDumpChildFramesAsText = dumpChildFramesAsText;
64    }
65
66    /**
67     * Used to recreate the Result when received by the service.
68     *
69     * @param bundle
70     *      bundle with data used to recreate the result
71     */
72    public TextResult(Bundle bundle) {
73        mExpectedResult = bundle.getString("expectedTextualResult");
74        mExpectedResultPath = bundle.getString("expectedTextualResultPath");
75        mActualResult = bundle.getString("actualTextualResult");
76        setAdditionalTextOutputString(bundle.getString("additionalTextOutputString"));
77        mRelativePath = bundle.getString("relativePath");
78        mDidTimeOut = bundle.getBoolean("didTimeOut");
79    }
80
81    @Override
82    public void clearResults() {
83        super.clearResults();
84        mExpectedResult = null;
85        mActualResult = null;
86    }
87
88    @Override
89    public ResultCode getResultCode() {
90        if (mResultCode == null) {
91            if (mExpectedResult == null) {
92                mResultCode = AbstractResult.ResultCode.NO_EXPECTED_RESULT;
93            } else {
94                mResultCode = resultsMatch() ? AbstractResult.ResultCode.RESULTS_MATCH
95                        : AbstractResult.ResultCode.RESULTS_DIFFER;
96            }
97        }
98        return mResultCode;
99    }
100
101    private boolean resultsMatch() {
102        assert mExpectedResult != null;
103        assert mActualResult != null;
104        // Trim leading and trailing empty lines, as other WebKit platforms do.
105        String leadingEmptyLines = "^\\n+";
106        String trailingEmptyLines = "\\n+$";
107        String trimmedExpectedResult = mExpectedResult.replaceFirst(leadingEmptyLines, "")
108                .replaceFirst(trailingEmptyLines, "");
109        String trimmedActualResult = mActualResult.replaceFirst(leadingEmptyLines, "")
110                .replaceFirst(trailingEmptyLines, "");
111        return trimmedExpectedResult.equals(trimmedActualResult);
112    }
113
114    @Override
115    public boolean didCrash() {
116        return false;
117    }
118
119    @Override
120    public boolean didTimeOut() {
121        return mDidTimeOut;
122    }
123
124    @Override
125    public void setDidTimeOut() {
126        mDidTimeOut = true;
127    }
128
129    @Override
130    public byte[] getActualImageResult() {
131        return null;
132    }
133
134    @Override
135    public String getActualTextResult() {
136        String additionalTextResultString = getAdditionalTextOutputString();
137        if (additionalTextResultString != null) {
138            return additionalTextResultString+ mActualResult;
139        }
140
141        return mActualResult;
142    }
143
144    @Override
145    public void setExpectedImageResult(byte[] expectedResult) {
146        /** This method is not applicable to this type of result */
147    }
148
149    @Override
150    public void setExpectedImageResultPath(String relativePath) {
151        /** This method is not applicable to this type of result */
152    }
153
154    @Override
155    public String getExpectedImageResultPath() {
156        /** This method is not applicable to this type of result */
157        return null;
158    }
159
160    @Override
161    public void setExpectedTextResultPath(String relativePath) {
162        mExpectedResultPath = relativePath;
163    }
164
165    @Override
166    public String getExpectedTextResultPath() {
167        return mExpectedResultPath;
168    }
169
170    @Override
171    public void setExpectedTextResult(String expectedResult) {
172        mExpectedResult = expectedResult;
173    }
174
175    @Override
176    public String getDiffAsHtml() {
177        StringBuilder html = new StringBuilder();
178        html.append("<table class=\"visual_diff\">");
179        html.append("    <tr class=\"headers\">");
180        html.append("        <td colspan=\"2\">Expected result:</td>");
181        html.append("        <td class=\"space\"></td>");
182        html.append("        <td colspan=\"2\">Actual result:</td>");
183        html.append("    </tr>");
184
185        if (mExpectedResult == null || mActualResult == null) {
186            appendNullsHtml(html);
187        } else {
188            appendDiffHtml(html);
189        }
190
191        html.append("    <tr class=\"footers\">");
192        html.append("        <td colspan=\"2\"></td>");
193        html.append("        <td class=\"space\"></td>");
194        html.append("        <td colspan=\"2\"></td>");
195        html.append("    </tr>");
196        html.append("</table>");
197
198        return html.toString();
199    }
200
201    private void appendDiffHtml(StringBuilder html) {
202        LinkedList<diff_match_patch.Diff> diffs =
203                new diff_match_patch().diff_main(mExpectedResult, mActualResult);
204
205        diffs = VisualDiffUtils.splitDiffsOnNewline(diffs);
206
207        LinkedList<String> expectedLines = new LinkedList<String>();
208        LinkedList<Integer> expectedLineNums = new LinkedList<Integer>();
209        LinkedList<String> actualLines = new LinkedList<String>();
210        LinkedList<Integer> actualLineNums = new LinkedList<Integer>();
211
212        VisualDiffUtils.generateExpectedResultLines(diffs, expectedLineNums, expectedLines);
213        VisualDiffUtils.generateActualResultLines(diffs, actualLineNums, actualLines);
214
215        html.append(VisualDiffUtils.getHtml(expectedLineNums, expectedLines,
216                actualLineNums, actualLines));
217    }
218
219    private void appendNullsHtml(StringBuilder html) {
220        /** TODO: Create a separate row for each line of not null result */
221        html.append("    <tr class=\"results\">");
222        html.append("    <td class=\"line_count\">");
223        html.append("    </td>");
224        html.append("    <td class=\"line\">");
225        if (mExpectedResult == null) {
226            html.append("Expected result was NULL");
227        } else {
228            html.append(mExpectedResult.replace("\n", "<br />"));
229        }
230        html.append("        </td>");
231        html.append("        <td class=\"space\"></td>");
232        html.append("    <td class=\"line_count\">");
233        html.append("    </td>");
234        html.append("    <td class=\"line\">");
235        if (mActualResult == null) {
236            html.append("Actual result was NULL");
237        } else {
238            html.append(mActualResult.replace("\n", "<br />"));
239        }
240        html.append("        </td>");
241        html.append("    </tr>");
242    }
243
244    @Override
245    public TestType getType() {
246        return TestType.TEXT;
247    }
248
249    @Override
250    public void obtainActualResults(WebView webview, Message resultObtainedMsg) {
251        mResultObtainedMsg = resultObtainedMsg;
252        Message msg = mHandler.obtainMessage(MSG_DOCUMENT_AS_TEXT);
253
254        /**
255         * arg1 - should dump top frame as text
256         * arg2 - should dump child frames as text
257         */
258        msg.arg1 = 1;
259        msg.arg2 = mDumpChildFramesAsText ? 1 : 0;
260        webview.documentAsText(msg);
261    }
262
263    @Override
264    public Bundle getBundle() {
265        Bundle bundle = new Bundle();
266        bundle.putString("expectedTextualResult", mExpectedResult);
267        bundle.putString("expectedTextualResultPath", mExpectedResultPath);
268        bundle.putString("actualTextualResult", getActualTextResult());
269        bundle.putString("additionalTextOutputString", getAdditionalTextOutputString());
270        bundle.putString("relativePath", mRelativePath);
271        bundle.putBoolean("didTimeOut", mDidTimeOut);
272        bundle.putString("type", getType().name());
273        return bundle;
274    }
275
276    @Override
277    public String getRelativePath() {
278        return mRelativePath;
279    }
280}
281