How do I create an IComparer for a Nunit CollectionAssert test? - c#

I wish to create the following test in NUnit for the following scenario: we wish to test the a new calculation method being created yields results similar to that of an old system. An acceptable difference (or rather a redefinition of equality) between all values has been defined as
abs(old_val - new_val) < 0.0001
I know that I can loop through every value from the new list and compare to values from the old list and test the above condition.
How would achieve this using Nunit's CollectionAssert.AreEqual method (or some CollectionAssert method)?

The current answers are outdated. Since NUnit 2.5, there is an overload of CollectionAssert.AreEqual that takes a System.Collections.IComparer.
Here is a minimal implementation:
public class Comparer : System.Collections.IComparer
{
private readonly double _epsilon;
public Comparer(double epsilon)
{
_epsilon = epsilon;
}
public int Compare(object x, object y)
{
var a = (double)x;
var b = (double)y;
double delta = System.Math.Abs(a - b);
if (delta < _epsilon)
{
return 0;
}
return a.CompareTo(b);
}
}
[NUnit.Framework.Test]
public void MyTest()
{
var a = ...
var b = ...
NUnit.Framework.CollectionAssert.AreEqual(a, b, new Comparer(0.0001));
}

Well there is method from the NUnit Framework that allows me to do tolerance checks on collections. Refer to the Equal Constraint. One uses the AsCollection and Within extension methods. On that note though I am not 100% sure regarding the implications of this statement made
If you want to treat the arrays being compared as simple collections,
use the AsCollection modifier, which causes the comparison to be made
element by element, without regard for the rank or dimensions of the
array.
[Test]
//[ExpectedException()]
public void CheckLists_FailsAt0()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result1 = new[] { -0.0004, 0.43520, 1.3454, 345345.0980 };
Assert.That(result1, Is.EqualTo(expected).AsCollection.Within(0.0001), "fail at [0]"); // fail on [0]
}
[Test]
//[ExpectedException()]
public void CheckLists_FailAt1()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result1a = new[] { 0.0001000000 , 0.4348245000 , 1.3450234000 , 345345.0975980000 };
Assert.That(result1a, Is.EqualTo(expected).AsCollection.Within(0.0001), "fail at [1]"); // fail on [3]
}
[Test]
public void CheckLists_AllPass_ForNegativeDiff_of_1over10001()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result2 = new[] { 0.00009900 , 0.43532350 , 1.34552240 , 345345.09809700 };
Assert.That(result2, Is.EqualTo(expected).AsCollection.Within(0.0001)); // pass
}
[Test]
public void CheckLists_StillPass_ForPositiveDiff_of_1over10001()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result3 = new[] { 0.00010100 , 0.43532550 , 1.34552440 , 345345.09809900 };
Assert.That(result3, Is.EqualTo(expected).AsCollection.Within(0.0001)); // pass
}

NUnit does not define any delegate object or interface to perform custom checks to lists, and determine that a expected result is valid.
But I think that the best and simplest option is writing a small static method that achieve your checks:
private const float MIN_ACCEPT_VALUE = 0.0001f;
public static void IsAcceptableDifference(IList collection, IList oldCollection)
{
if (collection == null)
throw new Exception("Source collection is null");
if (oldCollection == null)
throw new Exception("Old collection is null");
if (collection.Count != oldCollection.Count)
throw new Exception("Different lenghts");
for (int i = 0; i < collection.Count; i++)
{
float newValue = (float)collection[i];
float oldValue = (float)oldCollection[i];
float difference = Math.Abs(oldValue - newValue);
if (difference < MIN_ACCEPT_VALUE)
{
throw new Exception(
string.Format(
"Found a difference of {0} at index {1}",
difference,
i));
}
}
}

