I'm trying to write an NUnit test to check that my extension method throws an exception when called with a negative parameter, what i want is to execute the first two if condition to check the parameters without enumerating the soruce "infiniteSeq", not even partially.
I want this test to have success without using a toList or something to force the enumeration.
Assert.That(()=> infiniteSeq.Smooth(-1), Throws.TypeOf<ArgumentOutOfRangeException>());
This is my extension method, it must never end, if it does then the source is finite and it throws a FiniteSourceException.
public static IEnumerable<double> Smooth(this IEnumerable<double> s, int N)
{
if (N < 0) throw new ArgumentOutOfRangeException(nameof(N), "Is negative");
if (s is null) throw new ArgumentNullException(nameof(s), "is null");
while (true)
{
List<double> buffer = new List<double>();
using (var seqEnumerator = s.GetEnumerator())
{
int index = 0;
while (seqEnumerator.MoveNext())
{
buffer.Add(seqEnumerator.Current);
//Enough items to start Smoothing
if (buffer.Count >= N*2)
{
List<double> elementForAvg;
try
{
int startIndex = (index-N<0) ? 0 : index-N;
int endIndex = index+N;
elementForAvg = buffer.GetRange(startIndex,endIndex);
}
catch (Exception e)
{
if (e is ArgumentException)
throw new FiniteSourceException();
throw;
}
yield return AvgCalculator(elementForAvg);
index++;
}
}
throw new FiniteSourceException();
}
Is this possible?
If you're concerned about invoking an infinite loop, you could always perform a single iteration which will execute the
ifstatements:An alternative approach would be to alter the behaviour of
Smoothto throw immediately rather than after the first iteration.You could do this by returning an iterator instead of using
yieldwithin the body ofSmooth:In the above example, the
yieldkeyword is used within theIteratorlocal method rather thanSmooth, meaningSmoothis no longer an iterator and it's body will execute at the point of call rather than being deferred.