refactor: rename cloneObject() -> clone()
[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 7import {
40615072 8 clone,
9bf0ef23
JB
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,
9bf0ef23
JB
24 isNotEmptyArray,
25 isNotEmptyString,
9bf0ef23 26 isObject,
5dc7c990 27 isValidDate,
5adf6ca4
JB
28 max,
29 min,
5f742aac 30 once,
9bf0ef23
JB
31 roundTo,
32 secureRandom,
33 sleep,
66a7748d
JB
34 validateUUID
35} from '../../src/utils/Utils.js'
a2111e8d 36
6c43b441
JB
37await describe('Utils test suite', async () => {
38 await it('Verify generateUUID()/validateUUID()', () => {
66a7748d
JB
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)
878e026c 45 // Shall invalidate Nil UUID
66a7748d
JB
46 expect(validateUUID('00000000-0000-0000-0000-000000000000')).toBe(false)
47 expect(validateUUID('987FBC9-4BED-3078-CF07A-9141BA07C9F3')).toBe(false)
48 })
8bd02502 49
6c43b441 50 await it('Verify sleep()', async () => {
66a7748d
JB
51 const start = performance.now()
52 await sleep(1000)
53 const stop = performance.now()
54 expect(stop - start).toBeGreaterThanOrEqual(1000)
55 })
45999aab 56
6c43b441 57 await it('Verify formatDurationMilliSeconds()', () => {
66a7748d
JB
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 })
be4c6702 63
6c43b441 64 await it('Verify formatDurationSeconds()', () => {
66a7748d
JB
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 })
8053c842 70
40615072 71 await it('Verify isValidDate()', () => {
5dc7c990
JB
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)
66a7748d 79 })
ac8178a4 80
6c43b441 81 await it('Verify convertToDate()', () => {
66a7748d
JB
82 expect(convertToDate(undefined)).toBe(undefined)
83 expect(convertToDate(null)).toBe(null)
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 })
df645d8f 96
6c43b441 97 await it('Verify convertToInt()', () => {
66a7748d
JB
98 expect(convertToInt(undefined)).toBe(0)
99 expect(convertToInt(null)).toBe(0)
100 expect(convertToInt(0)).toBe(0)
101 const randomInteger = getRandomInteger()
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)
878e026c 113 expect(() => {
66a7748d
JB
114 convertToInt('NaN')
115 }).toThrow("Cannot convert to integer: 'NaN'")
116 })
df645d8f 117
6c43b441 118 await it('Verify convertToFloat()', () => {
66a7748d
JB
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)
878e026c 134 expect(() => {
66a7748d
JB
135 convertToFloat('NaN')
136 }).toThrow("Cannot convert to float: 'NaN'")
137 })
df645d8f 138
6c43b441 139 await it('Verify convertToBoolean()', () => {
66a7748d
JB
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 })
df645d8f 155
6c43b441 156 await it('Verify secureRandom()', () => {
66a7748d
JB
157 const random = secureRandom()
158 expect(typeof random === 'number').toBe(true)
159 expect(random).toBeGreaterThanOrEqual(0)
160 expect(random).toBeLessThan(1)
161 })
a2111e8d 162
6c43b441 163 await it('Verify getRandomInteger()', () => {
66a7748d
JB
164 let randomInteger = getRandomInteger()
165 expect(Number.isSafeInteger(randomInteger)).toBe(true)
166 expect(randomInteger).toBeGreaterThanOrEqual(0)
167 expect(randomInteger).toBeLessThanOrEqual(Constants.MAX_RANDOM_INTEGER)
168 expect(randomInteger).not.toEqual(getRandomInteger())
169 randomInteger = getRandomInteger(0, -Constants.MAX_RANDOM_INTEGER)
170 expect(randomInteger).toBeGreaterThanOrEqual(-Constants.MAX_RANDOM_INTEGER)
171 expect(randomInteger).toBeLessThanOrEqual(0)
68f56fdf 172 expect(() => getRandomInteger(0, 1)).toThrow(
66a7748d
JB
173 'The value of "max" is out of range. It must be greater than the value of "min" (1). Received 1'
174 )
68f56fdf 175 expect(() => getRandomInteger(-1)).toThrow(
66a7748d
JB
176 'The value of "max" is out of range. It must be greater than the value of "min" (0). Received 0'
177 )
68f56fdf 178 expect(() => getRandomInteger(Constants.MAX_RANDOM_INTEGER + 1)).toThrow(
878e026c
JB
179 `The value of "max" is out of range. It must be <= ${
180 Constants.MAX_RANDOM_INTEGER + 1
66a7748d
JB
181 }. Received 281_474_976_710_656`
182 )
183 randomInteger = getRandomInteger(2, 1)
184 expect(randomInteger).toBeGreaterThanOrEqual(1)
185 expect(randomInteger).toBeLessThanOrEqual(2)
186 const maximum = 2.2
187 const minimum = 1.1
188 randomInteger = getRandomInteger(maximum, minimum)
189 expect(randomInteger).toBeLessThanOrEqual(Math.floor(maximum))
190 expect(randomInteger).toBeGreaterThanOrEqual(Math.ceil(minimum))
191 })
a2111e8d 192
6c43b441 193 await it('Verify roundTo()', () => {
66a7748d
JB
194 expect(roundTo(0, 2)).toBe(0)
195 expect(roundTo(0.5, 0)).toBe(1)
196 expect(roundTo(0.5, 2)).toBe(0.5)
197 expect(roundTo(-0.5, 0)).toBe(-1)
198 expect(roundTo(-0.5, 2)).toBe(-0.5)
199 expect(roundTo(1.005, 0)).toBe(1)
200 expect(roundTo(1.005, 2)).toBe(1.01)
201 expect(roundTo(2.175, 2)).toBe(2.18)
202 expect(roundTo(5.015, 2)).toBe(5.02)
203 expect(roundTo(-1.005, 2)).toBe(-1.01)
204 expect(roundTo(-2.175, 2)).toBe(-2.18)
205 expect(roundTo(-5.015, 2)).toBe(-5.02)
206 })
316d1564 207
6c43b441 208 await it('Verify getRandomFloat()', () => {
66a7748d
JB
209 let randomFloat = getRandomFloat()
210 expect(typeof randomFloat === 'number').toBe(true)
211 expect(randomFloat).toBeGreaterThanOrEqual(0)
212 expect(randomFloat).toBeLessThanOrEqual(Number.MAX_VALUE)
213 expect(randomFloat).not.toEqual(getRandomFloat())
214 expect(() => getRandomFloat(0, 1)).toThrow(new RangeError('Invalid interval'))
68f56fdf 215 expect(() => getRandomFloat(Number.MAX_VALUE, -Number.MAX_VALUE)).toThrow(
66a7748d
JB
216 new RangeError('Invalid interval')
217 )
218 randomFloat = getRandomFloat(0, -Number.MAX_VALUE)
219 expect(randomFloat).toBeGreaterThanOrEqual(-Number.MAX_VALUE)
220 expect(randomFloat).toBeLessThanOrEqual(0)
221 })
a2111e8d 222
6c43b441 223 await it('Verify extractTimeSeriesValues()', () => {
66a7748d
JB
224 expect(extractTimeSeriesValues([])).toEqual([])
225 expect(extractTimeSeriesValues([{ timestamp: Date.now(), value: 1.1 }])).toEqual([1.1])
1553f6df
JB
226 expect(
227 extractTimeSeriesValues([
228 { timestamp: Date.now(), value: 1.1 },
66a7748d
JB
229 { timestamp: Date.now(), value: 2.2 }
230 ])
231 ).toEqual([1.1, 2.2])
232 })
1553f6df 233
6c43b441 234 await it('Verify isObject()', () => {
66a7748d
JB
235 expect(isObject('test')).toBe(false)
236 expect(isObject(undefined)).toBe(false)
237 expect(isObject(null)).toBe(false)
238 expect(isObject(0)).toBe(false)
239 expect(isObject([])).toBe(false)
240 expect(isObject([0, 1])).toBe(false)
241 expect(isObject(['0', '1'])).toBe(false)
242 expect(isObject({})).toBe(true)
243 expect(isObject({ 1: 1 })).toBe(true)
244 expect(isObject({ 1: '1' })).toBe(true)
245 expect(isObject(new Map())).toBe(true)
246 expect(isObject(new Set())).toBe(true)
247 expect(isObject(new WeakMap())).toBe(true)
248 expect(isObject(new WeakSet())).toBe(true)
249 })
a2111e8d 250
40615072 251 await it('Verify clone()', () => {
66a7748d 252 const obj = { 1: 1 }
40615072
JB
253 expect(clone(obj)).toStrictEqual(obj)
254 expect(clone(obj) === obj).toBe(false)
66a7748d 255 const nestedObj = { 1: obj, 2: obj }
40615072
JB
256 expect(clone(nestedObj)).toStrictEqual(nestedObj)
257 expect(clone(nestedObj) === nestedObj).toBe(false)
66a7748d 258 const array = [1, 2]
40615072
JB
259 expect(clone(array)).toStrictEqual(array)
260 expect(clone(array) === array).toBe(false)
66a7748d 261 const objArray = [obj, obj]
40615072
JB
262 expect(clone(objArray)).toStrictEqual(objArray)
263 expect(clone(objArray) === objArray).toBe(false)
66a7748d 264 const date = new Date()
40615072
JB
265 expect(clone(date)).toStrictEqual(date)
266 expect(clone(date) === date).toBe(false)
66a7748d 267 const map = new Map([['1', '2']])
40615072 268 expect(clone(map)).toStrictEqual({})
66a7748d 269 const set = new Set(['1'])
40615072 270 expect(clone(set)).toStrictEqual({})
dd5a1d6c 271 // The URL object seems to have not enumerable properties
66a7748d 272 const url = new URL('https://domain.tld')
40615072 273 expect(clone(url)).toStrictEqual({})
66a7748d 274 const weakMap = new WeakMap([[{ 1: 1 }, { 2: 2 }]])
40615072 275 expect(clone(weakMap)).toStrictEqual({})
66a7748d 276 const weakSet = new WeakSet([{ 1: 1 }, { 2: 2 }])
40615072 277 expect(clone(weakSet)).toStrictEqual({})
66a7748d 278 })
dd5a1d6c 279
6c43b441 280 await it('Verify hasOwnProp()', () => {
66a7748d
JB
281 expect(hasOwnProp('test', '')).toBe(false)
282 expect(hasOwnProp(undefined, '')).toBe(false)
283 expect(hasOwnProp(null, '')).toBe(false)
284 expect(hasOwnProp([], '')).toBe(false)
285 expect(hasOwnProp({}, '')).toBe(false)
286 expect(hasOwnProp({ 1: 1 }, 1)).toBe(true)
287 expect(hasOwnProp({ 1: 1 }, '1')).toBe(true)
288 expect(hasOwnProp({ 1: 1 }, 2)).toBe(false)
289 expect(hasOwnProp({ 1: 1 }, '2')).toBe(false)
290 expect(hasOwnProp({ 1: '1' }, '1')).toBe(true)
291 expect(hasOwnProp({ 1: '1' }, 1)).toBe(true)
292 expect(hasOwnProp({ 1: '1' }, '2')).toBe(false)
293 expect(hasOwnProp({ 1: '1' }, 2)).toBe(false)
294 })
af29b598 295
6c43b441 296 await it('Verify isEmptyString()', () => {
66a7748d
JB
297 expect(isEmptyString('')).toBe(true)
298 expect(isEmptyString(' ')).toBe(true)
299 expect(isEmptyString(' ')).toBe(true)
300 expect(isEmptyString('test')).toBe(false)
301 expect(isEmptyString(' test')).toBe(false)
302 expect(isEmptyString('test ')).toBe(false)
303 expect(isEmptyString(undefined)).toBe(true)
304 expect(isEmptyString(null)).toBe(true)
305 expect(isEmptyString(0)).toBe(false)
306 expect(isEmptyString({})).toBe(false)
307 expect(isEmptyString([])).toBe(false)
308 expect(isEmptyString(new Map())).toBe(false)
309 expect(isEmptyString(new Set())).toBe(false)
310 expect(isEmptyString(new WeakMap())).toBe(false)
311 expect(isEmptyString(new WeakSet())).toBe(false)
312 })
5a2a53cf 313
6c43b441 314 await it('Verify isNotEmptyString()', () => {
66a7748d
JB
315 expect(isNotEmptyString('')).toBe(false)
316 expect(isNotEmptyString(' ')).toBe(false)
317 expect(isNotEmptyString(' ')).toBe(false)
318 expect(isNotEmptyString('test')).toBe(true)
319 expect(isNotEmptyString(' test')).toBe(true)
320 expect(isNotEmptyString('test ')).toBe(true)
321 expect(isNotEmptyString(undefined)).toBe(false)
322 expect(isNotEmptyString(null)).toBe(false)
323 expect(isNotEmptyString(0)).toBe(false)
324 expect(isNotEmptyString({})).toBe(false)
325 expect(isNotEmptyString([])).toBe(false)
326 expect(isNotEmptyString(new Map())).toBe(false)
327 expect(isNotEmptyString(new Set())).toBe(false)
328 expect(isNotEmptyString(new WeakMap())).toBe(false)
329 expect(isNotEmptyString(new WeakSet())).toBe(false)
330 })
429f8c9d 331
6c43b441 332 await it('Verify isEmptyArray()', () => {
66a7748d
JB
333 expect(isEmptyArray([])).toBe(true)
334 expect(isEmptyArray([1, 2])).toBe(false)
335 expect(isEmptyArray(['1', '2'])).toBe(false)
336 expect(isEmptyArray(undefined)).toBe(false)
337 expect(isEmptyArray(null)).toBe(false)
338 expect(isEmptyArray('')).toBe(false)
339 expect(isEmptyArray('test')).toBe(false)
340 expect(isEmptyArray(0)).toBe(false)
341 expect(isEmptyArray({})).toBe(false)
342 expect(isEmptyArray(new Map())).toBe(false)
343 expect(isEmptyArray(new Set())).toBe(false)
344 expect(isEmptyArray(new WeakMap())).toBe(false)
345 expect(isEmptyArray(new WeakSet())).toBe(false)
346 })
a2111e8d 347
6c43b441 348 await it('Verify isNotEmptyArray()', () => {
66a7748d
JB
349 expect(isNotEmptyArray([])).toBe(false)
350 expect(isNotEmptyArray([1, 2])).toBe(true)
351 expect(isNotEmptyArray(['1', '2'])).toBe(true)
352 expect(isNotEmptyArray(undefined)).toBe(false)
353 expect(isNotEmptyArray(null)).toBe(false)
354 expect(isNotEmptyArray('')).toBe(false)
355 expect(isNotEmptyArray('test')).toBe(false)
356 expect(isNotEmptyArray(0)).toBe(false)
357 expect(isNotEmptyArray({})).toBe(false)
358 expect(isNotEmptyArray(new Map())).toBe(false)
359 expect(isNotEmptyArray(new Set())).toBe(false)
360 expect(isNotEmptyArray(new WeakMap())).toBe(false)
361 expect(isNotEmptyArray(new WeakSet())).toBe(false)
362 })
878e026c 363
6c43b441 364 await it('Verify isEmptyObject()', () => {
66a7748d
JB
365 expect(isEmptyObject({})).toBe(true)
366 expect(isEmptyObject({ 1: 1, 2: 2 })).toBe(false)
367 expect(isEmptyObject(new Map())).toBe(false)
368 expect(isEmptyObject(new Set())).toBe(false)
369 expect(isEmptyObject(new WeakMap())).toBe(false)
370 expect(isEmptyObject(new WeakSet())).toBe(false)
371 })
80c58041 372
6c43b441 373 await it('Verify isArraySorted()', () => {
80c58041
JB
374 expect(
375 isArraySorted([], (a, b) => {
66a7748d
JB
376 return a - b
377 })
378 ).toBe(true)
80c58041
JB
379 expect(
380 isArraySorted([1], (a, b) => {
66a7748d
JB
381 return a - b
382 })
383 ).toBe(true)
384 expect(isArraySorted<number>([1, 2, 3, 4, 5], (a, b) => a - b)).toBe(true)
385 expect(isArraySorted<number>([1, 2, 3, 5, 4], (a, b) => a - b)).toBe(false)
386 expect(isArraySorted<number>([2, 1, 3, 4, 5], (a, b) => a - b)).toBe(false)
387 })
5f742aac 388
6c43b441 389 await it('Verify once()', () => {
66a7748d
JB
390 let called = 0
391 const fn = (): number => ++called
392 const onceFn = once(fn, this)
393 const result1 = onceFn()
394 expect(called).toBe(1)
395 expect(result1).toBe(1)
396 const result2 = onceFn()
397 expect(called).toBe(1)
398 expect(result2).toBe(1)
399 const result3 = onceFn()
400 expect(called).toBe(1)
401 expect(result3).toBe(1)
402 })
5adf6ca4 403
6c43b441 404 await it('Verify min()', () => {
66a7748d
JB
405 expect(min()).toBe(Infinity)
406 expect(min(0, 1)).toBe(0)
407 expect(min(1, 0)).toBe(0)
408 expect(min(0, -1)).toBe(-1)
409 expect(min(-1, 0)).toBe(-1)
410 })
5adf6ca4 411
6c43b441 412 await it('Verify max()', () => {
66a7748d
JB
413 expect(max()).toBe(-Infinity)
414 expect(max(0, 1)).toBe(1)
415 expect(max(1, 0)).toBe(1)
416 expect(max(0, -1)).toBe(0)
417 expect(max(-1, 0)).toBe(0)
418 })
419})