Skip to content
File

Blob: src/workerd/jsg/rtti-test.c++

19.7 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#include <workerd/jsg/jsg.h>
6#include <workerd/jsg/rtti-test.capnp.h>
7#include <workerd/jsg/rtti.h>
8#include <workerd/jsg/type-wrapper.h>
9 
10#include <capnp/message.h>
11#include <capnp/serialize-text.h>
12#include <kj/test.h>
13 
14struct MockConfig {};
15 
16namespace workerd::jsg::rtti {
17namespace {
18 
19template <typename T>
20kj::String tType() {
21 // returns textual encoding of rtti.
22 Builder<MockConfig> builder((MockConfig()));
23 auto type = builder.type<T>();
24 capnp::TextCodec codec;
25 return codec.encode(type);
26}
27 
28template <typename T>
29kj::String tStructure() {
30 // returns textual encoding of structure.
31 Builder<MockConfig> builder((MockConfig()));
32 auto type = builder.structure<T>();
33 capnp::TextCodec codec;
34 return codec.encode(type);
35}
36 
37KJ_TEST("jsg::Js* types") {
38 KJ_EXPECT(tType<JsValue>() == "(unknown = void)");
39 KJ_EXPECT(tType<JsObject>() == "(object = void)");
40 KJ_EXPECT(tType<JsBoolean>() == "(boolt = void)");
41 KJ_EXPECT(tType<JsArray>() == "(array = (element = (unknown = void), name = \"jsg::JsArray\"))");
42 KJ_EXPECT(tType<JsString>() == "(string = (name = \"jsg::JsString\"))");
43 KJ_EXPECT(tType<JsBigInt>() == "(number = (name = \"jsg::JsBigInt\"))");
44 KJ_EXPECT(tType<JsNumber>() == "(number = (name = \"jsg::JsNumber\"))");
45 KJ_EXPECT(tType<JsInt32>() == "(number = (name = \"jsg::JsInt32\"))");
46 KJ_EXPECT(tType<JsUint32>() == "(number = (name = \"jsg::JsUint32\"))");
47 KJ_EXPECT(tType<JsDate>() == "(builtin = (type = kjDate))");
48 KJ_EXPECT(tType<JsRegExp>() == "(unknown = void)");
49 KJ_EXPECT(tType<JsMap>() == "(unknown = void)");
50 KJ_EXPECT(tType<JsSet>() == "(unknown = void)");
51 KJ_EXPECT(tType<JsSymbol>() == "(unknown = void)");
52 
53 KJ_EXPECT(tType<JsRef<JsValue>>() == "(unknown = void)");
54 KJ_EXPECT(tType<JsRef<JsObject>>() == "(object = void)");
55 KJ_EXPECT(tType<JsRef<JsBoolean>>() == "(boolt = void)");
56 KJ_EXPECT(
57 tType<JsRef<JsArray>>() == "(array = (element = (unknown = void), name = \"jsg::JsArray\"))");
58 KJ_EXPECT(tType<JsRef<JsString>>() == "(string = (name = \"jsg::JsString\"))");
59 KJ_EXPECT(tType<JsRef<JsBigInt>>() == "(number = (name = \"jsg::JsBigInt\"))");
60 KJ_EXPECT(tType<JsRef<JsNumber>>() == "(number = (name = \"jsg::JsNumber\"))");
61 KJ_EXPECT(tType<JsRef<JsInt32>>() == "(number = (name = \"jsg::JsInt32\"))");
62 KJ_EXPECT(tType<JsRef<JsUint32>>() == "(number = (name = \"jsg::JsUint32\"))");
63 KJ_EXPECT(tType<JsRef<JsDate>>() == "(builtin = (type = kjDate))");
64 KJ_EXPECT(tType<JsRef<JsRegExp>>() == "(unknown = void)");
65 KJ_EXPECT(tType<JsRef<JsMap>>() == "(unknown = void)");
66 KJ_EXPECT(tType<JsRef<JsSet>>() == "(unknown = void)");
67 KJ_EXPECT(tType<JsRef<JsSymbol>>() == "(unknown = void)");
68}
69 
70KJ_TEST("primitive types") {
71 KJ_EXPECT(tType<void>() == "(voidt = void)");
72 KJ_EXPECT(tType<bool>() == "(boolt = void)");
73 KJ_EXPECT(tType<v8::Value>() == "(unknown = void)");
74}
75 
76KJ_TEST("number types") {
77 KJ_EXPECT(tType<char>() == "(number = (name = \"char\"))");
78 KJ_EXPECT(tType<signed char>() == "(number = (name = \"signed char\"))");
79 KJ_EXPECT(tType<unsigned char>() == "(number = (name = \"unsigned char\"))");
80 KJ_EXPECT(tType<short>() == "(number = (name = \"short\"))");
81 KJ_EXPECT(tType<unsigned short>() == "(number = (name = \"unsigned short\"))");
82 KJ_EXPECT(tType<int>() == "(number = (name = \"int\"))");
83 KJ_EXPECT(tType<unsigned int>() == "(number = (name = \"unsigned int\"))");
84 KJ_EXPECT(tType<long>() == "(number = (name = \"long\"))");
85 KJ_EXPECT(tType<unsigned long>() == "(number = (name = \"unsigned long\"))");
86 
87 KJ_EXPECT(tType<double>() == "(number = (name = \"double\"))");
88}
89 
90KJ_TEST("string types") {
91 KJ_EXPECT(tType<kj::String>() == "(string = (name = \"kj::String\"))");
92 KJ_EXPECT(tType<kj::StringPtr>() == "(string = (name = \"kj::StringPtr\"))");
93 KJ_EXPECT(tType<v8::String>() == "(string = (name = \"v8::String\"))");
94 KJ_EXPECT(tType<USVString>() == "(string = (name = \"USVString\"))");
95}
96 
97KJ_TEST("object types") {
98 KJ_EXPECT(tType<v8::Object>() == "(object = void)");
99 KJ_EXPECT(tType<jsg::Object>() == "(object = void)");
100}
101 
102KJ_TEST("promises") {
103 KJ_EXPECT(tType<kj::Promise<void>>() == "(promise = (value = (voidt = void)))");
104 KJ_EXPECT(tType<kj::Promise<int>>() == "(promise = (value = (number = (name = \"int\"))))");
105 KJ_EXPECT(tType<jsg::Promise<int>>() == "(promise = (value = (number = (name = \"int\"))))");
106 KJ_EXPECT(tType<v8::Promise>() == "(promise = (value = (unknown = void)))");
107}
108 
109KJ_TEST("generic types") {
110 KJ_EXPECT(tType<Ref<v8::Object>>() == "(object = void)");
111 KJ_EXPECT(tType<V8Ref<v8::Object>>() == "(object = void)");
112 KJ_EXPECT(tType<HashableV8Ref<v8::Object>>() == "(object = void)");
113 KJ_EXPECT(tType<v8::Local<v8::Object>>() == "(object = void)");
114 KJ_EXPECT(tType<jsg::Identified<v8::Object>>() == "(object = void)");
115 KJ_EXPECT(tType<jsg::MemoizedIdentity<v8::Object>>() == "(object = void)");
116 KJ_EXPECT(tType<jsg::NonCoercible<kj::String>>() == "(string = (name = \"kj::String\"))");
117 
118 KJ_EXPECT(tType<kj::Array<int>>() ==
119 "(array = (element = (number = (name = \"int\")), name = \"kj::Array\"))");
120 KJ_EXPECT(tType<kj::ArrayPtr<int>>() ==
121 "(array = (element = (number = (name = \"int\")), name = \"kj::ArrayPtr\"))");
122 KJ_EXPECT(tType<jsg::Sequence<int>>() ==
123 "(array = (element = (number = (name = \"int\")), name = \"jsg::Sequence\"))");
124 
125 KJ_EXPECT(tType<kj::Maybe<int>>() ==
126 "(maybe = (value = (number = (name = \"int\")), name = \"kj::Maybe\"))");
127 KJ_EXPECT(tType<jsg::Optional<int>>() ==
128 "(maybe = (value = (number = (name = \"int\")), name = \"jsg::Optional\"))");
129 KJ_EXPECT(tType<jsg::LenientOptional<int>>() ==
130 "(maybe = (value = (number = (name = \"int\")), name = \"jsg::LenientOptional\"))");
131 
132 KJ_EXPECT(tType<jsg::Dict<int>>() ==
133 "(dict = (key = (string = (name = \"kj::String\")), value = (number = (name = \"int\"))))");
134 KJ_EXPECT((tType<jsg::Dict<int, double>>()) ==
135 "(dict = (key = (number = (name = \"double\")), value = (number = (name = \"int\"))))");
136 
137 KJ_EXPECT((tType<kj::OneOf<int, double>>()) ==
138 "(oneOf = (variants = ["
139 "(number = (name = \"int\")), "
140 "(number = (name = \"double\"))]))");
141 KJ_EXPECT((tType<kj::OneOf<int, double, kj::String>>()) ==
142 "(oneOf = (variants = ["
143 "(number = (name = \"int\")), "
144 "(number = (name = \"double\")), "
145 "(string = (name = \"kj::String\"))]))");
146}
147 
148KJ_TEST("builtins") {
149 KJ_EXPECT(tType<jsg::BufferSource>() == "(builtin = (type = jsgBufferSource))");
150 KJ_EXPECT(tType<v8::Uint8Array>() == "(builtin = (type = v8Uint8Array))");
151 KJ_EXPECT(tType<v8::ArrayBufferView>() == "(builtin = (type = v8ArrayBufferView))");
152 KJ_EXPECT(tType<v8::Function>() == "(builtin = (type = v8Function))");
153 KJ_EXPECT(tType<kj::Date>() == "(builtin = (type = kjDate))");
154}
155 
156KJ_TEST("jsgImpl") {
157 KJ_EXPECT(tType<jsg::Lock>() == "(jsgImpl = (type = jsgLock))");
158 KJ_EXPECT(tType<jsg::SelfRef>() == "(jsgImpl = (type = jsgSelfRef))");
159 KJ_EXPECT(tType<jsg::Unimplemented>() == "(jsgImpl = (type = jsgUnimplemented))");
160 KJ_EXPECT(tType<v8::Isolate*>() == "(jsgImpl = (type = v8Isolate))");
161 KJ_EXPECT(tType<MockConfig>() == "(jsgImpl = (type = configuration))");
162 KJ_EXPECT(tType<jsg::TypeHandler<kj::Date>>() == "(jsgImpl = (type = jsgTypeHandler))");
163 KJ_EXPECT(tType<v8::FunctionCallbackInfo<v8::Value>>() ==
164 "(jsgImpl = (type = v8FunctionCallbackInfo))");
165 KJ_EXPECT(tType<v8::PropertyCallbackInfo<v8::Value>>() ==
166 "(jsgImpl = (type = v8PropertyCallbackInfo))");
167}
168 
169KJ_TEST("functions") {
170 KJ_EXPECT(tType<jsg::Function<int()>>() ==
171 "(function = (returnType = (number = (name = \"int\")), args = []))");
172 KJ_EXPECT(tType<jsg::Function<void(int a, double b)>>() ==
173 "(function = (returnType = (voidt = void), args = [(number = (name = \"int\")), (number = (name = \"double\"))]))");
174}
175 
176KJ_TEST("c++ modifiers") {
177 KJ_EXPECT(tType<const int>() == "(number = (name = \"int\"))");
178 KJ_EXPECT(tType<int&>() == "(number = (name = \"int\"))");
179 KJ_EXPECT(tType<int&&>() == "(number = (name = \"int\"))");
180 KJ_EXPECT(tType<const int&>() == "(number = (name = \"int\"))");
181}
182 
183struct Base: public Object {
184 JSG_RESOURCE_TYPE(Base) {
185 JSG_INHERIT_INTRINSIC(v8::kIteratorPrototype);
186 }
187};
188 
189struct TestResource: public Base {
190 void instanceMethod(int i, double f) {}
191 static int staticMethod() {
192 return 42;
193 }
194 
195 int getSize() {
196 return 1;
197 }
198 void setSize(int size) {}
199 
200 static jsg::Ref<TestResource> constructor(jsg::Optional<kj::String> label);
201 
202 JSG_RESOURCE_TYPE(TestResource) {
203 JSG_INHERIT(Base);
204 
205 JSG_METHOD(instanceMethod);
206 JSG_STATIC_METHOD(staticMethod);
207 JSG_INSTANCE_PROPERTY(size, getSize, setSize);
208 JSG_READONLY_INSTANCE_PROPERTY(readonlySize, getSize);
209 JSG_LAZY_INSTANCE_PROPERTY(lazySize, getSize);
210 JSG_LAZY_READONLY_INSTANCE_PROPERTY(lazyReadonlySize, getSize);
211 JSG_PROTOTYPE_PROPERTY(protoSize, getSize, setSize);
212 JSG_READONLY_PROTOTYPE_PROPERTY(protoReadonlySize, getSize);
213 }
214};
215 
216KJ_TEST("resource reference") {
217 KJ_EXPECT(tType<TestResource>() ==
218 "(structure = (name = \"TestResource\", fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestResource\"))");
219}
220 
221KJ_TEST("resource structure") {
222 KJ_EXPECT(tStructure<Base>() ==
223 "(name = \"Base\", members = [], "
224 "extends = (intrinsic = (name = \"v8::kIteratorPrototype\")), "
225 "iterable = false, asyncIterable = false, "
226 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::Base\", tsRoot = false, "
227 "disposable = false, asyncDisposable = false)");
228 
229 KJ_EXPECT(tStructure<TestResource>() ==
230 "(name = \"TestResource\", members = ["
231 "(method = (name = \"instanceMethod\", returnType = (voidt = void), args = [(number = (name = \"int\")), (number = (name = \"double\"))], static = false, fastApiCompatible = true)), "
232 "(method = (name = \"staticMethod\", returnType = (number = (name = \"int\")), args = [], static = true, fastApiCompatible = true)), "
233 "(property = (name = \"size\", type = (number = (name = \"int\")), readonly = false, lazy = false, prototype = false, getterFastApiCompatible = true, setterFastApiCompatible = true)), "
234 "(property = (name = \"readonlySize\", type = (number = (name = \"int\")), readonly = true, lazy = false, prototype = false, getterFastApiCompatible = true, setterFastApiCompatible = false)), "
235 "(property = (name = \"lazySize\", type = (number = (name = \"int\")), readonly = false, lazy = true, prototype = false, getterFastApiCompatible = false, setterFastApiCompatible = false)), "
236 "(property = (name = \"lazyReadonlySize\", type = (number = (name = \"int\")), readonly = true, lazy = true, prototype = false, getterFastApiCompatible = false, setterFastApiCompatible = false)), "
237 "(property = (name = \"protoSize\", type = (number = (name = \"int\")), readonly = false, lazy = false, prototype = true, getterFastApiCompatible = true, setterFastApiCompatible = true)), "
238 "(property = (name = \"protoReadonlySize\", type = (number = (name = \"int\")), readonly = true, lazy = false, prototype = true, getterFastApiCompatible = false, setterFastApiCompatible = false)), "
239 "(constructor = (args = [(maybe = (value = (string = (name = \"kj::String\")), name = \"jsg::Optional\"))]))], "
240 "extends = (structure = (name = \"Base\", fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::Base\")), "
241 "iterable = false, asyncIterable = false, "
242 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestResource\", tsRoot = false, "
243 "disposable = false, asyncDisposable = false)");
244}
245 
246struct TestNested: jsg::Object {
247 JSG_RESOURCE_TYPE(TestNested) {
248 JSG_NESTED_TYPE(Base);
249 };
250};
251 
252KJ_TEST("nested structure") {
253 KJ_EXPECT(tStructure<TestNested>() ==
254 "(name = \"TestNested\", members = [("
255 "nested = ("
256 "structure = ("
257 "name = \"Base\", members = [], "
258 "extends = (intrinsic = (name = \"v8::kIteratorPrototype\")), "
259 "iterable = false, asyncIterable = false, "
260 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::Base\", "
261 "tsRoot = false, disposable = false, asyncDisposable = false"
262 "), "
263 "name = \"Base\"))"
264 "], "
265 "iterable = false, asyncIterable = false, "
266 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestNested\", tsRoot = false, "
267 "disposable = false, asyncDisposable = false)");
268}
269 
270struct TestConstant: jsg::Object {
271 static constexpr int ENABLED [[maybe_unused]] = 1;
272 
273 enum Type {
274 CIRCLE = 2,
275 };
276 
277 JSG_RESOURCE_TYPE(TestConstant) {
278 JSG_STATIC_CONSTANT(ENABLED);
279 JSG_STATIC_CONSTANT(CIRCLE);
280 };
281};
282 
283KJ_TEST("constant members") {
284 KJ_EXPECT(tStructure<TestConstant>() ==
285 "(name = \"TestConstant\", members = ["
286 "(constant = (name = \"ENABLED\", value = 1)), "
287 "(constant = (name = \"CIRCLE\", value = 2))], "
288 "iterable = false, asyncIterable = false, "
289 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestConstant\", "
290 "tsRoot = false, disposable = false, asyncDisposable = false)");
291}
292 
293struct TestStruct {
294 int a;
295 bool b;
296 JSG_STRUCT(a, b);
297};
298 
299KJ_TEST("struct reference") {
300 KJ_EXPECT(tType<TestStruct>() ==
301 "(structure = (name = \"TestStruct\", fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestStruct\"))");
302}
303 
304KJ_TEST("struct structure") {
305 KJ_EXPECT(tStructure<TestStruct>() ==
306 "(name = \"TestStruct\", members = ["
307 "(property = (name = \"a\", type = (number = (name = \"int\")), readonly = false, lazy = false, prototype = false, getterFastApiCompatible = false, setterFastApiCompatible = false)), "
308 "(property = (name = \"b\", type = (boolt = void), readonly = false, lazy = false, prototype = false, getterFastApiCompatible = false, setterFastApiCompatible = false))], "
309 "iterable = false, asyncIterable = false, "
310 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestStruct\", "
311 "tsRoot = false, disposable = false, asyncDisposable = false)");
312}
313 
314struct TestSymbolTable: public jsg::Object {
315 void acceptResource(const TestResource& resource) {};
316 void recursiveTypeFunction(const TestSymbolTable& table) {}
317 
318 JSG_RESOURCE_TYPE(TestSymbolTable) {
319 JSG_METHOD(acceptResource);
320 JSG_METHOD(recursiveTypeFunction);
321 };
322};
323 
324KJ_TEST("symbol table") {
325 Builder<MockConfig> builder((MockConfig()));
326 auto type = builder.structure<TestSymbolTable>();
327 capnp::TextCodec codec;
328 
329 KJ_EXPECT(codec.encode(type) ==
330 "(name = \"TestSymbolTable\", members = ["
331 "(method = (name = \"acceptResource\", returnType = (voidt = void), args = [(structure = (name = \"TestResource\", fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestResource\"))], static = false, fastApiCompatible = true)), "
332 "(method = (name = \"recursiveTypeFunction\", returnType = (voidt = void), args = [(structure = (name = \"TestSymbolTable\", fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestSymbolTable\"))], static = false, fastApiCompatible = true))], "
333 "iterable = false, asyncIterable = false, "
334 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestSymbolTable\", "
335 "tsRoot = false, disposable = false, asyncDisposable = false)");
336 
337 KJ_EXPECT(builder.structure("workerd::jsg::rtti::(anonymous namespace)::TestSymbolTable"_kj) !=
338 kj::none);
339 KJ_EXPECT(
340 builder.structure("workerd::jsg::rtti::(anonymous namespace)::TestResource"_kj) != kj::none);
341 KJ_EXPECT(KJ_REQUIRE_NONNULL(
342 builder.structure("workerd::jsg::rtti::(anonymous namespace)::TestResource"_kj))
343 .getMembers()
344 .size() > 0);
345}
346 
347struct TestTypeScriptResourceType: public jsg::Object {
348 int getThing() {
349 return 42;
350 }
351 
352 JSG_RESOURCE_TYPE(TestTypeScriptResourceType) {
353 JSG_READONLY_INSTANCE_PROPERTY(thing, getThing);
354 
355 JSG_TS_ROOT();
356 JSG_TS_DEFINE(interface Define {});
357 JSG_TS_OVERRIDE({ readonly thing: 42 });
358 };
359};
360 
361struct TestTypeScriptStruct {
362 int structThing;
363 JSG_STRUCT(structThing);
364 
365 JSG_STRUCT_TS_ROOT();
366 JSG_STRUCT_TS_DEFINE(interface StructDefine {});
367 JSG_STRUCT_TS_OVERRIDE(RenamedStructThing { structThing: 42 });
368};
369 
370struct TestTypeScriptStdioResourceType: public jsg::Object {
371 int getThing() {
372 return 42;
373 }
374 
375 JSG_RESOURCE_TYPE(TestTypeScriptStdioResourceType) {
376 JSG_READONLY_INSTANCE_PROPERTY(thing, getThing);
377 
378 JSG_TS_ROOT();
379 JSG_TS_DEFINE(interface Define { stdin: 0; stdout: 1; stderr: 2 });
380 JSG_TS_OVERRIDE({ stdin: 0; stdout: 1; stderr: 2 });
381 };
382};
383 
384struct TestTypeScriptStdioStruct {
385 int structThing;
386 JSG_STRUCT(structThing);
387 
388 JSG_STRUCT_TS_ROOT();
389 JSG_STRUCT_TS_DEFINE(interface StructDefine { stdin: 0; stdout: 1; stderr: 2 });
390 JSG_STRUCT_TS_OVERRIDE(Renamed { stdin: 0; stdout: 1; stderr: 2 });
391};
392 
393KJ_TEST("typescript macros") {
394 KJ_EXPECT(tStructure<TestTypeScriptResourceType>() ==
395 "(name = \"TestTypeScriptResourceType\", members = ["
396 "(property = (name = \"thing\", type = (number = (name = \"int\")), readonly = true, lazy = false, prototype = false, getterFastApiCompatible = true, setterFastApiCompatible = false))], "
397 "iterable = false, asyncIterable = false, "
398 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestTypeScriptResourceType\", "
399 "tsRoot = true, "
400 "tsOverride = \"{ readonly thing: 42 }\", "
401 "tsDefine = \"interface Define {}\", "
402 "disposable = false, asyncDisposable = false)");
403 KJ_EXPECT(tStructure<TestTypeScriptStruct>() ==
404 "(name = \"TestTypeScriptStruct\", members = ["
405 "(property = (name = \"structThing\", type = (number = (name = \"int\")), readonly = false, lazy = false, prototype = false, getterFastApiCompatible = false, setterFastApiCompatible = false))], "
406 "iterable = false, asyncIterable = false, "
407 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestTypeScriptStruct\", "
408 "tsRoot = true, "
409 "tsOverride = \"RenamedStructThing { structThing: 42 }\", "
410 "tsDefine = \"interface StructDefine {}\", "
411 "disposable = false, asyncDisposable = false)");
412}
413 
414KJ_TEST("typescript macros with stdio identifiers") {
415 // `<stdio.h>` on Darwin defines `stdin`/`stdout`/`stderr` as macros. The TS override and define
416 // macros must capture the user's source verbatim so these tokens are not expanded.
417 KJ_EXPECT(tStructure<TestTypeScriptStdioResourceType>() ==
418 "(name = \"TestTypeScriptStdioResourceType\", members = ["
419 "(property = (name = \"thing\", type = (number = (name = \"int\")), readonly = true, lazy = false, prototype = false, getterFastApiCompatible = true, setterFastApiCompatible = false))], "
420 "iterable = false, asyncIterable = false, "
421 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestTypeScriptStdioResourceType\", "
422 "tsRoot = true, "
423 "tsOverride = \"{ stdin: 0; stdout: 1; stderr: 2 }\", "
424 "tsDefine = \"interface Define { stdin: 0; stdout: 1; stderr: 2 }\", "
425 "disposable = false, asyncDisposable = false)");
426 KJ_EXPECT(tStructure<TestTypeScriptStdioStruct>() ==
427 "(name = \"TestTypeScriptStdioStruct\", members = ["
428 "(property = (name = \"structThing\", type = (number = (name = \"int\")), readonly = false, lazy = false, prototype = false, getterFastApiCompatible = false, setterFastApiCompatible = false))], "
429 "iterable = false, asyncIterable = false, "
430 "fullyQualifiedName = \"workerd::jsg::rtti::(anonymous namespace)::TestTypeScriptStdioStruct\", "
431 "tsRoot = true, "
432 "tsOverride = \"Renamed { stdin: 0; stdout: 1; stderr: 2 }\", "
433 "tsDefine = \"interface StructDefine { stdin: 0; stdout: 1; stderr: 2 }\", "
434 "disposable = false, asyncDisposable = false)");
435}
436 
437} // namespace
438} // namespace workerd::jsg::rtti