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.Message;
21import android.util.Log;
22import android.webkit.WebView;
23
24import java.io.ByteArrayInputStream;
25import java.io.ByteArrayOutputStream;
26import java.io.IOException;
27import java.io.ObjectInputStream;
28import java.io.ObjectOutputStream;
29import java.io.Serializable;
30
31/**
32 * A class that represent a result of the test. It is responsible for returning the result's
33 * raw data and generating its own diff in HTML format.
34 */
35public abstract class AbstractResult implements Comparable<AbstractResult>, Serializable {
36
37    private static final String LOG_TAG = "AbstractResult";
38
39    public enum TestType {
40        TEXT {
41            @Override
42            public AbstractResult createResult(Bundle bundle) {
43                return new TextResult(bundle);
44            }
45        },
46        RENDER_TREE {
47            @Override
48            public AbstractResult createResult(Bundle bundle) {
49                /** TODO: RenderTree tests are not yet supported */
50                return null;
51            }
52        };
53
54        public abstract AbstractResult createResult(Bundle bundle);
55    }
56
57    /**
58     * A code representing the result of comparing actual and expected results.
59     */
60    public enum ResultCode implements Serializable {
61        RESULTS_MATCH("Results match"),
62        RESULTS_DIFFER("Results differ"),
63        NO_EXPECTED_RESULT("No expected result"),
64        NO_ACTUAL_RESULT("No actual result");
65
66        private String mTitle;
67
68        private ResultCode(String title) {
69            mTitle = title;
70        }
71
72        @Override
73        public String toString() {
74            return mTitle;
75        }
76    }
77
78    String mAdditionalTextOutputString;
79
80    public int compareTo(AbstractResult another) {
81        return getRelativePath().compareTo(another.getRelativePath());
82    }
83
84    public void setAdditionalTextOutputString(String additionalTextOutputString) {
85        mAdditionalTextOutputString = additionalTextOutputString;
86    }
87
88    public String getAdditionalTextOutputString() {
89        return mAdditionalTextOutputString;
90    }
91
92    public byte[] getBytes() {
93        ByteArrayOutputStream baos = null;
94        ObjectOutputStream oos = null;
95        try {
96            try {
97                baos = new ByteArrayOutputStream();
98                oos = new ObjectOutputStream(baos);
99                oos.writeObject(this);
100            } finally {
101                if (baos != null) {
102                    baos.close();
103                }
104                if (oos != null) {
105                    oos.close();
106                }
107            }
108        } catch (IOException e) {
109            Log.e(LOG_TAG, "Unable to serialize result: " + getRelativePath(), e);
110        }
111
112        return baos == null ? null : baos.toByteArray();
113    }
114
115    public static AbstractResult create(byte[] bytes) {
116        ByteArrayInputStream bais = null;
117        ObjectInputStream ois = null;
118        AbstractResult result = null;
119        try {
120            try {
121                bais = new ByteArrayInputStream(bytes);
122                ois = new ObjectInputStream(bais);
123                result = (AbstractResult)ois.readObject();
124            } finally {
125                if (bais != null) {
126                    bais.close();
127                }
128                if (ois != null) {
129                    ois.close();
130                }
131            }
132        } catch (IOException e) {
133            Log.e(LOG_TAG, "Unable to deserialize result!", e);
134        } catch (ClassNotFoundException e) {
135            Log.e(LOG_TAG, "Unable to deserialize result!", e);
136        }
137        return result;
138    }
139
140    public void clearResults() {
141        mAdditionalTextOutputString = null;
142    }
143
144    /**
145     * Makes the result object obtain the results of the test from the webview
146     * and store them in the format that suits itself bests. This method is asynchronous.
147     * The message passed as a parameter is a message that should be sent to its target
148     * when the result finishes obtaining the result.
149     *
150     * @param webview
151     * @param resultObtainedMsg
152     */
153    public abstract void obtainActualResults(WebView webview, Message resultObtainedMsg);
154
155    public abstract void setExpectedImageResult(byte[] expectedResult);
156
157    public abstract void setExpectedImageResultPath(String relativePath);
158
159    public abstract String getExpectedImageResultPath();
160
161    public abstract void setExpectedTextResult(String expectedResult);
162
163    public abstract void setExpectedTextResultPath(String relativePath);
164
165    public abstract String getExpectedTextResultPath();
166
167    /**
168     * Returns result's image data that can be written to the disk. It can be null
169     * if there is an error of some sort or for example the test times out.
170     *
171     * <p> Some tests will not provide data (like text tests)
172     *
173     * @return
174     *      results image data
175     */
176    public abstract byte[] getActualImageResult();
177
178    /**
179     * Returns result's text data. It can be null
180     * if there is an error of some sort or for example the test times out.
181     *
182     * @return
183     *      results text data
184     */
185    public abstract String getActualTextResult();
186
187    /**
188     * Returns the status code representing the result of comparing actual and expected results.
189     *
190     * @return
191     *      the status code from comparing actual and expected results
192     */
193    public abstract ResultCode getResultCode();
194
195    /**
196     * Returns whether this test crashed.
197     *
198     * @return
199     *      whether this test crashed
200     */
201    public abstract boolean didCrash();
202
203    /**
204     * Returns whether this test timed out.
205     *
206     * @return
207     *      whether this test timed out
208     */
209    public abstract boolean didTimeOut();
210
211    /**
212     * Sets that this test timed out.
213     */
214    public abstract void setDidTimeOut();
215
216    /**
217     * Returns whether the test passed.
218     *
219     * @return
220     *      whether the test passed
221     */
222    public boolean didPass() {
223        // Tests that crash can't have timed out or have an actual result.
224        assert !(didCrash() && didTimeOut());
225        assert !(didCrash() && getResultCode() != ResultCode.NO_ACTUAL_RESULT);
226        return !didCrash() && !didTimeOut() && getResultCode() == ResultCode.RESULTS_MATCH;
227    }
228
229    /**
230     * Return the type of the result data.
231     *
232     * @return
233     *      the type of the result data.
234     */
235    public abstract TestType getType();
236
237    public abstract String getRelativePath();
238
239    /**
240     * Returns a piece of HTML code that presents a visual diff between a result and
241     * the expected result.
242     *
243     * @return
244     *      a piece of HTML code with a visual diff between the result and the expected result
245     */
246    public abstract String getDiffAsHtml();
247
248    public abstract Bundle getBundle();
249}
250