1/*
2 * Copyright (c) 2013, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "core/html/TimeRanges.h"
33
34#include "bindings/core/v8/ExceptionStatePlaceholder.h"
35#include <gtest/gtest.h>
36
37#include <sstream>
38
39using blink::TimeRanges;
40
41static std::string ToString(const TimeRanges& ranges)
42{
43    std::stringstream ss;
44    ss << "{";
45    for (unsigned i = 0; i < ranges.length(); ++i)
46        ss << " [" << ranges.start(i, IGNORE_EXCEPTION) << "," << ranges.end(i, IGNORE_EXCEPTION) << ")";
47    ss << " }";
48
49    return ss.str();
50}
51
52#define ASSERT_RANGE(expected, range) ASSERT_EQ(expected, ToString(*range))
53
54TEST(TimeRanges, Empty)
55{
56    ASSERT_RANGE("{ }", TimeRanges::create());
57}
58
59TEST(TimeRanges, SingleRange)
60{
61    ASSERT_RANGE("{ [1,2) }", TimeRanges::create(1, 2));
62}
63
64TEST(TimeRanges, CreateFromWebTimeRanges)
65{
66    blink::WebTimeRanges webRanges(static_cast<size_t>(2));
67    webRanges[0].start = 0;
68    webRanges[0].end = 1;
69    webRanges[1].start = 2;
70    webRanges[1].end = 3;
71    ASSERT_RANGE("{ [0,1) [2,3) }", TimeRanges::create(webRanges));
72}
73
74TEST(TimeRanges, AddOrder)
75{
76    RefPtrWillBeRawPtr<TimeRanges> rangeA = TimeRanges::create();
77    RefPtrWillBeRawPtr<TimeRanges> rangeB = TimeRanges::create();
78
79    rangeA->add(0, 2);
80    rangeA->add(3, 4);
81    rangeA->add(5, 100);
82
83    std::string expected = "{ [0,2) [3,4) [5,100) }";
84    ASSERT_RANGE(expected, rangeA);
85
86    // Add the values in rangeA to rangeB in reverse order.
87    for (int i = rangeA->length() - 1; i >= 0; --i)
88        rangeB->add(rangeA->start(i, IGNORE_EXCEPTION), rangeA->end(i, IGNORE_EXCEPTION));
89
90    ASSERT_RANGE(expected, rangeB);
91}
92
93TEST(TimeRanges, OverlappingAdds)
94{
95    RefPtrWillBeRawPtr<TimeRanges> ranges = TimeRanges::create();
96
97    ranges->add(0, 2);
98    ranges->add(10, 11);
99    ASSERT_RANGE("{ [0,2) [10,11) }", ranges);
100
101    ranges->add(0, 2);
102    ASSERT_RANGE("{ [0,2) [10,11) }", ranges);
103
104    ranges->add(2, 3);
105    ASSERT_RANGE("{ [0,3) [10,11) }", ranges);
106
107    ranges->add(2, 6);
108    ASSERT_RANGE("{ [0,6) [10,11) }", ranges);
109
110    ranges->add(9, 10);
111    ASSERT_RANGE("{ [0,6) [9,11) }", ranges);
112
113    ranges->add(8, 10);
114    ASSERT_RANGE("{ [0,6) [8,11) }", ranges);
115
116    ranges->add(-1, 7);
117    ASSERT_RANGE("{ [-1,7) [8,11) }", ranges);
118
119    ranges->add(6, 9);
120    ASSERT_RANGE("{ [-1,11) }", ranges);
121}
122
123TEST(TimeRanges, IntersectWith_Self)
124{
125    RefPtrWillBeRawPtr<TimeRanges> ranges = TimeRanges::create(0, 2);
126
127    ASSERT_RANGE("{ [0,2) }", ranges);
128
129    ranges->intersectWith(ranges.get());
130
131    ASSERT_RANGE("{ [0,2) }", ranges);
132}
133
134TEST(TimeRanges, IntersectWith_IdenticalRange)
135{
136    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create(0, 2);
137    RefPtrWillBeRawPtr<TimeRanges> rangesB = rangesA->copy();
138
139    ASSERT_RANGE("{ [0,2) }", rangesA);
140    ASSERT_RANGE("{ [0,2) }", rangesB);
141
142    rangesA->intersectWith(rangesB.get());
143
144    ASSERT_RANGE("{ [0,2) }", rangesA);
145    ASSERT_RANGE("{ [0,2) }", rangesB);
146}
147
148TEST(TimeRanges, IntersectWith_Empty)
149{
150    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create(0, 2);
151    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
152
153    ASSERT_RANGE("{ [0,2) }", rangesA);
154    ASSERT_RANGE("{ }", rangesB);
155
156    rangesA->intersectWith(rangesB.get());
157
158    ASSERT_RANGE("{ }", rangesA);
159    ASSERT_RANGE("{ }", rangesB);
160}
161
162TEST(TimeRanges, IntersectWith_DisjointRanges1)
163{
164    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
165    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
166
167    rangesA->add(0, 1);
168    rangesA->add(4, 5);
169
170    rangesB->add(2, 3);
171    rangesB->add(6, 7);
172
173    ASSERT_RANGE("{ [0,1) [4,5) }", rangesA);
174    ASSERT_RANGE("{ [2,3) [6,7) }", rangesB);
175
176    rangesA->intersectWith(rangesB.get());
177
178    ASSERT_RANGE("{ }", rangesA);
179    ASSERT_RANGE("{ [2,3) [6,7) }", rangesB);
180}
181
182TEST(TimeRanges, IntersectWith_DisjointRanges2)
183{
184    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
185    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
186
187    rangesA->add(0, 1);
188    rangesA->add(4, 5);
189
190    rangesB->add(1, 4);
191    rangesB->add(5, 7);
192
193    ASSERT_RANGE("{ [0,1) [4,5) }", rangesA);
194    ASSERT_RANGE("{ [1,4) [5,7) }", rangesB);
195
196    rangesA->intersectWith(rangesB.get());
197
198    ASSERT_RANGE("{ }", rangesA);
199    ASSERT_RANGE("{ [1,4) [5,7) }", rangesB);
200}
201
202TEST(TimeRanges, IntersectWith_CompleteOverlap1)
203{
204    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
205    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
206
207    rangesA->add(1, 3);
208    rangesA->add(4, 5);
209    rangesA->add(6, 9);
210
211    rangesB->add(0, 10);
212
213    ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
214    ASSERT_RANGE("{ [0,10) }", rangesB);
215
216    rangesA->intersectWith(rangesB.get());
217
218    ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
219    ASSERT_RANGE("{ [0,10) }", rangesB);
220}
221
222TEST(TimeRanges, IntersectWith_CompleteOverlap2)
223{
224    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
225    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
226
227    rangesA->add(1, 3);
228    rangesA->add(4, 5);
229    rangesA->add(6, 9);
230
231    rangesB->add(1, 9);
232
233    ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
234    ASSERT_RANGE("{ [1,9) }", rangesB);
235
236    rangesA->intersectWith(rangesB.get());
237
238    ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
239    ASSERT_RANGE("{ [1,9) }", rangesB);
240}
241
242TEST(TimeRanges, IntersectWith_Gaps1)
243{
244    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
245    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
246
247    rangesA->add(0, 2);
248    rangesA->add(4, 6);
249
250    rangesB->add(1, 5);
251
252    ASSERT_RANGE("{ [0,2) [4,6) }", rangesA);
253    ASSERT_RANGE("{ [1,5) }", rangesB);
254
255    rangesA->intersectWith(rangesB.get());
256
257    ASSERT_RANGE("{ [1,2) [4,5) }", rangesA);
258    ASSERT_RANGE("{ [1,5) }", rangesB);
259}
260
261TEST(TimeRanges, IntersectWith_Gaps2)
262{
263    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
264    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
265
266    rangesA->add(0, 2);
267    rangesA->add(4, 6);
268    rangesA->add(8, 10);
269
270    rangesB->add(1, 9);
271
272    ASSERT_RANGE("{ [0,2) [4,6) [8,10) }", rangesA);
273    ASSERT_RANGE("{ [1,9) }", rangesB);
274
275    rangesA->intersectWith(rangesB.get());
276
277    ASSERT_RANGE("{ [1,2) [4,6) [8,9) }", rangesA);
278    ASSERT_RANGE("{ [1,9) }", rangesB);
279}
280
281TEST(TimeRanges, IntersectWith_Gaps3)
282{
283    RefPtrWillBeRawPtr<TimeRanges> rangesA = TimeRanges::create();
284    RefPtrWillBeRawPtr<TimeRanges> rangesB = TimeRanges::create();
285
286    rangesA->add(0, 2);
287    rangesA->add(4, 7);
288    rangesA->add(8, 10);
289
290    rangesB->add(1, 5);
291    rangesB->add(6, 9);
292
293    ASSERT_RANGE("{ [0,2) [4,7) [8,10) }", rangesA);
294    ASSERT_RANGE("{ [1,5) [6,9) }", rangesB);
295
296    rangesA->intersectWith(rangesB.get());
297
298    ASSERT_RANGE("{ [1,2) [4,5) [6,7) [8,9) }", rangesA);
299    ASSERT_RANGE("{ [1,5) [6,9) }", rangesB);
300}
301
302TEST(TimeRanges, Nearest)
303{
304    RefPtrWillBeRawPtr<TimeRanges> ranges = TimeRanges::create();
305    ranges->add(0, 2);
306    ranges->add(5, 7);
307
308    ASSERT_EQ(0, ranges->nearest(0, 0));
309    ASSERT_EQ(1, ranges->nearest(1, 0));
310    ASSERT_EQ(2, ranges->nearest(2, 0));
311    ASSERT_EQ(2, ranges->nearest(3, 0));
312    ASSERT_EQ(5, ranges->nearest(4, 0));
313    ASSERT_EQ(5, ranges->nearest(5, 0));
314    ASSERT_EQ(7, ranges->nearest(8, 0));
315
316    ranges->add(9, 11);
317    ASSERT_EQ(7, ranges->nearest(8, 6));
318    ASSERT_EQ(7, ranges->nearest(8, 8));
319    ASSERT_EQ(9, ranges->nearest(8, 10));
320}
321