fix: fix ApplicationProtocolVersion type definition
[e-mobility-charging-stations-simulator.git] / tests / utils / Utils.test.ts
... / ...
CommitLineData
1import { randomInt } from 'node:crypto'
2import { version } from 'node:process'
3import { describe, it } from 'node:test'
4
5import { hoursToMilliseconds, hoursToSeconds } from 'date-fns'
6import { expect } from 'expect'
7import { CircularBuffer } from 'mnemonist'
8import { satisfies } from 'semver'
9
10import type { TimestampedData } from '../../src/types/index.js'
11import { Constants } from '../../src/utils/Constants.js'
12import {
13 clone,
14 convertToBoolean,
15 convertToDate,
16 convertToFloat,
17 convertToInt,
18 extractTimeSeriesValues,
19 formatDurationMilliSeconds,
20 formatDurationSeconds,
21 generateUUID,
22 getRandomFloat,
23 hasOwnProp,
24 insertAt,
25 isArraySorted,
26 isAsyncFunction,
27 isNotEmptyArray,
28 isNotEmptyString,
29 isObject,
30 isValidDate,
31 roundTo,
32 secureRandom,
33 sleep,
34 validateUUID
35} from '../../src/utils/Utils.js'
36
37await describe('Utils test suite', async () => {
38 await it('Verify generateUUID()/validateUUID()', () => {
39 const uuid = generateUUID()
40 expect(uuid).toBeDefined()
41 expect(uuid.length).toEqual(36)
42 expect(validateUUID(uuid)).toBe(true)
43 expect(validateUUID('abcdef00-0000-4000-0000-000000000000')).toBe(true)
44 expect(validateUUID('')).toBe(false)
45 // Shall invalidate Nil UUID
46 expect(validateUUID('00000000-0000-0000-0000-000000000000')).toBe(false)
47 expect(validateUUID('987FBC9-4BED-3078-CF07A-9141BA07C9F3')).toBe(false)
48 })
49
50 await it('Verify sleep()', async () => {
51 const start = performance.now()
52 await sleep(1000)
53 const stop = performance.now()
54 expect(stop - start).toBeGreaterThanOrEqual(1000)
55 })
56
57 await it('Verify formatDurationMilliSeconds()', () => {
58 expect(formatDurationMilliSeconds(0)).toBe('0 seconds')
59 expect(formatDurationMilliSeconds(900)).toBe('0 seconds')
60 expect(formatDurationMilliSeconds(1000)).toBe('1 second')
61 expect(formatDurationMilliSeconds(hoursToMilliseconds(4380))).toBe('182 days 12 hours')
62 })
63
64 await it('Verify formatDurationSeconds()', () => {
65 expect(formatDurationSeconds(0)).toBe('0 seconds')
66 expect(formatDurationSeconds(0.9)).toBe('0 seconds')
67 expect(formatDurationSeconds(1)).toBe('1 second')
68 expect(formatDurationSeconds(hoursToSeconds(4380))).toBe('182 days 12 hours')
69 })
70
71 await it('Verify isValidDate()', () => {
72 expect(isValidDate(undefined)).toBe(false)
73 expect(isValidDate(-1)).toBe(true)
74 expect(isValidDate(0)).toBe(true)
75 expect(isValidDate(1)).toBe(true)
76 expect(isValidDate(-0.5)).toBe(true)
77 expect(isValidDate(0.5)).toBe(true)
78 expect(isValidDate(new Date())).toBe(true)
79 })
80
81 await it('Verify convertToDate()', () => {
82 expect(convertToDate(undefined)).toBe(undefined)
83 expect(convertToDate(null)).toBe(undefined)
84 expect(() => convertToDate('')).toThrow(new Error("Cannot convert to date: ''"))
85 expect(() => convertToDate('00:70:61')).toThrow(new Error("Cannot convert to date: '00:70:61'"))
86 expect(convertToDate(0)).toStrictEqual(new Date('1970-01-01T00:00:00.000Z'))
87 expect(convertToDate(-1)).toStrictEqual(new Date('1969-12-31T23:59:59.999Z'))
88 const dateStr = '2020-01-01T00:00:00.000Z'
89 let date = convertToDate(dateStr)
90 expect(date).toBeInstanceOf(Date)
91 expect(date).toStrictEqual(new Date(dateStr))
92 date = convertToDate(new Date(dateStr))
93 expect(date).toBeInstanceOf(Date)
94 expect(date).toStrictEqual(new Date(dateStr))
95 })
96
97 await it('Verify convertToInt()', () => {
98 expect(convertToInt(undefined)).toBe(0)
99 expect(convertToInt(null)).toBe(0)
100 expect(convertToInt(0)).toBe(0)
101 const randomInteger = randomInt(Constants.MAX_RANDOM_INTEGER)
102 expect(convertToInt(randomInteger)).toEqual(randomInteger)
103 expect(convertToInt('-1')).toBe(-1)
104 expect(convertToInt('1')).toBe(1)
105 expect(convertToInt('1.1')).toBe(1)
106 expect(convertToInt('1.9')).toBe(1)
107 expect(convertToInt('1.999')).toBe(1)
108 expect(convertToInt(-1)).toBe(-1)
109 expect(convertToInt(1)).toBe(1)
110 expect(convertToInt(1.1)).toBe(1)
111 expect(convertToInt(1.9)).toBe(1)
112 expect(convertToInt(1.999)).toBe(1)
113 expect(() => {
114 convertToInt('NaN')
115 }).toThrow("Cannot convert to integer: 'NaN'")
116 })
117
118 await it('Verify convertToFloat()', () => {
119 expect(convertToFloat(undefined)).toBe(0)
120 expect(convertToFloat(null)).toBe(0)
121 expect(convertToFloat(0)).toBe(0)
122 const randomFloat = getRandomFloat()
123 expect(convertToFloat(randomFloat)).toEqual(randomFloat)
124 expect(convertToFloat('-1')).toBe(-1)
125 expect(convertToFloat('1')).toBe(1)
126 expect(convertToFloat('1.1')).toBe(1.1)
127 expect(convertToFloat('1.9')).toBe(1.9)
128 expect(convertToFloat('1.999')).toBe(1.999)
129 expect(convertToFloat(-1)).toBe(-1)
130 expect(convertToFloat(1)).toBe(1)
131 expect(convertToFloat(1.1)).toBe(1.1)
132 expect(convertToFloat(1.9)).toBe(1.9)
133 expect(convertToFloat(1.999)).toBe(1.999)
134 expect(() => {
135 convertToFloat('NaN')
136 }).toThrow("Cannot convert to float: 'NaN'")
137 })
138
139 await it('Verify convertToBoolean()', () => {
140 expect(convertToBoolean(undefined)).toBe(false)
141 expect(convertToBoolean(null)).toBe(false)
142 expect(convertToBoolean('true')).toBe(true)
143 expect(convertToBoolean('false')).toBe(false)
144 expect(convertToBoolean('TRUE')).toBe(true)
145 expect(convertToBoolean('FALSE')).toBe(false)
146 expect(convertToBoolean('1')).toBe(true)
147 expect(convertToBoolean('0')).toBe(false)
148 expect(convertToBoolean(1)).toBe(true)
149 expect(convertToBoolean(0)).toBe(false)
150 expect(convertToBoolean(true)).toBe(true)
151 expect(convertToBoolean(false)).toBe(false)
152 expect(convertToBoolean('')).toBe(false)
153 expect(convertToBoolean('NoNBoolean')).toBe(false)
154 })
155
156 await it('Verify secureRandom()', () => {
157 const random = secureRandom()
158 expect(typeof random === 'number').toBe(true)
159 expect(random).toBeGreaterThanOrEqual(0)
160 expect(random).toBeLessThan(1)
161 })
162
163 await it('Verify roundTo()', () => {
164 expect(roundTo(0, 2)).toBe(0)
165 expect(roundTo(0.5, 0)).toBe(1)
166 expect(roundTo(0.5, 2)).toBe(0.5)
167 expect(roundTo(-0.5, 0)).toBe(-1)
168 expect(roundTo(-0.5, 2)).toBe(-0.5)
169 expect(roundTo(1.005, 0)).toBe(1)
170 expect(roundTo(1.005, 2)).toBe(1.01)
171 expect(roundTo(2.175, 2)).toBe(2.18)
172 expect(roundTo(5.015, 2)).toBe(5.02)
173 expect(roundTo(-1.005, 2)).toBe(-1.01)
174 expect(roundTo(-2.175, 2)).toBe(-2.18)
175 expect(roundTo(-5.015, 2)).toBe(-5.02)
176 })
177
178 await it('Verify getRandomFloat()', () => {
179 let randomFloat = getRandomFloat()
180 expect(typeof randomFloat === 'number').toBe(true)
181 expect(randomFloat).toBeGreaterThanOrEqual(0)
182 expect(randomFloat).toBeLessThanOrEqual(Number.MAX_VALUE)
183 expect(randomFloat).not.toEqual(getRandomFloat())
184 expect(() => getRandomFloat(0, 1)).toThrow(new RangeError('Invalid interval'))
185 expect(() => getRandomFloat(Number.MAX_VALUE, -Number.MAX_VALUE)).toThrow(
186 new RangeError('Invalid interval')
187 )
188 randomFloat = getRandomFloat(0, -Number.MAX_VALUE)
189 expect(randomFloat).toBeGreaterThanOrEqual(-Number.MAX_VALUE)
190 expect(randomFloat).toBeLessThanOrEqual(0)
191 })
192
193 await it('Verify extractTimeSeriesValues()', () => {
194 expect(
195 extractTimeSeriesValues(
196 new CircularBuffer<TimestampedData>(Array, Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY)
197 )
198 ).toEqual([])
199 const circularBuffer = new CircularBuffer<TimestampedData>(
200 Array,
201 Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY
202 )
203 circularBuffer.push({ timestamp: Date.now(), value: 1.1 })
204 circularBuffer.push({ timestamp: Date.now(), value: 2.2 })
205 circularBuffer.push({ timestamp: Date.now(), value: 3.3 })
206 expect(extractTimeSeriesValues(circularBuffer)).toEqual([1.1, 2.2, 3.3])
207 })
208
209 await it('Verify isObject()', () => {
210 expect(isObject('test')).toBe(false)
211 expect(isObject(undefined)).toBe(false)
212 expect(isObject(null)).toBe(false)
213 expect(isObject(0)).toBe(false)
214 expect(isObject([])).toBe(false)
215 expect(isObject([0, 1])).toBe(false)
216 expect(isObject(['0', '1'])).toBe(false)
217 expect(isObject({})).toBe(true)
218 expect(isObject({ 1: 1 })).toBe(true)
219 expect(isObject({ 1: '1' })).toBe(true)
220 expect(isObject(new Map())).toBe(true)
221 expect(isObject(new Set())).toBe(true)
222 expect(isObject(new WeakMap())).toBe(true)
223 expect(isObject(new WeakSet())).toBe(true)
224 })
225
226 await it('Verify isAsyncFunction()', () => {
227 expect(isAsyncFunction(null)).toBe(false)
228 expect(isAsyncFunction(undefined)).toBe(false)
229 expect(isAsyncFunction(true)).toBe(false)
230 expect(isAsyncFunction(false)).toBe(false)
231 expect(isAsyncFunction(0)).toBe(false)
232 expect(isAsyncFunction('')).toBe(false)
233 expect(isAsyncFunction([])).toBe(false)
234 expect(isAsyncFunction(new Date())).toBe(false)
235 // eslint-disable-next-line prefer-regex-literals
236 expect(isAsyncFunction(/[a-z]/i)).toBe(false)
237 expect(isAsyncFunction(new Error())).toBe(false)
238 expect(isAsyncFunction(new Map())).toBe(false)
239 expect(isAsyncFunction(new Set())).toBe(false)
240 expect(isAsyncFunction(new WeakMap())).toBe(false)
241 expect(isAsyncFunction(new WeakSet())).toBe(false)
242 expect(isAsyncFunction(new Int8Array())).toBe(false)
243 expect(isAsyncFunction(new Uint8Array())).toBe(false)
244 expect(isAsyncFunction(new Uint8ClampedArray())).toBe(false)
245 expect(isAsyncFunction(new Int16Array())).toBe(false)
246 expect(isAsyncFunction(new Uint16Array())).toBe(false)
247 expect(isAsyncFunction(new Int32Array())).toBe(false)
248 expect(isAsyncFunction(new Uint32Array())).toBe(false)
249 expect(isAsyncFunction(new Float32Array())).toBe(false)
250 expect(isAsyncFunction(new Float64Array())).toBe(false)
251 expect(isAsyncFunction(new BigInt64Array())).toBe(false)
252 expect(isAsyncFunction(new BigUint64Array())).toBe(false)
253 // eslint-disable-next-line @typescript-eslint/no-empty-function
254 expect(isAsyncFunction(new Promise(() => {}))).toBe(false)
255 expect(isAsyncFunction(new WeakRef({}))).toBe(false)
256 // eslint-disable-next-line @typescript-eslint/no-empty-function
257 expect(isAsyncFunction(new FinalizationRegistry(() => {}))).toBe(false)
258 expect(isAsyncFunction(new ArrayBuffer(16))).toBe(false)
259 expect(isAsyncFunction(new SharedArrayBuffer(16))).toBe(false)
260 expect(isAsyncFunction(new DataView(new ArrayBuffer(16)))).toBe(false)
261 expect(isAsyncFunction({})).toBe(false)
262 expect(isAsyncFunction({ a: 1 })).toBe(false)
263 // eslint-disable-next-line @typescript-eslint/no-empty-function
264 expect(isAsyncFunction(() => {})).toBe(false)
265 // eslint-disable-next-line @typescript-eslint/no-empty-function
266 expect(isAsyncFunction(function () {})).toBe(false)
267 // eslint-disable-next-line @typescript-eslint/no-empty-function
268 expect(isAsyncFunction(function named () {})).toBe(false)
269 // eslint-disable-next-line @typescript-eslint/no-empty-function
270 expect(isAsyncFunction(async () => {})).toBe(true)
271 // eslint-disable-next-line @typescript-eslint/no-empty-function
272 expect(isAsyncFunction(async function () {})).toBe(true)
273 // eslint-disable-next-line @typescript-eslint/no-empty-function
274 expect(isAsyncFunction(async function named () {})).toBe(true)
275 class TestClass {
276 // eslint-disable-next-line @typescript-eslint/no-empty-function
277 public testSync (): void {}
278 // eslint-disable-next-line @typescript-eslint/no-empty-function
279 public async testAsync (): Promise<void> {}
280 // eslint-disable-next-line @typescript-eslint/no-empty-function
281 public testArrowSync = (): void => {}
282 // eslint-disable-next-line @typescript-eslint/no-empty-function
283 public testArrowAsync = async (): Promise<void> => {}
284 // eslint-disable-next-line @typescript-eslint/no-empty-function
285 public static testStaticSync (): void {}
286 // eslint-disable-next-line @typescript-eslint/no-empty-function
287 public static async testStaticAsync (): Promise<void> {}
288 }
289 const testClass = new TestClass()
290 // eslint-disable-next-line @typescript-eslint/unbound-method
291 expect(isAsyncFunction(testClass.testSync)).toBe(false)
292 // eslint-disable-next-line @typescript-eslint/unbound-method
293 expect(isAsyncFunction(testClass.testAsync)).toBe(true)
294 expect(isAsyncFunction(testClass.testArrowSync)).toBe(false)
295 expect(isAsyncFunction(testClass.testArrowAsync)).toBe(true)
296 // eslint-disable-next-line @typescript-eslint/unbound-method
297 expect(isAsyncFunction(TestClass.testStaticSync)).toBe(false)
298 // eslint-disable-next-line @typescript-eslint/unbound-method
299 expect(isAsyncFunction(TestClass.testStaticAsync)).toBe(true)
300 })
301
302 await it('Verify clone()', () => {
303 const obj = { 1: 1 }
304 expect(clone(obj)).toStrictEqual(obj)
305 expect(clone(obj) === obj).toBe(false)
306 const nestedObj = { 1: obj, 2: obj }
307 expect(clone(nestedObj)).toStrictEqual(nestedObj)
308 expect(clone(nestedObj) === nestedObj).toBe(false)
309 const array = [1, 2]
310 expect(clone(array)).toStrictEqual(array)
311 expect(clone(array) === array).toBe(false)
312 const objArray = [obj, obj]
313 expect(clone(objArray)).toStrictEqual(objArray)
314 expect(clone(objArray) === objArray).toBe(false)
315 const date = new Date()
316 expect(clone(date)).toStrictEqual(date)
317 expect(clone(date) === date).toBe(false)
318 if (satisfies(version, '>=21.0.0')) {
319 const url = new URL('https://domain.tld')
320 expect(() => clone(url)).toThrowError(new Error('Cannot clone object of unsupported type.'))
321 }
322 const map = new Map([['1', '2']])
323 expect(clone(map)).toStrictEqual(map)
324 expect(clone(map) === map).toBe(false)
325 const set = new Set(['1'])
326 expect(clone(set)).toStrictEqual(set)
327 expect(clone(set) === set).toBe(false)
328 const weakMap = new WeakMap([[{ 1: 1 }, { 2: 2 }]])
329 expect(() => clone(weakMap)).toThrowError(new Error('#<WeakMap> could not be cloned.'))
330 const weakSet = new WeakSet([{ 1: 1 }, { 2: 2 }])
331 expect(() => clone(weakSet)).toThrowError(new Error('#<WeakSet> could not be cloned.'))
332 })
333
334 await it('Verify hasOwnProp()', () => {
335 expect(hasOwnProp('test', '')).toBe(false)
336 expect(hasOwnProp(undefined, '')).toBe(false)
337 expect(hasOwnProp(null, '')).toBe(false)
338 expect(hasOwnProp([], '')).toBe(false)
339 expect(hasOwnProp({}, '')).toBe(false)
340 expect(hasOwnProp({ 1: 1 }, 1)).toBe(true)
341 expect(hasOwnProp({ 1: 1 }, '1')).toBe(true)
342 expect(hasOwnProp({ 1: 1 }, 2)).toBe(false)
343 expect(hasOwnProp({ 1: 1 }, '2')).toBe(false)
344 expect(hasOwnProp({ 1: '1' }, '1')).toBe(true)
345 expect(hasOwnProp({ 1: '1' }, 1)).toBe(true)
346 expect(hasOwnProp({ 1: '1' }, '2')).toBe(false)
347 expect(hasOwnProp({ 1: '1' }, 2)).toBe(false)
348 })
349
350 await it('Verify isNotEmptyString()', () => {
351 expect(isNotEmptyString('')).toBe(false)
352 expect(isNotEmptyString(' ')).toBe(false)
353 expect(isNotEmptyString(' ')).toBe(false)
354 expect(isNotEmptyString('test')).toBe(true)
355 expect(isNotEmptyString(' test')).toBe(true)
356 expect(isNotEmptyString('test ')).toBe(true)
357 expect(isNotEmptyString(undefined)).toBe(false)
358 expect(isNotEmptyString(null)).toBe(false)
359 expect(isNotEmptyString(0)).toBe(false)
360 expect(isNotEmptyString({})).toBe(false)
361 expect(isNotEmptyString([])).toBe(false)
362 expect(isNotEmptyString(new Map())).toBe(false)
363 expect(isNotEmptyString(new Set())).toBe(false)
364 expect(isNotEmptyString(new WeakMap())).toBe(false)
365 expect(isNotEmptyString(new WeakSet())).toBe(false)
366 })
367
368 await it('Verify isNotEmptyArray()', () => {
369 expect(isNotEmptyArray([])).toBe(false)
370 expect(isNotEmptyArray([1, 2])).toBe(true)
371 expect(isNotEmptyArray(['1', '2'])).toBe(true)
372 expect(isNotEmptyArray(undefined)).toBe(false)
373 expect(isNotEmptyArray(null)).toBe(false)
374 expect(isNotEmptyArray('')).toBe(false)
375 expect(isNotEmptyArray('test')).toBe(false)
376 expect(isNotEmptyArray(0)).toBe(false)
377 expect(isNotEmptyArray({})).toBe(false)
378 expect(isNotEmptyArray(new Map())).toBe(false)
379 expect(isNotEmptyArray(new Set())).toBe(false)
380 expect(isNotEmptyArray(new WeakMap())).toBe(false)
381 expect(isNotEmptyArray(new WeakSet())).toBe(false)
382 })
383
384 await it('Verify insertAt()', () => {
385 expect(insertAt('test', 'ing', 'test'.length)).toBe('testing')
386 expect(insertAt('test', 'ing', 2)).toBe('teingst')
387 })
388
389 await it('Verify isArraySorted()', () => {
390 expect(
391 isArraySorted([], (a, b) => {
392 return a - b
393 })
394 ).toBe(true)
395 expect(
396 isArraySorted([1], (a, b) => {
397 return a - b
398 })
399 ).toBe(true)
400 expect(isArraySorted<number>([1, 2, 3, 4, 5], (a, b) => a - b)).toBe(true)
401 expect(isArraySorted<number>([1, 2, 3, 5, 4], (a, b) => a - b)).toBe(false)
402 expect(isArraySorted<number>([2, 1, 3, 4, 5], (a, b) => a - b)).toBe(false)
403 })
404})