Пример #1
0
        public void EvaluationBehavior(int count)
        {
            int index = 0;
            int limit = count * 2;

            var source = new DelegateIterator <int>(
                moveNext: () => index++ != limit, // Stop once we go past the limit.
                current: () => index,             // Yield from 1 up to the limit, inclusive.
                dispose: () => index ^= int.MinValue);

            IEnumerator <int> iterator = source.TakeLast(count).GetEnumerator();

            Assert.Equal(0, index); // Nothing should be done before MoveNext is called.

            for (int i = 1; i <= count; i++)
            {
                Assert.True(iterator.MoveNext());
                Assert.Equal(count + i, iterator.Current);

                // After the first MoveNext call to the enumerator, everything should be evaluated and the enumerator
                // should be disposed.
                Assert.Equal(int.MinValue, index & int.MinValue);
                Assert.Equal(limit + 1, index & int.MaxValue);
            }

            Assert.False(iterator.MoveNext());

            // Unlike SkipLast, TakeLast can tell straightaway that it can return a sequence with no elements if count <= 0.
            // The enumerable it returns is a specialized empty iterator that has no connections to the source. Hence,
            // after MoveNext returns false under those circumstances, it won't invoke Dispose on our enumerator.
            int expected = count <= 0 ? 0 : int.MinValue;

            Assert.Equal(expected, index & int.MinValue);
        }
Пример #2
0
        public void DisposeAfterEnumeration(int sourceLength, int subLength)
        {
            int sourceState = 0;
            int subIndex    = 0; // Index within the arrays the sub-collection is supposed to be at.

            int[] subState = new int[sourceLength];

            bool sourceDisposed = false;

            bool[] subCollectionDisposed = new bool[sourceLength];

            var source = new DelegateIterator <int>(
                moveNext: () => ++ sourceState <= sourceLength,
                current: () => 0,
                dispose: () => sourceDisposed = true);

            var subCollection = new DelegateIterator <int>(
                moveNext: () => ++ subState[subIndex] <= subLength,       // Return true `subLength` times.
                current: () => subState[subIndex],
                dispose: () => subCollectionDisposed[subIndex++] = true); // Record that Dispose was called, and move on to the next index.

            var iterator = source.SelectMany(_ => subCollection);

            int index           = 0; // How much have we gone into the iterator?
            IEnumerator <int> e = iterator.GetEnumerator();

            using (e)
            {
                while (e.MoveNext())
                {
                    int item = e.Current;

                    Assert.Equal(subState[subIndex], item); // Verify Current.
                    Assert.Equal(index / subLength, subIndex);

                    Assert.False(sourceDisposed); // Not yet.

                    // This represents whehter the sub-collection we're iterating thru right now
                    // has been disposed. Also not yet.
                    Assert.False(subCollectionDisposed[subIndex]);

                    // However, all of the sub-collections before us should have been disposed.
                    // Their indices should also be maxed out.
                    Assert.All(subState.Take(subIndex), s => Assert.Equal(subLength + 1, s));
                    Assert.All(subCollectionDisposed.Take(subIndex), t => Assert.True(t));

                    index++;
                }
            }

            Assert.True(sourceDisposed);
            Assert.Equal(sourceLength, subIndex);
            Assert.All(subState, s => Assert.Equal(subLength + 1, s));
            Assert.All(subCollectionDisposed, t => Assert.True(t));

            // Make sure the iterator's enumerator has been disposed properly.
            Assert.Equal(0, e.Current); // Default value.
            Assert.False(e.MoveNext());
            Assert.Equal(0, e.Current);
        }
Пример #3
0
        public void EvaluationBehavior(int count)
        {
            // We want to make sure no more than `count` items are ever evaluated ahead of the current position.
            // As an example, if Enumerable.Range(1, 6).SkipLast(2) is called, then we should read in the first 3 items,
            // yield 1, read in 4, yield 2, and so on.
            int index = 0;
            int limit = Math.Max(0, count * 2);

            var source = new DelegateIterator <int>(
                moveNext: () => index++ != limit, // Stop once we go past the limit.
                current: () => index,             // Yield from 1 up to the limit, inclusive.
                dispose: () => index ^= int.MinValue);

            IEnumerator <int> iterator = source.SkipLast(count).GetEnumerator();

            Assert.Equal(0, index); // Nothing should be done before MoveNext is called.

            for (int i = 1; i <= count; i++)
            {
                Assert.True(iterator.MoveNext());
                Assert.Equal(i, iterator.Current);
                Assert.Equal(count + i, index);
            }

            Assert.False(iterator.MoveNext());
            Assert.Equal(int.MinValue, index & int.MinValue);
        }
