Perform Assert.AreMatch() to deep compare properties in two objects - c#

I am writing tests against our Caching mechanism and I want to be sure that what goes into the cache is the same as what comes out, ie that all properties match. Here is a fictional example of how I would like it to work
[Test]
public void add_client_model_member_to_cache_then_retreve()
{
//arrange
MemcachedClient client = new MemcachedClient();
Member member = GetMember();
client.Store(StoreMode.Set, "membertest", member);
// act
var result = client.Get<Member>("membertest");
// assert
Assert.AreMatch(result, member);
}
It is not feasible to perform Assert.AreEqual on each property as there will be many of these tests with many properties in each.
Wow, thanks Jon. I think you answered that in under one minute. Here are my resulting solution for any interested parties. I implemented as Jon suggested (I think) however I got into a little trouble with array properties and as such my solution only handles arrays of ints (all I currently require).
It also got to be a fairly slippery slope if I try to check deeper than one level. I am sure this can be achieved however for my purposes it is not required.
private bool AreMatch(object initial, object result)
{
if (initial.Equals(result))
return true;
foreach (var property in initial.GetType().GetProperties())
{
var initialPropValue = property.GetValue(initial,null);
var resultPropValue = result.GetType().GetProperty(property.Name).GetValue(result,null);
if (property.PropertyType.IsArray)
{
if ((initialPropValue != null && resultPropValue != null) && !Enumerable.SequenceEqual((int[])initialPropValue, (int[])resultPropValue))
return false;
}
else if (!object.Equals(initialPropValue, resultPropValue))
{
return false;
}
else if (initialPropValue != null && property.PropertyType.IsClass)
{
// Don't go deeper than one level, this got me into trouble
//if (!AreMatch(initialPropValue, resultPropValue))
// return false;
}
}
return true;
}
The method above can be used in the following situations
[Test]
public void cached_result_is_same_as_original()
{
//arrange
Member member = GetMember();
client.Store(StoreMode.Set, "membertest", member);
// act
var result = client.Get<Member>("membertest");
// assert
Assert.IsTrue(AreMatch(member, result));
}
[Test]
public void cached_result_is_same_as_original()
{
//arrange
Member member = GetMember();
client.Store(StoreMode.Set, "membertest", member);
// act
var result = client.Get<Member>("membertest");
result.FirstName = "Result is different";
// assert
Assert.IsFalse(AreMatch(member, result));
}

Well, you could certainly write something to recurse through all the properties, and call object.Equals on the result of fetching the property value from the expected and actual ones. Use Type.GetProperties() to get the properties themselves, and PropertyInfo.GetValue to get the value.
It'll be somewhat crude, but you could always tweak it if necessary.

Related

How can I find previous usages of a variable using Roslyn?

