public void DynamicWindow()

in Sources/Runtime/Test.Psi/OperatorTests.cs [1097:1243]


        public void DynamicWindow()
        {
            // test sets of window and expected result pairs
            void Test(((int, int, int) Window, int[] Expected)[] pairs, bool leftInclusive, bool rightInclusive)
            {
                // data is a 0..9 range, windows are start/end indexes into this + obsolete index
                int[][] GetWindowedData(IEnumerable<(int Obsolete, int Start, int End)> windows)
                {
                    // indexes mapped to originating time
                    DateTime ToTime(int i)
                    {
                        return DateTime.MinValue.AddMilliseconds(i * 10);
                    }

                    using (var p = Pipeline.Create())
                    {
                        var output = Generators.Sequence(p, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }.Select(d => (d, ToTime(d))))
                            .Window(
                                Generators.Sequence(p, windows, TimeSpan.FromMilliseconds(10)),
                                m => (new TimeInterval(ToTime(m.Data.Start), leftInclusive, ToTime(m.Data.End), rightInclusive), ToTime(m.Data.Obsolete)))
                            .Select(ms => ms.Select(m => m.Data).ToArray())
                            .ToObservable().ToListObservable();
                        p.Run();
                        return output.AsEnumerable().ToArray();
                    }
                }

                // get windowed data and compare with expected results
                var results = GetWindowedData(pairs.Select(p => p.Window));
                Assert.AreEqual(results.Length, pairs.Count());
                for (var i = 0; i < results.Length; i++)
                {
                    Assert.IsTrue(Enumerable.SequenceEqual(results[i], pairs[i].Expected));
                }
            }

            // test growing (right) window - pairs are (obsolete, start, end) windows with expected windowed data
            Test(
                new[]
                {
                    ((2, 2, 4), new[] { 2, 3, 4 }), // 2..4 growing to right
                    ((2, 2, 5), new[] { 2, 3, 4, 5 }), // 2..5
                    ((2, 2, 6), new[] { 2, 3, 4, 5, 6 }), // 2..6
                },
                true,
                true);

            // test left inclusivity
            Test(
                new[]
                {
                    ((2, 2, 4), new[] { 3, 4 }),
                    ((2, 2, 5), new[] { 3, 4, 5 }),
                    ((2, 2, 6), new[] { 3, 4, 5, 6 }),
                },
                false /* not including left */,
                true);

            // test right inclusivity
            Test(
                new[]
                {
                    ((2, 2, 4), new[] { 2, 3 }),
                    ((2, 2, 5), new[] { 2, 3, 4 }),
                    ((2, 2, 6), new[] { 2, 3, 4, 5 }),
                },
                true,
                false /* not including right */);

            // test left & right inclusivity
            Test(
                new[]
                {
                    ((2, 2, 4), new[] { 3 }),
                    ((2, 2, 5), new[] { 3, 4 }),
                    ((2, 2, 6), new[] { 3, 4, 5 }),
                },
                false /* not including left */,
                false /* not including right */);

            // test left-most window
            Test(new[] { ((0, 0, 2), new[] { 0, 1, 2 }), }, true, true);

            // test right-most window
            Test(new[] { ((7, 7, 9), new[] { 7, 8, 9 }), }, true, true);

            // test beyond right-most window
            Test(new[] { ((7, 7, 100), new[] { 7, 8, 9 }), }, true, true);

            // test sliding window
            Test(
                new[]
                {
                    ((2, 2, 4), new[] { 2, 3, 4 }), // 2..4 sliding to right
                    ((3, 3, 5), new[] { 3, 4, 5 }), // 3..6
                    ((4, 4, 6), new[] { 4, 5, 6 }), // 4..7
                },
                true,
                true);

            // test growing (left) window
            Test(
                new[]
                {
                    ((1, 3, 5), new[] { 3, 4, 5 }), // 3..5 growing to left
                    ((1, 2, 5), new[] { 2, 3, 4, 5 }), // 2..4
                    ((1, 1, 5), new[] { 1, 2, 3, 4, 5 }), // 1..5
                },
                true,
                true);

            // invalid if obsolete time moves backward!
            try
            {
                Test(
                    new[]
                    {
                        ((3, 3, 5), new[] { 3, 4, 5 }), // 3..5 growing to left
                        ((2, 3, 5), new[] { 3, 4, 5 }), // 3..4 boom! (2 earlier than previous [3] obsolete)
                    },
                    true,
                    true);
                Assert.Fail("Expected exception due to obsolete time backtracking");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(ex.InnerException.Message, "Dynamic window with obsolete time prior to previous window.");
            }

            // invalid if window requests are before previous obsolete time
            try
            {
                Test(
                    new[]
                    {
                        ((3, 3, 5), new[] { 3, 4, 5 }), // 3..5 growing to left
                        ((3, 2, 5), new[] { 1, 3, 4, 5 }), // 2..5 boom! (2 has already been obsoleted)
                    },
                    true,
                    true);
                Assert.Fail("Expected exception due to window request into obsoleted inputs");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(ex.InnerException.Message, "Dynamic window must not extend before previous obsolete time.");
            }
        }