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