Skip to content
File

Blob: src/workerd/api/basics-test.c++

3.3 KB
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5// Filter some stuff from the JSG_RESOURCE_TYPE blocks so that we can actually compile this
6// test without pulling in the world.
7#define WORKERD_API_BASICS_TEST 1
8 
9#include "actor-state.h"
10#include "actor.h"
11#include "basics.h"
12#include "util.h"
13 
14#include <workerd/io/promise-wrapper.h>
15#include <workerd/jsg/jsg-test.h>
16#include <workerd/jsg/jsg.h>
17 
18namespace workerd::api {
19namespace {
20 
21jsg::V8System v8System;
22 
23struct BasicsContext: public jsg::Object, public jsg::ContextGlobal {
24 
25 bool testNativeListenersWork(jsg::Lock& js) {
26 auto target = js.alloc<api::EventTarget>();
27 
28 int called = 0;
29 bool onceCalled = false;
30 
31 // Should be invoked multiple times.
32 auto handler = target->newNativeHandler(js, kj::str("foo"),
33 [&called](jsg::Lock& js, jsg::Ref<api::Event> event) { called++; }, false);
34 
35 // Should only be invoked once.
36 auto handlerOnce = target->newNativeHandler(
37 js, kj::str("foo"), [&](jsg::Lock& js, jsg::Ref<api::Event> event) {
38 KJ_ASSERT(!onceCalled);
39 onceCalled = true;
40 // Recursively dispatching the event here should not cause this handler to
41 // be invoked again.
42 target->dispatchEventImpl(js, js.alloc<api::Event>(kj::str("foo")));
43 }, true);
44 
45 KJ_ASSERT(target->dispatchEventImpl(js, js.alloc<api::Event>(kj::str("foo"))));
46 KJ_ASSERT(target->dispatchEventImpl(js, js.alloc<api::Event>(kj::str("foo"))));
47 KJ_ASSERT(onceCalled);
48 return called == 3;
49 }
50 
51 bool testCanAddHandlersInHandlers(jsg::Lock& js) {
52 // Exercises a use case that triggered asan failures in earlier implementations.
53 auto target = js.alloc<api::EventTarget>();
54 int toplevelCalls = 0;
55 int otherCalls = 0;
56 kj::Vector<kj::Own<void>> handlers;
57 
58 handlers.add(target->newNativeHandler(
59 js, kj::str("foo"), [&](jsg::Lock& js, jsg::Ref<api::Event> event) {
60 toplevelCalls++;
61 
62 for (int i = 0; i < 16; ++i) {
63 handlers.add(target->newNativeHandler(js, kj::str("foo", i),
64 [&](jsg::Lock& js, jsg::Ref<api::Event> event) { otherCalls++; }, false));
65 }
66 }, false));
67 
68 handlers.add(target->newNativeHandler(js, kj::str("foo"),
69 [&](jsg::Lock& js, jsg::Ref<api::Event> event) { toplevelCalls++; }, false));
70 
71 KJ_ASSERT(target->dispatchEventImpl(js, js.alloc<api::Event>(kj::str("foo"))));
72 
73 KJ_ASSERT(toplevelCalls == 2);
74 KJ_ASSERT(otherCalls == 0);
75 return true;
76 }
77 
78 JSG_RESOURCE_TYPE(BasicsContext) {
79 JSG_METHOD(testNativeListenersWork);
80 JSG_METHOD(testCanAddHandlersInHandlers);
81 }
82};
83JSG_DECLARE_ISOLATE_TYPE(BasicsIsolate,
84 BasicsContext,
85 EW_BASICS_ISOLATE_TYPES,
86 jsg::TypeWrapperExtension<PromiseWrapper>);
87 
88KJ_TEST("EventTarget native listeners work") {
89 jsg::test::Evaluator<BasicsContext, BasicsIsolate, CompatibilityFlags::Reader> e(v8System);
90 e.expectEval("testNativeListenersWork()", "boolean", "true");
91}
92 
93KJ_TEST("EventTarget can add handlers in handlers") {
94 jsg::test::Evaluator<BasicsContext, BasicsIsolate, CompatibilityFlags::Reader> e(v8System);
95 e.expectEval("testCanAddHandlersInHandlers()", "boolean", "true");
96}
97 
98} // namespace
99} // namespace workerd::api