Refactor android test results logging.
[chromium-blink-merge.git] / ppapi / tests / testing_instance.cc
bloba6fa0dd37932b5d0fc8fac22ef94bcd9620f01b9
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.
5 #include "ppapi/tests/testing_instance.h"
7 #include <algorithm>
8 #include <cstring>
9 #include <sstream>
10 #include <vector>
12 #include "ppapi/cpp/module.h"
13 #include "ppapi/cpp/var.h"
14 #include "ppapi/cpp/view.h"
15 #include "ppapi/tests/test_case.h"
17 TestCaseFactory* TestCaseFactory::head_ = NULL;
19 // Cookie value we use to signal "we're still working." See the comment above
20 // the class declaration for how this works.
21 static const char kProgressSignal[] = "...";
23 // Returns a new heap-allocated test case for the given test, or NULL on
24 // failure.
25 TestingInstance::TestingInstance(PP_Instance instance)
26 #if (defined __native_client__)
27 : pp::Instance(instance),
28 #else
29 : pp::InstancePrivate(instance),
30 #endif
31 current_case_(NULL),
32 executed_tests_(false),
33 number_tests_executed_(0),
34 nacl_mode_(false),
35 ssl_server_port_(-1),
36 websocket_port_(-1),
37 remove_plugin_(true) {
38 callback_factory_.Initialize(this);
41 TestingInstance::~TestingInstance() {
42 if (current_case_)
43 delete current_case_;
46 bool TestingInstance::Init(uint32_t argc,
47 const char* argn[],
48 const char* argv[]) {
49 for (uint32_t i = 0; i < argc; i++) {
50 if (std::strcmp(argn[i], "mode") == 0) {
51 if (std::strcmp(argv[i], "nacl") == 0)
52 nacl_mode_ = true;
53 } else if (std::strcmp(argn[i], "protocol") == 0) {
54 protocol_ = argv[i];
55 } else if (std::strcmp(argn[i], "websocket_port") == 0) {
56 websocket_port_ = atoi(argv[i]);
57 } else if (std::strcmp(argn[i], "ssl_server_port") == 0) {
58 ssl_server_port_ = atoi(argv[i]);
61 // Create the proper test case from the argument.
62 for (uint32_t i = 0; i < argc; i++) {
63 if (std::strcmp(argn[i], "testcase") == 0) {
64 if (argv[i][0] == '\0')
65 break;
66 current_case_ = CaseForTestName(argv[i]);
67 test_filter_ = FilterForTestName(argv[i]);
68 if (!current_case_)
69 errors_.append(std::string("Unknown test case ") + argv[i]);
70 else if (!current_case_->Init())
71 errors_.append(" Test case could not initialize.");
72 return true;
76 // In DidChangeView, we'll dump out a list of all available tests.
77 return true;
80 #if !(defined __native_client__)
81 pp::Var TestingInstance::GetInstanceObject() {
82 if (current_case_)
83 return current_case_->GetTestObject();
85 return pp::VarPrivate();
87 #endif
89 void TestingInstance::HandleMessage(const pp::Var& message_data) {
90 if (current_case_)
91 current_case_->HandleMessage(message_data);
94 void TestingInstance::DidChangeView(const pp::View& view) {
95 if (!executed_tests_) {
96 executed_tests_ = true;
97 pp::Module::Get()->core()->CallOnMainThread(
99 callback_factory_.NewCallback(&TestingInstance::ExecuteTests));
101 if (current_case_)
102 current_case_->DidChangeView(view);
105 bool TestingInstance::HandleInputEvent(const pp::InputEvent& event) {
106 if (current_case_)
107 return current_case_->HandleInputEvent(event);
108 return false;
111 void TestingInstance::EvalScript(const std::string& script) {
112 SendTestCommand("EvalScript", script);
115 void TestingInstance::SetCookie(const std::string& name,
116 const std::string& value) {
117 SendTestCommand("SetCookie", name + "=" + value);
120 void TestingInstance::LogTest(const std::string& test_name,
121 const std::string& error_message) {
122 // Tell the browser we're still working.
123 ReportProgress(kProgressSignal);
125 number_tests_executed_++;
127 std::string html;
128 html.append("<div class=\"test_line\"><span class=\"test_name\">");
129 html.append(test_name);
130 html.append("</span> ");
131 if (error_message.empty()) {
132 html.append("<span class=\"pass\">PASS</span>");
133 } else {
134 html.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
135 html.append(error_message);
136 html.append("</span>");
138 if (!errors_.empty())
139 errors_.append(", "); // Separator for different error messages.
140 errors_.append(test_name + " FAIL: " + error_message);
142 html.append("</div>");
143 LogHTML(html);
146 void TestingInstance::AppendError(const std::string& message) {
147 if (!errors_.empty())
148 errors_.append(", ");
149 errors_.append(message);
152 void TestingInstance::ExecuteTests(int32_t unused) {
153 ReportProgress(kProgressSignal);
155 // Clear the console.
156 SendTestCommand("ClearConsole");
158 if (!errors_.empty()) {
159 // Catch initialization errors and output the current error string to
160 // the console.
161 LogError("Plugin initialization failed: " + errors_);
162 } else if (!current_case_) {
163 LogAvailableTests();
164 errors_.append("FAIL: Only listed tests");
165 } else {
166 current_case_->RunTests(test_filter_);
168 if (number_tests_executed_ == 0) {
169 errors_.append("No tests executed. The test filter might be too "
170 "restrictive: '" + test_filter_ + "'.");
171 LogError(errors_);
173 else {
174 // Automated PyAuto tests rely on finding the exact strings below.
175 LogHTML(errors_.empty() ?
176 "<span class=\"pass\">[SHUTDOWN]</span> All tests passed." :
177 "<span class=\"fail\">[SHUTDOWN]</span> Some tests failed.");
181 // Declare we're done by setting a cookie to either "PASS" or the errors.
182 ReportProgress(errors_.empty() ? "PASS" : errors_);
183 if (remove_plugin_)
184 SendTestCommand("DidExecuteTests");
185 // Note, DidExecuteTests unloads the plugin. We can't really do anthing after
186 // this point.
189 TestCase* TestingInstance::CaseForTestName(const std::string& name) {
190 std::string case_name = name.substr(0, name.find_first_of('_'));
191 TestCaseFactory* iter = TestCaseFactory::head_;
192 while (iter != NULL) {
193 if (case_name == iter->name_)
194 return iter->method_(this);
195 iter = iter->next_;
197 return NULL;
200 std::string TestingInstance::FilterForTestName(const std::string& name) {
201 size_t delim = name.find_first_of('_');
202 if (delim != std::string::npos)
203 return name.substr(delim+1);
204 return "";
207 void TestingInstance::SendTestCommand(const std::string& command) {
208 std::string msg("TESTING_MESSAGE:");
209 msg += command;
210 PostMessage(pp::Var(msg));
213 void TestingInstance::SendTestCommand(const std::string& command,
214 const std::string& params) {
215 SendTestCommand(command + ":" + params);
219 void TestingInstance::LogAvailableTests() {
220 // Print out a listing of all tests.
221 std::vector<std::string> test_cases;
222 TestCaseFactory* iter = TestCaseFactory::head_;
223 while (iter != NULL) {
224 test_cases.push_back(iter->name_);
225 iter = iter->next_;
227 std::sort(test_cases.begin(), test_cases.end());
229 std::string html;
230 html.append("Available test cases: <dl>");
231 for (size_t i = 0; i < test_cases.size(); ++i) {
232 html.append("<dd><a href='?testcase=");
233 html.append(test_cases[i]);
234 if (nacl_mode_)
235 html.append("&mode=nacl");
236 html.append("'>");
237 html.append(test_cases[i]);
238 html.append("</a></dd>");
240 html.append("</dl>");
241 html.append("<button onclick='RunAll()'>Run All Tests</button>");
243 LogHTML(html);
246 void TestingInstance::LogError(const std::string& text) {
247 std::string html;
248 html.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
249 html.append(text);
250 html.append("</span>");
251 LogHTML(html);
254 void TestingInstance::LogHTML(const std::string& html) {
255 SendTestCommand("LogHTML", html);
258 void TestingInstance::ReportProgress(const std::string& progress_value) {
259 // Use streams since nacl doesn't compile base yet (for StringPrintf).
260 std::ostringstream script;
261 script << "window.domAutomationController.setAutomationId(0);" <<
262 "window.domAutomationController.send(\"" << progress_value << "\")";
263 EvalScript(script.str());
266 void TestingInstance::AddPostCondition(const std::string& script) {
267 SendTestCommand("AddPostCondition", script);
270 class Module : public pp::Module {
271 public:
272 Module() : pp::Module() {}
273 virtual ~Module() {}
275 virtual pp::Instance* CreateInstance(PP_Instance instance) {
276 return new TestingInstance(instance);
280 namespace pp {
282 Module* CreateModule() {
283 return new ::Module();
286 } // namespace pp