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/common/translate/translate_errors.h" 8 #include "chrome/test/base/chrome_render_view_test.h" 9 #include "grit/browser_resources.h" 10 #include "third_party/WebKit/public/web/WebFrame.h" 11 #include "third_party/WebKit/public/web/WebScriptSource.h" 12 #include "ui/base/resource/resource_bundle.h" 13 14 using blink::WebFrame; 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 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: 75 TranslateScriptBrowserTest() {} 76 77 protected: 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 87 void ExecuteScript(const std::string& script) { 88 WebScriptSource source = WebScriptSource(ASCIIToUTF16(script)); 89 GetMainFrame()->executeScript(source); 90 } 91 92 bool GetError() { 93 return ExecuteScriptAndGetBoolResult(kError); 94 } 95 96 double GetErrorCode() { 97 return ExecuteScriptAndGetNumberResult(kErrorCode); 98 } 99 100 bool IsLibReady() { 101 return ExecuteScriptAndGetBoolResult(kLibReady); 102 } 103 104 private: 105 virtual void SetUp() OVERRIDE { 106 ChromeRenderViewTest::SetUp(); 107 } 108 109 virtual void TearDown() OVERRIDE { 110 ChromeRenderViewTest::TearDown(); 111 } 112 113 double ExecuteScriptAndGetNumberResult(const std::string& script) { 114 WebScriptSource source = WebScriptSource(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 127 bool ExecuteScriptAndGetBoolResult(const std::string& script) { 128 WebScriptSource source = WebScriptSource(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. 143 TEST_F(TranslateScriptBrowserTest, ElementLoadSuccess) { 144 InjectElementLibrary(); 145 EXPECT_TRUE(IsLibReady()); 146 EXPECT_FALSE(GetError()); 147 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 148 } 149 150 // Test if onTranslateElementLoad() fails to initialize the element library and 151 // report the right error code. 152 TEST_F(TranslateScriptBrowserTest, ElementLoadFailure) { 153 ExecuteScript(kThrowInitializationError); 154 155 InjectElementLibrary(); 156 EXPECT_FALSE(IsLibReady()); 157 EXPECT_TRUE(GetError()); 158 EXPECT_EQ(TranslateErrors::INITIALIZATION_ERROR, GetErrorCode()); 159 } 160 161 // Test if cr.googleTranslate.translate() works. 162 TEST_F(TranslateScriptBrowserTest, TranslateSuccess) { 163 InjectElementLibrary(); 164 EXPECT_TRUE(IsLibReady()); 165 EXPECT_FALSE(GetError()); 166 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 167 168 ExecuteScript(kTranslate); 169 170 EXPECT_FALSE(GetError()); 171 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 172 } 173 174 // Test if cr.googleTranslate.translate() handles library exception correctly. 175 TEST_F(TranslateScriptBrowserTest, TranslateFail) { 176 ExecuteScript(kThrowUnexpectedScriptError); 177 178 InjectElementLibrary(); 179 EXPECT_TRUE(IsLibReady()); 180 EXPECT_FALSE(GetError()); 181 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 182 183 ExecuteScript(kTranslate); 184 185 EXPECT_TRUE(GetError()); 186 EXPECT_EQ(TranslateErrors::UNEXPECTED_SCRIPT_ERROR, GetErrorCode()); 187 } 188 189 // Test if onTranslateProgress callback handles boolean type error correctly. 190 // Remove this test once server side changes the API to return a number. 191 TEST_F(TranslateScriptBrowserTest, CallbackGetBooleanError) { 192 ExecuteScript(kCallbackReturnBooleanError); 193 194 InjectElementLibrary(); 195 EXPECT_TRUE(IsLibReady()); 196 EXPECT_FALSE(GetError()); 197 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 198 199 ExecuteScript(kTranslate); 200 201 EXPECT_TRUE(GetError()); 202 EXPECT_EQ(TranslateErrors::TRANSLATION_ERROR, GetErrorCode()); 203 } 204 205 // Test if onTranslateProgress callback handles number type error correctly and 206 // converts it to the proper error code. 207 TEST_F(TranslateScriptBrowserTest, CallbackGetNumberError1) { 208 ExecuteScript(kCallbackReturnNumberError); 209 ExecuteScript(GenerateSetCallbackErrorCodeScript(1)); 210 211 InjectElementLibrary(); 212 EXPECT_TRUE(IsLibReady()); 213 EXPECT_FALSE(GetError()); 214 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 215 216 ExecuteScript(kTranslate); 217 218 EXPECT_TRUE(GetError()); 219 EXPECT_EQ(TranslateErrors::TRANSLATION_ERROR, GetErrorCode()); 220 } 221 222 // Test if onTranslateProgress callback handles number type error correctly and 223 // converts it to the proper error code. 224 TEST_F(TranslateScriptBrowserTest, CallbackGetNumberError2) { 225 ExecuteScript(kCallbackReturnNumberError); 226 ExecuteScript(GenerateSetCallbackErrorCodeScript(2)); 227 228 InjectElementLibrary(); 229 EXPECT_TRUE(IsLibReady()); 230 EXPECT_FALSE(GetError()); 231 EXPECT_EQ(TranslateErrors::NONE, GetErrorCode()); 232 233 ExecuteScript(kTranslate); 234 235 EXPECT_TRUE(GetError()); 236 EXPECT_EQ(TranslateErrors::UNSUPPORTED_LANGUAGE, GetErrorCode()); 237 } 238 239 // TODO(toyoshim): Add test for onLoadJavaScript. 240