From 93a0fe1cbf6d25da6428efbe2b8724773727cd22 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 29 Aug 2022 22:02:19 +0200 Subject: [PATCH 1/9] Prepare next version --- appveyor.yml | 2 +- build/Build.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1a639e8..c85ec8c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ # http://www.appveyor.com/docs/appveyor-yml environment: - base_version: 1.2.3 + base_version: 1.2.4 version: $(base_version).{build} diff --git a/build/Build.cs b/build/Build.cs index 95cf87d..7d6e934 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -39,7 +39,7 @@ class Build : NukeBuild AbsolutePath TestsDirectory => RootDirectory / "Tests"; [Parameter("Version to be injected in the Build")] - public string Version { get; set; } = $"1.2.3"; + public string Version { get; set; } = $"1.2.4"; [Parameter("The Buildnumber provided by the CI")] public string BuildNo = "2"; From e8099bff76124ad776634586032603a740835912 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 10:19:26 +0200 Subject: [PATCH 2/9] Fix codecover issue --- .github/workflows/build.yml | 2 +- build/Build.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 668fe38..e7e59ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} shell: powershell run: | - .\.sonar\scanner\dotnet-sonarscanner begin /k:"WickedFlame_Yaml" /o:"wickedflame" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="src/Tests/YamlMap.Tests/coverage.opencover.xml" + .\.sonar\scanner\dotnet-sonarscanner begin /k:"WickedFlame_Yaml" /o:"wickedflame" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="src/Tests/YamlMap.Tests/coverage.*.opencover.xml" dotnet build dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" diff --git a/build/Build.cs b/build/Build.cs index 7d6e934..b7b628d 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -14,7 +14,6 @@ using static Nuke.Common.IO.PathConstruction; using static Nuke.Common.Tools.DotNet.DotNetTasks; -[CheckBuildProjectConfigurations] [ShutdownDotNetAfterServerBuild] class Build : NukeBuild { From bb3ed6cba34a2d85952548bd6814515c15468808 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 12:46:48 +0200 Subject: [PATCH 3/9] Refactor WickedFlame Yaml to YamlMap --- .../YamlMap.Tests/Reader/YamlReaderArrayTests.cs | 8 ++++---- .../Reader/YamlReaderDictionaryTests.cs | 8 ++++---- .../YamlMap.Tests/Reader/YamlReaderListTests.cs | 6 +++--- .../Serialization/Mappers/ArrayMapperTests.cs | 4 ++-- .../Mappers/GenericDictionaryMapperTests.cs | 6 +++--- .../Mappers/GenericListMapperTests.cs | 6 +++--- .../Serialization/Mappers/MapperFactoryTests.cs | 10 +++++----- .../Serialization/ObjectFactoryTests.cs | 8 ++++---- src/Tests/YamlMap.Tests/YamlFileReaderTests.cs | 2 +- .../YamlReaderArrayElementsTests.cs | 16 ++++++++-------- src/Tests/YamlMap.Tests/YamlWriterTests.cs | 16 ++++++++-------- src/YamlMap/Serialization/ObjectFactory.cs | 2 ++ 12 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/Tests/YamlMap.Tests/Reader/YamlReaderArrayTests.cs b/src/Tests/YamlMap.Tests/Reader/YamlReaderArrayTests.cs index 80fcd53..6565863 100644 --- a/src/Tests/YamlMap.Tests/Reader/YamlReaderArrayTests.cs +++ b/src/Tests/YamlMap.Tests/Reader/YamlReaderArrayTests.cs @@ -9,7 +9,7 @@ namespace YamlMap.Tests.Reader public class YamlReaderArrayTests { [Test] - public void WickedFlame_Yaml_YamlReader_Array() + public void YamlMap_YamlReader_Array() { var lines = new[] { @@ -31,7 +31,7 @@ public void WickedFlame_Yaml_YamlReader_Array() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_Brackets() + public void YamlMap_YamlReader_Array_Brackets() { var lines = new[] { @@ -48,7 +48,7 @@ public void WickedFlame_Yaml_YamlReader_Array_Brackets() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_Object() + public void YamlMap_YamlReader_Array_Object() { var lines = new[] { @@ -68,7 +68,7 @@ public void WickedFlame_Yaml_YamlReader_Array_Object() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_Nested() + public void YamlMap_YamlReader_Array_Nested() { var lines = new[] { diff --git a/src/Tests/YamlMap.Tests/Reader/YamlReaderDictionaryTests.cs b/src/Tests/YamlMap.Tests/Reader/YamlReaderDictionaryTests.cs index 6f8089c..1dc39e8 100644 --- a/src/Tests/YamlMap.Tests/Reader/YamlReaderDictionaryTests.cs +++ b/src/Tests/YamlMap.Tests/Reader/YamlReaderDictionaryTests.cs @@ -10,7 +10,7 @@ namespace YamlMap.Tests.Reader public class YamlReaderDictionaryTests { [Test] - public void WickedFlame_Yaml_YamlReader_Dictionary() + public void YamlMap_YamlReader_Dictionary() { var lines = new[] { @@ -28,7 +28,7 @@ public void WickedFlame_Yaml_YamlReader_Dictionary() } [Test] - public void WickedFlame_Yaml_YamlReader_Dictionary_Interface() + public void YamlMap_YamlReader_Dictionary_Interface() { var lines = new[] { @@ -46,7 +46,7 @@ public void WickedFlame_Yaml_YamlReader_Dictionary_Interface() } [Test] - public void WickedFlame_Yaml_YamlReader_Dictionary_List() + public void YamlMap_YamlReader_Dictionary_List() { // this is a list of object instead of a dictionary // to use dictionary remove the - @@ -62,7 +62,7 @@ public void WickedFlame_Yaml_YamlReader_Dictionary_List() } [Test] - public void WickedFlame_Yaml_YamlReader_Dictionary_Objects() + public void YamlMap_YamlReader_Dictionary_Objects() { var lines = new[] { diff --git a/src/Tests/YamlMap.Tests/Reader/YamlReaderListTests.cs b/src/Tests/YamlMap.Tests/Reader/YamlReaderListTests.cs index d5bb4a9..862f49f 100644 --- a/src/Tests/YamlMap.Tests/Reader/YamlReaderListTests.cs +++ b/src/Tests/YamlMap.Tests/Reader/YamlReaderListTests.cs @@ -10,7 +10,7 @@ namespace YamlMap.Tests.Reader public class YamlReaderListTests { [Test] - public void WickedFlame_Yaml_YamlReader_List() + public void YamlMap_YamlReader_List() { var lines = new[] { @@ -28,7 +28,7 @@ public void WickedFlame_Yaml_YamlReader_List() } [Test] - public void WickedFlame_Yaml_YamlReader_List_Interface() + public void YamlMap_YamlReader_List_Interface() { var lines = new[] { @@ -46,7 +46,7 @@ public void WickedFlame_Yaml_YamlReader_List_Interface() } [Test] - public void WickedFlame_Yaml_YamlReader_List_IEnumerable() + public void YamlMap_YamlReader_List_IEnumerable() { var lines = new[] { diff --git a/src/Tests/YamlMap.Tests/Serialization/Mappers/ArrayMapperTests.cs b/src/Tests/YamlMap.Tests/Serialization/Mappers/ArrayMapperTests.cs index 9e8160a..0102449 100644 --- a/src/Tests/YamlMap.Tests/Serialization/Mappers/ArrayMapperTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/Mappers/ArrayMapperTests.cs @@ -11,7 +11,7 @@ namespace YamlMap.Tests.Serialization.Mappers public class ArrayMapperTests { [Test] - public void WickedFlame_Yaml_Serialization_ArrayMapper_Simple() + public void YamlMap_Serialization_ArrayMapper_Simple() { var token = new ValueToken("Key", "Value", 0); var list = new string[1]; @@ -24,7 +24,7 @@ public void WickedFlame_Yaml_Serialization_ArrayMapper_Simple() } [Test] - public void WickedFlame_Yaml_Serialization_ArrayMapper() + public void YamlMap_Serialization_ArrayMapper() { var token = new Token("tmp", 0); diff --git a/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericDictionaryMapperTests.cs b/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericDictionaryMapperTests.cs index 799a039..7c007db 100644 --- a/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericDictionaryMapperTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericDictionaryMapperTests.cs @@ -11,7 +11,7 @@ namespace YamlMap.Tests.Serialization.Mappers public class GenericDictionaryMapperTests { [Test] - public void WickedFlame_Yaml_Serialization_GenericDictionaryMapper_Simple() + public void YamlMap_Serialization_GenericDictionaryMapper_Simple() { var token = new ValueToken("Key", "Value", 0); var list = new Dictionary(); @@ -24,7 +24,7 @@ public void WickedFlame_Yaml_Serialization_GenericDictionaryMapper_Simple() } [Test] - public void WickedFlame_Yaml_Serialization_GenericDictionaryMapper() + public void YamlMap_Serialization_GenericDictionaryMapper() { var token = new Token("Key", 0); @@ -40,7 +40,7 @@ public void WickedFlame_Yaml_Serialization_GenericDictionaryMapper() } [Test] - public void WickedFlame_Yaml_Serialization_GenericDictionaryMapper_NoDictionary() + public void YamlMap_Serialization_GenericDictionaryMapper_NoDictionary() { var token = new Token("Key", 0); diff --git a/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericListMapperTests.cs b/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericListMapperTests.cs index b12337e..a7d441f 100644 --- a/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericListMapperTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/Mappers/GenericListMapperTests.cs @@ -11,7 +11,7 @@ namespace YamlMap.Tests.Serialization.Mappers public class GenericListMapperTests { [Test] - public void WickedFlame_Yaml_Serialization_GenericListMapper_Simple() + public void YamlMap_Serialization_GenericListMapper_Simple() { var token = new ValueToken("Key", "Value", 0); var list = new List(); @@ -24,7 +24,7 @@ public void WickedFlame_Yaml_Serialization_GenericListMapper_Simple() } [Test] - public void WickedFlame_Yaml_Serialization_GenericListMapper() + public void YamlMap_Serialization_GenericListMapper() { var token = new Token("Key", 0); @@ -40,7 +40,7 @@ public void WickedFlame_Yaml_Serialization_GenericListMapper() } [Test] - public void WickedFlame_Yaml_Serialization_GenericListMapper_NoList() + public void YamlMap_Serialization_GenericListMapper_NoList() { var token = new Token("Key", 0); diff --git a/src/Tests/YamlMap.Tests/Serialization/Mappers/MapperFactoryTests.cs b/src/Tests/YamlMap.Tests/Serialization/Mappers/MapperFactoryTests.cs index 0ecfb9d..18a7405 100644 --- a/src/Tests/YamlMap.Tests/Serialization/Mappers/MapperFactoryTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/Mappers/MapperFactoryTests.cs @@ -12,35 +12,35 @@ namespace YamlMap.Tests.Serialization.Mappers public class MapperFactoryTests { [Test] - public void WickedFlame_Yaml_Serialization_MapperFactory_List() + public void YamlMap_Serialization_MapperFactory_List() { var mapper = MapperFactory.GetObjectMapper(new List(), typeof(MapperItem)); Assert.IsInstanceOf(mapper); } [Test] - public void WickedFlame_Yaml_Serialization_MapperFactory_Dictionary() + public void YamlMap_Serialization_MapperFactory_Dictionary() { var mapper = MapperFactory.GetObjectMapper(new Dictionary(), typeof(MapperItem)); Assert.IsInstanceOf(mapper); } [Test] - public void WickedFlame_Yaml_Serialization_MapperFactory_Array() + public void YamlMap_Serialization_MapperFactory_Array() { var mapper = MapperFactory.GetObjectMapper(new string[] {}, typeof(MapperItem)); Assert.IsInstanceOf(mapper); } [Test] - public void WickedFlame_Yaml_Serialization_MapperFactory_Array2() + public void YamlMap_Serialization_MapperFactory_Array2() { var mapper = MapperFactory.GetObjectMapper(new ArrayList(), typeof(IList)); Assert.IsInstanceOf(mapper); } [Test] - public void WickedFlame_Yaml_Serialization_MapperFactory_Default() + public void YamlMap_Serialization_MapperFactory_Default() { var mapper = MapperFactory.GetObjectMapper(new MapperItem(), typeof(MapperItem)); Assert.IsInstanceOf(mapper); diff --git a/src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs b/src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs index 13e4c5e..6207743 100644 --- a/src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs @@ -18,7 +18,7 @@ public class ObjectFactoryTests [TestCase(typeof(ICollection), typeof(List))] [TestCase(typeof(IDictionary), typeof(Dictionary))] [TestCase(typeof(IDictionary), typeof(Dictionary))] - public void WickedFlame_Yaml_Serialization_ObjectFactory_GenericLists(Type input, Type expected) + public void YamlMap_Serialization_ObjectFactory_GenericLists(Type input, Type expected) { var token = new Token("test", 0); var obj = input.CreateInstance(token); @@ -30,7 +30,7 @@ public void WickedFlame_Yaml_Serialization_ObjectFactory_GenericLists(Type input [TestCase(typeof(IList), typeof(List))] [TestCase(typeof(ICollection), typeof(List))] [TestCase(typeof(IDictionary), typeof(Dictionary))] - public void WickedFlame_Yaml_Serialization_ObjectFactory_NonGenericLists(Type input, Type expected) + public void YamlMap_Serialization_ObjectFactory_NonGenericLists(Type input, Type expected) { var token = new Token("test", 0); var obj = input.CreateInstance(token); @@ -39,7 +39,7 @@ public void WickedFlame_Yaml_Serialization_ObjectFactory_NonGenericLists(Type in } [TestCase(typeof(TestObject), typeof(TestObject))] - public void WickedFlame_Yaml_Serialization_ObjectFactory_BasicObject(Type input, Type expected) + public void YamlMap_Serialization_ObjectFactory_BasicObject(Type input, Type expected) { var token = new Token("test", 0); var obj = input.CreateInstance(token); @@ -48,7 +48,7 @@ public void WickedFlame_Yaml_Serialization_ObjectFactory_BasicObject(Type input, } [Test] - public void WickedFlame_Yaml_Serialization_ObjectFactory_Array() + public void YamlMap_Serialization_ObjectFactory_Array() { var type = typeof(string[]); var token = new Token("test", 0); diff --git a/src/Tests/YamlMap.Tests/YamlFileReaderTests.cs b/src/Tests/YamlMap.Tests/YamlFileReaderTests.cs index 50c894e..088c4b5 100644 --- a/src/Tests/YamlMap.Tests/YamlFileReaderTests.cs +++ b/src/Tests/YamlMap.Tests/YamlFileReaderTests.cs @@ -11,7 +11,7 @@ namespace YamlMap.Tests public class YamlFileReaderTests { [Test] - public void WickedFlame_Yaml_YamlReader_SimpleProperty_Root() + public void YamlMap_YamlReader_SimpleProperty_Root() { var reader = new YamlFileReader(); var data = reader.Read("YamlTest.yml"); diff --git a/src/Tests/YamlMap.Tests/YamlReaderArrayElementsTests.cs b/src/Tests/YamlMap.Tests/YamlReaderArrayElementsTests.cs index 914ea4b..4bf2f3f 100644 --- a/src/Tests/YamlMap.Tests/YamlReaderArrayElementsTests.cs +++ b/src/Tests/YamlMap.Tests/YamlReaderArrayElementsTests.cs @@ -11,7 +11,7 @@ namespace YamlMap.Tests public class YamlReaderArrayElementsTests { [Test] - public void WickedFlame_Yaml_YamlReader_Array_SimpleProperty_Root() + public void YamlMap_YamlReader_Array_SimpleProperty_Root() { var lines = new[] { @@ -25,7 +25,7 @@ public void WickedFlame_Yaml_YamlReader_Array_SimpleProperty_Root() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_ObjectProperty_Root() + public void YamlMap_YamlReader_Array_ObjectProperty_Root() { var lines = new[] { @@ -42,7 +42,7 @@ public void WickedFlame_Yaml_YamlReader_Array_ObjectProperty_Root() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_ObjectProperty_Nested() + public void YamlMap_YamlReader_Array_ObjectProperty_Nested() { var lines = new[] { @@ -62,7 +62,7 @@ public void WickedFlame_Yaml_YamlReader_Array_ObjectProperty_Nested() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_ObjectProperty_AfterNested() + public void YamlMap_YamlReader_Array_ObjectProperty_AfterNested() { var lines = new[] { @@ -80,7 +80,7 @@ public void WickedFlame_Yaml_YamlReader_Array_ObjectProperty_AfterNested() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_StringList() + public void YamlMap_YamlReader_Array_StringList() { var lines = new[] { @@ -101,7 +101,7 @@ public void WickedFlame_Yaml_YamlReader_Array_StringList() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_EnumerableList() + public void YamlMap_YamlReader_Array_EnumerableList() { var lines = new[] { @@ -122,7 +122,7 @@ public void WickedFlame_Yaml_YamlReader_Array_EnumerableList() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_ObjectList() + public void YamlMap_YamlReader_Array_ObjectList() { var lines = new[] { @@ -143,7 +143,7 @@ public void WickedFlame_Yaml_YamlReader_Array_ObjectList() } [Test] - public void WickedFlame_Yaml_YamlReader_Array_NestedObjectList() + public void YamlMap_YamlReader_Array_NestedObjectList() { var lines = new[] { diff --git a/src/Tests/YamlMap.Tests/YamlWriterTests.cs b/src/Tests/YamlMap.Tests/YamlWriterTests.cs index 2483f1c..c3665cc 100644 --- a/src/Tests/YamlMap.Tests/YamlWriterTests.cs +++ b/src/Tests/YamlMap.Tests/YamlWriterTests.cs @@ -9,7 +9,7 @@ namespace YamlMap.Tests public class YamlWriterTests { [Test] - public void WickedFlame_Yaml_YamlWriter() + public void YamlMap_YamlWriter() { var item = new YamlItem { @@ -24,7 +24,7 @@ public void WickedFlame_Yaml_YamlWriter() //TODO: null property [Test] - public void WickedFlame_Yaml_YamlWriter_null() + public void YamlMap_YamlWriter_null() { var item = new YamlItem { @@ -39,7 +39,7 @@ public void WickedFlame_Yaml_YamlWriter_null() //TODO: protected/private property [Test] - public void WickedFlame_Yaml_YamlWriter_Child() + public void YamlMap_YamlWriter_Child() { var item = new YamlItem { @@ -62,7 +62,7 @@ public void WickedFlame_Yaml_YamlWriter_Child() } [Test] - public void WickedFlame_Yaml_YamlWriter_StringArry() + public void YamlMap_YamlWriter_StringArry() { var item = new YamlItem { @@ -83,7 +83,7 @@ public void WickedFlame_Yaml_YamlWriter_StringArry() } [Test] - public void WickedFlame_Yaml_YamlWriter_ObjectList() + public void YamlMap_YamlWriter_ObjectList() { var item = new YamlItem { @@ -109,7 +109,7 @@ public void WickedFlame_Yaml_YamlWriter_ObjectList() } [Test] - public void WickedFlame_Yaml_YamlWriter_String_SpecialChars() + public void YamlMap_YamlWriter_String_SpecialChars() { var reader = new YamlWriter(); var data = reader.Write(new { Value = "tes:one" }); @@ -123,7 +123,7 @@ public void WickedFlame_Yaml_YamlWriter_String_SpecialChars() } [Test] - public void WickedFlame_Yaml_YamlWriter_StringList_SpecialChars() + public void YamlMap_YamlWriter_StringList_SpecialChars() { var reader = new YamlWriter(); var data = reader.Write(new { Values = new[] @@ -143,7 +143,7 @@ public void WickedFlame_Yaml_YamlWriter_StringList_SpecialChars() } [Test] - public void WickedFlame_Yaml_YamlWriter_Type() + public void YamlMap_YamlWriter_Type() { var reader = new YamlWriter(); var data = reader.Write(new { Type = typeof(YamlWriter) }); diff --git a/src/YamlMap/Serialization/ObjectFactory.cs b/src/YamlMap/Serialization/ObjectFactory.cs index 3c2d5dc..bdef03a 100644 --- a/src/YamlMap/Serialization/ObjectFactory.cs +++ b/src/YamlMap/Serialization/ObjectFactory.cs @@ -1,6 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; +using System.Reflection; namespace YamlMap.Serialization { From c3de10d2cbe230a2384560e2d3f8aaca0052f0a6 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 15:50:31 +0200 Subject: [PATCH 4/9] Create instances of types with parameterless constructors --- README.md | 5 + .../Serialization/ConstructorResolverTests.cs | 165 ++++++++++++++++++ ...tFactoryTests.cs => ObjectBuilderTests.cs} | 10 +- ...solver_CreateConstructoParameters.snapshot | 3 + src/Tests/YamlMap.Tests/YamlMap.Tests.csproj | 118 +++++++------ src/YamlMap/Serialization/ContractResolver.cs | 115 ++++++++++++ src/YamlMap/Serialization/IInstanceFactory.cs | 18 ++ src/YamlMap/Serialization/InstanceFactory.cs | 40 +++++ .../{ObjectFactory.cs => ObjectBuilder.cs} | 15 +- src/YamlMap/Serialization/ObjectContract.cs | 26 +++ src/YamlMap/Serialization/TokenSerializer.cs | 2 - src/YamlMap/TokenExtensions.cs | 34 ++++ src/YamlMap/YamlMap.csproj | 1 + src/YamlMap/YamlReader.cs | 4 +- 14 files changed, 485 insertions(+), 71 deletions(-) create mode 100644 src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs rename src/Tests/YamlMap.Tests/Serialization/{ObjectFactoryTests.cs => ObjectBuilderTests.cs} (82%) create mode 100644 src/Tests/YamlMap.Tests/Serialization/_Snapshots/ConstructorResolverTests_ConstructorResolver_CreateConstructoParameters.snapshot create mode 100644 src/YamlMap/Serialization/ContractResolver.cs create mode 100644 src/YamlMap/Serialization/IInstanceFactory.cs create mode 100644 src/YamlMap/Serialization/InstanceFactory.cs rename src/YamlMap/Serialization/{ObjectFactory.cs => ObjectBuilder.cs} (82%) create mode 100644 src/YamlMap/Serialization/ObjectContract.cs create mode 100644 src/YamlMap/TokenExtensions.cs diff --git a/README.md b/README.md index 96e4331..6a108c2 100644 --- a/README.md +++ b/README.md @@ -120,3 +120,8 @@ WrappedText: > ``` +# Best practice +## Deserialing to Object +To deserialize a Yaml to a object, it is best to have a parameterless constructor. +If a object needs to have a constructor with parameters, the parameter names have to be the same as the properties that they are mapped to. +Else YamlMap will not be able to mapt the correct values to the parameters. diff --git a/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs b/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs new file mode 100644 index 0000000..fa7cd42 --- /dev/null +++ b/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs @@ -0,0 +1,165 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using Polaroider; +using YamlMap.Serialization; + +namespace YamlMap.Tests.Serialization +{ + public class ConstructorResolverTests + { + [Test] + public void ConstructorResolver_NoCtor() + { + var resolver = new ContractResolver(); + var contract = resolver.GetConstructor(typeof(NoCtor)); + + contract.Constructor.GetParameters().Should().HaveCount(0); + } + + [Test] + public void ConstructorResolver_WithCtor() + { + var resolver = new ContractResolver(); + var contract = resolver.GetConstructor(typeof(WithCtor)); + + contract.Constructor.GetParameters().Should().HaveCount(2); + } + + [Test] + public void ConstructorResolver_CreateConstructoParameters() + { + var tokens = new[] + { + new ValueToken("test", "fail", 0), + new ValueToken("Id", "1", 0), + new ValueToken("Value", "passed", 0), + new ValueToken("values", "fail", 0) + }; + var resolver = new ContractResolver(); + var contract = resolver.GetConstructor(typeof(WithCtor)); + + resolver.CreateConstructoParameters(contract.Constructor, tokens).MatchSnapshot(); + } + + [Test] + public void ConstructorResolver_CreateConstructoParameters_InvalidType() + { + var tokens = new[] + { + new ValueToken("Id", "fail", 0), + new ValueToken("Value", "passed", 0) + }; + var resolver = new ContractResolver(); + var contract = resolver.GetConstructor(typeof(WithCtor)); + + resolver.CreateConstructoParameters(contract.Constructor, tokens).Should().HaveCount(1); + } + + [Test] + public void ConstructorResolver_CreateConstructoParameters_Primitive() + { + var tokens = new[] + { + new ValueToken("Value", "5", 0) + }; + var resolver = new ContractResolver(); + var contract = resolver.GetConstructor(typeof(int)); + + resolver.CreateConstructoParameters(contract.Constructor, tokens).Should().HaveCount(0); + } + + [Test] + public void InstanceFactory_Create_Simple() + { + var tokens = new[] + { + new ValueToken("Id", "1", 0), + new ValueToken("Value", "passed", 0) + }; + + var factory = new InstanceFactory(); + var obj = factory.CreateInstance(typeof(NoCtor), tokens); + + obj.Invoke().Should().NotBeNull(); + } + + [Test] + public void InstanceFactory_Create_ConstructorParameters() + { + var tokens = new[] + { + new ValueToken("Id", "1", 0), + new ValueToken("Value", "passed", 0) + }; + + var factory = new InstanceFactory(); + var obj = factory.CreateInstance(typeof(WithCtor), tokens); + + obj.Invoke().Should().NotBeNull(); + } + + [Test] + public void InstanceFactory_Create_ConstructorParameters_DefaultFactory() + { + var tokens = new[] + { + new ValueToken("Id", "1", 0), + new ValueToken("Value", "passed", 0) + }; + + InstanceFactory.Factory.CreateInstance(typeof(WithCtor), tokens).Invoke().Should().NotBeNull(); + } + + [Test] + public void InstanceFactory_Create_InvalidParameters() + { + var tokens = new[] + { + new ValueToken("Id", "fail", 0), + new ValueToken("Value", "passed", 0) + }; + + var factory = new InstanceFactory(); + var obj = factory.CreateInstance(typeof(WithCtor), tokens); + + obj.Should().Throw(); + } + + [Test] + public void InstanceFactory_Create_PrimitiveType() + { + var tokens = new[] + { + new ValueToken("Value", "1", 0) + }; + + InstanceFactory.Factory.CreateInstance(typeof(int), tokens).Invoke().Should().Be(0); + } + } + + public class NoCtor + { + public int Id { get; set; } + + public string Value { get; set; } + } + + public class WithCtor + { + public WithCtor(int id) + { + Id = id; + } + + public WithCtor(string value, int id) + { + Value = value; + Id = id; + } + + public int Id { get; set; } + + public string Value { get; set; } + } +} diff --git a/src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs b/src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs similarity index 82% rename from src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs rename to src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs index 6207743..73c4e4e 100644 --- a/src/Tests/YamlMap.Tests/Serialization/ObjectFactoryTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs @@ -8,7 +8,7 @@ namespace YamlMap.Tests.Serialization { [TestFixture] - public class ObjectFactoryTests + public class ObjectBuilderTests { [TestCase(typeof(IEnumerable), typeof(List))] [TestCase(typeof(IEnumerable), typeof(List))] @@ -18,7 +18,7 @@ public class ObjectFactoryTests [TestCase(typeof(ICollection), typeof(List))] [TestCase(typeof(IDictionary), typeof(Dictionary))] [TestCase(typeof(IDictionary), typeof(Dictionary))] - public void YamlMap_Serialization_ObjectFactory_GenericLists(Type input, Type expected) + public void ObjectBuilder_GenericLists(Type input, Type expected) { var token = new Token("test", 0); var obj = input.CreateInstance(token); @@ -30,7 +30,7 @@ public void YamlMap_Serialization_ObjectFactory_GenericLists(Type input, Type ex [TestCase(typeof(IList), typeof(List))] [TestCase(typeof(ICollection), typeof(List))] [TestCase(typeof(IDictionary), typeof(Dictionary))] - public void YamlMap_Serialization_ObjectFactory_NonGenericLists(Type input, Type expected) + public void ObjectBuilder_NonGenericLists(Type input, Type expected) { var token = new Token("test", 0); var obj = input.CreateInstance(token); @@ -39,7 +39,7 @@ public void YamlMap_Serialization_ObjectFactory_NonGenericLists(Type input, Type } [TestCase(typeof(TestObject), typeof(TestObject))] - public void YamlMap_Serialization_ObjectFactory_BasicObject(Type input, Type expected) + public void ObjectBuilder_BasicObject(Type input, Type expected) { var token = new Token("test", 0); var obj = input.CreateInstance(token); @@ -48,7 +48,7 @@ public void YamlMap_Serialization_ObjectFactory_BasicObject(Type input, Type exp } [Test] - public void YamlMap_Serialization_ObjectFactory_Array() + public void ObjectBuilder_Array() { var type = typeof(string[]); var token = new Token("test", 0); diff --git a/src/Tests/YamlMap.Tests/Serialization/_Snapshots/ConstructorResolverTests_ConstructorResolver_CreateConstructoParameters.snapshot b/src/Tests/YamlMap.Tests/Serialization/_Snapshots/ConstructorResolverTests_ConstructorResolver_CreateConstructoParameters.snapshot new file mode 100644 index 0000000..ae0f2a3 --- /dev/null +++ b/src/Tests/YamlMap.Tests/Serialization/_Snapshots/ConstructorResolverTests_ConstructorResolver_CreateConstructoParameters.snapshot @@ -0,0 +1,3 @@ +---data +passed +1 diff --git a/src/Tests/YamlMap.Tests/YamlMap.Tests.csproj b/src/Tests/YamlMap.Tests/YamlMap.Tests.csproj index 103da7d..14c605e 100644 --- a/src/Tests/YamlMap.Tests/YamlMap.Tests.csproj +++ b/src/Tests/YamlMap.Tests/YamlMap.Tests.csproj @@ -1,68 +1,70 @@  - - net6.0;net48 + + net6.0;net48 - false - + false + 9.0 + - - - - - - - - - - + + + + + + + + + + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + - - - + + + - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + - - - Always - - + + + Always + + diff --git a/src/YamlMap/Serialization/ContractResolver.cs b/src/YamlMap/Serialization/ContractResolver.cs new file mode 100644 index 0000000..4c8a645 --- /dev/null +++ b/src/YamlMap/Serialization/ContractResolver.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace YamlMap.Serialization +{ + /// + /// Resolve from + /// + public class ContractResolver + { + /// + /// Extract the Constructor from a + /// + /// + /// + public ObjectContract GetConstructor(Type type) + { + var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Select(c => + new + { + Constructor = c, + Parameters = c.GetParameters() + }) + .OrderBy(c => c.Parameters.Length) + .ToList(); + + if (!ctors.Any()) + { + return new ObjectContract + { + Type = type + }; + } + + if (ctors.Any(p => p.Parameters.Length == 0)) + { + return new ObjectContract + { + Type = type, + Constructor = ctors.First(p => p.Parameters.Length == 0).Constructor + }; + } + + return new ObjectContract + { + Type = type, + Constructor = ctors.Last().Constructor + }; + } + + /// + /// Try to create the parameters for a constructor based on the items in the + /// - Parameters have to be named the sames as the properties that they are assigned to + /// + /// + /// + /// + public object[] CreateConstructoParameters(ConstructorInfo ctor, IToken[] tokens) + { + if (ctor == null) + { + return Array.Empty(); + } + + var parameters = ctor.GetParameters(); + + var parameterCollection = new List(); + + foreach (var parameterInfo in parameters) + { + if (parameterInfo.Name == null) + { + continue; + } + + var token = MatchProperty(tokens, parameterInfo.Name); + + // ensure that property will have a name from matching property or from parameterinfo + // parameterinfo could have no name if generated by a proxy (I'm looking at you Castle) + if (token != null && parameterInfo.Name != null) + { + var converted = TypeConverter.Convert(parameterInfo.ParameterType, token.Value); + if (converted != null) + { + parameterCollection.Add(converted); + } + } + } + + return parameterCollection.ToArray(); + } + + private ValueToken MatchProperty(IEnumerable tokens, string name) + { + // it is possible to generate a member with a null name using Reflection.Emit + // protect against an ArgumentNullException from GetClosestMatchProperty by testing for null here + if (name == null) + { + return null; + } + + var token = tokens.Where(t => t.TokenType == TokenType.Value).FirstOrDefault(t => t.Key.Equals(name, StringComparison.OrdinalIgnoreCase)) as ValueToken; + // must match type as well as name + if (token == null) + { + return null; + } + + return token; + } + } +} diff --git a/src/YamlMap/Serialization/IInstanceFactory.cs b/src/YamlMap/Serialization/IInstanceFactory.cs new file mode 100644 index 0000000..a71ebb0 --- /dev/null +++ b/src/YamlMap/Serialization/IInstanceFactory.cs @@ -0,0 +1,18 @@ +using System; + +namespace YamlMap.Serialization +{ + /// + /// Interface to define a factory for creating instances of types + /// + public interface IInstanceFactory + { + /// + /// Create a instance of the type + /// + /// + /// + /// + Func CreateInstance(Type type, IToken[] tokens); + } +} diff --git a/src/YamlMap/Serialization/InstanceFactory.cs b/src/YamlMap/Serialization/InstanceFactory.cs new file mode 100644 index 0000000..9b6b1bd --- /dev/null +++ b/src/YamlMap/Serialization/InstanceFactory.cs @@ -0,0 +1,40 @@ +using System; + +namespace YamlMap.Serialization +{ + /// + /// Default factory to create instances of objects + /// + public class InstanceFactory : IInstanceFactory + { + /// + /// Singleton instance of the factory + /// + public static IInstanceFactory Factory { get; } = new InstanceFactory(); + + /// + /// Create an instance of the type + /// + /// + /// + /// + public Func CreateInstance(Type type, IToken[] tokens) + { + var resolver = new ContractResolver(); + var contract = resolver.GetConstructor(type); + contract.Parameters = resolver.CreateConstructoParameters(contract.Constructor, tokens); + + return () => CreateInstance(contract); + } + + private object CreateInstance(ObjectContract contract) + { + if (contract.Parameters != null && contract.Parameters.Length == 0) + { + return Activator.CreateInstance(contract.Type); + } + + return Activator.CreateInstance(contract.Type, contract.Parameters); + } + } +} diff --git a/src/YamlMap/Serialization/ObjectFactory.cs b/src/YamlMap/Serialization/ObjectBuilder.cs similarity index 82% rename from src/YamlMap/Serialization/ObjectFactory.cs rename to src/YamlMap/Serialization/ObjectBuilder.cs index bdef03a..194f2ad 100644 --- a/src/YamlMap/Serialization/ObjectFactory.cs +++ b/src/YamlMap/Serialization/ObjectBuilder.cs @@ -1,15 +1,13 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Reflection; namespace YamlMap.Serialization { /// /// Factory Class that generates instances of a type /// - public static class ObjectFactory + public static class ObjectBuilder { private static readonly Dictionary genericInterfaceImplementations = new Dictionary { @@ -27,6 +25,13 @@ public static class ObjectFactory { typeof(IDictionary), typeof(Dictionary) } }; + /// + /// Create a instance of the type + /// + /// + /// + /// + /// public static object CreateInstance(this Type type, IToken token) { if (type.IsArray) @@ -72,7 +77,9 @@ public static object CreateInstance(this Type type, IToken token) try { - return Activator.CreateInstance(type); + //return Activator.CreateInstance(type); + + return InstanceFactory.Factory.CreateInstance(type, token.GetChildTokens()).Invoke(); } catch (Exception e) { diff --git a/src/YamlMap/Serialization/ObjectContract.cs b/src/YamlMap/Serialization/ObjectContract.cs new file mode 100644 index 0000000..37edf1a --- /dev/null +++ b/src/YamlMap/Serialization/ObjectContract.cs @@ -0,0 +1,26 @@ +using System; +using System.Reflection; + +namespace YamlMap.Serialization +{ + /// + /// Objectcontract for creating objects + /// + public class ObjectContract + { + /// + /// Gets the type that the object is of + /// + public Type Type { get; set; } + + /// + /// Gets the for creating the new object + /// + public ConstructorInfo Constructor { get; set; } + + /// + /// Gets a array of parameters used to create the object + /// + public object[] Parameters { get; set; } + } +} diff --git a/src/YamlMap/Serialization/TokenSerializer.cs b/src/YamlMap/Serialization/TokenSerializer.cs index 24ec1ed..0f62e3a 100644 --- a/src/YamlMap/Serialization/TokenSerializer.cs +++ b/src/YamlMap/Serialization/TokenSerializer.cs @@ -1,8 +1,6 @@ using System; using System.Collections; -using System.Linq; using System.Text; -using System.Xml.Schema; namespace YamlMap.Serialization { diff --git a/src/YamlMap/TokenExtensions.cs b/src/YamlMap/TokenExtensions.cs new file mode 100644 index 0000000..7d684ab --- /dev/null +++ b/src/YamlMap/TokenExtensions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace YamlMap +{ + /// + /// Extensions for + /// + public static class TokenExtensions + { + /// + /// Gets all the childtokens from th + /// + /// + /// + public static IToken[] GetChildTokens(this IToken token) + { + if (token.Count == 0) + { + return Array.Empty(); + } + + var tokens = new IToken[token.Count]; + + for (var i = 0; i < token.Count; i++) + { + tokens[i] = token[i]; + } + + return tokens; + } + } +} diff --git a/src/YamlMap/YamlMap.csproj b/src/YamlMap/YamlMap.csproj index d64d500..3e81ab6 100644 --- a/src/YamlMap/YamlMap.csproj +++ b/src/YamlMap/YamlMap.csproj @@ -25,6 +25,7 @@ 1.0.0 1.0.0.0 1.0.0 + 9.0 diff --git a/src/YamlMap/YamlReader.cs b/src/YamlMap/YamlReader.cs index 5968cff..37d1ce5 100644 --- a/src/YamlMap/YamlReader.cs +++ b/src/YamlMap/YamlReader.cs @@ -56,12 +56,12 @@ public object Read(Type type, string yaml) /// public object Read(Type type, string[] lines) { - var deserializer = new TokenDeserializer(type, null); - var scanner = new Scanner(lines); var parser = new Parser(scanner); var tokens = parser.Parse(); + var deserializer = new TokenDeserializer(type, tokens); + for (var i = 0; i < tokens.Count; i++) { deserializer.Deserialize(tokens[i]); From 3b37e62578df58264d7a8308cefdcd32bffc7759 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 16:06:45 +0200 Subject: [PATCH 5/9] Added a changelog --- .gitignore | 1 + CHANGELOG.md | 24 ++++++++++++++++++++++++ YamlMap.sln | 1 + 3 files changed, 26 insertions(+) create mode 100644 CHANGELOG.md diff --git a/.gitignore b/.gitignore index 3e759b7..a638aa2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.user *.userosscache *.sln.docstates +*.lutconfig # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..032a49e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] - yyyy-mm-dd + +### Added +- Create instances of types with parameterless constructors + +### Changed + +### Fixed + +## [1.2.3] - 2022-08-15 + +### Added + +### Changed +- Downgrade to netstandard2.0 instead of netstandard2.1 +- Update building to use [https://nuke.build/](https://nuke.build/) + +### Fixed \ No newline at end of file diff --git a/YamlMap.sln b/YamlMap.sln index 937f238..f476d4b 100644 --- a/YamlMap.sln +++ b/YamlMap.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .travis.yml = .travis.yml appveyor.yml = appveyor.yml .github\workflows\build.yml = .github\workflows\build.yml + CHANGELOG.md = CHANGELOG.md LICENSE = LICENSE .github\workflows\linux.yml = .github\workflows\linux.yml README.md = README.md From b8f37763d398ae2761dc460da63226e742cb3887 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 18:01:15 +0200 Subject: [PATCH 6/9] Sonar - Reflection should not be used to increase accessibility of classes, methods, or fields --- src/YamlMap/Serialization/ContractResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YamlMap/Serialization/ContractResolver.cs b/src/YamlMap/Serialization/ContractResolver.cs index 4c8a645..6d085ab 100644 --- a/src/YamlMap/Serialization/ContractResolver.cs +++ b/src/YamlMap/Serialization/ContractResolver.cs @@ -17,7 +17,7 @@ public class ContractResolver /// public ObjectContract GetConstructor(Type type) { - var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public) .Select(c => new { From 88dc602b61135da6e5a3a7f6327281c33c9838e1 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 20:15:15 +0200 Subject: [PATCH 7/9] Extract Instancefactories from ObjectBuilder --- .../ArrayInstanceFactoryTests.cs | 28 ++++++++ .../Serialization/ConstructorResolverTests.cs | 68 ------------------- .../Serialization/InstanceFactoryTests.cs | 68 +++++++++++++++++++ .../Serialization/ObjectBuilderTests.cs | 31 +++++++++ .../Serialization/ArrayInstanceFactory.cs | 26 +++++++ .../GenericTypeInstanceFactory.cs | 34 ++++++++++ src/YamlMap/Serialization/IInstanceFactory.cs | 4 +- src/YamlMap/Serialization/InstanceFactory.cs | 6 +- src/YamlMap/Serialization/ObjectBuilder.cs | 20 ++---- src/YamlMap/TokenExtensions.cs | 2 - 10 files changed, 199 insertions(+), 88 deletions(-) create mode 100644 src/Tests/YamlMap.Tests/Serialization/ArrayInstanceFactoryTests.cs create mode 100644 src/Tests/YamlMap.Tests/Serialization/InstanceFactoryTests.cs create mode 100644 src/YamlMap/Serialization/ArrayInstanceFactory.cs create mode 100644 src/YamlMap/Serialization/GenericTypeInstanceFactory.cs diff --git a/src/Tests/YamlMap.Tests/Serialization/ArrayInstanceFactoryTests.cs b/src/Tests/YamlMap.Tests/Serialization/ArrayInstanceFactoryTests.cs new file mode 100644 index 0000000..1c1148f --- /dev/null +++ b/src/Tests/YamlMap.Tests/Serialization/ArrayInstanceFactoryTests.cs @@ -0,0 +1,28 @@ +using FluentAssertions; +using NUnit.Framework; +using YamlMap.Serialization; + +namespace YamlMap.Tests.Serialization +{ + public class ArrayInstanceFactoryTests + { + [Test] + public void ArrayInstanceFactory_Type() + { + var token = new Token("", 0); + token.Set(new ValueToken("Value", "1", 0)); + + ArrayInstanceFactory.Factory.CreateInstance(typeof(int[]), token).Invoke().Should().BeAssignableTo(); + } + + [Test] + public void ArrayInstanceFactory_Length() + { + var token = new Token("", 0); + token.Set(new ValueToken("Value1", "1", 0)); + token.Set(new ValueToken("Value2", "2", 0)); + + ((int[][])ArrayInstanceFactory.Factory.CreateInstance(typeof(int[]), token).Invoke()).Should().HaveCount(2); + } + } +} diff --git a/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs b/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs index fa7cd42..5c88914 100644 --- a/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/ConstructorResolverTests.cs @@ -68,74 +68,6 @@ public void ConstructorResolver_CreateConstructoParameters_Primitive() resolver.CreateConstructoParameters(contract.Constructor, tokens).Should().HaveCount(0); } - - [Test] - public void InstanceFactory_Create_Simple() - { - var tokens = new[] - { - new ValueToken("Id", "1", 0), - new ValueToken("Value", "passed", 0) - }; - - var factory = new InstanceFactory(); - var obj = factory.CreateInstance(typeof(NoCtor), tokens); - - obj.Invoke().Should().NotBeNull(); - } - - [Test] - public void InstanceFactory_Create_ConstructorParameters() - { - var tokens = new[] - { - new ValueToken("Id", "1", 0), - new ValueToken("Value", "passed", 0) - }; - - var factory = new InstanceFactory(); - var obj = factory.CreateInstance(typeof(WithCtor), tokens); - - obj.Invoke().Should().NotBeNull(); - } - - [Test] - public void InstanceFactory_Create_ConstructorParameters_DefaultFactory() - { - var tokens = new[] - { - new ValueToken("Id", "1", 0), - new ValueToken("Value", "passed", 0) - }; - - InstanceFactory.Factory.CreateInstance(typeof(WithCtor), tokens).Invoke().Should().NotBeNull(); - } - - [Test] - public void InstanceFactory_Create_InvalidParameters() - { - var tokens = new[] - { - new ValueToken("Id", "fail", 0), - new ValueToken("Value", "passed", 0) - }; - - var factory = new InstanceFactory(); - var obj = factory.CreateInstance(typeof(WithCtor), tokens); - - obj.Should().Throw(); - } - - [Test] - public void InstanceFactory_Create_PrimitiveType() - { - var tokens = new[] - { - new ValueToken("Value", "1", 0) - }; - - InstanceFactory.Factory.CreateInstance(typeof(int), tokens).Invoke().Should().Be(0); - } } public class NoCtor diff --git a/src/Tests/YamlMap.Tests/Serialization/InstanceFactoryTests.cs b/src/Tests/YamlMap.Tests/Serialization/InstanceFactoryTests.cs new file mode 100644 index 0000000..16187c6 --- /dev/null +++ b/src/Tests/YamlMap.Tests/Serialization/InstanceFactoryTests.cs @@ -0,0 +1,68 @@ +using NUnit.Framework; +using System; +using FluentAssertions; +using YamlMap.Serialization; + +namespace YamlMap.Tests.Serialization +{ + public class InstanceFactoryTests + { + [Test] + public void InstanceFactory_Create_Simple() + { + var token = new Token("", 0); + token.Set(new ValueToken("Id", "1", 0)); + token.Set(new ValueToken("Value", "passed", 0)); + + var factory = new InstanceFactory(); + var obj = factory.CreateInstance(typeof(NoCtor), token); + + obj.Invoke().Should().NotBeNull(); + } + + [Test] + public void InstanceFactory_Create_ConstructorParameters() + { + var token = new Token("", 0); + token.Set(new ValueToken("Id", "1", 0)); + token.Set(new ValueToken("Value", "passed", 0)); + + var factory = new InstanceFactory(); + var obj = factory.CreateInstance(typeof(WithCtor), token); + + obj.Invoke().Should().NotBeNull(); + } + + [Test] + public void InstanceFactory_Create_ConstructorParameters_DefaultFactory() + { + var token = new Token("", 0); + token.Set(new ValueToken("Id", "1", 0)); + token.Set(new ValueToken("Value", "passed", 0)); + + InstanceFactory.Factory.CreateInstance(typeof(WithCtor), token).Invoke().Should().NotBeNull(); + } + + [Test] + public void InstanceFactory_Create_InvalidParameters() + { + var token = new Token("", 0); + token.Set(new ValueToken("Id", "fail", 0)); + token.Set(new ValueToken("Value", "passed", 0)); + + var factory = new InstanceFactory(); + var obj = factory.CreateInstance(typeof(WithCtor), token); + + obj.Should().Throw(); + } + + [Test] + public void InstanceFactory_Create_PrimitiveType() + { + var token = new Token("", 0); + token.Set(new ValueToken("Value", "1", 0)); + + InstanceFactory.Factory.CreateInstance(typeof(int), token).Invoke().Should().Be(0); + } + } +} diff --git a/src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs b/src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs index 73c4e4e..274d80b 100644 --- a/src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs +++ b/src/Tests/YamlMap.Tests/Serialization/ObjectBuilderTests.cs @@ -2,8 +2,10 @@ using System.Collections; using System.Collections.Generic; using System.Text; +using FluentAssertions; using NUnit.Framework; using YamlMap.Serialization; +using static YamlMap.Tests.Serialization.ObjectBuilderTests; namespace YamlMap.Tests.Serialization { @@ -62,6 +64,35 @@ public void ObjectBuilder_Array() Assert.AreEqual(3, ((IList) obj).Count); } + [Test] + public void ObjectBuilder_Generics() + { + var type = typeof(GenericTest); + var token = new Token("test", 1); + + var obj = type.CreateInstance(token); + + obj.Should().NotBeNull(); + obj.Should().BeAssignableTo>(); + } + + [Test] + public void ObjectBuilder_GenericTypeDefinition() + { + var type = typeof(GenericTest<>); + var token = new Token("test", 1); + + var obj = type.CreateInstance(token); + + obj.Should().NotBeNull(); + obj.Should().BeAssignableTo>(); + } + public class TestObject { } + + public class GenericTest + { + public int Test { get; set; } + } } } diff --git a/src/YamlMap/Serialization/ArrayInstanceFactory.cs b/src/YamlMap/Serialization/ArrayInstanceFactory.cs new file mode 100644 index 0000000..fdf4c64 --- /dev/null +++ b/src/YamlMap/Serialization/ArrayInstanceFactory.cs @@ -0,0 +1,26 @@ +using System; + +namespace YamlMap.Serialization +{ + /// + /// Default factory to create instances of arrays + /// + public class ArrayInstanceFactory : IInstanceFactory + { + /// + /// Singleton instance of the factory + /// + public static IInstanceFactory Factory { get; } = new ArrayInstanceFactory(); + + /// + /// Create an instance of the type + /// + /// + /// + /// + public Func CreateInstance(Type type, IToken token) + { + return () => Array.CreateInstance(type, token.Count); + } + } +} diff --git a/src/YamlMap/Serialization/GenericTypeInstanceFactory.cs b/src/YamlMap/Serialization/GenericTypeInstanceFactory.cs new file mode 100644 index 0000000..162297e --- /dev/null +++ b/src/YamlMap/Serialization/GenericTypeInstanceFactory.cs @@ -0,0 +1,34 @@ +using System; + +namespace YamlMap.Serialization +{ + /// + /// Default factory to create instances of Generic Types + /// + public class GenericTypeInstanceFactory : IInstanceFactory + { + /// + /// Singleton instance of the factory + /// + public static IInstanceFactory Factory { get; } = new GenericTypeInstanceFactory(); + + /// + /// Create an instance of the type + /// + /// + /// + /// + public Func CreateInstance(Type type, IToken token) + { + var genericArgs = type.GetGenericArguments(); + var typeArgs = new Type[genericArgs.Length]; + for (var i = 0; i < genericArgs.Length; i++) + { + typeArgs[i] = typeof(object); + } + + var realizedType = type.MakeGenericType(typeArgs); + return () => realizedType.CreateInstance(token); + } + } +} diff --git a/src/YamlMap/Serialization/IInstanceFactory.cs b/src/YamlMap/Serialization/IInstanceFactory.cs index a71ebb0..ba57acc 100644 --- a/src/YamlMap/Serialization/IInstanceFactory.cs +++ b/src/YamlMap/Serialization/IInstanceFactory.cs @@ -11,8 +11,8 @@ public interface IInstanceFactory /// Create a instance of the type /// /// - /// + /// /// - Func CreateInstance(Type type, IToken[] tokens); + Func CreateInstance(Type type, IToken token); } } diff --git a/src/YamlMap/Serialization/InstanceFactory.cs b/src/YamlMap/Serialization/InstanceFactory.cs index 9b6b1bd..43c3e3b 100644 --- a/src/YamlMap/Serialization/InstanceFactory.cs +++ b/src/YamlMap/Serialization/InstanceFactory.cs @@ -16,13 +16,13 @@ public class InstanceFactory : IInstanceFactory /// Create an instance of the type /// /// - /// + /// /// - public Func CreateInstance(Type type, IToken[] tokens) + public Func CreateInstance(Type type, IToken token) { var resolver = new ContractResolver(); var contract = resolver.GetConstructor(type); - contract.Parameters = resolver.CreateConstructoParameters(contract.Constructor, tokens); + contract.Parameters = resolver.CreateConstructoParameters(contract.Constructor, token.GetChildTokens()); return () => CreateInstance(contract); } diff --git a/src/YamlMap/Serialization/ObjectBuilder.cs b/src/YamlMap/Serialization/ObjectBuilder.cs index 194f2ad..5d0ae86 100644 --- a/src/YamlMap/Serialization/ObjectBuilder.cs +++ b/src/YamlMap/Serialization/ObjectBuilder.cs @@ -36,20 +36,16 @@ public static object CreateInstance(this Type type, IToken token) { if (type.IsArray) { - return Array.CreateInstance(type.GetElementType(), token.Count); + var arrayType = type.GetElementType(); + if(arrayType != null) + { + return ArrayInstanceFactory.Factory.CreateInstance(arrayType, token).Invoke(); + } } if (type.IsGenericTypeDefinition) { - var genericArgs = type.GetGenericArguments(); - var typeArgs = new Type[genericArgs.Length]; - for (var i = 0; i < genericArgs.Length; i++) - { - typeArgs[i] = typeof(object); - } - - var realizedType = type.MakeGenericType(typeArgs); - return realizedType.CreateInstance(token); + return GenericTypeInstanceFactory.Factory.CreateInstance(type, token).Invoke(); } if (type.IsInterface) @@ -77,9 +73,7 @@ public static object CreateInstance(this Type type, IToken token) try { - //return Activator.CreateInstance(type); - - return InstanceFactory.Factory.CreateInstance(type, token.GetChildTokens()).Invoke(); + return InstanceFactory.Factory.CreateInstance(type, token).Invoke(); } catch (Exception e) { diff --git a/src/YamlMap/TokenExtensions.cs b/src/YamlMap/TokenExtensions.cs index 7d684ab..9402bd3 100644 --- a/src/YamlMap/TokenExtensions.cs +++ b/src/YamlMap/TokenExtensions.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; namespace YamlMap { From ba734c0bdaf30d7add585c413bebb0765062a578 Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 21:54:16 +0200 Subject: [PATCH 8/9] Added benchmarks --- YamlMap.sln | 7 ++ src/Tests/YamlMap.Benchmark/Program.cs | 38 +++++++++++ src/Tests/YamlMap.Benchmark/Results.md | 67 +++++++++++++++++++ src/Tests/YamlMap.Benchmark/TestItem.cs | 25 +++++++ .../YamlMap.Benchmark.csproj | 18 +++++ 5 files changed, 155 insertions(+) create mode 100644 src/Tests/YamlMap.Benchmark/Program.cs create mode 100644 src/Tests/YamlMap.Benchmark/Results.md create mode 100644 src/Tests/YamlMap.Benchmark/TestItem.cs create mode 100644 src/Tests/YamlMap.Benchmark/YamlMap.Benchmark.csproj diff --git a/YamlMap.sln b/YamlMap.sln index f476d4b..0bb2660 100644 --- a/YamlMap.sln +++ b/YamlMap.sln @@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{61A95099 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{720AA512-BFE2-4345-A1ED-2D3B2D91F4B2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlMap.Benchmark", "src\Tests\YamlMap.Benchmark\YamlMap.Benchmark.csproj", "{7FFE3802-EDF9-4764-8259-BD0B9142C9FD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {4FF32EEA-66F0-4A99-8D95-7D1E5A6E0CF4}.Release|Any CPU.Build.0 = Release|Any CPU {720AA512-BFE2-4345-A1ED-2D3B2D91F4B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {720AA512-BFE2-4345-A1ED-2D3B2D91F4B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7FFE3802-EDF9-4764-8259-BD0B9142C9FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7FFE3802-EDF9-4764-8259-BD0B9142C9FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7FFE3802-EDF9-4764-8259-BD0B9142C9FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7FFE3802-EDF9-4764-8259-BD0B9142C9FD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -46,6 +52,7 @@ Global GlobalSection(NestedProjects) = preSolution {4FF32EEA-66F0-4A99-8D95-7D1E5A6E0CF4} = {61A95099-5D81-4BE8-AFA3-C1779E02A7AF} {720AA512-BFE2-4345-A1ED-2D3B2D91F4B2} = {B215E0CA-21DD-453C-89E7-D39337E6215D} + {7FFE3802-EDF9-4764-8259-BD0B9142C9FD} = {61A95099-5D81-4BE8-AFA3-C1779E02A7AF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FAEBE709-29D8-48BA-91F8-ABF8E2471FAD} diff --git a/src/Tests/YamlMap.Benchmark/Program.cs b/src/Tests/YamlMap.Benchmark/Program.cs new file mode 100644 index 0000000..d68daa7 --- /dev/null +++ b/src/Tests/YamlMap.Benchmark/Program.cs @@ -0,0 +1,38 @@ +// See https://aka.ms/new-console-template for more information + +using MeasureMap; +using System.Text; +using YamlMap; +using YamlMap.Benchmark; + +var value = new StringBuilder().AppendLine("Simple: root") + .AppendLine("StringList:") + .AppendLine(" - one") + .AppendLine(" - 2") + .AppendLine("ObjList:") + .AppendLine(" - Simple: simple") + .AppendLine(" - Child:") + .AppendLine(" Simple: child").ToString(); + + +ProfilerSession.StartSession() + .SetIterations(10) + .SetThreads(10) + .Task(c => + { + var reader = new YamlReader(); + reader.Read(value); + }) + .RunSession() + .Trace(); + + +//ProfilerSession.StartSession() +// .SetIterations(10) +// .Task(c => +// { +// var reader = new YamlReader(); +// reader.Read(value); +// }) +// .RunSession() +// .Trace(); \ No newline at end of file diff --git a/src/Tests/YamlMap.Benchmark/Results.md b/src/Tests/YamlMap.Benchmark/Results.md new file mode 100644 index 0000000..06c2dee --- /dev/null +++ b/src/Tests/YamlMap.Benchmark/Results.md @@ -0,0 +1,67 @@ + + + +# MeasureMap - v1.2.4 +## Summary +| Category | Metric | Value | +| --- | --- | ---: | +| Warmup | Duration Warmup | 00:00:00.0850161 | +| Setup | Threads | 10 | +| | Iterations | 100 | +| Duration | Duration | 00:00:00.2859164 | +| | Total Time | 00:00:00.5425069 | +| | Average Time | 00:00:00.0054250 | +| | Average Milliseconds | 5.425 ms | +| | Throughput | 349.75259/s | +| | Fastest | 00:00:00.0003884 | +| | Slowest | 00:00:00.0147817 | +| Memory | Memory Initial size | 128336 | +| | Memory End size | 185048 | +| | Memory Increase | 56712 | + +## Details per Thread +| ThreadId | Iterations | Average Time | Slowest | Fastest | Throughput | +| --- | --- | ---: | ---: | ---: | ---: | +| 4 | 10 | 00:00:00.0058555 | 00:00:00.0140982 | 00:00:00.0014117 | 170.77873/s | +| 5 | 10 | 00:00:00.0057905 | 00:00:00.0139230 | 00:00:00.0018329 | 172.69606/s | +| 6 | 10 | 00:00:00.0038066 | 00:00:00.0065659 | 00:00:00.0012217 | 262.69886/s | +| 7 | 10 | 00:00:00.0057911 | 00:00:00.0120258 | 00:00:00.0013858 | 172.67787/s | +| 8 | 10 | 00:00:00.0062313 | 00:00:00.0130830 | 00:00:00.0038898 | 160.47887/s | +| 9 | 10 | 00:00:00.0047726 | 00:00:00.0075059 | 00:00:00.0003884 | 209.5272/s | +| 10 | 10 | 00:00:00.0045559 | 00:00:00.0072848 | 00:00:00.0005383 | 219.49271/s | +| 11 | 10 | 00:00:00.0057704 | 00:00:00.0147817 | 00:00:00.0017698 | 173.29731/s | +| 12 | 10 | 00:00:00.0047492 | 00:00:00.0073229 | 00:00:00.0011710 | 210.56178/s | +| 13 | 10 | 00:00:00.0069272 | 00:00:00.0093442 | 00:00:00.0043829 | 144.3568/s | + + +# MeasureMap - v1.2.3 +## Summary +| Category | Metric | Value | +| --- | --- | ---: | +| Warmup | Duration Warmup | 00:00:00.0934861 | +| Setup | Threads | 10 | +| | Iterations | 100 | +| Duration | Duration | 00:00:00.3045892 | +| | Total Time | 00:00:00.5476232 | +| | Average Time | 00:00:00.0054762 | +| | Average Milliseconds | 5.4762 ms | +| | Throughput | 328.31105/s | +| | Fastest | 00:00:00.0000867 | +| | Slowest | 00:00:00.0143229 | +| Memory | Memory Initial size | 126288 | +| | Memory End size | 198552 | +| | Memory Increase | 72264 | + +## Details per Thread +| ThreadId | Iterations | Average Time | Slowest | Fastest | Throughput | +| --- | --- | ---: | ---: | ---: | ---: | +| 4 | 10 | 00:00:00.0071977 | 00:00:00.0141091 | 00:00:00.0026345 | 138.93231/s | +| 5 | 10 | 00:00:00.0051405 | 00:00:00.0098962 | 00:00:00.0001348 | 194.53058/s | +| 6 | 10 | 00:00:00.0051938 | 00:00:00.0099995 | 00:00:00.0014394 | 192.53689/s | +| 7 | 10 | 00:00:00.0042084 | 00:00:00.0087129 | 00:00:00.0004524 | 237.61774/s | +| 8 | 10 | 00:00:00.0064520 | 00:00:00.0143229 | 00:00:00.0000867 | 154.98926/s | +| 9 | 10 | 00:00:00.0054007 | 00:00:00.0104453 | 00:00:00.0029130 | 185.15981/s | +| 10 | 10 | 00:00:00.0051964 | 00:00:00.0071006 | 00:00:00.0030690 | 192.44092/s | +| 11 | 10 | 00:00:00.0051198 | 00:00:00.0076924 | 00:00:00.0023300 | 195.3186/s | +| 12 | 10 | 00:00:00.0051012 | 00:00:00.0089473 | 00:00:00.0002999 | 196.03077/s | +| 13 | 10 | 00:00:00.0057514 | 00:00:00.0104961 | 00:00:00.0001130 | 173.8689/s | \ No newline at end of file diff --git a/src/Tests/YamlMap.Benchmark/TestItem.cs b/src/Tests/YamlMap.Benchmark/TestItem.cs new file mode 100644 index 0000000..93444e7 --- /dev/null +++ b/src/Tests/YamlMap.Benchmark/TestItem.cs @@ -0,0 +1,25 @@ + +namespace YamlMap.Benchmark +{ + public class TestlItem + { + public string Simple { get; set; } + + public TestlItemChild Child { get; set; } + + public IEnumerable StringList { get; set; } + + public IEnumerable ObjList { get; set; } + } + + public class TestlItemChild + { + public string Simple { get; set; } + + public TestlItem Child { get; set; } + + public IEnumerable StringList { get; set; } + + public IEnumerable ObjList { get; set; } + } +} diff --git a/src/Tests/YamlMap.Benchmark/YamlMap.Benchmark.csproj b/src/Tests/YamlMap.Benchmark/YamlMap.Benchmark.csproj new file mode 100644 index 0000000..cb37782 --- /dev/null +++ b/src/Tests/YamlMap.Benchmark/YamlMap.Benchmark.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + From 6bf78f3ff9473931fefe75db3775e187c22e607a Mon Sep 17 00:00:00 2001 From: Christian Walpen Date: Mon, 26 Sep 2022 22:01:03 +0200 Subject: [PATCH 9/9] v1.2.4 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 032a49e..fddbce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Create instances of types with parameterless constructors +- Added Benchmarks to ensure performance ### Changed