I have a list of string values. I iterate this list with a foreach. I apply on every list item Assert.That() method. Now comes the twist: I give as a second parameter of the method a function that returns IResolveConstraint. When the function returns Has.Exactly(1).Contains(), then AT THE SECOND item of the list (second iteration of the foreach) the assertion evaluates (throws) this message: "Expected: collection containing "value"". But the assertion was supposed to pass, because it was verifying exactly one item, not a collection.
I had NUnit 3.2.1. I upgraded to version 3.12.0 and after that the message changed from : "Expected: collection containing "value"" to message: "Expected: some item equal to "value"" and assertion still didn' pass.
public class Verifiers
{
public void VerifyCollectedValues(List<string> collectedValues, List<string> expectedValues
, string collectedValuesFrom, int countOfValueExpactance, bool verifyExactSameValue = true)
{
// Create a constraint function
Func<string, IResolveConstraint> constraintFunction = CreateConstraintFunction(Has.Exactly(countOfValueExpactance), verifyExactSameValue);
// Pass the constraint to the method
VerifyCollectedValues(constraintFunction, collectedValues, expectedValues, collectedValuesFrom);
}
public void VerifyCollectedValues(Func<string, IResolveConstraint> constraintFunction, List<string> collectedValues, List<string> expectedValues
, string collectedValuesFrom)
{
foreach (string expectedValue in expectedValues)
{
// Apply the constraint
Assert.That(collectedValues, constraintFunction(expectedValue));
}
}
public Func<string, IResolveConstraint> CreateConstraintFunction(ConstraintExpression constraintExpression, bool verifyExactSameValue)
{
if (verifyExactSameValue)
{
return (string value) => constraintExpression.EqualTo(value);
}
else
{
return (string value) => constraintExpression.Contains(value);
}
}
}
Sample code:
Verifiers verifiers = new Verifiers();
List<string> expectedValues = new List<string>()
{
"value1",
"value2",
"value3",
};
var collectedValues = new List<string>()
{
"some_value0",
"some_value1",
"some_value2",
"some_value3",
};
// This passes
foreach(string expectedValue in expectedValues)
{
Assert.That(collectedValues, Has.Exactly(1).Contains(expectedValue));
}
// This fails with the message: "Expected: collection containing "value2"" (with NUnit v3.2.1) / "Expected: some item equal to "value2""(with NUnit v3.12.0)
verifiers.VerifyCollectedValues(collectedValues, expectedValues, 1, false);
My assumption is that IResolveConstraint is causing the problem. What I don't understand is why the first item of list passes but the second one doesn't.
I'll be grateful for any answer.
UPDATE:
I've done some edits and base on that I excluded the possibility that IResolveConstraint is causing the problem. Here is sample of the current code:
public class Verifiers
{
public void VerifyCollectedValues(List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom, int countOfValueExpectance, bool verifyExactSameValue = true)
{
VerifyCollectedValues(CreateConstraintExpressionExactly(countOfValueExpectance), collectedValues, expectedValues, collectedValuesFrom, verifyExactSameValue);
}
private void VerifyCollectedValues(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom, bool exactSameValue)
{
if (exactSameValue)
{
VerifyCollectedValuesEqualTo(constraintExpression, collectedValues, expectedValues, collectedValuesFrom);
}
else
{
VerifyCollectedValuesContains(constraintExpression, collectedValues, expectedValues, collectedValuesFrom);
}
}
private void VerifyCollectedValuesEqualTo(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom)
{
Func<string, EqualConstraint> constraintFunction = (string value) => constraintExpression.EqualTo(value);
foreach (string expectedValue in expectedValues)
{
Assert.That(collectedValues, constraintFunction(expectedValue));
}
}
private void VerifyCollectedValuesContains(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom)
{
// if I don't use constraintExpression but write the expression manually (Has.Exactly(1).Contains(value)), then it works just fine
Func<string, ContainsConstraint> constraintFunction = (string value) => constraintExpression.Contains(value);
foreach (string expectedValue in expectedValues)
{
Assert.That(collectedValues, constraintFunction(expectedValue));
}
}
private ConstraintExpression CreateConstraintExpressionExactly(int countOfExpectance)
{
return Has.Exactly(countOfExpectance);
}
var verifiers = new Verifiers();
List<string> expectedValues = new List<string>()
{
"value1",
"value2",
"value3",
};
var collectedValues = new List<string>()
{
"some_value0",
"some_value1",
"some_value2",
"some_value3",
};
// This one pass successfully
foreach(string expectedValue in expectedValues)
{
Assert.That(collectedValues, Has.Exactly(1).Contains(expectedValue));
}
// But this one still doesn't pass and fails at the second list item "value2"
verifiers.VerifyCollectedValues(collectedValues, expectedValues, "list of strings", 1, false);
Your assumption that Has.Exactly(1).EqualTo() will pass if the actual value is a non-collection is not correct. ExactCountConstraint will error (not quite the same as fail) if passed a non-collection type.
However, in this case, string is a collection of chars so it tries to run.
The problem is that you are using a collection constraint, which iterates the list, but you are also iterating it yourself. You should either do it all yourself (which seems silly) or rely on the ExactCountConstraint to do the work.
If you continue to iterate the list yourself, then you should not use any collection constraints. In the example case, you would simply use Is.EqualTo().
Well, the bug is in your implementation actually, since you're passing ConstraintExpression all the time.
If you try to decompose the working code and create methods for each verification you'll have something like this:
[Test]
public void ListCompareTest()
{
List<string> expectedValues = new List<string>()
{
"value1",
"value2",
"value3",
};
var collectedValues = new List<string>()
{
"some_value0",
"some_value1",
"some_value2",
"some_value3",
};
int count = 1;
// This one pass successfully
foreach (string expectedValue in expectedValues)
{
ItemsConstraintExpression itemsConstraintExpression = GetExactly(count);
// this code works
Assert.That(collectedValues, GetContains(expectedValue, itemsConstraintExpression));
}
// this code works as well
DoVerification(expectedValues, collectedValues, 1, false);
}
public static void DoVerification(List<string> expectedList, List<string> actualList, int exactlyCount, bool equalsOrContains)
{
if (equalsOrContains)
{
foreach (var expectedValue in expectedList)
{
Assert.That(actualList, GetEquals(expectedValue, GetExactly(exactlyCount)));
}
}
else
{
foreach (var expectedValue in expectedList)
{
Assert.That(actualList, GetContains(expectedValue, GetExactly(exactlyCount)));
}
}
}
private static EqualConstraint GetEquals(string expectedValue, ItemsConstraintExpression itemsConstraintExpression)
{
return itemsConstraintExpression.EqualTo(expectedValue);
}
private static ContainsConstraint GetContains(string expectedValue, ItemsConstraintExpression itemsConstraintExpression)
{
return itemsConstraintExpression.Contains(expectedValue);
}
private static ItemsConstraintExpression GetExactly(int count)
{
return Has.Exactly(count);
}
Related
How can we get parameter name called by a method in C#?
Example:
public static void PrintList (List<string> list)
{
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
PrintList(oxygenList);
I need the method to print:
oxygenList
Thanks.
If you're using C# 10 or later, you can use the new CallerArgumentExpression attribute to achieve this:
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public static class Program
{
public static void Main()
{
List<string> oxygenList = new List<string> { "A", "B", "C" };
PrintList(oxygenList);
}
public static void PrintList(List<string> list, [CallerArgumentExpression("list")] string? name = null)
{
Console.WriteLine("Argument name = " + name); // Prints "Argument name = oxygenList
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
}
However, note that this gives the expression used when calling the method - so if you call it with this code:
public static void Main()
{
PrintList(getOxygenList());
}
public static List<string> getOxygenList()
{
return new List<string> { "A", "B", "C" };
}
the value passed as name will be "getOxygenList()".
It has to work like this because an expression can be used for the parameter - it's not restricted to a simple variable name.
You should use:
Console.WriteLine(nameof(list));
See more: nameof
Update:
This is still not clear for me what do You want to achieve but the easiest way would be:
public static void PrintList (List<string> list, string nameOfList)
{
Console.WriteLine(nameOfList);
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
PrintList(oxygenList, nameof(oxygenList));
You may also create a bit cleaner extension method, like this:
public static class ListPrinter
{
public static void PrintListWithName(this List<string> list, string nameOfList)
{
Console.WriteLine(nameOfList);
list.ForEach(element => Console.WriteLine(element));
}
}
called like this:
oxygenList.PrintListWithName(nameof(oxygenList));
My class has 3 properties that have to do the same thing in the custom set that I made.
Now I have this repeated in all 3, which isn't DRY.
How do I make this DRY? Just put the foreach into a method? I feel like there must be a more elegant way.
(also I wish I didn't need the private backing fields because they are kind of an eye-sore)
private List<string> _ImageTypes;
public List<string> ImageTypes
{
get { return _ImageTypes; }
set
{
_ImageTypes = new List<string>();
foreach (var type in value)
if (!string.IsNullOrEmpty(type))
_ImageTypes.Add("." + type.Replace(".", "").Replace("*", ""));
}
}
private List<string> _AnimationTypes;
public List<string> AnimationTypes
{
get { return _AnimationTypes; }
set
{
_AnimationTypes = new List<string>();
foreach (var type in value)
if (!string.IsNullOrEmpty(type))
_AnimationTypes.Add("." + type.Replace(".", "").Replace("*", ""));
}
}
private List<string> _VideoTypes;
public List<string> VideoTypes
{
get { return _VideoTypes; }
set
{
_VideoTypes = new List<string>();
foreach (var type in value)
if (!string.IsNullOrEmpty(type))
_VideoTypes.Add("." + type.Replace(".", "").Replace("*", ""));
}
}
Yes, put it in the method
private List<string> CreateListFrom(List<string> list)
{
return list.Where(type => !string.IsNullOrEmpty(type))
.Select(type => type.Replace(".", "").Replace("*", ""))
.Select(type => $".{type}")
.ToList();
}
Then use it in the setters
private List<string> _ImageTypes;
public List<string> ImageTypes
{
get { return _ImageTypes; }
set
{
_ImageTypes = CreateListFrom(value);
}
}
Another approach - do it in the constructor, then you can get rid of private members.
But this will depend on how this class is consumed
Before talking about DRY - you should be sure that similar looking code are going to be changed for same reasons.
I am trying to create two sets and put both in a list and display all items in the list. I am getting an error with my code.
Error: System.Collections.Generic.List1[System.Collections.Generic.SortedSet1[System.String]]
I am attaching my code below. Any help is appreciated.
namespace Prog 5
{
class Program
{
static void Main(string[] args)
{
List<SortedSet<string>> items = new List<SortedSet<string>>();
SortedSet<string> set = new SortedSet<string>();
SortedSet<string> set2 = new SortedSet<string>();
set.Add("a");
set.Add("b");
set.Add("d");
set.Add("c");
set2.Add("e");
set2.Add("d");
set2.Add("c");
foreach (string item in set)
{
items.Add(set);
}
foreach (string item in set2)
{
items.Add(set2);
}
DisplayItem(items);
}
public static void DisplaySet(SortedSet<string> set)
{
string set1 = string.Join(",", set);
Console.WriteLine(set1);
Console.ReadLine();
}
public static void DisplayItem(List<SortedSet<string>> items)
{
foreach (SortedSet<string> item in items)
{
Console.WriteLine(items);
Console.ReadLine();
}
}
}
In DisplayItem(...) you have Console.WriteLine(items)... which is type List>. ToString() automatically gets called on that to produce a string for Console.WriteLine to output: that's why you get your current message. I'm guessing you want to write each item to console.
public static void DisplayItem(List<SortedSet<string>> items)
{
foreach (SortedSet<string> item in items)
{
DisplaySet(item);
}
}
SortedSet<string> inherits from Object and the default behavior of ToString() is GetType().ToString();, because of that you receive System.Collections.Generic.List1[System.Collections.Generic.SortedSet1[System.String]] in the console. Reference Code
public virtual String ToString()
{
return GetType().ToString();
}
SOLUTION: If you want to show elements of the SortedSet in the console you should use this:
Console.WriteLine(string.Join(",", item.ToArray()));
This will concatenate all the strings in the SortedSet and show them in the console with , separator.
If I understood your requirements correctly, you are looking to merge 2 SortedSets into single list or perhaps set.
The following code should work (explanations of why it is working follow):
class Program
{
static void Main(string[] args)
{
SortedSet<string> items = new SortedSet<string>();
SortedSet<string> set = new SortedSet<string>();
SortedSet<string> set2 = new SortedSet<string>();
set.Add("a");
set.Add("b");
set.Add("d");
set.Add("c");
set2.Add("e");
set2.Add("d");
set2.Add("c");
foreach (string item in set)
{
items.Add(item);
}
foreach (string item in set2)
{
items.Add(item);
}
DisplayItem(items);
}
public static void DisplaySet(SortedSet<string> set)
{
string set1 = string.Join(",", set);
Console.WriteLine(set1);
Console.ReadLine();
}
public static void DisplayItem(SortedSet<string> items)
{
foreach (string item in items)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
The main issue in code listed in question is that it is attempting to create a List of OrderedSet<string> objects. Since each OrderedSet<string> represents a collection of strings you need to iterate over these collections and put strings into a new collection. The code presented in question does not do it. Instead of that it is adding 7 OrderedSet<string> objects into the List.
Corrected code fixes that issue and adds strings to a new OrderedList<string>. You can decide what collection it is depending on your requirements. If you need collection not to contain duplicates and be sorted you can choose a new OrderedSet<string>, however if you don't care about duplicates then you can choose a
List<string>.
If you wish to compare the difference between OrderedSet<string> and List<string> you can simply change 'items' data type to List<string> and run the program.
Current output:
a
b
c
d
e
If you change
SortedSet<string> items = new SortedSet<string>();
to
List<string> items = new List<string>();
...
public static void DisplayItem(List<string> items)
{
...
you will get:
a
b
c
d
c
d
e
I have this domain:
public class ADomainClass
{
public int Id { get; set; }
}
public interface IMyClass : IEnumerable<ADomainClass>
{
}
public class MyClass : IMyClass
{
public IEnumerator<ADomainClass> GetEnumerator()
{
IList<ADomainClass> list = new List<ADomainClass>();
//list = GetData...();
foreach (var item in list)
{
yield return item;
}
}
...
}
and want to build the following test:
[Test]
public void TestSample()
{
//Arrange
IMyClass myclass = Substitute.For<IMyClass>();
IList<ADomainClass> testdata = new List<ADomainClass>()
{
new ADomainClass(){ Id = 1, },
new ADomainClass(){ Id = 2, },
new ADomainClass(){ Id = 3, },
new ADomainClass(){ Id = 4, },
};
int count = 0;
myclass.ReturnsForAnyArgs(testdata); //How to set the "return" value?
//Act
foreach (ADomainClass item in myclass)
{
count++;
}
//Assert
count.Should().Be(testdata.Count);
}
Setting the return value for a method is easy and would look like this:
myclass.GetData().Returns(data);
I can't remember how to set the return value when it is an enumerable class. I have solved this once before, but can't remember where I have used it.
My problem was that NSubstitute stores the state of the enum, so if you use the Enumerator twice in the system under test, it will continue with the second element at the second time. I am using something like the code below as a workaround (using a lambda instead of returning the Enumerator, lines 1 + 2 are for demonstration only). I have only tested this with some Linq and foreach.
var bar = new List<string> { "a", "b", "c" };
var foo = Substitute.For<ICollection<string>>();
foo.GetEnumerator().Returns((ci) => { return bar.GetEnumerator(); });
You just need to tell your substitute to return the enumerator from you test data:
myclass.GetEnumerator().Returns(testdata.GetEnumerator());
I have list of arrays:
List<HeaderItem> _headerItems = new List<HeaderItem>();
class HeaderItem
{
private string[] _headers = new string[6];
public string this[int index]
{
get
{
return _headers[index];
}
set
{
_headers[index] = value;
}
}
}
Each of the 6 items in the array represent a level in the hierarchy. If all items matched in array position 0 then a single root level node would exist.
So,
A,B,C
A,B,D
B,C,D
B,D,E
would produce:
A
....B
........C
........D
B
....C
........D
....D
........E
etc....
Currently my solution is pretty hacked up and although it works I am trying to come up with a "cool" way of doing it.
You can achieve that by calling a print method recursively providing it with the subset of items to be printed and depth of the tree printed so far. I amended your class to contain a Length property so that the caller does not have to always assume it is 6. Also I added a constructor to make my initialization easy. Probably it wouldn't make sense in your code.
public class HeaderItem
{
public HeaderItem(string headers)
{
_headers = headers.ToCharArray().Select(x => x.ToString()).ToArray();
}
private string[] _headers = new string[6];
public int Length
{
get { return _headers.Length; }
}
//...
}
This is the print method. See how it does grouping and then calls itself recursively:
private static void PrintHeaders(IEnumerable<HeaderItem> headerItems, int depth = 0)
{
var result =
headerItems.Where(h => h.Length > depth)
.GroupBy(h => h[depth], h => h,
(k, g) => new {Key = k, Items = g})
.OrderBy(g => g.Key);
foreach (var pair in result)
{
Console.Write(new string('.', depth)); // change here to add more dots
Console.WriteLine(pair.Key);
PrintHeaders(pair.Items, depth + 1);
}
}
And this is how you can begin calling it:
PrintHeaders(_headerItems);
For testing, this is my Main method:
static void Main(string[] args)
{
_headerItems.Add(new HeaderItem("abc"));
_headerItems.Add(new HeaderItem("abd"));
_headerItems.Add(new HeaderItem("acd"));
_headerItems.Add(new HeaderItem("ace"));
_headerItems.Add(new HeaderItem("bce"));
_headerItems.Add(new HeaderItem("bcd"));
_headerItems.Add(new HeaderItem("bef"));
PrintHeaders(_headerItems);
Console.ReadLine();
}
And this is the result:
a
.b
..c
..d
.c
..d
..e
b
.c
..d
..e
.e
..f
When ever making tree always create a list of entity within that entity like this
class HeaderItem
{
private string[] _headers = new string[6];
private List<HeaderItem> _items;
public string this[int index]
{
get
{
return _headers[index];
}
set
{
_headers[index] = value;
}
}
public List<HeaderItem> Items
{
get
{
if (_items == null)
_items = new List<HeaderItem>();
return _items;
}
}
}