Skip to content

Commit 3abfed7

Browse files
bartlomiejuclaude
andcommitted
test(core): add tests for cloneable resource registry
Tests cover: - structuredClone with a cloneable object - serialize/deserialize round-trip with cloneable object - cloneable object nested inside a plain object - duplicate registration throws Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b3c6f5e commit 3abfed7

File tree

1 file changed

+107
-1
lines changed

1 file changed

+107
-1
lines changed

libs/core_testing/unit/serialize_deserialize_test.ts

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// Copyright 2018-2026 the Deno authors. MIT license.
2-
import { assertArrayEquals, assertEquals, test } from "checkin:testing";
2+
import {
3+
assert,
4+
assertArrayEquals,
5+
assertEquals,
6+
assertThrows,
7+
test,
8+
} from "checkin:testing";
39

410
test(function testIssue20727() {
511
// https://github.com/denoland/deno/issues/20727
@@ -109,3 +115,103 @@ test(function structuredClone() {
109115
assertEquals(cloned.test2, circularObject.test2);
110116
assertEquals(cloned.test3, circularObject.test3);
111117
});
118+
119+
test(function cloneableResourceStructuredClone() {
120+
// Create a class that supports structured cloning via hostObjectBrand
121+
class MyCloneable {
122+
value: string;
123+
constructor(value: string) {
124+
this.value = value;
125+
// deno-lint-ignore no-this-alias
126+
const self = this;
127+
this[Deno.core.hostObjectBrand] = () => ({
128+
type: "MyCloneable",
129+
value: self.value,
130+
});
131+
}
132+
}
133+
134+
Deno.core.registerCloneableResource(
135+
"MyCloneable",
136+
(data: { value: string }) => new MyCloneable(data.value),
137+
);
138+
139+
const original = new MyCloneable("hello");
140+
const cloned = Deno.core.structuredClone(original);
141+
142+
assert(cloned instanceof MyCloneable);
143+
assertEquals(cloned.value, "hello");
144+
assert(cloned !== original);
145+
});
146+
147+
test(function cloneableResourceSerializeDeserialize() {
148+
// Use a different name to avoid duplicate registration
149+
class AnotherCloneable {
150+
data: number;
151+
constructor(data: number) {
152+
this.data = data;
153+
// deno-lint-ignore no-this-alias
154+
const self = this;
155+
this[Deno.core.hostObjectBrand] = () => ({
156+
type: "AnotherCloneable",
157+
data: self.data,
158+
});
159+
}
160+
}
161+
162+
Deno.core.registerCloneableResource(
163+
"AnotherCloneable",
164+
(d: { data: number }) => new AnotherCloneable(d.data),
165+
);
166+
167+
const original = new AnotherCloneable(42);
168+
const serialized = Deno.core.serialize(original);
169+
const deserialized = Deno.core.deserialize(serialized, {
170+
deserializers: Deno.core.getCloneableDeserializers(),
171+
});
172+
173+
assert(deserialized instanceof AnotherCloneable);
174+
assertEquals(deserialized.data, 42);
175+
});
176+
177+
test(function cloneableResourceNestedInObject() {
178+
class NestedCloneable {
179+
name: string;
180+
constructor(name: string) {
181+
this.name = name;
182+
// deno-lint-ignore no-this-alias
183+
const self = this;
184+
this[Deno.core.hostObjectBrand] = () => ({
185+
type: "NestedCloneable",
186+
name: self.name,
187+
});
188+
}
189+
}
190+
191+
Deno.core.registerCloneableResource(
192+
"NestedCloneable",
193+
(d: { name: string }) => new NestedCloneable(d.name),
194+
);
195+
196+
const obj = {
197+
foo: "bar",
198+
nested: new NestedCloneable("test"),
199+
num: 123,
200+
};
201+
202+
const cloned = Deno.core.structuredClone(obj);
203+
204+
assertEquals(cloned.foo, "bar");
205+
assertEquals(cloned.num, 123);
206+
assert(cloned.nested instanceof NestedCloneable);
207+
assertEquals(cloned.nested.name, "test");
208+
});
209+
210+
test(function cloneableResourceDuplicateRegistrationThrows() {
211+
Deno.core.registerCloneableResource("DuplicateTest", () => {});
212+
assertThrows(
213+
() => Deno.core.registerCloneableResource("DuplicateTest", () => {}),
214+
Error,
215+
"already registered",
216+
);
217+
});

0 commit comments

Comments
 (0)