@aidc-toolkit/utility 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
2
+ import { describe, expect, test } from "vitest";
3
+ import {
4
+ ALPHABETIC_CREATOR,
5
+ ALPHANUMERIC_CREATOR,
6
+ CharacterSetCreator,
7
+ Exclusion,
8
+ HEXADECIMAL_CREATOR,
9
+ IterationHelper,
10
+ NUMERIC_CREATOR
11
+ } from "../src/index.js";
12
+
13
+ await i18nInit(I18NEnvironment.CLI, true);
14
+
15
+ // eslint-disable-next-line jsdoc/require-jsdoc
16
+ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSetCreator, characterSetSize: number, length: number, excludeFirstZero: boolean, excludeAllNumeric: boolean): void {
17
+ describe(name, () => {
18
+ test("Character set", () => {
19
+ characterSetCreator.characterSet.forEach((c, index) => {
20
+ expect(c).not.toBeUndefined();
21
+ expect(characterSetCreator.characterIndex(c)).toBe(index);
22
+ });
23
+
24
+ let s = "";
25
+
26
+ for (let index = 0; index < characterSetSize; index++) {
27
+ const c = characterSetCreator.character(index);
28
+
29
+ s += c;
30
+
31
+ expect(c).not.toBeUndefined();
32
+ expect(characterSetCreator.characterIndex(c)).toBe(index);
33
+ }
34
+
35
+ expect(characterSetCreator.character(characterSetSize)).toBeUndefined();
36
+
37
+ const characterIndexes = characterSetCreator.characterIndexes(s);
38
+
39
+ expect(characterIndexes.length).toBe(characterSetSize);
40
+
41
+ characterIndexes.forEach((characterIndex, index) => {
42
+ expect(characterIndex).toBe(index);
43
+ });
44
+
45
+ expect(characterSetCreator.exclusionSupport.includes(Exclusion.FirstZero)).toBe(excludeFirstZero);
46
+ expect(characterSetCreator.exclusionSupport.includes(Exclusion.AllNumeric)).toBe(excludeAllNumeric);
47
+ });
48
+
49
+ // eslint-disable-next-line jsdoc/require-jsdoc
50
+ function testCreate(exclusion: Exclusion): void {
51
+ let domain: number;
52
+
53
+ switch (exclusion) {
54
+ case Exclusion.FirstZero:
55
+ expect(() => characterSetCreator.create(0, 0, Exclusion.FirstZero)).toThrow("Domain 0 must be greater than 0");
56
+ domain = (characterSetSize - 1) * characterSetSize ** (length - 1);
57
+ break;
58
+
59
+ case Exclusion.AllNumeric:
60
+ expect(() => characterSetCreator.create(0, 0, Exclusion.AllNumeric)).toThrow("Domain 0 must be greater than 0");
61
+ domain = characterSetSize ** length - 10 ** length;
62
+ break;
63
+
64
+ default:
65
+ domain = characterSetSize ** length;
66
+ break;
67
+ }
68
+
69
+ const sequence = IterationHelper.from(characterSetCreator.createSequence(length, 0n, domain, exclusion));
70
+
71
+ let previousS = "";
72
+
73
+ let sequenceCount = 0;
74
+
75
+ sequence.forEach((s, index) => {
76
+ expect(s > previousS).toBe(true);
77
+ previousS = s;
78
+
79
+ expect(s.length).toBe(length);
80
+
81
+ expect(characterSetCreator.value(s, exclusion)).toBe(BigInt(index));
82
+
83
+ sequenceCount++;
84
+ });
85
+
86
+ expect(sequenceCount).toBe(domain);
87
+
88
+ expect(() => characterSetCreator.create(length, domain, exclusion)).toThrow(RangeError);
89
+
90
+ const sparseSequence = IterationHelper.from(characterSetCreator.createSequence(length, 0n, domain, exclusion, 123456n));
91
+
92
+ let sequential = true;
93
+ previousS = "";
94
+
95
+ const sequenceSet = new Set<string>();
96
+
97
+ sequenceCount = 0;
98
+
99
+ sparseSequence.forEach((s, index) => {
100
+ sequential = sequential && s > previousS;
101
+ previousS = s;
102
+
103
+ expect(s.length).toBe(length);
104
+
105
+ expect(sequenceSet.has(s)).toBe(false);
106
+ sequenceSet.add(s);
107
+
108
+ expect(characterSetCreator.value(s, exclusion, 123456n)).toBe(BigInt(index));
109
+
110
+ sequenceCount++;
111
+ });
112
+
113
+ expect(sequential).toBe(false);
114
+ expect(sequenceCount).toBe(domain);
115
+
116
+ const randomValues = new Array<bigint>();
117
+ const straightRandomValues = new Array<string>();
118
+ const sparseRandomValues = new Array<string>();
119
+
120
+ for (let i = 0; i < 1000; i++) {
121
+ const randomValue = BigInt(Math.floor(Math.random() * domain));
122
+
123
+ randomValues.push(randomValue);
124
+ straightRandomValues.push(characterSetCreator.create(length, randomValue, exclusion));
125
+ sparseRandomValues.push(characterSetCreator.create(length, randomValue, exclusion, 123456n));
126
+ }
127
+
128
+ expect(Array.from(characterSetCreator.createMultiple(length, randomValues, exclusion))).toStrictEqual(straightRandomValues);
129
+ expect(Array.from(characterSetCreator.createMultiple(length, randomValues, exclusion, 123456n))).toStrictEqual(sparseRandomValues);
130
+
131
+ expect(() => characterSetCreator.create(length, exclusion, domain, 123456n)).toThrow(RangeError);
132
+ }
133
+
134
+ test("Create sequence", () => {
135
+ testCreate(Exclusion.None);
136
+ });
137
+
138
+ if (excludeFirstZero) {
139
+ test("Create sequence, exclude first zero", () => {
140
+ testCreate(Exclusion.FirstZero);
141
+
142
+ expect(() => characterSetCreator.value("0000", Exclusion.FirstZero)).toThrow(RangeError);
143
+ expect(() => characterSetCreator.value("1000", Exclusion.FirstZero)).not.toThrow(RangeError);
144
+ });
145
+ }
146
+
147
+ if (excludeAllNumeric) {
148
+ test("Create sequence, exclude all numeric", () => {
149
+ testCreate(Exclusion.AllNumeric);
150
+
151
+ expect(() => characterSetCreator.value("0000", Exclusion.AllNumeric)).toThrow(RangeError);
152
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
153
+ expect(() => characterSetCreator.value("000" + characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1), Exclusion.AllNumeric)).not.toThrow(RangeError);
154
+ expect(() => characterSetCreator.value("9999", Exclusion.AllNumeric)).toThrow(RangeError);
155
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
156
+ expect(() => characterSetCreator.value("999" + characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1), Exclusion.AllNumeric)).not.toThrow(RangeError);
157
+ });
158
+ }
159
+ });
160
+ }
161
+
162
+ testCharacterSetCreator("Numeric", NUMERIC_CREATOR, 10, 4, true, false);
163
+ testCharacterSetCreator("Hexadecimal", HEXADECIMAL_CREATOR, 16, 4, true, true);
164
+ testCharacterSetCreator("Alphabetic", ALPHABETIC_CREATOR, 26, 3, false, false);
165
+ testCharacterSetCreator("Alphanumeric", ALPHANUMERIC_CREATOR, 36, 3, true, true);
166
+ testCharacterSetCreator("Middle numeric", new CharacterSetCreator([
167
+ "(", ")", "*", "+",
168
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
169
+ ":", ";", "<", ">"
170
+ ], Exclusion.AllNumeric), 18, 4, false, true);
@@ -0,0 +1,282 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { IterationHelper, type IterationSource } from "../src/index.js";
3
+
4
+ const source: readonly string[] = [
5
+ "1", "2", "3", "4", "5"
6
+ ];
7
+
8
+ // eslint-disable-next-line jsdoc/require-jsdoc
9
+ function iterableSource(): Iterable<string> {
10
+ return [...source];
11
+ }
12
+
13
+ // eslint-disable-next-line jsdoc/require-jsdoc
14
+ function arraySource(): string[] {
15
+ return [...source];
16
+ }
17
+
18
+ // eslint-disable-next-line jsdoc/require-jsdoc
19
+ function iteratorSource(): Iterator<string> {
20
+ return [...source][Symbol.iterator]();
21
+ }
22
+
23
+ // eslint-disable-next-line jsdoc/require-jsdoc
24
+ function * generatorSource(): Generator<string> {
25
+ for (const s of source) {
26
+ yield s;
27
+ }
28
+ }
29
+
30
+ // eslint-disable-next-line jsdoc/require-jsdoc
31
+ function callbackSource(): string[] {
32
+ return [...source];
33
+ }
34
+
35
+ describe("Iterable", () => {
36
+ // eslint-disable-next-line jsdoc/require-jsdoc
37
+ function validateIterable(iterationSource: IterationSource<string>, testEquality: boolean): void {
38
+ const iterationHelper = IterationHelper.from(iterationSource);
39
+
40
+ expect(IterationHelper.from(iterationHelper)).toBe(iterationHelper);
41
+ expect(iterationHelper.iterationSource).toBe(iterationSource);
42
+
43
+ expect(iterationHelper.asIterable() === iterationSource).toBe(testEquality);
44
+ expect(Array.from(iterationHelper)).toStrictEqual(source);
45
+ }
46
+
47
+ test("Iterable", () => {
48
+ validateIterable(iterableSource, false);
49
+ validateIterable(iterableSource(), true);
50
+ });
51
+
52
+ test("Array", () => {
53
+ validateIterable(arraySource, false);
54
+ validateIterable(arraySource(), true);
55
+ });
56
+
57
+ test("Iterator", () => {
58
+ validateIterable(iteratorSource, false);
59
+ validateIterable(iteratorSource(), true);
60
+ });
61
+
62
+ test("Generator", () => {
63
+ validateIterable(generatorSource, false);
64
+ validateIterable(generatorSource(), true);
65
+ });
66
+
67
+ test("Callback", () => {
68
+ validateIterable(callbackSource, false);
69
+ validateIterable(callbackSource(), true);
70
+ });
71
+ });
72
+
73
+ describe("Array", () => {
74
+ // eslint-disable-next-line jsdoc/require-jsdoc
75
+ function validateArray(iterationSource: IterationSource<string>, testEquality: boolean): void {
76
+ const iterationHelper = IterationHelper.from(iterationSource);
77
+
78
+ expect(IterationHelper.from(iterationHelper)).toBe(iterationHelper);
79
+ expect(iterationHelper.iterationSource).toBe(iterationSource);
80
+
81
+ const array = iterationHelper.asArray();
82
+
83
+ expect(array === iterationSource).toBe(testEquality);
84
+ expect(array).toStrictEqual(source);
85
+ }
86
+
87
+ test("Iterable", () => {
88
+ validateArray(iterableSource, false);
89
+ validateArray(iterableSource(), true);
90
+ });
91
+
92
+ test("Array", () => {
93
+ validateArray(arraySource, false);
94
+ validateArray(arraySource(), true);
95
+ });
96
+
97
+ test("Iterator", () => {
98
+ validateArray(iteratorSource, false);
99
+ validateArray(iteratorSource(), false);
100
+ });
101
+
102
+ test("Generator", () => {
103
+ validateArray(generatorSource, false);
104
+ validateArray(generatorSource(), false);
105
+ });
106
+
107
+ test("Callback", () => {
108
+ validateArray(callbackSource, false);
109
+ validateArray(callbackSource(), true);
110
+ });
111
+ });
112
+
113
+ describe("Iterator", () => {
114
+ // eslint-disable-next-line jsdoc/require-jsdoc
115
+ function validateIterator(iterationSource: IterationSource<string>, testEquality: boolean): void {
116
+ const iterationHelper = IterationHelper.from(iterationSource);
117
+
118
+ expect(IterationHelper.from(iterationHelper)).toBe(iterationHelper);
119
+ expect(iterationHelper.iterationSource).toBe(iterationSource);
120
+
121
+ const iterator = iterationHelper.asIterator();
122
+
123
+ expect(iterator === iterationSource).toBe(testEquality);
124
+ expect(Array.from({
125
+ [Symbol.iterator](): Iterator<string> {
126
+ return iterator;
127
+ }
128
+ })).toStrictEqual(source);
129
+ }
130
+
131
+ test("Iterable", () => {
132
+ validateIterator(iterableSource, false);
133
+ validateIterator(iterableSource(), false);
134
+ });
135
+
136
+ test("Array", () => {
137
+ validateIterator(arraySource, false);
138
+ validateIterator(arraySource(), false);
139
+ });
140
+
141
+ test("Iterator", () => {
142
+ validateIterator(iteratorSource, false);
143
+ validateIterator(iteratorSource(), true);
144
+ });
145
+
146
+ test("Generator", () => {
147
+ validateIterator(generatorSource, false);
148
+ validateIterator(generatorSource(), true);
149
+ });
150
+
151
+ test("Callback", () => {
152
+ validateIterator(callbackSource, false);
153
+ validateIterator(callbackSource(), false);
154
+ });
155
+ });
156
+
157
+ describe("Callback", () => {
158
+ // eslint-disable-next-line jsdoc/require-jsdoc
159
+ function validateCallback(iterationSource: IterationSource<string>, testEquality: boolean): void {
160
+ const iterationHelper = IterationHelper.from(iterationSource);
161
+
162
+ expect(IterationHelper.from(iterationHelper)).toBe(iterationHelper);
163
+ expect(iterationHelper.iterationSource).toBe(iterationSource);
164
+
165
+ expect(iterationHelper.asCallback() === iterationSource).toBe(testEquality);
166
+ expect(iterationHelper.asArray()).toStrictEqual(source);
167
+ }
168
+
169
+ test("Iterable", () => {
170
+ validateCallback(iterableSource, true);
171
+ validateCallback(iterableSource(), false);
172
+ });
173
+
174
+ test("Array", () => {
175
+ validateCallback(arraySource, true);
176
+ validateCallback(arraySource(), false);
177
+ });
178
+
179
+ test("Iterator", () => {
180
+ validateCallback(iteratorSource, true);
181
+ validateCallback(iteratorSource(), false);
182
+ });
183
+
184
+ test("Generator", () => {
185
+ validateCallback(generatorSource, true);
186
+ validateCallback(generatorSource(), false);
187
+ });
188
+
189
+ test("Callback", () => {
190
+ validateCallback(callbackSource, true);
191
+ validateCallback(callbackSource(), false);
192
+ });
193
+ });
194
+
195
+ describe("Helpers", () => {
196
+ test("For each", () => {
197
+ let count = 0;
198
+
199
+ IterationHelper.from(source).forEach((value, index) => {
200
+ expect(Number(value)).toBe(index + 1);
201
+ expect(index).toBe(count++);
202
+ });
203
+
204
+ expect(count).toBe(source.length);
205
+ });
206
+
207
+ test("Map", () => {
208
+ let count = 0;
209
+
210
+ const mappedIterationHelper = IterationHelper.from(source).map((element, index) => {
211
+ expect(Number(element)).toBe(index + 1);
212
+ expect(index).toBe(count++);
213
+
214
+ return -count;
215
+ });
216
+
217
+ expect(count).toBe(0);
218
+
219
+ let negativeCount = 0;
220
+
221
+ for (const element of mappedIterationHelper) {
222
+ expect(element).toBe(--negativeCount);
223
+ }
224
+
225
+ expect(count).toBe(source.length);
226
+ });
227
+
228
+ test("Filter", () => {
229
+ let count = 0;
230
+
231
+ const filteredIterable = IterationHelper.from(source).filter((element, index) => {
232
+ expect(Number(element)).toBe(index + 1);
233
+ expect(index).toBe(count++);
234
+
235
+ return Number(element) % 2 === 0;
236
+ });
237
+
238
+ expect(count).toBe(0);
239
+
240
+ let evenCount = 0;
241
+
242
+ for (const element of filteredIterable) {
243
+ const n = Number(element);
244
+
245
+ expect(n % 2).toBe(0);
246
+ expect(Math.floor((n - 1) / 2)).toBe(evenCount++);
247
+ }
248
+
249
+ expect(count).toBe(source.length);
250
+ expect(evenCount).toBe(Math.floor(source.length / 2));
251
+ });
252
+
253
+ test("Reduce no initial value", () => {
254
+ let count = 0;
255
+
256
+ expect(IterationHelper.from(source).reduce((previousValue, currentValue, currentIndex) => {
257
+ expect(Number(currentValue)).toBe(currentIndex + 1);
258
+ expect(currentIndex - 1).toBe(count++);
259
+
260
+ return previousValue + currentValue;
261
+ })).toBe("".concat(...source));
262
+
263
+ expect(count).toBe(source.length - 1);
264
+
265
+ expect(() => IterationHelper.from<string>([]).reduce(() => "")).toThrow("reduce() of empty iterator with no initial value");
266
+ });
267
+
268
+ test("Reduce initial value", () => {
269
+ let count = 0;
270
+
271
+ expect(IterationHelper.from(source).reduce((previousValue, currentValue, currentIndex) => {
272
+ expect(Number(currentValue)).toBe(currentIndex + 1);
273
+ expect(currentIndex).toBe(count++);
274
+
275
+ return previousValue + currentValue;
276
+ }, "0")).toBe("0".concat(...source));
277
+
278
+ expect(count).toBe(source.length);
279
+
280
+ expect(IterationHelper.from<string>([]).reduce(() => "", "0")).toBe("0");
281
+ });
282
+ });
@@ -0,0 +1,41 @@
1
+ import {I18NEnvironment, i18nInit} from "@aidc-toolkit/core";
2
+ import {describe, expect, test} from "vitest";
3
+ import {RecordValidator} from "../src/index.js";
4
+
5
+ await i18nInit(I18NEnvironment.CLI, true);
6
+
7
+ describe("Record validator", () => {
8
+ enum StringEnum {
9
+ ValueA = "A",
10
+ ValueB = "B",
11
+ ValueC = "C",
12
+ ValueD = "D"
13
+ }
14
+
15
+ const stringEnumRecord: Record<StringEnum, string> = {
16
+ [StringEnum.ValueA]: "This is for Value A",
17
+ [StringEnum.ValueB]: "This is for Value B",
18
+ [StringEnum.ValueC]: "This is for Value C",
19
+ [StringEnum.ValueD]: "This is for Value D"
20
+ };
21
+
22
+ test("Validation", () => {
23
+ const stringEnumRecordValidator = new RecordValidator("String enumeration", stringEnumRecord);
24
+
25
+ expect(() => {
26
+ stringEnumRecordValidator.validate("A");
27
+ }).not.toThrow(RangeError);
28
+ expect(() => {
29
+ stringEnumRecordValidator.validate("B");
30
+ }).not.toThrow(RangeError);
31
+ expect(() => {
32
+ stringEnumRecordValidator.validate("C");
33
+ }).not.toThrow(RangeError);
34
+ expect(() => {
35
+ stringEnumRecordValidator.validate("D");
36
+ }).not.toThrow(RangeError);
37
+ expect(() => {
38
+ stringEnumRecordValidator.validate("E");
39
+ }).toThrow("String enumeration \"E\" not found");
40
+ });
41
+ });
@@ -0,0 +1,43 @@
1
+ import {I18NEnvironment, i18nInit} from "@aidc-toolkit/core";
2
+ import {describe, expect, test} from "vitest";
3
+ import {RegExpValidator} from "../src/index.js";
4
+
5
+ await i18nInit(I18NEnvironment.CLI, true);
6
+
7
+ describe("Regular expression validator", () => {
8
+ test("Validation", () => {
9
+ const anyDigitValidator = new RegExpValidator(/\d+/);
10
+ const allDigitValidator = new RegExpValidator(/^\d+$/);
11
+
12
+ expect(() => {
13
+ anyDigitValidator.validate("ABC123DEF");
14
+ }).not.toThrow(RangeError);
15
+ expect(() => {
16
+ allDigitValidator.validate("ABC123DEF");
17
+ }).toThrow("String ABC123DEF does not match pattern");
18
+
19
+ expect(() => {
20
+ anyDigitValidator.validate("1234567890");
21
+ }).not.toThrow(RangeError);
22
+ expect(() => {
23
+ allDigitValidator.validate("1234567890");
24
+ }).not.toThrow(RangeError);
25
+
26
+ expect(() => {
27
+ anyDigitValidator.validate("123456789O");
28
+ }).not.toThrow(RangeError);
29
+ expect(() => {
30
+ allDigitValidator.validate("123456789O");
31
+ }).toThrow("String 123456789O does not match pattern");
32
+ });
33
+
34
+ test("Error message", () => {
35
+ expect(() => {
36
+ new class extends RegExpValidator {
37
+ protected override createErrorMessage(s: string): string {
38
+ return `Failed to validate "${s}"`;
39
+ }
40
+ }(/[A-Z]+/).validate("1234567890");
41
+ }).toThrow("Failed to validate \"1234567890\"");
42
+ });
43
+ });
@@ -0,0 +1,143 @@
1
+ import {I18NEnvironment, i18nInit} from "@aidc-toolkit/core";
2
+ import {describe, expect, test} from "vitest";
3
+ import { EncryptionTransformer, IdentityTransformer, IterationHelper, Transformer } from "../src/index.js";
4
+
5
+ await i18nInit(I18NEnvironment.CLI, true);
6
+
7
+ function testTransformer(domain: number, tweak?: number, callback?: (value: bigint, forwardValue: bigint) => void): void {
8
+ const transformer = Transformer.get(domain, tweak);
9
+
10
+ let sequential = true;
11
+
12
+ const transformedValuesSet = new Set<bigint>();
13
+
14
+ IterationHelper.from(transformer.forwardSequence(0n, domain)).forEach((transformedValue, index) => {
15
+ const indexN = BigInt(index);
16
+
17
+ if (sequential && transformedValue !== indexN) {
18
+ sequential = false;
19
+ }
20
+
21
+ expect(transformedValuesSet.has(transformedValue)).toBe(false);
22
+ expect(transformer.reverse(transformedValue)).toBe(indexN);
23
+
24
+ transformedValuesSet.add(transformedValue);
25
+
26
+ if (callback !== undefined) {
27
+ callback(indexN, transformedValue);
28
+ }
29
+ });
30
+
31
+ expect(sequential).toBe(tweak === undefined);
32
+
33
+ const randomValues = new Array<bigint>();
34
+ const transformedRandomValues = new Array<bigint>();
35
+
36
+ for (let i = 0; i < 1000; i++) {
37
+ const randomValue = BigInt(Math.floor(Math.random() * domain));
38
+
39
+ randomValues.push(randomValue);
40
+ transformedRandomValues.push(transformer.forward(randomValue));
41
+ }
42
+
43
+ expect(Array.from(transformer.forwardMultiple(randomValues))).toStrictEqual(transformedRandomValues);
44
+
45
+ expect(() => transformer.forward(BigInt(domain))).toThrow(`Value ${domain} must be less than ${domain}`);
46
+ expect(() => transformer.forwardSequence(BigInt(domain), 0)).not.toThrow(RangeError);
47
+ expect(() => transformer.forwardSequence(BigInt(domain) - 1n, 1)).not.toThrow(RangeError);
48
+ expect(() => transformer.forwardSequence(BigInt(domain), 1)).toThrow(`End value (start value + count - 1) ${domain} must be less than ${domain}`);
49
+ }
50
+
51
+ describe("Identity", () => {
52
+ test("Get", () => {
53
+ const transformer = Transformer.get(1000);
54
+
55
+ expect(transformer instanceof IdentityTransformer).toBe(true);
56
+ expect(Transformer.get(1000n)).toBe(transformer);
57
+
58
+ expect(transformer.domain).toBe(BigInt(1000n));
59
+ });
60
+
61
+ test("Reversible", () => {
62
+ const transformer = Transformer.get(25000000n);
63
+
64
+ expect(transformer.reverse(transformer.forward(17171717n))).toBe(17171717n);
65
+ });
66
+
67
+ test("Small domain", () => {
68
+ testTransformer(10);
69
+ });
70
+
71
+ test("Large domain", () => {
72
+ testTransformer(100000);
73
+ });
74
+ });
75
+
76
+ describe("Encryption", () => {
77
+ test("Get", () => {
78
+ const transformer = Transformer.get(1000, 1234);
79
+
80
+ expect(transformer instanceof EncryptionTransformer).toBe(true);
81
+ expect(Transformer.get(1000n, 1234n)).toBe(transformer);
82
+
83
+ expect(transformer.domain).toBe(BigInt(1000n));
84
+ expect((transformer as EncryptionTransformer).tweak).toBe(BigInt(1234n));
85
+
86
+ const transformer0 = Transformer.get(1000, 0);
87
+
88
+ expect(transformer0 instanceof EncryptionTransformer).toBe(true);
89
+ expect(transformer0).not.toBe(Transformer.get(1000));
90
+ });
91
+
92
+ test("Reversible", () => {
93
+ const transformer = Transformer.get(25000000n, 12345678901234567890n);
94
+
95
+ expect(transformer instanceof EncryptionTransformer).toBe(true);
96
+ expect(transformer.reverse(transformer.forward(17171717n))).toBe(17171717n);
97
+ });
98
+
99
+ test("Zero domain", () => {
100
+ expect(() => Transformer.get(0n, 12345678901234567890n)).toThrow("Domain 0 must be greater than 0");
101
+ });
102
+
103
+ test("Zero tweak", () => {
104
+ const transformer = Transformer.get(1000n, 0n);
105
+
106
+ for (let value = 0n; value < 1000n; value++) {
107
+ expect(transformer.forward(value)).toBe(value);
108
+ }
109
+ });
110
+
111
+ test("Small domain and tweak", () => {
112
+ testTransformer(10, 1);
113
+ });
114
+
115
+ test("Large domain and tweak", () => {
116
+ testTransformer(100000, 123456);
117
+ });
118
+
119
+ test("Byte boundary", () => {
120
+ // eslint-disable-next-line @typescript-eslint/dot-notation
121
+ expect((Transformer.get(256n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(1);
122
+ // eslint-disable-next-line @typescript-eslint/dot-notation
123
+ expect((Transformer.get(257n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(2);
124
+ // eslint-disable-next-line @typescript-eslint/dot-notation
125
+ expect((Transformer.get(65536n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(2);
126
+ // eslint-disable-next-line @typescript-eslint/dot-notation
127
+ expect((Transformer.get(65537n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(3);
128
+
129
+ testTransformer(256, 1);
130
+ testTransformer(257, 1);
131
+ });
132
+
133
+ test("Tweak variation", () => {
134
+ expect(Array.from(Transformer.get(1000, 1235).forwardSequence(0n, 1000))).not.toStrictEqual(Array.from(Transformer.get(1000, 1234).forwardSequence(0n, 1000)));
135
+ });
136
+
137
+ test("Consistency", () => {
138
+ expect(Transformer.get(1000n, 1234n).forward(987n)).toBe(35n);
139
+ expect(Transformer.get(10000n, 12345n).forward(9876n)).toBe(1960n);
140
+ expect(Transformer.get(100000n, 123456n).forward(98765n)).toBe(21407n);
141
+ expect(Transformer.get(1000000n, 1234567n).forward(987654n)).toBe(639402n);
142
+ });
143
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@aidc-toolkit/dev/tsconfig.json"
3
+ }
package/typedoc.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "extends": [
4
+ "@aidc-toolkit/dev/typedoc.json"
5
+ ],
6
+ "name": "Utility",
7
+ "entryPoints": [
8
+ "src/index.ts"
9
+ ]
10
+ }