diff --git a/ObjectPrinting/ObjectPrinter.cs b/ObjectPrinting/ObjectPrinter.cs index 3c7867c3..caa93e56 100644 --- a/ObjectPrinting/ObjectPrinter.cs +++ b/ObjectPrinting/ObjectPrinter.cs @@ -1,10 +1,9 @@ -namespace ObjectPrinting +namespace ObjectPrinting; + +public static class ObjectPrinter { - public class ObjectPrinter + public static PrintingConfig For() { - public static PrintingConfig For() - { - return new PrintingConfig(); - } + return new PrintingConfig(); } } \ No newline at end of file diff --git a/ObjectPrinting/ObjectPrinting.csproj b/ObjectPrinting/ObjectPrinting.csproj index 1c5eaf1c..da4f5733 100644 --- a/ObjectPrinting/ObjectPrinting.csproj +++ b/ObjectPrinting/ObjectPrinting.csproj @@ -1,8 +1,8 @@  - 8 - netcoreapp3.1 + 11 + net7.0 false diff --git a/ObjectPrinting/PrintingConfig.cs b/ObjectPrinting/PrintingConfig.cs index a9e08211..35e6f131 100644 --- a/ObjectPrinting/PrintingConfig.cs +++ b/ObjectPrinting/PrintingConfig.cs @@ -1,41 +1,222 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Text; -namespace ObjectPrinting +namespace ObjectPrinting; + +public class PrintingConfig { - public class PrintingConfig + private readonly HashSet excludedTypes = new(); + private readonly Dictionary> customTypeSerialization = new(); + private readonly Dictionary specifiedCultureInfo = new(); + protected readonly Dictionary> CustomMemberSerialization = new(); + protected readonly Dictionary MemberMaxStringLength = new(); + protected readonly HashSet ExcludedMembers = new(); + + private readonly Type[] finalTypes = + { + typeof(int), typeof(double), typeof(float), typeof(string), + typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(uint), + typeof(decimal), typeof(long), typeof(ushort), typeof(ulong), typeof(short) + }; + + public PrintingConfig() + { + } + + protected PrintingConfig(PrintingConfig printingConfig) + { + excludedTypes = printingConfig.excludedTypes; + customTypeSerialization = printingConfig.customTypeSerialization; + specifiedCultureInfo = printingConfig.specifiedCultureInfo; + CustomMemberSerialization = printingConfig.CustomMemberSerialization; + MemberMaxStringLength = printingConfig.MemberMaxStringLength; + ExcludedMembers = printingConfig.ExcludedMembers; + } + + public string PrintToString(TOwner obj) + { + return PrintToString(obj, 0, obj.GetType().Name, new List()); + } + + public PrintingConfig ExcludeType() + { + excludedTypes.Add(typeof(T)); + return this; + } + + public PrintingConfig WithSerializationForType(Func serializationFunc) + { + var type = typeof(T); + customTypeSerialization[type] = obj => serializationFunc((T) obj); + return this; + } + + public PrintingConfig SetCultureForType(CultureInfo cultureInfo) where T : IFormattable { - public string PrintToString(TOwner obj) + var type = typeof(T); + specifiedCultureInfo[type] = cultureInfo; + return this; + } + + public PrintingStringMemberConfig SelectMember(Expression> member) + { + PrintingConfigUtils.ValidateMemberExpression(member); + return new PrintingStringMemberConfig(this, member); + } + + public PrintingMemberConfig SelectMember(Expression> member) + { + PrintingConfigUtils.ValidateMemberExpression(member); + return new PrintingMemberConfig(this, member); + } + + private string PrintWithCultureIfExists(object obj, string initial) + { + if (obj is not IFormattable formattable || + !specifiedCultureInfo.TryGetValue(obj.GetType(), out var cultureInfo)) + return initial; + + return formattable.ToString("", cultureInfo) + Environment.NewLine; + } + + private string PrintToString(object obj, int nestingLevel, string memberPrefix, List parents) + { + if (parents.Contains(obj)) + return "CYCLIC_REFERENCE" + Environment.NewLine; + + if (obj is null) + return "null" + Environment.NewLine; + + if (excludedTypes.Contains(obj.GetType()) || ExcludedMembers.Contains(memberPrefix)) + return ""; + + if (CustomMemberSerialization.TryGetValue(memberPrefix, out var memberSerialization)) + return memberSerialization(obj) + Environment.NewLine; + + if (customTypeSerialization.TryGetValue(obj.GetType(), out var typeSerialization)) + return typeSerialization(obj) + Environment.NewLine; + + if (MemberMaxStringLength.TryGetValue(memberPrefix, out var maxLength)) + return CutString((string) obj, maxLength) + Environment.NewLine; + + if (finalTypes.Contains(obj.GetType())) + return PrintWithCultureIfExists(obj, obj + Environment.NewLine); + + if (obj is IEnumerable enumerable) + return PrintEnumerable(enumerable, nestingLevel, memberPrefix, parents); + + return PrintObjectMembers(obj, nestingLevel, memberPrefix, parents); + } + + private string PrintEnumerable(IEnumerable obj, int nestingLevel, string memberPrefix, List parents) + { + var enumerator = obj.GetEnumerator(); + using var disposable = enumerator as IDisposable; + if (!enumerator.MoveNext()) + return "EMPTY_COLLECTION" + Environment.NewLine; + + if (obj is IList indexed) + return PrintIndexed(indexed, nestingLevel, memberPrefix, parents); + if (obj is IDictionary dictionary) + return PrintDictionary(dictionary, nestingLevel, memberPrefix, parents); + return "NOT_SUPPORTED_COLLECTION" + Environment.NewLine; + } + + private string PrintCollectionElement(string memberPrefix, string itemIdentificator, string indentation, + object element, int nestingLevel, List parents) + { + var sb = new StringBuilder(); + var elementName = memberPrefix + $".get_Item({itemIdentificator})"; + sb.Append(indentation); + sb.Append(PrintToString(element, nestingLevel + 1, elementName, parents)); + sb.Remove(sb.Length - Environment.NewLine.Length, Environment.NewLine.Length); + return sb.ToString(); + } + + private string PrintDictionary(IDictionary dictionary, int nestingLevel, string memberPrefix, List parents) + { + var indentation = new string('\t', nestingLevel + 1); + var sb = new StringBuilder("{" + Environment.NewLine); + foreach (DictionaryEntry entry in dictionary) { - return PrintToString(obj, 0); + sb.Append(PrintCollectionElement(memberPrefix, "DICTIONARY_ELEMENT", indentation, entry, nestingLevel, parents)); + sb.AppendLine(","); } - private string PrintToString(object obj, int nestingLevel) + sb.Remove(sb.Length - Environment.NewLine.Length - 1, Environment.NewLine.Length + 1); + sb.AppendLine(); + sb.AppendLine(indentation[..^1] + "}"); + return sb.ToString(); + } + + private string PrintIndexed(IList indexed, int nestingLevel, string memberPrefix, List parents) + { + var indentation = new string('\t', nestingLevel + 1); + var sb = new StringBuilder("[" + Environment.NewLine); + for (var i = 0; i < indexed.Count; i++) { - //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; - - 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()) - { - sb.Append(identation + propertyInfo.Name + " = " + - PrintToString(propertyInfo.GetValue(obj), - nestingLevel + 1)); - } - return sb.ToString(); + sb.Append(PrintCollectionElement(memberPrefix, i.ToString(), indentation, indexed[i], nestingLevel, parents)); + if (i != indexed.Count - 1) + sb.AppendLine(","); } + + sb.AppendLine(); + sb.AppendLine(indentation[..^1] + "]"); + return sb.ToString(); + } + + private static string CutString(string s, int maxLength) + { + return s.Length > maxLength ? s[..maxLength] : s; + } + + private string PrintObjectMembers(object obj, int nestingLevel, string memberPrefix, List parents) + { + var indentation = new string('\t', nestingLevel + 1); + var objectType = obj.GetType(); + var sb = new StringBuilder().AppendLine(objectType.Name); + + if (memberPrefix != "") + memberPrefix += "."; + + parents.Add(obj); + foreach (var propertyInfo in objectType.GetProperties()) + { + sb.Append(ProcessMember(propertyInfo.PropertyType, propertyInfo.Name, propertyInfo.GetValue(obj), + indentation, + memberPrefix, nestingLevel, parents)); + } + + foreach (var fieldInfo in objectType.GetFields()) + { + sb.Append(ProcessMember(fieldInfo.FieldType, fieldInfo.Name, fieldInfo.GetValue(obj), indentation, + memberPrefix, + nestingLevel, parents)); + } + + parents.Remove(parents.Count - 1); + return sb.ToString(); + } + + private string ProcessMember(Type type, string name, object value, string indentation, string memberPrefix, + int nestingLevel, List parents) + { + var sb = new StringBuilder(); + + if (excludedTypes.Contains(type) || ExcludedMembers.Contains(memberPrefix + name)) + return ""; + + sb.Append(indentation + name + " = "); + + sb.Append(CustomMemberSerialization.TryGetValue(memberPrefix + name, out var serialization) + ? serialization(value) + Environment.NewLine + : PrintToString(value, nestingLevel + 1, memberPrefix + name, parents)); + + return sb.ToString(); } } \ No newline at end of file diff --git a/ObjectPrinting/PrintingConfigUtils.cs b/ObjectPrinting/PrintingConfigUtils.cs new file mode 100644 index 00000000..106f054c --- /dev/null +++ b/ObjectPrinting/PrintingConfigUtils.cs @@ -0,0 +1,13 @@ +using System; +using System.Linq.Expressions; + +namespace ObjectPrinting; + +public static class PrintingConfigUtils +{ + public static void ValidateMemberExpression(Expression> member) + { + if (member.Body.NodeType != ExpressionType.MemberAccess) + throw new MissingMemberException("Type's member has to be selected."); + } +} \ No newline at end of file diff --git a/ObjectPrinting/PrintingMemberConfig.cs b/ObjectPrinting/PrintingMemberConfig.cs new file mode 100644 index 00000000..88ee4f4e --- /dev/null +++ b/ObjectPrinting/PrintingMemberConfig.cs @@ -0,0 +1,29 @@ +using System; +using System.Linq.Expressions; + +namespace ObjectPrinting; + +public class PrintingMemberConfig : PrintingConfig +{ + protected readonly Expression> Member; + + public PrintingMemberConfig(PrintingConfig printingConfig, Expression> member) + : base(printingConfig) + { + Member = member; + } + + public PrintingMemberConfig ExcludeMember() + { + var memberName = PrintingMemberConfigUtils.GetFullMemberName(Member); + ExcludedMembers.Add(memberName); + return this; + } + + public PrintingMemberConfig WithSerialization(Func serializationFunc) + { + var memberName = PrintingMemberConfigUtils.GetFullMemberName(Member); + CustomMemberSerialization[memberName] = obj => serializationFunc((T)obj); + return this; + } +} \ No newline at end of file diff --git a/ObjectPrinting/PrintingMemberConfigUtils.cs b/ObjectPrinting/PrintingMemberConfigUtils.cs new file mode 100644 index 00000000..b9771896 --- /dev/null +++ b/ObjectPrinting/PrintingMemberConfigUtils.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace ObjectPrinting; + +public static class PrintingMemberConfigUtils +{ + public static string GetFullMemberName(Expression> expression) + { + PrintingConfigUtils.ValidateMemberExpression(expression); + var expressionBody = expression.Body; + + var memberNames = new List(); + while (expressionBody != null) + { + switch (expressionBody) + { + case MemberExpression memberExpression: + memberNames.Add(memberExpression.Member.Name); + expressionBody = memberExpression.Expression; + continue; + case MethodCallExpression {Method.Name: "get_Item"} methodCallExpression: + memberNames.Add($"get_Item({methodCallExpression.Arguments[0]})"); + expressionBody = methodCallExpression.Object; + continue; + default: + expressionBody = null; + break; + } + } + + memberNames.Reverse(); + memberNames.Insert(0, typeof(TOwner).Name); + + return string.Join(".", memberNames); + } +} \ No newline at end of file diff --git a/ObjectPrinting/PrintingStringMemberConfig.cs b/ObjectPrinting/PrintingStringMemberConfig.cs new file mode 100644 index 00000000..cba5d078 --- /dev/null +++ b/ObjectPrinting/PrintingStringMemberConfig.cs @@ -0,0 +1,21 @@ +using System; +using System.Linq.Expressions; + +namespace ObjectPrinting; + +public class PrintingStringMemberConfig : PrintingMemberConfig +{ + public PrintingStringMemberConfig(PrintingConfig printingConfig, Expression> member) : base(printingConfig, member) + { + } + + public PrintingStringMemberConfig SetStringMaxLength(int length) + { + if (length < 0) + throw new ArgumentException("Provided string length cannot be negative"); + + var memberName = PrintingMemberConfigUtils.GetFullMemberName(Member); + MemberMaxStringLength[memberName] = length; + return this; + } +} \ No newline at end of file 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/ObjectPrinting/Tests/Person.cs b/ObjectPrinting/Tests/Person.cs deleted file mode 100644 index f9555955..00000000 --- a/ObjectPrinting/Tests/Person.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace ObjectPrinting.Tests -{ - public class Person - { - public Guid Id { get; set; } - public string Name { get; set; } - public double Height { get; set; } - public int Age { get; set; } - } -} \ No newline at end of file diff --git a/ObjectPrintingTests/GlobalUsings.cs b/ObjectPrintingTests/GlobalUsings.cs new file mode 100644 index 00000000..cefced49 --- /dev/null +++ b/ObjectPrintingTests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.AcceptanceTest.verified.txt b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.AcceptanceTest.verified.txt new file mode 100644 index 00000000..be147bbf --- /dev/null +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.AcceptanceTest.verified.txt @@ -0,0 +1,4 @@ +Person + Id = this is guid + Name = Al + Height = 192,8 diff --git a/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs new file mode 100644 index 00000000..054c0819 --- /dev/null +++ b/ObjectPrintingTests/ObjectPrinterAcceptanceTests.cs @@ -0,0 +1,25 @@ +using System.Globalization; +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +[TestFixture] +public class ObjectPrinterAcceptanceTests +{ + [Test] + public async Task AcceptanceTest() + { + var person = new Person(new Guid(), "Alex", 192.8, 33); + + var printer = ObjectPrinter.For() + .ExcludeType() + .SetCultureForType(new CultureInfo("ru")) + .SelectMember(m => m.Name) + .SetStringMaxLength(2) + .SelectMember(m => m.Id) + .WithSerialization(_ => "this is guid"); + + await Verify(printer.PrintToString(person)); + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/ObjectPrintingTests.csproj b/ObjectPrintingTests/ObjectPrintingTests.csproj new file mode 100644 index 00000000..62ab758f --- /dev/null +++ b/ObjectPrintingTests/ObjectPrintingTests.csproj @@ -0,0 +1,59 @@ + + + + net7.0 + enable + enable + + false + true + ObjectPrintingTests + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + PrintingConfigExcludeTypeTests.cs + + + PrintingConfigTypeSerializationTests.cs + + + PrintingConfigTypeSerializationTests.cs + + + PrintingConfigCultureTests.cs + + + PrintingConfigCutStringTests.cs + + + PrintingConfigCutStringTests.cs + + + PrintingConfigEnumerableTests.cs + + + ObjectPrinterAcceptanceTests.cs + + + + diff --git a/ObjectPrintingTests/PrintingConfigCultureTests.SetCultureInfoForType_MakesFloatingPointTypesDisplayComma_WhenCultureInfoIsRu.verified.txt b/ObjectPrintingTests/PrintingConfigCultureTests.SetCultureInfoForType_MakesFloatingPointTypesDisplayComma_WhenCultureInfoIsRu.verified.txt new file mode 100644 index 00000000..fd14c007 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCultureTests.SetCultureInfoForType_MakesFloatingPointTypesDisplayComma_WhenCultureInfoIsRu.verified.txt @@ -0,0 +1,5 @@ +Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Alex + Age = 33 + Height = 192,2 diff --git a/ObjectPrintingTests/PrintingConfigCultureTests.SetCultureInfoForType_OverwritesPreviousCulture_WhenMoreThanOneCultureSpecified.verified.txt b/ObjectPrintingTests/PrintingConfigCultureTests.SetCultureInfoForType_OverwritesPreviousCulture_WhenMoreThanOneCultureSpecified.verified.txt new file mode 100644 index 00000000..e75c780b --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCultureTests.SetCultureInfoForType_OverwritesPreviousCulture_WhenMoreThanOneCultureSpecified.verified.txt @@ -0,0 +1,5 @@ +Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Alex + Age = 33 + Height = 192.2 diff --git a/ObjectPrintingTests/PrintingConfigCultureTests.cs b/ObjectPrintingTests/PrintingConfigCultureTests.cs new file mode 100644 index 00000000..5c501da4 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCultureTests.cs @@ -0,0 +1,32 @@ +using System.Globalization; +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigCultureTests +{ + [Test] + public async Task SetCultureInfoForType_MakesFloatingPointTypesDisplayComma_WhenCultureInfoIsRu() + { + var ruCulture = new CultureInfo("ru"); + + var printer = ObjectPrinter.For() + .SetCultureForType(ruCulture); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } + + [Test] + public async Task SetCultureInfoForType_OverwritesPreviousCulture_WhenMoreThanOneCultureSpecified() + { + var ruCulture = new CultureInfo("ru"); + var enCulture = new CultureInfo("en"); + + var printer = ObjectPrinter.For() + .SetCultureForType(ruCulture) + .SetCultureForType(enCulture); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_OverwritesPreviousCallResult_WhenCalledMoreThanOnce.verified.txt b/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_OverwritesPreviousCallResult_WhenCalledMoreThanOnce.verified.txt new file mode 100644 index 00000000..4cd637d3 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_OverwritesPreviousCallResult_WhenCalledMoreThanOnce.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Iv + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_PrintsCutString_WhenValueLengthIsLessThanMaxLength.verified.txt b/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_PrintsCutString_WhenValueLengthIsLessThanMaxLength.verified.txt new file mode 100644 index 00000000..4cd637d3 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_PrintsCutString_WhenValueLengthIsLessThanMaxLength.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Iv + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_PrintsEntireString_WhenMaxLengthIsGreaterThanValueLength.verified.txt b/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_PrintsEntireString_WhenMaxLengthIsGreaterThanValueLength.verified.txt new file mode 100644 index 00000000..ea8bc74b --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCutStringTests.SetStringMaxLength_PrintsEntireString_WhenMaxLengthIsGreaterThanValueLength.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigCutStringTests.cs b/ObjectPrintingTests/PrintingConfigCutStringTests.cs new file mode 100644 index 00000000..14d9cdfb --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCutStringTests.cs @@ -0,0 +1,49 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigCutStringTests +{ + [Test] + public void SetStringMaxLength_ThrowsArgumentException_WhenProvidedLengthIsNegative() + { + Assert.Throws(() => + { + ObjectPrinter.For() + .SelectMember(p => p.Name) + .SetStringMaxLength(-1); + }); + } + + [Test] + public async Task SetStringMaxLength_PrintsEntireString_WhenMaxLengthIsGreaterThanValueLength() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Name) + .SetStringMaxLength(100); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task SetStringMaxLength_PrintsCutString_WhenValueLengthIsLessThanMaxLength() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Name) + .SetStringMaxLength(2); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task SetStringMaxLength_OverwritesPreviousCallResult_WhenCalledMoreThanOnce() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Name) + .SetStringMaxLength(100) + .SetStringMaxLength(2); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WhenCyclicReferenceIsExcluded.verified.txt b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WhenCyclicReferenceIsExcluded.verified.txt new file mode 100644 index 00000000..26d9f302 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WhenCyclicReferenceIsExcluded.verified.txt @@ -0,0 +1,6 @@ +ComplexPerson + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WithDirectCyclicReference.verified.txt b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WithDirectCyclicReference.verified.txt new file mode 100644 index 00000000..8290b688 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WithDirectCyclicReference.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = CYCLIC_REFERENCE + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WithNestedCyclicReference.verified.txt b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WithNestedCyclicReference.verified.txt new file mode 100644 index 00000000..a1ac7810 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.PrintToString_PrintsCorrectResult_WithNestedCyclicReference.verified.txt @@ -0,0 +1,13 @@ +ComplexPerson + Parent = ComplexPerson + Parent = CYCLIC_REFERENCE + Id = 00000000-0000-0000-0000-000000000000 + Name = Asd + Age = 12 + Height = 0,12 + Weight = 0 + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.cs b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.cs new file mode 100644 index 00000000..af3b71fe --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigCyclicReferenceTests.cs @@ -0,0 +1,47 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigCyclicReferenceTests +{ + [Test] + public async Task PrintToString_PrintsCorrectResult_WithDirectCyclicReference() + { + TestDataFactory.ComplexPerson.Parent = TestDataFactory.ComplexPerson; + + var printer = ObjectPrinter.For(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task PrintToString_PrintsCorrectResult_WithNestedCyclicReference() + { + TestDataFactory.ComplexPerson.Parent = TestDataFactory.Parent; + TestDataFactory.Parent.Parent = TestDataFactory.ComplexPerson; + + var printer = ObjectPrinter.For(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task PrintToString_PrintsCorrectResult_WhenCyclicReferenceIsExcluded() + { + TestDataFactory.ComplexPerson.Parent = TestDataFactory.ComplexPerson; + + var printer = ObjectPrinter.For() + .SelectMember(p => p.Parent) + .ExcludeMember(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [TearDown] + public void TearDown() + { + TestDataFactory.ComplexPerson.Parent = null; + TestDataFactory.Parent.Parent = null; + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_AppliesConfigToCollectionElements_WhenElementsMatchConfig.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_AppliesConfigToCollectionElements_WhenElementsMatchConfig.verified.txt new file mode 100644 index 00000000..3387bcac --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_AppliesConfigToCollectionElements_WhenElementsMatchConfig.verified.txt @@ -0,0 +1,11 @@ +EnumerableTest + Array = [ + 1,2, + 2,12, + 3,2, + 4 + ] + List = [ + ComplexPerson object + ] + Dictionary = this is a dictionary object diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_AppliesConfigToMembersOfIndexedElementsOnly_WhenSpecified.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_AppliesConfigToMembersOfIndexedElementsOnly_WhenSpecified.verified.txt new file mode 100644 index 00000000..3a3b3c34 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_AppliesConfigToMembersOfIndexedElementsOnly_WhenSpecified.verified.txt @@ -0,0 +1,28 @@ +ComplexEnumerable + List = [ + [ + 2 + ], + [ + 2, + 3 + ] + ] + Persons = [ + Person + Id = 00000000-0000-0000-0000-000000000000 + Name = 123123 + Age = 33 + Height = 192,2 + ] + Dictionary = { + DictionaryEntry + Key = asd + Value = ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 + } diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WhenCollectionIsEmpty.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WhenCollectionIsEmpty.verified.txt new file mode 100644 index 00000000..97a83212 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WhenCollectionIsEmpty.verified.txt @@ -0,0 +1,9 @@ +EnumerableTest + Array = [ + 1,2, + 2,12, + 3,2, + 4 + ] + List = EMPTY_COLLECTION + Dictionary = EMPTY_COLLECTION diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WithCollectionElementsWithCyclicReference.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WithCollectionElementsWithCyclicReference.verified.txt new file mode 100644 index 00000000..70ea347e --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WithCollectionElementsWithCyclicReference.verified.txt @@ -0,0 +1,24 @@ +EnumerableTest + Array = [ + 1,2, + 2,12, + 3,2, + 4 + ] + List = [ + ComplexPerson + Parent = CYCLIC_REFERENCE + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 + ] + Dictionary = { + DictionaryEntry + Key = 1 + Value = 01.01.0001 0:00:00, + DictionaryEntry + Key = 3 + Value = 28.02.1988 0:00:00 + } diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WithNestedCollections.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WithNestedCollections.verified.txt new file mode 100644 index 00000000..39e0e09d --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsCorrectResult_WithNestedCollections.verified.txt @@ -0,0 +1,28 @@ +ComplexEnumerable + List = [ + [ + 2 + ], + [ + 2, + 3 + ] + ] + Persons = [ + Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Alex + Age = 33 + Height = 192,2 + ] + Dictionary = { + DictionaryEntry + Key = asd + Value = ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 + } diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsEmptyLine_WhenCollectionIsExcluded.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsEmptyLine_WhenCollectionIsExcluded.verified.txt new file mode 100644 index 00000000..633d257b --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsEmptyLine_WhenCollectionIsExcluded.verified.txt @@ -0,0 +1,15 @@ +EnumerableTest + Array = [ + 1,2, + 2,12, + 3,2, + 4 + ] + Dictionary = { + DictionaryEntry + Key = 1 + Value = 01.01.0001 0:00:00, + DictionaryEntry + Key = 3 + Value = 28.02.1988 0:00:00 + } diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsEmptyLine_WhenTypeOfCollectionElementsIsExcluded.verified.txt b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsEmptyLine_WhenTypeOfCollectionElementsIsExcluded.verified.txt new file mode 100644 index 00000000..f8e21f83 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.PrintToString_PrintsEmptyLine_WhenTypeOfCollectionElementsIsExcluded.verified.txt @@ -0,0 +1,18 @@ +EnumerableTest + Array = [ + 1,2, + 2,12, + 3,2, + 4 + ] + List = [ + + ] + Dictionary = { + DictionaryEntry + Key = 1 + Value = 01.01.0001 0:00:00, + DictionaryEntry + Key = 3 + Value = 28.02.1988 0:00:00 + } diff --git a/ObjectPrintingTests/PrintingConfigEnumerableTests.cs b/ObjectPrintingTests/PrintingConfigEnumerableTests.cs new file mode 100644 index 00000000..6189ac7c --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigEnumerableTests.cs @@ -0,0 +1,81 @@ +using System.Globalization; +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigEnumerableTests +{ + [Test] + public async Task PrintToString_PrintsEmptyLine_WhenCollectionIsExcluded() + { + var printer = ObjectPrinter.For() + .ExcludeType>(); + + await Verify(printer.PrintToString(TestDataFactory.EnumerableSimpleTest)); + } + + [Test] + public async Task PrintToString_PrintsEmptyLine_WhenTypeOfCollectionElementsIsExcluded() + { + var printer = ObjectPrinter.For() + .ExcludeType(); + + await Verify(printer.PrintToString(TestDataFactory.EnumerableSimpleTest)); + } + + [Test] + public async Task PrintToString_PrintsCorrectResult_WhenCollectionIsEmpty() + { + var printer = ObjectPrinter.For(); + + await Verify(printer.PrintToString(TestDataFactory.EnumerableEmptyTest)); + } + + [Test] + public async Task PrintToString_AppliesConfigToCollectionElements_WhenElementsMatchConfig() + { + var printer = ObjectPrinter.For() + .SetCultureForType(new CultureInfo("ru")) + .WithSerializationForType>(_ => "this is a dictionary object") + .WithSerializationForType(_ => "ComplexPerson object"); + + await Verify(printer.PrintToString(TestDataFactory.EnumerableSimpleTest)); + } + + [Test] + public async Task PrintToString_PrintsCorrectResult_WithCollectionElementsWithCyclicReference() + { + TestDataFactory.EnumerableSimpleTest.List[0].Parent = TestDataFactory.EnumerableSimpleTest.List[0]; + + var printer = ObjectPrinter.For(); + + await Verify(printer.PrintToString(TestDataFactory.EnumerableSimpleTest)); + } + + [Test] + public async Task PrintToString_PrintsCorrectResult_WithNestedCollections() + { + var printer = ObjectPrinter.For(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexEnumerable)); + } + + [Test] + public async Task PrintToString_AppliesConfigToMembersOfIndexedElementsOnly_WhenSpecified() + { + var printer = ObjectPrinter.For() + .SelectMember(e => e.Persons[0].Name) + .WithSerialization(_ => "123123") + .SelectMember(e => e.Dictionary["asd"].Age) + .WithSerialization(_ => "age"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexEnumerable)); + } + + [TearDown] + public void TearDown() + { + TestDataFactory.EnumerableSimpleTest.List[0].Parent = null; + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ExcludesBasedOnFullName_WhenMoreThanOneMemberWithSameNameIsPresent.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ExcludesBasedOnFullName_WhenMoreThanOneMemberWithSameNameIsPresent.verified.txt new file mode 100644 index 00000000..62a9be31 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ExcludesBasedOnFullName_WhenMoreThanOneMemberWithSameNameIsPresent.verified.txt @@ -0,0 +1,12 @@ +ComplexPerson + Parent = ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Asd + Height = 0,12 + Weight = 0 + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ReturnsCorrectResult_WhenExcludingComplexType.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ReturnsCorrectResult_WhenExcludingComplexType.verified.txt new file mode 100644 index 00000000..26d9f302 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ReturnsCorrectResult_WhenExcludingComplexType.verified.txt @@ -0,0 +1,6 @@ +ComplexPerson + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ReturnsCorrectResult_WithExcludedMemberOfFinalType.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ReturnsCorrectResult_WithExcludedMemberOfFinalType.verified.txt new file mode 100644 index 00000000..e519d05b --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.ExcludeMember_ReturnsCorrectResult_WithExcludedMemberOfFinalType.verified.txt @@ -0,0 +1,6 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigExcludeMemberTests.cs b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.cs new file mode 100644 index 00000000..2d22bc64 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeMemberTests.cs @@ -0,0 +1,45 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigExcludeMemberTests +{ + [Test] + public async Task ExcludeMember_ReturnsCorrectResult_WithExcludedMemberOfFinalType() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Age) + .ExcludeMember(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task ExcludeMember_ExcludesBasedOnFullName_WhenMoreThanOneMemberWithSameNameIsPresent() + { + TestDataFactory.ComplexPerson.Parent = TestDataFactory.Parent; + + var printer = ObjectPrinter.For() + .SelectMember(p => p.Parent!.Age) + .ExcludeMember(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task ExcludeMember_ReturnsCorrectResult_WhenExcludingComplexType() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Parent) + .ExcludeMember(); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [TearDown] + public void TearDown() + { + TestDataFactory.ComplexPerson.Parent = null; + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_DoesNotAffectResult_WhenExcludingNonPresentType.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_DoesNotAffectResult_WhenExcludingNonPresentType.verified.txt new file mode 100644 index 00000000..fd14c007 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_DoesNotAffectResult_WhenExcludingNonPresentType.verified.txt @@ -0,0 +1,5 @@ +Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Alex + Age = 33 + Height = 192,2 diff --git a/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WhenExcludingForFinalType.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WhenExcludingForFinalType.verified.txt new file mode 100644 index 00000000..30ab4cf8 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WhenExcludingForFinalType.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WithExcludedComplexTypeItself.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WithExcludedComplexTypeItself.verified.txt new file mode 100644 index 00000000..30ab4cf8 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WithExcludedComplexTypeItself.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WithExcludedFinalType.verified.txt b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WithExcludedFinalType.verified.txt new file mode 100644 index 00000000..c9974ee6 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.PrintToString_ReturnsCorrectResult_WithExcludedFinalType.verified.txt @@ -0,0 +1,4 @@ +Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Alex + Height = 192,2 diff --git a/ObjectPrintingTests/PrintingConfigExcludeTypeTests.cs b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.cs new file mode 100644 index 00000000..fcf40765 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigExcludeTypeTests.cs @@ -0,0 +1,43 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigExcludeTypeTests +{ + [Test] + public async Task PrintToString_ReturnsCorrectResult_WithExcludedFinalType() + { + var printer = ObjectPrinter.For() + .ExcludeType(); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } + + [Test] + public async Task PrintToString_ReturnsCorrectResult_WithExcludedComplexTypeItself() + { + var printer = ObjectPrinter.For() + .ExcludeType(); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } + + [Test] + public async Task PrintToString_ReturnsCorrectResult_WhenExcludingForFinalType() + { + var printer = ObjectPrinter.For() + .ExcludeType(); + + await Verify(printer.PrintToString(3)); + } + + [Test] + public async Task PrintToString_DoesNotAffectResult_WhenExcludingNonPresentType() + { + var printer = ObjectPrinter.For() + .ExcludeType(); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_ConsidersFullMemberName_WhenMemberFullNamesDiffer.verified.txt b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_ConsidersFullMemberName_WhenMemberFullNamesDiffer.verified.txt new file mode 100644 index 00000000..ae943435 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_ConsidersFullMemberName_WhenMemberFullNamesDiffer.verified.txt @@ -0,0 +1,13 @@ +ComplexPerson + Parent = ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Asd + Age = 123 + Height = 0,12 + Weight = 0 + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_OverwritesPreviousSerialization_WhenNewSerializationIsProvided.verified.txt b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_OverwritesPreviousSerialization_WhenNewSerializationIsProvided.verified.txt new file mode 100644 index 00000000..1c904ed3 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_OverwritesPreviousSerialization_WhenNewSerializationIsProvided.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 321 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_ReturnsCorrectResult_WhenAlternativeSerializationIsSpecified.verified.txt b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_ReturnsCorrectResult_WhenAlternativeSerializationIsSpecified.verified.txt new file mode 100644 index 00000000..99ab9e22 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_ReturnsCorrectResult_WhenAlternativeSerializationIsSpecified.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 123 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_TakesPrecedence_WhenTypeSerializationIsAlsoSpecified.verified.txt b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_TakesPrecedence_WhenTypeSerializationIsAlsoSpecified.verified.txt new file mode 100644 index 00000000..99ab9e22 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerialization_TakesPrecedence_WhenTypeSerializationIsAlsoSpecified.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 123 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerializtion_ReturnsCorrectResult_WhenSerializationIsSetForMultipleMembers.verified.txt b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerializtion_ReturnsCorrectResult_WhenSerializationIsSetForMultipleMembers.verified.txt new file mode 100644 index 00000000..571afa6f --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerializtion_ReturnsCorrectResult_WhenSerializationIsSetForMultipleMembers.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = null + Id = 00000000-0000-0000-0000-000000000000 + Name = 123 + Age = 123 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerializtion_ReturnsCorrectResult_WithComplexTypeMemberSerialization.verified.txt b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerializtion_ReturnsCorrectResult_WithComplexTypeMemberSerialization.verified.txt new file mode 100644 index 00000000..5f69cb80 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.WithSerializtion_ReturnsCorrectResult_WithComplexTypeMemberSerialization.verified.txt @@ -0,0 +1,7 @@ +ComplexPerson + Parent = custom + Id = 00000000-0000-0000-0000-000000000000 + Name = Ivan + Age = 30 + Height = 190,1 + Weight = 0 diff --git a/ObjectPrintingTests/PrintingConfigMemberSerializationTests.cs b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.cs new file mode 100644 index 00000000..0b5f58b3 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigMemberSerializationTests.cs @@ -0,0 +1,82 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigMemberSerializationTests +{ + [Test] + public async Task WithSerialization_ReturnsCorrectResult_WhenAlternativeSerializationIsSpecified() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Age) + .WithSerialization(_ => "123"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task WithSerialization_OverwritesPreviousSerialization_WhenNewSerializationIsProvided() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Age) + .WithSerialization(_ => "123") + .SelectMember(p => p.Age) + .WithSerialization(_ => "321"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task WithSerialization_ConsidersFullMemberName_WhenMemberFullNamesDiffer() + { + TestDataFactory.ComplexPerson.Parent = TestDataFactory.Parent; + + var printer = ObjectPrinter.For() + .SelectMember(p => p.Parent!.Age) + .WithSerialization(_ => "123"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task WithSerialization_TakesPrecedence_WhenTypeSerializationIsAlsoSpecified() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Age) + .WithSerialization(_ => "123") + .WithSerializationForType(_ => "321"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task WithSerializtion_ReturnsCorrectResult_WithComplexTypeMemberSerialization() + { + TestDataFactory.ComplexPerson.Parent = TestDataFactory.Parent; + + var printer = ObjectPrinter.For() + .SelectMember(p => p.Parent) + .WithSerialization(_ => "custom"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [Test] + public async Task WithSerializtion_ReturnsCorrectResult_WhenSerializationIsSetForMultipleMembers() + { + var printer = ObjectPrinter.For() + .SelectMember(p => p.Age) + .WithSerialization(_ => "123") + .SelectMember(p => p.Name) + .WithSerialization(_ => "123"); + + await Verify(printer.PrintToString(TestDataFactory.ComplexPerson)); + } + + [TearDown] + public void TearDown() + { + TestDataFactory.ComplexPerson.Parent = null; + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigSelectMemberTests.cs b/ObjectPrintingTests/PrintingConfigSelectMemberTests.cs new file mode 100644 index 00000000..642e6f54 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigSelectMemberTests.cs @@ -0,0 +1,17 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigSelectMemberTests +{ + [Test] + public void SelectMember_ThrowsMissingMemberException_WhenInvalidMemberIsSpecified() + { + Assert.Throws(() => + { + ObjectPrinter.For() + .SelectMember(p => "123"); + }); + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_OverwritesPreviousSerialization_WhenNewSerializationIsProvided.verified.txt b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_OverwritesPreviousSerialization_WhenNewSerializationIsProvided.verified.txt new file mode 100644 index 00000000..15062f1d --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_OverwritesPreviousSerialization_WhenNewSerializationIsProvided.verified.txt @@ -0,0 +1,5 @@ +Person + Id = 00000000-0000-0000-0000-000000000000 + Name = second + Age = 33 + Height = 192,2 diff --git a/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenAlternativeComplexTypeSerializationIsSpecified.verified.txt b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenAlternativeComplexTypeSerializationIsSpecified.verified.txt new file mode 100644 index 00000000..4971fa3c --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenAlternativeComplexTypeSerializationIsSpecified.verified.txt @@ -0,0 +1 @@ +This is a "Person" type diff --git a/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenAlternativeFinalTypeSerializationIsSpecified.verified.txt b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenAlternativeFinalTypeSerializationIsSpecified.verified.txt new file mode 100644 index 00000000..2208c035 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenAlternativeFinalTypeSerializationIsSpecified.verified.txt @@ -0,0 +1,5 @@ +Person + Id = 00000000-0000-0000-0000-000000000000 + Name = Misha + Age = 33 + Height = 192,2 diff --git a/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenUsingPropertiesOfComplexType.verified.txt b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenUsingPropertiesOfComplexType.verified.txt new file mode 100644 index 00000000..6d67a767 --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.WithSerializationForType_ReturnsCorrectResult_WhenUsingPropertiesOfComplexType.verified.txt @@ -0,0 +1 @@ +Alex 33 diff --git a/ObjectPrintingTests/PrintingConfigTypeSerializationTests.cs b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.cs new file mode 100644 index 00000000..f1653fda --- /dev/null +++ b/ObjectPrintingTests/PrintingConfigTypeSerializationTests.cs @@ -0,0 +1,44 @@ +using ObjectPrinting; +using ObjectPrintingTests.TestData; + +namespace ObjectPrintingTests; + +public class PrintingConfigTypeSerializationTests +{ + [Test] + public async Task WithSerializationForType_ReturnsCorrectResult_WhenAlternativeFinalTypeSerializationIsSpecified() + { + var printer = ObjectPrinter.For() + .WithSerializationForType(_ => "Misha"); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } + + [Test] + public async Task WithSerializationForType_ReturnsCorrectResult_WhenAlternativeComplexTypeSerializationIsSpecified() + { + var printer = ObjectPrinter.For() + .WithSerializationForType(_ => "This is a \"Person\" type"); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } + + [Test] + public async Task WithSerializationForType_OverwritesPreviousSerialization_WhenNewSerializationIsProvided() + { + var printer = ObjectPrinter.For() + .WithSerializationForType(_ => "first") + .WithSerializationForType(_ => "second"); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } + + [Test] + public async Task WithSerializationForType_ReturnsCorrectResult_WhenUsingPropertiesOfComplexType() + { + var printer = ObjectPrinter.For() + .WithSerializationForType(p => p.Name + " " + p.Age); + + await Verify(printer.PrintToString(TestDataFactory.Person)); + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/TestData/ComplexEnumerable.cs b/ObjectPrintingTests/TestData/ComplexEnumerable.cs new file mode 100644 index 00000000..5f517dfb --- /dev/null +++ b/ObjectPrintingTests/TestData/ComplexEnumerable.cs @@ -0,0 +1,20 @@ +namespace ObjectPrintingTests.TestData; + +public class ComplexEnumerable +{ + public List> List = new() + { + new List {2}, + new List {2, 3} + }; + + public readonly List Persons = new() + { + TestDataFactory.Person + }; + + public readonly Dictionary Dictionary = new() + { + {"asd", TestDataFactory.ComplexPerson} + }; +} \ No newline at end of file diff --git a/ObjectPrintingTests/TestData/ComplexPerson.cs b/ObjectPrintingTests/TestData/ComplexPerson.cs new file mode 100644 index 00000000..75131361 --- /dev/null +++ b/ObjectPrintingTests/TestData/ComplexPerson.cs @@ -0,0 +1,12 @@ +namespace ObjectPrintingTests.TestData; + +public class ComplexPerson : Person +{ + public ComplexPerson? Parent { get; set; } + + public float Weight = 0; + + public ComplexPerson(Guid id, string name, double height, int age) : base(id, name, height, age) + { + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/TestData/EnumerableTest.cs b/ObjectPrintingTests/TestData/EnumerableTest.cs new file mode 100644 index 00000000..2fd9b2cf --- /dev/null +++ b/ObjectPrintingTests/TestData/EnumerableTest.cs @@ -0,0 +1,16 @@ +namespace ObjectPrintingTests.TestData; + +public class EnumerableTest +{ + public readonly double[] Array = {1.2, 2.12, 3.2, 4.0}; + + public readonly List List; + + public Dictionary Dictionary; + + public EnumerableTest(List list, Dictionary dictionary) + { + List = list; + Dictionary = dictionary; + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/TestData/Person.cs b/ObjectPrintingTests/TestData/Person.cs new file mode 100644 index 00000000..5540fb26 --- /dev/null +++ b/ObjectPrintingTests/TestData/Person.cs @@ -0,0 +1,17 @@ +namespace ObjectPrintingTests.TestData; + +public class Person +{ + public Guid Id { get; } + public string Name { get; } + public int Age { get; } + public double Height { get; } + + public Person(Guid id, string name, double height, int age) + { + Id = id; + Name = name; + Height = height; + Age = age; + } +} \ No newline at end of file diff --git a/ObjectPrintingTests/TestData/TestDataFactory.cs b/ObjectPrintingTests/TestData/TestDataFactory.cs new file mode 100644 index 00000000..4fd2e783 --- /dev/null +++ b/ObjectPrintingTests/TestData/TestDataFactory.cs @@ -0,0 +1,18 @@ +namespace ObjectPrintingTests.TestData; + +public static class TestDataFactory +{ + public static readonly Person Person = new(new Guid(), "Alex", 192.2, 33); + + public static readonly ComplexPerson ComplexPerson = new(new Guid(), "Ivan", 190.1, 30); + + public static readonly ComplexPerson Parent = new(new Guid(), "Asd", 0.12, 12); + + public static readonly EnumerableTest EnumerableSimpleTest = new(new List {ComplexPerson}, + new Dictionary {{1, new DateTime(1, 1, 1)}, {3, new DateTime(1988, 2, 28)}}); + + public static readonly EnumerableTest + EnumerableEmptyTest = new(new List(), new Dictionary()); + + public static readonly ComplexEnumerable ComplexEnumerable = new(); +} \ No newline at end of file diff --git a/Samples/FluentMapper/SetterSpec.cs b/Samples/FluentMapper/SetterSpec.cs index 0cd7ac48..f03677d3 100644 --- a/Samples/FluentMapper/SetterSpec.cs +++ b/Samples/FluentMapper/SetterSpec.cs @@ -21,7 +21,7 @@ public sealed class SetterSpec : ISetterSpecProperties spec, PropertyInfo targetProperty - ) + ) { _spec = spec; _targetProperty = targetProperty; @@ -31,7 +31,8 @@ public TypeMappingSpec From(Expression From(Expression x != srcExpr.Member) - .ToArray() - ) - .Transforms().WithTargetProperties( - specProperties.TargetProperties - .Where(x => x != _targetProperty) - .ToArray() - ) + .Transforms().WithMappingActions( + specProperties.MappingActions + .Concat(new[] {setterAction}) + .ToArray() + ) + .Transforms().WithSourceProperties( + specProperties.SourceProperties + .Where(x => x != srcExpr.Member) + .ToArray() + ) + .Transforms().WithTargetProperties( + specProperties.TargetProperties + .Where(x => x != _targetProperty) + .ToArray() + ) ; } diff --git a/fluent-api.sln b/fluent-api.sln index 69c8db9e..418c65a0 100644 --- a/fluent-api.sln +++ b/fluent-api.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentMapping.Tests", "Samp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spectacle", "Samples\Spectacle\Spectacle.csproj", "{EFA9335C-411B-4597-B0B6-5438D1AE04C3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectPrintingTests", "ObjectPrintingTests\ObjectPrintingTests.csproj", "{E0C40C7D-C872-413C-8AE6-6E6ABB0AE5A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -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 + {E0C40C7D-C872-413C-8AE6-6E6ABB0AE5A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0C40C7D-C872-413C-8AE6-6E6ABB0AE5A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0C40C7D-C872-413C-8AE6-6E6ABB0AE5A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0C40C7D-C872-413C-8AE6-6E6ABB0AE5A3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE