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"
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
25 TestingInstance::TestingInstance(PP_Instance instance
)
26 #if (defined __native_client__)
27 : pp::Instance(instance
),
29 : pp::InstancePrivate(instance
),
32 executed_tests_(false),
33 number_tests_executed_(0),
37 remove_plugin_(true) {
38 callback_factory_
.Initialize(this);
41 TestingInstance::~TestingInstance() {
46 bool TestingInstance::Init(uint32_t argc
,
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)
53 } else if (std::strcmp(argn
[i
], "protocol") == 0) {
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')
66 current_case_
= CaseForTestName(argv
[i
]);
67 test_filter_
= FilterForTestName(argv
[i
]);
69 errors_
.append(std::string("Unknown test case ") + argv
[i
]);
70 else if (!current_case_
->Init())
71 errors_
.append(" Test case could not initialize.");
76 // In DidChangeView, we'll dump out a list of all available tests.
80 #if !(defined __native_client__)
81 pp::Var
TestingInstance::GetInstanceObject() {
83 return current_case_
->GetTestObject();
85 return pp::VarPrivate();
89 void TestingInstance::HandleMessage(const pp::Var
& message_data
) {
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
));
102 current_case_
->DidChangeView(view
);
105 bool TestingInstance::HandleInputEvent(const pp::InputEvent
& event
) {
107 return current_case_
->HandleInputEvent(event
);
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_
++;
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>");
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>");
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
161 LogError("Plugin initialization failed: " + errors_
);
162 } else if (!current_case_
) {
164 errors_
.append("FAIL: Only listed tests");
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_
+ "'.");
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_
);
184 SendTestCommand("DidExecuteTests");
185 // Note, DidExecuteTests unloads the plugin. We can't really do anthing after
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);
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);
207 void TestingInstance::SendTestCommand(const std::string
& command
) {
208 std::string
msg("TESTING_MESSAGE:");
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_
);
227 std::sort(test_cases
.begin(), test_cases
.end());
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
]);
235 html
.append("&mode=nacl");
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>");
246 void TestingInstance::LogError(const std::string
& text
) {
248 html
.append("<span class=\"fail\">FAIL</span>: <span class=\"err_msg\">");
250 html
.append("</span>");
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
{
272 Module() : pp::Module() {}
275 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
276 return new TestingInstance(instance
);
282 Module
* CreateModule() {
283 return new ::Module();