7701576b55a187819df5cc9ee446f91b872212dd
[WebKit-https.git] / Websites / perf.webkit.org / unit-tests / time-series-tests.js
1 'use strict';
2
3 const assert = require('assert');
4 if (!assert.almostEqual)
5     assert.almostEqual = require('./resources/almost-equal.js');
6
7 const MockRemoteAPI = require('./resources/mock-remote-api.js').MockRemoteAPI;
8 require('../tools/js/v3-models.js');
9
10 let threePoints;
11 let fivePoints;
12 beforeEach(() => {
13     threePoints = [
14         {id: 910, time: 101, value: 110},
15         {id: 902, time: 220, value: 102},
16         {id: 930, time: 303, value: 130},
17     ];
18     fivePoints = [...threePoints,
19         {id: 904, time: 400, value: 114},
20         {id: 950, time: 505, value: 105},
21         {id: 960, time: 600, value: 116},
22     ];
23 });
24
25 function addPointsToSeries(timeSeries, list = threePoints)
26 {
27     for (let point of list)
28         timeSeries.append(point);
29 }
30
31 describe('TimeSeries', () => {
32
33     describe('length', () => {
34         it('should return the length', () => {
35             const timeSeries = new TimeSeries();
36             addPointsToSeries(timeSeries);
37             assert.equal(timeSeries.length(), 3);
38         });
39
40         it('should return 0 when there are no points', () => {
41             const timeSeries = new TimeSeries();
42             assert.equal(timeSeries.length(), 0);
43         });
44     });
45
46     describe('firstPoint', () => {
47         it('should return the first point', () => {
48             const timeSeries = new TimeSeries();
49             addPointsToSeries(timeSeries);
50             assert.equal(timeSeries.firstPoint(), threePoints[0]);
51         });
52
53         it('should return null when there are no points', () => {
54             const timeSeries = new TimeSeries();
55             assert.equal(timeSeries.firstPoint(), null);
56         });
57     });
58
59     describe('lastPoint', () => {
60         it('should return the first point', () => {
61             const timeSeries = new TimeSeries();
62             addPointsToSeries(timeSeries);
63             assert.equal(timeSeries.lastPoint(), threePoints[2]);
64         });
65
66         it('should return null when there are no points', () => {
67             const timeSeries = new TimeSeries();
68             assert.equal(timeSeries.lastPoint(), null);
69         });
70     });
71
72     describe('nextPoint', () => {
73         it('should return the next point when called on the first point', () => {
74             const timeSeries = new TimeSeries();
75             addPointsToSeries(timeSeries);
76             assert.equal(timeSeries.nextPoint(threePoints[0]), threePoints[1]);
77         });
78
79         it('should return the next point when called on a mid-point', () => {
80             const timeSeries = new TimeSeries();
81             addPointsToSeries(timeSeries);
82             assert.equal(timeSeries.nextPoint(threePoints[1]), threePoints[2]);
83         });
84
85         it('should return null when called on the last point', () => {
86             const timeSeries = new TimeSeries();
87             addPointsToSeries(timeSeries);
88             assert.equal(timeSeries.nextPoint(threePoints[2]), null);
89         });
90     });
91
92     describe('previousPoint', () => {
93         it('should return null when called on the first point', () => {
94             const timeSeries = new TimeSeries();
95             addPointsToSeries(timeSeries);
96             assert.equal(timeSeries.previousPoint(threePoints[0]), null);
97         });
98
99         it('should return the previous point when called on a mid-point', () => {
100             const timeSeries = new TimeSeries();
101             addPointsToSeries(timeSeries);
102             assert.equal(timeSeries.previousPoint(threePoints[1]), threePoints[0]);
103         });
104
105         it('should return the previous point when called on the last point', () => {
106             const timeSeries = new TimeSeries();
107             addPointsToSeries(timeSeries);
108             assert.equal(timeSeries.previousPoint(threePoints[2]), threePoints[1]);
109         });
110     });
111
112     describe('findPointByIndex', () => {
113         it('should return null the index is less than 0', () => {
114             const timeSeries = new TimeSeries();
115             addPointsToSeries(timeSeries);
116             assert.equal(timeSeries.findPointByIndex(-10), null);
117             assert.equal(timeSeries.findPointByIndex(-1), null);
118         });
119
120         it('should return null when the index is greater than or equal to the length', () => {
121             const timeSeries = new TimeSeries();
122             addPointsToSeries(timeSeries);
123             assert.equal(timeSeries.findPointByIndex(10), null);
124             assert.equal(timeSeries.findPointByIndex(3), null);
125         });
126
127         it('should return null when the index is not a number', () => {
128             const timeSeries = new TimeSeries();
129             addPointsToSeries(timeSeries);
130             assert.equal(timeSeries.findPointByIndex(undefined), null);
131             assert.equal(timeSeries.findPointByIndex(NaN), null);
132             assert.equal(timeSeries.findPointByIndex('a'), null);
133         });
134
135         it('should return the point at the specified index when it is in the valid range', () => {
136             const timeSeries = new TimeSeries();
137             addPointsToSeries(timeSeries);
138             assert.equal(timeSeries.findPointByIndex(0), threePoints[0]);
139             assert.equal(timeSeries.findPointByIndex(1), threePoints[1]);
140             assert.equal(timeSeries.findPointByIndex(2), threePoints[2]);
141         });
142     });
143
144     describe('findById', () => {
145         it('should return the point with the specified ID', () => {
146             const timeSeries = new TimeSeries();
147             addPointsToSeries(timeSeries);
148             assert.equal(timeSeries.findById(threePoints[0].id), threePoints[0]);
149             assert.equal(timeSeries.findById(threePoints[1].id), threePoints[1]);
150             assert.equal(timeSeries.findById(threePoints[2].id), threePoints[2]);
151         });
152
153         it('should return null for a non-existent ID', () => {
154             const timeSeries = new TimeSeries();
155             addPointsToSeries(timeSeries);
156             assert.equal(timeSeries.findById(null), null);
157             assert.equal(timeSeries.findById(undefined), null);
158             assert.equal(timeSeries.findById(NaN), null);
159             assert.equal(timeSeries.findById('a'), null);
160             assert.equal(timeSeries.findById(4231563246), null);
161         });
162     });
163
164     describe('findPointAfterTime', () => {
165         it('should return the point at the specified time', () => {
166             const timeSeries = new TimeSeries();
167             addPointsToSeries(timeSeries);
168             assert.equal(timeSeries.findPointAfterTime(threePoints[0].time), threePoints[0]);
169             assert.equal(timeSeries.findPointAfterTime(threePoints[1].time), threePoints[1]);
170             assert.equal(timeSeries.findPointAfterTime(threePoints[2].time), threePoints[2]);
171         });
172
173         it('should return the point after the specified time', () => {
174             const timeSeries = new TimeSeries();
175             addPointsToSeries(timeSeries);
176             assert.equal(timeSeries.findPointAfterTime(threePoints[0].time - 0.1), threePoints[0]);
177             assert.equal(timeSeries.findPointAfterTime(threePoints[1].time - 0.1), threePoints[1]);
178             assert.equal(timeSeries.findPointAfterTime(threePoints[2].time - 0.1), threePoints[2]);
179         });
180
181         it('should return null when there are no points after the specified time', () => {
182             const timeSeries = new TimeSeries();
183             addPointsToSeries(timeSeries);
184             assert.equal(timeSeries.findPointAfterTime(threePoints[2].time + 0.1), null);
185         });
186
187         it('should return the first point when there are multiple points at the specified time', () => {
188             const timeSeries = new TimeSeries();
189             const points = [
190                 {id: 909, time:  99, value: 105},
191                 {id: 910, time: 100, value: 110},
192                 {id: 902, time: 100, value: 102},
193                 {id: 930, time: 101, value: 130},
194             ];
195             addPointsToSeries(timeSeries, points);
196             assert.equal(timeSeries.findPointAfterTime(points[1].time), points[1]);
197         });
198     });
199
200     describe('viewBetweenPoints', () => {
201
202         it('should return a view between two points', () => {
203             const timeSeries = new TimeSeries();
204             addPointsToSeries(timeSeries, fivePoints);
205             const view = timeSeries.viewBetweenPoints(fivePoints[1], fivePoints[3]);
206             assert.equal(view.length(), 3);
207             assert.equal(view.firstPoint(), fivePoints[1]);
208             assert.equal(view.lastPoint(), fivePoints[3]);
209
210             assert.equal(view.nextPoint(fivePoints[1]), fivePoints[2]);
211             assert.equal(view.nextPoint(fivePoints[2]), fivePoints[3]);
212             assert.equal(view.nextPoint(fivePoints[3]), null);
213
214             assert.equal(view.previousPoint(fivePoints[1]), null);
215             assert.equal(view.previousPoint(fivePoints[2]), fivePoints[1]);
216             assert.equal(view.previousPoint(fivePoints[3]), fivePoints[2]);
217
218             assert.equal(view.findPointByIndex(0), fivePoints[1]);
219             assert.equal(view.findPointByIndex(1), fivePoints[2]);
220             assert.equal(view.findPointByIndex(2), fivePoints[3]);
221             assert.equal(view.findPointByIndex(3), null);
222
223             assert.equal(view.findById(fivePoints[0].id), null);
224             assert.equal(view.findById(fivePoints[1].id), fivePoints[1]);
225             assert.equal(view.findById(fivePoints[2].id), fivePoints[2]);
226             assert.equal(view.findById(fivePoints[3].id), fivePoints[3]);
227             assert.equal(view.findById(fivePoints[4].id), null);
228
229             assert.deepEqual(view.values(), [fivePoints[1].value, fivePoints[2].value, fivePoints[3].value]);
230
231             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[4].time), fivePoints[1]);
232             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[4].time), fivePoints[1]);
233             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[1].time), fivePoints[1]);
234             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[0].time), null);
235             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time + 0.1, fivePoints[2].time), fivePoints[2]);
236             assert.deepEqual(view.firstPointInTimeRange(fivePoints[3].time - 0.1, fivePoints[4].time), fivePoints[3]);
237             assert.deepEqual(view.firstPointInTimeRange(fivePoints[4].time, fivePoints[4].time), null);
238
239             assert.deepEqual([...view], fivePoints.slice(1, 4));
240         });
241
242         it('should return a view with exactly one point for when the starting point is identical to the ending point', () => {
243             const timeSeries = new TimeSeries();
244             addPointsToSeries(timeSeries, fivePoints);
245             const view = timeSeries.viewBetweenPoints(fivePoints[2], fivePoints[2]);
246             assert.equal(view.length(), 1);
247             assert.equal(view.firstPoint(), fivePoints[2]);
248             assert.equal(view.lastPoint(), fivePoints[2]);
249
250             assert.equal(view.findPointByIndex(0), fivePoints[2]);
251             assert.equal(view.findPointByIndex(1), null);
252
253             assert.equal(view.findById(fivePoints[0].id), null);
254             assert.equal(view.findById(fivePoints[1].id), null);
255             assert.equal(view.findById(fivePoints[2].id), fivePoints[2]);
256             assert.equal(view.findById(fivePoints[3].id), null);
257             assert.equal(view.findById(fivePoints[4].id), null);
258
259             assert.deepEqual(view.values(), [fivePoints[2].value]);
260
261             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[4].time), fivePoints[2]);
262             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[4].time), fivePoints[2]);
263             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[1].time), null);
264             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[0].time), null);
265             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time + 0.1, fivePoints[2].time), fivePoints[2]);
266             assert.deepEqual(view.firstPointInTimeRange(fivePoints[3].time - 0.1, fivePoints[4].time), null);
267             assert.deepEqual(view.firstPointInTimeRange(fivePoints[4].time, fivePoints[4].time), null);
268
269             assert.deepEqual([...view], [fivePoints[2]]);
270         });
271
272     });
273
274 });
275
276 describe('TimeSeriesView', () => {
277
278     describe('filter', () => {
279         it('should create a filtered view', () => {
280             const timeSeries = new TimeSeries();
281             addPointsToSeries(timeSeries, fivePoints);
282             const originalView = timeSeries.viewBetweenPoints(fivePoints[0], fivePoints[4]);
283             const view = originalView.filter((point) => { return point == fivePoints[1] || point == fivePoints[3]; });
284
285             assert.equal(view.length(), 2);
286             assert.equal(view.firstPoint(), fivePoints[1]);
287             assert.equal(view.lastPoint(), fivePoints[3]);
288
289             assert.equal(view.nextPoint(fivePoints[1]), fivePoints[3]);
290             assert.equal(view.nextPoint(fivePoints[3]), null);
291
292             assert.equal(view.previousPoint(fivePoints[1]), null);
293             assert.equal(view.previousPoint(fivePoints[3]), fivePoints[1]);
294
295             assert.equal(view.findPointByIndex(0), fivePoints[1]);
296             assert.equal(view.findPointByIndex(1), fivePoints[3]);
297             assert.equal(view.findPointByIndex(2), null);
298
299             assert.equal(view.findById(fivePoints[0].id), null);
300             assert.equal(view.findById(fivePoints[1].id), fivePoints[1]);
301             assert.equal(view.findById(fivePoints[2].id), null);
302             assert.equal(view.findById(fivePoints[3].id), fivePoints[3]);
303             assert.equal(view.findById(fivePoints[4].id), null);
304
305             assert.deepEqual(view.values(), [fivePoints[1].value, fivePoints[3].value]);
306
307             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[4].time), fivePoints[1]);
308             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[4].time), fivePoints[1]);
309             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[1].time), fivePoints[1]);
310             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[0].time), null);
311             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time + 0.1, fivePoints[2].time), null);
312             assert.deepEqual(view.firstPointInTimeRange(fivePoints[3].time - 0.1, fivePoints[4].time), fivePoints[3]);
313             assert.deepEqual(view.firstPointInTimeRange(fivePoints[4].time, fivePoints[4].time), null);
314
315             assert.deepEqual([...view], [fivePoints[1], fivePoints[3]]);
316         });
317     });
318
319     describe('viewTimeRange', () => {
320         it('should create a view filtered by the specified time range', () => {
321             const timeSeries = new TimeSeries();
322             addPointsToSeries(timeSeries, fivePoints);
323             const originalView = timeSeries.viewBetweenPoints(fivePoints[0], fivePoints[4]);
324             const view = originalView.viewTimeRange(fivePoints[1].time - 0.1, fivePoints[4].time - 0.1);
325
326             assert.equal(view.length(), 3);
327             assert.equal(view.firstPoint(), fivePoints[1]);
328             assert.equal(view.lastPoint(), fivePoints[3]);
329
330             assert.equal(view.nextPoint(fivePoints[1]), fivePoints[2]);
331             assert.equal(view.nextPoint(fivePoints[2]), fivePoints[3]);
332             assert.equal(view.nextPoint(fivePoints[3]), null);
333
334             assert.equal(view.previousPoint(fivePoints[1]), null);
335             assert.equal(view.previousPoint(fivePoints[2]), fivePoints[1]);
336             assert.equal(view.previousPoint(fivePoints[3]), fivePoints[2]);
337
338             assert.equal(view.findPointByIndex(0), fivePoints[1]);
339             assert.equal(view.findPointByIndex(1), fivePoints[2]);
340             assert.equal(view.findPointByIndex(2), fivePoints[3]);
341             assert.equal(view.findPointByIndex(3), null);
342
343             assert.equal(view.findById(fivePoints[0].id), null);
344             assert.equal(view.findById(fivePoints[1].id), fivePoints[1]);
345             assert.equal(view.findById(fivePoints[2].id), fivePoints[2]);
346             assert.equal(view.findById(fivePoints[3].id), fivePoints[3]);
347             assert.equal(view.findById(fivePoints[4].id), null);
348
349             assert.deepEqual(view.values(), [fivePoints[1].value, fivePoints[2].value, fivePoints[3].value]);
350
351             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[4].time), fivePoints[1]);
352             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[4].time), fivePoints[1]);
353             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[1].time), fivePoints[1]);
354             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[0].time), null);
355             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time + 0.1, fivePoints[2].time), fivePoints[2]);
356             assert.deepEqual(view.firstPointInTimeRange(fivePoints[3].time - 0.1, fivePoints[4].time), fivePoints[3]);
357             assert.deepEqual(view.firstPointInTimeRange(fivePoints[4].time, fivePoints[4].time), null);
358
359             assert.deepEqual([...view], fivePoints.slice(1, 4));
360         });
361
362         it('should create a view filtered by the specified time range on a view already filtered by a time range', () => {
363             const timeSeries = new TimeSeries();
364             addPointsToSeries(timeSeries, fivePoints);
365             const originalView = timeSeries.viewBetweenPoints(fivePoints[0], fivePoints[4]);
366             const prefilteredView = originalView.viewTimeRange(fivePoints[1].time - 0.1, fivePoints[4].time - 0.1);
367             const view = prefilteredView.viewTimeRange(fivePoints[3].time - 0.1, fivePoints[3].time + 0.1);
368
369             assert.equal(view.length(), 1);
370             assert.equal(view.firstPoint(), fivePoints[3]);
371             assert.equal(view.lastPoint(), fivePoints[3]);
372
373             assert.equal(view.nextPoint(fivePoints[3]), null);
374             assert.equal(view.previousPoint(fivePoints[3]), null);
375
376             assert.equal(view.findPointByIndex(0), fivePoints[3]);
377             assert.equal(view.findPointByIndex(1), null);
378
379             assert.equal(view.findById(fivePoints[0].id), null);
380             assert.equal(view.findById(fivePoints[1].id), null);
381             assert.equal(view.findById(fivePoints[2].id), null);
382             assert.equal(view.findById(fivePoints[3].id), fivePoints[3]);
383             assert.equal(view.findById(fivePoints[4].id), null);
384
385             assert.deepEqual(view.values(), [fivePoints[3].value]);
386
387             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[4].time), fivePoints[3]);
388             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[4].time), fivePoints[3]);
389             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[1].time), null);
390             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[0].time), null);
391             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time + 0.1, fivePoints[2].time), null);
392             assert.deepEqual(view.firstPointInTimeRange(fivePoints[3].time - 0.1, fivePoints[4].time), fivePoints[3]);
393             assert.deepEqual(view.firstPointInTimeRange(fivePoints[4].time, fivePoints[4].time), null);
394
395             assert.deepEqual([...view], [fivePoints[3]]);
396         });
397
398         it('should create a view filtered by the specified time range on a view already filtered', () => {
399             const timeSeries = new TimeSeries();
400             addPointsToSeries(timeSeries, fivePoints);
401             const originalView = timeSeries.viewBetweenPoints(fivePoints[0], fivePoints[4]);
402             const prefilteredView = originalView.filter((point) => { return point == fivePoints[1] || point == fivePoints[3]; });
403             const view = prefilteredView.viewTimeRange(fivePoints[3].time - 0.1, fivePoints[3].time + 0.1);
404
405             assert.equal(view.length(), 1);
406             assert.equal(view.firstPoint(), fivePoints[3]);
407             assert.equal(view.lastPoint(), fivePoints[3]);
408
409             assert.equal(view.nextPoint(fivePoints[3]), null);
410             assert.equal(view.previousPoint(fivePoints[3]), null);
411
412             assert.equal(view.findPointByIndex(0), fivePoints[3]);
413             assert.equal(view.findPointByIndex(1), null);
414
415             assert.equal(view.findById(fivePoints[0].id), null);
416             assert.equal(view.findById(fivePoints[1].id), null);
417             assert.equal(view.findById(fivePoints[2].id), null);
418             assert.equal(view.findById(fivePoints[3].id), fivePoints[3]);
419             assert.equal(view.findById(fivePoints[4].id), null);
420
421             assert.deepEqual(view.values(), [fivePoints[3].value]);
422
423             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[4].time), fivePoints[3]);
424             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[4].time), fivePoints[3]);
425             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time, fivePoints[1].time), null);
426             assert.deepEqual(view.firstPointInTimeRange(fivePoints[0].time, fivePoints[0].time), null);
427             assert.deepEqual(view.firstPointInTimeRange(fivePoints[1].time + 0.1, fivePoints[2].time), null);
428             assert.deepEqual(view.firstPointInTimeRange(fivePoints[3].time - 0.1, fivePoints[4].time), fivePoints[3]);
429             assert.deepEqual(view.firstPointInTimeRange(fivePoints[4].time, fivePoints[4].time), null);
430
431             assert.deepEqual([...view], [fivePoints[3]]);
432         });
433     });
434
435 });