refactor: remove isUndefined() helper
[e-mobility-charging-stations-simulator.git] / tests / utils / Utils.test.ts
CommitLineData
66a7748d 1import { describe, it } from 'node:test'
6c43b441 2
66a7748d
JB
3import { hoursToMilliseconds, hoursToSeconds } from 'date-fns'
4import { expect } from 'expect'
a2111e8d 5
66a7748d 6import { Constants } from '../../src/utils/Constants.js'
9bf0ef23
JB
7import {
8 cloneObject,
9 convertToBoolean,
10 convertToDate,
11 convertToFloat,
12 convertToInt,
1553f6df 13 extractTimeSeriesValues,
be4c6702 14 formatDurationMilliSeconds,
8053c842 15 formatDurationSeconds,
9bf0ef23
JB
16 generateUUID,
17 getRandomFloat,
18 getRandomInteger,
19 hasOwnProp,
80c58041 20 isArraySorted,
9bf0ef23
JB
21 isEmptyArray,
22 isEmptyObject,
23 isEmptyString,
24 isIterable,
25 isNotEmptyArray,
26 isNotEmptyString,
9bf0ef23 27 isObject,
0bd926c1 28 isValidTime,
5adf6ca4
JB
29 max,
30 min,
5f742aac 31 once,
9bf0ef23
JB
32 roundTo,
33 secureRandom,
34 sleep,
66a7748d
JB
35 validateUUID
36} from '../../src/utils/Utils.js'
a2111e8d 37
6c43b441
JB
38await describe('Utils test suite', async () => {
39 await it('Verify generateUUID()/validateUUID()', () => {
66a7748d
JB
40 const uuid = generateUUID()
41 expect(uuid).toBeDefined()
42 expect(uuid.length).toEqual(36)
43 expect(validateUUID(uuid)).toBe(true)
44 expect(validateUUID('abcdef00-0000-4000-0000-000000000000')).toBe(true)
45 expect(validateUUID('')).toBe(false)
878e026c 46 // Shall invalidate Nil UUID
66a7748d
JB
47 expect(validateUUID('00000000-0000-0000-0000-000000000000')).toBe(false)
48 expect(validateUUID('987FBC9-4BED-3078-CF07A-9141BA07C9F3')).toBe(false)
49 })
8bd02502 50
6c43b441 51 await it('Verify sleep()', async () => {
66a7748d
JB
52 const start = performance.now()
53 await sleep(1000)
54 const stop = performance.now()
55 expect(stop - start).toBeGreaterThanOrEqual(1000)
56 })
45999aab 57
6c43b441 58 await it('Verify formatDurationMilliSeconds()', () => {
66a7748d
JB
59 expect(formatDurationMilliSeconds(0)).toBe('0 seconds')
60 expect(formatDurationMilliSeconds(900)).toBe('0 seconds')
61 expect(formatDurationMilliSeconds(1000)).toBe('1 second')
62 expect(formatDurationMilliSeconds(hoursToMilliseconds(4380))).toBe('182 days 12 hours')
63 })
be4c6702 64
6c43b441 65 await it('Verify formatDurationSeconds()', () => {
66a7748d
JB
66 expect(formatDurationSeconds(0)).toBe('0 seconds')
67 expect(formatDurationSeconds(0.9)).toBe('0 seconds')
68 expect(formatDurationSeconds(1)).toBe('1 second')
69 expect(formatDurationSeconds(hoursToSeconds(4380))).toBe('182 days 12 hours')
70 })
8053c842 71
6c43b441 72 await it('Verify isValidTime()', () => {
66a7748d
JB
73 expect(isValidTime(undefined)).toBe(false)
74 expect(isValidTime(null)).toBe(false)
75 expect(isValidTime('')).toBe(false)
76 expect(isValidTime({})).toBe(false)
77 expect(isValidTime([])).toBe(false)
78 expect(isValidTime(new Map())).toBe(false)
79 expect(isValidTime(new Set())).toBe(false)
80 expect(isValidTime(new WeakMap())).toBe(false)
81 expect(isValidTime(new WeakSet())).toBe(false)
82 expect(isValidTime(-1)).toBe(true)
83 expect(isValidTime(0)).toBe(true)
84 expect(isValidTime(1)).toBe(true)
85 expect(isValidTime(-0.5)).toBe(true)
86 expect(isValidTime(0.5)).toBe(true)
87 expect(isValidTime(new Date())).toBe(true)
88 })
ac8178a4 89
6c43b441 90 await it('Verify convertToDate()', () => {
66a7748d
JB
91 expect(convertToDate(undefined)).toBe(undefined)
92 expect(convertToDate(null)).toBe(null)
93 expect(() => convertToDate('')).toThrow(new Error("Cannot convert to date: ''"))
94 expect(() => convertToDate('00:70:61')).toThrow(new Error("Cannot convert to date: '00:70:61'"))
95 expect(convertToDate(0)).toStrictEqual(new Date('1970-01-01T00:00:00.000Z'))
96 expect(convertToDate(-1)).toStrictEqual(new Date('1969-12-31T23:59:59.999Z'))
97 const dateStr = '2020-01-01T00:00:00.000Z'
98 let date = convertToDate(dateStr)
99 expect(date).toBeInstanceOf(Date)
100 expect(date).toStrictEqual(new Date(dateStr))
101 date = convertToDate(new Date(dateStr))
102 expect(date).toBeInstanceOf(Date)
103 expect(date).toStrictEqual(new Date(dateStr))
104 })
df645d8f 105
6c43b441 106 await it('Verify convertToInt()', () => {
66a7748d
JB
107 expect(convertToInt(undefined)).toBe(0)
108 expect(convertToInt(null)).toBe(0)
109 expect(convertToInt(0)).toBe(0)
110 const randomInteger = getRandomInteger()
111 expect(convertToInt(randomInteger)).toEqual(randomInteger)
112 expect(convertToInt('-1')).toBe(-1)
113 expect(convertToInt('1')).toBe(1)
114 expect(convertToInt('1.1')).toBe(1)
115 expect(convertToInt('1.9')).toBe(1)
116 expect(convertToInt('1.999')).toBe(1)
117 expect(convertToInt(-1)).toBe(-1)
118 expect(convertToInt(1)).toBe(1)
119 expect(convertToInt(1.1)).toBe(1)
120 expect(convertToInt(1.9)).toBe(1)
121 expect(convertToInt(1.999)).toBe(1)
878e026c 122 expect(() => {
66a7748d
JB
123 convertToInt('NaN')
124 }).toThrow("Cannot convert to integer: 'NaN'")
125 })
df645d8f 126
6c43b441 127 await it('Verify convertToFloat()', () => {
66a7748d
JB
128 expect(convertToFloat(undefined)).toBe(0)
129 expect(convertToFloat(null)).toBe(0)
130 expect(convertToFloat(0)).toBe(0)
131 const randomFloat = getRandomFloat()
132 expect(convertToFloat(randomFloat)).toEqual(randomFloat)
133 expect(convertToFloat('-1')).toBe(-1)
134 expect(convertToFloat('1')).toBe(1)
135 expect(convertToFloat('1.1')).toBe(1.1)
136 expect(convertToFloat('1.9')).toBe(1.9)
137 expect(convertToFloat('1.999')).toBe(1.999)
138 expect(convertToFloat(-1)).toBe(-1)
139 expect(convertToFloat(1)).toBe(1)
140 expect(convertToFloat(1.1)).toBe(1.1)
141 expect(convertToFloat(1.9)).toBe(1.9)
142 expect(convertToFloat(1.999)).toBe(1.999)
878e026c 143 expect(() => {
66a7748d
JB
144 convertToFloat('NaN')
145 }).toThrow("Cannot convert to float: 'NaN'")
146 })
df645d8f 147
6c43b441 148 await it('Verify convertToBoolean()', () => {
66a7748d
JB
149 expect(convertToBoolean(undefined)).toBe(false)
150 expect(convertToBoolean(null)).toBe(false)
151 expect(convertToBoolean('true')).toBe(true)
152 expect(convertToBoolean('false')).toBe(false)
153 expect(convertToBoolean('TRUE')).toBe(true)
154 expect(convertToBoolean('FALSE')).toBe(false)
155 expect(convertToBoolean('1')).toBe(true)
156 expect(convertToBoolean('0')).toBe(false)
157 expect(convertToBoolean(1)).toBe(true)
158 expect(convertToBoolean(0)).toBe(false)
159 expect(convertToBoolean(true)).toBe(true)
160 expect(convertToBoolean(false)).toBe(false)
161 expect(convertToBoolean('')).toBe(false)
162 expect(convertToBoolean('NoNBoolean')).toBe(false)
163 })
df645d8f 164
6c43b441 165 await it('Verify secureRandom()', () => {
66a7748d
JB
166 const random = secureRandom()
167 expect(typeof random === 'number').toBe(true)
168 expect(random).toBeGreaterThanOrEqual(0)
169 expect(random).toBeLessThan(1)
170 })
a2111e8d 171
6c43b441 172 await it('Verify getRandomInteger()', () => {
66a7748d
JB
173 let randomInteger = getRandomInteger()
174 expect(Number.isSafeInteger(randomInteger)).toBe(true)
175 expect(randomInteger).toBeGreaterThanOrEqual(0)
176 expect(randomInteger).toBeLessThanOrEqual(Constants.MAX_RANDOM_INTEGER)
177 expect(randomInteger).not.toEqual(getRandomInteger())
178 randomInteger = getRandomInteger(0, -Constants.MAX_RANDOM_INTEGER)
179 expect(randomInteger).toBeGreaterThanOrEqual(-Constants.MAX_RANDOM_INTEGER)
180 expect(randomInteger).toBeLessThanOrEqual(0)
68f56fdf 181 expect(() => getRandomInteger(0, 1)).toThrow(
66a7748d
JB
182 'The value of "max" is out of range. It must be greater than the value of "min" (1). Received 1'
183 )
68f56fdf 184 expect(() => getRandomInteger(-1)).toThrow(
66a7748d
JB
185 'The value of "max" is out of range. It must be greater than the value of "min" (0). Received 0'
186 )
68f56fdf 187 expect(() => getRandomInteger(Constants.MAX_RANDOM_INTEGER + 1)).toThrow(
878e026c
JB
188 `The value of "max" is out of range. It must be <= ${
189 Constants.MAX_RANDOM_INTEGER + 1
66a7748d
JB
190 }. Received 281_474_976_710_656`
191 )
192 randomInteger = getRandomInteger(2, 1)
193 expect(randomInteger).toBeGreaterThanOrEqual(1)
194 expect(randomInteger).toBeLessThanOrEqual(2)
195 const maximum = 2.2
196 const minimum = 1.1
197 randomInteger = getRandomInteger(maximum, minimum)
198 expect(randomInteger).toBeLessThanOrEqual(Math.floor(maximum))
199 expect(randomInteger).toBeGreaterThanOrEqual(Math.ceil(minimum))
200 })
a2111e8d 201
6c43b441 202 await it('Verify roundTo()', () => {
66a7748d
JB
203 expect(roundTo(0, 2)).toBe(0)
204 expect(roundTo(0.5, 0)).toBe(1)
205 expect(roundTo(0.5, 2)).toBe(0.5)
206 expect(roundTo(-0.5, 0)).toBe(-1)
207 expect(roundTo(-0.5, 2)).toBe(-0.5)
208 expect(roundTo(1.005, 0)).toBe(1)
209 expect(roundTo(1.005, 2)).toBe(1.01)
210 expect(roundTo(2.175, 2)).toBe(2.18)
211 expect(roundTo(5.015, 2)).toBe(5.02)
212 expect(roundTo(-1.005, 2)).toBe(-1.01)
213 expect(roundTo(-2.175, 2)).toBe(-2.18)
214 expect(roundTo(-5.015, 2)).toBe(-5.02)
215 })
316d1564 216
6c43b441 217 await it('Verify getRandomFloat()', () => {
66a7748d
JB
218 let randomFloat = getRandomFloat()
219 expect(typeof randomFloat === 'number').toBe(true)
220 expect(randomFloat).toBeGreaterThanOrEqual(0)
221 expect(randomFloat).toBeLessThanOrEqual(Number.MAX_VALUE)
222 expect(randomFloat).not.toEqual(getRandomFloat())
223 expect(() => getRandomFloat(0, 1)).toThrow(new RangeError('Invalid interval'))
68f56fdf 224 expect(() => getRandomFloat(Number.MAX_VALUE, -Number.MAX_VALUE)).toThrow(
66a7748d
JB
225 new RangeError('Invalid interval')
226 )
227 randomFloat = getRandomFloat(0, -Number.MAX_VALUE)
228 expect(randomFloat).toBeGreaterThanOrEqual(-Number.MAX_VALUE)
229 expect(randomFloat).toBeLessThanOrEqual(0)
230 })
a2111e8d 231
6c43b441 232 await it('Verify extractTimeSeriesValues()', () => {
66a7748d
JB
233 expect(extractTimeSeriesValues([])).toEqual([])
234 expect(extractTimeSeriesValues([{ timestamp: Date.now(), value: 1.1 }])).toEqual([1.1])
1553f6df
JB
235 expect(
236 extractTimeSeriesValues([
237 { timestamp: Date.now(), value: 1.1 },
66a7748d
JB
238 { timestamp: Date.now(), value: 2.2 }
239 ])
240 ).toEqual([1.1, 2.2])
241 })
1553f6df 242
6c43b441 243 await it('Verify isObject()', () => {
66a7748d
JB
244 expect(isObject('test')).toBe(false)
245 expect(isObject(undefined)).toBe(false)
246 expect(isObject(null)).toBe(false)
247 expect(isObject(0)).toBe(false)
248 expect(isObject([])).toBe(false)
249 expect(isObject([0, 1])).toBe(false)
250 expect(isObject(['0', '1'])).toBe(false)
251 expect(isObject({})).toBe(true)
252 expect(isObject({ 1: 1 })).toBe(true)
253 expect(isObject({ 1: '1' })).toBe(true)
254 expect(isObject(new Map())).toBe(true)
255 expect(isObject(new Set())).toBe(true)
256 expect(isObject(new WeakMap())).toBe(true)
257 expect(isObject(new WeakSet())).toBe(true)
258 })
a2111e8d 259
6c43b441 260 await it('Verify cloneObject()', () => {
66a7748d
JB
261 const obj = { 1: 1 }
262 expect(cloneObject(obj)).toStrictEqual(obj)
263 expect(cloneObject(obj) === obj).toBe(false)
264 const nestedObj = { 1: obj, 2: obj }
265 expect(cloneObject(nestedObj)).toStrictEqual(nestedObj)
266 expect(cloneObject(nestedObj) === nestedObj).toBe(false)
267 const array = [1, 2]
268 expect(cloneObject(array)).toStrictEqual(array)
269 expect(cloneObject(array) === array).toBe(false)
270 const objArray = [obj, obj]
271 expect(cloneObject(objArray)).toStrictEqual(objArray)
272 expect(cloneObject(objArray) === objArray).toBe(false)
273 const date = new Date()
274 expect(cloneObject(date)).toStrictEqual(date)
275 expect(cloneObject(date) === date).toBe(false)
276 const map = new Map([['1', '2']])
277 expect(cloneObject(map)).toStrictEqual({})
278 const set = new Set(['1'])
279 expect(cloneObject(set)).toStrictEqual({})
dd5a1d6c 280 // The URL object seems to have not enumerable properties
66a7748d
JB
281 const url = new URL('https://domain.tld')
282 expect(cloneObject(url)).toStrictEqual({})
283 const weakMap = new WeakMap([[{ 1: 1 }, { 2: 2 }]])
284 expect(cloneObject(weakMap)).toStrictEqual({})
285 const weakSet = new WeakSet([{ 1: 1 }, { 2: 2 }])
286 expect(cloneObject(weakSet)).toStrictEqual({})
287 })
dd5a1d6c 288
6c43b441 289 await it('Verify hasOwnProp()', () => {
66a7748d
JB
290 expect(hasOwnProp('test', '')).toBe(false)
291 expect(hasOwnProp(undefined, '')).toBe(false)
292 expect(hasOwnProp(null, '')).toBe(false)
293 expect(hasOwnProp([], '')).toBe(false)
294 expect(hasOwnProp({}, '')).toBe(false)
295 expect(hasOwnProp({ 1: 1 }, 1)).toBe(true)
296 expect(hasOwnProp({ 1: 1 }, '1')).toBe(true)
297 expect(hasOwnProp({ 1: 1 }, 2)).toBe(false)
298 expect(hasOwnProp({ 1: 1 }, '2')).toBe(false)
299 expect(hasOwnProp({ 1: '1' }, '1')).toBe(true)
300 expect(hasOwnProp({ 1: '1' }, 1)).toBe(true)
301 expect(hasOwnProp({ 1: '1' }, '2')).toBe(false)
302 expect(hasOwnProp({ 1: '1' }, 2)).toBe(false)
303 })
af29b598 304
6c43b441 305 await it('Verify isIterable()', () => {
66a7748d
JB
306 expect(isIterable('')).toBe(true)
307 expect(isIterable(' ')).toBe(true)
308 expect(isIterable('test')).toBe(true)
309 expect(isIterable(undefined)).toBe(false)
310 expect(isIterable(null)).toBe(false)
311 expect(isIterable(0)).toBe(false)
312 expect(isIterable([0, 1])).toBe(true)
313 expect(isIterable({ 1: 1 })).toBe(false)
314 expect(isIterable(new Map())).toBe(true)
315 expect(isIterable(new Set())).toBe(true)
316 expect(isIterable(new WeakMap())).toBe(false)
317 expect(isIterable(new WeakSet())).toBe(false)
318 })
a2111e8d 319
6c43b441 320 await it('Verify isEmptyString()', () => {
66a7748d
JB
321 expect(isEmptyString('')).toBe(true)
322 expect(isEmptyString(' ')).toBe(true)
323 expect(isEmptyString(' ')).toBe(true)
324 expect(isEmptyString('test')).toBe(false)
325 expect(isEmptyString(' test')).toBe(false)
326 expect(isEmptyString('test ')).toBe(false)
327 expect(isEmptyString(undefined)).toBe(true)
328 expect(isEmptyString(null)).toBe(true)
329 expect(isEmptyString(0)).toBe(false)
330 expect(isEmptyString({})).toBe(false)
331 expect(isEmptyString([])).toBe(false)
332 expect(isEmptyString(new Map())).toBe(false)
333 expect(isEmptyString(new Set())).toBe(false)
334 expect(isEmptyString(new WeakMap())).toBe(false)
335 expect(isEmptyString(new WeakSet())).toBe(false)
336 })
5a2a53cf 337
6c43b441 338 await it('Verify isNotEmptyString()', () => {
66a7748d
JB
339 expect(isNotEmptyString('')).toBe(false)
340 expect(isNotEmptyString(' ')).toBe(false)
341 expect(isNotEmptyString(' ')).toBe(false)
342 expect(isNotEmptyString('test')).toBe(true)
343 expect(isNotEmptyString(' test')).toBe(true)
344 expect(isNotEmptyString('test ')).toBe(true)
345 expect(isNotEmptyString(undefined)).toBe(false)
346 expect(isNotEmptyString(null)).toBe(false)
347 expect(isNotEmptyString(0)).toBe(false)
348 expect(isNotEmptyString({})).toBe(false)
349 expect(isNotEmptyString([])).toBe(false)
350 expect(isNotEmptyString(new Map())).toBe(false)
351 expect(isNotEmptyString(new Set())).toBe(false)
352 expect(isNotEmptyString(new WeakMap())).toBe(false)
353 expect(isNotEmptyString(new WeakSet())).toBe(false)
354 })
429f8c9d 355
6c43b441 356 await it('Verify isEmptyArray()', () => {
66a7748d
JB
357 expect(isEmptyArray([])).toBe(true)
358 expect(isEmptyArray([1, 2])).toBe(false)
359 expect(isEmptyArray(['1', '2'])).toBe(false)
360 expect(isEmptyArray(undefined)).toBe(false)
361 expect(isEmptyArray(null)).toBe(false)
362 expect(isEmptyArray('')).toBe(false)
363 expect(isEmptyArray('test')).toBe(false)
364 expect(isEmptyArray(0)).toBe(false)
365 expect(isEmptyArray({})).toBe(false)
366 expect(isEmptyArray(new Map())).toBe(false)
367 expect(isEmptyArray(new Set())).toBe(false)
368 expect(isEmptyArray(new WeakMap())).toBe(false)
369 expect(isEmptyArray(new WeakSet())).toBe(false)
370 })
a2111e8d 371
6c43b441 372 await it('Verify isNotEmptyArray()', () => {
66a7748d
JB
373 expect(isNotEmptyArray([])).toBe(false)
374 expect(isNotEmptyArray([1, 2])).toBe(true)
375 expect(isNotEmptyArray(['1', '2'])).toBe(true)
376 expect(isNotEmptyArray(undefined)).toBe(false)
377 expect(isNotEmptyArray(null)).toBe(false)
378 expect(isNotEmptyArray('')).toBe(false)
379 expect(isNotEmptyArray('test')).toBe(false)
380 expect(isNotEmptyArray(0)).toBe(false)
381 expect(isNotEmptyArray({})).toBe(false)
382 expect(isNotEmptyArray(new Map())).toBe(false)
383 expect(isNotEmptyArray(new Set())).toBe(false)
384 expect(isNotEmptyArray(new WeakMap())).toBe(false)
385 expect(isNotEmptyArray(new WeakSet())).toBe(false)
386 })
878e026c 387
6c43b441 388 await it('Verify isEmptyObject()', () => {
66a7748d
JB
389 expect(isEmptyObject({})).toBe(true)
390 expect(isEmptyObject({ 1: 1, 2: 2 })).toBe(false)
391 expect(isEmptyObject(new Map())).toBe(false)
392 expect(isEmptyObject(new Set())).toBe(false)
393 expect(isEmptyObject(new WeakMap())).toBe(false)
394 expect(isEmptyObject(new WeakSet())).toBe(false)
395 })
80c58041 396
6c43b441 397 await it('Verify isArraySorted()', () => {
80c58041
JB
398 expect(
399 isArraySorted([], (a, b) => {
66a7748d
JB
400 return a - b
401 })
402 ).toBe(true)
80c58041
JB
403 expect(
404 isArraySorted([1], (a, b) => {
66a7748d
JB
405 return a - b
406 })
407 ).toBe(true)
408 expect(isArraySorted<number>([1, 2, 3, 4, 5], (a, b) => a - b)).toBe(true)
409 expect(isArraySorted<number>([1, 2, 3, 5, 4], (a, b) => a - b)).toBe(false)
410 expect(isArraySorted<number>([2, 1, 3, 4, 5], (a, b) => a - b)).toBe(false)
411 })
5f742aac 412
6c43b441 413 await it('Verify once()', () => {
66a7748d
JB
414 let called = 0
415 const fn = (): number => ++called
416 const onceFn = once(fn, this)
417 const result1 = onceFn()
418 expect(called).toBe(1)
419 expect(result1).toBe(1)
420 const result2 = onceFn()
421 expect(called).toBe(1)
422 expect(result2).toBe(1)
423 const result3 = onceFn()
424 expect(called).toBe(1)
425 expect(result3).toBe(1)
426 })
5adf6ca4 427
6c43b441 428 await it('Verify min()', () => {
66a7748d
JB
429 expect(min()).toBe(Infinity)
430 expect(min(0, 1)).toBe(0)
431 expect(min(1, 0)).toBe(0)
432 expect(min(0, -1)).toBe(-1)
433 expect(min(-1, 0)).toBe(-1)
434 })
5adf6ca4 435
6c43b441 436 await it('Verify max()', () => {
66a7748d
JB
437 expect(max()).toBe(-Infinity)
438 expect(max(0, 1)).toBe(1)
439 expect(max(1, 0)).toBe(1)
440 expect(max(0, -1)).toBe(0)
441 expect(max(-1, 0)).toBe(0)
442 })
443})