From b21d0c66612c63b0a9b478e5472b99a0f64ea3d7 Mon Sep 17 00:00:00 2001 From: a-postx Date: Sun, 17 Sep 2023 09:10:09 -0700 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE=D0=B2:=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3?= =?UTF-8?q?=D1=83=D0=BB=D0=B8=D1=80=D1=83=D0=B5=D1=82=D1=81=D1=8F=20=D0=BD?= =?UTF-8?q?=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=BE=D0=B9,=20?= =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=BE=20=D0=B1=D1=8B?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=B4=D0=B5=D0=B9=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D0=B8=D0=B5,=20=D0=B2.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ytes.NetCore.EntityReportGeneration.csproj | 8 +- ...lobytes.NetCore.EntityReportGeneration.xml | 5 + src/EntityReportGenerator.cs | 40 ++- src/EntityReportGeneratorOptions.cs | 4 + test/EntityReportGeneratorTests.cs | 266 ++++++++++++++---- test/ObjectWithEnumerable.cs | 10 + ...jectWithTypedList.cs => ObjectWithList.cs} | 4 +- ...ist.cs => ObjectWithNullableEnumerable.cs} | 4 +- test/ObjectWithNullableList.cs | 10 + 9 files changed, 286 insertions(+), 65 deletions(-) create mode 100644 test/ObjectWithEnumerable.cs rename test/{ObjectWithTypedList.cs => ObjectWithList.cs} (77%) rename test/{ObjectWithGenericList.cs => ObjectWithNullableEnumerable.cs} (73%) create mode 100644 test/ObjectWithNullableList.cs diff --git a/src/Delobytes.NetCore.EntityReportGeneration.csproj b/src/Delobytes.NetCore.EntityReportGeneration.csproj index 81f35b9..283f4cc 100644 --- a/src/Delobytes.NetCore.EntityReportGeneration.csproj +++ b/src/Delobytes.NetCore.EntityReportGeneration.csproj @@ -2,7 +2,7 @@ net6.0 - 1.0.0.0 + 2.0.0.0 latest Алексей Якубин Делобайты @@ -22,9 +22,9 @@ - - - + + + diff --git a/src/Delobytes.NetCore.EntityReportGeneration.xml b/src/Delobytes.NetCore.EntityReportGeneration.xml index 312d60f..3206dbc 100644 --- a/src/Delobytes.NetCore.EntityReportGeneration.xml +++ b/src/Delobytes.NetCore.EntityReportGeneration.xml @@ -43,6 +43,11 @@ Символ-разделитель для вывода в CSV. + + + Признак необходимости подробного вывода перечислимых свойств. + + Атрибут показывает, что свойство должно быть проигнорировано. diff --git a/src/EntityReportGenerator.cs b/src/EntityReportGenerator.cs index 8fff486..13b23c2 100644 --- a/src/EntityReportGenerator.cs +++ b/src/EntityReportGenerator.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Data; using System.Reflection; +using System.Text; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -88,6 +89,12 @@ private DataTable ConvertObjectsToExcelDataTable(IEnumerable items, string return result; } + private static string ConvertToString(object? property, string stringToCleanup) + { + string cellValue = property?.ToString() ?? string.Empty; + return string.IsNullOrEmpty(stringToCleanup) ? cellValue : RemoveDelimiterChar(cellValue, stringToCleanup); + } + /// public byte[] GenerateExcelContent(IDictionary> pagesDataset) where T : class { @@ -170,27 +177,46 @@ private DataTable ConvertObjectsToDataTableForCsv(IEnumerable items, strin for (int i = 0; i < properties.Length; i++) { - if (properties[i].PropertyType == typeof(List)) + object? columnValue; + + Type[]? interfaces = properties[i].PropertyType.GetInterfaces(); + + if (interfaces.Contains(typeof(IEnumerable)) + && properties[i].PropertyType.Name != "String" + && _options.DetailedEnumerables) { - string? stringValue = string.Empty; + object? value = properties[i].GetValue(item, null); + + StringBuilder sb = value is IList list ? new StringBuilder(list.Count) : new StringBuilder(); + bool firstElement = true; if (properties[i].GetValue(item, null) is IEnumerable enumerable) { foreach (object element in enumerable) { - stringValue = string.IsNullOrEmpty(stringValue) ? element.ToString() : stringValue + "," + element; + if (firstElement) + { + sb.Append(element.ToString()); + firstElement = false; + } + else + { + sb.Append(','); + sb.Append(element); + } } } - dataRow[i] = string.IsNullOrEmpty(stringToCleanup) ? stringValue : RemoveDelimiterChar(stringValue, stringToCleanup); + columnValue = sb.ToString(); } else { - object? propertyValue = properties[i].GetValue(item, null); - string cellValue = propertyValue?.ToString() ?? string.Empty; - dataRow[i] = string.IsNullOrEmpty(stringToCleanup) ? cellValue : RemoveDelimiterChar(cellValue, stringToCleanup); + columnValue = properties[i].GetValue(item, null); } + + dataRow[i] = ConvertToString(columnValue, stringToCleanup); } + result.Rows.Add(dataRow); } } diff --git a/src/EntityReportGeneratorOptions.cs b/src/EntityReportGeneratorOptions.cs index eb52c99..a869daa 100644 --- a/src/EntityReportGeneratorOptions.cs +++ b/src/EntityReportGeneratorOptions.cs @@ -9,4 +9,8 @@ public class EntityReportGeneratorOptions /// Символ-разделитель для вывода в CSV. /// public string CsvDelimiter { get; set; } = "U+002C"; + /// + /// Признак необходимости подробного вывода перечислимых свойств. + /// + public bool DetailedEnumerables { get; set; } = false; } diff --git a/test/EntityReportGeneratorTests.cs b/test/EntityReportGeneratorTests.cs index 5e9b451..dbb83be 100644 --- a/test/EntityReportGeneratorTests.cs +++ b/test/EntityReportGeneratorTests.cs @@ -13,6 +13,11 @@ public class EntityReportGeneratorTests { options.CsvDelimiter = "`"; }; + private static readonly Action DetailedEnumerablesOptions = options => + { + options.CsvDelimiter = "`"; + options.DetailedEnumerables = true; + }; #region Infrastructure @@ -33,17 +38,23 @@ private IEntityReportGenerator GetReportGenerator() return app.Services.GetRequiredService(); } - private List GetGenericListEntities() + private IEntityReportGenerator GetDetailedReportGenerator() + { + WebApplication app = CreateApplication(DetailedEnumerablesOptions); + return app.Services.GetRequiredService(); + } + + private List GetNullableListEntities() { List strings = new List { "string1", "string2" }; Guid id1 = Guid.NewGuid(); Guid id2 = Guid.NewGuid(); - ObjectWithGenericList obj1 = new ObjectWithGenericList { Id = 1, IsDeleted = true, Name = "Obj1", ObjGuid = id1, Properties = strings }; - ObjectWithGenericList obj2 = new ObjectWithGenericList { Id = 2, IsDeleted = false, Name = "Obj2", ObjGuid = id2, Properties = strings }; + ObjectWithNullableList obj1 = new ObjectWithNullableList { Id = 1, IsDeleted = true, Name = "Obj1", GuidProp = id1, Properties = strings }; + ObjectWithNullableList obj2 = new ObjectWithNullableList { Id = 2, IsDeleted = false, Name = "Obj2", GuidProp = id2, Properties = strings }; - List entitiesList = new List + List entitiesList = new List { obj1, obj2 @@ -52,17 +63,56 @@ private List GetGenericListEntities() return entitiesList; } - private List GetTypedListEntities() + private List GetListEntities() { List strings = new List { "string1", "string2" }; + Guid id1 = Guid.NewGuid(); + Guid id2 = Guid.NewGuid(); + + ObjectWithList obj1 = new ObjectWithList { Id = 1, IsDeleted = true, Name = "Obj1", GuidProp = id1, Properties = strings }; + ObjectWithList obj2 = new ObjectWithList { Id = 2, IsDeleted = false, Name = "Obj2", GuidProp = id2, Properties = strings }; + + List entitiesList = new List + { + obj1, + obj2 + }; + return entitiesList; + } + + private List GetEnumerableEntities() + { + string[] strings = new string[2]; + strings.SetValue("string1", 0); + strings.SetValue("string2", 1); Guid id1 = Guid.NewGuid(); Guid id2 = Guid.NewGuid(); - ObjectWithTypedList obj1 = new ObjectWithTypedList { Id = 1, IsDeleted = true, Name = "Obj1", ObjGuid = id1, Properties = strings }; - ObjectWithTypedList obj2 = new ObjectWithTypedList { Id = 2, IsDeleted = false, Name = "Obj2", ObjGuid = id2, Properties = strings }; + ObjectWithEnumerable obj1 = new ObjectWithEnumerable { Id = 1, IsDeleted = true, Name = "Obj1", GuidProp = id1, Properties = strings }; + ObjectWithEnumerable obj2 = new ObjectWithEnumerable { Id = 2, IsDeleted = false, Name = "Obj2", GuidProp = id2, Properties = strings }; - List entitiesList = new List + List entitiesList = new List + { + obj1, + obj2 + }; + + return entitiesList; + } + + private List GetNullableEnumerableEntities() + { + string[] strings = new string[2]; + strings.SetValue("string1", 0); + strings.SetValue("string2", 1); + Guid id1 = Guid.NewGuid(); + Guid id2 = Guid.NewGuid(); + + ObjectWithNullableEnumerable obj1 = new ObjectWithNullableEnumerable { Id = 1, IsDeleted = true, Name = "Obj1", GuidProp = id1, Properties = strings }; + ObjectWithNullableEnumerable obj2 = new ObjectWithNullableEnumerable { Id = 2, IsDeleted = false, Name = "Obj2", GuidProp = id2, Properties = strings }; + + List entitiesList = new List { obj1, obj2 @@ -92,10 +142,10 @@ public void EntityReportGenerator_ConfiguredSuccessfully() public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_WithTwoElements() { IEntityReportGenerator generator = GetReportGenerator(); - List entitiesForPage1 = GetTypedListEntities(); - List entitiesForPage2 = GetTypedListEntities(); + List entitiesForPage1 = GetListEntities(); + List entitiesForPage2 = GetListEntities(); - Dictionary> sheets = new Dictionary> + Dictionary> sheets = new Dictionary> { { "page1", entitiesForPage1 }, { "page2", entitiesForPage2 } @@ -130,15 +180,15 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_W sheet.Cells.Value.Should().NotBeNull(); object r0c0Value = ((object[,])sheet.Cells.Value)[0, 0]; - r0c0Value.Should().Be(nameof(ObjectWithTypedList.Id)); + r0c0Value.Should().Be(nameof(ObjectWithList.Id)); object r0c1Value = ((object[,])sheet.Cells.Value)[0, 1]; - r0c1Value.Should().Be(nameof(ObjectWithTypedList.IsDeleted)); + r0c1Value.Should().Be(nameof(ObjectWithList.IsDeleted)); object r0c2Value = ((object[,])sheet.Cells.Value)[0, 2]; - r0c2Value.Should().Be(nameof(ObjectWithTypedList.Name)); + r0c2Value.Should().Be(nameof(ObjectWithList.Name)); object r0c3Value = ((object[,])sheet.Cells.Value)[0, 3]; - r0c3Value.Should().Be(nameof(ObjectWithTypedList.ObjGuid)); + r0c3Value.Should().Be(nameof(ObjectWithList.GuidProp)); object r0c4Value = ((object[,])sheet.Cells.Value)[0, 4]; - r0c4Value.Should().Be(nameof(ObjectWithTypedList.Properties)); + r0c4Value.Should().Be(nameof(ObjectWithList.Properties)); object r1c0Value = ((object[,])sheet.Cells.Value)[1, 0]; r1c0Value.Should().Be(entitiesForPage1[0].Id); @@ -149,7 +199,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_W object r1c3Value = ((object[,])sheet.Cells.Value)[1, 3]; bool guid1Parsed = Guid.TryParse(r1c3Value.ToString(), out Guid guid1value); guid1Parsed.Should().Be(true); - guid1value.Should().Be(entitiesForPage1[0].ObjGuid.ToString()); + guid1value.Should().Be(entitiesForPage1[0].GuidProp.ToString()); object r1c4Value = ((object[,])sheet.Cells.Value)[1, 4]; //EPPlus заносит значение первого элемента коллекции r1c4Value.Should().Be(entitiesForPage1[0].Properties[0]); @@ -163,7 +213,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_W object r2c3Value = ((object[,])sheet.Cells.Value)[2, 3]; bool guid2Parsed = Guid.TryParse(r2c3Value.ToString(), out Guid guid2value); guid2Parsed.Should().Be(true); - guid2value.Should().Be(entitiesForPage1[1].ObjGuid.ToString()); + guid2value.Should().Be(entitiesForPage1[1].GuidProp.ToString()); object r2c4Value = ((object[,])sheet.Cells.Value)[2, 4]; r2c4Value.Should().Be(entitiesForPage1[1].Properties[0]); @@ -176,15 +226,15 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_W sheet2.Cells.Value.Should().NotBeNull(); object s2r0c0Value = ((object[,])sheet2.Cells.Value)[0, 0]; - s2r0c0Value.Should().Be(nameof(ObjectWithTypedList.Id)); + s2r0c0Value.Should().Be(nameof(ObjectWithList.Id)); object s2r0c1Value = ((object[,])sheet2.Cells.Value)[0, 1]; - s2r0c1Value.Should().Be(nameof(ObjectWithTypedList.IsDeleted)); + s2r0c1Value.Should().Be(nameof(ObjectWithList.IsDeleted)); object s2r0c2Value = ((object[,])sheet2.Cells.Value)[0, 2]; - s2r0c2Value.Should().Be(nameof(ObjectWithTypedList.Name)); + s2r0c2Value.Should().Be(nameof(ObjectWithList.Name)); object s2r0c3Value = ((object[,])sheet2.Cells.Value)[0, 3]; - s2r0c3Value.Should().Be(nameof(ObjectWithTypedList.ObjGuid)); + s2r0c3Value.Should().Be(nameof(ObjectWithList.GuidProp)); object s2r0c4Value = ((object[,])sheet2.Cells.Value)[0, 4]; - s2r0c4Value.Should().Be(nameof(ObjectWithTypedList.Properties)); + s2r0c4Value.Should().Be(nameof(ObjectWithList.Properties)); object s2r1c0Value = ((object[,])sheet2.Cells.Value)[1, 0]; s2r1c0Value.Should().Be(entitiesForPage2[0].Id); @@ -195,7 +245,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_W object s2r1c3Value = ((object[,])sheet2.Cells.Value)[1, 3]; bool s2guid1Parsed = Guid.TryParse(s2r1c3Value.ToString(), out Guid s2guid1value); s2guid1Parsed.Should().Be(true); - s2guid1value.Should().Be(entitiesForPage2[0].ObjGuid.ToString()); + s2guid1value.Should().Be(entitiesForPage2[0].GuidProp.ToString()); object s2r1c4Value = ((object[,])sheet2.Cells.Value)[1, 4]; //EPPlus заносит значение первого элемента коллекции s2r1c4Value.Should().Be(entitiesForPage2[0].Properties[0]); @@ -209,7 +259,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromGeneric_W object s2r2c3Value = ((object[,])sheet2.Cells.Value)[2, 3]; bool s2guid2Parsed = Guid.TryParse(s2r2c3Value.ToString(), out Guid s2guid2value); s2guid2Parsed.Should().Be(true); - s2guid2value.Should().Be(entitiesForPage2[1].ObjGuid.ToString()); + s2guid2value.Should().Be(entitiesForPage2[1].GuidProp.ToString()); object s2r2c4Value = ((object[,])sheet2.Cells.Value)[2, 4]; s2r2c4Value.Should().Be(entitiesForPage2[1].Properties[0]); } @@ -356,7 +406,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromExpando() public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromDirect() { IEntityReportGenerator generator = GetReportGenerator(); - List entities = GetTypedListEntities(); + List entities = GetListEntities(); byte[]? content = null; @@ -389,15 +439,15 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromDirect() sheet.Cells.Value.Should().NotBeNull(); object r0c0Value = ((object[,])sheet.Cells.Value)[0, 0]; - r0c0Value.Should().Be(nameof(ObjectWithTypedList.Id)); + r0c0Value.Should().Be(nameof(ObjectWithList.Id)); object r0c1Value = ((object[,])sheet.Cells.Value)[0, 1]; - r0c1Value.Should().Be(nameof(ObjectWithTypedList.IsDeleted)); + r0c1Value.Should().Be(nameof(ObjectWithList.IsDeleted)); object r0c2Value = ((object[,])sheet.Cells.Value)[0, 2]; - r0c2Value.Should().Be(nameof(ObjectWithTypedList.Name)); + r0c2Value.Should().Be(nameof(ObjectWithList.Name)); object r0c3Value = ((object[,])sheet.Cells.Value)[0, 3]; - r0c3Value.Should().Be(nameof(ObjectWithTypedList.ObjGuid)); + r0c3Value.Should().Be(nameof(ObjectWithList.GuidProp)); object r0c4Value = ((object[,])sheet.Cells.Value)[0, 4]; - r0c4Value.Should().Be(nameof(ObjectWithTypedList.Properties)); + r0c4Value.Should().Be(nameof(ObjectWithList.Properties)); object r1c0Value = ((object[,])sheet.Cells.Value)[1, 0]; r1c0Value.Should().Be(entities[0].Id); @@ -408,7 +458,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromDirect() object r1c3Value = ((object[,])sheet.Cells.Value)[1, 3]; bool guid1Parsed = Guid.TryParse(r1c3Value.ToString(), out Guid guid1value); guid1Parsed.Should().Be(true); - guid1value.Should().Be(entities[0].ObjGuid!.ToString()); + guid1value.Should().Be(entities[0].GuidProp!.ToString()); object r1c4Value = ((object[,])sheet.Cells.Value)[1, 4]; //EPPlus заносит значение первого элемента коллекции r1c4Value.Should().Be(entities[0]?.Properties[0]); @@ -422,7 +472,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromDirect() object r2c3Value = ((object[,])sheet.Cells.Value)[2, 3]; bool guid2Parsed = Guid.TryParse(r2c3Value.ToString(), out Guid guid2value); guid2Parsed.Should().Be(true); - guid2value.Should().Be(entities[1].ObjGuid!.ToString()); + guid2value.Should().Be(entities[1].GuidProp!.ToString()); object r2c4Value = ((object[,])sheet.Cells.Value)[2, 4]; r2c4Value.Should().Be(entities[1]?.Properties[0]); } @@ -432,7 +482,7 @@ public void EntityReportGenerator_GenerateExcelContentSuccessfully_FromDirect() public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithNonNullableList() { IEntityReportGenerator generator = GetReportGenerator(); - List objectList = GetTypedListEntities(); + List objectList = GetListEntities(); string? content = null; @@ -446,20 +496,20 @@ public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithNonNullable ex.Should().BeNull(); content.Should().NotBeNull(); content.Should().Contain(CsvDelimiter); - content.Should().Contain(nameof(ObjectWithTypedList.Id)); - content.Should().Contain(nameof(ObjectWithTypedList.IsDeleted)); - content.Should().Contain(nameof(ObjectWithTypedList.Name)); - content.Should().Contain(nameof(ObjectWithTypedList.ObjGuid)); - content.Should().Contain(nameof(ObjectWithTypedList.Properties)); + content.Should().Contain(nameof(ObjectWithList.Id)); + content.Should().Contain(nameof(ObjectWithList.IsDeleted)); + content.Should().Contain(nameof(ObjectWithList.Name)); + content.Should().Contain(nameof(ObjectWithList.GuidProp)); + content.Should().Contain(nameof(ObjectWithList.Properties)); content.Should().Contain(objectList[0].Id.ToString()); content.Should().Contain(objectList[1].Id.ToString()); content.Should().Contain(objectList[0].IsDeleted.ToString()); content.Should().Contain(objectList[1].IsDeleted.ToString()); content.Should().Contain(objectList[0].Name); content.Should().Contain(objectList[1].Name); - content.Should().Contain(objectList[0].ObjGuid.ToString()); - content.Should().Contain(objectList[1].ObjGuid.ToString()); - content.Should().Contain(string.Join(",", objectList[0].Properties)); + content.Should().Contain(objectList[0].GuidProp.ToString()); + content.Should().Contain(objectList[1].GuidProp.ToString()); + content.Should().Contain(objectList[0].Properties!.ToString()!.Replace("`", "")); content.Should().Contain(Environment.NewLine); } @@ -467,7 +517,42 @@ public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithNonNullable public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithNullableList() { IEntityReportGenerator generator = GetReportGenerator(); - List objectList = GetGenericListEntities(); + List objectList = GetNullableListEntities(); + + string? content = null; + + Action execute = () => + { + content = generator.GenerateCsvContent(objectList); + }; + + Exception ex = Record.Exception(execute); + + ex.Should().BeNull(); + content.Should().NotBeNull(); + content.Should().Contain(CsvDelimiter); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Id)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.IsDeleted)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Name)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.GuidProp)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Properties)); + content.Should().Contain(objectList[0].Id.ToString()); + content.Should().Contain(objectList[1].Id.ToString()); + content.Should().Contain(objectList[0].IsDeleted.ToString()); + content.Should().Contain(objectList[1].IsDeleted.ToString()); + content.Should().Contain(objectList[0].Name); + content.Should().Contain(objectList[1].Name); + content.Should().Contain(objectList[0].GuidProp.ToString()); + content.Should().Contain(objectList[1].GuidProp.ToString()); + content.Should().Contain(objectList[0].Properties!.ToString()!.Replace("`", "")); + content.Should().Contain(Environment.NewLine); + } + + [Fact] + public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithEnumerable() + { + IEntityReportGenerator generator = GetReportGenerator(); + List objectList = GetEnumerableEntities(); string? content = null; @@ -481,20 +566,101 @@ public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithNullableLis ex.Should().BeNull(); content.Should().NotBeNull(); content.Should().Contain(CsvDelimiter); - content.Should().Contain(nameof(ObjectWithGenericList.Id)); - content.Should().Contain(nameof(ObjectWithGenericList.IsDeleted)); - content.Should().Contain(nameof(ObjectWithGenericList.Name)); - content.Should().Contain(nameof(ObjectWithGenericList.ObjGuid)); - content.Should().Contain(nameof(ObjectWithGenericList.Properties)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Id)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.IsDeleted)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Name)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.GuidProp)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Properties)); content.Should().Contain(objectList[0].Id.ToString()); content.Should().Contain(objectList[1].Id.ToString()); content.Should().Contain(objectList[0].IsDeleted.ToString()); content.Should().Contain(objectList[1].IsDeleted.ToString()); content.Should().Contain(objectList[0].Name); content.Should().Contain(objectList[1].Name); - content.Should().Contain(objectList[0].ObjGuid.ToString()); - content.Should().Contain(objectList[1].ObjGuid.ToString()); + content.Should().Contain(objectList[0].GuidProp.ToString()); + content.Should().Contain(objectList[1].GuidProp.ToString()); content.Should().Contain(objectList[0].Properties!.ToString()!.Replace("`", "")); content.Should().Contain(Environment.NewLine); } + + [Fact] + public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithNullableEnumerable() + { + IEntityReportGenerator generator = GetReportGenerator(); + List objectList = GetNullableEnumerableEntities(); + + string? content = null; + + Action execute = () => + { + content = generator.GenerateCsvContent(objectList); + }; + + Exception ex = Record.Exception(execute); + + ex.Should().BeNull(); + content.Should().NotBeNull(); + content.Should().Contain(CsvDelimiter); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Id)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.IsDeleted)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Name)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.GuidProp)); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Properties)); + content.Should().Contain(objectList[0].Id.ToString()); + content.Should().Contain(objectList[1].Id.ToString()); + content.Should().Contain(objectList[0].IsDeleted.ToString()); + content.Should().Contain(objectList[1].IsDeleted.ToString()); + content.Should().Contain(objectList[0].Name); + content.Should().Contain(objectList[1].Name); + content.Should().Contain(objectList[0].GuidProp.ToString()); + content.Should().Contain(objectList[1].GuidProp.ToString()); + content.Should().Contain(objectList[0].Properties!.ToString()!.Replace("`", "")); + content.Should().Contain(Environment.NewLine); + } + + [Fact] + public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithDetailedEnumerable() + { + IEntityReportGenerator generator = GetDetailedReportGenerator(); + List objectList = GetEnumerableEntities(); + + string? content = null; + + Action execute = () => + { + content = generator.GenerateCsvContent(objectList); + }; + + Exception ex = Record.Exception(execute); + + ex.Should().BeNull(); + content.Should().NotBeNull(); + content.Should().Contain(CsvDelimiter); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Properties)); + content.Should().Contain(string.Join(",", objectList[0].Properties!)); + content.Should().Contain(Environment.NewLine); + } + + [Fact] + public void EntityReportGenerator_GenerateCsvContentSuccessfully_WithListAndDetailedEnumerable() + { + IEntityReportGenerator generator = GetDetailedReportGenerator(); + List objectList = GetListEntities(); + + string? content = null; + + Action execute = () => + { + content = generator.GenerateCsvContent(objectList); + }; + + Exception ex = Record.Exception(execute); + + ex.Should().BeNull(); + content.Should().NotBeNull(); + content.Should().Contain(CsvDelimiter); + content.Should().Contain(nameof(ObjectWithNullableEnumerable.Properties)); + content.Should().Contain(string.Join(",", objectList[0].Properties!)); + content.Should().Contain(Environment.NewLine); + } } diff --git a/test/ObjectWithEnumerable.cs b/test/ObjectWithEnumerable.cs new file mode 100644 index 0000000..fb39217 --- /dev/null +++ b/test/ObjectWithEnumerable.cs @@ -0,0 +1,10 @@ +namespace Delobytes.NetCore.EntityReportGeneration.Tests; + +public class ObjectWithEnumerable +{ + public int? Id { get; set; } + public bool? IsDeleted { get; set; } + public string? Name { get; set; } + public Guid? GuidProp { get; set; } + public IEnumerable Properties { get; set; } = Array.Empty(); +} diff --git a/test/ObjectWithTypedList.cs b/test/ObjectWithList.cs similarity index 77% rename from test/ObjectWithTypedList.cs rename to test/ObjectWithList.cs index 1be94e7..3e97c4c 100644 --- a/test/ObjectWithTypedList.cs +++ b/test/ObjectWithList.cs @@ -1,10 +1,10 @@ namespace Delobytes.NetCore.EntityReportGeneration.Tests; -public class ObjectWithTypedList +public class ObjectWithList { public int? Id { get; set; } public bool? IsDeleted { get; set; } public string? Name { get; set; } - public Guid? ObjGuid { get; set; } + public Guid? GuidProp { get; set; } public List Properties { get; set; } = new List(); } diff --git a/test/ObjectWithGenericList.cs b/test/ObjectWithNullableEnumerable.cs similarity index 73% rename from test/ObjectWithGenericList.cs rename to test/ObjectWithNullableEnumerable.cs index 6a5eb65..a32f5d4 100644 --- a/test/ObjectWithGenericList.cs +++ b/test/ObjectWithNullableEnumerable.cs @@ -1,10 +1,10 @@ namespace Delobytes.NetCore.EntityReportGeneration.Tests; -public class ObjectWithGenericList +public class ObjectWithNullableEnumerable { public int? Id { get; set; } public bool? IsDeleted { get; set; } public string? Name { get; set; } - public Guid? ObjGuid { get; set; } + public Guid? GuidProp { get; set; } public IEnumerable? Properties { get; set; } } diff --git a/test/ObjectWithNullableList.cs b/test/ObjectWithNullableList.cs new file mode 100644 index 0000000..bc1b1d6 --- /dev/null +++ b/test/ObjectWithNullableList.cs @@ -0,0 +1,10 @@ +namespace Delobytes.NetCore.EntityReportGeneration.Tests; + +public class ObjectWithNullableList +{ + public int? Id { get; set; } + public bool? IsDeleted { get; set; } + public string? Name { get; set; } + public Guid? GuidProp { get; set; } + public List? Properties { get; set; } +}