I'm writing a Rosyln analyser/analyzer. It checks to ensure that a method is called before accessing another (potentially dangerous) method on a type. To show what I mean, here's some bad code that I want to analyse and fail on:
private void myMethod()
{
var myThing = new MyThing();
myThing.Value = null;
string value = myThing.GetValue(); // code blows up here as the internal value is null
}
Here's code that's OK because it calls a method that says whether it's null:
private void myMethod()
{
var myThing = new MyThing();
myThing.Value = null;
if(!myThing.HasValue)
{
return ;
}
string value = myThing.GetValue();
}
So, it should check that all calls to GetValue are preceeded by a call to HasValue.
I've just started with Roslyn, so there's probably a more elegant way than my initial (failing) attempt at:
1 - Declare that I want to inspect invocation expressions
context.RegisterSyntaxNodeAction(analyseMemberAccessNode, SyntaxKind.InvocationExpression);
2 - In my method, I get the method name (GetValue())
var expr = (InvocationExpressionSyntax)context.Node;
var memberAccess = expr.Expression as MemberAccessExpressionSyntax;
if (memberAccess?.Name.ToString() != "GetValue")
return;
3 - I then check to see if it's the right 'GetValue'
var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol;
if (!memberSymbol?.OverriddenMethod.ToString().StartsWith("MyNamespace.MyThing.GetValue") ?? true)
return;
4 - Up to here, everything is fine. So I get the name of the variable
var e = memberAccess.Expression as IdentifierNameSyntax;
string variableName = e.Identifier.Text;
5 - now I'm stuck - my theory was to; get the containing method, find the single variable declaration that matches variableName, find usages of that, and ensure that HasValue is called before GetValue.
In short, using a Roslyn analyser (deriving from DiagnosticAnalyzer), how do I ensure that HasValue is called before GetValue?
Instead of registering for each Invocation, you might be better off registering for the entire method declaration. Then you can keep track of all MemberAccessExpressionSyntax and ensure that for a given variable that HasValue is called before GetValue. To do that, I would get the MemberAccessExpressionSyntax descendants from the MethodDeclaration node.
context.RegisterSyntaxNodeAction((analysisContext) =>
{
var invocations =
analysisContext.Node.DescendantNodes().OfType<MemberAccessExpressionSyntax>();
var hasValueCalls = new HashSet<string>();
foreach (var invocation in invocations)
{
var e = invocation.Expression as IdentifierNameSyntax;
if (e == null)
continue;
string variableName = e.Identifier.Text;
if (invocation.Name.ToString() == "HasValue")
{
hasValueCalls.Add(variableName);
}
if (invocation.Name.ToString() == "GetValue")
{
if (!hasValueCalls.Contains(variableName))
{
analysisContext.ReportDiagnostic(Diagnostic.Create(Rule, e.GetLocation()));
}
}
}
}, SyntaxKind.MethodDeclaration);

Write a function taking arbitrary objects and methods with common return types

