Bug 1540028 [wpt PR 16099] - Catch more exceptions in Document-createElement-namespac...
[gecko.git] / widget / tests / TestAppShellSteadyState.cpp
blob058fd22d9682bb4973c6b9d202ed87118215945e
1 /**
2 * Any copyright is dedicated to the Public Domain.
3 * http://creativecommons.org/publicdomain/zero/1.0/
4 */
6 #include "TestHarness.h"
8 #include "nsGlobalWindowOuter.h"
9 #include "nsIAppShell.h"
10 #include "nsIAppShellService.h"
11 #include "mozilla/dom/Document.h"
12 #include "nsIDOMEventListener.h"
13 #include "nsIDOMWindow.h"
14 #include "nsIDOMWindowUtils.h"
15 #include "nsIInterfaceRequestor.h"
16 #include "nsIRunnable.h"
17 #include "nsIURI.h"
18 #include "nsIWebBrowserChrome.h"
19 #include "nsIXULWindow.h"
21 #include "nsAppShellCID.h"
22 #include "nsIInterfaceRequestorUtils.h"
23 #include "nsNetUtil.h"
24 #include "nsThreadUtils.h"
25 #include "mozilla/Attributes.h"
26 #include "mozilla/dom/Event.h"
27 #include "mozilla/dom/EventTarget.h"
29 #ifdef XP_WIN
30 # include <windows.h>
31 #endif
33 using namespace mozilla;
35 typedef void (*TestFunc)(nsIAppShell*);
37 bool gStableStateEventHasRun = false;
39 class ExitAppShellRunnable : public Runnable {
40 nsCOMPtr<nsIAppShell> mAppShell;
42 public:
43 explicit ExitAppShellRunnable(nsIAppShell* aAppShell)
44 : mAppShell(aAppShell) {}
46 NS_IMETHOD
47 Run() override { return mAppShell->Exit(); }
50 class StableStateRunnable : public Runnable {
51 public:
52 NS_IMETHOD
53 Run() override {
54 if (gStableStateEventHasRun) {
55 fail("StableStateRunnable already ran");
57 gStableStateEventHasRun = true;
58 return NS_OK;
62 class CheckStableStateRunnable : public Runnable {
63 bool mShouldHaveRun;
65 public:
66 explicit CheckStableStateRunnable(bool aShouldHaveRun)
67 : mShouldHaveRun(aShouldHaveRun) {}
69 NS_IMETHOD
70 Run() override {
71 if (mShouldHaveRun == gStableStateEventHasRun) {
72 passed("StableStateRunnable state correct (%s)",
73 mShouldHaveRun ? "true" : "false");
74 } else {
75 fail("StableStateRunnable ran at wrong time");
77 return NS_OK;
81 class ScheduleStableStateRunnable : public CheckStableStateRunnable {
82 protected:
83 nsCOMPtr<nsIAppShell> mAppShell;
85 public:
86 explicit ScheduleStableStateRunnable(nsIAppShell* aAppShell)
87 : CheckStableStateRunnable(false), mAppShell(aAppShell) {}
89 NS_IMETHOD
90 Run() override {
91 CheckStableStateRunnable::Run();
93 nsCOMPtr<nsIRunnable> runnable = new StableStateRunnable();
94 nsresult rv = mAppShell->RunBeforeNextEvent(runnable);
95 if (NS_FAILED(rv)) {
96 fail("RunBeforeNextEvent returned failure code %u", rv);
99 return rv;
103 class NextTestRunnable : public Runnable {
104 nsCOMPtr<nsIAppShell> mAppShell;
106 public:
107 explicit NextTestRunnable(nsIAppShell* aAppShell) : mAppShell(aAppShell) {}
109 NS_IMETHOD Run() override;
112 class ScheduleNestedStableStateRunnable : public ScheduleStableStateRunnable {
113 public:
114 explicit ScheduleNestedStableStateRunnable(nsIAppShell* aAppShell)
115 : ScheduleStableStateRunnable(aAppShell) {}
117 NS_IMETHOD
118 Run() override {
119 ScheduleStableStateRunnable::Run();
121 nsCOMPtr<nsIRunnable> runnable = new CheckStableStateRunnable(false);
122 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
123 fail("Failed to dispatch check runnable");
126 if (NS_FAILED(NS_ProcessPendingEvents(nullptr))) {
127 fail("Failed to process all pending events");
130 runnable = new CheckStableStateRunnable(true);
131 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
132 fail("Failed to dispatch check runnable");
135 runnable = new NextTestRunnable(mAppShell);
136 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
137 fail("Failed to dispatch next test runnable");
140 return NS_OK;
144 class EventListener final : public nsIDOMEventListener {
145 nsCOMPtr<nsIAppShell> mAppShell;
147 static nsIDOMWindowUtils* sWindowUtils;
148 static nsIAppShell* sAppShell;
150 ~EventListener() {}
152 public:
153 NS_DECL_ISUPPORTS
155 explicit EventListener(nsIAppShell* aAppShell) : mAppShell(aAppShell) {}
157 NS_IMETHOD
158 HandleEvent(dom::Event* aEvent) override {
159 nsString type;
160 if (NS_FAILED(aEvent->GetType(type))) {
161 fail("Failed to get event type");
162 return NS_ERROR_FAILURE;
165 if (type.EqualsLiteral("load")) {
166 passed("Got load event");
168 nsCOMPtr<dom::Document> document = do_QueryInterface(aEvent->GetTarget());
169 if (!document) {
170 fail("Failed to QI to Document!");
171 return NS_ERROR_FAILURE;
174 nsCOMPtr<nsPIDOMWindowOuter> window = document->GetWindow();
175 if (!window) {
176 fail("Failed to get window from document!");
177 return NS_ERROR_FAILURE;
180 nsCOMPtr<nsIDOMWindowUtils> utils =
181 nsGlobalWindowOuter::Cast(window)->WindowUtils();
183 if (!ScheduleTimer(utils)) {
184 return NS_ERROR_FAILURE;
187 return NS_OK;
190 if (type.EqualsLiteral("keypress")) {
191 passed("Got keypress event");
193 nsCOMPtr<nsIRunnable> runnable = new StableStateRunnable();
194 nsresult rv = mAppShell->RunBeforeNextEvent(runnable);
195 if (NS_FAILED(rv)) {
196 fail("RunBeforeNextEvent returned failure code %u", rv);
197 return NS_ERROR_FAILURE;
200 return NS_OK;
203 fail("Got an unexpected event: %s", NS_ConvertUTF16toUTF8(type).get());
204 return NS_OK;
207 #ifdef XP_WIN
208 static VOID CALLBACK TimerCallback(HWND hwnd, UINT uMsg, UINT idEvent,
209 DWORD dwTime) {
210 if (sWindowUtils) {
211 nsCOMPtr<nsIDOMWindowUtils> utils = dont_AddRef(sWindowUtils);
212 sWindowUtils = nullptr;
214 if (gStableStateEventHasRun) {
215 fail("StableStateRunnable ran at wrong time");
216 } else {
217 passed("StableStateRunnable state correct (false)");
220 int32_t layout = 0x409; // US
221 int32_t keyCode = 0x41; // VK_A
222 NS_NAMED_LITERAL_STRING(a, "a");
224 if (NS_FAILED(
225 utils->SendNativeKeyEvent(layout, keyCode, 0, a, a, nullptr))) {
226 fail("Failed to synthesize native event");
229 return;
232 KillTimer(nullptr, idEvent);
234 nsCOMPtr<nsIAppShell> appShell = dont_AddRef(sAppShell);
236 if (!gStableStateEventHasRun) {
237 fail("StableStateRunnable didn't run yet");
238 } else {
239 passed("StableStateRunnable state correct (true)");
242 nsCOMPtr<nsIRunnable> runnable = new NextTestRunnable(appShell);
243 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
244 fail("Failed to dispatch next test runnable");
247 #endif
249 bool ScheduleTimer(nsIDOMWindowUtils* aWindowUtils) {
250 #ifdef XP_WIN
251 UINT_PTR timerId = SetTimer(nullptr, 0, 1000, (TIMERPROC)TimerCallback);
252 if (!timerId) {
253 fail("SetTimer failed!");
254 return false;
257 nsCOMPtr<nsIDOMWindowUtils> utils = aWindowUtils;
258 utils.forget(&sWindowUtils);
260 nsCOMPtr<nsIAppShell> appShell = mAppShell;
261 appShell.forget(&sAppShell);
263 return true;
264 #else
265 return false;
266 #endif
270 nsIDOMWindowUtils* EventListener::sWindowUtils = nullptr;
271 nsIAppShell* EventListener::sAppShell = nullptr;
273 NS_IMPL_ISUPPORTS(EventListener, nsIDOMEventListener)
275 already_AddRefed<nsIAppShell> GetAppShell() {
276 static const char* platforms[] = {"android", "mac", "gtk", "qt", "win"};
278 NS_NAMED_LITERAL_CSTRING(contractPrefix, "@mozilla.org/widget/appshell/");
279 NS_NAMED_LITERAL_CSTRING(contractSuffix, ";1");
281 for (size_t index = 0; index < ArrayLength(platforms); index++) {
282 nsAutoCString contractID(contractPrefix);
283 contractID.AppendASCII(platforms[index]);
284 contractID.Append(contractSuffix);
286 nsCOMPtr<nsIAppShell> appShell = do_GetService(contractID.get());
287 if (appShell) {
288 return appShell.forget();
292 return nullptr;
295 void Test1(nsIAppShell* aAppShell) {
296 // Schedule stable state runnable to be run before next event.
298 nsCOMPtr<nsIRunnable> runnable = new StableStateRunnable();
299 if (NS_FAILED(aAppShell->RunBeforeNextEvent(runnable))) {
300 fail("RunBeforeNextEvent failed");
303 runnable = new CheckStableStateRunnable(true);
304 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
305 fail("Failed to dispatch check runnable");
308 runnable = new NextTestRunnable(aAppShell);
309 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
310 fail("Failed to dispatch next test runnable");
314 void Test2(nsIAppShell* aAppShell) {
315 // Schedule stable state runnable to be run before next event from another
316 // runnable.
318 nsCOMPtr<nsIRunnable> runnable = new ScheduleStableStateRunnable(aAppShell);
319 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
320 fail("Failed to dispatch schedule runnable");
323 runnable = new CheckStableStateRunnable(true);
324 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
325 fail("Failed to dispatch check runnable");
328 runnable = new NextTestRunnable(aAppShell);
329 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
330 fail("Failed to dispatch next test runnable");
334 void Test3(nsIAppShell* aAppShell) {
335 // Schedule steadystate runnable to be run before next event with nested loop.
337 nsCOMPtr<nsIRunnable> runnable =
338 new ScheduleNestedStableStateRunnable(aAppShell);
339 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
340 fail("Failed to dispatch schedule runnable");
344 bool Test4Internal(nsIAppShell* aAppShell) {
345 #ifndef XP_WIN
346 // Not sure how to test on other platforms.
347 return false;
348 #else
349 nsCOMPtr<nsIAppShellService> appService =
350 do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
351 if (!appService) {
352 fail("Failed to get appshell service!");
353 return false;
356 nsCOMPtr<nsIURI> uri;
357 if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), "about:", nullptr))) {
358 fail("Failed to create new uri");
359 return false;
362 uint32_t flags = nsIWebBrowserChrome::CHROME_DEFAULT;
364 nsCOMPtr<nsIXULWindow> xulWindow;
365 if (NS_FAILED(appService->CreateTopLevelWindow(
366 nullptr, uri, flags, 100, 100, nullptr, getter_AddRefs(xulWindow)))) {
367 fail("Failed to create new window");
368 return false;
371 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(xulWindow);
372 if (!window) {
373 fail("Can't get dom window!");
374 return false;
377 RefPTr<dom::EventTarget> target = do_QueryInterface(window);
378 if (!target) {
379 fail("Can't QI to EventTarget!");
380 return false;
383 nsCOMPtr<nsIDOMEventListener> listener = new EventListener(aAppShell);
384 if (NS_FAILED(target->AddEventListener(NS_LITERAL_STRING("keypress"),
385 listener, false, false)) ||
386 NS_FAILED(target->AddEventListener(NS_LITERAL_STRING("load"), listener,
387 false, false))) {
388 fail("Can't add event listeners!");
389 return false;
392 return true;
393 #endif
396 void Test4(nsIAppShell* aAppShell) {
397 if (!Test4Internal(aAppShell)) {
398 nsCOMPtr<nsIRunnable> runnable = new NextTestRunnable(aAppShell);
399 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
400 fail("Failed to dispatch next test runnable");
405 const TestFunc gTests[] = {Test1, Test2, Test3, Test4};
407 size_t gTestIndex = 0;
409 NS_IMETHODIMP
410 NextTestRunnable::Run() {
411 if (gTestIndex > 0) {
412 passed("Finished test %u", gTestIndex);
415 gStableStateEventHasRun = false;
417 if (gTestIndex < ArrayLength(gTests)) {
418 gTests[gTestIndex++](mAppShell);
419 } else {
420 nsCOMPtr<nsIRunnable> exitRunnable = new ExitAppShellRunnable(mAppShell);
422 nsresult rv = NS_DispatchToCurrentThread(exitRunnable);
423 if (NS_FAILED(rv)) {
424 fail("Failed to dispatch exit runnable!");
428 return NS_OK;
431 int main(int argc, char** argv) {
432 ScopedLogging log;
433 ScopedXPCOM xpcom("TestAppShellSteadyState");
435 if (!xpcom.failed()) {
436 nsCOMPtr<nsIAppShell> appShell = GetAppShell();
437 if (!appShell) {
438 fail("Couldn't get appshell!");
439 } else {
440 nsCOMPtr<nsIRunnable> runnable = new NextTestRunnable(appShell);
441 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
442 fail("Failed to dispatch next test runnable");
443 } else if (NS_FAILED(appShell->Run())) {
444 fail("Failed to run appshell");
449 return gFailCount != 0;