From 455866bea687477603a38060e0cde5f81501fa4c Mon Sep 17 00:00:00 2001 From: Denis Voituron Date: Sun, 5 Aug 2018 14:27:49 +0200 Subject: [PATCH] Add MockTable.FromCsv method --- DbMocker.Tests/DbMockTableTests.cs | 17 ++++-- DbMocker/DbMocker.csproj | 4 +- DbMocker/Helpers/TypeExtension.cs | 16 ++++- DbMocker/MockReturns.cs | 2 +- DbMocker/MockTableImport.cs | 94 ++++++++++++++++++++++++++++++ DbMocker/MockTableStatic.cs | 54 ----------------- ReadMe.md | 19 +++++- 7 files changed, 141 insertions(+), 65 deletions(-) create mode 100644 DbMocker/MockTableImport.cs diff --git a/DbMocker.Tests/DbMockTableTests.cs b/DbMocker.Tests/DbMockTableTests.cs index b864113..b43d50d 100644 --- a/DbMocker.Tests/DbMockTableTests.cs +++ b/DbMocker.Tests/DbMockTableTests.cs @@ -153,10 +153,10 @@ public void Mock_MockTable_FromCsv_Test() { var conn = new MockDbConnection(); - string csv = @" Id Name - 1 Scott - 2 Bill - 3 Anders "; + string csv = @" Id Name Birthdate + 1 Scott 1980-02-03 + 2 Bill 1972-01-12 + 3 Anders 1965-03-14 "; var table = MockTable.FromCsv(csv); @@ -164,8 +164,15 @@ 2 Bill Assert.AreEqual("Name", table.Columns[1]); Assert.AreEqual(3, table.Rows.RowsCount()); + Assert.AreEqual("Scott", table.Rows[0, 1]); - Assert.AreEqual("3", table.Rows[2, 0]); + Assert.IsInstanceOfType(table.Rows[0, 1], typeof(string)); + + Assert.AreEqual(3, table.Rows[2, 0]); + Assert.IsInstanceOfType(table.Rows[2, 0], typeof(int)); + + Assert.AreEqual(new DateTime(1972, 1, 12), table.Rows[1, 2]); + Assert.IsInstanceOfType(table.Rows[1, 2], typeof(DateTime)); } } diff --git a/DbMocker/DbMocker.csproj b/DbMocker/DbMocker.csproj index 9ab7805..bd52388 100644 --- a/DbMocker/DbMocker.csproj +++ b/DbMocker/DbMocker.csproj @@ -4,7 +4,7 @@ netcoreapp2.1 Apps72.Dev.Data.DbMocker Apps72.Dev.Data.DbMocker - 1.3.0 + 1.4.0 DbMocker Denis Voituron DbMocker @@ -18,7 +18,7 @@ conn.Mocks.WhenAny()..ReturnsScalar(14); DbMocker, Mocker, SQLServer, Oracle, Sqlite, EntityFramework, EF, Dapper, UnitTest https://github.com/Apps72/DbMocker true - 1.3.0.0 + 1.4.0.0 https://github.com/Apps72/DbMocker https://github.com/Apps72/DbMocker diff --git a/DbMocker/Helpers/TypeExtension.cs b/DbMocker/Helpers/TypeExtension.cs index 276d91c..bf6b825 100644 --- a/DbMocker/Helpers/TypeExtension.cs +++ b/DbMocker/Helpers/TypeExtension.cs @@ -3,7 +3,7 @@ namespace Apps72.Dev.Data.DbMocker.Helpers { /// - internal class TypeExtension + internal static class TypeExtension { /// /// Returns True if this object is a simple type. @@ -11,7 +11,7 @@ internal class TypeExtension /// /// /// - public static bool IsPrimitive(Type type) + public static bool IsPrimitive(this Type type) { return type == typeof(DateTime) || type == typeof(Nullable) || type == typeof(Decimal) || type == typeof(Nullable) || @@ -31,5 +31,17 @@ public static bool IsPrimitive(Type type) type == typeof(Double) || type == typeof(Nullable) || type == typeof(Single) || type == typeof(Nullable); } + + public static Type BestType(this string text) + { + if (DateTime.TryParse(text, out DateTime _)) return typeof(DateTime); + if (Boolean.TryParse(text, out Boolean _)) return typeof(DateTime); + if (Int32.TryParse(text, out Int32 _)) return typeof(Int32); + if (Int64.TryParse(text, out Int64 _)) return typeof(Int64); + if (Double.TryParse(text, out Double _)) return typeof(Double); + if (Decimal.TryParse(text, out Decimal _)) return typeof(Decimal); + if (Char.TryParse(text, out Char _)) return typeof(Char); + return typeof(string); + } } } diff --git a/DbMocker/MockReturns.cs b/DbMocker/MockReturns.cs index bf5fb11..a1274c7 100644 --- a/DbMocker/MockReturns.cs +++ b/DbMocker/MockReturns.cs @@ -78,7 +78,7 @@ public void ReturnsScalar(T returns) /// private MockTable ConvertToMockTable(T returns) { - if (returns == null || returns is DBNull || TypeExtension.IsPrimitive(typeof(T))) + if (returns == null || returns is DBNull || typeof(T).IsPrimitive()) { return new MockTable() { diff --git a/DbMocker/MockTableImport.cs b/DbMocker/MockTableImport.cs new file mode 100644 index 0000000..146865f --- /dev/null +++ b/DbMocker/MockTableImport.cs @@ -0,0 +1,94 @@ +using Apps72.Dev.Data.DbMocker.Helpers; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Apps72.Dev.Data.DbMocker +{ + public partial class MockTable + { + /// + public static MockTable FromCsv(string content, string delimiter, CsvImportOptions options) + { + var table = MockTable.Empty(); + Type[] types = null; + bool isFirstRow = true; // First row = Column names + bool isFirstDataRow = false; // Second row = First data row + bool mustRemoveEmptyLines = (options & CsvImportOptions.RemoveEmptyLines) == CsvImportOptions.RemoveEmptyLines; + bool mustTrimLines = (options & CsvImportOptions.TrimLines) == CsvImportOptions.TrimLines; + + foreach (string row in content.Split(Environment.NewLine)) + { + if (mustRemoveEmptyLines && string.IsNullOrEmpty(row)) + { + + } + else + { + string[] data; + + if (mustTrimLines) + data = row.Trim().Split(delimiter); + else + data = row.Split(delimiter); + + if (isFirstRow) + table.AddColumns(data); + else + { + if (isFirstDataRow) + types = GetTypesOfFirstDataRow(data); + + table.AddRow(ConvertStringToTypes(data, types)); + } + + isFirstRow = false; + isFirstDataRow = !isFirstDataRow ? true : isFirstDataRow; + } + } + + return table; + } + + /// + public static MockTable FromCsv(string content, string delimiter) + { + return FromCsv(content, delimiter, CsvImportOptions.RemoveEmptyLines | CsvImportOptions.TrimLines); + } + + /// + public static MockTable FromCsv(string content) + { + return FromCsv(content, "\t"); + } + + /// + private static Type[] GetTypesOfFirstDataRow(string[] values) + { + return values.Select(i => i.BestType()).ToArray(); + } + + /// + private static object[] ConvertStringToTypes(string[] values, Type[] types) + { + var result = new List(); + + for (int i = 0; i < values.Length; i++) + { + if (i < types.Length) + result.Add(Convert.ChangeType(values[i], types[i])); + else + result.Add(values[i]); + } + + return result.ToArray(); + } + } + + public enum CsvImportOptions + { + None = 0, + RemoveEmptyLines = 1, + TrimLines = 2, + } +} diff --git a/DbMocker/MockTableStatic.cs b/DbMocker/MockTableStatic.cs index f17c766..0dfb490 100644 --- a/DbMocker/MockTableStatic.cs +++ b/DbMocker/MockTableStatic.cs @@ -35,59 +35,5 @@ public static MockTable SingleCell(object value) { return SingleCell(String.Empty, value); } - - /// - public static MockTable FromCsv(string content, string delimiter, CsvImportOptions options) - { - var table = MockTable.Empty(); - bool isFirstRow = true; - bool mustRemoveEmptyLines = (options & CsvImportOptions.RemoveEmptyLines) == CsvImportOptions.RemoveEmptyLines; - bool mustTrimLines = (options & CsvImportOptions.TrimLines) == CsvImportOptions.TrimLines; - - foreach (string row in content.Split(Environment.NewLine)) - { - if (mustRemoveEmptyLines && string.IsNullOrEmpty(row)) - { - - } - else - { - string[] data; - - if (mustTrimLines) - data = row.Trim().Split(delimiter); - else - data = row.Split(delimiter); - - if (isFirstRow) - table.AddColumns(data); - else - table.AddRow(data); - - isFirstRow = false; - } - } - - return table; - } - - /// - public static MockTable FromCsv(string content, string delimiter) - { - return FromCsv(content, delimiter, CsvImportOptions.RemoveEmptyLines | CsvImportOptions.TrimLines); - } - - /// - public static MockTable FromCsv(string content) - { - return FromCsv(content, "\t"); - } - } - - public enum CsvImportOptions - { - None = 0, - RemoveEmptyLines = 1, - TrimLines = 2, } } diff --git a/ReadMe.md b/ReadMe.md index 8e90627..e37aa44 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -125,6 +125,21 @@ conn.Mocks .ReturnsTable(cmd => cmd.Parameters.Count() > 0 ? 14 : 99); ``` +using a **CSV string** with all data. +The first row contains the column names. +The first data row defines types for each columns (like in a Excel importation). + +```CSharp +string csv = @" Id Name Birthdate + 1 Scott 1980-02-03 + 2 Bill 1972-01-12 + 3 Anders 1965-03-14 "; + +conn.Mocks + .WhenAny() + .ReturnsTable(MockTable.FromCsv(csv)); +``` + ## ReturnsRow When a condition occured, a single data row will be return. @@ -168,7 +183,9 @@ conn.Mocks - Add `ReturnsRow(T)` and `ReturnsRow(Func)` methods. +### Version 1.4 +- Add `MockTable.FromCsv(string)` method. + ## Road map -- To create a MockTable from a CSV, to detect column type from values of first row (like Excel) - DataSets are not yet implemented.