]> Lady’s Gitweb - Pisces/blob - iterable.test.js
Add iterator function builders; use in string.js
[Pisces] / iterable.test.js
1 // ♓🌟 Piscēs ∷ iterable.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 assertEquals,
12 assertStrictEquals,
13 assertThrows,
14 describe,
15 it,
16 } from "./dev-deps.js";
17 import {
18 arrayIteratorFunction,
19 generatorIteratorFunction,
20 mapIteratorFunction,
21 setIteratorFunction,
22 stringIteratorFunction,
23 } from "./iterable.js";
24
25 describe("arrayIteratorFunction", () => {
26 it("[[Call]] returns a function", () => {
27 assertStrictEquals(typeof arrayIteratorFunction(), "function");
28 });
29
30 it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
31 assertStrictEquals(
32 Object.getPrototypeOf(arrayIteratorFunction()),
33 Function.prototype,
34 );
35 });
36
37 describe("()", () => {
38 it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
39 const iteratorProto = Object.getPrototypeOf(
40 Object.getPrototypeOf([][Symbol.iterator]),
41 );
42 const iterator = arrayIteratorFunction();
43 assertStrictEquals(
44 iterator([]) instanceof Object.assign(
45 function () {},
46 { prototype: iteratorProto },
47 ),
48 true,
49 );
50 });
51
52 it("[[Call]] returns a value with the provided string tag", () => {
53 const iterator = arrayIteratorFunction(null, "My Iterator");
54 assertStrictEquals(
55 iterator([])[Symbol.toStringTag],
56 "My Iterator",
57 );
58 });
59
60 it("[[Call]] yields the values", () => {
61 const iterator = arrayIteratorFunction();
62 assertEquals(
63 [...iterator(["etaoin", "shrdlu"])],
64 ["etaoin", "shrdlu"],
65 );
66 });
67
68 it("[[Call]] maps the values", () => {
69 const iterator = arrayIteratorFunction(function* ($) {
70 yield $.toUpperCase();
71 });
72 assertEquals(
73 [...iterator(["etaoin", "shrdlu"])],
74 ["ETAOIN", "SHRDLU"],
75 );
76 });
77
78 it("[[Call]] can map to nothing", () => {
79 const iterator = arrayIteratorFunction(function* () {});
80 assertEquals(
81 [...iterator(["etaoin", "shrdlu"])],
82 [],
83 );
84 });
85
86 it("[[Call]] can map to multiple values", () => {
87 const iterator = arrayIteratorFunction(function* ($) {
88 yield* $;
89 });
90 assertEquals(
91 [...iterator(["etaoin", "shrdlu"])],
92 [..."etaoinshrdlu"],
93 );
94 });
95
96 it("[[Call]] throws if not provided with any arguments", () => {
97 const iterator = arrayIteratorFunction();
98 assertThrows(() => {
99 iterator();
100 });
101 });
102
103 it("[[Call]] throws if not provided an arraylike", () => {
104 const iterator = arrayIteratorFunction();
105 assertThrows(() => {
106 iterator(null);
107 });
108 });
109
110 describe("::next", () => {
111 it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
112 const iterator = arrayIteratorFunction(function () {});
113 assertThrows(() => {
114 iterator(["etaoin"]).next();
115 });
116 });
117 });
118 });
119 });
120
121 describe("generatorIteratorFunction", () => {
122 it("[[Call]] returns a function", () => {
123 assertStrictEquals(typeof generatorIteratorFunction(), "function");
124 });
125
126 it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
127 assertStrictEquals(
128 Object.getPrototypeOf(generatorIteratorFunction()),
129 Function.prototype,
130 );
131 });
132
133 describe("()", () => {
134 it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
135 const iteratorProto = Object.getPrototypeOf(
136 Object.getPrototypeOf([][Symbol.iterator]),
137 );
138 const iterator = generatorIteratorFunction();
139 assertStrictEquals(
140 iterator(function* () {}) instanceof Object.assign(
141 function () {},
142 { prototype: iteratorProto },
143 ),
144 true,
145 );
146 });
147
148 it("[[Call]] returns a value with the provided string tag", () => {
149 const iterator = generatorIteratorFunction(null, "My Iterator");
150 assertStrictEquals(
151 iterator(function* () {})[Symbol.toStringTag],
152 "My Iterator",
153 );
154 });
155
156 it("[[Call]] yields the values", () => {
157 const generator = function* () {
158 yield* ["etaoin", "shrdlu"];
159 };
160 const iterator = generatorIteratorFunction();
161 assertEquals(
162 [...iterator(generator)],
163 ["etaoin", "shrdlu"],
164 );
165 });
166
167 it("[[Call]] maps the values", () => {
168 const generator = function* () {
169 yield* ["etaoin", "shrdlu"];
170 };
171 const iterator = generatorIteratorFunction(function* ($) {
172 yield $.toUpperCase();
173 });
174 assertEquals(
175 [...iterator(generator)],
176 ["ETAOIN", "SHRDLU"],
177 );
178 });
179
180 it("[[Call]] can map to nothing", () => {
181 const generator = function* () {
182 yield* ["etaoin", "shrdlu"];
183 };
184 const iterator = generatorIteratorFunction(function* () {});
185 assertEquals(
186 [...iterator(generator)],
187 [],
188 );
189 });
190
191 it("[[Call]] can map to multiple values", () => {
192 const generator = function* () {
193 yield* ["etaoin", "shrdlu"];
194 };
195 const iterator = generatorIteratorFunction(function* ($) {
196 yield* $;
197 });
198 assertEquals(
199 [...iterator(generator)],
200 [..."etaoinshrdlu"],
201 );
202 });
203
204 it("[[Call]] throws if not provided with any arguments", () => {
205 const iterator = generatorIteratorFunction();
206 assertThrows(() => {
207 iterator();
208 });
209 });
210
211 it("[[Call]] throws if not provided a function", () => {
212 const iterator = generatorIteratorFunction();
213 assertThrows(() => {
214 iterator([]);
215 });
216 });
217
218 describe("::next", () => {
219 it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
220 const generator = function* () {
221 yield "etaoin";
222 };
223 const iterator = generatorIteratorFunction(function () {});
224 assertThrows(() => {
225 iterator(generator).next();
226 });
227 });
228
229 it("[[Call]] throws if not constructed with a generator function", () => {
230 const iterator = generatorIteratorFunction();
231 assertThrows(() => {
232 iterator(Array.prototype[Symbol.iterator].bind([])).next();
233 });
234 });
235 });
236 });
237 });
238
239 describe("mapIteratorFunction", () => {
240 it("[[Call]] returns a function", () => {
241 assertStrictEquals(typeof mapIteratorFunction(), "function");
242 });
243
244 it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
245 assertStrictEquals(
246 Object.getPrototypeOf(mapIteratorFunction()),
247 Function.prototype,
248 );
249 });
250
251 describe("()", () => {
252 it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
253 const iteratorProto = Object.getPrototypeOf(
254 Object.getPrototypeOf([][Symbol.iterator]),
255 );
256 const iterator = mapIteratorFunction();
257 assertStrictEquals(
258 iterator(new Map()) instanceof Object.assign(
259 function () {},
260 { prototype: iteratorProto },
261 ),
262 true,
263 );
264 });
265
266 it("[[Call]] returns a value with the provided string tag", () => {
267 const iterator = mapIteratorFunction(null, "My Iterator");
268 assertStrictEquals(
269 iterator(new Map())[Symbol.toStringTag],
270 "My Iterator",
271 );
272 });
273
274 it("[[Call]] yields the values", () => {
275 const iterator = mapIteratorFunction();
276 assertEquals(
277 [...iterator(new Map([["etaoin", "shrdlu"]]))],
278 [["etaoin", "shrdlu"]],
279 );
280 });
281
282 it("[[Call]] maps the values", () => {
283 const iterator = mapIteratorFunction(function* ([k, v]) {
284 yield [k.toUpperCase(), v.toUpperCase()];
285 });
286 assertEquals(
287 [...iterator(new Map([["etaoin", "shrdlu"]]))],
288 [["ETAOIN", "SHRDLU"]],
289 );
290 });
291
292 it("[[Call]] can map to nothing", () => {
293 const iterator = mapIteratorFunction(function* () {});
294 assertEquals(
295 [...iterator(new Map([["etaoin", "shrdlu"]]))],
296 [],
297 );
298 });
299
300 it("[[Call]] can map to multiple values", () => {
301 const iterator = mapIteratorFunction(function* ($) {
302 yield* $;
303 });
304 assertEquals(
305 [...iterator(new Map([["etaoin", "shrdlu"]]))],
306 ["etaoin", "shrdlu"],
307 );
308 });
309
310 it("[[Call]] throws if not provided with any arguments", () => {
311 const iterator = mapIteratorFunction();
312 assertThrows(() => {
313 iterator();
314 });
315 });
316
317 it("[[Call]] throws if not provided a map", () => {
318 const iterator = mapIteratorFunction();
319 assertThrows(() => {
320 iterator([]);
321 });
322 });
323
324 describe("::next", () => {
325 it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
326 const iterator = mapIteratorFunction(function () {});
327 assertThrows(() => {
328 iterator(new Map([["etaoin", "shrdlu"]])).next();
329 });
330 });
331 });
332 });
333 });
334
335 describe("setIteratorFunction", () => {
336 it("[[Call]] returns a function", () => {
337 assertStrictEquals(typeof setIteratorFunction(), "function");
338 });
339
340 it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
341 assertStrictEquals(
342 Object.getPrototypeOf(setIteratorFunction()),
343 Function.prototype,
344 );
345 });
346
347 describe("()", () => {
348 it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
349 const iteratorProto = Object.getPrototypeOf(
350 Object.getPrototypeOf([][Symbol.iterator]),
351 );
352 const iterator = setIteratorFunction();
353 assertStrictEquals(
354 iterator(new Set()) instanceof Object.assign(
355 function () {},
356 { prototype: iteratorProto },
357 ),
358 true,
359 );
360 });
361
362 it("[[Call]] returns a value with the provided string tag", () => {
363 const iterator = setIteratorFunction(null, "My Iterator");
364 assertStrictEquals(
365 iterator(new Set())[Symbol.toStringTag],
366 "My Iterator",
367 );
368 });
369
370 it("[[Call]] yields the values", () => {
371 const iterator = setIteratorFunction();
372 assertEquals(
373 [...iterator(new Set(["etaoin", "shrdlu"]))],
374 ["etaoin", "shrdlu"],
375 );
376 });
377
378 it("[[Call]] maps the values", () => {
379 const iterator = setIteratorFunction(function* ($) {
380 yield $.toUpperCase();
381 });
382 assertEquals(
383 [...iterator(new Set(["etaoin", "shrdlu"]))],
384 ["ETAOIN", "SHRDLU"],
385 );
386 });
387
388 it("[[Call]] can map to nothing", () => {
389 const iterator = setIteratorFunction(function* () {});
390 assertEquals(
391 [...iterator(new Set(["etaoin", "shrdlu"]))],
392 [],
393 );
394 });
395
396 it("[[Call]] can map to multiple values", () => {
397 const iterator = setIteratorFunction(function* ($) {
398 yield* $;
399 });
400 assertEquals(
401 [...iterator(new Set(["etaoin", "shrdlu"]))],
402 [..."etaoinshrdlu"],
403 );
404 });
405
406 it("[[Call]] throws if not provided with any arguments", () => {
407 const iterator = setIteratorFunction();
408 assertThrows(() => {
409 iterator();
410 });
411 });
412
413 it("[[Call]] throws if not provided a set", () => {
414 const iterator = setIteratorFunction();
415 assertThrows(() => {
416 iterator([]);
417 });
418 });
419
420 describe("::next", () => {
421 it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
422 const iterator = setIteratorFunction(function () {});
423 assertThrows(() => {
424 iterator(new Set(["etaoin"])).next();
425 });
426 });
427 });
428 });
429 });
430
431 describe("stringIteratorFunction", () => {
432 it("[[Call]] returns a function", () => {
433 assertStrictEquals(typeof stringIteratorFunction(), "function");
434 });
435
436 it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
437 assertStrictEquals(
438 Object.getPrototypeOf(stringIteratorFunction()),
439 Function.prototype,
440 );
441 });
442
443 describe("()", () => {
444 it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
445 const iteratorProto = Object.getPrototypeOf(
446 Object.getPrototypeOf([][Symbol.iterator]),
447 );
448 const iterator = stringIteratorFunction();
449 assertStrictEquals(
450 iterator("") instanceof Object.assign(
451 function () {},
452 { prototype: iteratorProto },
453 ),
454 true,
455 );
456 });
457
458 it("[[Call]] returns a value with the provided string tag", () => {
459 const iterator = stringIteratorFunction(null, "My Iterator");
460 assertStrictEquals(
461 iterator("")[Symbol.toStringTag],
462 "My Iterator",
463 );
464 });
465
466 it("[[Call]] yields the values", () => {
467 const iterator = stringIteratorFunction();
468 assertEquals(
469 [...iterator("etaoin👀")],
470 [..."etaoin👀"],
471 );
472 });
473
474 it("[[Call]] maps the values", () => {
475 const iterator = stringIteratorFunction(function* ($) {
476 yield $.toUpperCase();
477 });
478 assertEquals(
479 [...iterator("etaoin👀")],
480 [..."ETAOIN👀"],
481 );
482 });
483
484 it("[[Call]] can map to nothing", () => {
485 const iterator = stringIteratorFunction(function* () {});
486 assertEquals(
487 [...iterator("etaoin👀")],
488 [],
489 );
490 });
491
492 it("[[Call]] can map to multiple values", () => {
493 const iterator = stringIteratorFunction(function* ($) {
494 yield $;
495 yield $;
496 });
497 assertEquals(
498 [...iterator("etaoin👀")],
499 [..."eettaaooiinn👀👀"],
500 );
501 });
502
503 it("[[Call]] throws if not provided with any arguments", () => {
504 const iterator = stringIteratorFunction();
505 assertThrows(() => {
506 iterator();
507 });
508 });
509
510 it("[[Call]] throws if not provided something convertible to a string", () => {
511 const iterator = stringIteratorFunction();
512 assertThrows(() => {
513 iterator({
514 toString() {
515 throw null;
516 },
517 });
518 });
519 });
520
521 describe("::next", () => {
522 it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
523 const iterator = stringIteratorFunction(function () {});
524 assertThrows(() => {
525 iterator("etaoin").next();
526 });
527 });
528 });
529 });
530 });
This page took 0.096956 seconds and 5 git commands to generate.