1// Copyright 2015 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
5package org.chromium.webview_shell;
6
7import android.os.Environment;
8import android.test.ActivityInstrumentationTestCase2;
9import android.util.Log;
10
11import java.io.BufferedReader;
12import java.io.File;
13import java.io.FileInputStream;
14import java.io.FileNotFoundException;
15import java.io.FileOutputStream;
16import java.io.IOException;
17import java.io.InputStreamReader;
18import java.util.concurrent.TimeUnit;
19import java.util.concurrent.TimeoutException;
20
21/**
22 * Tests running end-to-end layout tests.
23 */
24public class WebViewLayoutTest
25        extends ActivityInstrumentationTestCase2<WebViewLayoutTestActivity> {
26
27    private static final String TAG = "WebViewLayoutTest";
28
29    private static final String EXTERNAL_PREFIX =
30            Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
31    private static final String BASE_WEBVIEW_TEST_PATH = "android_webview/tools/WebViewShell/test/";
32    private static final String BASE_BLINK_TEST_PATH = "third_party/WebKit/LayoutTests/";
33    private static final String PATH_WEBVIEW_PREFIX = EXTERNAL_PREFIX + BASE_WEBVIEW_TEST_PATH;
34    private static final String PATH_BLINK_PREFIX = EXTERNAL_PREFIX + BASE_BLINK_TEST_PATH;
35
36    private static final long TIMEOUT_SECONDS = 20;
37
38    private WebViewLayoutTestActivity mTestActivity;
39
40    public WebViewLayoutTest() {
41        super(WebViewLayoutTestActivity.class);
42    }
43
44    @Override
45    protected void setUp() throws Exception {
46        super.setUp();
47        mTestActivity = (WebViewLayoutTestActivity) getActivity();
48    }
49
50    @Override
51    protected void tearDown() throws Exception {
52        mTestActivity.finish();
53        super.tearDown();
54    }
55
56    @Override
57    public WebViewLayoutTestRunner getInstrumentation() {
58        return (WebViewLayoutTestRunner) super.getInstrumentation();
59    }
60
61    public void testSimple() throws Exception {
62        runWebViewLayoutTest("experimental/basic-logging.html",
63                             "experimental/basic-logging-expected.txt");
64    }
65
66    public void testGlobalInterface() throws Exception {
67        runBlinkLayoutTest("webexposed/global-interface-listing.html",
68                           "webexposed/global-interface-listing-expected.txt");
69    }
70
71    // test helper methods
72
73    private void runWebViewLayoutTest(final String fileName, final String fileNameExpected)
74            throws Exception {
75        runTest(PATH_WEBVIEW_PREFIX + fileName, PATH_WEBVIEW_PREFIX + fileNameExpected);
76    }
77
78    private void runBlinkLayoutTest(final String fileName, final String fileNameExpected)
79            throws Exception {
80        ensureJsTestCopied();
81        runTest(PATH_BLINK_PREFIX + fileName, PATH_WEBVIEW_PREFIX + fileNameExpected);
82    }
83
84    private void runTest(final String fileName, final String fileNameExpected)
85            throws FileNotFoundException, IOException, InterruptedException, TimeoutException {
86        loadUrlWebViewAsync("file://" + fileName, mTestActivity);
87
88        if (getInstrumentation().isRebaseline()) {
89            // this is the rebaseline process
90            mTestActivity.waitForFinish(TIMEOUT_SECONDS, TimeUnit.SECONDS);
91            String result = mTestActivity.getTestResult();
92            writeFile(fileNameExpected, result, true);
93            Log.i(TAG, "file: " + fileNameExpected + " --> rebaselined, length=" + result.length());
94        } else {
95            String expected = readFile(fileNameExpected);
96            mTestActivity.waitForFinish(TIMEOUT_SECONDS, TimeUnit.SECONDS);
97            String result = mTestActivity.getTestResult();
98            assertEquals(expected, result);
99        }
100    }
101
102    private void loadUrlWebViewAsync(final String fileUrl,
103            final WebViewLayoutTestActivity activity) {
104        getInstrumentation().runOnMainSync(new Runnable() {
105            @Override
106            public void run() {
107                activity.loadUrl(fileUrl);
108            }
109        });
110    }
111
112    private static void ensureJsTestCopied() throws IOException {
113        File jsTestFile = new File(PATH_BLINK_PREFIX + "resources/js-test.js");
114        if (jsTestFile.exists()) return;
115        String original = readFile(PATH_WEBVIEW_PREFIX + "resources/js-test.js");
116        writeFile(PATH_BLINK_PREFIX + "resources/js-test.js", original, false);
117    }
118
119    /**
120     * Reads a file and returns it's contents as string.
121     */
122    private static String readFile(String fileName) throws IOException {
123        FileInputStream inputStream = new FileInputStream(new File(fileName));
124        try {
125            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
126            try {
127                StringBuilder contents = new StringBuilder();
128                String line;
129
130                while ((line = reader.readLine()) != null) {
131                    contents.append(line);
132                    contents.append("\n");
133                }
134                return contents.toString();
135            } finally {
136                reader.close();
137            }
138        } finally {
139            inputStream.close();
140        }
141    }
142
143    /**
144     * Writes a file with the given fileName and contents. If overwrite is true overwrites any
145     * exisiting file with the same file name. If the file does not exist any intermediate
146     * required directories are created.
147     */
148    private static void writeFile(final String fileName, final String contents, boolean overwrite)
149            throws FileNotFoundException, IOException {
150        File fileOut = new File(fileName);
151
152        if (fileOut.exists() && !overwrite) {
153            return;
154        }
155
156        String absolutePath = fileOut.getAbsolutePath();
157        File filePath = new File(absolutePath.substring(0, absolutePath.lastIndexOf("/")));
158
159        if (!filePath.exists()) {
160            if (!filePath.mkdirs())
161                throw new IOException("failed to create directories: " + filePath);
162        }
163
164        FileOutputStream outputStream = new FileOutputStream(fileOut);
165        try {
166            outputStream.write(contents.getBytes());
167        } finally {
168            outputStream.close();
169        }
170    }
171}
172