I have several objects of different types with methods taking different parameters that all return the same type. These methods can fail. Is there a way to write a function that will take the object and its method, indicate if the method fails, and indicate the object on which failure occurred? I can't modify the Result object, and it holds no information about the object that called it.
I find this a little verbose:
Result resultA = A.something();
if(resultA.Failed) return new Status{Failed=A.GetType().ToString()};
Result resultB = B.somethingElse(3);
if(resultB.Failed) return new Status{Failed=B.GetType().ToString()};
Result result3 = C.someOtherThing("apple");
if(resultC.Failed) return new Status{Failed=C.GetType().ToString()};
// Do some processing of the results (will succeed if A,B,C succeeded)
return new Status {Failed=null, Success=true};
Is there a way to encapsulate all that into a function? It seems very repetitive. A, B, and C do not inherit from a useful base class, and their methods all take different parameters and have different names.
That being said, I do have access to the Status class, and even the return value of this function. The function need not return, it could throw an exception instead. If there's a failure, the function can break immediately.
I Suggest a small variation to #Shawn Holzworth's answer that is a bit simpler.
First, since the only thing in common to your methods is their return type, this is the only thing that we can generalize here. We can construct a methods that will handle the execution as you requested like so:
public static Status ExecuteRequests(params Func<Result>[] actions){
foreach (Func<Result> action in actions) {
Result r = action();
if (!r.Success) {
Status s = new Status() { Failed = action.Target.GetType().ToString() };
return s;
}
}
return new Status() { Success = true };
}
And the call site:
ExecuteRequests(
() => A.doSomething(),
() => B.doSomethingElse(42));
If you want to perfrom extra computation on the Results, you can extend the ExecuteRequests method to input a handler in the Form of Action.
This abstraction actually facilitates another thing that you did not ask about but I believe is worth mentioning: Parallel execution. When you encapsulate these operations like this, it is very easy to make use of the TPL, to send out the requests in parallel and aggregate them as the arrive, but this is a bit more involved.
Having mentioned the above, I wonder whether this is worth the effort. Indeed it abstracts the execution sequence, but I am not sure that this significantly enhances readability (Unless you have a longer execution sequence than 3, and expect it to grow in the future).
The simplest way is make a new subclass of Status that fills it the Failed property for you, you can just have the constructor take a object in as the type and call GetType() in there.
public class FailedStatus : Status
{
public FailedStatus(object source)
{
this.Failed = source.GetType().ToString();
}
}
Result resultA = A.something();
if(resultA.Failed) return new FailedStatus(A);
Result resultB = B.somethingElse(3);
if(resultB.Failed) return new FailedStatus(B);
Result result3 = C.someOtherThing("apple");
if(resultC.Failed) return new FailedStatus(C);
If Result derives from Status too the least verbose way is modify something(), somethingElse(int), and someOtherThing(string) to set the string itself (but I doubt this is true sense it appears Result.Failed is a bool but Status.Failed is a string).
One simple way you could do this:
//Note: the method signature could just be IEnumerable<Result> AggregateResults(params Func<Result>[])
//if you want to be able to aggregate the results of 0 calls
IEnumerable<Result> AggregateResults(Func<Result> func, params Func<Result>[] otherFuncs)
{
yield return func();
foreach(var otherFunc in otherFuncs)
yield return otherFunc();
}
//Usage:
var results = AggregateResults(
() => A.Something(),
() => B.SomethingElse(3),
() => C.SomethingOtherThing("apple"));
Unfortunately the requirement to stop on the first failing call and get the calling object makes it slightly harder:
class AggregateResult
{
public object CallingObject;
public Result Result;
public static AggregateResult Create<T>(T t, Func<T,Result> func)
{
return new AggregateResult() { CallingObject = t, Result = func(t) };
}
}
IEnumerable<AggregateResult> AggregateResults(Func<AggregateResult> func, params Func<AggregateResult>[] otherFuncs)
{
yield return func();
foreach (var otherFunc in otherFuncs)
yield return otherFunc();
}
//Usage:
var results = AggregateResults(
() => AggregateResult.Create(A, x=>x.Something()),
() => AggregateResult.Create(B, x=>x.SomethingElse(3)),
() => AggregateResult.Create(C, x=>x.SomethingOtherThing("apple")));
var failedResult = results.FirstOrDefault(x => x.Result.Failed);
if (failedResult != null) return new Status() { Failed = failedResult.CallingObject.GetType().ToString() };
That said, I agree with the comments that this sounds like an XY problem.
You could create an extension method for Result that returns null in case of success, like this:
static class ResultExtension
{
public static Status GetStatus<T>(this Result res, T a) {
return res.Failed? new Status{Failed=a.GetType().ToString()} : null;
}
}
then you could chain operations with the null-coalescing operator ?? :
return A.something().GetStatus(A) ??
B.somethingElse(3).GetStatus(B) ??
C.someOtherThing("apple").GetStatus(C) ??
new Status{Failed=null, Success=true};
note that the ?? operator short-circuits, so you only evaluate somethingElse(3) or someOtherThing("apple") if none of the previous results is null (i.e. a failure), as you want and in the end, if and only if all calls succeeded you return a success Status.

Prevent stack overflow while crawling inside objects via reflection in c#

