1 | import * as assert from 'assert';
|
---|
2 | import test, { describe } from 'node:test';
|
---|
3 | import parse from '../parse.js';
|
---|
4 | import v1, { updateV1State } from '../v1.js';
|
---|
5 | const TIME = 1321644961388;
|
---|
6 | const RFC_V1 = 'c232ab00-9414-11ec-b3c8-9f68deced846';
|
---|
7 | const RFC_V1_BYTES = parse(RFC_V1);
|
---|
8 | const RFC_OPTIONS = {
|
---|
9 | msecs: 0x17f22e279b0,
|
---|
10 | nsecs: 0,
|
---|
11 | clockseq: 0x33c8,
|
---|
12 | node: Uint8Array.of(0x9f, 0x68, 0xde, 0xce, 0xd8, 0x46),
|
---|
13 | };
|
---|
14 | const RFC_RANDOM = Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0, RFC_OPTIONS.clockseq >> 8, RFC_OPTIONS.clockseq & 0xff, ...RFC_OPTIONS.node);
|
---|
15 | function compareV1TimeField(a, b) {
|
---|
16 | a = a.split('-').slice(0, 3).reverse().join('');
|
---|
17 | b = b.split('-').slice(0, 3).reverse().join('');
|
---|
18 | return a < b ? -1 : a > b ? 1 : 0;
|
---|
19 | }
|
---|
20 | describe('v1', () => {
|
---|
21 | test('v1 sort order (default)', () => {
|
---|
22 | const ids = [v1(), v1(), v1(), v1(), v1()];
|
---|
23 | const sorted = [...ids].sort(compareV1TimeField);
|
---|
24 | assert.deepEqual(ids, sorted);
|
---|
25 | });
|
---|
26 | test('v1 sort order (time option)', () => {
|
---|
27 | const ids = [
|
---|
28 | v1({ msecs: TIME - 10 * 3600 * 1000 }),
|
---|
29 | v1({ msecs: TIME - 1 }),
|
---|
30 | v1({ msecs: TIME }),
|
---|
31 | v1({ msecs: TIME + 1 }),
|
---|
32 | v1({ msecs: TIME + 28 * 24 * 3600 * 1000 }),
|
---|
33 | ];
|
---|
34 | const sorted = [...ids].sort(compareV1TimeField);
|
---|
35 | assert.deepEqual(ids, sorted);
|
---|
36 | });
|
---|
37 | test('v1(options)', () => {
|
---|
38 | assert.equal(v1({ msecs: RFC_OPTIONS.msecs, random: RFC_RANDOM }), RFC_V1, 'minimal options');
|
---|
39 | assert.equal(v1(RFC_OPTIONS), RFC_V1, 'full options');
|
---|
40 | });
|
---|
41 | test('v1(options) equality', () => {
|
---|
42 | assert.notEqual(v1({ msecs: TIME }), v1({ msecs: TIME }), 'UUIDs with minimal options differ');
|
---|
43 | assert.equal(v1(RFC_OPTIONS), v1(RFC_OPTIONS), 'UUIDs with full options are identical');
|
---|
44 | });
|
---|
45 | test('fills one UUID into a buffer as expected', () => {
|
---|
46 | const buffer = new Uint8Array(16);
|
---|
47 | const result = v1(RFC_OPTIONS, buffer);
|
---|
48 | assert.deepEqual(buffer, RFC_V1_BYTES);
|
---|
49 | assert.strictEqual(buffer, result);
|
---|
50 | });
|
---|
51 | test('fills two UUIDs into a buffer as expected', () => {
|
---|
52 | const buffer = new Uint8Array(32);
|
---|
53 | v1(RFC_OPTIONS, buffer, 0);
|
---|
54 | v1(RFC_OPTIONS, buffer, 16);
|
---|
55 | const expectedBuf = new Uint8Array(32);
|
---|
56 | expectedBuf.set(RFC_V1_BYTES);
|
---|
57 | expectedBuf.set(RFC_V1_BYTES, 16);
|
---|
58 | assert.deepEqual(buffer, expectedBuf);
|
---|
59 | });
|
---|
60 | test('v1() state transitions', () => {
|
---|
61 | const PRE_STATE = {
|
---|
62 | msecs: 10,
|
---|
63 | nsecs: 20,
|
---|
64 | clockseq: 0x1234,
|
---|
65 | node: Uint8Array.of(0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc),
|
---|
66 | };
|
---|
67 | const tests = [
|
---|
68 | {
|
---|
69 | title: 'initial state',
|
---|
70 | state: {},
|
---|
71 | now: 10,
|
---|
72 | expected: {
|
---|
73 | msecs: 10,
|
---|
74 | nsecs: 0,
|
---|
75 | clockseq: RFC_OPTIONS.clockseq,
|
---|
76 | node: RFC_OPTIONS.node,
|
---|
77 | },
|
---|
78 | },
|
---|
79 | {
|
---|
80 | title: 'same time interval',
|
---|
81 | state: { ...PRE_STATE },
|
---|
82 | now: PRE_STATE.msecs,
|
---|
83 | expected: {
|
---|
84 | ...PRE_STATE,
|
---|
85 | nsecs: 21,
|
---|
86 | },
|
---|
87 | },
|
---|
88 | {
|
---|
89 | title: 'new time interval',
|
---|
90 | state: { ...PRE_STATE },
|
---|
91 | now: PRE_STATE.msecs + 1,
|
---|
92 | expected: {
|
---|
93 | ...PRE_STATE,
|
---|
94 | msecs: PRE_STATE.msecs + 1,
|
---|
95 | nsecs: 0,
|
---|
96 | },
|
---|
97 | },
|
---|
98 | {
|
---|
99 | title: 'same time interval (nsecs overflow)',
|
---|
100 | state: { ...PRE_STATE, nsecs: 9999 },
|
---|
101 | now: PRE_STATE.msecs,
|
---|
102 | expected: {
|
---|
103 | ...PRE_STATE,
|
---|
104 | nsecs: 0,
|
---|
105 | clockseq: RFC_OPTIONS.clockseq,
|
---|
106 | node: RFC_OPTIONS.node,
|
---|
107 | },
|
---|
108 | },
|
---|
109 | {
|
---|
110 | title: 'time regression',
|
---|
111 | state: { ...PRE_STATE },
|
---|
112 | now: PRE_STATE.msecs - 1,
|
---|
113 | expected: {
|
---|
114 | ...PRE_STATE,
|
---|
115 | msecs: PRE_STATE.msecs - 1,
|
---|
116 | clockseq: RFC_OPTIONS.clockseq,
|
---|
117 | node: RFC_OPTIONS.node,
|
---|
118 | },
|
---|
119 | },
|
---|
120 | ];
|
---|
121 | for (const { title, state, now, expected } of tests) {
|
---|
122 | assert.deepStrictEqual(updateV1State(state, now, RFC_RANDOM), expected, `Failed: ${title}`);
|
---|
123 | }
|
---|
124 | });
|
---|
125 | });
|
---|