blob: 5c393d8057e81305a87edeee03588c596b23ba96 [file] [log] [blame]
[email protected]13e343c2012-03-16 22:34:221// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]1758e882010-11-01 16:16:502// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/tests/testing_instance.h"
6
avie029c4132015-12-23 06:45:227#include <stddef.h>
8
[email protected]1758e882010-11-01 16:16:509#include <algorithm>
[email protected]9888f132011-03-23 21:07:1510#include <cstring>
[email protected]76aa16e2013-02-19 23:36:2211#include <iomanip>
[email protected]b46661f2011-08-25 01:42:5312#include <sstream>
[email protected]9888f132011-03-23 21:07:1513#include <vector>
[email protected]1758e882010-11-01 16:16:5014
[email protected]76aa16e2013-02-19 23:36:2215#include "ppapi/cpp/core.h"
[email protected]1758e882010-11-01 16:16:5016#include "ppapi/cpp/module.h"
17#include "ppapi/cpp/var.h"
[email protected]09c37ba2012-01-05 18:00:3318#include "ppapi/cpp/view.h"
[email protected]1758e882010-11-01 16:16:5019#include "ppapi/tests/test_case.h"
20
21TestCaseFactory* TestCaseFactory::head_ = NULL;
22
[email protected]b46661f2011-08-25 01:42:5323// Cookie value we use to signal "we're still working." See the comment above
24// the class declaration for how this works.
25static const char kProgressSignal[] = "...";
26
[email protected]1758e882010-11-01 16:16:5027// Returns a new heap-allocated test case for the given test, or NULL on
28// failure.
29TestingInstance::TestingInstance(PP_Instance instance)
[email protected]7f801d82011-07-08 23:30:1130#if (defined __native_client__)
[email protected]1758e882010-11-01 16:16:5031 : pp::Instance(instance),
[email protected]7f801d82011-07-08 23:30:1132#else
33 : pp::InstancePrivate(instance),
34#endif
[email protected]1758e882010-11-01 16:16:5035 current_case_(NULL),
[email protected]52d2c8e02010-11-16 20:59:2336 executed_tests_(false),
[email protected]2baf7ace2012-06-22 18:51:2037 number_tests_executed_(0),
[email protected]bedf8742012-03-16 16:44:1138 nacl_mode_(false),
[email protected]6c113402012-03-23 01:31:5139 ssl_server_port_(-1),
[email protected]5b8f977d2012-06-28 21:19:3740 websocket_port_(-1),
41 remove_plugin_(true) {
[email protected]1758e882010-11-01 16:16:5042 callback_factory_.Initialize(this);
43}
44
[email protected]63082002011-06-07 22:56:0445TestingInstance::~TestingInstance() {
46 if (current_case_)
47 delete current_case_;
48}
49
[email protected]52d2c8e02010-11-16 20:59:2350bool TestingInstance::Init(uint32_t argc,
51 const char* argn[],
52 const char* argv[]) {
53 for (uint32_t i = 0; i < argc; i++) {
[email protected]9888f132011-03-23 21:07:1554 if (std::strcmp(argn[i], "mode") == 0) {
55 if (std::strcmp(argv[i], "nacl") == 0)
[email protected]52d2c8e02010-11-16 20:59:2356 nacl_mode_ = true;
[email protected]bedf8742012-03-16 16:44:1157 } else if (std::strcmp(argn[i], "protocol") == 0) {
[email protected]7f801d82011-07-08 23:30:1158 protocol_ = argv[i];
[email protected]21de9cb22013-02-14 13:07:3459 } else if (std::strcmp(argn[i], "websocket_host") == 0) {
60 websocket_host_ = argv[i];
[email protected]bedf8742012-03-16 16:44:1161 } else if (std::strcmp(argn[i], "websocket_port") == 0) {
62 websocket_port_ = atoi(argv[i]);
[email protected]6c113402012-03-23 01:31:5163 } else if (std::strcmp(argn[i], "ssl_server_port") == 0) {
64 ssl_server_port_ = atoi(argv[i]);
[email protected]bedf8742012-03-16 16:44:1165 }
[email protected]52d2c8e02010-11-16 20:59:2366 }
[email protected]1758e882010-11-01 16:16:5067 // Create the proper test case from the argument.
68 for (uint32_t i = 0; i < argc; i++) {
[email protected]9888f132011-03-23 21:07:1569 if (std::strcmp(argn[i], "testcase") == 0) {
[email protected]1758e882010-11-01 16:16:5070 if (argv[i][0] == '\0')
71 break;
72 current_case_ = CaseForTestName(argv[i]);
[email protected]76aa16e2013-02-19 23:36:2273 test_filter_ = argv[i];
[email protected]1758e882010-11-01 16:16:5074 if (!current_case_)
75 errors_.append(std::string("Unknown test case ") + argv[i]);
76 else if (!current_case_->Init())
77 errors_.append(" Test case could not initialize.");
78 return true;
79 }
80 }
81
82 // In DidChangeView, we'll dump out a list of all available tests.
83 return true;
84}
85
[email protected]7f801d82011-07-08 23:30:1186#if !(defined __native_client__)
[email protected]1758e882010-11-01 16:16:5087pp::Var TestingInstance::GetInstanceObject() {
[email protected]88bfb432011-05-23 22:43:5988 if (current_case_)
89 return current_case_->GetTestObject();
90
[email protected]7f801d82011-07-08 23:30:1191 return pp::VarPrivate();
[email protected]1758e882010-11-01 16:16:5092}
[email protected]7f801d82011-07-08 23:30:1193#endif
[email protected]1758e882010-11-01 16:16:5094
[email protected]9888f132011-03-23 21:07:1595void TestingInstance::HandleMessage(const pp::Var& message_data) {
[email protected]dafab752011-09-20 20:08:4096 if (current_case_)
97 current_case_->HandleMessage(message_data);
[email protected]9888f132011-03-23 21:07:1598}
99
[email protected]09c37ba2012-01-05 18:00:33100void TestingInstance::DidChangeView(const pp::View& view) {
[email protected]1758e882010-11-01 16:16:50101 if (!executed_tests_) {
102 executed_tests_ = true;
103 pp::Module::Get()->core()->CallOnMainThread(
104 0,
105 callback_factory_.NewCallback(&TestingInstance::ExecuteTests));
106 }
[email protected]dafab752011-09-20 20:08:40107 if (current_case_)
[email protected]09c37ba2012-01-05 18:00:33108 current_case_->DidChangeView(view);
[email protected]1758e882010-11-01 16:16:50109}
110
[email protected]f949c9c2011-09-23 22:04:09111bool TestingInstance::HandleInputEvent(const pp::InputEvent& event) {
112 if (current_case_)
113 return current_case_->HandleInputEvent(event);
114 return false;
115}
116
[email protected]08610102011-12-17 14:24:30117void TestingInstance::EvalScript(const std::string& script) {
[email protected]13e343c2012-03-16 22:34:22118 SendTestCommand("EvalScript", script);
[email protected]08610102011-12-17 14:24:30119}
120
[email protected]09c37ba2012-01-05 18:00:33121void TestingInstance::SetCookie(const std::string& name,
122 const std::string& value) {
[email protected]13e343c2012-03-16 22:34:22123 SendTestCommand("SetCookie", name + "=" + value);
[email protected]09c37ba2012-01-05 18:00:33124}
125
[email protected]1758e882010-11-01 16:16:50126void TestingInstance::LogTest(const std::string& test_name,
[email protected]76aa16e2013-02-19 23:36:22127 const std::string& error_message,
128 PP_TimeTicks start_time) {
dmichaele5ac6332014-09-26 20:34:38129 current_test_name_ = test_name;
130
[email protected]76aa16e2013-02-19 23:36:22131 // Compute the time to run the test and save it in a string for logging:
132 PP_TimeTicks end_time(pp::Module::Get()->core()->GetTimeTicks());
133 std::ostringstream number_stream;
134 PP_TimeTicks elapsed_time(end_time - start_time);
135 number_stream << std::fixed << std::setprecision(3) << elapsed_time;
136 std::string time_string(number_stream.str());
137
[email protected]b46661f2011-08-25 01:42:53138 // Tell the browser we're still working.
139 ReportProgress(kProgressSignal);
140
[email protected]2baf7ace2012-06-22 18:51:20141 number_tests_executed_++;
142
[email protected]1758e882010-11-01 16:16:50143 std::string html;
144 html.append("<div class=\"test_line\"><span class=\"test_name\">");
145 html.append(test_name);
146 html.append("</span> ");
147 if (error_message.empty()) {
148 html.append("<span class=\"pass\">PASS</span>");
149 } else {
150 html.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
151 html.append(error_message);
152 html.append("</span>");
153
154 if (!errors_.empty())
155 errors_.append(", "); // Separator for different error messages.
156 errors_.append(test_name + " FAIL: " + error_message);
157 }
[email protected]76aa16e2013-02-19 23:36:22158 html.append(" <span class=\"time\">(");
159 html.append(time_string);
160 html.append("s)</span>");
161
[email protected]1758e882010-11-01 16:16:50162 html.append("</div>");
163 LogHTML(html);
[email protected]a33a08982013-10-31 17:23:29164
165 std::string test_time;
166 test_time.append(test_name);
167 test_time.append(" finished in ");
168 test_time.append(time_string);
169 test_time.append(" seconds.");
170 LogTestTime(test_time);
dmichaele5ac6332014-09-26 20:34:38171
172 current_test_name_.clear();
[email protected]1758e882010-11-01 16:16:50173}
174
175void TestingInstance::AppendError(const std::string& message) {
176 if (!errors_.empty())
177 errors_.append(", ");
178 errors_.append(message);
179}
180
181void TestingInstance::ExecuteTests(int32_t unused) {
[email protected]b46661f2011-08-25 01:42:53182 ReportProgress(kProgressSignal);
[email protected]49c09c15d2010-12-10 02:46:03183
[email protected]1758e882010-11-01 16:16:50184 // Clear the console.
[email protected]13e343c2012-03-16 22:34:22185 SendTestCommand("ClearConsole");
[email protected]1758e882010-11-01 16:16:50186
187 if (!errors_.empty()) {
188 // Catch initialization errors and output the current error string to
189 // the console.
190 LogError("Plugin initialization failed: " + errors_);
191 } else if (!current_case_) {
192 LogAvailableTests();
[email protected]ebc5c8be2011-05-20 22:52:59193 errors_.append("FAIL: Only listed tests");
[email protected]1758e882010-11-01 16:16:50194 } else {
[email protected]2622d6b2011-11-16 04:28:02195 current_case_->RunTests(test_filter_);
[email protected]2baf7ace2012-06-22 18:51:20196
197 if (number_tests_executed_ == 0) {
198 errors_.append("No tests executed. The test filter might be too "
199 "restrictive: '" + test_filter_ + "'.");
200 LogError(errors_);
201 }
[email protected]76aa16e2013-02-19 23:36:22202 if (current_case_->skipped_tests().size()) {
203 // TODO(dmichael): Convert all TestCases to run all tests in one fixture,
204 // and enable this check. Currently, a lot of our tests
205 // run 1 test per fixture, which is slow.
206 /*
207 errors_.append("Some tests were not listed and thus were not run. Make "
208 "sure all tests are passed in the test_case URL (even if "
209 "they are marked DISABLED_). Forgotten tests: ");
210 std::set<std::string>::const_iterator iter =
211 current_case_->skipped_tests().begin();
212 for (; iter != current_case_->skipped_tests().end(); ++iter) {
213 errors_.append(*iter);
214 errors_.append(" ");
215 }
216 LogError(errors_);
217 */
218 }
219 if (current_case_->remaining_tests().size()) {
220 errors_.append("Some listed tests were not found in the TestCase. Check "
221 "the test names that were passed to make sure they match "
222 "tests in the TestCase. Unknown tests: ");
223 std::map<std::string, bool>::const_iterator iter =
224 current_case_->remaining_tests().begin();
225 for (; iter != current_case_->remaining_tests().end(); ++iter) {
226 errors_.append(iter->first);
227 errors_.append(" ");
228 }
229 LogError(errors_);
[email protected]2baf7ace2012-06-22 18:51:20230 }
[email protected]1758e882010-11-01 16:16:50231 }
232
[email protected]5b8f977d2012-06-28 21:19:37233 if (remove_plugin_)
[email protected]e7425db2013-07-17 20:15:21234 SendTestCommand("RemovePluginWhenFinished");
235 std::string result(errors_);
236 if (result.empty())
237 result = "PASS";
238 SendTestCommand("DidExecuteTests", result);
239 // Note, DidExecuteTests may unload the plugin. We can't really do anything
240 // after this point.
[email protected]1758e882010-11-01 16:16:50241}
242
[email protected]2622d6b2011-11-16 04:28:02243TestCase* TestingInstance::CaseForTestName(const std::string& name) {
[email protected]bedf8742012-03-16 16:44:11244 std::string case_name = name.substr(0, name.find_first_of('_'));
[email protected]1758e882010-11-01 16:16:50245 TestCaseFactory* iter = TestCaseFactory::head_;
246 while (iter != NULL) {
[email protected]2622d6b2011-11-16 04:28:02247 if (case_name == iter->name_)
[email protected]1758e882010-11-01 16:16:50248 return iter->method_(this);
249 iter = iter->next_;
250 }
251 return NULL;
252}
253
[email protected]13e343c2012-03-16 22:34:22254void TestingInstance::SendTestCommand(const std::string& command) {
255 std::string msg("TESTING_MESSAGE:");
256 msg += command;
257 PostMessage(pp::Var(msg));
258}
259
260void TestingInstance::SendTestCommand(const std::string& command,
261 const std::string& params) {
262 SendTestCommand(command + ":" + params);
263}
264
265
[email protected]1758e882010-11-01 16:16:50266void TestingInstance::LogAvailableTests() {
267 // Print out a listing of all tests.
268 std::vector<std::string> test_cases;
269 TestCaseFactory* iter = TestCaseFactory::head_;
270 while (iter != NULL) {
271 test_cases.push_back(iter->name_);
272 iter = iter->next_;
273 }
274 std::sort(test_cases.begin(), test_cases.end());
275
276 std::string html;
277 html.append("Available test cases: <dl>");
278 for (size_t i = 0; i < test_cases.size(); ++i) {
[email protected]52d2c8e02010-11-16 20:59:23279 html.append("<dd><a href='?testcase=");
[email protected]1758e882010-11-01 16:16:50280 html.append(test_cases[i]);
[email protected]52d2c8e02010-11-16 20:59:23281 if (nacl_mode_)
282 html.append("&mode=nacl");
[email protected]1758e882010-11-01 16:16:50283 html.append("'>");
284 html.append(test_cases[i]);
285 html.append("</a></dd>");
286 }
287 html.append("</dl>");
288 html.append("<button onclick='RunAll()'>Run All Tests</button>");
[email protected]7f801d82011-07-08 23:30:11289
[email protected]1758e882010-11-01 16:16:50290 LogHTML(html);
291}
292
293void TestingInstance::LogError(const std::string& text) {
294 std::string html;
295 html.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
296 html.append(text);
297 html.append("</span>");
298 LogHTML(html);
299}
300
301void TestingInstance::LogHTML(const std::string& html) {
[email protected]13e343c2012-03-16 22:34:22302 SendTestCommand("LogHTML", html);
[email protected]1758e882010-11-01 16:16:50303}
304
[email protected]b46661f2011-08-25 01:42:53305void TestingInstance::ReportProgress(const std::string& progress_value) {
[email protected]e7425db2013-07-17 20:15:21306 SendTestCommand("ReportProgress", progress_value);
[email protected]b46661f2011-08-25 01:42:53307}
308
[email protected]13e343c2012-03-16 22:34:22309void TestingInstance::AddPostCondition(const std::string& script) {
310 SendTestCommand("AddPostCondition", script);
311}
312
[email protected]a33a08982013-10-31 17:23:29313void TestingInstance::LogTestTime(const std::string& test_time) {
314 SendTestCommand("LogTestTime", test_time);
315}
316
[email protected]1758e882010-11-01 16:16:50317class Module : public pp::Module {
318 public:
319 Module() : pp::Module() {}
320 virtual ~Module() {}
321
322 virtual pp::Instance* CreateInstance(PP_Instance instance) {
323 return new TestingInstance(instance);
324 }
325};
326
327namespace pp {
328
phosek70a330f2015-09-24 03:23:22329#if defined(WIN32)
330__declspec(dllexport)
331#else
332__attribute__((visibility("default")))
333#endif
[email protected]1758e882010-11-01 16:16:50334Module* CreateModule() {
335 return new ::Module();
336}
337
338} // namespace pp