Skip to content
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
38 changes: 38 additions & 0 deletions Moq.Dapper.Test/DapperQueryTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
Expand Down Expand Up @@ -282,6 +284,42 @@ public void QueryFirstOrDefaultString()
Assert.That(actual, Is.Null);
}

[Test]
public void SetupDapper_SetForKnownNonPrimitiveTypes_QueryShouldBeAbleToReturnMockedCollections()
{
TestQueryWithKnownNonPrimitiveTypes(new List<FileMode> { FileMode.Open, FileMode.Create });
TestQueryWithKnownNonPrimitiveTypes(new List<FileMode?> { FileMode.Open, null });
TestQueryWithKnownNonPrimitiveTypes(new List<DateTime> { DateTime.Now, DateTime.Now.AddDays(1) });
TestQueryWithKnownNonPrimitiveTypes(new List<DateTime?> { null, DateTime.Now.AddDays(1) });
TestQueryWithKnownNonPrimitiveTypes(new List<DateTimeOffset> { DateTimeOffset.UtcNow, DateTimeOffset.Now});
TestQueryWithKnownNonPrimitiveTypes(new List<DateTimeOffset?> { null, DateTimeOffset.UtcNow });
TestQueryWithKnownNonPrimitiveTypes(new List<decimal> { 1.234m, 4.65m });
TestQueryWithKnownNonPrimitiveTypes(new List<decimal?> { null, 4.65m });
TestQueryWithKnownNonPrimitiveTypes(new List<Guid> { Guid.NewGuid(), Guid.NewGuid() });
TestQueryWithKnownNonPrimitiveTypes(new List<Guid?> { Guid.NewGuid(), null });
TestQueryWithKnownNonPrimitiveTypes(new List<string> { "One", "Two" });
TestQueryWithKnownNonPrimitiveTypes(new List<string> { "One", null });
TestQueryWithKnownNonPrimitiveTypes(new List<TimeSpan> { TimeSpan.MinValue, TimeSpan.MaxValue });
TestQueryWithKnownNonPrimitiveTypes(new List<TimeSpan?> { TimeSpan.MinValue, null });
TestQueryWithKnownNonPrimitiveTypes(new List<byte[]> { new byte[] { 144, 27, 113, 141, 6, 167, 63, 45, 89, 186, 226, 225, 155, 20, 175, 86 }, new byte[] { 144, 27, 113, 141, 6, 167, 63, 45, 89, 186, 226, 225, 155, 20, 175, 87 }});
TestQueryWithKnownNonPrimitiveTypes(new List<byte[]> { new byte[] { 144, 27, 113, 141, 6, 167, 63, 45, 89, 186, 226, 225, 155, 20, 175, 86 }, null });
}

#region Private members
private void TestQueryWithKnownNonPrimitiveTypes<TResult>(IEnumerable<TResult> expected)
{
var connection = new Mock<IDbConnection>();

connection.SetupDapper(c => c.Query<TResult>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<bool>(), It.IsAny<int?>(), It.IsAny<CommandType?>()))
.Returns(expected);

var actual = connection.Object.Query<TResult>("");

Assert.That(actual.Count, Is.EqualTo(expected.Count()));
Assert.That(actual, Is.EquivalentTo(expected));
}
#endregion

public class ComplexType
{
public enum EnumType
Expand Down
67 changes: 42 additions & 25 deletions Moq.Dapper/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,28 @@ public static class EnumerableExtensions
internal static DataTable ToDataTable(this IEnumerable results, Type tableType)
{
var dataTable = new DataTable();

if (tableType.IsPrimitive || tableType == typeof(string))

var underlyingType = GetDataColumnType(tableType);

if (IsADapperQuerySupportedType(underlyingType))
{
dataTable.Columns.Add();
dataTable.Columns.Add(new DataColumn("Column1", underlyingType));

foreach (var element in results)
dataTable.Rows.Add(element);
{
if(element == null)
{
dataTable.Rows.Add(DBNull.Value);
}
else
{
dataTable.Rows.Add(element);
}
}

}
else
{
bool IsNullable(Type t) =>
t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(Nullable<>);

Type GetDataColumnType(Type source) =>
IsNullable(source) ?
Nullable.GetUnderlyingType(source) :
source;

bool IsMatchingType(Type t) =>
t.IsPrimitive ||
t.IsEnum ||
t == typeof(DateTime) ||
t == typeof(DateTimeOffset) ||
t == typeof(decimal) ||
t == typeof(BigInteger) ||
t == typeof(Guid) ||
t == typeof(string) ||
t == typeof(TimeSpan) ||
t == typeof(byte[]);

var properties =
tableType.GetProperties().
Where
Expand All @@ -61,6 +52,32 @@ bool IsMatchingType(Type t) =>
foreach (var element in results)
dataTable.Rows.Add(valuesFactory.Select(getValue => getValue(element)).ToArray());
}

bool IsNullable(Type t) =>
t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(Nullable<>);

Type GetDataColumnType(Type source) =>
IsNullable(source) ?
Nullable.GetUnderlyingType(source) :
source;

bool IsADapperQuerySupportedType(Type t) =>
t.IsPrimitive ||
t.IsEnum ||
t == typeof(DateTime) ||
t == typeof(DateTimeOffset) ||
t == typeof(decimal) ||
t == typeof(Guid) ||
t == typeof(string) ||
t == typeof(TimeSpan) ||
t == typeof(byte[]);

//Dapper does not list BigInteger in it's type map.
//So, Query<BigInteger> returns 0 for every BigInteger in Response.
bool IsMatchingType(Type t) =>
IsADapperQuerySupportedType(t) ||
t == typeof(BigInteger);

return dataTable;
}
Expand Down