blob: 58e08907fc217d7e8d4c3a0aa83d67becad7865e [file] [log] [blame]
[email protected]ebc5c8be2011-05-20 22:52:591// Copyright (c) 2011 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
7#include <algorithm>
[email protected]9888f132011-03-23 21:07:158#include <cstring>
[email protected]b46661f2011-08-25 01:42:539#include <sstream>
[email protected]9888f132011-03-23 21:07:1510#include <vector>
[email protected]1758e882010-11-01 16:16:5011
12#include "ppapi/cpp/module.h"
13#include "ppapi/cpp/var.h"
[email protected]09c37ba2012-01-05 18:00:3314#include "ppapi/cpp/view.h"
[email protected]1758e882010-11-01 16:16:5015#include "ppapi/tests/test_case.h"
16
17TestCaseFactory* TestCaseFactory::head_ = NULL;
18
[email protected]b46661f2011-08-25 01:42:5319// Cookie value we use to signal "we're still working." See the comment above
20// the class declaration for how this works.
21static const char kProgressSignal[] = "...";
22
[email protected]1758e882010-11-01 16:16:5023// Returns a new heap-allocated test case for the given test, or NULL on
24// failure.
25TestingInstance::TestingInstance(PP_Instance instance)
[email protected]7f801d82011-07-08 23:30:1126#if (defined __native_client__)
[email protected]1758e882010-11-01 16:16:5027 : pp::Instance(instance),
[email protected]7f801d82011-07-08 23:30:1128#else
29 : pp::InstancePrivate(instance),
30#endif
[email protected]1758e882010-11-01 16:16:5031 current_case_(NULL),
[email protected]b46661f2011-08-25 01:42:5332 progress_cookie_number_(0),
[email protected]52d2c8e02010-11-16 20:59:2333 executed_tests_(false),
34 nacl_mode_(false) {
[email protected]1758e882010-11-01 16:16:5035 callback_factory_.Initialize(this);
36}
37
[email protected]63082002011-06-07 22:56:0438TestingInstance::~TestingInstance() {
39 if (current_case_)
40 delete current_case_;
41}
42
[email protected]52d2c8e02010-11-16 20:59:2343bool TestingInstance::Init(uint32_t argc,
44 const char* argn[],
45 const char* argv[]) {
46 for (uint32_t i = 0; i < argc; i++) {
[email protected]9888f132011-03-23 21:07:1547 if (std::strcmp(argn[i], "mode") == 0) {
48 if (std::strcmp(argv[i], "nacl") == 0)
[email protected]52d2c8e02010-11-16 20:59:2349 nacl_mode_ = true;
[email protected]52d2c8e02010-11-16 20:59:2350 }
[email protected]7f801d82011-07-08 23:30:1151 else if (std::strcmp(argn[i], "protocol") == 0)
52 protocol_ = argv[i];
[email protected]52d2c8e02010-11-16 20:59:2353 }
[email protected]1758e882010-11-01 16:16:5054 // Create the proper test case from the argument.
55 for (uint32_t i = 0; i < argc; i++) {
[email protected]9888f132011-03-23 21:07:1556 if (std::strcmp(argn[i], "testcase") == 0) {
[email protected]1758e882010-11-01 16:16:5057 if (argv[i][0] == '\0')
58 break;
59 current_case_ = CaseForTestName(argv[i]);
[email protected]2622d6b2011-11-16 04:28:0260 test_filter_ = FilterForTestName(argv[i]);
[email protected]1758e882010-11-01 16:16:5061 if (!current_case_)
62 errors_.append(std::string("Unknown test case ") + argv[i]);
63 else if (!current_case_->Init())
64 errors_.append(" Test case could not initialize.");
65 return true;
66 }
67 }
68
69 // In DidChangeView, we'll dump out a list of all available tests.
70 return true;
71}
72
[email protected]7f801d82011-07-08 23:30:1173#if !(defined __native_client__)
[email protected]1758e882010-11-01 16:16:5074pp::Var TestingInstance::GetInstanceObject() {
[email protected]88bfb432011-05-23 22:43:5975 if (current_case_)
76 return current_case_->GetTestObject();
77
[email protected]7f801d82011-07-08 23:30:1178 return pp::VarPrivate();
[email protected]1758e882010-11-01 16:16:5079}
[email protected]7f801d82011-07-08 23:30:1180#endif
[email protected]1758e882010-11-01 16:16:5081
[email protected]9888f132011-03-23 21:07:1582void TestingInstance::HandleMessage(const pp::Var& message_data) {
[email protected]dafab752011-09-20 20:08:4083 if (current_case_)
84 current_case_->HandleMessage(message_data);
[email protected]9888f132011-03-23 21:07:1585}
86
[email protected]09c37ba2012-01-05 18:00:3387void TestingInstance::DidChangeView(const pp::View& view) {
[email protected]1758e882010-11-01 16:16:5088 if (!executed_tests_) {
89 executed_tests_ = true;
90 pp::Module::Get()->core()->CallOnMainThread(
91 0,
92 callback_factory_.NewCallback(&TestingInstance::ExecuteTests));
93 }
[email protected]dafab752011-09-20 20:08:4094 if (current_case_)
[email protected]09c37ba2012-01-05 18:00:3395 current_case_->DidChangeView(view);
[email protected]1758e882010-11-01 16:16:5096}
97
[email protected]f949c9c2011-09-23 22:04:0998bool TestingInstance::HandleInputEvent(const pp::InputEvent& event) {
99 if (current_case_)
100 return current_case_->HandleInputEvent(event);
101 return false;
102}
103
[email protected]08610102011-12-17 14:24:30104void TestingInstance::EvalScript(const std::string& script) {
105 std::string message("TESTING_MESSAGE:EvalScript:");
106 message.append(script);
107 PostMessage(pp::Var(message));
108}
109
[email protected]09c37ba2012-01-05 18:00:33110void TestingInstance::SetCookie(const std::string& name,
111 const std::string& value) {
112 std::string message("TESTING_MESSAGE:SetCookie:");
113 message.append(name);
114 message.append("=");
115 message.append(value);
116 PostMessage(pp::Var(message));
117}
118
[email protected]1758e882010-11-01 16:16:50119void TestingInstance::LogTest(const std::string& test_name,
[email protected]9888f132011-03-23 21:07:15120 const std::string& error_message) {
[email protected]b46661f2011-08-25 01:42:53121 // Tell the browser we're still working.
122 ReportProgress(kProgressSignal);
123
[email protected]1758e882010-11-01 16:16:50124 std::string html;
125 html.append("<div class=\"test_line\"><span class=\"test_name\">");
126 html.append(test_name);
127 html.append("</span> ");
128 if (error_message.empty()) {
129 html.append("<span class=\"pass\">PASS</span>");
130 } else {
131 html.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
132 html.append(error_message);
133 html.append("</span>");
134
135 if (!errors_.empty())
136 errors_.append(", "); // Separator for different error messages.
137 errors_.append(test_name + " FAIL: " + error_message);
138 }
139 html.append("</div>");
140 LogHTML(html);
141}
142
143void TestingInstance::AppendError(const std::string& message) {
144 if (!errors_.empty())
145 errors_.append(", ");
146 errors_.append(message);
147}
148
149void TestingInstance::ExecuteTests(int32_t unused) {
[email protected]b46661f2011-08-25 01:42:53150 ReportProgress(kProgressSignal);
[email protected]49c09c15d2010-12-10 02:46:03151
[email protected]1758e882010-11-01 16:16:50152 // Clear the console.
[email protected]7f801d82011-07-08 23:30:11153 PostMessage(pp::Var("TESTING_MESSAGE:ClearConsole"));
[email protected]1758e882010-11-01 16:16:50154
155 if (!errors_.empty()) {
156 // Catch initialization errors and output the current error string to
157 // the console.
158 LogError("Plugin initialization failed: " + errors_);
159 } else if (!current_case_) {
160 LogAvailableTests();
[email protected]ebc5c8be2011-05-20 22:52:59161 errors_.append("FAIL: Only listed tests");
[email protected]1758e882010-11-01 16:16:50162 } else {
[email protected]2622d6b2011-11-16 04:28:02163 current_case_->RunTests(test_filter_);
[email protected]88bfb432011-05-23 22:43:59164 // Automated PyAuto tests rely on finding the exact strings below.
165 LogHTML(errors_.empty() ?
166 "<span class=\"pass\">[SHUTDOWN]</span> All tests passed." :
167 "<span class=\"fail\">[SHUTDOWN]</span> Some tests failed.");
[email protected]1758e882010-11-01 16:16:50168 }
169
170 // Declare we're done by setting a cookie to either "PASS" or the errors.
[email protected]b46661f2011-08-25 01:42:53171 ReportProgress(errors_.empty() ? "PASS" : errors_);
[email protected]7f801d82011-07-08 23:30:11172 PostMessage(pp::Var("TESTING_MESSAGE:DidExecuteTests"));
[email protected]1758e882010-11-01 16:16:50173}
174
[email protected]2622d6b2011-11-16 04:28:02175TestCase* TestingInstance::CaseForTestName(const std::string& name) {
176 std::string case_name = name.substr(0, name.find_first_of('_'));
[email protected]1758e882010-11-01 16:16:50177 TestCaseFactory* iter = TestCaseFactory::head_;
178 while (iter != NULL) {
[email protected]2622d6b2011-11-16 04:28:02179 if (case_name == iter->name_)
[email protected]1758e882010-11-01 16:16:50180 return iter->method_(this);
181 iter = iter->next_;
182 }
183 return NULL;
184}
185
[email protected]2622d6b2011-11-16 04:28:02186std::string TestingInstance::FilterForTestName(const std::string& name) {
187 size_t delim = name.find_first_of('_');
188 if (delim != std::string::npos)
189 return name.substr(delim+1);
190 return "";
191}
192
[email protected]1758e882010-11-01 16:16:50193void TestingInstance::LogAvailableTests() {
194 // Print out a listing of all tests.
195 std::vector<std::string> test_cases;
196 TestCaseFactory* iter = TestCaseFactory::head_;
197 while (iter != NULL) {
198 test_cases.push_back(iter->name_);
199 iter = iter->next_;
200 }
201 std::sort(test_cases.begin(), test_cases.end());
202
203 std::string html;
204 html.append("Available test cases: <dl>");
205 for (size_t i = 0; i < test_cases.size(); ++i) {
[email protected]52d2c8e02010-11-16 20:59:23206 html.append("<dd><a href='?testcase=");
[email protected]1758e882010-11-01 16:16:50207 html.append(test_cases[i]);
[email protected]52d2c8e02010-11-16 20:59:23208 if (nacl_mode_)
209 html.append("&mode=nacl");
[email protected]1758e882010-11-01 16:16:50210 html.append("'>");
211 html.append(test_cases[i]);
212 html.append("</a></dd>");
213 }
214 html.append("</dl>");
215 html.append("<button onclick='RunAll()'>Run All Tests</button>");
[email protected]7f801d82011-07-08 23:30:11216
[email protected]1758e882010-11-01 16:16:50217 LogHTML(html);
218}
219
220void TestingInstance::LogError(const std::string& text) {
221 std::string html;
222 html.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
223 html.append(text);
224 html.append("</span>");
225 LogHTML(html);
226}
227
228void TestingInstance::LogHTML(const std::string& html) {
[email protected]7f801d82011-07-08 23:30:11229 std::string message("TESTING_MESSAGE:LogHTML:");
230 message.append(html);
231 PostMessage(pp::Var(message));
[email protected]1758e882010-11-01 16:16:50232}
233
[email protected]b46661f2011-08-25 01:42:53234void TestingInstance::ReportProgress(const std::string& progress_value) {
235 // Use streams since nacl doesn't compile base yet (for StringPrintf).
236 std::ostringstream cookie_name;
237 cookie_name << "PPAPI_PROGRESS_" << progress_cookie_number_;
238 SetCookie(cookie_name.str(), progress_value);
239 progress_cookie_number_++;
240}
241
[email protected]1758e882010-11-01 16:16:50242class Module : public pp::Module {
243 public:
244 Module() : pp::Module() {}
245 virtual ~Module() {}
246
247 virtual pp::Instance* CreateInstance(PP_Instance instance) {
248 return new TestingInstance(instance);
249 }
250};
251
252namespace pp {
253
254Module* CreateModule() {
255 return new ::Module();
256}
257
258} // namespace pp