I have this method called MatchNodes: IEnumerable<bool> MatchNodes<T>(T n1, T n2)
Which basically gets every property and field from both T objects (via reflection, and not including properties/fields from base classes) and compares them, returning the result as a IEnumerable of bools.
When it finds a primitive type or string, if just returns the == between them.
When it finds a type derived from a collection, it iterates each member and calls MatchNodes for each of them (ouch).
When it finds any other type, it calls MatchNodes for each property/field.
My solution is obviously asking for a stack overflow exception, but I don't have a clue on how make it better, because I have no idea how deep the objects will go.
Code (try not to cry please, it's ugly as hell):
public static IEnumerable<bool> MatchNodes<T>(T n1, T n2)
{
Func<PropertyInfo, bool> func= null;
if (typeof(T) == typeof(String))
{
String str1 = n1 as String;
String str2 = n2 as String;
func = new Func<PropertyInfo, bool>((property) => str1 == str2);
}
else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(typeof(T)))
{
System.Collections.IEnumerable e1 = (System.Collections.IEnumerable)n1;
System.Collections.IEnumerable e2 = (System.Collections.IEnumerable)n2;
func = new Func<PropertyInfo, bool>((property) =>
{
foreach (var v1 in e1)
{
if (e2.GetEnumerator().MoveNext())
{
var v2 = e2.GetEnumerator().Current;
if (((IEnumerable<bool>)MatchNodes(v1, v2)).All(b => b == true))
{
return false;
}
}
else
{
return false;
}
}
if (e2.GetEnumerator().MoveNext())
{
return false;
}
else return true;
});
}
else if (typeof(T).IsPrimitive || typeof(T) == typeof(Decimal))
{
func = new Func<PropertyInfo, bool>((property) => property.GetValue(n1, null) == property.GetValue(n2, null));
}
else
{
func = new Func<PropertyInfo, bool>((property) =>
((IEnumerable<bool>)MatchNodes(property.GetValue(n1, null),
property.GetValue(n2, null))).All(b => b == true));
}
foreach (PropertyInfo property in typeof(T).GetProperties().Where((property) => property.DeclaringType == typeof(T)))
{
bool result =func(property);
yield return result;
}
}
What I'm looking at is a way to crawl into the objects without calling my method recursively.
EDIT
To clarify, example:
public class Class1 : RandomClassWithMoreProperties{
public string Str1{get;set;}
public int Int1{get;set;}
}
public class Class2{
public List<Class1> MyClassProp1 {get;set;}
public Class1 MyClassProp2 {get;set;}
public string MyStr {get;set;}
}
MatchNodes(n1,n2) where n1.GetType() and n2.GetType() are Class2 would return true if:
Every Class1 object inside MyClassProp1 has the same Str1,Int1 for both objects
MyClassProp2 has the same Str1,Int1 for both objects
MyStr is equal for both objects
And I won't compare any properties from RandomClassWithMoreProperties.
You can use a stack or queue to store the properties you want to compare. It goes along these lines:
var stack = new Stack<Tuple<object, object>>();
// prime the stack
foreach (var prop in n1.GetType().GetProperties())
{
stack.Push(Tuple.Create(prop.GetValue(n1), prop.GetValue(n2));
}
while (stack.Count > 0)
{
var current = stack.Pop();
// if current is promitive: compare
// if current is enumerable: push all elements as Tuples on the stack
// else: push all properties as tuples on the stack
}
If you use a Queue instead of a Stack you get a BFS instead of a DFS. Also you should probably keep track of already visited nodes in a HashSet. You also might want to add a check to make sure the types of n1 and n2 are the same.
A good approach here is to keep a breadcrumb trail of objects that you've touched, and passing that forward as you delve deeper. For each new object, check to see whether it is in the graph of objects that you have already seen, and if it is, short circuit and bail out (you've already seen that node). A stack is probably appropriate.
You are not likely to get stack overflows by comparing an acyclic object graph- it's when you end up with loops that things blow up.
Just keep track of the objects you already visited, in a List<object> for example (or Set<> or anything like that)...
Also, any recursion can be un-recursed using the stack that you'll control manually.

Moq: How to get to a parameter passed to a method of a mocked service

