1 /*
<lambda>null2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.ui.benchmark.input.pointer
18 
19 import android.content.Context
20 import android.view.MotionEvent
21 import android.view.View
22 import androidx.test.core.app.ApplicationProvider
23 import androidx.test.ext.junit.runners.AndroidJUnit4
24 import androidx.test.filters.MediumTest
25 import com.google.common.truth.Truth.assertThat
26 import kotlin.math.abs
27 import org.junit.Test
28 import org.junit.runner.RunWith
29 
30 @MediumTest
31 @RunWith(AndroidJUnit4::class)
32 class UtilsTest {
33     // Tests for Down Motion Event Creation <---------------
34     @Test
35     fun createDownMotionEvents_noEvent() {
36         val y = (ItemHeightPx / 2)
37         val xMoveInitial = 0f
38         val initialTime = 100
39         val numberOfEvents = 0
40 
41         val context = ApplicationProvider.getApplicationContext<Context>()
42         val view = View(context)
43 
44         val downs =
45             createDowns(
46                 initialX = xMoveInitial,
47                 initialTime = initialTime,
48                 y = y,
49                 rootView = view,
50                 numberOfEvents = numberOfEvents,
51             )
52 
53         // Should just return an empty array
54         assertThat(downs.size).isEqualTo(numberOfEvents)
55     }
56 
57     @Test
58     fun createDownMotionEvents_oneEvent() {
59         val y = (ItemHeightPx / 2)
60         val xMoveInitial = 0f
61         val initialTime = 100
62         val numberOfEvents = 1
63 
64         val context = ApplicationProvider.getApplicationContext<Context>()
65         val view = View(context)
66 
67         val downs =
68             createDowns(
69                 initialX = xMoveInitial,
70                 initialTime = initialTime,
71                 y = y,
72                 rootView = view,
73                 numberOfEvents = numberOfEvents,
74             )
75 
76         assertThat(downs.size).isEqualTo(numberOfEvents)
77 
78         for ((index, down) in downs.withIndex()) {
79             if (index == 0) {
80                 assertThat(down.actionMasked).isEqualTo(MotionEvent.ACTION_DOWN)
81             } else {
82                 assertThat(down.actionMasked).isEqualTo(MotionEvent.ACTION_POINTER_DOWN)
83             }
84 
85             val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
86             assertThat(down.eventTime).isEqualTo(expectedTime)
87 
88             val expectedX = xMoveInitial + (index * DefaultPointerInputMoveAmountPx)
89             assertThat(down.x).isEqualTo(expectedX)
90 
91             assertThat(down.y).isEqualTo(y)
92             assertThat(down.historySize).isEqualTo(0)
93         }
94     }
95 
96     @Test
97     fun createDownMotionEvents_sixEventsWithSixPointers() {
98         val y = (ItemHeightPx / 2)
99         val xMoveInitial = 0f
100         val initialTime = 100
101         val numberOfEvents = 6
102 
103         val context = ApplicationProvider.getApplicationContext<Context>()
104         val view = View(context)
105 
106         val downs =
107             createDowns(
108                 initialX = xMoveInitial,
109                 initialTime = initialTime,
110                 y = y,
111                 rootView = view,
112                 numberOfEvents = numberOfEvents,
113             )
114 
115         assertThat(downs.size).isEqualTo(numberOfEvents)
116 
117         for ((index, down) in downs.withIndex()) {
118             if (index == 0) {
119                 assertThat(down.actionMasked).isEqualTo(MotionEvent.ACTION_DOWN)
120             } else {
121                 assertThat(down.actionMasked).isEqualTo(MotionEvent.ACTION_POINTER_DOWN)
122             }
123 
124             val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
125             assertThat(down.eventTime).isEqualTo(expectedTime)
126 
127             val expectedX = xMoveInitial + (index * DefaultPointerInputMoveAmountPx)
128 
129             val pointerId: Int = down.getPointerId(index)
130             val localPointerCoords = MotionEvent.PointerCoords()
131             down.getPointerCoords(pointerId, localPointerCoords)
132 
133             assertThat(localPointerCoords.x).isEqualTo(expectedX)
134             assertThat(localPointerCoords.y).isEqualTo(y)
135 
136             assertThat(down.historySize).isEqualTo(0)
137         }
138     }
139 
140     // Tests for Up Motion Event Creation <---------------
141     @Test
142     fun createUpMotionEvents_noEvent() {
143         val initialTime = 100
144 
145         val simplifiedUps = arrayOf<BenchmarkSimplifiedPointerInputPointer>()
146 
147         val context = ApplicationProvider.getApplicationContext<Context>()
148         val view = View(context)
149 
150         val ups =
151             createUps(
152                 initialTime = initialTime,
153                 initialPointers = simplifiedUps,
154                 rootView = view,
155             )
156 
157         // Should just return an empty array
158         assertThat(ups.size).isEqualTo(simplifiedUps.size)
159     }
160 
161     @Test
162     fun createUpMotionEvents_oneEvent() {
163         val y = (ItemHeightPx / 2)
164         val xMoveInitial = 0f
165         val initialTime = 100
166 
167         val context = ApplicationProvider.getApplicationContext<Context>()
168         val view = View(context)
169 
170         val simplifiedUps =
171             arrayOf(BenchmarkSimplifiedPointerInputPointer(id = 0, x = xMoveInitial, y = y))
172 
173         val ups =
174             createUps(
175                 initialTime = initialTime,
176                 initialPointers = simplifiedUps,
177                 rootView = view,
178             )
179 
180         assertThat(ups.size).isEqualTo(simplifiedUps.size)
181 
182         for ((index, move) in ups.withIndex()) {
183             if (index == (ups.size - 1)) { // last event should be ACTION_UP
184                 assertThat(move.actionMasked).isEqualTo(MotionEvent.ACTION_UP)
185             } else {
186                 assertThat(move.actionMasked).isEqualTo(MotionEvent.ACTION_POINTER_UP)
187             }
188 
189             val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
190             assertThat(move.eventTime).isEqualTo(expectedTime)
191 
192             val expectedX = simplifiedUps[index].x
193             assertThat(move.x).isEqualTo(expectedX)
194 
195             val expectedY = simplifiedUps[index].y
196             assertThat(move.y).isEqualTo(expectedY)
197             assertThat(move.historySize).isEqualTo(0)
198         }
199     }
200 
201     @Test
202     fun createUpMotionEvents_sixEventsWithSixPointers() {
203         val y = (ItemHeightPx / 2)
204         val xMoveInitial = 0f
205         val initialTime = 100
206         val numberOfEvents = 6
207 
208         val simplifiedUps =
209             Array(numberOfEvents) { index ->
210                 BenchmarkSimplifiedPointerInputPointer(
211                     id = index,
212                     x = xMoveInitial + (index * DefaultPointerInputMoveAmountPx),
213                     y = y
214                 )
215             }
216 
217         val context = ApplicationProvider.getApplicationContext<Context>()
218         val view = View(context)
219 
220         val ups =
221             createUps(
222                 initialTime = initialTime,
223                 initialPointers = simplifiedUps,
224                 rootView = view,
225             )
226 
227         assertThat(ups.size).isEqualTo(simplifiedUps.size)
228 
229         // The main x and y will always be the first pointer, but we want to verify that for all
230         // events.
231         val expectedMainX = simplifiedUps[0].x
232         val expectedMainY = simplifiedUps[0].y
233 
234         for ((index, move) in ups.withIndex()) {
235             if (index == (ups.size - 1)) { // last event should be ACTION_UP
236                 assertThat(move.actionMasked).isEqualTo(MotionEvent.ACTION_UP)
237             } else {
238                 assertThat(move.actionMasked).isEqualTo(MotionEvent.ACTION_POINTER_UP)
239             }
240 
241             val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
242             assertThat(move.eventTime).isEqualTo(expectedTime)
243 
244             assertThat(move.x).isEqualTo(expectedMainX)
245             assertThat(move.y).isEqualTo(expectedMainY)
246 
247             // Check all pointers are there and valid
248             val expectedPointerCount = simplifiedUps.size - index
249             assertThat(move.pointerCount).isEqualTo(expectedPointerCount)
250 
251             for (pointerIndex in 0 until move.pointerCount) {
252                 val pointerId: Int = move.getPointerId(pointerIndex)
253                 val localPointerCoords = MotionEvent.PointerCoords()
254                 move.getPointerCoords(pointerId, localPointerCoords)
255 
256                 val expectedPointerCoords = simplifiedUps[pointerIndex]
257                 assertThat(localPointerCoords.x).isEqualTo(expectedPointerCoords.x)
258                 assertThat(localPointerCoords.y).isEqualTo(expectedPointerCoords.y)
259             }
260 
261             assertThat(move.historySize).isEqualTo(0)
262         }
263     }
264 
265     // Tests for Move Motion Event Creation <---------------
266     // Note: For tests with history, I am only checking the history count, not each history's x/y.
267     // One pointer/finger
268     @Test
269     fun createMoveMotionEvents_sixEventsOnePointerNegativeMoveDeltaWithoutHistory() {
270         val y = (ItemHeightPx / 2)
271         val xMoveInitial = 0f
272         val initialTime = 100
273         val numberOfEvents = 6
274         val enableFlingStyleHistory = false
275 
276         val context = ApplicationProvider.getApplicationContext<Context>()
277         val view = View(context)
278 
279         val moves =
280             createMoveMotionEvents(
281                 initialTime = initialTime,
282                 initialPointers =
283                     arrayOf(
284                         BenchmarkSimplifiedPointerInputPointer(id = 0, x = xMoveInitial, y = y)
285                     ),
286                 rootView = view,
287                 numberOfMoveEvents = numberOfEvents,
288                 enableFlingStyleHistory = enableFlingStyleHistory,
289                 timeDelta = 100,
290                 moveDelta = -DefaultPointerInputMoveAmountPx
291             )
292 
293         assertThat(moves.size).isEqualTo(numberOfEvents)
294 
295         for ((moveIndex, move) in moves.withIndex()) {
296             val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
297             assertThat(move.eventTime).isEqualTo(expectedTime)
298 
299             val expectedX = xMoveInitial - (abs(moveIndex * DefaultPointerInputMoveAmountPx))
300             assertThat(move.x).isEqualTo(expectedX)
301 
302             assertThat(move.y).isEqualTo(y)
303             assertThat(move.historySize).isEqualTo(0)
304         }
305     }
306 
307     @Test
308     fun createMoveMotionEvents_sixEventsOnePointerPositiveMoveDeltaWithoutHistory() {
309         val y = (ItemHeightPx / 2)
310         val xMoveInitial = 0f
311         val initialTime = 100
312         val numberOfEvents = 6
313         val enableFlingStyleHistory = false
314 
315         val context = ApplicationProvider.getApplicationContext<Context>()
316         val view = View(context)
317 
318         val moves =
319             createMoveMotionEvents(
320                 initialTime = initialTime,
321                 initialPointers =
322                     arrayOf(
323                         BenchmarkSimplifiedPointerInputPointer(id = 0, x = xMoveInitial, y = y)
324                     ),
325                 rootView = view,
326                 numberOfMoveEvents = numberOfEvents,
327                 enableFlingStyleHistory = enableFlingStyleHistory
328             )
329 
330         assertThat(moves.size).isEqualTo(numberOfEvents)
331 
332         for ((moveIndex, move) in moves.withIndex()) {
333             val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
334             assertThat(move.eventTime).isEqualTo(expectedTime)
335 
336             val expectedX = xMoveInitial + (moveIndex * DefaultPointerInputMoveAmountPx)
337             assertThat(move.x).isEqualTo(expectedX)
338 
339             assertThat(move.y).isEqualTo(y)
340             assertThat(move.historySize).isEqualTo(0)
341         }
342     }
343 
344     @Test
345     fun createMoveMotionEvents_sixEventsOnePointerPositiveMoveDeltaWithHistory() {
346         val y = (ItemHeightPx / 2)
347         val xMoveInitial = 0f
348         val initialTime = 100
349         val numberOfEvents = 6
350         val enableFlingStyleHistory = true
351 
352         val context = ApplicationProvider.getApplicationContext<Context>()
353         val view = View(context)
354 
355         val moves =
356             createMoveMotionEvents(
357                 initialTime = initialTime,
358                 initialPointers =
359                     arrayOf(
360                         BenchmarkSimplifiedPointerInputPointer(id = 0, x = xMoveInitial, y = y)
361                     ),
362                 rootView = view,
363                 numberOfMoveEvents = numberOfEvents,
364                 enableFlingStyleHistory = enableFlingStyleHistory
365             )
366 
367         assertThat(moves.size).isEqualTo(numberOfEvents)
368 
369         for ((moveIndex, move) in moves.withIndex()) {
370             val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
371 
372             val expectedX = xMoveInitial + (moveIndex * DefaultPointerInputMoveAmountPx)
373 
374             assertThat(move.eventTime).isEqualTo(expectedTime)
375             assertThat(move.x).isEqualTo(expectedX)
376             assertThat(move.y).isEqualTo(y)
377             assertThat(move.historySize)
378                 .isEqualTo(numberOfHistoricalEventsBasedOnArrayLocation(moveIndex))
379         }
380     }
381 
382     @Test
383     fun createMoveMotionEvents_sixEventsOnePointerNegativeMoveDeltaWithHistory() {
384         val y = (ItemHeightPx / 2)
385         val xMoveInitial = 0f
386         val initialTime = 100
387         val numberOfEvents = 6
388         val enableFlingStyleHistory = true
389 
390         val context = ApplicationProvider.getApplicationContext<Context>()
391         val view = View(context)
392 
393         val moves =
394             createMoveMotionEvents(
395                 initialTime = initialTime,
396                 initialPointers =
397                     arrayOf(
398                         BenchmarkSimplifiedPointerInputPointer(id = 0, x = xMoveInitial, y = y)
399                     ),
400                 rootView = view,
401                 numberOfMoveEvents = numberOfEvents,
402                 enableFlingStyleHistory = enableFlingStyleHistory,
403                 timeDelta = 100,
404                 moveDelta = -DefaultPointerInputMoveAmountPx
405             )
406         assertThat(moves.size).isEqualTo(numberOfEvents)
407 
408         for ((moveIndex, move) in moves.withIndex()) {
409             val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
410 
411             val expectedX = xMoveInitial - (abs(moveIndex * DefaultPointerInputMoveAmountPx))
412 
413             assertThat(move.eventTime).isEqualTo(expectedTime)
414             assertThat(move.x).isEqualTo(expectedX)
415             assertThat(move.y).isEqualTo(y)
416             assertThat(move.historySize)
417                 .isEqualTo(numberOfHistoricalEventsBasedOnArrayLocation(moveIndex))
418         }
419     }
420 
421     // Multiple pointers/fingers
422     @Test
423     fun createMoveMotionEvents_sixEventsThreePointerNegativeMoveDeltaWithoutHistory() {
424         val y = (ItemHeightPx / 2)
425         val xMoveInitial = 0f
426         val initialTime = 100
427         val numberOfEvents = 6
428         val numberOfPointers = 3 // fingers
429         val enableFlingStyleHistory = false
430 
431         val context = ApplicationProvider.getApplicationContext<Context>()
432         val view = View(context)
433 
434         val initialPointers =
435             Array(numberOfPointers) { simpleIndex ->
436                 BenchmarkSimplifiedPointerInputPointer(
437                     id = simpleIndex,
438                     x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
439                     y = y
440                 )
441             }
442 
443         val moves =
444             createMoveMotionEvents(
445                 initialTime = initialTime,
446                 initialPointers = initialPointers,
447                 rootView = view,
448                 numberOfMoveEvents = numberOfEvents,
449                 enableFlingStyleHistory = enableFlingStyleHistory,
450                 timeDelta = 100,
451                 moveDelta = -DefaultPointerInputMoveAmountPx
452             )
453 
454         assertThat(moves.size).isEqualTo(numberOfEvents)
455 
456         for ((index, move) in moves.withIndex()) {
457             val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
458             assertThat(move.eventTime).isEqualTo(expectedTime)
459             assertThat(move.historySize).isEqualTo(0)
460 
461             for (pointerIndex in 0 until move.pointerCount) {
462                 val pointerId: Int = move.getPointerId(pointerIndex)
463                 val localPointerCoords = MotionEvent.PointerCoords()
464                 move.getPointerCoords(pointerId, localPointerCoords)
465 
466                 val expectedX =
467                     (xMoveInitial - (abs(index * DefaultPointerInputMoveAmountPx))) +
468                         (pointerIndex * DefaultPointerInputMoveAmountPx)
469                 assertThat(localPointerCoords.x).isEqualTo(expectedX)
470 
471                 assertThat(localPointerCoords.y).isEqualTo(y)
472             }
473         }
474     }
475 
476     @Test
477     fun createMoveMotionEvents_sixEventsThreePointerPositiveMoveDeltaWithoutHistory() {
478         val y = (ItemHeightPx / 2)
479         val xMoveInitial = 0f
480         val initialTime = 100
481         val numberOfEvents = 6
482         val numberOfPointers = 3 // fingers
483         val enableFlingStyleHistory = false
484 
485         val context = ApplicationProvider.getApplicationContext<Context>()
486         val view = View(context)
487 
488         val initialPointers =
489             Array(numberOfPointers) { simpleIndex ->
490                 BenchmarkSimplifiedPointerInputPointer(
491                     id = simpleIndex,
492                     x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
493                     y = y
494                 )
495             }
496 
497         val moves =
498             createMoveMotionEvents(
499                 initialTime = initialTime,
500                 initialPointers = initialPointers,
501                 rootView = view,
502                 numberOfMoveEvents = numberOfEvents,
503                 enableFlingStyleHistory = enableFlingStyleHistory
504             )
505 
506         assertThat(moves.size).isEqualTo(numberOfEvents)
507 
508         for ((index, move) in moves.withIndex()) {
509             val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
510             assertThat(move.eventTime).isEqualTo(expectedTime)
511             assertThat(move.historySize).isEqualTo(0)
512 
513             for (pointerIndex in 0 until move.pointerCount) {
514                 val pointerId: Int = move.getPointerId(pointerIndex)
515                 val localPointerCoords = MotionEvent.PointerCoords()
516                 move.getPointerCoords(pointerId, localPointerCoords)
517 
518                 val expectedX =
519                     (xMoveInitial + (index * DefaultPointerInputMoveAmountPx)) +
520                         (pointerIndex * DefaultPointerInputMoveAmountPx)
521                 assertThat(localPointerCoords.x).isEqualTo(expectedX)
522 
523                 assertThat(localPointerCoords.y).isEqualTo(y)
524             }
525         }
526     }
527 
528     @Test
529     fun createMoveMotionEvents_sixEventsThreePointerNegativeMoveDeltaWithHistory() {
530         val y = (ItemHeightPx / 2)
531         val xMoveInitial = 0f
532         val initialTime = 100
533         val numberOfEvents = 6
534         val numberOfPointers = 3 // fingers
535         val enableFlingStyleHistory = true
536 
537         val context = ApplicationProvider.getApplicationContext<Context>()
538         val view = View(context)
539 
540         val initialPointers =
541             Array(numberOfPointers) { simpleIndex ->
542                 BenchmarkSimplifiedPointerInputPointer(
543                     id = simpleIndex,
544                     x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
545                     y = y
546                 )
547             }
548 
549         val moves =
550             createMoveMotionEvents(
551                 initialTime = initialTime,
552                 initialPointers = initialPointers,
553                 rootView = view,
554                 numberOfMoveEvents = numberOfEvents,
555                 enableFlingStyleHistory = enableFlingStyleHistory,
556                 timeDelta = 100,
557                 moveDelta = -DefaultPointerInputMoveAmountPx
558             )
559 
560         assertThat(moves.size).isEqualTo(numberOfEvents)
561 
562         for ((moveIndex, move) in moves.withIndex()) {
563             val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
564             assertThat(move.eventTime).isEqualTo(expectedTime)
565 
566             assertThat(move.historySize)
567                 .isEqualTo(numberOfHistoricalEventsBasedOnArrayLocation(moveIndex))
568 
569             for (pointerIndex in 0 until move.pointerCount) {
570                 val pointerId: Int = move.getPointerId(pointerIndex)
571                 val localPointerCoords = MotionEvent.PointerCoords()
572                 move.getPointerCoords(pointerId, localPointerCoords)
573 
574                 val expectedX =
575                     (xMoveInitial - (abs(moveIndex * DefaultPointerInputMoveAmountPx))) +
576                         (pointerIndex * DefaultPointerInputMoveAmountPx)
577                 assertThat(localPointerCoords.x).isEqualTo(expectedX)
578                 assertThat(localPointerCoords.y).isEqualTo(y)
579             }
580         }
581     }
582 
583     @Test
584     fun createMoveMotionEvents_sixEventsThreePointerPositiveMoveDeltaWithHistory() {
585         val y = (ItemHeightPx / 2)
586         val xMoveInitial = 0f
587         val initialTime = 100
588         val numberOfEvents = 6
589         val numberOfPointers = 3 // fingers
590         val enableFlingStyleHistory = true
591 
592         val context = ApplicationProvider.getApplicationContext<Context>()
593         val view = View(context)
594 
595         val initialPointers =
596             Array(numberOfPointers) { simpleIndex ->
597                 BenchmarkSimplifiedPointerInputPointer(
598                     id = simpleIndex,
599                     x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
600                     y = y
601                 )
602             }
603 
604         val moves =
605             createMoveMotionEvents(
606                 initialTime = initialTime,
607                 initialPointers = initialPointers,
608                 rootView = view,
609                 numberOfMoveEvents = numberOfEvents,
610                 enableFlingStyleHistory = enableFlingStyleHistory
611             )
612 
613         assertThat(moves.size).isEqualTo(numberOfEvents)
614 
615         for ((moveIndex, move) in moves.withIndex()) {
616             val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
617             assertThat(move.eventTime).isEqualTo(expectedTime)
618 
619             assertThat(move.historySize)
620                 .isEqualTo(numberOfHistoricalEventsBasedOnArrayLocation(moveIndex))
621 
622             for (pointerIndex in 0 until move.pointerCount) {
623                 val pointerId: Int = move.getPointerId(pointerIndex)
624                 val localPointerCoords = MotionEvent.PointerCoords()
625                 move.getPointerCoords(pointerId, localPointerCoords)
626 
627                 val expectedX =
628                     (xMoveInitial + (moveIndex * DefaultPointerInputMoveAmountPx)) +
629                         (pointerIndex * DefaultPointerInputMoveAmountPx)
630                 assertThat(localPointerCoords.x).isEqualTo(expectedX)
631                 assertThat(localPointerCoords.y).isEqualTo(y)
632             }
633         }
634     }
635 
636     @Test
637     fun testNumberOfHistoricalEventsBasedOnArrayLocation() {
638         var numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(0)
639         assertThat(numberOfEvents).isEqualTo(12)
640 
641         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(1)
642         assertThat(numberOfEvents).isEqualTo(9)
643 
644         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(2)
645         assertThat(numberOfEvents).isEqualTo(4)
646 
647         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(3)
648         assertThat(numberOfEvents).isEqualTo(4)
649 
650         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(4)
651         assertThat(numberOfEvents).isEqualTo(2)
652 
653         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(5)
654         assertThat(numberOfEvents).isEqualTo(2)
655 
656         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(20)
657         assertThat(numberOfEvents).isEqualTo(2)
658 
659         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(2000)
660         assertThat(numberOfEvents).isEqualTo(2)
661 
662         numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(-1)
663         assertThat(numberOfEvents).isEqualTo(2)
664     }
665 }
666