summaryrefslogtreecommitdiffstats
path: root/dom/media/gtest/TestIntervalSet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/gtest/TestIntervalSet.cpp')
-rw-r--r--dom/media/gtest/TestIntervalSet.cpp819
1 files changed, 819 insertions, 0 deletions
diff --git a/dom/media/gtest/TestIntervalSet.cpp b/dom/media/gtest/TestIntervalSet.cpp
new file mode 100644
index 0000000000..11d0428f6c
--- /dev/null
+++ b/dom/media/gtest/TestIntervalSet.cpp
@@ -0,0 +1,819 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/TimeRanges.h"
+#include "TimeUnits.h"
+#include "Intervals.h"
+#include <algorithm>
+#include <type_traits>
+#include <vector>
+
+using namespace mozilla;
+
+typedef media::Interval<uint8_t> ByteInterval;
+typedef media::Interval<int> IntInterval;
+typedef media::IntervalSet<int> IntIntervals;
+
+ByteInterval CreateByteInterval(int32_t aStart, int32_t aEnd) {
+ ByteInterval test(aStart, aEnd);
+ return test;
+}
+
+media::IntervalSet<uint8_t> CreateByteIntervalSet(int32_t aStart,
+ int32_t aEnd) {
+ media::IntervalSet<uint8_t> test;
+ test += ByteInterval(aStart, aEnd);
+ return test;
+}
+
+TEST(IntervalSet, Constructors)
+{
+ const int32_t start = 1;
+ const int32_t end = 2;
+ const int32_t fuzz = 0;
+
+ // Compiler exercise.
+ ByteInterval test1(start, end);
+ ByteInterval test2(test1);
+ ByteInterval test3(start, end, fuzz);
+ ByteInterval test4(test3);
+ ByteInterval test5 = CreateByteInterval(start, end);
+
+ media::IntervalSet<uint8_t> blah1(test1);
+ media::IntervalSet<uint8_t> blah2 = blah1;
+ media::IntervalSet<uint8_t> blah3 = blah1 + test1;
+ media::IntervalSet<uint8_t> blah4 = test1 + blah1;
+ media::IntervalSet<uint8_t> blah5 = CreateByteIntervalSet(start, end);
+ (void)test1;
+ (void)test2;
+ (void)test3;
+ (void)test4;
+ (void)test5;
+ (void)blah1;
+ (void)blah2;
+ (void)blah3;
+ (void)blah4;
+ (void)blah5;
+}
+
+media::TimeInterval CreateTimeInterval(int32_t aStart, int32_t aEnd) {
+ // Copy constructor test
+ media::TimeUnit start = media::TimeUnit::FromMicroseconds(aStart);
+ media::TimeUnit end;
+ // operator= test
+ end = media::TimeUnit::FromMicroseconds(aEnd);
+ media::TimeInterval ti(start, end);
+ return ti;
+}
+
+media::TimeIntervals CreateTimeIntervals(int32_t aStart, int32_t aEnd) {
+ media::TimeIntervals test;
+ test += CreateTimeInterval(aStart, aEnd);
+ return test;
+}
+
+TEST(IntervalSet, TimeIntervalsConstructors)
+{
+ const auto start = media::TimeUnit::FromMicroseconds(1);
+ const auto end = media::TimeUnit::FromMicroseconds(2);
+ const media::TimeUnit fuzz;
+
+ // Compiler exercise.
+ media::TimeInterval test1(start, end);
+ media::TimeInterval test2(test1);
+ media::TimeInterval test3(start, end, fuzz);
+ media::TimeInterval test4(test3);
+ media::TimeInterval test5 =
+ CreateTimeInterval(start.ToMicroseconds(), end.ToMicroseconds());
+
+ media::TimeIntervals blah1(test1);
+ media::TimeIntervals blah2(blah1);
+ media::TimeIntervals blah3 = blah1 + test1;
+ media::TimeIntervals blah4 = test1 + blah1;
+ media::TimeIntervals blah5 =
+ CreateTimeIntervals(start.ToMicroseconds(), end.ToMicroseconds());
+ (void)test1;
+ (void)test2;
+ (void)test3;
+ (void)test4;
+ (void)test5;
+ (void)blah1;
+ (void)blah2;
+ (void)blah3;
+ (void)blah4;
+ (void)blah5;
+
+ media::TimeIntervals i0{media::TimeInterval(media::TimeUnit::FromSeconds(0),
+ media::TimeUnit::FromSeconds(0))};
+ EXPECT_TRUE(i0.IsEmpty()); // Constructing with an empty time interval.
+}
+
+TEST(IntervalSet, Length)
+{
+ IntInterval i(15, 25);
+ EXPECT_EQ(10, i.Length());
+}
+
+TEST(IntervalSet, Intersects)
+{
+ EXPECT_TRUE(IntInterval(1, 5).Intersects(IntInterval(3, 4)));
+ EXPECT_TRUE(IntInterval(1, 5).Intersects(IntInterval(3, 7)));
+ EXPECT_TRUE(IntInterval(1, 5).Intersects(IntInterval(-1, 3)));
+ EXPECT_TRUE(IntInterval(1, 5).Intersects(IntInterval(-1, 7)));
+ EXPECT_FALSE(IntInterval(1, 5).Intersects(IntInterval(6, 7)));
+ EXPECT_FALSE(IntInterval(1, 5).Intersects(IntInterval(-1, 0)));
+ // End boundary is exclusive of the interval.
+ EXPECT_FALSE(IntInterval(1, 5).Intersects(IntInterval(5, 7)));
+ EXPECT_FALSE(IntInterval(1, 5).Intersects(IntInterval(0, 1)));
+ // Empty identical interval do not intersect.
+ EXPECT_FALSE(IntInterval(1, 1).Intersects(IntInterval(1, 1)));
+ // Empty interval do not intersect.
+ EXPECT_FALSE(IntInterval(1, 1).Intersects(IntInterval(2, 2)));
+}
+
+TEST(IntervalSet, Intersection)
+{
+ IntInterval i0(10, 20);
+ IntInterval i1(15, 25);
+ IntInterval i = i0.Intersection(i1);
+ EXPECT_EQ(15, i.mStart);
+ EXPECT_EQ(20, i.mEnd);
+ IntInterval j0(10, 20);
+ IntInterval j1(20, 25);
+ IntInterval j = j0.Intersection(j1);
+ EXPECT_TRUE(j.IsEmpty());
+ IntInterval k0(2, 2);
+ IntInterval k1(2, 2);
+ IntInterval k = k0.Intersection(k1);
+ EXPECT_TRUE(k.IsEmpty());
+}
+
+TEST(IntervalSet, Equals)
+{
+ IntInterval i0(10, 20);
+ IntInterval i1(10, 20);
+ EXPECT_EQ(i0, i1);
+
+ IntInterval i2(5, 20);
+ EXPECT_NE(i0, i2);
+
+ IntInterval i3(10, 15);
+ EXPECT_NE(i0, i2);
+}
+
+TEST(IntervalSet, IntersectionIntervalSet)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+
+ IntIntervals i1;
+ i1.Add(IntInterval(7, 15));
+ i1.Add(IntInterval(16, 27));
+ i1.Add(IntInterval(45, 50));
+ i1.Add(IntInterval(53, 57));
+
+ IntIntervals i = media::Intersection(i0, i1);
+
+ EXPECT_EQ(4u, i.Length());
+
+ EXPECT_EQ(7, i[0].mStart);
+ EXPECT_EQ(10, i[0].mEnd);
+
+ EXPECT_EQ(20, i[1].mStart);
+ EXPECT_EQ(25, i[1].mEnd);
+
+ EXPECT_EQ(45, i[2].mStart);
+ EXPECT_EQ(50, i[2].mEnd);
+
+ EXPECT_EQ(53, i[3].mStart);
+ EXPECT_EQ(57, i[3].mEnd);
+}
+
+template <typename T>
+static void Compare(const media::IntervalSet<T>& aI1,
+ const media::IntervalSet<T>& aI2) {
+ EXPECT_EQ(aI1.Length(), aI2.Length());
+ if (aI1.Length() != aI2.Length()) {
+ return;
+ }
+ for (uint32_t i = 0; i < aI1.Length(); i++) {
+ EXPECT_EQ(aI1[i].mStart, aI2[i].mStart);
+ EXPECT_EQ(aI1[i].mEnd, aI2[i].mEnd);
+ }
+}
+
+static void GeneratePermutations(const IntIntervals& aI1,
+ const IntIntervals& aI2) {
+ IntIntervals i_ref = media::Intersection(aI1, aI2);
+ // Test all permutations possible
+ std::vector<uint32_t> comb1;
+ for (uint32_t i = 0; i < aI1.Length(); i++) {
+ comb1.push_back(i);
+ }
+ std::vector<uint32_t> comb2;
+ for (uint32_t i = 0; i < aI2.Length(); i++) {
+ comb2.push_back(i);
+ }
+
+ do {
+ do {
+ // Create intervals according to new indexes.
+ IntIntervals i_0;
+ for (uint32_t i = 0; i < comb1.size(); i++) {
+ i_0 += aI1[comb1[i]];
+ }
+ // Test that intervals are always normalized.
+ Compare(aI1, i_0);
+ IntIntervals i_1;
+ for (uint32_t i = 0; i < comb2.size(); i++) {
+ i_1 += aI2[comb2[i]];
+ }
+ Compare(aI2, i_1);
+ // Check intersections yield the same result.
+ Compare(i_0.Intersection(i_1), i_ref);
+ } while (std::next_permutation(comb2.begin(), comb2.end()));
+ } while (std::next_permutation(comb1.begin(), comb1.end()));
+}
+
+TEST(IntervalSet, IntersectionNormalizedIntervalSet)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+
+ IntIntervals i1;
+ i1.Add(IntInterval(7, 15));
+ i1.Add(IntInterval(16, 27));
+ i1.Add(IntInterval(45, 50));
+ i1.Add(IntInterval(53, 57));
+
+ GeneratePermutations(i0, i1);
+}
+
+TEST(IntervalSet, IntersectionUnorderedNonNormalizedIntervalSet)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(8, 25);
+ i0 += IntInterval(24, 60);
+
+ IntIntervals i1;
+ i1.Add(IntInterval(7, 15));
+ i1.Add(IntInterval(10, 27));
+ i1.Add(IntInterval(45, 50));
+ i1.Add(IntInterval(53, 57));
+
+ GeneratePermutations(i0, i1);
+}
+
+TEST(IntervalSet, IntersectionNonNormalizedInterval)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(8, 25);
+ i0 += IntInterval(30, 60);
+
+ media::Interval<int> i1(9, 15);
+ i0.Intersection(i1);
+ EXPECT_EQ(1u, i0.Length());
+ EXPECT_EQ(i0[0].mStart, i1.mStart);
+ EXPECT_EQ(i0[0].mEnd, i1.mEnd);
+}
+
+TEST(IntervalSet, IntersectionUnorderedNonNormalizedInterval)
+{
+ IntIntervals i0;
+ i0 += IntInterval(1, 3);
+ i0 += IntInterval(1, 10);
+ i0 += IntInterval(9, 12);
+ i0 += IntInterval(12, 15);
+ i0 += IntInterval(8, 25);
+ i0 += IntInterval(30, 60);
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(30, 60);
+
+ media::Interval<int> i1(9, 15);
+ i0.Intersection(i1);
+ EXPECT_EQ(1u, i0.Length());
+ EXPECT_EQ(i0[0].mStart, i1.mStart);
+ EXPECT_EQ(i0[0].mEnd, i1.mEnd);
+}
+
+static IntIntervals Duplicate(const IntIntervals& aValue) {
+ IntIntervals value(aValue);
+ return value;
+}
+
+TEST(IntervalSet, Normalize)
+{
+ IntIntervals i;
+ // Test IntervalSet<T> + Interval<T> operator.
+ i = i + IntInterval(20, 30);
+ // Test Internal<T> + IntervalSet<T> operator.
+ i = IntInterval(2, 7) + i;
+ // Test Interval<T> + IntervalSet<T> operator
+ i = IntInterval(1, 8) + i;
+ IntIntervals interval;
+ interval += IntInterval(5, 10);
+ // Test += with rval move.
+ i += Duplicate(interval);
+ // Test = with move and add with move.
+ i = Duplicate(interval) + i;
+
+ EXPECT_EQ(2u, i.Length());
+
+ EXPECT_EQ(1, i[0].mStart);
+ EXPECT_EQ(10, i[0].mEnd);
+
+ EXPECT_EQ(20, i[1].mStart);
+ EXPECT_EQ(30, i[1].mEnd);
+
+ media::TimeIntervals ti;
+ ti += media::TimeInterval(media::TimeUnit::FromSeconds(0.0),
+ media::TimeUnit::FromSeconds(3.203333));
+ ti += media::TimeInterval(media::TimeUnit::FromSeconds(3.203366),
+ media::TimeUnit::FromSeconds(10.010065));
+ EXPECT_EQ(2u, ti.Length());
+ ti += media::TimeInterval(ti.Start(0), ti.End(0),
+ media::TimeUnit::FromMicroseconds(35000));
+ EXPECT_EQ(1u, ti.Length());
+}
+
+TEST(IntervalSet, ContainValue)
+{
+ IntIntervals i0;
+ i0 += IntInterval(0, 10);
+ i0 += IntInterval(15, 20);
+ i0 += IntInterval(30, 50);
+ EXPECT_TRUE(i0.Contains(0)); // start is inclusive.
+ EXPECT_TRUE(i0.Contains(17));
+ EXPECT_FALSE(i0.Contains(20)); // end boundary is exclusive.
+ EXPECT_FALSE(i0.Contains(25));
+}
+
+TEST(IntervalSet, ContainValueWithFuzz)
+{
+ IntIntervals i0;
+ i0 += IntInterval(0, 10);
+ i0 += IntInterval(15, 20, 1);
+ i0 += IntInterval(30, 50);
+ EXPECT_TRUE(i0.Contains(0)); // start is inclusive.
+ EXPECT_TRUE(i0.Contains(17));
+ EXPECT_TRUE(
+ i0.Contains(20)); // end boundary is exclusive but we have a fuzz of 1.
+ EXPECT_FALSE(i0.Contains(25));
+}
+
+TEST(IntervalSet, ContainInterval)
+{
+ IntIntervals i0;
+ i0 += IntInterval(0, 10);
+ i0 += IntInterval(15, 20);
+ i0 += IntInterval(30, 50);
+ EXPECT_TRUE(i0.Contains(IntInterval(2, 8)));
+ EXPECT_TRUE(i0.Contains(IntInterval(31, 50)));
+ EXPECT_TRUE(i0.Contains(IntInterval(0, 10)));
+ EXPECT_FALSE(i0.Contains(IntInterval(0, 11)));
+ EXPECT_TRUE(i0.Contains(IntInterval(0, 5)));
+ EXPECT_FALSE(i0.Contains(IntInterval(8, 15)));
+ EXPECT_FALSE(i0.Contains(IntInterval(15, 30)));
+ EXPECT_FALSE(i0.Contains(IntInterval(30, 55)));
+}
+
+TEST(IntervalSet, ContainIntervalWithFuzz)
+{
+ IntIntervals i0;
+ i0 += IntInterval(0, 10);
+ i0 += IntInterval(15, 20);
+ i0 += IntInterval(30, 50);
+ EXPECT_TRUE(i0.Contains(IntInterval(2, 8)));
+ EXPECT_TRUE(i0.Contains(IntInterval(31, 50)));
+ EXPECT_TRUE(i0.Contains(IntInterval(0, 11, 1)));
+ EXPECT_TRUE(i0.Contains(IntInterval(0, 5)));
+ EXPECT_FALSE(i0.Contains(IntInterval(8, 15)));
+ EXPECT_FALSE(i0.Contains(IntInterval(15, 21)));
+ EXPECT_FALSE(i0.Contains(IntInterval(15, 30)));
+ EXPECT_FALSE(i0.Contains(IntInterval(30, 55)));
+
+ IntIntervals i1;
+ i1 += IntInterval(0, 10, 1);
+ i1 += IntInterval(15, 20, 1);
+ i1 += IntInterval(30, 50, 1);
+ EXPECT_TRUE(i1.Contains(IntInterval(2, 8)));
+ EXPECT_TRUE(i1.Contains(IntInterval(29, 51)));
+ EXPECT_TRUE(i1.Contains(IntInterval(0, 11, 1)));
+ EXPECT_TRUE(i1.Contains(IntInterval(15, 21)));
+}
+
+TEST(IntervalSet, Span)
+{
+ IntInterval i0(0, 10);
+ IntInterval i1(20, 30);
+ IntInterval i{i0.Span(i1)};
+
+ EXPECT_EQ(i.mStart, 0);
+ EXPECT_EQ(i.mEnd, 30);
+}
+
+TEST(IntervalSet, Union)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+
+ IntIntervals i1;
+ i1.Add(IntInterval(7, 15));
+ i1.Add(IntInterval(16, 27));
+ i1.Add(IntInterval(45, 50));
+ i1.Add(IntInterval(53, 57));
+
+ IntIntervals i = media::Union(i0, i1);
+
+ EXPECT_EQ(3u, i.Length());
+
+ EXPECT_EQ(5, i[0].mStart);
+ EXPECT_EQ(15, i[0].mEnd);
+
+ EXPECT_EQ(16, i[1].mStart);
+ EXPECT_EQ(27, i[1].mEnd);
+
+ EXPECT_EQ(40, i[2].mStart);
+ EXPECT_EQ(60, i[2].mEnd);
+}
+
+TEST(IntervalSet, UnionNotOrdered)
+{
+ IntIntervals i0;
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+ i0 += IntInterval(5, 10);
+
+ IntIntervals i1;
+ i1.Add(IntInterval(16, 27));
+ i1.Add(IntInterval(7, 15));
+ i1.Add(IntInterval(53, 57));
+ i1.Add(IntInterval(45, 50));
+
+ IntIntervals i = media::Union(i0, i1);
+
+ EXPECT_EQ(3u, i.Length());
+
+ EXPECT_EQ(5, i[0].mStart);
+ EXPECT_EQ(15, i[0].mEnd);
+
+ EXPECT_EQ(16, i[1].mStart);
+ EXPECT_EQ(27, i[1].mEnd);
+
+ EXPECT_EQ(40, i[2].mStart);
+ EXPECT_EQ(60, i[2].mEnd);
+}
+
+TEST(IntervalSet, NormalizeFuzz)
+{
+ IntIntervals i0;
+ i0 += IntInterval(11, 25, 0);
+ i0 += IntInterval(5, 10, 1);
+ i0 += IntInterval(40, 60, 1);
+
+ EXPECT_EQ(2u, i0.Length());
+
+ EXPECT_EQ(5, i0[0].mStart);
+ EXPECT_EQ(25, i0[0].mEnd);
+
+ EXPECT_EQ(40, i0[1].mStart);
+ EXPECT_EQ(60, i0[1].mEnd);
+}
+
+TEST(IntervalSet, UnionFuzz)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10, 1);
+ i0 += IntInterval(11, 25, 0);
+ i0 += IntInterval(40, 60, 1);
+ EXPECT_EQ(2u, i0.Length());
+ EXPECT_EQ(5, i0[0].mStart);
+ EXPECT_EQ(25, i0[0].mEnd);
+ EXPECT_EQ(40, i0[1].mStart);
+ EXPECT_EQ(60, i0[1].mEnd);
+
+ IntIntervals i1;
+ i1.Add(IntInterval(7, 15, 1));
+ i1.Add(IntInterval(16, 27, 1));
+ i1.Add(IntInterval(45, 50, 1));
+ i1.Add(IntInterval(53, 57, 1));
+ EXPECT_EQ(3u, i1.Length());
+ EXPECT_EQ(7, i1[0].mStart);
+ EXPECT_EQ(27, i1[0].mEnd);
+ EXPECT_EQ(45, i1[1].mStart);
+ EXPECT_EQ(50, i1[1].mEnd);
+ EXPECT_EQ(53, i1[2].mStart);
+ EXPECT_EQ(57, i1[2].mEnd);
+
+ IntIntervals i = media::Union(i0, i1);
+
+ EXPECT_EQ(2u, i.Length());
+
+ EXPECT_EQ(5, i[0].mStart);
+ EXPECT_EQ(27, i[0].mEnd);
+
+ EXPECT_EQ(40, i[1].mStart);
+ EXPECT_EQ(60, i[1].mEnd);
+}
+
+TEST(IntervalSet, Contiguous)
+{
+ EXPECT_FALSE(IntInterval(5, 10).Contiguous(IntInterval(11, 25)));
+ EXPECT_TRUE(IntInterval(5, 10).Contiguous(IntInterval(10, 25)));
+ EXPECT_TRUE(IntInterval(5, 10, 1).Contiguous(IntInterval(11, 25)));
+ EXPECT_TRUE(IntInterval(5, 10).Contiguous(IntInterval(11, 25, 1)));
+}
+
+TEST(IntervalSet, TimeRangesSeconds)
+{
+ media::TimeIntervals i0;
+ i0 += media::TimeInterval(media::TimeUnit::FromSeconds(20),
+ media::TimeUnit::FromSeconds(25));
+ i0 += media::TimeInterval(media::TimeUnit::FromSeconds(40),
+ media::TimeUnit::FromSeconds(60));
+ i0 += media::TimeInterval(media::TimeUnit::FromSeconds(5),
+ media::TimeUnit::FromSeconds(10));
+
+ media::TimeIntervals i1;
+ i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(16),
+ media::TimeUnit::FromSeconds(27)));
+ i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(7),
+ media::TimeUnit::FromSeconds(15)));
+ i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(53),
+ media::TimeUnit::FromSeconds(57)));
+ i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(45),
+ media::TimeUnit::FromSeconds(50)));
+
+ media::TimeIntervals i(i0 + i1);
+ RefPtr<dom::TimeRanges> tr = new dom::TimeRanges(i);
+ EXPECT_EQ(tr->Length(), i.Length());
+ for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
+ ErrorResult rv;
+ EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
+ EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
+ EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
+ EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
+ }
+}
+
+static void CheckTimeRanges(dom::TimeRanges* aTr,
+ const media::TimeIntervals& aTi) {
+ RefPtr<dom::TimeRanges> tr = new dom::TimeRanges;
+ tr->Union(aTr, 0); // This will normalize the time range.
+ EXPECT_EQ(tr->Length(), aTi.Length());
+ for (dom::TimeRanges::index_type i = 0; i < tr->Length(); i++) {
+ ErrorResult rv;
+ EXPECT_EQ(tr->Start(i, rv), aTi[i].mStart.ToSeconds());
+ EXPECT_EQ(tr->Start(i, rv), aTi.Start(i).ToSeconds());
+ EXPECT_EQ(tr->End(i, rv), aTi[i].mEnd.ToSeconds());
+ EXPECT_EQ(tr->End(i, rv), aTi.End(i).ToSeconds());
+ }
+}
+
+TEST(IntervalSet, TimeRangesConversion)
+{
+ RefPtr<dom::TimeRanges> tr = new dom::TimeRanges();
+ tr->Add(20, 25);
+ tr->Add(40, 60);
+ tr->Add(5, 10);
+ tr->Add(16, 27);
+ tr->Add(53, 57);
+ tr->Add(45, 50);
+
+ // explicit copy constructor and ToTimeIntervals.
+ media::TimeIntervals i1(tr->ToTimeIntervals());
+ CheckTimeRanges(tr, i1);
+
+ // ctor(const TimeIntervals&)
+ RefPtr<dom::TimeRanges> tr2 = new dom::TimeRanges(tr->ToTimeIntervals());
+ CheckTimeRanges(tr2, i1);
+}
+
+TEST(IntervalSet, TimeRangesMicroseconds)
+{
+ media::TimeIntervals i0;
+
+ i0 += media::TimeInterval(media::TimeUnit::FromMicroseconds(20),
+ media::TimeUnit::FromMicroseconds(25));
+ i0 += media::TimeInterval(media::TimeUnit::FromMicroseconds(40),
+ media::TimeUnit::FromMicroseconds(60));
+ i0 += media::TimeInterval(media::TimeUnit::FromMicroseconds(5),
+ media::TimeUnit::FromMicroseconds(10));
+
+ media::TimeIntervals i1;
+ i1.Add(media::TimeInterval(media::TimeUnit::FromMicroseconds(16),
+ media::TimeUnit::FromMicroseconds(27)));
+ i1.Add(media::TimeInterval(media::TimeUnit::FromMicroseconds(7),
+ media::TimeUnit::FromMicroseconds(15)));
+ i1.Add(media::TimeInterval(media::TimeUnit::FromMicroseconds(53),
+ media::TimeUnit::FromMicroseconds(57)));
+ i1.Add(media::TimeInterval(media::TimeUnit::FromMicroseconds(45),
+ media::TimeUnit::FromMicroseconds(50)));
+
+ media::TimeIntervals i(i0 + i1);
+ RefPtr<dom::TimeRanges> tr = new dom::TimeRanges(i);
+ EXPECT_EQ(tr->Length(), i.Length());
+ for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
+ ErrorResult rv;
+ EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
+ EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
+ EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
+ EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
+ }
+
+ tr->Normalize();
+ EXPECT_EQ(tr->Length(), i.Length());
+ for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
+ ErrorResult rv;
+ EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
+ EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
+ EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
+ EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
+ }
+
+ // Check infinity values aren't lost in the conversion.
+ tr = new dom::TimeRanges();
+ tr->Add(0, 30);
+ tr->Add(50, std::numeric_limits<double>::infinity());
+ media::TimeIntervals i_oo = tr->ToTimeIntervals();
+ RefPtr<dom::TimeRanges> tr2 = new dom::TimeRanges(i_oo);
+ EXPECT_EQ(tr->Length(), tr2->Length());
+ for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
+ ErrorResult rv;
+ EXPECT_EQ(tr->Start(index, rv), tr2->Start(index, rv));
+ EXPECT_EQ(tr->End(index, rv), tr2->End(index, rv));
+ }
+}
+
+template <typename T>
+class Foo {
+ public:
+ Foo() : mArg1(1), mArg2(2), mArg3(3) {}
+
+ Foo(T a1, T a2, T a3) : mArg1(a1), mArg2(a2), mArg3(a3) {}
+
+ Foo<T> operator+(const Foo<T>& aOther) const {
+ Foo<T> blah;
+ blah.mArg1 += aOther.mArg1;
+ blah.mArg2 += aOther.mArg2;
+ blah.mArg3 += aOther.mArg3;
+ return blah;
+ }
+ Foo<T> operator-(const Foo<T>& aOther) const {
+ Foo<T> blah;
+ blah.mArg1 -= aOther.mArg1;
+ blah.mArg2 -= aOther.mArg2;
+ blah.mArg3 -= aOther.mArg3;
+ return blah;
+ }
+ bool operator<(const Foo<T>& aOther) const { return mArg1 < aOther.mArg1; }
+ bool operator==(const Foo<T>& aOther) const { return mArg1 == aOther.mArg1; }
+ bool operator<=(const Foo<T>& aOther) const { return mArg1 <= aOther.mArg1; }
+
+ private:
+ int32_t mArg1;
+ int32_t mArg2;
+ int32_t mArg3;
+};
+
+TEST(IntervalSet, FooIntervalSet)
+{
+ media::Interval<Foo<int>> i(Foo<int>(), Foo<int>(4, 5, 6));
+ media::IntervalSet<Foo<int>> is;
+ is += i;
+ is += i;
+ is.Add(i);
+ is = is + i;
+ is = i + is;
+ EXPECT_EQ(1u, is.Length());
+ EXPECT_EQ(Foo<int>(), is[0].mStart);
+ EXPECT_EQ(Foo<int>(4, 5, 6), is[0].mEnd);
+}
+
+TEST(IntervalSet, StaticAssert)
+{
+ media::Interval<int> i;
+
+ static_assert(
+ std::is_same_v<nsTArray_RelocationStrategy<IntIntervals>::Type,
+ nsTArray_RelocateUsingMoveConstructor<IntIntervals>>,
+ "Must use copy constructor");
+ static_assert(
+ std::is_same_v<
+ nsTArray_RelocationStrategy<media::TimeIntervals>::Type,
+ nsTArray_RelocateUsingMoveConstructor<media::TimeIntervals>>,
+ "Must use copy constructor");
+}
+
+TEST(IntervalSet, Substraction)
+{
+ IntIntervals i0;
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+
+ IntInterval i1(8, 15);
+ i0 -= i1;
+
+ EXPECT_EQ(3u, i0.Length());
+ EXPECT_EQ(5, i0[0].mStart);
+ EXPECT_EQ(8, i0[0].mEnd);
+ EXPECT_EQ(20, i0[1].mStart);
+ EXPECT_EQ(25, i0[1].mEnd);
+ EXPECT_EQ(40, i0[2].mStart);
+ EXPECT_EQ(60, i0[2].mEnd);
+
+ i0 = IntIntervals();
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+ i1 = IntInterval(0, 60);
+ i0 -= i1;
+ EXPECT_TRUE(i0.IsEmpty());
+
+ i0 = IntIntervals();
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+ i1 = IntInterval(0, 45);
+ i0 -= i1;
+ EXPECT_EQ(1u, i0.Length());
+ EXPECT_EQ(45, i0[0].mStart);
+ EXPECT_EQ(60, i0[0].mEnd);
+
+ i0 = IntIntervals();
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+ i1 = IntInterval(8, 45);
+ i0 -= i1;
+ EXPECT_EQ(2u, i0.Length());
+ EXPECT_EQ(5, i0[0].mStart);
+ EXPECT_EQ(8, i0[0].mEnd);
+ EXPECT_EQ(45, i0[1].mStart);
+ EXPECT_EQ(60, i0[1].mEnd);
+
+ i0 = IntIntervals();
+ i0 += IntInterval(5, 10);
+ i0 += IntInterval(20, 25);
+ i0 += IntInterval(40, 60);
+ i1 = IntInterval(8, 70);
+ i0 -= i1;
+ EXPECT_EQ(1u, i0.Length());
+ EXPECT_EQ(5, i0[0].mStart);
+ EXPECT_EQ(8, i0[0].mEnd);
+
+ i0 = IntIntervals();
+ i0 += IntInterval(0, 10);
+ IntIntervals i2;
+ i2 += IntInterval(4, 6);
+ i0 -= i2;
+ EXPECT_EQ(2u, i0.Length());
+ EXPECT_EQ(0, i0[0].mStart);
+ EXPECT_EQ(4, i0[0].mEnd);
+ EXPECT_EQ(6, i0[1].mStart);
+ EXPECT_EQ(10, i0[1].mEnd);
+
+ i0 = IntIntervals();
+ i0 += IntInterval(0, 1);
+ i0 += IntInterval(3, 10);
+ EXPECT_EQ(2u, i0.Length());
+ // This fuzz should collapse i0 into [0,10).
+ i0.SetFuzz(1);
+ EXPECT_EQ(1u, i0.Length());
+ EXPECT_EQ(1, i0[0].mFuzz);
+ i2 = IntInterval(4, 6);
+ i0 -= i2;
+ EXPECT_EQ(2u, i0.Length());
+ EXPECT_EQ(0, i0[0].mStart);
+ EXPECT_EQ(4, i0[0].mEnd);
+ EXPECT_EQ(6, i0[1].mStart);
+ EXPECT_EQ(10, i0[1].mEnd);
+ EXPECT_EQ(1, i0[0].mFuzz);
+ EXPECT_EQ(1, i0[1].mFuzz);
+
+ i0 = IntIntervals();
+ i0 += IntInterval(0, 10);
+ // [4,6) with fuzz 1 used to fail because the complementary interval set
+ // [0,4)+[6,10) would collapse into [0,10).
+ i2 = IntInterval(4, 6);
+ i2.SetFuzz(1);
+ i0 -= i2;
+ EXPECT_EQ(2u, i0.Length());
+ EXPECT_EQ(0, i0[0].mStart);
+ EXPECT_EQ(4, i0[0].mEnd);
+ EXPECT_EQ(6, i0[1].mStart);
+ EXPECT_EQ(10, i0[1].mEnd);
+}