-
Notifications
You must be signed in to change notification settings - Fork 409
/
TestingSequence.cs
89 lines (78 loc) · 3.01 KB
/
TestingSequence.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#region License and Terms
// MoreLINQ - Extensions to LINQ to Objects
// Copyright (c) 2009 Atif Aziz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
namespace MoreLinq.Test
{
using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
static class TestingSequence
{
internal static TestingSequence<T> Of<T>(params T[] elements) =>
new TestingSequence<T>(elements);
internal static TestingSequence<T> AsTestingSequence<T>(this IEnumerable<T> source) =>
source != null
? new TestingSequence<T>(source)
: throw new ArgumentNullException(nameof(source));
}
/// <summary>
/// Sequence that asserts whether its iterator has been disposed
/// when it is disposed itself and also whether GetEnumerator() is
/// called exactly once or not.
/// </summary>
sealed class TestingSequence<T> : IEnumerable<T>, IDisposable
{
bool? _disposed;
IEnumerable<T> _sequence;
internal TestingSequence(IEnumerable<T> sequence) =>
_sequence = sequence;
public int MoveNextCallCount { get; private set; }
void IDisposable.Dispose() =>
AssertDisposed();
/// <summary>
/// Checks that the iterator was disposed, and then resets.
/// </summary>
void AssertDisposed()
{
if (_disposed == null)
return;
Assert.IsTrue(_disposed, "Expected sequence to be disposed.");
_disposed = null;
}
public IEnumerator<T> GetEnumerator()
{
Assert.That(_sequence, Is.Not.Null, "LINQ operators should not enumerate a sequence more than once.");
var enumerator = _sequence.GetEnumerator().AsWatchtable();
_disposed = false;
enumerator.Disposed += delegate
{
Assert.That(_disposed, Is.False, "LINQ operators should not dispose a sequence more than once.");
_disposed = true;
};
var ended = false;
enumerator.MoveNextCalled += (_, moved) =>
{
Assert.That(ended, Is.False, "LINQ operators should not continue iterating a sequence that has terminated.");
ended = !moved;
MoveNextCallCount++;
};
_sequence = null;
return enumerator;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}