]> Lady’s Gitweb - Etiquette/blob - memory.test.js
8187635a7cee18320258727de6b027b4674da56b
[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("[[Construct]] creates a new Storage", () => {
44 assertStrictEquals(
45 Object.getPrototypeOf(new Storage()),
46 Storage.prototype,
47 );
48 });
49
50 describe(".toInstance", () => {
51 it("[[Get]] returns a symbol", () => {
52 assertStrictEquals(typeof Storage.toInstance, "symbol");
53 });
54
55 it("[[Set]] throws", () => {
56 assertThrows(() => Storage.toInstance = null);
57 });
58 });
59
60 describe(".toObject", () => {
61 it("[[Get]] returns a symbol", () => {
62 assertStrictEquals(typeof Storage.toObject, "symbol");
63 });
64
65 it("[[Set]] throws", () => {
66 assertThrows(() => Storage.toObject = null);
67 });
68 });
69
70 describe("::add", () => {
71 let instance;
72
73 beforeEach(() => {
74 instance = new Storage();
75 });
76
77 it("[[Call]] returns an id", () => {
78 const result = instance.add(new Storable());
79 assertStrictEquals(typeof result, "string");
80 assert(
81 /^[0-9A-Z*~$=][0-9A-TV-Z]{2}-[0-9A-TV-Z]{4}$/u.test(result),
82 );
83 });
84
85 it("[[Call]] stores data for retrieval later", () => {
86 const data = { my: "data" };
87 const storable = new Storable(data);
88 const newID = instance.add(storable);
89 assertEquals(instance.get(newID).data, data);
90 });
91
92 it("[[Call]] does not store non‐enumerable properties", () => {
93 const data = Object.create(null, {
94 gone: { enumerable: false },
95 });
96 const storable = new Storable(data);
97 const newID = instance.add(storable);
98 assert(!("gone" in instance.get(newID).data));
99 });
100
101 it("[[Call]] does not store prototype properties", () => {
102 const data = Object.create({ gone: true });
103 const storable = new Storable(data);
104 const newID = instance.add(storable);
105 assert(!("gone" in instance.get(newID).data));
106 });
107
108 it("[[Call]] throws if the provided value is not an object", () => {
109 assertThrows(() => {
110 instance.add("");
111 });
112 });
113
114 it("[[Call]] throws if the provided value does not implement `[Storage.toObject]`", () => {
115 assertThrows(() => {
116 instance.add(Object.create(null));
117 });
118 });
119 });
120
121 describe("::delete", () => {
122 let instance;
123
124 beforeEach(() => {
125 instance = new Storage();
126 });
127
128 it("[[Call]] returns whether the value was assigned", () => {
129 assertStrictEquals(instance.delete("000-0000"), false);
130 const newID = instance.add(new Storable());
131 assertStrictEquals(instance.delete(newID), true);
132 });
133
134 it("[[Call]] deletes the value", () => {
135 const newID = instance.add(new Storable());
136 instance.delete(newID);
137 assertStrictEquals(instance.get(newID), null);
138 });
139
140 it("[[Call]] throws if the provided identifier is invalid", () => {
141 assertThrows(() => {
142 instance.delete("");
143 });
144 });
145 });
146
147 describe("::has", () => {
148 let instance;
149
150 beforeEach(() => {
151 instance = new Storage();
152 });
153
154 it("[[Call]] returns whether the value was assigned", () => {
155 assertStrictEquals(instance.has("000-0000"), false);
156 instance.set("000-0000", new Storable());
157 assertStrictEquals(instance.has("000-0000"), true);
158 instance.delete("000-0000")
159 assertStrictEquals(instance.has("000-0000"), false);
160 });
161
162 it("[[Call]] throws if the provided identifier is invalid", () => {
163 assertThrows(() => {
164 instance.has("");
165 });
166 });
167 });
168
169 describe("::set", () => {
170 let instance;
171 let newID;
172
173 beforeEach(() => {
174 instance = new Storage();
175 newID = new Storage().add(new Storable());
176 });
177
178 it("[[Call]] returns the instance", () => {
179 const result = instance.set(newID, new Storable());
180 assertStrictEquals(result, instance);
181 });
182
183 it("[[Call]] stores data for retrieval later", () => {
184 const data = { my: "data" };
185 const storable = new Storable(data);
186 instance.set(newID, storable);
187 assertEquals(instance.get(newID).data, data);
188 });
189
190 it("[[Call]] updates existing data", () => {
191 const data = { my: "data" };
192 const storable = new Storable(data);
193 instance.set(newID, storable);
194 data.my = "new data"
195 instance.set(newID, storable);
196 assertEquals(instance.get(newID).data, data);
197 });
198
199 it("[[Call]] does not store non‐enumerable properties", () => {
200 const data = Object.create(null, {
201 gone: { enumerable: false },
202 });
203 const storable = new Storable(data);
204 instance.set(newID, storable);
205 assert(!("gone" in instance.get(newID).data));
206 });
207
208 it("[[Call]] does not store prototype properties", () => {
209 const data = Object.create({ gone: true });
210 const storable = new Storable(data);
211 instance.set(newID, storable);
212 assert(!("gone" in instance.get(newID).data));
213 });
214
215 it("[[Call]] throws if the provided identifier is invalid", () => {
216 assertThrows(() => {
217 instance.set("", new Storable());
218 });
219 });
220
221 it("[[Call]] throws if the provided value is not an object", () => {
222 assertThrows(() => {
223 instance.set(newID, "");
224 });
225 });
226
227 it("[[Call]] throws if the provided value does not implement `[Storage.toObject]`", () => {
228 assertThrows(() => {
229 instance.set(newID, Object.create(null));
230 });
231 });
232 });
233
234 describe("::size", () => {
235 let instance;
236
237 beforeEach(() => {
238 instance = new Storage();
239 });
240
241 it("[[Get]] returns the number of stored values", () => {
242 assertStrictEquals(instance.size, 0);
243 instance.add(new Storable());
244 assertStrictEquals(instance.size, 1);
245 const newID = instance.add(new Storable());
246 assertStrictEquals(instance.size, 2);
247 instance.set(newID, new Storable());
248 assertStrictEquals(instance.size, 2);
249 });
250
251 it("[[Get]] does not count deleted values", () => {
252 assertStrictEquals(instance.size, 0);
253 instance.add(new Storable());
254 assertStrictEquals(instance.size, 1);
255 const newID = instance.add(new Storable());
256 assertStrictEquals(instance.size, 2);
257 instance.delete(newID);
258 assertStrictEquals(instance.size, 1);
259 });
260
261 it("[[Set]] throws when setting", () => {
262 assertThrows(() => {
263 instance.size = 1;
264 });
265 });
266 });
267 });
This page took 0.116028 seconds and 3 git commands to generate.