From 871837ce6337a4de8ade486e2ed1265fd6cf7356 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Tue, 26 Dec 2023 01:25:09 +0500 Subject: [PATCH 01/11] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D1=82=D1=80=D0=B5=D0=B1=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/PrintingConfig.cs | 128 +++++++++++++++++- .../Tests/ObjectPrinterAcceptanceTests.cs | 27 ---- .../ObjectPrinterAcceptanceTests.cs | 104 ++++++++++++++ .../ObjectPrintingTests.csproj | 22 +++ .../Tests => ObjectPrintingTests}/Person.cs | 1 + ObjectPrintingTests/SubPerson.cs | 11 ++ fluent-api.sln | 21 ++- 7 files changed, 275 insertions(+), 39 deletions(-) delete mode 100644 ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs create mode 100644 ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs create mode 100644 ObjectPrintingTests/ObjectPrintingTests.csproj rename {ObjectPrinting/Tests => ObjectPrintingTests}/Person.cs (83%) create mode 100644 ObjectPrintingTests/SubPerson.cs diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index a9e08211..499e8038 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -1,40 +1,156 @@ using System; +using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Linq.Expressions; +using System.Reflection; using System.Text; namespace ObjectPrinting { public class PrintingConfig { + private readonly List exludedProperties = new List(); + private readonly List excludedTypes = new List(); + private readonly Dictionary complexObjectLinks = new Dictionary(); + private int maxRecursion = 2; + + private readonly Type[] finalTypes = + { + typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) + }; + + private readonly Dictionary> typeSerializesInfos = + new Dictionary>(); + + private readonly Dictionary> membersSerializesInfos = + new Dictionary>(); + + public string PrintToString(TOwner obj) { return PrintToString(obj, 0); } + public PrintingConfig WithMaxRecursion(int maxRecursion) + { + if (maxRecursion < 1) + throw new ArgumentException(); + this.maxRecursion = maxRecursion; + + return this; + } + + public PrintingConfig Exclude(Expression> exclude) + { + var memberInfo = GetMemberInfo(exclude); + + exludedProperties.Add(memberInfo); + + return this; + } + + public PrintingConfig SetCulture(CultureInfo culture) + where T : IFormattable + { + return SerializeWith( + p => p.ToString(null, culture)); + } + + public PrintingConfig SerializeWith(Func serialize) + { + Func func = p => serialize((T)p); + + typeSerializesInfos[typeof(T)] = func; + + return this; + } + + public PrintingConfig SerializeWith( + Expression> property, + Func serialize) + { + var memberInfo = GetMemberInfo(property); + Func func = p => serialize((T)p); + + membersSerializesInfos[memberInfo] = func; + + return this; + } + + private MemberInfo GetMemberInfo(Expression> expression) + { + var memberExpression = expression.Body is UnaryExpression unaryExpression + ? (MemberExpression)unaryExpression.Operand + : (MemberExpression)expression.Body; + + return memberExpression.Member; + } + + public PrintingConfig Trim(Expression> property, int length) + { + Func func = value => value.Length <= length + ? value + : value.Substring(0, length); + + return SerializeWith(property, func); + } + + public PrintingConfig Exclude() + { + excludedTypes.Add(typeof(T)); + + return this; + } + private string PrintToString(object obj, int nestingLevel) { - //TODO apply configurations if (obj == null) return "null" + Environment.NewLine; - var finalTypes = new[] - { - typeof(int), typeof(double), typeof(float), typeof(string), - typeof(DateTime), typeof(TimeSpan) - }; if (finalTypes.Contains(obj.GetType())) return obj + Environment.NewLine; + if (!complexObjectLinks.ContainsKey(obj)) + complexObjectLinks[obj] = 0; + complexObjectLinks[obj]++; + + if (complexObjectLinks[obj] == maxRecursion) + return "Maximum recursion has been reached" + Environment.NewLine; + var identation = new string('\t', nestingLevel + 1); + var sb = new StringBuilder(); var type = obj.GetType(); sb.AppendLine(type.Name); + foreach (var propertyInfo in type.GetProperties()) { + if (exludedProperties.Any(m => m.Name == propertyInfo.Name) || + excludedTypes.Contains(propertyInfo.PropertyType)) + continue; + + if (membersSerializesInfos.TryGetValue(propertyInfo, out var serializeMember)) + { + var t = serializeMember(propertyInfo.GetValue(obj)); + + sb.Append(identation + propertyInfo.Name + " = " + t + Environment.NewLine); + continue; + } + + if (typeSerializesInfos.TryGetValue(propertyInfo.PropertyType, out var serializeType)) + { + var t = serializeType(propertyInfo.GetValue(obj)); + + sb.Append(identation + propertyInfo.Name + " = " + t + Environment.NewLine); + continue; + } + sb.Append(identation + propertyInfo.Name + " = " + PrintToString(propertyInfo.GetValue(obj), nestingLevel + 1)); } + return sb.ToString(); } } diff --git a/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs b/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs deleted file mode 100644 index 4c8b2445..00000000 --- a/ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using NUnit.Framework; - -namespace ObjectPrinting.Tests -{ - [TestFixture] - public class ObjectPrinterAcceptanceTests - { - [Test] - public void Demo() - { - var person = new Person { Name = "Alex", Age = 19 }; - - var printer = ObjectPrinter.For(); - //1. Исключить из сериализации свойства определенного типа - //2. Указать альтернативный способ сериализации для определенного типа - //3. Для числовых типов указать культуру - //4. Настроить сериализацию конкретного свойства - //5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) - //6. Исключить из сериализации конкретного свойства - - string s1 = printer.PrintToString(person); - - //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию - //8. ...с конфигурированием - } - } -} \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs new file mode 100644 index 00000000..d54156bb --- /dev/null +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -0,0 +1,104 @@ +using System.Globalization; +using FluentAssertions; +using NUnit.Framework; +using ObjectPrinting; +using ObjectPrinting.Tests; + +namespace ObjectPrintingTests +{ + [TestFixture] + public class ObjectPrinterAcceptanceTests + { + [Test] + public void WhenExcludeType_ShouldReturnWithoutThisType() + { + var person = new Person { Name = "Alex", Age = 19 }; + + var printer = ObjectPrinter.For(); + printer.Exclude(p => p.Age) + .Exclude(); + + //1. Исключить из сериализации свойства определенного типа + //2. Указать альтернативный способ сериализации для определенного типа + //3. Для числовых типов указать культуру + //4. Настроить сериализацию конкретного свойства + //5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) + //6. Исключить из сериализации конкретного свойства + + var s1 = printer.PrintToString(person); + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n"); + + //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию + //8. ...с конфигурированием + } + + [Test] + public void TrimString_ShouldReturnSubstring() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180 }; + var printer = ObjectPrinter.For(); + + var s1 = printer.Trim(p => p.Name, 1).PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n"); + } + + [Test] + public void ShouldSerializeMember_WithGivenFunc() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180 }; + var printer = ObjectPrinter.For(); + + var s1 = printer.SerializeWith(person => person.Age, age => (age + 1000).ToString()).PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n"); + } + + [Test] + public void SetCulture_ShouldAddedCultureInfo() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180.5 }; + var printer = ObjectPrinter.For(); + + var s1 = printer.SetCulture(CultureInfo.InvariantCulture).PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n"); + } + + [Test] + public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180, SubPerson = new SubPerson() }; + person.SubPerson.Age = 15; + person.SubPerson.Person = person; + var printer = ObjectPrinter.For(); + + var s1 = printer.PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n"); + } + + [Test] + public void WhenPassNull_ShouldReturnNullString() + { + var printer = ObjectPrinter.For(); + var s1 = printer.PrintToString(null); + + s1.Should().Be("null\r\n"); + } + + [Test] + public void WhenPassFinalType_ShouldReturnStringRepresentationOfThisType() + { + var printer = ObjectPrinter.For(); + var s1 = printer.PrintToString(1); + + s1.Should().Be("1\r\n"); + } + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrintingTests.csproj b/ObjectPrintingTests/ObjectPrintingTests.csproj new file mode 100644 index 00000000..8d6309d7 --- /dev/null +++ b/ObjectPrintingTests/ObjectPrintingTests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + + + diff --git a/ObjectPrinting/Tests/Person.cs b/ObjectPrintingTests/Person.cs similarity index 83% rename from ObjectPrinting/Tests/Person.cs rename to ObjectPrintingTests/Person.cs index f9555955..62309c2f 100644 --- a/ObjectPrinting/Tests/Person.cs +++ b/ObjectPrintingTests/Person.cs @@ -8,5 +8,6 @@ public class Person public string Name { get; set; } public double Height { get; set; } public int Age { get; set; } + public SubPerson SubPerson { get; set; } } } \ No newline at end of file diff --git a/ObjectPrintingTests/SubPerson.cs b/ObjectPrintingTests/SubPerson.cs new file mode 100644 index 00000000..e5adb91a --- /dev/null +++ b/ObjectPrintingTests/SubPerson.cs @@ -0,0 +1,11 @@ +using System; + +namespace ObjectPrinting.Tests +{ + public class SubPerson + { + public Person Person { get; set; } + + public int Age { get; set; } + } +} diff --git a/fluent-api.sln b/fluent-api.sln index 69c8db9e..c6377338 100644 --- a/fluent-api.sln +++ b/fluent-api.sln @@ -1,17 +1,19 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectPrinting", "ObjectPrinting\ObjectPrinting.csproj", "{07B8C9B7-8289-46CB-9875-048A57758EEE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObjectPrinting", "ObjectPrinting\ObjectPrinting.csproj", "{07B8C9B7-8289-46CB-9875-048A57758EEE}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{6D308E4A-CEC7-4536-9B87-81CD337A87AD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentMapping", "Samples\FluentMapper\FluentMapping.csproj", "{FEEA5AFE-459A-4D13-81D0-252E1A2E6F4E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentMapping", "Samples\FluentMapper\FluentMapping.csproj", "{FEEA5AFE-459A-4D13-81D0-252E1A2E6F4E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentMapping.Tests", "Samples\FluentMapper.Tests\FluentMapping.Tests.csproj", "{8A7BB3EA-3E6A-4D04-A801-D5CD1620DA0D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentMapping.Tests", "Samples\FluentMapper.Tests\FluentMapping.Tests.csproj", "{8A7BB3EA-3E6A-4D04-A801-D5CD1620DA0D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spectacle", "Samples\Spectacle\Spectacle.csproj", "{EFA9335C-411B-4597-B0B6-5438D1AE04C3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectacle", "Samples\Spectacle\Spectacle.csproj", "{EFA9335C-411B-4597-B0B6-5438D1AE04C3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectPrintingTests", "ObjectPrintingTests\ObjectPrintingTests.csproj", "{D4C55796-285B-43A6-B0C8-CCAFD9311A7E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -35,6 +37,10 @@ Global {EFA9335C-411B-4597-B0B6-5438D1AE04C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {EFA9335C-411B-4597-B0B6-5438D1AE04C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {EFA9335C-411B-4597-B0B6-5438D1AE04C3}.Release|Any CPU.Build.0 = Release|Any CPU + {D4C55796-285B-43A6-B0C8-CCAFD9311A7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4C55796-285B-43A6-B0C8-CCAFD9311A7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4C55796-285B-43A6-B0C8-CCAFD9311A7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4C55796-285B-43A6-B0C8-CCAFD9311A7E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -44,4 +50,7 @@ Global {8A7BB3EA-3E6A-4D04-A801-D5CD1620DA0D} = {6D308E4A-CEC7-4536-9B87-81CD337A87AD} {EFA9335C-411B-4597-B0B6-5438D1AE04C3} = {6D308E4A-CEC7-4536-9B87-81CD337A87AD} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A5E3DAB2-51C4-45F2-8C29-BD9CE58F6479} + EndGlobalSection EndGlobal From 767afb5b38a72fa66b8e234f244bcbdce28cba9a Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Tue, 26 Dec 2023 06:13:38 +0500 Subject: [PATCH 02/11] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/PrintingConfig.cs | 92 +++++++++++-------- .../ObjectPrinterAcceptanceTests.cs | 51 +++++++--- ObjectPrintingTests/Person.cs | 3 + 3 files changed, 95 insertions(+), 51 deletions(-) diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index 499e8038..59bc3305 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -10,12 +10,12 @@ namespace ObjectPrinting { public class PrintingConfig { - private readonly List exludedProperties = new List(); - private readonly List excludedTypes = new List(); + private readonly HashSet excludedProperties = new HashSet(); + private readonly HashSet excludedTypes = new HashSet(); private readonly Dictionary complexObjectLinks = new Dictionary(); private int maxRecursion = 2; - private readonly Type[] finalTypes = + private readonly HashSet finalTypes = new HashSet() { typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) }; @@ -41,44 +41,44 @@ public PrintingConfig WithMaxRecursion(int maxRecursion) return this; } - public PrintingConfig Exclude(Expression> exclude) + public PrintingConfig Exclude(Expression> exclude) { var memberInfo = GetMemberInfo(exclude); - exludedProperties.Add(memberInfo); + excludedProperties.Add(memberInfo); return this; } - public PrintingConfig SetCulture(CultureInfo culture) - where T : IFormattable + public PrintingConfig SetCulture(CultureInfo culture) + where TPropType : IFormattable { - return SerializeWith( + return SerializeWith( p => p.ToString(null, culture)); } - public PrintingConfig SerializeWith(Func serialize) + public PrintingConfig SerializeWith(Func serialize) { - Func func = p => serialize((T)p); + Func func = p => serialize((TPropType)p); - typeSerializesInfos[typeof(T)] = func; + typeSerializesInfos[typeof(TPropType)] = func; return this; } - public PrintingConfig SerializeWith( - Expression> property, - Func serialize) + public PrintingConfig SerializeWith( + Expression> property, + Func serialize) { var memberInfo = GetMemberInfo(property); - Func func = p => serialize((T)p); + Func func = p => serialize((TPropType)p); membersSerializesInfos[memberInfo] = func; return this; } - private MemberInfo GetMemberInfo(Expression> expression) + private static MemberInfo GetMemberInfo(Expression> expression) { var memberExpression = expression.Body is UnaryExpression unaryExpression ? (MemberExpression)unaryExpression.Operand @@ -91,14 +91,23 @@ public PrintingConfig Trim(Expression> property, in { Func func = value => value.Length <= length ? value - : value.Substring(0, length); + : value[..length]; return SerializeWith(property, func); } - public PrintingConfig Exclude() + public PrintingConfig Trim(int length) // { - excludedTypes.Add(typeof(T)); + Func func = value => value.Length <= length + ? value + : value[..length]; + + return SerializeWith(func); + } + + public PrintingConfig Exclude() + { + excludedTypes.Add(typeof(TPropType)); return this; } @@ -106,52 +115,59 @@ public PrintingConfig Exclude() private string PrintToString(object obj, int nestingLevel) { if (obj == null) - return "null" + Environment.NewLine; + return $"null{Environment.NewLine}"; if (finalTypes.Contains(obj.GetType())) return obj + Environment.NewLine; - if (!complexObjectLinks.ContainsKey(obj)) - complexObjectLinks[obj] = 0; - complexObjectLinks[obj]++; - - if (complexObjectLinks[obj] == maxRecursion) - return "Maximum recursion has been reached" + Environment.NewLine; - - var identation = new string('\t', nestingLevel + 1); + if (MaxRecursionHasBeenReached(obj)) + return $"Maximum recursion has been reached{Environment.NewLine}"; - var sb = new StringBuilder(); + var indentation = string.Intern(new string('\t', nestingLevel + 1)); + var type = obj.GetType(); - sb.AppendLine(type.Name); + var sb = new StringBuilder().AppendLine(type.Name); foreach (var propertyInfo in type.GetProperties()) { - if (exludedProperties.Any(m => m.Name == propertyInfo.Name) || + if (excludedProperties.Any(memberInfo => memberInfo.Name == propertyInfo.Name) || excludedTypes.Contains(propertyInfo.PropertyType)) continue; if (membersSerializesInfos.TryGetValue(propertyInfo, out var serializeMember)) { - var t = serializeMember(propertyInfo.GetValue(obj)); - - sb.Append(identation + propertyInfo.Name + " = " + t + Environment.NewLine); + sb.Append(GetSerializedString(obj, propertyInfo, indentation, serializeMember)); continue; } if (typeSerializesInfos.TryGetValue(propertyInfo.PropertyType, out var serializeType)) { - var t = serializeType(propertyInfo.GetValue(obj)); - - sb.Append(identation + propertyInfo.Name + " = " + t + Environment.NewLine); + sb.Append(GetSerializedString(obj, propertyInfo, indentation, serializeType)); continue; } - sb.Append(identation + propertyInfo.Name + " = " + + sb.Append($"{indentation}{propertyInfo.Name} = " + PrintToString(propertyInfo.GetValue(obj), nestingLevel + 1)); } return sb.ToString(); } + + private bool MaxRecursionHasBeenReached(object obj) + { + complexObjectLinks.TryAdd(obj, 0); + complexObjectLinks[obj]++; + + return complexObjectLinks[obj] == maxRecursion; + } + + private string GetSerializedString(object obj, PropertyInfo propertyInfo, string indentation, Func serializeMember) + { + var serializedString = serializeMember(propertyInfo.GetValue(obj)); + + return $"{indentation}{propertyInfo.Name} = {serializedString}{Environment.NewLine}"; + } + } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index d54156bb..977f7963 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -10,7 +10,42 @@ namespace ObjectPrintingTests public class ObjectPrinterAcceptanceTests { [Test] - public void WhenExcludeType_ShouldReturnWithoutThisType() + public void Demo() + { + var person = new Person { Name = "Alex", Age = 19, Height = 180.5, SubPerson = new SubPerson() }; + person.SubPerson.Age = 15; + person.SubPerson.Person = person; + + var printer = ObjectPrinter.For(); + + //Исключение из сериализации свойства/ поля определенного типа + //Альтернативный способ сериализации для определенного типа + //Для всех типов, имеющих культуру, есть возможность ее указать + //printer.Exclude() + // .SerializeWith(p => p.Age, age => (age + 1000).ToString()) + // .SetCulture(CultureInfo.InvariantCulture) + // .SerializeWith((p) => p.ToUpper()) + // .Trim(p => p.Name, 1) + // .Exclude(p => p.Name) + // . + + + //Корректная обработка циклических ссылок между объектами(не должны приводить к StackOverflowException) + } + + [Test] + public void DoSomething_WhenSomething() + { + var person = new Person { Name = "Alex", Age = 19 }; + var printer = ObjectPrinter.For(); + + printer.SerializeWith(p => p.Name, n => $"{n} :))") + .Trim(p => p.Name, 1) + .Trim(1); + } + + [Test] + public void ShouldExcludeMember_WhenItsTypeSpecified() { var person = new Person { Name = "Alex", Age = 19 }; @@ -18,23 +53,13 @@ public void WhenExcludeType_ShouldReturnWithoutThisType() printer.Exclude(p => p.Age) .Exclude(); - //1. Исключить из сериализации свойства определенного типа - //2. Указать альтернативный способ сериализации для определенного типа - //3. Для числовых типов указать культуру - //4. Настроить сериализацию конкретного свойства - //5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) - //6. Исключить из сериализации конкретного свойства - var s1 = printer.PrintToString(person); s1.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n"); - - //7. Синтаксический сахар в виде метода расширения, сериализующего по-умолчанию - //8. ...с конфигурированием } [Test] - public void TrimString_ShouldReturnSubstring() + public void ShouldUseTrimming_WhenItsSpecifiedForType() { var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); @@ -51,7 +76,7 @@ public void ShouldSerializeMember_WithGivenFunc() var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); - var s1 = printer.SerializeWith(person => person.Age, age => (age + 1000).ToString()).PrintToString(person); + var s1 = printer.SerializeWith(p => p.Age, age => (age + 1000).ToString()).PrintToString(person); s1.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n"); diff --git a/ObjectPrintingTests/Person.cs b/ObjectPrintingTests/Person.cs index 62309c2f..038658df 100644 --- a/ObjectPrintingTests/Person.cs +++ b/ObjectPrintingTests/Person.cs @@ -9,5 +9,8 @@ public class Person public double Height { get; set; } public int Age { get; set; } public SubPerson SubPerson { get; set; } + + public string PublicField; + private string privateField; } } \ No newline at end of file From 6432b5895a5038366d8941f873986ab00c81b079 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Tue, 26 Dec 2023 14:58:10 +0500 Subject: [PATCH 03/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BF=D1=83=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=87=D0=BD=D1=8B=D1=85=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/DataMember.cs | 30 ++++++ ObjectPrinting/PrintingConfig.cs | 91 +++++++++++++------ .../ObjectPrinterAcceptanceTests.cs | 46 +--------- ObjectPrintingTests/Person.cs | 2 +- ObjectPrintingTests/SubPerson.cs | 4 +- 5 files changed, 102 insertions(+), 71 deletions(-) create mode 100644 ObjectPrinting/DataMember.cs diff --git a/ObjectPrinting/DataMember.cs b/ObjectPrinting/DataMember.cs new file mode 100644 index 00000000..7f10d167 --- /dev/null +++ b/ObjectPrinting/DataMember.cs @@ -0,0 +1,30 @@ +using System; +using System.Reflection; + +namespace ObjectPrinting +{ + public class DataMember + { + public string Name { get; set; } + public Type Type { get; set; } + + public Func GetValue; + public MemberInfo MemberInfo { get; set; } + + public DataMember(FieldInfo fieldInfo) + { + Name = fieldInfo.Name; + GetValue = fieldInfo.GetValue; + Type = fieldInfo.FieldType; + MemberInfo = fieldInfo; + } + + public DataMember(PropertyInfo property) + { + Name = property.Name; + GetValue = property.GetValue; + Type = property.PropertyType; + MemberInfo = property; + } + } +} diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index 59bc3305..c92ba9d3 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -12,6 +12,9 @@ public class PrintingConfig { private readonly HashSet excludedProperties = new HashSet(); private readonly HashSet excludedTypes = new HashSet(); + + private readonly HashSet excludedFields = new HashSet(); + private readonly Dictionary complexObjectLinks = new Dictionary(); private int maxRecursion = 2; @@ -61,7 +64,8 @@ public PrintingConfig SerializeWith(Func s { Func func = p => serialize((TPropType)p); - typeSerializesInfos[typeof(TPropType)] = func; + if (!typeSerializesInfos.ContainsKey(typeof(TPropType))) + typeSerializesInfos[typeof(TPropType)] = func; return this; } @@ -96,7 +100,7 @@ public PrintingConfig Trim(Expression> property, in return SerializeWith(property, func); } - public PrintingConfig Trim(int length) // + public PrintingConfig Trim(int length) { Func func = value => value.Length <= length ? value @@ -128,32 +132,62 @@ private string PrintToString(object obj, int nestingLevel) var type = obj.GetType(); var sb = new StringBuilder().AppendLine(type.Name); + + HandleMembers(type, sb, indentation, obj, nestingLevel); + + + + + return sb.ToString(); + } + + private void HandleMembers(Type type, StringBuilder sb, string indentation, object obj, int nestingLevel) + { foreach (var propertyInfo in type.GetProperties()) { - if (excludedProperties.Any(memberInfo => memberInfo.Name == propertyInfo.Name) || - excludedTypes.Contains(propertyInfo.PropertyType)) - continue; - - if (membersSerializesInfos.TryGetValue(propertyInfo, out var serializeMember)) - { - sb.Append(GetSerializedString(obj, propertyInfo, indentation, serializeMember)); - continue; - } - - if (typeSerializesInfos.TryGetValue(propertyInfo.PropertyType, out var serializeType)) - { - sb.Append(GetSerializedString(obj, propertyInfo, indentation, serializeType)); - continue; - } - - sb.Append($"{indentation}{propertyInfo.Name} = " + - PrintToString(propertyInfo.GetValue(obj), - nestingLevel + 1)); + DataMember data = new DataMember(propertyInfo); + + HandleMember(sb, data, obj, indentation, nestingLevel); } - return sb.ToString(); + foreach (var fieldInfo in type.GetFields()) + { + DataMember data = new DataMember(fieldInfo); + + HandleMember(sb, data, obj, indentation, nestingLevel); + } } + private void HandleMember(StringBuilder sb, DataMember member, object obj, string indentation, int nestingLevel) + { + if (excludedProperties.Any(memberInfo => memberInfo.Name == member.Name) || + excludedTypes.Contains(member.Type)) + return; + + if (membersSerializesInfos.TryGetValue(member.MemberInfo, out var serializeMember)) + { + sb.Append(GetSerializedString(obj, member, indentation, serializeMember)); + return; + } + + if (typeSerializesInfos.TryGetValue(member.Type, out var serializeType)) + { + sb.Append(GetSerializedString(obj, member, indentation, serializeType)); + return; + } + + sb.Append( + GetSerializedString( + obj, + member, + indentation, + (value) => PrintToString( + value, + nestingLevel + 1), + false)); + } + + private bool MaxRecursionHasBeenReached(object obj) { complexObjectLinks.TryAdd(obj, 0); @@ -162,12 +196,17 @@ private bool MaxRecursionHasBeenReached(object obj) return complexObjectLinks[obj] == maxRecursion; } - private string GetSerializedString(object obj, PropertyInfo propertyInfo, string indentation, Func serializeMember) + private string GetSerializedString( + object obj, + DataMember memberInfo, + string indentation, + Func serializeMember, + bool needNewLine = true) { - var serializedString = serializeMember(propertyInfo.GetValue(obj)); + var serializedString = serializeMember(memberInfo.GetValue(obj)); + var stringEnd = needNewLine ? Environment.NewLine : string.Empty; - return $"{indentation}{propertyInfo.Name} = {serializedString}{Environment.NewLine}"; + return $"{indentation}{memberInfo.Name} = {serializedString}{stringEnd}"; } - } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index 977f7963..0ff99dda 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -2,48 +2,12 @@ using FluentAssertions; using NUnit.Framework; using ObjectPrinting; -using ObjectPrinting.Tests; namespace ObjectPrintingTests { [TestFixture] public class ObjectPrinterAcceptanceTests { - [Test] - public void Demo() - { - var person = new Person { Name = "Alex", Age = 19, Height = 180.5, SubPerson = new SubPerson() }; - person.SubPerson.Age = 15; - person.SubPerson.Person = person; - - var printer = ObjectPrinter.For(); - - //Исключение из сериализации свойства/ поля определенного типа - //Альтернативный способ сериализации для определенного типа - //Для всех типов, имеющих культуру, есть возможность ее указать - //printer.Exclude() - // .SerializeWith(p => p.Age, age => (age + 1000).ToString()) - // .SetCulture(CultureInfo.InvariantCulture) - // .SerializeWith((p) => p.ToUpper()) - // .Trim(p => p.Name, 1) - // .Exclude(p => p.Name) - // . - - - //Корректная обработка циклических ссылок между объектами(не должны приводить к StackOverflowException) - } - - [Test] - public void DoSomething_WhenSomething() - { - var person = new Person { Name = "Alex", Age = 19 }; - var printer = ObjectPrinter.For(); - - printer.SerializeWith(p => p.Name, n => $"{n} :))") - .Trim(p => p.Name, 1) - .Trim(1); - } - [Test] public void ShouldExcludeMember_WhenItsTypeSpecified() { @@ -55,7 +19,7 @@ public void ShouldExcludeMember_WhenItsTypeSpecified() var s1 = printer.PrintToString(person); s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n"); + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } [Test] @@ -67,7 +31,7 @@ public void ShouldUseTrimming_WhenItsSpecifiedForType() var s1 = printer.Trim(p => p.Name, 1).PrintToString(person); s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n"); + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } [Test] @@ -79,7 +43,7 @@ public void ShouldSerializeMember_WithGivenFunc() var s1 = printer.SerializeWith(p => p.Age, age => (age + 1000).ToString()).PrintToString(person); s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n"); + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } [Test] @@ -91,7 +55,7 @@ public void SetCulture_ShouldAddedCultureInfo() var s1 = printer.SetCulture(CultureInfo.InvariantCulture).PrintToString(person); s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n"); + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } [Test] @@ -105,7 +69,7 @@ public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() var s1 = printer.PrintToString(person); s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n"); + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); } [Test] diff --git a/ObjectPrintingTests/Person.cs b/ObjectPrintingTests/Person.cs index 038658df..6baceb25 100644 --- a/ObjectPrintingTests/Person.cs +++ b/ObjectPrintingTests/Person.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectPrinting.Tests +namespace ObjectPrintingTests { public class Person { diff --git a/ObjectPrintingTests/SubPerson.cs b/ObjectPrintingTests/SubPerson.cs index e5adb91a..93519781 100644 --- a/ObjectPrintingTests/SubPerson.cs +++ b/ObjectPrintingTests/SubPerson.cs @@ -1,6 +1,4 @@ -using System; - -namespace ObjectPrinting.Tests +namespace ObjectPrintingTests { public class SubPerson { From 0aae76debf46f585ff52620a0690ca021041e161 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Tue, 26 Dec 2023 17:51:07 +0500 Subject: [PATCH 04/11] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/ObjectPrinter.cs | 2 +- ObjectPrinting/PrinterExtensions.cs | 10 ++ ObjectPrinting/PrintingConfig.cs | 150 ++++-------------- ObjectPrinting/Serializer.cs | 123 ++++++++++++++ .../ObjectPrinterAcceptanceTests.cs | 50 +++++- ObjectPrintingTests/PrinterExtensionsTests.cs | 21 +++ 6 files changed, 237 insertions(+), 119 deletions(-) create mode 100644 ObjectPrinting/PrinterExtensions.cs create mode 100644 ObjectPrinting/Serializer.cs create mode 100644 ObjectPrintingTests/PrinterExtensionsTests.cs diff --git a/ObjectPrinting/ObjectPrinter.cs b/ObjectPrinting/ObjectPrinter.cs index 3c7867c3..9a19ba1d 100644 --- a/ObjectPrinting/ObjectPrinter.cs +++ b/ObjectPrinting/ObjectPrinter.cs @@ -1,6 +1,6 @@ namespace ObjectPrinting { - public class ObjectPrinter + public static class ObjectPrinter { public static PrintingConfig For() { diff --git a/ObjectPrinting/PrinterExtensions.cs b/ObjectPrinting/PrinterExtensions.cs new file mode 100644 index 00000000..f22948ca --- /dev/null +++ b/ObjectPrinting/PrinterExtensions.cs @@ -0,0 +1,10 @@ +namespace ObjectPrinting +{ + public static class PrinterExtensions + { + public static PrintingConfig CreatePrinter(this T instance) + { + return ObjectPrinter.For(); + } + } +} \ No newline at end of file diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index c92ba9d3..1ea33325 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -4,31 +4,21 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Text; namespace ObjectPrinting { public class PrintingConfig { - private readonly HashSet excludedProperties = new HashSet(); + private readonly HashSet excludedMembers = new HashSet(); private readonly HashSet excludedTypes = new HashSet(); - private readonly HashSet excludedFields = new HashSet(); - - private readonly Dictionary complexObjectLinks = new Dictionary(); - private int maxRecursion = 2; - - private readonly HashSet finalTypes = new HashSet() - { - typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) - }; + private readonly Dictionary> membersSerializesInfos = + new Dictionary>(); private readonly Dictionary> typeSerializesInfos = new Dictionary>(); - private readonly Dictionary> membersSerializesInfos = - new Dictionary>(); - + private int maxRecursion = 2; public string PrintToString(TOwner obj) { @@ -48,29 +38,28 @@ public PrintingConfig Exclude(Expression SetCulture(CultureInfo culture) + public PrintingConfig Using(CultureInfo culture) where TPropType : IFormattable { - return SerializeWith( + return Using( p => p.ToString(null, culture)); } - public PrintingConfig SerializeWith(Func serialize) + public PrintingConfig Using(Func serialize) { Func func = p => serialize((TPropType)p); - if (!typeSerializesInfos.ContainsKey(typeof(TPropType))) - typeSerializesInfos[typeof(TPropType)] = func; + typeSerializesInfos[typeof(TPropType)] = func; return this; } - public PrintingConfig SerializeWith( + public PrintingConfig Using( Expression> property, Func serialize) { @@ -93,20 +82,30 @@ private static MemberInfo GetMemberInfo(Expression Trim(Expression> property, int length) { - Func func = value => value.Length <= length - ? value - : value[..length]; + Func finalFunc = value => TrimString(value, length); + + var memberInfo = GetMemberInfo(property); + if (membersSerializesInfos.TryGetValue(memberInfo, out var serialize)) + finalFunc = value => TrimString(serialize(value), length); - return SerializeWith(property, func); + return Using(property, finalFunc); } public PrintingConfig Trim(int length) { - Func func = value => value.Length <= length + Func finalFunc = value => TrimString(value, length); + + if (typeSerializesInfos.TryGetValue(typeof(string), out var serialize)) + finalFunc = value => TrimString(serialize(value), length); + + return Using(finalFunc); + } + + private string TrimString(string value, int length) + { + return value.Length <= length ? value : value[..length]; - - return SerializeWith(func); } public PrintingConfig Exclude() @@ -118,95 +117,14 @@ public PrintingConfig Exclude() private string PrintToString(object obj, int nestingLevel) { - if (obj == null) - return $"null{Environment.NewLine}"; - - if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; - - if (MaxRecursionHasBeenReached(obj)) - return $"Maximum recursion has been reached{Environment.NewLine}"; - - var indentation = string.Intern(new string('\t', nestingLevel + 1)); - - var type = obj.GetType(); - var sb = new StringBuilder().AppendLine(type.Name); - - - HandleMembers(type, sb, indentation, obj, nestingLevel); - - - - - return sb.ToString(); - } - - private void HandleMembers(Type type, StringBuilder sb, string indentation, object obj, int nestingLevel) - { - foreach (var propertyInfo in type.GetProperties()) - { - DataMember data = new DataMember(propertyInfo); - - HandleMember(sb, data, obj, indentation, nestingLevel); - } - - foreach (var fieldInfo in type.GetFields()) - { - DataMember data = new DataMember(fieldInfo); - - HandleMember(sb, data, obj, indentation, nestingLevel); - } - } - - private void HandleMember(StringBuilder sb, DataMember member, object obj, string indentation, int nestingLevel) - { - if (excludedProperties.Any(memberInfo => memberInfo.Name == member.Name) || - excludedTypes.Contains(member.Type)) - return; - - if (membersSerializesInfos.TryGetValue(member.MemberInfo, out var serializeMember)) - { - sb.Append(GetSerializedString(obj, member, indentation, serializeMember)); - return; - } - - if (typeSerializesInfos.TryGetValue(member.Type, out var serializeType)) - { - sb.Append(GetSerializedString(obj, member, indentation, serializeType)); - return; - } - - sb.Append( - GetSerializedString( - obj, - member, - indentation, - (value) => PrintToString( - value, - nestingLevel + 1), - false)); - } - - - private bool MaxRecursionHasBeenReached(object obj) - { - complexObjectLinks.TryAdd(obj, 0); - complexObjectLinks[obj]++; - - return complexObjectLinks[obj] == maxRecursion; - } - - private string GetSerializedString( - object obj, - DataMember memberInfo, - string indentation, - Func serializeMember, - bool needNewLine = true) - { - var serializedString = serializeMember(memberInfo.GetValue(obj)); - var stringEnd = needNewLine ? Environment.NewLine : string.Empty; + var serializer = new Serializer( + excludedMembers, + excludedTypes, + membersSerializesInfos, + typeSerializesInfos, + maxRecursion); - return $"{indentation}{memberInfo.Name} = {serializedString}{stringEnd}"; + return serializer.Serialize(obj, nestingLevel); } } } \ No newline at end of file diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serializer.cs new file mode 100644 index 00000000..807bb5ba --- /dev/null +++ b/ObjectPrinting/Serializer.cs @@ -0,0 +1,123 @@ +using System.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace ObjectPrinting +{ + public class Serializer + { + private readonly Dictionary complexObjectLinks = new Dictionary(); + + private readonly HashSet finalTypes = new HashSet + { + typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) + }; + + private readonly HashSet excludedMembers; + private readonly HashSet excludedTypes; + private readonly Dictionary> membersSerializesInfos; + private readonly Dictionary> typeSerializesInfos; + private readonly int maxRecursion = 2; + + public Serializer( + HashSet excludedMembers, + HashSet excludedTypes, + Dictionary> membersSerializesInfos, + Dictionary> typeSerializesInfos, + int maxRecursion) + { + this.typeSerializesInfos = typeSerializesInfos; + this.excludedMembers = excludedMembers; + this.excludedTypes = excludedTypes; + this.membersSerializesInfos = membersSerializesInfos; + this.maxRecursion = maxRecursion; + } + + public string Serialize(object obj, int nestingLevel) + { + if (obj == null) + return $"null{Environment.NewLine}"; + + if (finalTypes.Contains(obj.GetType())) + return obj + Environment.NewLine; + + if (MaxRecursionHasBeenReached(obj)) + return $"Maximum recursion has been reached{Environment.NewLine}"; + + var indentation = string.Intern(new string('\t', nestingLevel + 1)); + + var type = obj.GetType(); + var sb = new StringBuilder().AppendLine(type.Name); + + HandleMembers(type, sb, indentation, obj, nestingLevel); + + return sb.ToString(); + + } + + private void HandleMembers(Type type, StringBuilder sb, string indentation, object obj, int nestingLevel) + { + foreach (var propertyInfo in type.GetProperties()) + { + var data = new DataMember(propertyInfo); + var serializedValue = HandleMember(sb, data, obj, indentation, nestingLevel); + if (serializedValue != null) + sb.Append(serializedValue); + } + + foreach (var fieldInfo in type.GetFields()) + { + var data = new DataMember(fieldInfo); + var serializedValue = HandleMember(sb, data, obj, indentation, nestingLevel); + if (serializedValue != null) + sb.Append(serializedValue); + } + } + + private string HandleMember(StringBuilder sb, DataMember member, object obj, string indentation, + int nestingLevel) + { + if (excludedMembers.Any(memberInfo => memberInfo.Name == member.Name) || + excludedTypes.Contains(member.Type)) + return null; + + if (membersSerializesInfos.TryGetValue(member.MemberInfo, out var serializeMember)) + return GetSerializedString(obj, member, indentation, serializeMember); + + if (typeSerializesInfos.TryGetValue(member.Type, out var serializeType)) + return GetSerializedString(obj, member, indentation, serializeType); + + return GetSerializedString( + obj, + member, + indentation, + value => Serialize( + value, + nestingLevel + 1), + false); + } + + private string GetSerializedString( + object obj, + DataMember memberInfo, + string indentation, + Func serializeMember, + bool needNewLine = true) + { + var serializedString = serializeMember(memberInfo.GetValue(obj)); + var stringEnd = needNewLine ? Environment.NewLine : string.Empty; + + return $"{indentation}{memberInfo.Name} = {serializedString}{stringEnd}"; + } + + private bool MaxRecursionHasBeenReached(object obj) + { + complexObjectLinks.TryAdd(obj, 0); + complexObjectLinks[obj]++; + + return complexObjectLinks[obj] == maxRecursion; + } + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index 0ff99dda..ceac383d 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -8,6 +8,43 @@ namespace ObjectPrintingTests [TestFixture] public class ObjectPrinterAcceptanceTests { + [Test] + public void Demo() + { + var person = new Person { Name = "Alex", Age = 19, Height = 180.5, SubPerson = new SubPerson() }; + person.SubPerson.Age = 15; + person.SubPerson.Person = person; + + var printer = ObjectPrinter.For(); + + //Исключение из сериализации свойства/ поля определенного типа + //Альтернативный способ сериализации для определенного типа + //Для всех типов, имеющих культуру, есть возможность ее указать + printer.Exclude() + .Using(p => p.Age, age => (age + 1000).ToString()) + .Using(CultureInfo.InvariantCulture) + .Using((p) => p.ToUpper()) + .Trim(p => p.Name, 1) + .Exclude(p => p.Name) + .WithMaxRecursion(3); + + //Корректная обработка циклических ссылок между объектами(не должны приводить к StackOverflowException) + } + + [Test] + public void Do44Something_WhenSomething() + { + var person = new Person { Name = "Alex", Age = 19, Height = 160 }; + var printer = ObjectPrinter.For(); + + var s1 = printer + .Using(p => p.Name, n => n + ":))") + .Trim(p => p.Name, 6) + .PrintToString(person); + + s1.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + } + [Test] public void ShouldExcludeMember_WhenItsTypeSpecified() { @@ -40,7 +77,7 @@ public void ShouldSerializeMember_WithGivenFunc() var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); - var s1 = printer.SerializeWith(p => p.Age, age => (age + 1000).ToString()).PrintToString(person); + var s1 = printer.Using(p => p.Age, age => (age + 1000).ToString()).PrintToString(person); s1.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); @@ -52,7 +89,7 @@ public void SetCulture_ShouldAddedCultureInfo() var person = new Person { Name = "Petr", Age = 20, Height = 180.5 }; var printer = ObjectPrinter.For(); - var s1 = printer.SetCulture(CultureInfo.InvariantCulture).PrintToString(person); + var s1 = printer.Using(CultureInfo.InvariantCulture).PrintToString(person); s1.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); @@ -89,5 +126,14 @@ public void WhenPassFinalType_ShouldReturnStringRepresentationOfThisType() s1.Should().Be("1\r\n"); } + + [Test] + public void DoSomething_WhenSomething() + { + var printer = ObjectPrinter.For(); + var s1 = printer.PrintToString(1); + + s1.Should().Be("1\r\n"); + } } } \ No newline at end of file diff --git a/ObjectPrintingTests/PrinterExtensionsTests.cs b/ObjectPrintingTests/PrinterExtensionsTests.cs new file mode 100644 index 00000000..1b11e0a7 --- /dev/null +++ b/ObjectPrintingTests/PrinterExtensionsTests.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using FluentAssertions; +using NUnit.Framework; +using ObjectPrinting; + +namespace ObjectPrintingTests +{ + internal class PrinterExtensionsTests + { + [Test] + public void CreatePrinterWithExtensionMethod_ShouldNotBeNull() + { + var person = new Person(); + var printer = person.CreatePrinter(); + + printer.Should().NotBe(null); + } + } +} From d14c11a70efb993fa13cfd130264e79dd6be0cc4 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 02:09:52 +0500 Subject: [PATCH 05/11] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20Fluent=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D1=84=D0=B5=D0=B9=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/DataMember.cs | 15 +-- ObjectPrinting/IHasSerializationFunc.cs | 9 ++ ObjectPrinting/ISerializationConfig.cs | 9 ++ ObjectPrinting/IUsing.cs | 9 ++ ObjectPrinting/IWrap.cs | 11 ++ ObjectPrinting/PrintingConfig.cs | 90 ++++--------- ObjectPrinting/SerializationConfig.cs | 38 ++++++ ObjectPrinting/Serializer.cs | 39 +++--- ObjectPrinting/StringHelper.cs | 15 +++ ObjectPrinting/UsingExtensions.cs | 25 ++++ ObjectPrinting/WrapExtensions.cs | 12 ++ .../ObjectPrinterAcceptanceTests.cs | 125 ++--------------- ObjectPrintingTests/ObjectPrintingTest.cs | 126 ++++++++++++++++++ 13 files changed, 319 insertions(+), 204 deletions(-) create mode 100644 ObjectPrinting/IHasSerializationFunc.cs create mode 100644 ObjectPrinting/ISerializationConfig.cs create mode 100644 ObjectPrinting/IUsing.cs create mode 100644 ObjectPrinting/IWrap.cs create mode 100644 ObjectPrinting/SerializationConfig.cs create mode 100644 ObjectPrinting/StringHelper.cs create mode 100644 ObjectPrinting/UsingExtensions.cs create mode 100644 ObjectPrinting/WrapExtensions.cs create mode 100644 ObjectPrintingTests/ObjectPrintingTest.cs diff --git a/ObjectPrinting/DataMember.cs b/ObjectPrinting/DataMember.cs index 7f10d167..96238455 100644 --- a/ObjectPrinting/DataMember.cs +++ b/ObjectPrinting/DataMember.cs @@ -5,14 +5,8 @@ namespace ObjectPrinting { public class DataMember { - public string Name { get; set; } - public Type Type { get; set; } - - public Func GetValue; - public MemberInfo MemberInfo { get; set; } - public DataMember(FieldInfo fieldInfo) - { + { Name = fieldInfo.Name; GetValue = fieldInfo.GetValue; Type = fieldInfo.FieldType; @@ -26,5 +20,10 @@ public DataMember(PropertyInfo property) Type = property.PropertyType; MemberInfo = property; } + + public string Name { get; } + public Type Type { get; } + public Func GetValue { get; } + public MemberInfo MemberInfo { get; } } -} +} \ No newline at end of file diff --git a/ObjectPrinting/IHasSerializationFunc.cs b/ObjectPrinting/IHasSerializationFunc.cs new file mode 100644 index 00000000..8ec2d687 --- /dev/null +++ b/ObjectPrinting/IHasSerializationFunc.cs @@ -0,0 +1,9 @@ +using System; + +namespace ObjectPrinting +{ + public interface IHasSerializationFunc + { + Func SerializationFunc { get; } + } +} \ No newline at end of file diff --git a/ObjectPrinting/ISerializationConfig.cs b/ObjectPrinting/ISerializationConfig.cs new file mode 100644 index 00000000..7de6aa25 --- /dev/null +++ b/ObjectPrinting/ISerializationConfig.cs @@ -0,0 +1,9 @@ +namespace ObjectPrinting +{ + public interface ISerializationConfig : + IWrap, + IUsing, + IHasSerializationFunc + { + } +} \ No newline at end of file diff --git a/ObjectPrinting/IUsing.cs b/ObjectPrinting/IUsing.cs new file mode 100644 index 00000000..ec689ae3 --- /dev/null +++ b/ObjectPrinting/IUsing.cs @@ -0,0 +1,9 @@ +using System; + +namespace ObjectPrinting +{ + public interface IUsing + { + public IWrap Using(Func serialize); + } +} \ No newline at end of file diff --git a/ObjectPrinting/IWrap.cs b/ObjectPrinting/IWrap.cs new file mode 100644 index 00000000..c862a099 --- /dev/null +++ b/ObjectPrinting/IWrap.cs @@ -0,0 +1,11 @@ +using System; + +namespace ObjectPrinting +{ + public interface IWrap + { + PrintingConfig And { get; } + + IWrap Wrap(Func modify); + } +} \ No newline at end of file diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index 1ea33325..154c1fd7 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -12,11 +10,11 @@ public class PrintingConfig private readonly HashSet excludedMembers = new HashSet(); private readonly HashSet excludedTypes = new HashSet(); - private readonly Dictionary> membersSerializesInfos = - new Dictionary>(); + private readonly Dictionary membersSerializesInfos = + new Dictionary(); - private readonly Dictionary> typeSerializesInfos = - new Dictionary>(); + private readonly Dictionary typeSerializesInfos = + new Dictionary(); private int maxRecursion = 2; @@ -36,41 +34,15 @@ public PrintingConfig WithMaxRecursion(int maxRecursion) public PrintingConfig Exclude(Expression> exclude) { - var memberInfo = GetMemberInfo(exclude); + if (exclude == null) + throw new ArgumentNullException(); + var memberInfo = GetMemberInfo(exclude); excludedMembers.Add(memberInfo); return this; } - public PrintingConfig Using(CultureInfo culture) - where TPropType : IFormattable - { - return Using( - p => p.ToString(null, culture)); - } - - public PrintingConfig Using(Func serialize) - { - Func func = p => serialize((TPropType)p); - - typeSerializesInfos[typeof(TPropType)] = func; - - return this; - } - - public PrintingConfig Using( - Expression> property, - Func serialize) - { - var memberInfo = GetMemberInfo(property); - Func func = p => serialize((TPropType)p); - - membersSerializesInfos[memberInfo] = func; - - return this; - } - private static MemberInfo GetMemberInfo(Expression> expression) { var memberExpression = expression.Body is UnaryExpression unaryExpression @@ -80,33 +52,6 @@ private static MemberInfo GetMemberInfo(Expression Trim(Expression> property, int length) - { - Func finalFunc = value => TrimString(value, length); - - var memberInfo = GetMemberInfo(property); - if (membersSerializesInfos.TryGetValue(memberInfo, out var serialize)) - finalFunc = value => TrimString(serialize(value), length); - - return Using(property, finalFunc); - } - - public PrintingConfig Trim(int length) - { - Func finalFunc = value => TrimString(value, length); - - if (typeSerializesInfos.TryGetValue(typeof(string), out var serialize)) - finalFunc = value => TrimString(serialize(value), length); - - return Using(finalFunc); - } - - private string TrimString(string value, int length) - { - return value.Length <= length - ? value - : value[..length]; - } public PrintingConfig Exclude() { @@ -126,5 +71,26 @@ private string PrintToString(object obj, int nestingLevel) return serializer.Serialize(obj, nestingLevel); } + + public IUsing Printing() + { + var config = new SerializationConfig(this); + typeSerializesInfos[typeof(T)] = config; + + return config; + } + + public IUsing Printing(Expression> property) + { + if (property == null) + throw new ArgumentNullException(); + + var memberInfo = GetMemberInfo(property); + + var config = new SerializationConfig(this); + membersSerializesInfos[memberInfo] = config; + + return config; + } } } \ No newline at end of file diff --git a/ObjectPrinting/SerializationConfig.cs b/ObjectPrinting/SerializationConfig.cs new file mode 100644 index 00000000..353bf98e --- /dev/null +++ b/ObjectPrinting/SerializationConfig.cs @@ -0,0 +1,38 @@ +using System; + +namespace ObjectPrinting +{ + public class SerializationConfig : ISerializationConfig + { + private Func serialize; + + public SerializationConfig(PrintingConfig printingConfig) + { + And = printingConfig; + } + + public PrintingConfig And { get; } + + public IWrap Using(Func serialize) + { + if (serialize == null) + throw new ArgumentNullException(); + + this.serialize = serialize; + return this; + } + + public IWrap Wrap(Func modify) + { + if (modify == null) + throw new ArgumentNullException(); + + var currentFunc = serialize; + serialize = value => modify(currentFunc(value)); + return this; + } + + public Func SerializationFunc => + p => serialize((TSerialization)p); + } +} \ No newline at end of file diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serializer.cs index 807bb5ba..5ddaeabf 100644 --- a/ObjectPrinting/Serializer.cs +++ b/ObjectPrinting/Serializer.cs @@ -1,33 +1,35 @@ -using System.Text; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Text; namespace ObjectPrinting { public class Serializer { + private const BindingFlags SerializingMembersFlag = BindingFlags.Public | BindingFlags.Instance; private readonly Dictionary complexObjectLinks = new Dictionary(); + private readonly HashSet excludedMembers; + private readonly HashSet excludedTypes; + private readonly HashSet finalTypes = new HashSet { typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) }; - private readonly HashSet excludedMembers; - private readonly HashSet excludedTypes; - private readonly Dictionary> membersSerializesInfos; - private readonly Dictionary> typeSerializesInfos; - private readonly int maxRecursion = 2; + private readonly int maxRecursion; + private readonly Dictionary membersSerializesInfos; + private readonly Dictionary typeSerializesInfos; public Serializer( - HashSet excludedMembers, + HashSet excludedMembers, HashSet excludedTypes, - Dictionary> membersSerializesInfos, - Dictionary> typeSerializesInfos, + Dictionary membersSerializesInfos, + Dictionary typeSerializesInfos, int maxRecursion) - { + { this.typeSerializesInfos = typeSerializesInfos; this.excludedMembers = excludedMembers; this.excludedTypes = excludedTypes; @@ -41,7 +43,7 @@ public string Serialize(object obj, int nestingLevel) return $"null{Environment.NewLine}"; if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; + return obj + Environment.NewLine; // todo if (MaxRecursionHasBeenReached(obj)) return $"Maximum recursion has been reached{Environment.NewLine}"; @@ -54,12 +56,11 @@ public string Serialize(object obj, int nestingLevel) HandleMembers(type, sb, indentation, obj, nestingLevel); return sb.ToString(); - } private void HandleMembers(Type type, StringBuilder sb, string indentation, object obj, int nestingLevel) { - foreach (var propertyInfo in type.GetProperties()) + foreach (var propertyInfo in type.GetProperties(SerializingMembersFlag)) { var data = new DataMember(propertyInfo); var serializedValue = HandleMember(sb, data, obj, indentation, nestingLevel); @@ -67,7 +68,7 @@ private void HandleMembers(Type type, StringBuilder sb, string indentation, obje sb.Append(serializedValue); } - foreach (var fieldInfo in type.GetFields()) + foreach (var fieldInfo in type.GetFields(SerializingMembersFlag)) { var data = new DataMember(fieldInfo); var serializedValue = HandleMember(sb, data, obj, indentation, nestingLevel); @@ -83,11 +84,11 @@ private string HandleMember(StringBuilder sb, DataMember member, object obj, str excludedTypes.Contains(member.Type)) return null; - if (membersSerializesInfos.TryGetValue(member.MemberInfo, out var serializeMember)) - return GetSerializedString(obj, member, indentation, serializeMember); + if (membersSerializesInfos.TryGetValue(member.MemberInfo, out var memberSerialization)) + return GetSerializedString(obj, member, indentation, memberSerialization.SerializationFunc); - if (typeSerializesInfos.TryGetValue(member.Type, out var serializeType)) - return GetSerializedString(obj, member, indentation, serializeType); + if (typeSerializesInfos.TryGetValue(member.Type, out var typeSerialization)) + return GetSerializedString(obj, member, indentation, typeSerialization.SerializationFunc); return GetSerializedString( obj, diff --git a/ObjectPrinting/StringHelper.cs b/ObjectPrinting/StringHelper.cs new file mode 100644 index 00000000..35a1219d --- /dev/null +++ b/ObjectPrinting/StringHelper.cs @@ -0,0 +1,15 @@ +namespace ObjectPrinting +{ + public static class StringHelper + { + public static string Trim(string value, int length) + { + if (value == null) + return null; + + return value.Length <= length + ? value + : value[..length]; + } + } +} \ No newline at end of file diff --git a/ObjectPrinting/UsingExtensions.cs b/ObjectPrinting/UsingExtensions.cs new file mode 100644 index 00000000..60afe486 --- /dev/null +++ b/ObjectPrinting/UsingExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; + +namespace ObjectPrinting +{ + public static class UsingExtensions + { + public static IWrap Using( + this IUsing @using, + CultureInfo culture) + where TSerialization : IFormattable + { + return @using.Using( + p => p.ToString(null, culture)); + } + + public static IWrap Trim( + this IUsing @using, + int length) + + { + return @using.Using(value => StringHelper.Trim(value, length)); + } + } +} \ No newline at end of file diff --git a/ObjectPrinting/WrapExtensions.cs b/ObjectPrinting/WrapExtensions.cs new file mode 100644 index 00000000..d04d716a --- /dev/null +++ b/ObjectPrinting/WrapExtensions.cs @@ -0,0 +1,12 @@ +namespace ObjectPrinting +{ + public static class WrapExtensions + { + public static IWrap Trim( + this IWrap wrap, + int length) + { + return wrap.Wrap(value => StringHelper.Trim(value, length)); + } + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index ceac383d..419f6efa 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -17,123 +17,18 @@ public void Demo() var printer = ObjectPrinter.For(); - //Исключение из сериализации свойства/ поля определенного типа - //Альтернативный способ сериализации для определенного типа - //Для всех типов, имеющих культуру, есть возможность ее указать - printer.Exclude() - .Using(p => p.Age, age => (age + 1000).ToString()) - .Using(CultureInfo.InvariantCulture) - .Using((p) => p.ToUpper()) - .Trim(p => p.Name, 1) - .Exclude(p => p.Name) - .WithMaxRecursion(3); - - //Корректная обработка циклических ссылок между объектами(не должны приводить к StackOverflowException) - } - - [Test] - public void Do44Something_WhenSomething() - { - var person = new Person { Name = "Alex", Age = 19, Height = 160 }; - var printer = ObjectPrinter.For(); - - var s1 = printer - .Using(p => p.Name, n => n + ":))") - .Trim(p => p.Name, 6) + var actualString = printer.Exclude() + .Printing(p => p.Age) + .Using(age => (age + 1000).ToString()) + .And.Printing() + .Using(CultureInfo.InvariantCulture) + .And.Printing(p => p.Name) + .Trim(1) + .And.Exclude(p => p.Name) + .WithMaxRecursion(2) .PrintToString(person); - s1.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); - } - - [Test] - public void ShouldExcludeMember_WhenItsTypeSpecified() - { - var person = new Person { Name = "Alex", Age = 19 }; - - var printer = ObjectPrinter.For(); - printer.Exclude(p => p.Age) - .Exclude(); - - var s1 = printer.PrintToString(person); - s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); - } - - [Test] - public void ShouldUseTrimming_WhenItsSpecifiedForType() - { - var person = new Person { Name = "Petr", Age = 20, Height = 180 }; - var printer = ObjectPrinter.For(); - - var s1 = printer.Trim(p => p.Name, 1).PrintToString(person); - - s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); - } - - [Test] - public void ShouldSerializeMember_WithGivenFunc() - { - var person = new Person { Name = "Petr", Age = 20, Height = 180 }; - var printer = ObjectPrinter.For(); - - var s1 = printer.Using(p => p.Age, age => (age + 1000).ToString()).PrintToString(person); - - s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); - } - - [Test] - public void SetCulture_ShouldAddedCultureInfo() - { - var person = new Person { Name = "Petr", Age = 20, Height = 180.5 }; - var printer = ObjectPrinter.For(); - - var s1 = printer.Using(CultureInfo.InvariantCulture).PrintToString(person); - - s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); - } - - [Test] - public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() - { - var person = new Person { Name = "Petr", Age = 20, Height = 180, SubPerson = new SubPerson() }; - person.SubPerson.Age = 15; - person.SubPerson.Person = person; - var printer = ObjectPrinter.For(); - - var s1 = printer.PrintToString(person); - - s1.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); - } - - [Test] - public void WhenPassNull_ShouldReturnNullString() - { - var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(null); - - s1.Should().Be("null\r\n"); - } - - [Test] - public void WhenPassFinalType_ShouldReturnStringRepresentationOfThisType() - { - var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(1); - - s1.Should().Be("1\r\n"); - } - - [Test] - public void DoSomething_WhenSomething() - { - var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(1); - - s1.Should().Be("1\r\n"); + actualString.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tAge = 1019\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); } } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs new file mode 100644 index 00000000..af0bed05 --- /dev/null +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -0,0 +1,126 @@ +using NUnit.Framework; +using FluentAssertions; +using ObjectPrinting; +using System.Globalization; +using ObjectPrinter = ObjectPrinting.ObjectPrinter; + +namespace ObjectPrintingTests +{ + public class ObjectPrintingTest + { + [Test] + public void Do44Something_WhenSomething() + { + var person = new Person { Name = "Alex", Age = 19, Height = 160 }; + var printer = ObjectPrinter.For(); + + var s1 = printer + .Printing(p => p.Name) + .Using(n => n + ":))") + .Trim(6) + .And.PrintToString(person); + + s1.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + } + + [Test] + public void ShouldExcludeMember_WhenItsTypeSpecified() + { + var person = new Person { Name = "Alex", Age = 19 }; + + var printer = ObjectPrinter.For(); + printer.Exclude(p => p.Age) + .Exclude(); + + var s1 = printer.PrintToString(person); + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + } + + [Test] + public void ShouldUseTrimming_WhenItsSpecifiedForType() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180 }; + var printer = ObjectPrinter.For(); + + var s1 = printer + .Printing(p => p.Name) + .Trim(1) + .And.PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + } + + [Test] + public void ShouldSerializeMember_WithGivenFunc() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180 }; + var printer = ObjectPrinter.For(); + + var s1 = printer + .Printing(p => p.Age) + .Using(age => (age + 1000).ToString()) + .And.PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + } + + [Test] + public void SetCulture_ShouldAddedCultureInfo() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180.5 }; + var printer = ObjectPrinter.For(); + + var s1 = printer + .Printing() + .Using(CultureInfo.InvariantCulture) + .And.PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + } + + [Test] + public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() + { + var person = new Person { Name = "Petr", Age = 20, Height = 180, SubPerson = new SubPerson() }; + person.SubPerson.Age = 15; + person.SubPerson.Person = person; + var printer = ObjectPrinter.For(); + + var s1 = printer.PrintToString(person); + + s1.Should().Be( + "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); + } + + [Test] + public void WhenPassNull_ShouldReturnNullString() + { + var printer = ObjectPrinter.For(); + var s1 = printer.PrintToString(null); + + s1.Should().Be("null\r\n"); + } + + [Test] + public void WhenPassFinalType_ShouldReturnStringRepresentationOfThisType() + { + var printer = ObjectPrinter.For(); + var s1 = printer.PrintToString(1); + + s1.Should().Be("1\r\n"); + } + + [Test] + public void DoSomething_WhenSomething() + { + var printer = ObjectPrinter.For(); + var s1 = printer.PrintToString(1); + + s1.Should().Be("1\r\n"); + } + } +} From 3a465c2f2adda25422a3f4174837a29f599649e9 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 03:51:35 +0500 Subject: [PATCH 06/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=B8=20=D1=86=D0=B8=D0=BA=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D1=85=20=D1=81=D1=81=D1=8B=D0=BB?= =?UTF-8?q?=D0=BA=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/PrintingConfig.cs | 14 +++- ObjectPrinting/Serializer.cs | 30 ++++----- .../ObjectPrinterAcceptanceTests.cs | 14 ++-- ObjectPrintingTests/ObjectPrintingTest.cs | 66 +++++++++++-------- 4 files changed, 72 insertions(+), 52 deletions(-) diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index 154c1fd7..68956fe4 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -16,7 +16,9 @@ public class PrintingConfig private readonly Dictionary typeSerializesInfos = new Dictionary(); - private int maxRecursion = 2; + private Func handleMaxRecursion; + + private int maxRecursion = 60; public string PrintToString(TOwner obj) { @@ -32,6 +34,13 @@ public PrintingConfig WithMaxRecursion(int maxRecursion) return this; } + public PrintingConfig OnMaxRecursion(Func func) + { + handleMaxRecursion = func; + + return this; + } + public PrintingConfig Exclude(Expression> exclude) { if (exclude == null) @@ -67,7 +76,8 @@ private string PrintToString(object obj, int nestingLevel) excludedTypes, membersSerializesInfos, typeSerializesInfos, - maxRecursion); + maxRecursion, + handleMaxRecursion); return serializer.Serialize(obj, nestingLevel); } diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serializer.cs index 5ddaeabf..728d59c9 100644 --- a/ObjectPrinting/Serializer.cs +++ b/ObjectPrinting/Serializer.cs @@ -9,8 +9,6 @@ namespace ObjectPrinting public class Serializer { private const BindingFlags SerializingMembersFlag = BindingFlags.Public | BindingFlags.Instance; - private readonly Dictionary complexObjectLinks = new Dictionary(); - private readonly HashSet excludedMembers; private readonly HashSet excludedTypes; @@ -22,19 +20,22 @@ public class Serializer private readonly int maxRecursion; private readonly Dictionary membersSerializesInfos; private readonly Dictionary typeSerializesInfos; + private readonly Func handleMaxRecursion; public Serializer( HashSet excludedMembers, HashSet excludedTypes, Dictionary membersSerializesInfos, Dictionary typeSerializesInfos, - int maxRecursion) + int maxRecursion, + Func handleMaxRecursion) { this.typeSerializesInfos = typeSerializesInfos; this.excludedMembers = excludedMembers; this.excludedTypes = excludedTypes; this.membersSerializesInfos = membersSerializesInfos; this.maxRecursion = maxRecursion; + this.handleMaxRecursion = handleMaxRecursion; } public string Serialize(object obj, int nestingLevel) @@ -45,9 +46,14 @@ public string Serialize(object obj, int nestingLevel) if (finalTypes.Contains(obj.GetType())) return obj + Environment.NewLine; // todo - if (MaxRecursionHasBeenReached(obj)) - return $"Maximum recursion has been reached{Environment.NewLine}"; + if (nestingLevel == maxRecursion) + { + if (handleMaxRecursion != null) + return handleMaxRecursion(obj); + return $"Maximum recursion has been reached{Environment.NewLine}"; + } + var indentation = string.Intern(new string('\t', nestingLevel + 1)); var type = obj.GetType(); @@ -63,7 +69,7 @@ private void HandleMembers(Type type, StringBuilder sb, string indentation, obje foreach (var propertyInfo in type.GetProperties(SerializingMembersFlag)) { var data = new DataMember(propertyInfo); - var serializedValue = HandleMember(sb, data, obj, indentation, nestingLevel); + var serializedValue = HandleMember(data, obj, indentation, nestingLevel); if (serializedValue != null) sb.Append(serializedValue); } @@ -71,13 +77,13 @@ private void HandleMembers(Type type, StringBuilder sb, string indentation, obje foreach (var fieldInfo in type.GetFields(SerializingMembersFlag)) { var data = new DataMember(fieldInfo); - var serializedValue = HandleMember(sb, data, obj, indentation, nestingLevel); + var serializedValue = HandleMember(data, obj, indentation, nestingLevel); if (serializedValue != null) sb.Append(serializedValue); } } - private string HandleMember(StringBuilder sb, DataMember member, object obj, string indentation, + private string HandleMember(DataMember member, object obj, string indentation, int nestingLevel) { if (excludedMembers.Any(memberInfo => memberInfo.Name == member.Name) || @@ -112,13 +118,5 @@ private string GetSerializedString( return $"{indentation}{memberInfo.Name} = {serializedString}{stringEnd}"; } - - private bool MaxRecursionHasBeenReached(object obj) - { - complexObjectLinks.TryAdd(obj, 0); - complexObjectLinks[obj]++; - - return complexObjectLinks[obj] == maxRecursion; - } } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index 419f6efa..d20deca1 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System; +using System.Globalization; using FluentAssertions; using NUnit.Framework; using ObjectPrinting; @@ -11,24 +12,23 @@ public class ObjectPrinterAcceptanceTests [Test] public void Demo() { - var person = new Person { Name = "Alex", Age = 19, Height = 180.5, SubPerson = new SubPerson() }; - person.SubPerson.Age = 15; - person.SubPerson.Person = person; + var person = new Person { Name = "Alex", Age = 19, Height = 180.5 }; var printer = ObjectPrinter.For(); - var actualString = printer.Exclude() + var actualString = printer.Exclude() .Printing(p => p.Age) .Using(age => (age + 1000).ToString()) .And.Printing() .Using(CultureInfo.InvariantCulture) .And.Printing(p => p.Name) .Trim(1) - .And.Exclude(p => p.Name) + .And.Exclude(p => p.PublicField) .WithMaxRecursion(2) + .OnMaxRecursion((_) => throw new ArgumentException()) .PrintToString(person); - actualString.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tAge = 1019\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); + actualString.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = A\r\n\tHeight = 180.5\r\n\tAge = 1019\r\n"); } } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs index af0bed05..a45a6c44 100644 --- a/ObjectPrintingTests/ObjectPrintingTest.cs +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -3,24 +3,28 @@ using ObjectPrinting; using System.Globalization; using ObjectPrinter = ObjectPrinting.ObjectPrinter; +using System; namespace ObjectPrintingTests { public class ObjectPrintingTest { [Test] - public void Do44Something_WhenSomething() + public void WhenReachedMaxRecursion_ShouldThrowException() { - var person = new Person { Name = "Alex", Age = 19, Height = 160 }; + var person = new Person { Name = "Alex", Age = 19, Height = 180.5, SubPerson = new SubPerson() }; + person.SubPerson.Age = 15; + person.SubPerson.Person = person; + var printer = ObjectPrinter.For(); - var s1 = printer - .Printing(p => p.Name) - .Using(n => n + ":))") - .Trim(6) - .And.PrintToString(person); + printer + .WithMaxRecursion(5) + .OnMaxRecursion(_ => throw new ArgumentException()); + + Action act = () => { printer.PrintToString(person); }; - s1.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + act.Should().Throw(); } [Test] @@ -32,8 +36,8 @@ public void ShouldExcludeMember_WhenItsTypeSpecified() printer.Exclude(p => p.Age) .Exclude(); - var s1 = printer.PrintToString(person); - s1.Should().Be( + var actual = printer.PrintToString(person); + actual.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } @@ -43,12 +47,12 @@ public void ShouldUseTrimming_WhenItsSpecifiedForType() var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); - var s1 = printer + var actual = printer .Printing(p => p.Name) .Trim(1) .And.PrintToString(person); - s1.Should().Be( + actual.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } @@ -58,12 +62,12 @@ public void ShouldSerializeMember_WithGivenFunc() var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); - var s1 = printer + var actual = printer .Printing(p => p.Age) .Using(age => (age + 1000).ToString()) .And.PrintToString(person); - s1.Should().Be( + actual.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } @@ -73,12 +77,12 @@ public void SetCulture_ShouldAddedCultureInfo() var person = new Person { Name = "Petr", Age = 20, Height = 180.5 }; var printer = ObjectPrinter.For(); - var s1 = printer + var actual = printer .Printing() .Using(CultureInfo.InvariantCulture) .And.PrintToString(person); - s1.Should().Be( + actual.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } @@ -90,37 +94,45 @@ public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() person.SubPerson.Person = person; var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(person); + var actual = printer + .WithMaxRecursion(2) + .PrintToString(person); - s1.Should().Be( + actual.Should().Be( "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); } [Test] - public void WhenPassNull_ShouldReturnNullString() + public void WhenPassNull_ShouldReturnNullInString() { var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(null); + var actual = printer.PrintToString(null); - s1.Should().Be("null\r\n"); + actual.Should().Be("null\r\n"); } [Test] public void WhenPassFinalType_ShouldReturnStringRepresentationOfThisType() { var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(1); + var actual = printer.PrintToString(1); - s1.Should().Be("1\r\n"); + actual.Should().Be("1\r\n"); } [Test] - public void DoSomething_WhenSomething() + public void WhenDoCustomSerializeAndTrimString_ShouldReturnCorrectResult() { - var printer = ObjectPrinter.For(); - var s1 = printer.PrintToString(1); + var person = new Person { Name = "Alex", Age = 19, Height = 160 }; + var printer = ObjectPrinter.For(); + + var actual = printer + .Printing(p => p.Name) + .Using(n => n + ":))") + .Trim(6) + .And.PrintToString(person); - s1.Should().Be("1\r\n"); + actual.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } } } From 4a2ac351105becb576d6d4b3d81369cee4f1a626 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 16:21:02 +0500 Subject: [PATCH 07/11] =?UTF-8?q?=D0=9A=D0=BE=D1=80=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=BD=D0=B0=D1=8F=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D1=86=D0=B8=D0=BA=D0=BB=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=D1=85=20=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=BC=D0=B5=D0=B6=D0=B4=D1=83=20=D0=BE=D0=B1=D1=8A=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/PrintingConfig.cs | 11 +----- ObjectPrinting/Serializer.cs | 15 ++++++-- .../ObjectPrinterAcceptanceTests.cs | 1 - ObjectPrintingTests/ObjectPrintingTest.cs | 37 ++++++++++++++++++- ObjectPrintingTests/Parent.cs | 8 ++++ ObjectPrintingTests/SomethingObject.cs | 11 ++++++ 6 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 ObjectPrintingTests/Parent.cs create mode 100644 ObjectPrintingTests/SomethingObject.cs diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index 68956fe4..ed00c624 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -18,22 +18,13 @@ public class PrintingConfig private Func handleMaxRecursion; - private int maxRecursion = 60; + private readonly int maxRecursion = 1; public string PrintToString(TOwner obj) { return PrintToString(obj, 0); } - public PrintingConfig WithMaxRecursion(int maxRecursion) - { - if (maxRecursion < 1) - throw new ArgumentException(); - this.maxRecursion = maxRecursion; - - return this; - } - public PrintingConfig OnMaxRecursion(Func func) { handleMaxRecursion = func; diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serializer.cs index 728d59c9..380df496 100644 --- a/ObjectPrinting/Serializer.cs +++ b/ObjectPrinting/Serializer.cs @@ -9,6 +9,7 @@ namespace ObjectPrinting public class Serializer { private const BindingFlags SerializingMembersFlag = BindingFlags.Public | BindingFlags.Instance; + private readonly HashSet complexObjectLinks = new HashSet(); private readonly HashSet excludedMembers; private readonly HashSet excludedTypes; @@ -44,16 +45,18 @@ public string Serialize(object obj, int nestingLevel) return $"null{Environment.NewLine}"; if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; // todo + return obj + Environment.NewLine; - if (nestingLevel == maxRecursion) + if (complexObjectLinks.Contains(obj)) { if (handleMaxRecursion != null) return handleMaxRecursion(obj); return $"Maximum recursion has been reached{Environment.NewLine}"; } - + + complexObjectLinks.Add(obj); + var indentation = string.Intern(new string('\t', nestingLevel + 1)); var type = obj.GetType(); @@ -61,6 +64,7 @@ public string Serialize(object obj, int nestingLevel) HandleMembers(type, sb, indentation, obj, nestingLevel); + complexObjectLinks.Remove(obj); return sb.ToString(); } @@ -118,5 +122,10 @@ private string GetSerializedString( return $"{indentation}{memberInfo.Name} = {serializedString}{stringEnd}"; } + + //private bool MaxRecursionHasBeenReached(object obj) + //{ + // return complexObjectLinks.Count > 1; + //} } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index d20deca1..a07df250 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -24,7 +24,6 @@ public void Demo() .And.Printing(p => p.Name) .Trim(1) .And.Exclude(p => p.PublicField) - .WithMaxRecursion(2) .OnMaxRecursion((_) => throw new ArgumentException()) .PrintToString(person); diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs index a45a6c44..f64165ac 100644 --- a/ObjectPrintingTests/ObjectPrintingTest.cs +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -19,7 +19,6 @@ public void WhenReachedMaxRecursion_ShouldThrowException() var printer = ObjectPrinter.For(); printer - .WithMaxRecursion(5) .OnMaxRecursion(_ => throw new ArgumentException()); Action act = () => { printer.PrintToString(person); }; @@ -27,6 +26,41 @@ public void WhenReachedMaxRecursion_ShouldThrowException() act.Should().Throw(); } + [Test] + public void WhenAreNoCircularLinks_ShouldReturnCorrectAnswer() + { + var subPerson = new SubPerson(); + var person = new Person() {SubPerson = subPerson}; + + var parent = new Parent() + { + Person = person, + SubPerson = subPerson + }; + + var actual = parent + .CreatePrinter() + .OnMaxRecursion((_) => "РЕКУРСИЯ") + .PrintToString(parent); + + actual.Should().Be("Parent\r\n\tPerson = Person\r\n\t\tId = 00000000-0000-0000-0000-000000000000\r\n\t\tName = null\r\n\t\tHeight = 0\r\n\t\tAge = 0\r\n\t\tSubPerson = SubPerson\r\n\t\t\tPerson = null\r\n\t\t\tAge = 0\r\n\t\tPublicField = null\r\n\tSubPerson = SubPerson\r\n\t\tPerson = null\r\n\t\tAge = 0\r\n"); + } + + [Test] + public void WhenObjectRefersToItself_ShouldReturnCorrectAnswer() + { + var currentObject = new SomethingObject(); + + currentObject.ToSameObject = currentObject; + + var actual = currentObject + .CreatePrinter() + .OnMaxRecursion((_) => "РЕКУРСИЯ") + .PrintToString(currentObject); + + actual.Should().Be("SomethingObject\r\n\tToSameObject = РЕКУРСИЯ"); + } + [Test] public void ShouldExcludeMember_WhenItsTypeSpecified() { @@ -95,7 +129,6 @@ public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() var printer = ObjectPrinter.For(); var actual = printer - .WithMaxRecursion(2) .PrintToString(person); actual.Should().Be( diff --git a/ObjectPrintingTests/Parent.cs b/ObjectPrintingTests/Parent.cs new file mode 100644 index 00000000..c25bac8f --- /dev/null +++ b/ObjectPrintingTests/Parent.cs @@ -0,0 +1,8 @@ +namespace ObjectPrintingTests +{ + public class Parent + { + public Person Person { get; set; } + public SubPerson SubPerson { get; set; } + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/SomethingObject.cs b/ObjectPrintingTests/SomethingObject.cs new file mode 100644 index 00000000..c3694519 --- /dev/null +++ b/ObjectPrintingTests/SomethingObject.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ObjectPrintingTests +{ + public class SomethingObject + { + public SomethingObject ToSameObject { get; set; } + } +} From 59e34005cbda6bc044875fb92c2dec30fbfe1544 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 17:56:21 +0500 Subject: [PATCH 08/11] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BB?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/Serializer.cs | 43 +++++++++++++++++++---- ObjectPrintingTests/CollectionsKeeper.cs | 14 ++++++++ ObjectPrintingTests/ObjectPrintingTest.cs | 43 +++++++++++++++++++++++ 3 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 ObjectPrintingTests/CollectionsKeeper.cs diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serializer.cs index 380df496..f14a25d5 100644 --- a/ObjectPrinting/Serializer.cs +++ b/ObjectPrinting/Serializer.cs @@ -1,8 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using ObjectPrinting.Solved; namespace ObjectPrinting { @@ -44,6 +46,8 @@ public string Serialize(object obj, int nestingLevel) if (obj == null) return $"null{Environment.NewLine}"; + var indentation = string.Intern(new string('\t', nestingLevel + 1)); + if (finalTypes.Contains(obj.GetType())) return obj + Environment.NewLine; @@ -57,7 +61,8 @@ public string Serialize(object obj, int nestingLevel) complexObjectLinks.Add(obj); - var indentation = string.Intern(new string('\t', nestingLevel + 1)); + if (obj is ICollection collection) + return SerializeCollection(collection, nestingLevel); var type = obj.GetType(); var sb = new StringBuilder().AppendLine(type.Name); @@ -100,6 +105,14 @@ private string HandleMember(DataMember member, object obj, string indentation, if (typeSerializesInfos.TryGetValue(member.Type, out var typeSerialization)) return GetSerializedString(obj, member, indentation, typeSerialization.SerializationFunc); + if (typeof(ICollection).IsAssignableFrom(member.Type)) + return GetSerializedString( + obj, + member, + indentation, + obj => SerializeCollection((ICollection) obj, nestingLevel + 1), + false); + return GetSerializedString( obj, member, @@ -110,6 +123,29 @@ private string HandleMember(DataMember member, object obj, string indentation, false); } + private string SerializeCollection(ICollection collection, int nestingLevel) + { + if (collection == null) + return $"null{Environment.NewLine}"; + + var sb = new StringBuilder(); + sb.AppendLine(collection.GetType().Name); + + var indentation = GetIndentation(nestingLevel + 1); + foreach (var element in collection) + { + sb.Append(indentation); + sb.Append(Serialize(element, nestingLevel + 1)); + } + + return sb.ToString(); + } + + private string GetIndentation(int nestingLevel) + { + return string.Intern(new string('\t', nestingLevel)); + } + private string GetSerializedString( object obj, DataMember memberInfo, @@ -122,10 +158,5 @@ private string GetSerializedString( return $"{indentation}{memberInfo.Name} = {serializedString}{stringEnd}"; } - - //private bool MaxRecursionHasBeenReached(object obj) - //{ - // return complexObjectLinks.Count > 1; - //} } } \ No newline at end of file diff --git a/ObjectPrintingTests/CollectionsKeeper.cs b/ObjectPrintingTests/CollectionsKeeper.cs new file mode 100644 index 00000000..f95ca36a --- /dev/null +++ b/ObjectPrintingTests/CollectionsKeeper.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace ObjectPrintingTests +{ + public class CollectionsKeeper + { + public List stringsList; + + public int[] intsArray; + + public Dictionary dictionary; + } +} diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs index f64165ac..1c736ea5 100644 --- a/ObjectPrintingTests/ObjectPrintingTest.cs +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -4,6 +4,7 @@ using System.Globalization; using ObjectPrinter = ObjectPrinting.ObjectPrinter; using System; +using System.Collections.Generic; namespace ObjectPrintingTests { @@ -167,5 +168,47 @@ public void WhenDoCustomSerializeAndTrimString_ShouldReturnCorrectResult() actual.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); } + + [Test] + public void WhenFieldIsList_ShouldReturnCorrectCollectionSerialization() + { + var collections = new CollectionsKeeper(); + collections.stringsList = new List() { "один", "два" }; + + var printer = collections.CreatePrinter(); + + var actual = printer + .PrintToString(collections); + + actual.Should().Be("CollectionsKeeper\r\n\tstringsList = List`1\r\n\t\tодин\r\n\t\tдва\r\n\tintsArray = null\r\n\tdictionary = null\r\n"); + } + + [Test] + public void WhenFieldIsArray_ShouldReturnCorrectCollectionSerialization() + { + var collections = new CollectionsKeeper(); + collections.intsArray = new int[] { 1, 2, 3 }; + + var printer = collections.CreatePrinter(); + + var actual = printer + .PrintToString(collections); + + actual.Should().Be("CollectionsKeeper\r\n\tstringsList = null\r\n\tintsArray = Int32[]\r\n\t\t1\r\n\t\t2\r\n\t\t3\r\n\tdictionary = null\r\n"); + } + + [Test] + public void WhenFieldIsDictionary_ShouldReturnCorrectCollectionSerialization() + { + var collections = new CollectionsKeeper(); + collections.dictionary = new Dictionary() { {1, "один"} , { 2, "два" }}; + + var printer = collections.CreatePrinter(); + + var actual = printer + .PrintToString(collections); + + actual.Should().Be("CollectionsKeeper\r\n\tstringsList = null\r\n\tintsArray = null\r\n\tdictionary = Dictionary`2\r\n\t\tKeyValuePair`2\r\n\t\t\tKey = 1\r\n\t\t\tValue = один\r\n\t\tKeyValuePair`2\r\n\t\t\tKey = 2\r\n\t\t\tValue = два\r\n"); + } } } From b64fd61c9975d97e618aa799146e1dedabbc5287 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 18:22:36 +0500 Subject: [PATCH 09/11] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/Serializer.cs | 38 +++++++++++------------ ObjectPrintingTests/ObjectPrintingTest.cs | 26 ++++++++-------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serializer.cs index f14a25d5..f0a3991a 100644 --- a/ObjectPrinting/Serializer.cs +++ b/ObjectPrinting/Serializer.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Reflection; using System.Text; -using ObjectPrinting.Solved; namespace ObjectPrinting { @@ -20,10 +19,11 @@ public class Serializer typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) }; + private readonly Func handleMaxRecursion; + private readonly int maxRecursion; private readonly Dictionary membersSerializesInfos; private readonly Dictionary typeSerializesInfos; - private readonly Func handleMaxRecursion; public Serializer( HashSet excludedMembers, @@ -46,10 +46,10 @@ public string Serialize(object obj, int nestingLevel) if (obj == null) return $"null{Environment.NewLine}"; - var indentation = string.Intern(new string('\t', nestingLevel + 1)); - if (finalTypes.Contains(obj.GetType())) - return obj + Environment.NewLine; + return typeSerializesInfos.TryGetValue(obj.GetType(), out var typeSerialization1) + ? typeSerialization1.SerializationFunc(obj) + Environment.NewLine + : obj + Environment.NewLine; if (complexObjectLinks.Contains(obj)) { @@ -61,12 +61,23 @@ public string Serialize(object obj, int nestingLevel) complexObjectLinks.Add(obj); + if (typeSerializesInfos.TryGetValue(obj.GetType(), out var typeSerialization)) + { + var result = typeSerialization.SerializationFunc(obj); + complexObjectLinks.Remove(obj); + return result + Environment.NewLine; + } + if (obj is ICollection collection) - return SerializeCollection(collection, nestingLevel); + { + var result = SerializeCollection(collection, nestingLevel); + complexObjectLinks.Remove(obj); + return result; + } var type = obj.GetType(); var sb = new StringBuilder().AppendLine(type.Name); - + var indentation = string.Intern(new string('\t', nestingLevel + 1)); HandleMembers(type, sb, indentation, obj, nestingLevel); complexObjectLinks.Remove(obj); @@ -102,17 +113,6 @@ private string HandleMember(DataMember member, object obj, string indentation, if (membersSerializesInfos.TryGetValue(member.MemberInfo, out var memberSerialization)) return GetSerializedString(obj, member, indentation, memberSerialization.SerializationFunc); - if (typeSerializesInfos.TryGetValue(member.Type, out var typeSerialization)) - return GetSerializedString(obj, member, indentation, typeSerialization.SerializationFunc); - - if (typeof(ICollection).IsAssignableFrom(member.Type)) - return GetSerializedString( - obj, - member, - indentation, - obj => SerializeCollection((ICollection) obj, nestingLevel + 1), - false); - return GetSerializedString( obj, member, @@ -143,7 +143,7 @@ private string SerializeCollection(ICollection collection, int nestingLevel) private string GetIndentation(int nestingLevel) { - return string.Intern(new string('\t', nestingLevel)); + return string.Intern(new string('\t', nestingLevel)); } private string GetSerializedString( diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs index 1c736ea5..8547dbe4 100644 --- a/ObjectPrintingTests/ObjectPrintingTest.cs +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -44,7 +44,7 @@ public void WhenAreNoCircularLinks_ShouldReturnCorrectAnswer() .OnMaxRecursion((_) => "РЕКУРСИЯ") .PrintToString(parent); - actual.Should().Be("Parent\r\n\tPerson = Person\r\n\t\tId = 00000000-0000-0000-0000-000000000000\r\n\t\tName = null\r\n\t\tHeight = 0\r\n\t\tAge = 0\r\n\t\tSubPerson = SubPerson\r\n\t\t\tPerson = null\r\n\t\t\tAge = 0\r\n\t\tPublicField = null\r\n\tSubPerson = SubPerson\r\n\t\tPerson = null\r\n\t\tAge = 0\r\n"); + actual.Should().Be($"Parent{Environment.NewLine}\tPerson = Person{Environment.NewLine}\t\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\t\tName = null{Environment.NewLine}\t\tHeight = 0{Environment.NewLine}\t\tAge = 0{Environment.NewLine}\t\tSubPerson = SubPerson{Environment.NewLine}\t\t\tPerson = null{Environment.NewLine}\t\t\tAge = 0{Environment.NewLine}\t\tPublicField = null{Environment.NewLine}\tSubPerson = SubPerson{Environment.NewLine}\t\tPerson = null{Environment.NewLine}\t\tAge = 0{Environment.NewLine}"); } [Test] @@ -59,7 +59,7 @@ public void WhenObjectRefersToItself_ShouldReturnCorrectAnswer() .OnMaxRecursion((_) => "РЕКУРСИЯ") .PrintToString(currentObject); - actual.Should().Be("SomethingObject\r\n\tToSameObject = РЕКУРСИЯ"); + actual.Should().Be($"SomethingObject{Environment.NewLine}\tToSameObject = РЕКУРСИЯ"); } [Test] @@ -73,7 +73,7 @@ public void ShouldExcludeMember_WhenItsTypeSpecified() var actual = printer.PrintToString(person); actual.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + $"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = Alex{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } [Test] @@ -88,7 +88,7 @@ public void ShouldUseTrimming_WhenItsSpecifiedForType() .And.PrintToString(person); actual.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = P\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + $"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = P{Environment.NewLine}\tHeight = 180{Environment.NewLine}\tAge = 20{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } [Test] @@ -103,7 +103,7 @@ public void ShouldSerializeMember_WithGivenFunc() .And.PrintToString(person); actual.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 1020\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + $"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = Petr{Environment.NewLine}\tHeight = 180{Environment.NewLine}\tAge = 1020{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } [Test] @@ -118,7 +118,7 @@ public void SetCulture_ShouldAddedCultureInfo() .And.PrintToString(person); actual.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180.5\r\n\tAge = 20\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + $"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = Petr{Environment.NewLine}\tHeight = 180.5{Environment.NewLine}\tAge = 20{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } [Test] @@ -133,7 +133,7 @@ public void WhenCyclicLinksWasFound_ShouldPrintWithRecursionLimit() .PrintToString(person); actual.Should().Be( - "Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Petr\r\n\tHeight = 180\r\n\tAge = 20\r\n\tSubPerson = SubPerson\r\n\t\tPerson = Maximum recursion has been reached\r\n\t\tAge = 15\r\n\tPublicField = null\r\n"); + $"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = Petr{Environment.NewLine}\tHeight = 180{Environment.NewLine}\tAge = 20{Environment.NewLine}\tSubPerson = SubPerson{Environment.NewLine}\t\tPerson = Maximum recursion has been reached{Environment.NewLine}\t\tAge = 15{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } [Test] @@ -142,7 +142,7 @@ public void WhenPassNull_ShouldReturnNullInString() var printer = ObjectPrinter.For(); var actual = printer.PrintToString(null); - actual.Should().Be("null\r\n"); + actual.Should().Be($"null{Environment.NewLine}"); } [Test] @@ -151,7 +151,7 @@ public void WhenPassFinalType_ShouldReturnStringRepresentationOfThisType() var printer = ObjectPrinter.For(); var actual = printer.PrintToString(1); - actual.Should().Be("1\r\n"); + actual.Should().Be($"1{Environment.NewLine}"); } [Test] @@ -166,7 +166,7 @@ public void WhenDoCustomSerializeAndTrimString_ShouldReturnCorrectResult() .Trim(6) .And.PrintToString(person); - actual.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = Alex:)\r\n\tHeight = 160\r\n\tAge = 19\r\n\tSubPerson = null\r\n\tPublicField = null\r\n"); + actual.Should().Be($"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = Alex:){Environment.NewLine}\tHeight = 160{Environment.NewLine}\tAge = 19{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } [Test] @@ -180,7 +180,7 @@ public void WhenFieldIsList_ShouldReturnCorrectCollectionSerialization() var actual = printer .PrintToString(collections); - actual.Should().Be("CollectionsKeeper\r\n\tstringsList = List`1\r\n\t\tодин\r\n\t\tдва\r\n\tintsArray = null\r\n\tdictionary = null\r\n"); + actual.Should().Be($"CollectionsKeeper{Environment.NewLine}\tstringsList = List`1{Environment.NewLine}\t\tодин{Environment.NewLine}\t\tдва{Environment.NewLine}\tintsArray = null{Environment.NewLine}\tdictionary = null{Environment.NewLine}"); } [Test] @@ -194,7 +194,7 @@ public void WhenFieldIsArray_ShouldReturnCorrectCollectionSerialization() var actual = printer .PrintToString(collections); - actual.Should().Be("CollectionsKeeper\r\n\tstringsList = null\r\n\tintsArray = Int32[]\r\n\t\t1\r\n\t\t2\r\n\t\t3\r\n\tdictionary = null\r\n"); + actual.Should().Be($"CollectionsKeeper{Environment.NewLine}\tstringsList = null{Environment.NewLine}\tintsArray = Int32[]{Environment.NewLine}\t\t1{Environment.NewLine}\t\t2{Environment.NewLine}\t\t3{Environment.NewLine}\tdictionary = null{Environment.NewLine}"); } [Test] @@ -208,7 +208,7 @@ public void WhenFieldIsDictionary_ShouldReturnCorrectCollectionSerialization() var actual = printer .PrintToString(collections); - actual.Should().Be("CollectionsKeeper\r\n\tstringsList = null\r\n\tintsArray = null\r\n\tdictionary = Dictionary`2\r\n\t\tKeyValuePair`2\r\n\t\t\tKey = 1\r\n\t\t\tValue = один\r\n\t\tKeyValuePair`2\r\n\t\t\tKey = 2\r\n\t\t\tValue = два\r\n"); + actual.Should().Be($"CollectionsKeeper{Environment.NewLine}\tstringsList = null{Environment.NewLine}\tintsArray = null{Environment.NewLine}\tdictionary = Dictionary`2{Environment.NewLine}\t\tKeyValuePair`2{Environment.NewLine}\t\t\tKey = 1{Environment.NewLine}\t\t\tValue = один{Environment.NewLine}\t\tKeyValuePair`2{Environment.NewLine}\t\t\tKey = 2{Environment.NewLine}\t\t\tValue = два{Environment.NewLine}"); } } } From 5a18f9c243f347ea6a07576325204e8feb2519d2 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 19:18:22 +0500 Subject: [PATCH 10/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=81=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D0=B0=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/PrintingConfig.cs | 1 + .../IHasSerializationFunc.cs | 2 +- .../ISerializationConfig.cs | 2 +- ObjectPrinting/{ => Serialization}/IUsing.cs | 2 +- ObjectPrinting/{ => Serialization}/IWrap.cs | 2 +- .../SerializationConfig.cs | 2 +- .../{ => Serialization}/Serializer.cs | 4 +-- .../{ => Serialization}/StringHelper.cs | 2 +- .../{ => Serialization}/UsingExtensions.cs | 2 +- .../{ => Serialization}/WrapExtensions.cs | 2 +- .../ObjectPrinterAcceptanceTests.cs | 4 ++- ObjectPrintingTests/ObjectPrintingTest.cs | 34 +++++++++++++++++-- .../ObjectPrintingTests.csproj | 2 +- ObjectPrintingTests/PrinterExtensionsTests.cs | 8 ++--- .../{ => TestHelpers}/CollectionsKeeper.cs | 7 ++-- .../{ => TestHelpers}/Parent.cs | 2 +- .../{ => TestHelpers}/Person.cs | 2 +- .../{ => TestHelpers}/SomethingObject.cs | 9 ++--- .../{ => TestHelpers}/SubPerson.cs | 4 +-- ObjectPrintingTests/TestHelpers/Test.cs | 8 +++++ 20 files changed, 68 insertions(+), 33 deletions(-) rename ObjectPrinting/{ => Serialization}/IHasSerializationFunc.cs (77%) rename ObjectPrinting/{ => Serialization}/ISerializationConfig.cs (80%) rename ObjectPrinting/{ => Serialization}/IUsing.cs (80%) rename ObjectPrinting/{ => Serialization}/IWrap.cs (81%) rename ObjectPrinting/{ => Serialization}/SerializationConfig.cs (96%) rename ObjectPrinting/{ => Serialization}/Serializer.cs (98%) rename ObjectPrinting/{ => Serialization}/StringHelper.cs (87%) rename ObjectPrinting/{ => Serialization}/UsingExtensions.cs (94%) rename ObjectPrinting/{ => Serialization}/WrapExtensions.cs (86%) rename ObjectPrintingTests/{ => TestHelpers}/CollectionsKeeper.cs (67%) rename ObjectPrintingTests/{ => TestHelpers}/Parent.cs (74%) rename ObjectPrintingTests/{ => TestHelpers}/Person.cs (88%) rename ObjectPrintingTests/{ => TestHelpers}/SomethingObject.cs (50%) rename ObjectPrintingTests/{ => TestHelpers}/SubPerson.cs (72%) create mode 100644 ObjectPrintingTests/TestHelpers/Test.cs diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index ed00c624..b6ff88d3 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; +using ObjectPrinting.Serialization; namespace ObjectPrinting { diff --git a/ObjectPrinting/IHasSerializationFunc.cs b/ObjectPrinting/Serialization/IHasSerializationFunc.cs similarity index 77% rename from ObjectPrinting/IHasSerializationFunc.cs rename to ObjectPrinting/Serialization/IHasSerializationFunc.cs index 8ec2d687..3f9f3bd4 100644 --- a/ObjectPrinting/IHasSerializationFunc.cs +++ b/ObjectPrinting/Serialization/IHasSerializationFunc.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public interface IHasSerializationFunc { diff --git a/ObjectPrinting/ISerializationConfig.cs b/ObjectPrinting/Serialization/ISerializationConfig.cs similarity index 80% rename from ObjectPrinting/ISerializationConfig.cs rename to ObjectPrinting/Serialization/ISerializationConfig.cs index 7de6aa25..2d3b6507 100644 --- a/ObjectPrinting/ISerializationConfig.cs +++ b/ObjectPrinting/Serialization/ISerializationConfig.cs @@ -1,4 +1,4 @@ -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public interface ISerializationConfig : IWrap, diff --git a/ObjectPrinting/IUsing.cs b/ObjectPrinting/Serialization/IUsing.cs similarity index 80% rename from ObjectPrinting/IUsing.cs rename to ObjectPrinting/Serialization/IUsing.cs index ec689ae3..02831afa 100644 --- a/ObjectPrinting/IUsing.cs +++ b/ObjectPrinting/Serialization/IUsing.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public interface IUsing { diff --git a/ObjectPrinting/IWrap.cs b/ObjectPrinting/Serialization/IWrap.cs similarity index 81% rename from ObjectPrinting/IWrap.cs rename to ObjectPrinting/Serialization/IWrap.cs index c862a099..341134c5 100644 --- a/ObjectPrinting/IWrap.cs +++ b/ObjectPrinting/Serialization/IWrap.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public interface IWrap { diff --git a/ObjectPrinting/SerializationConfig.cs b/ObjectPrinting/Serialization/SerializationConfig.cs similarity index 96% rename from ObjectPrinting/SerializationConfig.cs rename to ObjectPrinting/Serialization/SerializationConfig.cs index 353bf98e..df3e5282 100644 --- a/ObjectPrinting/SerializationConfig.cs +++ b/ObjectPrinting/Serialization/SerializationConfig.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public class SerializationConfig : ISerializationConfig { diff --git a/ObjectPrinting/Serializer.cs b/ObjectPrinting/Serialization/Serializer.cs similarity index 98% rename from ObjectPrinting/Serializer.cs rename to ObjectPrinting/Serialization/Serializer.cs index f0a3991a..1af10b4e 100644 --- a/ObjectPrinting/Serializer.cs +++ b/ObjectPrinting/Serialization/Serializer.cs @@ -5,7 +5,7 @@ using System.Reflection; using System.Text; -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public class Serializer { @@ -54,7 +54,7 @@ public string Serialize(object obj, int nestingLevel) if (complexObjectLinks.Contains(obj)) { if (handleMaxRecursion != null) - return handleMaxRecursion(obj); + return handleMaxRecursion(obj) + Environment.NewLine; return $"Maximum recursion has been reached{Environment.NewLine}"; } diff --git a/ObjectPrinting/StringHelper.cs b/ObjectPrinting/Serialization/StringHelper.cs similarity index 87% rename from ObjectPrinting/StringHelper.cs rename to ObjectPrinting/Serialization/StringHelper.cs index 35a1219d..bbd1d8eb 100644 --- a/ObjectPrinting/StringHelper.cs +++ b/ObjectPrinting/Serialization/StringHelper.cs @@ -1,4 +1,4 @@ -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public static class StringHelper { diff --git a/ObjectPrinting/UsingExtensions.cs b/ObjectPrinting/Serialization/UsingExtensions.cs similarity index 94% rename from ObjectPrinting/UsingExtensions.cs rename to ObjectPrinting/Serialization/UsingExtensions.cs index 60afe486..31641ab7 100644 --- a/ObjectPrinting/UsingExtensions.cs +++ b/ObjectPrinting/Serialization/UsingExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public static class UsingExtensions { diff --git a/ObjectPrinting/WrapExtensions.cs b/ObjectPrinting/Serialization/WrapExtensions.cs similarity index 86% rename from ObjectPrinting/WrapExtensions.cs rename to ObjectPrinting/Serialization/WrapExtensions.cs index d04d716a..6d23cabf 100644 --- a/ObjectPrinting/WrapExtensions.cs +++ b/ObjectPrinting/Serialization/WrapExtensions.cs @@ -1,4 +1,4 @@ -namespace ObjectPrinting +namespace ObjectPrinting.Serialization { public static class WrapExtensions { diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index a07df250..6de5c701 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -3,6 +3,8 @@ using FluentAssertions; using NUnit.Framework; using ObjectPrinting; +using ObjectPrinting.Serialization; +using ObjectPrintingTests.TestHelpers; namespace ObjectPrintingTests { @@ -27,7 +29,7 @@ public void Demo() .OnMaxRecursion((_) => throw new ArgumentException()) .PrintToString(person); - actualString.Should().Be("Person\r\n\tId = 00000000-0000-0000-0000-000000000000\r\n\tName = A\r\n\tHeight = 180.5\r\n\tAge = 1019\r\n"); + actualString.Should().Be($"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = A{Environment.NewLine}\tHeight = 180.5{Environment.NewLine}\tAge = 1019{Environment.NewLine}"); } } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs index 8547dbe4..80c3a872 100644 --- a/ObjectPrintingTests/ObjectPrintingTest.cs +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -5,6 +5,8 @@ using ObjectPrinter = ObjectPrinting.ObjectPrinter; using System; using System.Collections.Generic; +using ObjectPrintingTests.TestHelpers; +using ObjectPrinting.Serialization; namespace ObjectPrintingTests { @@ -51,7 +53,6 @@ public void WhenAreNoCircularLinks_ShouldReturnCorrectAnswer() public void WhenObjectRefersToItself_ShouldReturnCorrectAnswer() { var currentObject = new SomethingObject(); - currentObject.ToSameObject = currentObject; var actual = currentObject @@ -59,7 +60,7 @@ public void WhenObjectRefersToItself_ShouldReturnCorrectAnswer() .OnMaxRecursion((_) => "РЕКУРСИЯ") .PrintToString(currentObject); - actual.Should().Be($"SomethingObject{Environment.NewLine}\tToSameObject = РЕКУРСИЯ"); + actual.Should().Be($"SomethingObject{Environment.NewLine}\tToSameObject = РЕКУРСИЯ{Environment.NewLine}\tCount = 1{Environment.NewLine}"); } [Test] @@ -72,6 +73,7 @@ public void ShouldExcludeMember_WhenItsTypeSpecified() .Exclude(); var actual = printer.PrintToString(person); + actual.Should().Be( $"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = Alex{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); } @@ -210,5 +212,33 @@ public void WhenFieldIsDictionary_ShouldReturnCorrectCollectionSerialization() actual.Should().Be($"CollectionsKeeper{Environment.NewLine}\tstringsList = null{Environment.NewLine}\tintsArray = null{Environment.NewLine}\tdictionary = Dictionary`2{Environment.NewLine}\t\tKeyValuePair`2{Environment.NewLine}\t\t\tKey = 1{Environment.NewLine}\t\t\tValue = один{Environment.NewLine}\t\tKeyValuePair`2{Environment.NewLine}\t\t\tKey = 2{Environment.NewLine}\t\t\tValue = два{Environment.NewLine}"); } + + [Test] + public void WhenPassCollectionToPrinter_ShouldReturnThisCollectionInString() + { + var dict = new Dictionary() {{1, "один"} }; + + var printer = dict.CreatePrinter(); + + var actual = printer.PrintToString(dict); + + actual.Should().Be($"Dictionary`2{Environment.NewLine}\tKeyValuePair`2{Environment.NewLine}\t\tKey = 1{Environment.NewLine}\t\tValue = один{Environment.NewLine}"); + } + + [Test] + public void WhenToSameObjectInTwoFields_ShouldReturnCorrectResultWithoutRecursion() + { + var test = new Test(); + var obj = new SomethingObject(); + + test.ToSameObject = obj; + test.ToSameObject2 = obj; + + var printer = test.CreatePrinter(); + + var actual = printer.PrintToString(test); + + actual.Should().Be($"Test{Environment.NewLine}\tToSameObject = SomethingObject{Environment.NewLine}\t\tToSameObject = null{Environment.NewLine}\t\tCount = 1{Environment.NewLine}\tToSameObject2 = SomethingObject{Environment.NewLine}\t\tToSameObject = null{Environment.NewLine}\t\tCount = 1{Environment.NewLine}"); + } } } diff --git a/ObjectPrintingTests/ObjectPrintingTests.csproj b/ObjectPrintingTests/ObjectPrintingTests.csproj index 8d6309d7..8ebd2e8a 100644 --- a/ObjectPrintingTests/ObjectPrintingTests.csproj +++ b/ObjectPrintingTests/ObjectPrintingTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/ObjectPrintingTests/PrinterExtensionsTests.cs b/ObjectPrintingTests/PrinterExtensionsTests.cs index 1b11e0a7..82242c54 100644 --- a/ObjectPrintingTests/PrinterExtensionsTests.cs +++ b/ObjectPrintingTests/PrinterExtensionsTests.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; -using FluentAssertions; +using FluentAssertions; using NUnit.Framework; using ObjectPrinting; +using ObjectPrinting.Solved.Tests; namespace ObjectPrintingTests { @@ -18,4 +16,4 @@ public void CreatePrinterWithExtensionMethod_ShouldNotBeNull() printer.Should().NotBe(null); } } -} +} \ No newline at end of file diff --git a/ObjectPrintingTests/CollectionsKeeper.cs b/ObjectPrintingTests/TestHelpers/CollectionsKeeper.cs similarity index 67% rename from ObjectPrintingTests/CollectionsKeeper.cs rename to ObjectPrintingTests/TestHelpers/CollectionsKeeper.cs index f95ca36a..a3ddc8bb 100644 --- a/ObjectPrintingTests/CollectionsKeeper.cs +++ b/ObjectPrintingTests/TestHelpers/CollectionsKeeper.cs @@ -1,7 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; -namespace ObjectPrintingTests +namespace ObjectPrintingTests.TestHelpers { public class CollectionsKeeper { @@ -11,4 +10,4 @@ public class CollectionsKeeper public Dictionary dictionary; } -} +} \ No newline at end of file diff --git a/ObjectPrintingTests/Parent.cs b/ObjectPrintingTests/TestHelpers/Parent.cs similarity index 74% rename from ObjectPrintingTests/Parent.cs rename to ObjectPrintingTests/TestHelpers/Parent.cs index c25bac8f..6afee895 100644 --- a/ObjectPrintingTests/Parent.cs +++ b/ObjectPrintingTests/TestHelpers/Parent.cs @@ -1,4 +1,4 @@ -namespace ObjectPrintingTests +namespace ObjectPrintingTests.TestHelpers { public class Parent { diff --git a/ObjectPrintingTests/Person.cs b/ObjectPrintingTests/TestHelpers/Person.cs similarity index 88% rename from ObjectPrintingTests/Person.cs rename to ObjectPrintingTests/TestHelpers/Person.cs index 6baceb25..b0e362ea 100644 --- a/ObjectPrintingTests/Person.cs +++ b/ObjectPrintingTests/TestHelpers/Person.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectPrintingTests +namespace ObjectPrintingTests.TestHelpers { public class Person { diff --git a/ObjectPrintingTests/SomethingObject.cs b/ObjectPrintingTests/TestHelpers/SomethingObject.cs similarity index 50% rename from ObjectPrintingTests/SomethingObject.cs rename to ObjectPrintingTests/TestHelpers/SomethingObject.cs index c3694519..781ad9d5 100644 --- a/ObjectPrintingTests/SomethingObject.cs +++ b/ObjectPrintingTests/TestHelpers/SomethingObject.cs @@ -1,11 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ObjectPrintingTests +namespace ObjectPrintingTests.TestHelpers { public class SomethingObject { public SomethingObject ToSameObject { get; set; } + public int Count = 1; } -} +} \ No newline at end of file diff --git a/ObjectPrintingTests/SubPerson.cs b/ObjectPrintingTests/TestHelpers/SubPerson.cs similarity index 72% rename from ObjectPrintingTests/SubPerson.cs rename to ObjectPrintingTests/TestHelpers/SubPerson.cs index 93519781..2d656e23 100644 --- a/ObjectPrintingTests/SubPerson.cs +++ b/ObjectPrintingTests/TestHelpers/SubPerson.cs @@ -1,4 +1,4 @@ -namespace ObjectPrintingTests +namespace ObjectPrintingTests.TestHelpers { public class SubPerson { @@ -6,4 +6,4 @@ public class SubPerson public int Age { get; set; } } -} +} \ No newline at end of file diff --git a/ObjectPrintingTests/TestHelpers/Test.cs b/ObjectPrintingTests/TestHelpers/Test.cs new file mode 100644 index 00000000..09344e55 --- /dev/null +++ b/ObjectPrintingTests/TestHelpers/Test.cs @@ -0,0 +1,8 @@ +namespace ObjectPrintingTests.TestHelpers +{ + public class Test + { + public SomethingObject ToSameObject { get; set; } + public SomethingObject ToSameObject2 { get; set; } + } +} \ No newline at end of file From 230d3cbaff77fa038c419a11d5cc3cb72a627047 Mon Sep 17 00:00:00 2001 From: Irina_Yatsenko Date: Wed, 27 Dec 2023 21:21:31 +0500 Subject: [PATCH 11/11] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=81=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D0=B0=D0=B8=20=D0=B8=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ObjectPrinting/Serialization/Serializer.cs | 3 +- .../ObjectPrinterAcceptanceTests.cs | 3 +- ObjectPrintingTests/ObjectPrintingTest.cs | 139 +++++++++++++++++- ObjectPrintingTests/PrinterExtensionsTests.cs | 2 +- 4 files changed, 137 insertions(+), 10 deletions(-) diff --git a/ObjectPrinting/Serialization/Serializer.cs b/ObjectPrinting/Serialization/Serializer.cs index 1af10b4e..9ba98fc6 100644 --- a/ObjectPrinting/Serialization/Serializer.cs +++ b/ObjectPrinting/Serialization/Serializer.cs @@ -16,7 +16,8 @@ public class Serializer private readonly HashSet finalTypes = new HashSet { - typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) + typeof(int), typeof(double), typeof(float), typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid), + typeof(long), typeof(decimal), typeof(char), typeof(byte), typeof(bool), typeof(short) }; private readonly Func handleMaxRecursion; diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs index 6de5c701..ae9fc4ff 100644 --- a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -21,6 +21,7 @@ public void Demo() var actualString = printer.Exclude() .Printing(p => p.Age) .Using(age => (age + 1000).ToString()) + .Wrap(p => p + "1") .And.Printing() .Using(CultureInfo.InvariantCulture) .And.Printing(p => p.Name) @@ -29,7 +30,7 @@ public void Demo() .OnMaxRecursion((_) => throw new ArgumentException()) .PrintToString(person); - actualString.Should().Be($"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = A{Environment.NewLine}\tHeight = 180.5{Environment.NewLine}\tAge = 1019{Environment.NewLine}"); + actualString.Should().Be($"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = A{Environment.NewLine}\tHeight = 180.5{Environment.NewLine}\tAge = 10191{Environment.NewLine}"); } } } \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrintingTest.cs b/ObjectPrintingTests/ObjectPrintingTest.cs index 80c3a872..a7dfa484 100644 --- a/ObjectPrintingTests/ObjectPrintingTest.cs +++ b/ObjectPrintingTests/ObjectPrintingTest.cs @@ -7,11 +7,25 @@ using System.Collections.Generic; using ObjectPrintingTests.TestHelpers; using ObjectPrinting.Serialization; +using ObjectPrinting.Solved.Tests; +using Person = ObjectPrintingTests.TestHelpers.Person; namespace ObjectPrintingTests { public class ObjectPrintingTest { + [Test] + public void WhenPassComplexObject_ShouldReturnCorrectSerializeString() + { + var person = new Person(); + + var printer = person.CreatePrinter(); + + var actual = printer.PrintToString(person); + + actual.Should().Be($"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = null{Environment.NewLine}\tHeight = 0{Environment.NewLine}\tAge = 0{Environment.NewLine}\tSubPerson = null{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); + } + [Test] public void WhenReachedMaxRecursion_ShouldThrowException() { @@ -50,7 +64,7 @@ public void WhenAreNoCircularLinks_ShouldReturnCorrectAnswer() } [Test] - public void WhenObjectRefersToItself_ShouldReturnCorrectAnswer() + public void WhenObjectReferenceToItself_ShouldReturnCorrectAnswer() { var currentObject = new SomethingObject(); currentObject.ToSameObject = currentObject; @@ -64,7 +78,7 @@ public void WhenObjectRefersToItself_ShouldReturnCorrectAnswer() } [Test] - public void ShouldExcludeMember_WhenItsTypeSpecified() + public void WhenItsTypeSpecified_ShouldExcludeMember() { var person = new Person { Name = "Alex", Age = 19 }; @@ -79,7 +93,7 @@ public void ShouldExcludeMember_WhenItsTypeSpecified() } [Test] - public void ShouldUseTrimming_WhenItsSpecifiedForType() + public void WhenItsSpecifiedForType_ShouldUseTrimming() { var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); @@ -94,7 +108,7 @@ public void ShouldUseTrimming_WhenItsSpecifiedForType() } [Test] - public void ShouldSerializeMember_WithGivenFunc() + public void WithGivenFunc_ShouldSerializeMember() { var person = new Person { Name = "Petr", Age = 20, Height = 180 }; var printer = ObjectPrinter.For(); @@ -109,7 +123,7 @@ public void ShouldSerializeMember_WithGivenFunc() } [Test] - public void SetCulture_ShouldAddedCultureInfo() + public void WhenPassCustomSetCulture_ShouldAddedCultureInfo() { var person = new Person { Name = "Petr", Age = 20, Height = 180.5 }; var printer = ObjectPrinter.For(); @@ -214,9 +228,49 @@ public void WhenFieldIsDictionary_ShouldReturnCorrectCollectionSerialization() } [Test] - public void WhenPassCollectionToPrinter_ShouldReturnThisCollectionInString() + public void WhenFieldIsIEnumerable_ShouldReturnCorrectCollectionSerialization() + { + IEnumerable enumerable = new[] { 1,2 }; + + var printer = enumerable.CreatePrinter(); + + var actual = printer + .PrintToString(enumerable); + + actual.Should().Be($"Int32[]{Environment.NewLine}\t1{Environment.NewLine}\t2{Environment.NewLine}"); + } + + [Test] + public void WhenFieldIsComplexObject_ShouldReturnCorrectCollectionSerialization() + { + var person = new Person(); + person.SubPerson = new SubPerson(); + + var printer = person.CreatePrinter(); + + var actual = printer + .PrintToString(person); + + actual.Should().Be($"Person{Environment.NewLine}\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\tName = null{Environment.NewLine}\tHeight = 0{Environment.NewLine}\tAge = 0{Environment.NewLine}\tSubPerson = SubPerson{Environment.NewLine}\t\tPerson = null{Environment.NewLine}\t\tAge = 0{Environment.NewLine}\tPublicField = null{Environment.NewLine}"); + } + + [Test] + public void WhenCollectionElementIsComplexObject_ShouldReturnCorrectCollectionSerialization() { - var dict = new Dictionary() {{1, "один"} }; + var listWithComplexObject = new List () { new Person() }; + + var printer = listWithComplexObject.CreatePrinter(); + + var actual = printer + .PrintToString(listWithComplexObject); + + actual.Should().Be($"List`1{Environment.NewLine}\tPerson{Environment.NewLine}\t\tId = 00000000-0000-0000-0000-000000000000{Environment.NewLine}\t\tName = null{Environment.NewLine}\t\tHeight = 0{Environment.NewLine}\t\tAge = 0{Environment.NewLine}\t\tSubPerson = null{Environment.NewLine}\t\tPublicField = null{Environment.NewLine}"); + } + + [Test] + public void WhenPassDictionaryToPrinter_ShouldReturnThisCollectionInString() + { + var dict = new Dictionary{{1, "один"} }; var printer = dict.CreatePrinter(); @@ -225,6 +279,18 @@ public void WhenPassCollectionToPrinter_ShouldReturnThisCollectionInString() actual.Should().Be($"Dictionary`2{Environment.NewLine}\tKeyValuePair`2{Environment.NewLine}\t\tKey = 1{Environment.NewLine}\t\tValue = один{Environment.NewLine}"); } + [Test] + public void WhenPassListToPrinter_ShouldReturnThisCollectionInString() + { + var list = new List{1.7f, 6.5f}; + + var printer = list.CreatePrinter(); + + var actual = printer.PrintToString(list); + + actual.Should().Be($"List`1{Environment.NewLine}\t1,7{Environment.NewLine}\t6,5{Environment.NewLine}"); + } + [Test] public void WhenToSameObjectInTwoFields_ShouldReturnCorrectResultWithoutRecursion() { @@ -240,5 +306,64 @@ public void WhenToSameObjectInTwoFields_ShouldReturnCorrectResultWithoutRecursio actual.Should().Be($"Test{Environment.NewLine}\tToSameObject = SomethingObject{Environment.NewLine}\t\tToSameObject = null{Environment.NewLine}\t\tCount = 1{Environment.NewLine}\tToSameObject2 = SomethingObject{Environment.NewLine}\t\tToSameObject = null{Environment.NewLine}\t\tCount = 1{Environment.NewLine}"); } + + [Test] + public void WhenPassEmptyCollection_ShouldPrintOnlyCollectionType() + { + var list = new List(); + + var printer = list.CreatePrinter(); + + var actual = printer.PrintToString(list); + + actual.Should().Be($"List`1{Environment.NewLine}"); + + } + + [Test] + public void WhenPassFinalTypeWithCustomSerialization_ShouldReturnCustomSerializationFuncResultString() + { + var currentString = new string("abcd"); + + var printer = currentString.CreatePrinter(); + + var actual = printer + .Printing() + .Trim(3) + .And.PrintToString(currentString); + + actual.Should().Be($"abc{Environment.NewLine}"); + } + + [Test] + public void WhenPassNullToUsing_ShouldThrowNullReferenceExceprion() + { + var currentString = "abc"; + var printer = currentString.CreatePrinter(); + + Action actual = () => { printer + .Printing() + .Using(null) + .And.PrintToString(currentString); }; + + actual.Should().Throw(); + } + + [Test] + public void WhenPassNullToWrap_ShouldThrowNullReferenceExceprion() + { + var currentString = "abc"; + var printer = currentString.CreatePrinter(); + + Action actual = () => { + printer + .Printing() + .Using(p => currentString + 1) + .Wrap(null) + .And.PrintToString(currentString); + }; + + actual.Should().Throw(); + } } } diff --git a/ObjectPrintingTests/PrinterExtensionsTests.cs b/ObjectPrintingTests/PrinterExtensionsTests.cs index 82242c54..27c5c659 100644 --- a/ObjectPrintingTests/PrinterExtensionsTests.cs +++ b/ObjectPrintingTests/PrinterExtensionsTests.cs @@ -8,7 +8,7 @@ namespace ObjectPrintingTests internal class PrinterExtensionsTests { [Test] - public void CreatePrinterWithExtensionMethod_ShouldNotBeNull() + public void WhenCreatePrinterWithExtensionMethod_ShouldNotBeNull() { var person = new Person(); var printer = person.CreatePrinter();