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