diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /dom/media/gtest/TestIntervalSet.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream/115.8.0esr.tar.xz firefox-esr-upstream/115.8.0esr.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/gtest/TestIntervalSet.cpp')
-rw-r--r-- | dom/media/gtest/TestIntervalSet.cpp | 819 |
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); +} |