1 // Copyright 2013 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 #include "base/strings/stringprintf.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "chrome/test/base/chrome_render_view_test.h"
8 #include "components/translate/core/common/translate_errors.h"
9 #include "grit/components_resources.h"
10 #include "third_party/WebKit/public/web/WebLocalFrame.h"
11 #include "third_party/WebKit/public/web/WebScriptSource.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "v8/include/v8.h"
14
15 using blink::WebScriptSource;
16
17 namespace {
18
19 // JavaScript code to set runtime test flags.
20 const char kThrowInitializationError[] = "throwInitializationError = true";
21 const char kThrowUnexpectedScriptError[] = "throwUnexpectedScriptError = true";
22 const char kCallbackReturnBooleanError[] = "callbackReturnBooleanError = true";
23 const char kCallbackReturnNumberError[] = "callbackReturnNumberError = true";
24 const char kSetCallbackErrorCode[] = "callbackErrorCode = ";
25
26 // JavaScript code to check if any error happens.
27 const char kError[] = "cr.googleTranslate.error";
28
29 // JavaScript code to get error code.
30 const char kErrorCode[] = "cr.googleTranslate.errorCode";
31
32 // JavaScript code to check if the library is ready.
33 const char kLibReady[] = "cr.googleTranslate.libReady";
34
35 // JavaScript code to perform translation.
36 const char kTranslate[] = "cr.googleTranslate.translate('auto', 'en')";
37
38 // JavaScript code to mimic element.js provided by a translate server.
39 const char kElementJs[] =
40 "translateApiKey = '';"
41 "google = {};"
42 "google.translate = {};"
43 "google.translate.TranslateService = function() {"
44 " if (window['throwInitializationError']) {"
45 " throw 'API initialization error';"
46 " }"
47 " return {"
48 " isAvailable: function() { return true; },"
49 " restore: function() {},"
50 " translatePage: function(originalLang, targetLang, cb) {"
51 " if (window['throwUnexpectedScriptError']) {"
52 " throw 'all your base are belong to us';"
53 " }"
54 " if (window['callbackReturnBooleanError']) {"
55 " cb(0, false, true);"
56 " }"
57 " if (window['callbackReturnNumberError']) {"
58 " cb(0, false, callbackErrorCode);"
59 " }"
60 " }"
61 " };"
62 "};"
63 "cr.googleTranslate.onTranslateElementLoad();";
64
GenerateSetCallbackErrorCodeScript(int code)65 std::string GenerateSetCallbackErrorCodeScript(int code) {
66 return base::StringPrintf("%s%d", kSetCallbackErrorCode, code);
67 }
68
69 }; // namespace
70
71 // This class is for testing resource/translate.js works and reports errors
72 // correctly.
73 class TranslateScriptBrowserTest : public ChromeRenderViewTest {
74 public:
TranslateScriptBrowserTest()75 TranslateScriptBrowserTest() {}
76
77 protected:
InjectElementLibrary()78 void InjectElementLibrary() {
79 std::string script;
80 base::StringPiece translate_js = ResourceBundle::GetSharedInstance().
81 GetRawDataResource(IDR_TRANSLATE_JS);
82 translate_js.CopyToString(&script);
83 script += kElementJs;
84 ExecuteScript(script);
85 }
86
ExecuteScript(const std::string & script)87 void ExecuteScript(const std::string& script) {
88 WebScriptSource source = WebScriptSource(base::ASCIIToUTF16(script));
89 GetMainFrame()->executeScript(source);
90 }
91
GetError()92 bool GetError() {
93 return ExecuteScriptAndGetBoolResult(kError);
94 }
95
GetErrorCode()96 double GetErrorCode() {
97 return ExecuteScriptAndGetNumberResult(kErrorCode);
98 }
99
IsLibReady()100 bool IsLibReady() {
101 return ExecuteScriptAndGetBoolResult(kLibReady);
102 }
103
104 private:
SetUp()105 virtual void SetUp() OVERRIDE {
106 ChromeRenderViewTest::SetUp();
107 }
108
TearDown()109 virtual void TearDown() OVERRIDE {
110 ChromeRenderViewTest::TearDown();
111 }
112
ExecuteScriptAndGetNumberResult(const std::string & script)113 double ExecuteScriptAndGetNumberResult(const std::string& script) {
114 WebScriptSource source = WebScriptSource(base::ASCIIToUTF16(script));
115 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
116 v8::Handle<v8::Value> result =
117 GetMainFrame()->executeScriptAndReturnValue(source);
118 if (result.IsEmpty() || !result->IsNumber()) {
119 NOTREACHED();
120 // TODO(toyoshim): Return NaN here and the real implementation in
121 // TranslateHelper::ExecuteScriptAndGetDoubleResult().
122 return 0.0;
123 }
124 return result->NumberValue();
125 }
126
ExecuteScriptAndGetBoolResult(const std::string & script)127 bool ExecuteScriptAndGetBoolResult(const std::string& script) {
128 WebScriptSource source = WebScriptSource(base::ASCIIToUTF16(script));
129 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
130 v8::Handle<v8::Value> result =
131 GetMainFrame()->executeScriptAndReturnValue(source);
132 if (result.IsEmpty() || !result->IsBoolean()) {
133 NOTREACHED();
134 return false;
135 }
136 return result->BooleanValue();
137 }
138
139 DISALLOW_COPY_AND_ASSIGN(TranslateScriptBrowserTest);
140 };
141
142 // Test if onTranslateElementLoad() succeeds to initialize the element library.
TEST_F(TranslateScriptBrowserTest,ElementLoadSuccess)143 TEST_F(TranslateScriptBrowserTest, ElementLoadSuccess) {
144 InjectElementLibrary();
145 EXPECT_TRUE(IsLibReady());
146 EXPECT_FALSE(GetError());
147 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
148 }
149
150 // Test if onTranslateElementLoad() fails to initialize the element library and
151 // report the right error code.
TEST_F(TranslateScriptBrowserTest,ElementLoadFailure)152 TEST_F(TranslateScriptBrowserTest, ElementLoadFailure) {
153 ExecuteScript(kThrowInitializationError);
154
155 InjectElementLibrary();
156 EXPECT_FALSE(IsLibReady());
157 EXPECT_TRUE(GetError());
158 EXPECT_EQ(translate::TranslateErrors::INITIALIZATION_ERROR, GetErrorCode());
159 }
160
161 // Test if cr.googleTranslate.translate() works.
TEST_F(TranslateScriptBrowserTest,TranslateSuccess)162 TEST_F(TranslateScriptBrowserTest, TranslateSuccess) {
163 InjectElementLibrary();
164 EXPECT_TRUE(IsLibReady());
165 EXPECT_FALSE(GetError());
166 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
167
168 ExecuteScript(kTranslate);
169
170 EXPECT_FALSE(GetError());
171 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
172 }
173
174 // Test if cr.googleTranslate.translate() handles library exception correctly.
TEST_F(TranslateScriptBrowserTest,TranslateFail)175 TEST_F(TranslateScriptBrowserTest, TranslateFail) {
176 ExecuteScript(kThrowUnexpectedScriptError);
177
178 InjectElementLibrary();
179 EXPECT_TRUE(IsLibReady());
180 EXPECT_FALSE(GetError());
181 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
182
183 ExecuteScript(kTranslate);
184
185 EXPECT_TRUE(GetError());
186 EXPECT_EQ(translate::TranslateErrors::UNEXPECTED_SCRIPT_ERROR,
187 GetErrorCode());
188 }
189
190 // Test if onTranslateProgress callback handles boolean type error correctly.
191 // Remove this test once server side changes the API to return a number.
TEST_F(TranslateScriptBrowserTest,CallbackGetBooleanError)192 TEST_F(TranslateScriptBrowserTest, CallbackGetBooleanError) {
193 ExecuteScript(kCallbackReturnBooleanError);
194
195 InjectElementLibrary();
196 EXPECT_TRUE(IsLibReady());
197 EXPECT_FALSE(GetError());
198 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
199
200 ExecuteScript(kTranslate);
201
202 EXPECT_TRUE(GetError());
203 EXPECT_EQ(translate::TranslateErrors::TRANSLATION_ERROR, GetErrorCode());
204 }
205
206 // Test if onTranslateProgress callback handles number type error correctly and
207 // converts it to the proper error code.
TEST_F(TranslateScriptBrowserTest,CallbackGetNumberError1)208 TEST_F(TranslateScriptBrowserTest, CallbackGetNumberError1) {
209 ExecuteScript(kCallbackReturnNumberError);
210 ExecuteScript(GenerateSetCallbackErrorCodeScript(1));
211
212 InjectElementLibrary();
213 EXPECT_TRUE(IsLibReady());
214 EXPECT_FALSE(GetError());
215 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
216
217 ExecuteScript(kTranslate);
218
219 EXPECT_TRUE(GetError());
220 EXPECT_EQ(translate::TranslateErrors::TRANSLATION_ERROR, GetErrorCode());
221 }
222
223 // Test if onTranslateProgress callback handles number type error correctly and
224 // converts it to the proper error code.
TEST_F(TranslateScriptBrowserTest,CallbackGetNumberError2)225 TEST_F(TranslateScriptBrowserTest, CallbackGetNumberError2) {
226 ExecuteScript(kCallbackReturnNumberError);
227 ExecuteScript(GenerateSetCallbackErrorCodeScript(2));
228
229 InjectElementLibrary();
230 EXPECT_TRUE(IsLibReady());
231 EXPECT_FALSE(GetError());
232 EXPECT_EQ(translate::TranslateErrors::NONE, GetErrorCode());
233
234 ExecuteScript(kTranslate);
235
236 EXPECT_TRUE(GetError());
237 EXPECT_EQ(translate::TranslateErrors::UNSUPPORTED_LANGUAGE, GetErrorCode());
238 }
239
240 // TODO(toyoshim): Add test for onLoadJavaScript.
241