// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "cefclient/test_runner.h" #include "include/base/cef_bind.h" #include "include/cef_task.h" #include "include/cef_trace.h" #include "include/cef_url.h" #include "include/cef_web_plugin.h" #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_stream_resource_handler.h" #include "cefclient/binding_test.h" #include "cefclient/dialog_test.h" #include "cefclient/main_context.h" #include "cefclient/resource.h" #include "cefclient/resource_util.h" #include "cefclient/scheme_test.h" #include "cefclient/window_test.h" namespace client { namespace test_runner { namespace { const char kTestOrigin[] = "http://tests/"; // Replace all instances of |from| with |to| in |str|. std::string StringReplace(const std::string& str, const std::string& from, const std::string& to) { std::string result = str; std::string::size_type pos = 0; std::string::size_type from_len = from.length(); std::string::size_type to_len = to.length(); do { pos = result.find(from, pos); if (pos != std::string::npos) { result.replace(pos, from_len, to); pos += to_len; } } while (pos != std::string::npos); return result; } void RunGetSourceTest(CefRefPtr browser) { class Visitor : public CefStringVisitor { public: explicit Visitor(CefRefPtr browser) : browser_(browser) {} virtual void Visit(const CefString& string) OVERRIDE { std::string source = StringReplace(string, "<", "<"); source = StringReplace(source, ">", ">"); std::stringstream ss; ss << "Source:
" << source <<
            "
"; browser_->GetMainFrame()->LoadString(ss.str(), "http://tests/getsource"); } private: CefRefPtr browser_; IMPLEMENT_REFCOUNTING(Visitor); }; browser->GetMainFrame()->GetSource(new Visitor(browser)); } void RunGetTextTest(CefRefPtr browser) { class Visitor : public CefStringVisitor { public: explicit Visitor(CefRefPtr browser) : browser_(browser) {} virtual void Visit(const CefString& string) OVERRIDE { std::string text = StringReplace(string, "<", "<"); text = StringReplace(text, ">", ">"); std::stringstream ss; ss << "Text:
" << text <<
            "
"; browser_->GetMainFrame()->LoadString(ss.str(), "http://tests/gettext"); } private: CefRefPtr browser_; IMPLEMENT_REFCOUNTING(Visitor); }; browser->GetMainFrame()->GetText(new Visitor(browser)); } void RunRequestTest(CefRefPtr browser) { // Create a new request CefRefPtr request(CefRequest::Create()); // Set the request URL request->SetURL("http://tests/request"); // Add post data to the request. The correct method and content- // type headers will be set by CEF. CefRefPtr postDataElement(CefPostDataElement::Create()); std::string data = "arg1=val1&arg2=val2"; postDataElement->SetToBytes(data.length(), data.c_str()); CefRefPtr postData(CefPostData::Create()); postData->AddElement(postDataElement); request->SetPostData(postData); // Add a custom header CefRequest::HeaderMap headerMap; headerMap.insert( std::make_pair("X-My-Header", "My Header Value")); request->SetHeaderMap(headerMap); // Load the request browser->GetMainFrame()->LoadRequest(request); } void RunPopupTest(CefRefPtr browser) { browser->GetMainFrame()->ExecuteJavaScript( "window.open('http://www.google.com');", "about:blank", 0); } void RunPluginInfoTest(CefRefPtr browser) { class Visitor : public CefWebPluginInfoVisitor { public: explicit Visitor(CefRefPtr browser) : browser_(browser) { html_ = "Plugin Info Test" "" "\nInstalled plugins:"; } ~Visitor() { html_ += "\n"; // Load the html in the browser. browser_->GetMainFrame()->LoadString(html_, "http://tests/plugin_info"); } virtual bool Visit(CefRefPtr info, int count, int total) OVERRIDE { html_ += "\n

