Recently Written · git

scan-subread

PDF reader that follows an audiobook with the SubRead suite

git clone https://github.com/equwal/scan-subread

Log | Files | Refs


test/read-order.test.ts (2477 bytes)

1 import fc from 'fast-check';
2 import { describe, expect, it } from 'vitest';
3 import { nextPage } from '../src/read-order';
4 
5 /** The whole numbers from `from` up to, but not including, `to`. */
6 function range(from: number, to: number): number[] {
7   return Array.from({ length: Math.max(0, to - from) }, (_, i) => from + i);
8 }
9 
10 /** All pages of a book of `count` pages, in the order of nextPage, while the current page stays. */
11 function readAll(count: number, current: number): number[] {
12   const pending = new Set(range(0, count));
13   const order: number[] = [];
14   while (pending.size > 0) {
15     const page = nextPage(pending, current);
16     pending.delete(page);
17     order.push(page);
18   }
19   return order;
20 }
21 
22 describe('nextPage', () => {
23   it('reads the current page, then the pages after it, then the pages before it', () => {
24     expect(readAll(6, 2)).toEqual([2, 3, 4, 5, 1, 0]);
25   });
26 
27   it('gives -1 when all pages are read', () => {
28     expect(nextPage(new Set(), 3)).toBe(-1);
29   });
30 
31   it('reads every page once: from the current page to the end, then back to the start', () => {
32     const book = fc
33       .integer({ min: 1, max: 60 })
34       .chain((count) => fc.tuple(fc.constant(count), fc.nat({ max: count - 1 })));
35     fc.assert(
36       fc.property(book, ([count, current]) => {
37         expect(readAll(count, current)).toEqual([
38           ...range(current, count),
39           ...range(0, current).reverse(),
40         ]);
41       }),
42     );
43   });
44 
45   it('follows the current page when the user turns pages during the read', () => {
46     // At each step the user can be on another page.
47     const read = fc
48       .integer({ min: 1, max: 40 })
49       .chain((count) =>
50         fc.tuple(
51           fc.constant(count),
52           fc.array(fc.nat({ max: count - 1 }), { minLength: count, maxLength: count }),
53         ),
54       );
55     fc.assert(
56       fc.property(read, ([count, currents]) => {
57         const pending = new Set(range(0, count));
58         const order: number[] = [];
59         for (const current of currents) {
60           const page = nextPage(pending, current);
61           // The nearest page at or after the current page, else the nearest before it.
62           const after = [...pending].filter((p) => p >= current);
63           expect(page).toBe(after.length > 0 ? Math.min(...after) : Math.max(...pending));
64           pending.delete(page);
65           order.push(page);
66         }
67         expect(order.sort((x, y) => x - y)).toEqual(range(0, count));
68       }),
69     );
70   });
71 });