]> Lady’s Gitweb - Etiquette/blob - memory.test.js
Apply some reformatting and make Reuse‐compliant
[Etiquette] / memory.test.js
1 // SPDX-FileCopyrightText: 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: MPL-2.0
3 /**
4 * ⁌ 📧🏷️ Étiquette ∷ memory.test.js
5 *
6 * Copyright © 2023, 2025 Lady [@ Ladys Computer].
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
11 */
12
13 import {
14 assert,
15 assertEquals,
16 assertStrictEquals,
17 assertThrows,
18 beforeEach,
19 describe,
20 it,
21 } from "./dev-deps.js";
22 import { Storage } from "./memory.js";
23
24 /** A simple storable class for use in testing. */
25 class Storable {
26 /** Constructs a new instance with the provided data. */
27 constructor(data) {
28 this.data = data;
29 this.id = null;
30 }
31
32 /** Returns a new instance with the provided data and id. */
33 static [Storage.toInstance](data, id) {
34 const result = new Storable(data);
35 result.id = id;
36 return result;
37 }
38
39 /** Returns the data of this instance. */
40 [Storage.toObject]() {
41 return this.data;
42 }
43 }
44
45 describe("Storage", () => {
46 it("[[Call]] throws", () => {
47 assertThrows(() => {
48 Storage();
49 });
50 });
51
52 it("[[Construct]] creates a new Storage", () => {
53 assertStrictEquals(
54 Object.getPrototypeOf(new Storage()),
55 Storage.prototype,
56 );
57 });
58
59 describe(".toInstance", () => {
60 it("[[Get]] returns a symbol", () => {
61 assertStrictEquals(typeof Storage.toInstance, "symbol");
62 });
63
64 it("[[Set]] throws", () => {
65 assertThrows(() => Storage.toInstance = null);
66 });
67 });
68
69 describe(".toObject", () => {
70 it("[[Get]] returns a symbol", () => {
71 assertStrictEquals(typeof Storage.toObject, "symbol");
72 });
73
74 it("[[Set]] throws", () => {
75 assertThrows(() => Storage.toObject = null);
76 });
77 });
78
79 describe("::add", () => {
80 let instance;
81
82 beforeEach(() => {
83 instance = new Storage();
84 });
85
86 it("[[Call]] returns an id", () => {
87 const result = instance.add(new Storable());
88 assertStrictEquals(typeof result, "string");
89 assert(
90 /^[0-9A-Z*~$=][0-9A-TV-Z]{2}-[0-9A-TV-Z]{4}$/u.test(result),
91 );
92 });
93
94 it("[[Call]] stores data for retrieval later", () => {
95 const data = { my: "data" };
96 const storable = new Storable(data);
97 const newID = instance.add(storable);
98 assertEquals(instance.get(newID).data, data);
99 });
100
101 it("[[Call]] does not store non‐enumerable properties", () => {
102 const data = Object.create(null, {
103 gone: { enumerable: false },
104 });
105 const storable = new Storable(data);
106 const newID = instance.add(storable);
107 assert(!("gone" in instance.get(newID).data));
108 });
109
110 it("[[Call]] does not store prototype properties", () => {
111 const data = Object.create({ gone: true });
112 const storable = new Storable(data);
113 const newID = instance.add(storable);
114 assert(!("gone" in instance.get(newID).data));
115 });
116
117 it("[[Call]] throws if the provided value is not an object", () => {
118 assertThrows(() => {
119 instance.add("");
120 });
121 });
122
123 it("[[Call]] throws if the provided value does not implement `[Storage.toObject]`", () => {
124 assertThrows(() => {
125 instance.add(Object.create(null));
126 });
127 });
128 });
129
130 describe("::delete", () => {
131 let instance;
132
133 beforeEach(() => {
134 instance = new Storage();
135 });
136
137 it("[[Call]] returns whether the value was assigned", () => {
138 assertStrictEquals(instance.delete("000-0000"), false);
139 const newID = instance.add(new Storable());
140 assertStrictEquals(instance.delete(newID), true);
141 });
142
143 it("[[Call]] deletes the value", () => {
144 const newID = instance.add(new Storable());
145 instance.delete(newID);
146 assertStrictEquals(instance.get(newID), null);
147 });
148
149 it("[[Call]] throws if the provided identifier is invalid", () => {
150 assertThrows(() => {
151 instance.delete("");
152 });
153 });
154 });
155
156 describe("::has", () => {
157 let instance;
158
159 beforeEach(() => {
160 instance = new Storage();
161 });
162
163 it("[[Call]] returns whether the value was assigned", () => {
164 assertStrictEquals(instance.has("000-0000"), false);
165 instance.set("000-0000", new Storable());
166 assertStrictEquals(instance.has("000-0000"), true);
167 instance.delete("000-0000");
168 assertStrictEquals(instance.has("000-0000"), false);
169 });
170
171 it("[[Call]] throws if the provided identifier is invalid", () => {
172 assertThrows(() => {
173 instance.has("");
174 });
175 });
176 });
177
178 describe("::set", () => {
179 let instance;
180 let newID;
181
182 beforeEach(() => {
183 instance = new Storage();
184 newID = new Storage().add(new Storable());
185 });
186
187 it("[[Call]] returns the instance", () => {
188 const result = instance.set(newID, new Storable());
189 assertStrictEquals(result, instance);
190 });
191
192 it("[[Call]] stores data for retrieval later", () => {
193 const data = { my: "data" };
194 const storable = new Storable(data);
195 instance.set(newID, storable);
196 assertEquals(instance.get(newID).data, data);
197 });
198
199 it("[[Call]] updates existing data", () => {
200 const data = { my: "data" };
201 const storable = new Storable(data);
202 instance.set(newID, storable);
203 data.my = "new data";
204 instance.set(newID, storable);
205 assertEquals(instance.get(newID).data, data);
206 });
207
208 it("[[Call]] does not store non‐enumerable properties", () => {
209 const data = Object.create(null, {
210 gone: { enumerable: false },
211 });
212 const storable = new Storable(data);
213 instance.set(newID, storable);
214 assert(!("gone" in instance.get(newID).data));
215 });
216
217 it("[[Call]] does not store prototype properties", () => {
218 const data = Object.create({ gone: true });
219 const storable = new Storable(data);
220 instance.set(newID, storable);
221 assert(!("gone" in instance.get(newID).data));
222 });
223
224 it("[[Call]] throws if the provided identifier is invalid", () => {
225 assertThrows(() => {
226 instance.set("", new Storable());
227 });
228 });
229
230 it("[[Call]] throws if the provided value is not an object", () => {
231 assertThrows(() => {
232 instance.set(newID, "");
233 });
234 });
235
236 it("[[Call]] throws if the provided value does not implement `[Storage.toObject]`", () => {
237 assertThrows(() => {
238 instance.set(newID, Object.create(null));
239 });
240 });
241 });
242
243 describe("::size", () => {
244 let instance;
245
246 beforeEach(() => {
247 instance = new Storage();
248 });
249
250 it("[[Get]] returns the number of stored values", () => {
251 assertStrictEquals(instance.size, 0);
252 instance.add(new Storable());
253 assertStrictEquals(instance.size, 1);
254 const newID = instance.add(new Storable());
255 assertStrictEquals(instance.size, 2);
256 instance.set(newID, new Storable());
257 assertStrictEquals(instance.size, 2);
258 });
259
260 it("[[Get]] does not count deleted values", () => {
261 assertStrictEquals(instance.size, 0);
262 instance.add(new Storable());
263 assertStrictEquals(instance.size, 1);
264 const newID = instance.add(new Storable());
265 assertStrictEquals(instance.size, 2);
266 instance.delete(newID);
267 assertStrictEquals(instance.size, 1);
268 });
269
270 it("[[Set]] throws when setting", () => {
271 assertThrows(() => {
272 instance.size = 1;
273 });
274 });
275 });
276 });
This page took 0.074583 seconds and 5 git commands to generate.