@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.
- package/.github/workflows/npm-publish.yml +32 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/runConfigurations/Test_all.xml +12 -0
- package/.idea/runConfigurations/Test_character_set.xml +12 -0
- package/.idea/runConfigurations/Test_iteration.xml +12 -0
- package/.idea/runConfigurations/Test_record.xml +12 -0
- package/.idea/runConfigurations/Test_regular_expression.xml +12 -0
- package/.idea/runConfigurations/Test_transformer.xml +12 -0
- package/.idea/runConfigurations/build.xml +12 -0
- package/.idea/runConfigurations/eslint.xml +12 -0
- package/.idea/utility.iml +9 -0
- package/.idea/vcs.xml +6 -0
- package/LICENSE +201 -0
- package/README.md +12 -0
- package/eslint.config.js +15 -0
- package/package.json +42 -0
- package/src/character_set.ts +766 -0
- package/src/index.ts +6 -0
- package/src/iteration.ts +343 -0
- package/src/locale/en/locale_strings.ts +30 -0
- package/src/locale/i18n.ts +8 -0
- package/src/locale/i18next.d.ts +10 -0
- package/src/record.ts +64 -0
- package/src/reg_exp.ts +58 -0
- package/src/string.ts +22 -0
- package/src/transformer.ts +654 -0
- package/test/character_set.test.ts +170 -0
- package/test/iteration.test.ts +282 -0
- package/test/record.test.ts +41 -0
- package/test/reg_exp.test.ts +43 -0
- package/test/transformer.test.ts +143 -0
- package/tsconfig.json +3 -0
- package/typedoc.json +10 -0
|
@@ -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