- add sources.
[platform/framework/web/crosswalk.git] / src / android_webview / javatests / src / org / chromium / android_webview / test / AwTestBase.java
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.android_webview.test;
6
7 import android.app.Instrumentation;
8 import android.content.Context;
9 import android.test.ActivityInstrumentationTestCase2;
10
11 import org.chromium.android_webview.AwBrowserContext;
12 import org.chromium.android_webview.AwBrowserProcess;
13 import org.chromium.android_webview.AwContents;
14 import org.chromium.android_webview.AwContentsClient;
15 import org.chromium.android_webview.AwLayoutSizer;
16 import org.chromium.android_webview.AwSettings;
17 import org.chromium.android_webview.test.util.JSUtils;
18 import org.chromium.base.test.util.InMemorySharedPreferences;
19 import org.chromium.content.browser.ContentSettings;
20 import org.chromium.content.browser.LoadUrlParams;
21 import org.chromium.content.browser.test.util.CallbackHelper;
22 import org.chromium.content.browser.test.util.Criteria;
23 import org.chromium.content.browser.test.util.CriteriaHelper;
24
25 import java.util.concurrent.Callable;
26 import java.util.concurrent.FutureTask;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 /**
31  * A base class for android_webview tests.
32  */
33 public class AwTestBase
34         extends ActivityInstrumentationTestCase2<AwTestRunnerActivity> {
35     protected static final int WAIT_TIMEOUT_SECONDS = 15;
36     protected static final int CHECK_INTERVAL = 100;
37
38     public AwTestBase() {
39         super(AwTestRunnerActivity.class);
40     }
41
42     @Override
43     protected void setUp() throws Exception {
44         super.setUp();
45         final Context context = getActivity();
46         getInstrumentation().runOnMainSync(new Runnable() {
47             @Override
48             public void run() {
49                 AwBrowserProcess.start(context);
50              }
51         });
52     }
53
54     /**
55      * Runs a {@link Callable} on the main thread, blocking until it is
56      * complete, and returns the result. Calls
57      * {@link Instrumentation#waitForIdleSync()} first to help avoid certain
58      * race conditions.
59      *
60      * @param <R> Type of result to return
61      */
62     public <R> R runTestOnUiThreadAndGetResult(Callable<R> callable)
63             throws Exception {
64         FutureTask<R> task = new FutureTask<R>(callable);
65         getInstrumentation().waitForIdleSync();
66         getInstrumentation().runOnMainSync(task);
67         return task.get();
68     }
69
70     protected void enableJavaScriptOnUiThread(final AwContents awContents) {
71         getInstrumentation().runOnMainSync(new Runnable() {
72             @Override
73             public void run() {
74                 awContents.getSettings().setJavaScriptEnabled(true);
75             }
76         });
77     }
78
79     /**
80      * Loads url on the UI thread and blocks until onPageFinished is called.
81      */
82     protected void loadUrlSync(final AwContents awContents,
83                                CallbackHelper onPageFinishedHelper,
84                                final String url) throws Exception {
85         int currentCallCount = onPageFinishedHelper.getCallCount();
86         loadUrlAsync(awContents, url);
87         onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
88                 TimeUnit.SECONDS);
89     }
90
91     protected void loadUrlSyncAndExpectError(final AwContents awContents,
92             CallbackHelper onPageFinishedHelper,
93             CallbackHelper onReceivedErrorHelper,
94             final String url) throws Exception {
95         int onErrorCallCount = onReceivedErrorHelper.getCallCount();
96         int onFinishedCallCount = onPageFinishedHelper.getCallCount();
97         loadUrlAsync(awContents, url);
98         onReceivedErrorHelper.waitForCallback(onErrorCallCount, 1, WAIT_TIMEOUT_SECONDS,
99                 TimeUnit.SECONDS);
100         onPageFinishedHelper.waitForCallback(onFinishedCallCount, 1, WAIT_TIMEOUT_SECONDS,
101                 TimeUnit.SECONDS);
102     }
103
104     /**
105      * Loads url on the UI thread but does not block.
106      */
107     protected void loadUrlAsync(final AwContents awContents,
108                                 final String url) throws Exception {
109         getInstrumentation().runOnMainSync(new Runnable() {
110             @Override
111             public void run() {
112                 awContents.loadUrl(new LoadUrlParams(url));
113             }
114         });
115     }
116
117     /**
118      * Posts url on the UI thread and blocks until onPageFinished is called.
119      */
120     protected void postUrlSync(final AwContents awContents,
121             CallbackHelper onPageFinishedHelper, final String url,
122             byte[] postData) throws Exception {
123         int currentCallCount = onPageFinishedHelper.getCallCount();
124         postUrlAsync(awContents, url, postData);
125         onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
126                 TimeUnit.SECONDS);
127     }
128
129     /**
130      * Loads url on the UI thread but does not block.
131      */
132     protected void postUrlAsync(final AwContents awContents,
133             final String url, byte[] postData) throws Exception {
134         class PostUrl implements Runnable {
135             byte[] mPostData;
136             public PostUrl(byte[] postData) {
137                 mPostData = postData;
138             }
139             @Override
140             public void run() {
141                 awContents.loadUrl(LoadUrlParams.createLoadHttpPostParams(url,
142                         mPostData));
143             }
144         }
145         getInstrumentation().runOnMainSync(new PostUrl(postData));
146     }
147
148     /**
149      * Loads data on the UI thread and blocks until onPageFinished is called.
150      */
151     protected void loadDataSync(final AwContents awContents,
152                                 CallbackHelper onPageFinishedHelper,
153                                 final String data, final String mimeType,
154                                 final boolean isBase64Encoded) throws Exception {
155         int currentCallCount = onPageFinishedHelper.getCallCount();
156         loadDataAsync(awContents, data, mimeType, isBase64Encoded);
157         onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
158                 TimeUnit.SECONDS);
159     }
160
161     protected void loadDataSyncWithCharset(final AwContents awContents,
162                                            CallbackHelper onPageFinishedHelper,
163                                            final String data, final String mimeType,
164                                            final boolean isBase64Encoded, final String charset)
165             throws Exception {
166         int currentCallCount = onPageFinishedHelper.getCallCount();
167         getInstrumentation().runOnMainSync(new Runnable() {
168             @Override
169             public void run() {
170                 awContents.loadUrl(LoadUrlParams.createLoadDataParams(
171                         data, mimeType, isBase64Encoded, charset));
172             }
173         });
174         onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
175                 TimeUnit.SECONDS);
176     }
177
178     /**
179      * Loads data on the UI thread but does not block.
180      */
181     protected void loadDataAsync(final AwContents awContents, final String data,
182                                  final String mimeType, final boolean isBase64Encoded)
183             throws Exception {
184         getInstrumentation().runOnMainSync(new Runnable() {
185             @Override
186             public void run() {
187                 awContents.loadUrl(LoadUrlParams.createLoadDataParams(
188                         data, mimeType, isBase64Encoded));
189             }
190         });
191     }
192
193     /**
194      * Factory class used in creation of test AwContents instances.
195      *
196      * Test cases can provide subclass instances to the createAwTest* methods in order to create an
197      * AwContents instance with injected test dependencies.
198      */
199     public static class TestDependencyFactory {
200         public AwLayoutSizer createLayoutSizer() {
201             return new AwLayoutSizer();
202         }
203         public AwTestContainerView createAwTestContainerView(AwTestRunnerActivity activity) {
204             return new AwTestContainerView(activity);
205         }
206     }
207
208     protected TestDependencyFactory createTestDependencyFactory() {
209         return new TestDependencyFactory();
210     }
211
212     protected AwTestContainerView createAwTestContainerView(
213             final AwContentsClient awContentsClient) {
214         return createAwTestContainerView(awContentsClient, true);
215     }
216
217     protected AwTestContainerView createAwTestContainerView(
218             final AwContentsClient awContentsClient, boolean supportsLegacyQuirks) {
219         AwTestContainerView testContainerView =
220                 createDetachedAwTestContainerView(awContentsClient, supportsLegacyQuirks);
221         getActivity().addView(testContainerView);
222         testContainerView.requestFocus();
223         return testContainerView;
224     }
225
226     // The browser context needs to be a process-wide singleton.
227     private AwBrowserContext mBrowserContext =
228             new AwBrowserContext(new InMemorySharedPreferences());
229
230     protected AwTestContainerView createDetachedAwTestContainerView(
231             final AwContentsClient awContentsClient) {
232         return createDetachedAwTestContainerView(awContentsClient, true);
233     }
234
235     protected AwTestContainerView createDetachedAwTestContainerView(
236             final AwContentsClient awContentsClient, boolean supportsLegacyQuirks) {
237         final TestDependencyFactory testDependencyFactory = createTestDependencyFactory();
238         final AwTestContainerView testContainerView =
239             testDependencyFactory.createAwTestContainerView(getActivity());
240         // TODO(mnaganov): Should also have tests for the "pure Chromium" mode.
241         // See http://crbug.com/278106
242         testContainerView.initialize(new AwContents(
243                 mBrowserContext, testContainerView, testContainerView.getInternalAccessDelegate(),
244                 awContentsClient, false, testDependencyFactory.createLayoutSizer(),
245                 supportsLegacyQuirks));
246         AwContents.setShouldDownloadFavicons();
247         return testContainerView;
248     }
249
250     protected AwTestContainerView createAwTestContainerViewOnMainSync(
251             final AwContentsClient client) throws Exception {
252         return createAwTestContainerViewOnMainSync(client, true);
253     }
254
255     protected AwTestContainerView createAwTestContainerViewOnMainSync(
256             final AwContentsClient client, final boolean supportsLegacyQuirks) throws Exception {
257         final AtomicReference<AwTestContainerView> testContainerView =
258                 new AtomicReference<AwTestContainerView>();
259         getInstrumentation().runOnMainSync(new Runnable() {
260             @Override
261             public void run() {
262                 testContainerView.set(createAwTestContainerView(client, supportsLegacyQuirks));
263             }
264         });
265         return testContainerView.get();
266     }
267
268     protected void destroyAwContentsOnMainSync(final AwContents awContents) {
269         if (awContents == null) return;
270         getInstrumentation().runOnMainSync(new Runnable() {
271             @Override
272             public void run() {
273                 awContents.destroy();
274             }
275         });
276     }
277
278     protected String getTitleOnUiThread(final AwContents awContents) throws Exception {
279         return runTestOnUiThreadAndGetResult(new Callable<String>() {
280             @Override
281             public String call() throws Exception {
282                 return awContents.getContentViewCore().getTitle();
283             }
284         });
285     }
286
287     protected ContentSettings getContentSettingsOnUiThread(
288             final AwContents awContents) throws Exception {
289         return runTestOnUiThreadAndGetResult(new Callable<ContentSettings>() {
290             @Override
291             public ContentSettings call() throws Exception {
292                 return awContents.getContentViewCore().getContentSettings();
293             }
294         });
295     }
296
297     protected AwSettings getAwSettingsOnUiThread(
298             final AwContents awContents) throws Exception {
299         return runTestOnUiThreadAndGetResult(new Callable<AwSettings>() {
300             @Override
301             public AwSettings call() throws Exception {
302                 return awContents.getSettings();
303             }
304         });
305     }
306
307     /**
308      * Executes the given snippet of JavaScript code within the given ContentView. Returns the
309      * result of its execution in JSON format.
310      */
311     protected String executeJavaScriptAndWaitForResult(final AwContents awContents,
312             TestAwContentsClient viewClient, final String code) throws Exception {
313         return JSUtils.executeJavaScriptAndWaitForResult(this, awContents,
314                 viewClient.getOnEvaluateJavaScriptResultHelper(),
315                 code);
316     }
317
318     /**
319      * Similar to CriteriaHelper.pollForCriteria but runs the callable on the UI thread.
320      * Note that exceptions are treated as failure.
321      */
322     protected boolean pollOnUiThread(final Callable<Boolean> callable) throws Exception {
323         return CriteriaHelper.pollForCriteria(new Criteria() {
324             @Override
325             public boolean isSatisfied() {
326                 try {
327                     return runTestOnUiThreadAndGetResult(callable);
328                 } catch (Throwable e) {
329                     return false;
330                 }
331             }
332         });
333     }
334
335     /**
336      * Clears the resource cache. Note that the cache is per-application, so this will clear the
337      * cache for all WebViews used.
338      */
339     protected void clearCacheOnUiThread(
340             final AwContents awContents,
341             final boolean includeDiskFiles) throws Exception {
342         getInstrumentation().runOnMainSync(new Runnable() {
343             @Override
344             public void run() {
345               awContents.clearCache(includeDiskFiles);
346             }
347         });
348     }
349
350     /**
351      * Returns pure page scale.
352      */
353     protected float getScaleOnUiThread(final AwContents awContents) throws Exception {
354         return runTestOnUiThreadAndGetResult(new Callable<Float>() {
355             @Override
356             public Float call() throws Exception {
357                 return awContents.getContentViewCore().getScale();
358             }
359         });
360     }
361
362     /**
363      * Returns page scale multiplied by the screen density.
364      */
365     protected float getPixelScaleOnUiThread(final AwContents awContents) throws Throwable {
366         return runTestOnUiThreadAndGetResult(new Callable<Float>() {
367             @Override
368             public Float call() throws Exception {
369                 return awContents.getScale();
370             }
371         });
372     }
373
374     /**
375      * Returns whether a user can zoom the page in.
376      */
377     protected boolean canZoomInOnUiThread(final AwContents awContents) throws Throwable {
378         return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
379             @Override
380             public Boolean call() throws Exception {
381                 return awContents.canZoomIn();
382             }
383         });
384     }
385
386     /**
387      * Returns whether a user can zoom the page out.
388      */
389     protected boolean canZoomOutOnUiThread(final AwContents awContents) throws Throwable {
390         return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
391             @Override
392             public Boolean call() throws Exception {
393                 return awContents.canZoomOut();
394             }
395         });
396     }
397 }