#include #include "Timeline.h" #include #include using namespace testing; using cs = centiseconds; using std::vector; TEST(Timeline, constructors_initializeState) { EXPECT_THAT( Timeline(Timed(cs(10), cs(30), 42)), ElementsAre(Timed(cs(10), cs(30), 42)) ); EXPECT_THAT( Timeline(TimeRange(cs(10), cs(30)), 42), ElementsAre(Timed(cs(10), cs(30), 42)) ); EXPECT_THAT( Timeline(cs(10), cs(30), 42), ElementsAre(Timed(cs(10), cs(30), 42)) ); auto args = { Timed(cs(-10), cs(30), 1), Timed(cs(10), cs(40), 2), Timed(cs(50), cs(60), 3) }; auto expected = { Timed(cs(-10), cs(10), 1), Timed(cs(10), cs(40), 2), Timed(cs(40), cs(50), 42), Timed(cs(50), cs(60), 3) }; EXPECT_THAT( Timeline(args.begin(), args.end(), 42), ElementsAreArray(expected) ); EXPECT_THAT( Timeline(args, 42), ElementsAreArray(expected) ); } TEST(Timeline, constructors_throwForInvalidArgs) { EXPECT_THROW( Timeline(cs(10), cs(9)), std::invalid_argument ); } TEST(Timeline, empty) { Timeline empty1{}; EXPECT_TRUE(empty1.empty()); EXPECT_THAT(empty1, IsEmpty()); Timeline empty2(cs(1), cs(1)); EXPECT_TRUE(empty2.empty()); EXPECT_THAT(empty2, IsEmpty()); Timeline nonEmpty(cs(1), cs(2)); EXPECT_FALSE(nonEmpty.empty()); EXPECT_THAT(nonEmpty, Not(IsEmpty())); } TEST(Timeline, size) { Timeline empty1{}; EXPECT_EQ(0, empty1.size()); EXPECT_THAT(empty1, SizeIs(0)); Timeline empty2(cs(1), cs(1)); EXPECT_EQ(0, empty2.size()); EXPECT_THAT(empty2, SizeIs(0)); Timeline size1(cs(1), cs(10)); EXPECT_EQ(1, size1.size()); EXPECT_THAT(size1, SizeIs(1)); Timeline size2{Timed(cs(-10), cs(10), 1), Timed(cs(10), cs(11), 5)}; EXPECT_EQ(2, size2.size()); EXPECT_THAT(size2, SizeIs(2)); } TEST(Timeline, getRange) { Timeline empty1{}; EXPECT_EQ(TimeRange(cs(0), cs(0)), empty1.getRange()); Timeline empty2(cs(1), cs(1)); EXPECT_EQ(TimeRange(cs(1), cs(1)), empty2.getRange()); Timeline nonEmpty1(cs(1), cs(10)); EXPECT_EQ(TimeRange(cs(1), cs(10)), nonEmpty1.getRange()); Timeline nonEmpty2{ Timed(cs(-10), cs(10), 1), Timed(cs(10), cs(11), 5) }; EXPECT_EQ(TimeRange(cs(-10), cs(11)), nonEmpty2.getRange()); } TEST(Timeline, iterators) { Timeline timeline{ Timed(cs(-5), cs(0), 10), Timed(cs(5), cs(15), 9) }; auto expected = { Timed(cs(-5), cs(0), 10), Timed(cs(0), cs(5), 0), Timed(cs(5), cs(15), 9) }; EXPECT_THAT(timeline, ElementsAreArray(expected)); vector> reversedActual; std::copy(timeline.rbegin(), timeline.rend(), back_inserter(reversedActual)); vector> reversedExpected; std::reverse_copy(expected.begin(), expected.end(), back_inserter(reversedExpected)); EXPECT_THAT(reversedActual, ElementsAreArray(reversedExpected)); } TEST(Timeline, find) { vector> elements = { Timed(cs(1), cs(2), 1), // #0 Timed(cs(2), cs(4), 2), // #1 Timed(cs(4), cs(5), 3) // #2 }; Timeline timeline(elements.begin(), elements.end()); EXPECT_EQ(timeline.end(), timeline.find(cs(-1))); EXPECT_EQ(timeline.end(), timeline.find(cs(0))); EXPECT_EQ(elements[0], *timeline.find(cs(1))); EXPECT_EQ(elements[1], *timeline.find(cs(2))); EXPECT_EQ(elements[1], *timeline.find(cs(3))); EXPECT_EQ(elements[2], *timeline.find(cs(4))); EXPECT_EQ(timeline.end(), timeline.find(cs(5))); } TEST(Timeline, get) { vector> elements = { Timed(cs(1), cs(2), 1), // #0 Timed(cs(2), cs(4), 2), // #1 Timed(cs(4), cs(5), 3) // #2 }; Timeline timeline(elements.begin(), elements.end()); EXPECT_THROW(timeline.get(cs(-1)), std::invalid_argument); EXPECT_THROW(timeline.get(cs(0)), std::invalid_argument); EXPECT_EQ(elements[0], timeline.get(cs(1))); EXPECT_EQ(elements[1], timeline.get(cs(2))); EXPECT_EQ(elements[1], timeline.get(cs(3))); EXPECT_EQ(elements[2], timeline.get(cs(4))); EXPECT_THROW(timeline.get(cs(5)), std::invalid_argument); } void testSetter(std::function&, Timeline&)> set) { const Timed initial(cs(0), cs(10), 42); Timeline timeline(initial); vector expectedValues(10, 42); auto newElements = { Timed(cs(1), cs(2), 4), Timed(cs(3), cs(6), 4), Timed(cs(7), cs(9), 5), Timed(cs(9), cs(10), 6), Timed(cs(2), cs(3), 4), Timed(cs(0), cs(1), 7), Timed(cs(-10), cs(1), 8), Timed(cs(-10), cs(0), 9), Timed(cs(-10), cs(-1), 10), Timed(cs(9), cs(20), 11), Timed(cs(10), cs(20), 12), Timed(cs(11), cs(20), 13), Timed(cs(4), cs(6), 14), Timed(cs(4), cs(6), 15), Timed(cs(8), cs(10), 15), Timed(cs(6), cs(8), 15), Timed(cs(6), cs(8), 16) }; for (const auto& newElement : newElements) { // Set element in timeline set(newElement, timeline); // Update expected value for every index cs elementStart = max(newElement.getStart(), cs(0)); cs elementEnd = min(newElement.getEnd(), cs(10)); for (cs t = elementStart; t < elementEnd; ++t) { expectedValues[t.count()] = newElement.getValue(); } // Check timeline via indexer for (cs t = cs(0); t < cs(10); ++t) { EXPECT_EQ(expectedValues[t.count()], timeline[t]); } // Check timeline via iterators int lastValue = std::numeric_limits::min(); for (const auto& element : timeline) { // No element shound have zero-length EXPECT_LT(cs(0), element.getLength()); // No two adjacent elements should have the same value; they should have been merged EXPECT_NE(lastValue, element.getValue()); lastValue = element.getValue(); // Element should match expected values for (cs t = element.getStart(); t < element.getEnd(); ++t) { EXPECT_EQ(expectedValues[t.count()], element.getValue()); } } } } TEST(Timeline, set) { testSetter([](const Timed& element, Timeline& timeline) { timeline.set(element); }); testSetter([](const Timed& element, Timeline& timeline) { timeline.set(element, element.getValue()); }); testSetter([](const Timed& element, Timeline& timeline) { timeline.set(element.getStart(), element.getEnd(), element.getValue()); }); } TEST(Timeline, indexer_set) { testSetter([](const Timed& element, Timeline& timeline) { for (cs t = element.getStart(); t < element.getEnd(); ++t) { if (t >= timeline.getRange().getStart() && t < timeline.getRange().getEnd()) { timeline[t] = element.getValue(); } else { EXPECT_THROW(timeline[t] = element.getValue(), std::invalid_argument); } } }); } TEST(Timeline, equality) { vector> timelines = { Timeline{}, Timeline(cs(1), cs(1)), Timeline(cs(1), cs(2)), Timeline(cs(-10), cs(0)) }; for (size_t i = 0; i < timelines.size(); ++i) { for (size_t j = 0; j < timelines.size(); ++j) { if (i == j) { EXPECT_EQ(timelines[i], Timeline(timelines[j])); } else { EXPECT_NE(timelines[i], timelines[j]); } } } }