Skip to content
This repository has been archived by the owner on Oct 21, 2018. It is now read-only.

Changed the default return value for methods that return a collection interface to return an instance of an empty collection #11

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Rhino.Mocks.Tests/StubTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#endregion

using System;
using System.Collections.Generic;
using Xunit;
using Rhino.Mocks.Interfaces;

Expand Down Expand Up @@ -59,6 +60,17 @@ public void StubHasPropertyBehaviorForAllProperties()
Assert.Equal("Caucasusian Shepherd", animal.Species);
}

[Fact]
public void DefaultValue_OfAMethodThatHasNoExpectationsAndReturnACollection_ReturnAnEmptyCollection()
{
var animal = MockRepository.GenerateStub<IAnimal>();

var parents = animal.GetParents();

Assert.NotNull(parents);
Assert.Equal(0, parents.Count);
}

[Fact]
public void CanRegisterToEventsAndRaiseThem()
{
Expand Down Expand Up @@ -132,6 +144,8 @@ public interface IAnimal

event EventHandler Hungry;
string GetMood();

IList<IAnimal> GetParents();
}

public class SomeClass
Expand Down
57 changes: 56 additions & 1 deletion Rhino.Mocks.Tests/Utilities/ReturnValueUtilTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion


using System.Collections;
using Xunit;
using Rhino.Mocks.Utilities;
using System.Collections.Generic;

namespace Rhino.Mocks.Tests.Utilities
{
Expand All @@ -38,6 +39,7 @@ public class ReturnValueUtilTests
[Fact]
public void DefaultReturnValue()
{
Assert.Null(ReturnValueUtil.DefaultValue(typeof(void), null));
Assert.Null(ReturnValueUtil.DefaultValue(typeof (string),null));
Assert.Equal(0, ReturnValueUtil.DefaultValue(typeof (int),null));
Assert.Equal((short) 0, ReturnValueUtil.DefaultValue(typeof (short),null));
Expand All @@ -48,10 +50,63 @@ public void DefaultReturnValue()
Assert.Equal(TestEnum.DefaultValue, ReturnValueUtil.DefaultValue(typeof (TestEnum),null));
}

[Fact]
public void DefaultReturnValue_WhenTheReturnTypeIsACollectionInterface_ReturnAnEmptyCollection()
{
Assert.NotNull(ReturnValueUtil.DefaultValue(typeof (IEnumerable), null) as IEnumerable);

var defaultValueForCollections = ReturnValueUtil.DefaultValue(typeof (ICollection), null) as ICollection;
Assert.NotNull(defaultValueForCollections);
Assert.Equal(0, defaultValueForCollections.Count);

var defaultValueForLists = ReturnValueUtil.DefaultValue(typeof (IList), null) as IList;
Assert.NotNull(defaultValueForLists);
Assert.Equal(0, defaultValueForLists.Count);

var defaultValueForDictionaries = ReturnValueUtil.DefaultValue(typeof (IDictionary), null) as IDictionary;
Assert.NotNull(defaultValueForDictionaries);
Assert.Equal(0, defaultValueForDictionaries.Keys.Count);
Assert.Equal(0, defaultValueForDictionaries.Values.Count);
}

[Fact]
public void DefaultReturnValue_WhenTheReturnTypeIsAGenericCollectionInterface_ReturnAnEmptyCollection()
{
var defValForGenericEnumerable = ReturnValueUtil.DefaultValue(typeof (IEnumerable<IFoo>), null);
Assert.NotNull(defValForGenericEnumerable);

var defValForAGenericCollection = ReturnValueUtil.DefaultValue(typeof (ICollection<IFoo>), null) as ICollection<IFoo>;
Assert.NotNull(defValForAGenericCollection);
Assert.Equal(0, defValForAGenericCollection.Count);

var defValForAGenericList = ReturnValueUtil.DefaultValue(typeof (IList<IFoo>), null) as IList<IFoo>;
Assert.NotNull(defValForAGenericList);
Assert.Equal(0, defValForAGenericList.Count);

var defValForAGenericDictionary =
ReturnValueUtil.DefaultValue(typeof (IDictionary<IFoo, TestEnum>), null) as IDictionary<IFoo, TestEnum>;
Assert.NotNull(defValForAGenericDictionary);
Assert.Equal(0, defValForAGenericDictionary.Keys.Count);
Assert.Equal(0, defValForAGenericDictionary.Values.Count);
}

[Fact]
public void DefaultReturnValue_WhenTheReturnTypeImplementsAdditionalsInterfacesToIEnumerable_ReturnNull()
{
object defVal = ReturnValueUtil.DefaultValue(typeof (IFoo), null);

Assert.Null(defVal);
}

private enum TestEnum
{
DefaultValue,
NonDefaultValue
}

public interface IFoo : IEnumerable
{
string Bar { get; set; }
}
}
}
39 changes: 37 additions & 2 deletions Rhino.Mocks/Utilities/ReturnValueUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@


using System;
using System.Collections;
using System.Collections.Generic;
using Castle.Core.Interceptor;

namespace Rhino.Mocks.Utilities
Expand All @@ -39,7 +41,8 @@ public class ReturnValueUtil
{
/// <summary>
/// The default value for a type.
/// Null for reference types and void
/// Empty Collections for IEnumerable, ICollection, IList and IDictionary types
/// Null for the rest of reference types and void
/// 0 for value types.
/// First element for enums
/// Note that we need to get the value even for opened generic types, such as those from
Expand All @@ -52,8 +55,40 @@ public static object DefaultValue(Type type, IInvocation invocation)
{
type = GenericsUtil.GetRealType(type, invocation);
if (type.IsValueType == false || type==typeof(void))
return null;
return TryInstantiateCollectionInterfacesOrReturnNull(type);

return Activator.CreateInstance(type);
}

private static object TryInstantiateCollectionInterfacesOrReturnNull(Type returnType)
{
if (!returnType.IsInterface) return null;

if (returnType.IsGenericType)
{
Type[] arguments = returnType.GetGenericArguments();

Type typeDefinition = returnType.GetGenericTypeDefinition();

if (typeDefinition == typeof(IList<>) ||
typeDefinition == typeof(IEnumerable<>) ||
typeDefinition == typeof(ICollection<>))
return Activator.CreateInstance(typeof(List<>).MakeGenericType(arguments));

if (typeDefinition == typeof(IDictionary<,>))
return Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(arguments));

return null;
}
if (returnType == (typeof(IList)) ||
returnType == typeof(IEnumerable) ||
returnType.Equals(typeof(ICollection)))
return new ArrayList();

if (returnType.Equals(typeof(IDictionary)))
return new Dictionary<object, object>();

return null;
}
}
}