You've asked how to achieve your desired test using a CollectionAssert method without looping through the list. I'm sure this is obvious, but looping is exactly what such a method would do...
The short answer to your exact question is that you can't use CollectionAssert methods to do what you want. However, if what you really want is an easy way to compare lists of floating point numbers and assert their equality, then read on.
The method Assert.AreEqual( double expected, double actual, double tolerance ) releases you from the need to write the individual item assertions yourself. Using LINQ, you could do something like this:
double delta = 0.0001;
IEnumerable<double> expectedValues;
IEnumerable<double> actualValues;
// code code code
foreach (var pair in expectedValues.Zip(actualValues, Tuple.Create))
{
Assert.AreEqual(pair.Item1, pair.Item2, delta, "Collections differ.");
}
If you wanted to get fancier, you could pull this out into a method of its own, catch the AssertionException, massage it and rethrow it for a cleaner interface.
If you don't care about which items differ:
var areEqual = expectedValues
.Zip(actualValues, Tuple.Create)
.Select(tup => Math.Abs(tup.Item1 - tup.Item2) < delta)
.All(b => b);
Assert.IsTrue(areEqual, "Collections differ.");

Related

Testing an infinite sequence with NUnit, but only a finite sequence must be checked

I have an Extension Method that extract the numbers in a list of strings (bbb1, da21ds, dsa231djsla90 ==> 1, 21, 23190):
public static int[] GetContainedNumbers(this string[] source)
{
if (source == null) throw new ArgumentNullException();
int[] result = new int[] {};
foreach (var s in source)
{
string onlyNumbers = new String(s.Where(Char.IsDigit).ToArray());
if (String.IsNullOrEmpty(onlyNumbers)) throw new ArgumentException();
int extractedNumber = Int32.Parse(onlyNumbers);
result = result.Concat(new int[] { extractedNumber }).ToArray();
}
return result;
}
I need to make a test with NUnit. The request is to make a test with an infinite sequence of strings (a1z, a2z, a3z, ...), but the output only needs to check the first 100 numbers.
Currently I have no idea what I'm supposed to do. My starting idea was to create a test like this:
int[] expectedResult = Enumerable.Range(0, 99).ToArray();
string[] source = new string[] {};
int n = 0;
while (true)
{
if (n == 99) break;
source = source.Concat(new string[] { "a" + n + "z" }).ToArray();
n++;
}
Assert.AreEqual(expectedResult, source.GetContainedNumbers());
But it doesn't really make sense since the array is finite and not infinite.
I don't know what it means to create an infinite list of things and how I should create it nor testing it.
I can edit the Extension Method if needed. Thanks in advance for any help and sorry if my english is quite broken.
The first task is to make the Extension method itself, which I have resolved above. It can be modified, but it must resolve this piece of code (which I can't edit):
foreach (var d in new[] { "1qui7", "q8u8o", "-1024", "0q0ua0" }.GetContainedNumbers())
{
Console.WriteLine("{0}, ", d);
var strings = new [ ] { "1qui7" , " q8u8o " , " −1024" , " 0 q0ua0 " };
}
Expected output: 17, 88, 1024, 0,
I believe the purpose of this exercise is to investigate lazy evaluation.
Currently your method accepts a string[] and returns an int[] - but there's nothing in the question that says it has to do that.
If instead you were to write an extension method accepting an IEnumerable<string> and returning an IEnumerable<int>, then you could accept an infinite sequence of elements and return a corresponding infinite sequence of outputs, that is lazily evaluated: when the caller requests the next output element, you in turn request the next input element, process it, and yield an output. C# makes all of this quite straightforward with iterator blocks.
So I would expect a method like this:
public static IEnumerable<int> GetContainedNumbers(IEnumerable<string> source)
{
foreach (string inputElement)
{
int outputElement = ...; // TODO: your logic here
yield return output;
}
}
Now to test this, you can either use iterator blocks again to generate genuinely infinite sequences, or you could test against an effectively infinite sequence using LINQ, e.g.
IEnumerable<string> veryLargeInput = Enumerable
.Range(0, int.MaxValue)
.Select(x => $"a{x}z");
The truly infinite version might be something like:
IEnumerable<string> infiniteSequence = GetInfiniteSequence();
...
private static IEnumerable<string> GetInfiniteSequence()
{
int value = 0;
while (true)
{
yield return $"x{value}z";
// Eventually this will loop round from int.MaxValue to
// int.MinValue. You could use BigInteger if you really wanted.
value++;
}
}
When testing the result, you'll want to take the first 100 elements of the output. For example:
var input = GetInfiniteSequence(); // Or the huge Enumerable.Range
var output = input.GetContainedNumbers(); // This is still infinite
var first100Elements = output.Take(100).ToList();
// Now make assertions against first100Elements

Overriding many functions of class at once with C#

Maybe overriding isn't the correct term here.
I want to extend some of the System.Math class functions to work on double arrays.
What I'm currently doing is:
public double[] Sin(double[] d)
{
double[] result = new double[d.Length];
for(int i=0;i<result.Length;i++)
result[i] = Math.Sin(d[i]);
}
For many functions in a Math (about 20) just replacing Sin by Cos,Round,...
Is there a way to make this more elegant?
Please note that I'm building something to allow the user to evaluate expressions in runtime.
The user needs to be able to write "Cos(d)" for d double array and for all the functions, so solutions from the input side aren't really an option.
Thanks all
Not really, but you can shorten it with Array.ConvertAll:
double[] result = Array.ConvertAll(d, Math.Sin);
If the function name is in a string, you might be able to use a dictionary:
var dict = new Dictionary<string, Func<double[], double[]>> {
{ "Sin", a => Array.ConvertAll(a, Math.Sin) },
{ "Cos", a => Array.ConvertAll(a, Math.Cos) }
};
double[] d = { 1, 2 };
double[] result = dict["Sin"](d); // { 0.8414709848078965, 0.90929742682568171 }
You can create more generic method to work with the arrays. Something like this
internal static void Transform(double[] values, Func<double, double> transformation)
{
for(int i = 0; i < values.Length; i++)
values[i] = transformation[values[i]];
}
Now you can use more concrete methods like
internal static void Sin(doube[] values)
{
return Transform(values, Math.Sin);
}
Or
internal static void Cos(doube[] values)
{
return Transform(values, Math.Cos);
}
the the usage will be like this
var result = Sin(values)
You could use Extension methods:
public static class MathExtensions
{
public static double[] Sin(this double[] input)
{
return input.Select(Math.Sin).ToArray();
}
}
And then the call would be:
var f = d.Sin();
Note: This doesn't get the syntax you wanted, nor does it solve the issue of having to write one of these for each of the corresponding Math methods but I'll post it here as an answer to how to extend existing methods more elegantly.

List always does not contain array even it is

I am trying to check if list of arrays contains array with factors in reverse order and if not, add them:
var faclist = new List<int[]>();
var factors = new int[2] {i, j};
if (!faclist.Contains(factors.Reverse()))
{
faclist.Add(factors);
}
However this code always not true even there are arrays with reversed factors.
The .Contains works on the .Equals method. By default, the .Equals method returns only true, if the two instances (references) are the same.
A possible way to solve this - if the number of factors are fixed - is using a Tuple<int,int>. You can define the Reverse method on a `Tuple class with:
public static class Foo {
public static Tuple<T2,T1> Reverse<T1,T2> (this Tuple<T1,T2> tuple) {
return new Tuple<T2,T1>(tuple.Item2,tuple.Item1);
}
}
And then call it simply with:
Tuple<int,int> t = new Tuple<int,int>(3,5);
Tuple<int,int> t2 = t.Reverse();
If not, you could define a wrapper class, that performs the equality check as described here.
Or another alternative, is to provide an equality checker yourself in the .Contains method as described by #xanatos answer.
Demo:
$ csharp
Mono C# Shell, type "help;" for help
Enter statements below.
csharp> var t1 = new Tuple<int,int>(3,2);
csharp> var t2 = new Tuple<int,int>(3,2);
csharp> t1.Equals(t2);
true
csharp> int[] t1 = new int[] {3,2};
csharp> int[] t2 = new int[] {3,2};
csharp> t1.Equals(t2);
false
As written by CommuSoft, because arrays don't implement comparison in the way you think (they do only reference comparison)
Another solution is to implement an equality comparer:
public class IntArrayComparison : IEqualityComparer<int[]> {
public bool Equals(int[] x, int[] y) {
if (x == null) {
return y == null;
}
if (y == null) {
return false;
}
return x.SequenceEqual(y);
}
public int GetHashCode(int[] obj) {
throw new NotImplementedException();
}
}
if (!faclist.Contains(factors.Reverse().ToArray(), new IntArrayComparison())) {
And then use it in the Contains method. (note that I have to change the result of Reverse() back to an array, because Reverse() returns an IEnumerable<T>)

Using ImmutableSortedSet<T> for a thread safe cache

I have a method that takes a DateTime and returns the date marking the end of that quarter. Because of some complexity involving business days and holiday calendars, I want to cache the result to speed up subsequent calls. I'm using a SortedSet<DateTime> to maintain a cache of data, and I use the GetViewBetween method in order to do cache lookups as follows:
private static SortedSet<DateTime> quarterEndCache = new SortedSet<DateTime>();
public static DateTime GetNextQuarterEndDate(DateTime date)
{
var oneDayLater = date.AddDays(1.0);
var fiveMonthsLater = date.AddMonths(5);
var range = quarterEndCache.GetViewBetween(oneDayLater, fiveMonthsLater);
if (range.Count > 0)
{
return range.Min;
}
// Perform expensive calc here
}
Now I want to make my cache threadsafe. Rather than use a lock everywhere which would incur a performance hit on every lookup, I'm exploring the new ImmutableSortedSet<T> collection which would allow me to avoid locks entirely. The problem is that ImmutableSortedSet<T> doesn't have the method GetViewBetween. Is there any way to get similar functionality from the ImmutableSortedSet<T>?
[EDIT]
Servy has convinced me just using a lock with a normal SortedSet<T> is the easiest solution. I'll leave the question open though just because I'm interested to know whether the ImmutableSortedSet<T> can handle this scenario efficiently.
Let's divide the question into two parts:
How to get a functionality similar to GetViewBetween with ImmutableSortedSet<T>? I'd suggest using the IndexOf method. In the snippet below, I created an extension method GetRangeBetween which should do the job.
How to implement lock-free, thread-safe updates with data immutable data structures? Despite this is not the original question, there are some skeptical comments with respect to this issue.
The immutables framework implements a method for exactly that purpose: System.Collections.Immutable.Update<T>(ref T location, Func<T, T> transformer) where T : class; The method internally relies on atomic compare/exchange operations. If you want to do this by hand, you'll find an alternative implementation below which should behave the same like Immutable.Update.
So here is the code:
public static class ImmutableExtensions
{
public static IEnumerable<T> GetRangeBetween<T>(
this ImmutableSortedSet<T> set, T min, T max)
{
int i = set.IndexOf(min);
if (i < 0) i = ~i;
while (i < set.Count)
{
T x = set[i++];
if (set.KeyComparer.Compare(x, min) >= 0 &&
set.KeyComparer.Compare(x, max) <= 0)
{
yield return x;
}
else
{
break;
}
}
}
public static void LockfreeUpdate<T>(ref T item, Func<T, T> fn)
where T: class
{
T x, y;
do
{
x = item;
y = fn(x);
} while (Interlocked.CompareExchange(ref item, y, x) != x);
}
}
Usage:
private static volatile ImmutableSortedSet<DateTime> quarterEndCache =
ImmutableSortedSet<DateTime>.Empty;
private static volatile int counter; // test/verification purpose only
public static DateTime GetNextQuarterEndDate(DateTime date)
{
var oneDayLater = date.AddDays(1.0);
var fiveMonthsLater = date.AddMonths(5);
var range = quarterEndCache.GetRangeBetween(oneDayLater, fiveMonthsLater);
if (range.Any())
{
return range.First();
}
// Perform expensive calc here
// -> Meaningless dummy computation for verification purpose only
long x = Interlocked.Increment(ref counter);
DateTime test = DateTime.FromFileTime(x);
ImmutableExtensions.LockfreeUpdate(
ref quarterEndCache,
c => c.Add(test));
return test;
}
[TestMethod]
public void TestIt()
{
var tasks = Enumerable
.Range(0, 100000)
.Select(x => Task.Factory.StartNew(
() => GetNextQuarterEndDate(DateTime.Now)))
.ToArray();
Task.WaitAll(tasks);
Assert.AreEqual(100000, counter);
}

How to test function returns IEnumerable<Integer>

I'm trying to test a function
public static IEnumerable<Integer> Divisors(Integer n)
{
int max = (int)System.Math.Sqrt(n);
if (n != 0)
yield return 1;
for (int i = 2; i <= max; i++)
if (n % i == 0)
yield return i;
}
and I need to write a test function like
[Test]
public void DivisorsTest()
{
Integer n = 0;
IEnumerable<Integer> expected = 0 ; //error
IEnumerable<Integer> actual;
actual = Science.Mathematics.NumberTheoryFunctions.Divisors(n);
Assert.AreEqual(expected, actual);
}
How can I modify this line to test the output I need to test the returning values which are not just a zero
There are various tricks to checking entire collections. It looks like for an input of zero, you don't want to have any values returned (i.e. an empty set), so you could do this:
Assert.IsFalse(actual.Any()); // There should not be any elements returned
For more complex outputs, it is often easier to put the result into an array, and check the results by index like this:
var results = actual.ToArray();
Assert.AreEqual(5, results.Count);
Assert.AreEqual(1, results[0]);
Assert.AreEqual(2, results[1]);
// etc.
Couldn't you use something like this (sorry, it needs Linq):
[Test]
public void DivisorsTest()
{
int n = 0;
int expected = 0; //error
IEnumerable<Integer> actual;
actual = Science.Mathematics.NumberTheoryFunctions.Divisors(n);
Assert.IsTrue(actual.All(x => x != expected));
}
You could also initialize expected to an empty enumerable (i.e., zero elements) like this
IEnumerable<int> expected = System.Linq.Enumerable.Empty<int>();
MSDN Reference for Enumerable
I often use something like that:
var expected = new int[] { /* expected values */ };
var actual = Science.Mathematics.NumberTheoryFunctions.Divisors(n);
Assert.IsTrue(expected.SequenceEquals(actual));
The drawback is that the assertion default error message isn't very descriptive:
Expected: True
But was: False
Instead, you can use CollectionAssert.AreEquivalent, which gives a more detailed error message, but it's not ideal either... If you use a Linq query, the message can look like that:
Expected: equivalent to < 0, 1, 3, 4, 6, 7, 9, 10 >
But was: <System.Linq.Enumerable+<WhereIterator>d__0`1[System.Int32]>
(at least with NUnit 2.4.8, perhaps I should upgrade to a newer version...)
OK, thanks everybody for your answers and here is what i did using your answers
the test functions will be :
1- when you expect that the function won't return any value
[Test]
public void DivisorsTest_01()
{
Integer n = 0;
IEnumerable<Integer> actual;
actual = Science.Mathematics.NumberTheoryFunctions.Divisors(n);
Assert.IsFalse(actual.Any()); // There should not be any elements returned so empty
}
2- all what you need is to convert the o/p into an array and use it :
[Test]
public void DivisorsTest_03()
{
Integer n = 9;
Integer[] expected = new Integer[3] { 1,3,9 };
IEnumerable<Integer> actual;
actual = Science.Mathematics.NumberTheoryFunctions.Divisors(n);
var actual1 = actual.ToArray();
Assert.AreEqual(expected[0], actual1[0]);
Assert.AreEqual(expected[1], actual1[1]);
Assert.AreEqual(expected[2], actual1[2]);
}
3- sometimes you expect the output will be exception so don't forget to write:
[Test]
[ExpectedException]
before the function.
thanks again everybody

Categories