Пример #4
0
        public void DisposeSource(int sourceCount, int count)
        {
            int state = 0;

            var source = new DelegateIterator <int>(
                moveNext: () => ++ state <= sourceCount,
                current: () => 0,
                dispose: () => state = -1);

            IEnumerator <int> iterator = source.Skip(count).GetEnumerator();
            int iteratorCount          = Math.Max(0, sourceCount - Math.Max(0, count));

            Assert.All(Enumerable.Range(0, iteratorCount), _ => Assert.True(iterator.MoveNext()));

            Assert.False(iterator.MoveNext());
            Assert.Equal(-1, state);
        }
Пример #5
0
        public void DisposeSource(int sourceCount, int count)
        {
            int state = 0;

            var source = new DelegateIterator <int>(
                moveNext: () => ++ state <= sourceCount,
                current: () => 0,
                dispose: () => state = -1);

            IEnumerator <int> iterator = source.Take(count).GetEnumerator();
            int iteratorCount          = Math.Min(sourceCount, Math.Max(0, count));

            Assert.All(Enumerable.Range(0, iteratorCount), _ => Assert.True(iterator.MoveNext()));

            Assert.False(iterator.MoveNext());

            // Unlike Skip, Take can tell straightaway that it can return a sequence with no elements if count <= 0.
            // The enumerable it returns is a specialized empty iterator that has no connections to the source. Hence,
            // after MoveNext returns false under those circumstances, it won't invoke Dispose on our enumerator.
            int expected = count <= 0 ? 0 : -1;

            Assert.Equal(expected, state);
        }
Пример #6
0
        public void DisposeAfterEnumeration(int sourceLength, int subLength)
        {
            int sourceState = 0;
            int subIndex    = 0; // Index within the arrays the sub-collection is supposed to be at.

            int[] subState = new int[sourceLength];

            bool sourceDisposed = false;

            bool[] subCollectionDisposed = new bool[sourceLength];

            var source = new DelegateIterator <int>(
                moveNext: () => ++ sourceState <= sourceLength,
                current: () => 0,
                dispose: () => sourceDisposed = true);

            var subCollection = new DelegateIterator <int>(
                moveNext: () => ++ subState[subIndex] <= subLength,       // Return true `subLength` times.
                current: () => subState[subIndex],
                dispose: () => subCollectionDisposed[subIndex++] = true); // Record that Dispose was called, and move on to the next index.

            var iterator = source.SelectMany(_ => subCollection);

            int index           = 0; // How much have we gone into the iterator?
            IEnumerator <int> e = iterator.GetEnumerator();

            using (e)
            {
                while (e.MoveNext())
                {
                    int item = e.Current;

                    Assert.Equal(subState[subIndex], item); // Verify Current.
                    Assert.Equal(index / subLength, subIndex);

                    Assert.False(sourceDisposed); // Not yet.

                    // This represents whehter the sub-collection we're iterating thru right now
                    // has been disposed. Also not yet.
                    Assert.False(subCollectionDisposed[subIndex]);

                    // However, all of the sub-collections before us should have been disposed.
                    // Their indices should also be maxed out.
                    Assert.All(subState.Take(subIndex), s => Assert.Equal(subLength + 1, s));
                    Assert.All(subCollectionDisposed.Take(subIndex), t => Assert.True(t));

                    index++;
                }
            }

            Assert.True(sourceDisposed);
            Assert.Equal(sourceLength, subIndex);
            Assert.All(subState, s => Assert.Equal(subLength + 1, s));
            Assert.All(subCollectionDisposed, t => Assert.True(t));

            // .NET Core fixes an oversight where we wouldn't properly dispose
            // the SelectMany iterator. See https://github.com/dotnet/corefx/pull/13942.
            int expectedCurrent = PlatformDetection.IsFullFramework ? subLength : 0;

            Assert.Equal(expectedCurrent, e.Current);
            Assert.False(e.MoveNext());
            Assert.Equal(expectedCurrent, e.Current);
        }