Name: " + info->GetName().ToString() + "\n
Description: " + info->GetDescription().ToString() + "\n
Version: " + info->GetVersion().ToString() + "\n
Path: " + info->GetPath().ToString(); return true; } private: std::string html_; CefRefPtr browser_; IMPLEMENT_REFCOUNTING(Visitor); }; CefVisitWebPluginInfo(new Visitor(browser)); } void ModifyZoom(CefRefPtr browser, double delta) { if (!CefCurrentlyOn(TID_UI)) { // Execute on the UI thread. CefPostTask(TID_UI, base::Bind(&ModifyZoom, browser, delta)); return; } browser->GetHost()->SetZoomLevel( browser->GetHost()->GetZoomLevel() + delta); } void BeginTracing() { if (!CefCurrentlyOn(TID_UI)) { // Execute on the UI thread. CefPostTask(TID_UI, base::Bind(&BeginTracing)); return; } CefBeginTracing(CefString(), NULL); } void EndTracing(CefRefPtr browser) { if (!CefCurrentlyOn(TID_UI)) { // Execute on the UI thread. CefPostTask(TID_UI, base::Bind(&EndTracing, browser)); return; } class Client : public CefEndTracingCallback, public CefRunFileDialogCallback { public: explicit Client(CefRefPtr browser) : browser_(browser) { RunDialog(); } void RunDialog() { static const char kDefaultFileName[] = "trace.txt"; std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName); if (path.empty()) path = kDefaultFileName; // Results in a call to OnFileDialogDismissed. browser_->GetHost()->RunFileDialog( FILE_DIALOG_SAVE, CefString(), // title path, std::vector(), // accept_filters 0, // selected_accept_filter this); } virtual void OnFileDialogDismissed( int selected_accept_filter, const std::vector& file_paths) OVERRIDE { if (!file_paths.empty()) { // File selected. Results in a call to OnEndTracingComplete. CefEndTracing(file_paths.front(), this); } else { // No file selected. Discard the trace data. CefEndTracing(CefString(), NULL); } } virtual void OnEndTracingComplete( const CefString& tracing_file) OVERRIDE { Alert(browser_, "File \"" + tracing_file.ToString() + "\" saved successfully."); } private: CefRefPtr browser_; IMPLEMENT_REFCOUNTING(Client); }; new Client(browser); } void RunOtherTests(CefRefPtr browser) { browser->GetMainFrame()->LoadURL("http://tests/other_tests"); } // Retrieve the file name and mime type based on the specified url. bool ParseTestUrl(const std::string& url, std::string* file_name, std::string* mime_type) { // Retrieve the path component. CefURLParts parts; CefParseURL(url, parts); std::string file = CefString(&parts.path); if (file.size() < 2) return false; // Remove the leading slash. file = file.substr(1); // Verify that the file name is valid. for(size_t i = 0; i < file.size(); ++i) { const char c = file[i]; if (!isalpha(c) && !isdigit(c) && c != '_' && c != '.') return false; } // Determine the mime type based on the file extension, if any. size_t pos = file.rfind("."); if (pos != std::string::npos) { std::string ext = file.substr(pos + 1); if (ext == "html") *mime_type = "text/html"; else if (ext == "png") *mime_type = "image/png"; else return false; } else { // Default to an html extension if none is specified. *mime_type = "text/html"; file += ".html"; } *file_name = file; return true; } } // namespace void RunTest(CefRefPtr browser, int id) { if (!browser) return; switch (id) { case ID_TESTS_GETSOURCE: RunGetSourceTest(browser); break; case ID_TESTS_GETTEXT: RunGetTextTest(browser); break; case ID_TESTS_POPUP: RunPopupTest(browser); break; case ID_TESTS_REQUEST: RunRequestTest(browser); break; case ID_TESTS_PLUGIN_INFO: RunPluginInfoTest(browser); break; case ID_TESTS_ZOOM_IN: ModifyZoom(browser, 0.5); break; case ID_TESTS_ZOOM_OUT: ModifyZoom(browser, -0.5); break; case ID_TESTS_ZOOM_RESET: browser->GetHost()->SetZoomLevel(0.0); break; case ID_TESTS_TRACING_BEGIN: BeginTracing(); break; case ID_TESTS_TRACING_END: EndTracing(browser); break; case ID_TESTS_PRINT: browser->GetHost()->Print(); break; case ID_TESTS_OTHER_TESTS: RunOtherTests(browser); break; } } void DumpRequestContents(CefRefPtr request, std::string& str) { std::stringstream ss; ss << "URL: " << std::string(request->GetURL()); ss << "\nMethod: " << std::string(request->GetMethod()); CefRequest::HeaderMap headerMap; request->GetHeaderMap(headerMap); if (headerMap.size() > 0) { ss << "\nHeaders:"; CefRequest::HeaderMap::const_iterator it = headerMap.begin(); for (; it != headerMap.end(); ++it) { ss << "\n\t" << std::string((*it).first) << ": " << std::string((*it).second); } } CefRefPtr postData = request->GetPostData(); if (postData.get()) { CefPostData::ElementVector elements; postData->GetElements(elements); if (elements.size() > 0) { ss << "\nPost Data:"; CefRefPtr element; CefPostData::ElementVector::const_iterator it = elements.begin(); for (; it != elements.end(); ++it) { element = (*it); if (element->GetType() == PDE_TYPE_BYTES) { // the element is composed of bytes ss << "\n\tBytes: "; if (element->GetBytesCount() == 0) { ss << "(empty)"; } else { // retrieve the data. size_t size = element->GetBytesCount(); char* bytes = new char[size]; element->GetBytes(size, bytes); ss << std::string(bytes, size); delete [] bytes; } } else if (element->GetType() == PDE_TYPE_FILE) { ss << "\n\tFile: " << std::string(element->GetFile()); } } } } str = ss.str(); } CefRefPtr GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) { std::string url = request->GetURL(); if (url.find(kTestOrigin) == 0) { // Handle URLs in the test origin. std::string file_name, mime_type; if (ParseTestUrl(url, &file_name, &mime_type)) { if (file_name == "request.html") { // Show the request contents. std::string dump; DumpRequestContents(request, dump); std::string str = "
" + dump +
                          "
"; CefRefPtr stream = CefStreamReader::CreateForData( static_cast(const_cast(str.c_str())), str.size()); DCHECK(stream.get()); return new CefStreamResourceHandler("text/html", stream); } else { // Load the resource from file. CefRefPtr stream = GetBinaryResourceReader(file_name.c_str()); if (stream.get()) return new CefStreamResourceHandler(mime_type, stream); } } } return NULL; } void Alert(CefRefPtr browser, const std::string& message) { // Escape special characters in the message. std::string msg = StringReplace(message, "\\", "\\\\"); msg = StringReplace(msg, "'", "\\'"); // Execute a JavaScript alert(). CefRefPtr frame = browser->GetMainFrame(); frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0); } void CreateMessageHandlers(MessageHandlerSet& handlers) { // Create the dialog test handlers. dialog_test::CreateMessageHandlers(handlers); // Create the binding test handlers. binding_test::CreateMessageHandlers(handlers); // Create the window test handlers. window_test::CreateMessageHandlers(handlers); } void RegisterSchemeHandlers() { // Register the scheme handler. scheme_test::RegisterSchemeHandlers(); } } // namespace test_runner } // namespace client