/* -*- 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/dom/TimeRanges.h" #include "TimeUnits.h" #include "Intervals.h" #include <algorithm> #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::Microseconds startus(aStart); media::TimeUnit start(startus); media::TimeUnit end; // operator= test end = media::Microseconds(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 media::Microseconds start(1); const media::Microseconds end(2); const media::Microseconds 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.mValue, end.mValue); media::TimeIntervals blah1(test1); media::TimeIntervals blah2(blah1); media::TimeIntervals blah3 = blah1 + test1; media::TimeIntervals blah4 = test1 + blah1; media::TimeIntervals blah5 = CreateTimeIntervals(start.mValue, end.mValue); (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_EQ(0u, i0.Length()); // 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(IntIntervals aI1, 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.ToTimeRanges(tr); 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 media::TimeIntervals i1(tr); CheckTimeRanges(tr, i1); // static FromTimeRanges media::TimeIntervals i2 = media::TimeIntervals::FromTimeRanges(tr); CheckTimeRanges(tr, i2); media::TimeIntervals i3; // operator=(TimeRanges*) i3 = tr; CheckTimeRanges(tr, i3); // operator= test i1 = tr.get(); CheckTimeRanges(tr, i1); } TEST(IntervalSet, TimeRangesMicroseconds) { media::TimeIntervals i0; // Test media::Microseconds and TimeUnit interchangeability (compilation only) media::TimeUnit time1{media::Microseconds(5)}; media::Microseconds microseconds(5); media::TimeUnit time2 = media::TimeUnit(microseconds); EXPECT_EQ(time1, time2); i0 += media::TimeInterval(media::Microseconds(20), media::Microseconds(25)); i0 += media::TimeInterval(media::Microseconds(40), media::Microseconds(60)); i0 += media::TimeInterval(media::Microseconds(5), media::Microseconds(10)); media::TimeIntervals i1; i1.Add(media::TimeInterval(media::Microseconds(16), media::Microseconds(27))); i1.Add(media::TimeInterval(media::Microseconds(7), media::Microseconds(15))); i1.Add(media::TimeInterval(media::Microseconds(53), media::Microseconds(57))); i1.Add(media::TimeInterval(media::Microseconds(45), media::Microseconds(50))); media::TimeIntervals i(i0 + i1); RefPtr<dom::TimeRanges> tr = new dom::TimeRanges(); i.ToTimeRanges(tr); 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{media::TimeIntervals::FromTimeRanges(tr)}; RefPtr<dom::TimeRanges> tr2 = new dom::TimeRanges(); i_oo.ToTimeRanges(tr2); 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(mozilla::IsSame<nsTArray_CopyChooser<IntIntervals>::Type, nsTArray_CopyWithConstructors<IntIntervals>>::value, "Must use copy constructor"); static_assert(mozilla::IsSame<nsTArray_CopyChooser<media::TimeIntervals>::Type, nsTArray_CopyWithConstructors<media::TimeIntervals>>::value, "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_EQ(0u, i0.Length()); 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); }