Imagine this class
public class Foo {
private Handler _h;
public Foo(Handler h)
{
_h = h;
}
public void Bar(int i)
{
_h.AsyncHandle(CalcOn(i));
}
private SomeResponse CalcOn(int i)
{
...;
}
}
Mo(q)cking Handler in a test of Foo, how would I be able to check what Bar() has passed to _h.AsyncHandle?
You can use the Mock.Callback-method:
var mock = new Mock<Handler>();
SomeResponse result = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<SomeResponse>()))
.Callback<SomeResponse>(r => result = r);
// do your test
new Foo(mock.Object).Bar(22);
Assert.NotNull(result);
If you only want to check something simple on the passed in argument, you also can do it directly:
mock.Setup(h => h.AsyncHandle(It.Is<SomeResponse>(response => response != null)));
An alternative is to use Capture.In, which is an out-of-the-box feature in Moq that lets you capture arguments into a collection:
//Arrange
var args = new List<SomeResponse>();
mock.Setup(h => h.AsyncHandle(Capture.In(args)));
//Act
new Foo(mock.Object).Bar(22);
//Assert
//... assert args.Single() or args.First()
Gamlor's answer worked for me, but I thought I would expand on John Carpenter's comment because I was looking for a solution involving more than one parameter. I figured other folks who stumble onto this page may be in a similar situation. I found this info in the Moq documentation.
I'll use Gamlor's example, but let's pretend the AsyncHandle method takes two arguments: a string and a SomeResponse object.
var mock = new Mock<Handler>();
string stringResult = string.Empty;
SomeResponse someResponse = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>()))
.Callback<string, SomeResponse>((s, r) =>
{
stringResult = s;
someResponse = r;
});
// do your test
new Foo(mock.Object).Bar(22);
Assert.AreEqual("expected string", stringResult);
Assert.IsNotNull(someResponse);
Basically you just need to add another It.IsAny<>() with the appropriate type, add another type to the Callback method, and change the lambda expression as appropriate.
The Callback method will certainly work, but if you are doing this on a method with a lot of parameters it can be a bit verbose. Here is something that I have used to remove some of the boilerplate.
var mock = new Mock<Handler>();
// do your test
new Foo(mock.Object).Bar(22);
var arg = new ArgumentCaptor<SomeResponse>();
mock.Verify(h => h.AsyncHandle(arg.Capture()));
Assert.NotNull(arg.Value);
Here is the source for ArgumentCaptor:
public class ArgumentCaptor<T>
{
public T Capture()
{
return It.Is<T>(t => SaveValue(t));
}
private bool SaveValue(T t)
{
Value = t;
return true;
}
public T Value { get; private set; }
}
Gamlor's answer works, but another way of doing it (and one which I consider to be more expressive in the test) is...
var mock = new Mock<Handler>();
var desiredParam = 47; // this is what you want to be passed to AsyncHandle
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once());
Verify is very powerful, and worth taking the time to get used to.
You could use It.Is<TValue>() matcher.
var mock = new Mock<Handler>();
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null )));
This also works:
Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;
Lot's of good answers here! Go with the out of the box Moq feature-set until you need to make assertions about several class parameters passed to your dependencies. If you end up in that situation though, the Moq Verify feature with It.Is matchers doesn't do a good job of isolating the test failure, and the Returns/Callback way of capturing arguments adds unnecessary lines of code to your test (and long tests are a no-go for me).
Here is a gist: https://gist.github.com/Jacob-McKay/8b8d41ebb9565f5fca23654fd944ac6b with a Moq (4.12) extension I wrote that gives a more declarative way to make assertions about arguments passed to mocks, without the drawbacks aforementioned. Here is what the Verify section looks like now:
mockDependency
.CheckMethodWasCalledOnce(nameof(IExampleDependency.PersistThings))
.WithArg<InThing2>(inThing2 =>
{
Assert.Equal("Input Data with Important additional data", inThing2.Prop1);
Assert.Equal("I need a trim", inThing2.Prop2);
})
.AndArg<InThing3>(inThing3 =>
{
Assert.Equal("Important Default Value", inThing3.Prop1);
Assert.Equal("I NEED TO BE UPPER CASED", inThing3.Prop2);
});
I would be stoked if Moq provided a feature that accomplished the same thing while being as declarative and providing the failure isolation this does. Fingers crossed!

Unit tests for deep cloning

Let's say I have a complex .NET class, with lots of arrays and other class object members. I need to be able to generate a deep clone of this object - so I write a Clone() method, and implement it with a simple BinaryFormatter serialize/deserialize - or perhaps I do the deep clone using some other technique which is more error prone and I'd like to make sure is tested.
OK, so now (ok, I should have done it first) I'd like write tests which cover the cloning. All the members of the class are private, and my architecture is so good (!) that I haven't needed to write hundreds of public properties or other accessors. The class isn't IComparable or IEquatable, because that's not needed by the application. My unit tests are in a separate assembly to the production code.
What approaches do people take to testing that the cloned object is a good copy? Do you write (or rewrite once you discover the need for the clone) all your unit tests for the class so that they can be invoked with either a 'virgin' object or with a clone of it? How would you test if part of the cloning wasn't deep enough - as this is just the kind of problem which can give hideous-to-find bugs later?
You method of testing will depend on the type of solution you come up with. If you write some custom cloning code and have to manually implement that in each cloneable type then you should really test the cloning of each one of those types. Alternatively, if you decide to go a more generic route (where the aforementioned reflection would likely fit in), your tests would only need to test the specific scenarios that you cloning system will have to deal with.
To answer your specific questions:
Do you write (or rewrite once you discover the need for the clone) all your unit tests for the class so that they can be invoked with either a 'virgin' object or with a clone of it?
You should have tests for all the methods that can be performed on both the original and cloned objects. Note that it should be pretty easy to set up a simple test design to support this without manually updating the logic for each test.
How would you test if part of the cloning wasn't deep enough - as this is just the kind of problem which can give hideous-to-find bugs later?
It depends on the cloning method you choose. If you have to manually update the cloneable types then you should test that each type is cloning all (and only) the members you expect. Whereas, if you are testing a cloning framework I would create some test cloneable types to test each scenario you need to support.
There's a really obvious solution that doesn't take nearly as much work:
Serialize the object into a binary format.
Clone the object.
Serialize the clone into a binary format.
Compare the bytes.
Assuming that serialization works - and it better because you are using it to clone - this should be easy to maintain. In fact, it will be encapsulated from changes to the structure of your class completely.
I'd just write a single test to determine if the clone was correct or not. If the class isn't sealed, you can create a harness for it by extending it, and then exposing all your internals within the child class. Alternatively, you could use reflection (yech), or use MSTest's Accessor generators.
You need to clone your object and then go through every single property and variable that your object has and determine if it was copied correctly or cloned correctly.
I like to write unit tests that use one of the builtin serializers on the original and the cloned object and then check the serialized representations for equality (for a binary formatter, I can just compare the byte arrays). This works great in cases where the object is still serializable, and I'm only changing to a custom deep clone for perf reasons.
Furthermore, I like to add a debug mode check to all of my Clone implementations using something like this
[Conditional("DEBUG")]
public static void DebugAssertValueEquality<T>(T current, T other, bool expected,
params string[] ignoredFields) {
if (null == current)
{ throw new ArgumentNullException("current"); }
if (null == ignoredFields)
{ ignoredFields = new string[] { }; }
FieldInfo lastField = null;
bool test;
if (object.ReferenceEquals(other, null))
{ Debug.Assert(false == expected, "The other object was null"); return; }
test = true;
foreach (FieldInfo fi in current.GetType().GetFields(BindingFlags.Instance)) {
if (test = false) { break; }
if (0 <= Array.IndexOf<string>(ignoredFields, fi.Name))
{ continue; }
lastField = fi;
object leftValue = fi.GetValue(current);
object rightValue = fi.GetValue(other);
if (object.ReferenceEquals(null, leftValue)) {
if (!object.ReferenceEquals(null, rightValue))
{ test = false; }
}
else if (object.ReferenceEquals(null, rightValue))
{ test = false; }
else {
if (!leftValue.Equals(rightValue))
{ test = false; }
}
}
Debug.Assert(test == expected, string.Format("field: {0}", lastField));
}
This method relies on an accurate implementation of Equals on any nested members, but in my case anything that is cloneable is also equatable
I would usually implement Equals() for comparing the two objects in depth. You might not need it in your production code but it might still come in handy later and the test code is much cleaner.
Here is a sample of how I implemented this a while back, although this will need to be tailored to the scenario. In this case we had a nasty object chain that could easily change and the clone was used as a very critical prototype implementation and so I had to patch (hack) this test together.
public static class TestDeepClone
{
private static readonly List<long> objectIDs = new List<long>();
private static readonly ObjectIDGenerator objectIdGenerator = new ObjectIDGenerator();
public static bool DefaultCloneExclusionsCheck(Object obj)
{
return
obj is ValueType ||
obj is string ||
obj is Delegate ||
obj is IEnumerable;
}
/// <summary>
/// Executes various assertions to ensure the validity of a deep copy for any object including its compositions
/// </summary>
/// <param name="original">The original object</param>
/// <param name="copy">The cloned object</param>
/// <param name="checkExclude">A predicate for any exclusions to be done, i.e not to expect IPolicy items to be cloned</param>
public static void AssertDeepClone(this Object original, Object copy, Predicate<object> checkExclude)
{
bool isKnown;
if (original == null) return;
if (copy == null) Assert.Fail("Copy is null while original is not", original, copy);
var id = objectIdGenerator.GetId(original, out isKnown); //Avoid checking the same object more than once
if (!objectIDs.Contains(id))
{
objectIDs.Add(id);
}
else
{
return;
}
if (!checkExclude(original))
{
Assert.That(ReferenceEquals(original, copy) == false);
}
Type type = original.GetType();
PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
FieldInfo[] fieldInfos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo memberInfo in propertyInfos)
{
var getmethod = memberInfo.GetGetMethod();
if (getmethod == null) continue;
var originalValue = getmethod.Invoke(original, new object[] { });
var copyValue = getmethod.Invoke(copy, new object[] { });
if (originalValue == null) continue;
if (!checkExclude(originalValue))
{
Assert.That(ReferenceEquals(originalValue, copyValue) == false);
}
if (originalValue is IEnumerable && !(originalValue is string))
{
var originalValueEnumerable = originalValue as IEnumerable;
var copyValueEnumerable = copyValue as IEnumerable;
if (copyValueEnumerable == null) Assert.Fail("Copy is null while original is not", new[] { original, copy });
int count = 0;
List<object> items = copyValueEnumerable.Cast<object>().ToList();
foreach (object o in originalValueEnumerable)
{
AssertDeepClone(o, items[count], checkExclude);
count++;
}
}
else
{
//Recurse over reference types to check deep clone success
if (!checkExclude(originalValue))
{
AssertDeepClone(originalValue, copyValue, checkExclude);
}
if (originalValue is ValueType && !(originalValue is Guid))
{
//check value of non reference type
Assert.That(originalValue.Equals(copyValue));
}
}
}
foreach (FieldInfo fieldInfo in fieldInfos)
{
var originalValue = fieldInfo.GetValue(original);
var copyValue = fieldInfo.GetValue(copy);
if (originalValue == null) continue;
if (!checkExclude(originalValue))
{
Assert.That(ReferenceEquals(originalValue, copyValue) == false);
}
if (originalValue is IEnumerable && !(originalValue is string))
{
var originalValueEnumerable = originalValue as IEnumerable;
var copyValueEnumerable = copyValue as IEnumerable;
if (copyValueEnumerable == null) Assert.Fail("Copy is null while original is not", new[] { original, copy });
int count = 0;
List<object> items = copyValueEnumerable.Cast<object>().ToList();
foreach (object o in originalValueEnumerable)
{
AssertDeepClone(o, items[count], checkExclude);
count++;
}
}
else
{
//Recurse over reference types to check deep clone success
if (!checkExclude(originalValue))
{
AssertDeepClone(originalValue, copyValue, checkExclude);
}
if (originalValue is ValueType && !(originalValue is Guid))
{
//check value of non reference type
Assert.That(originalValue.Equals(copyValue));
}
}
}
}
}

Categories