From 10b5a01f16a3d070c7071e861bd075ceef43f34f Mon Sep 17 00:00:00 2001 From: MCKanpolat Date: Fri, 2 Mar 2018 11:44:23 +0300 Subject: [PATCH] StubManager can instantiate generic classes now --- .../GenericModel`1.cs | 9 ++++ .../GenericModel`2.cs | 12 +++++ src/StubGenerator.Test/StubManagerTests.cs | 38 ++++++++++++-- .../Core/Conventions/CountryConventionMap.cs | 13 +++++ .../Core/Conventions/LastnameConvetionMap.cs | 3 +- .../Conventions/StreetNameConventionMap.cs | 13 +++++ .../Core/Conventions/ZipCodeConventionMap.cs | 13 +++++ .../DefaultConventionMappingProfile.cs | 21 ++++---- .../Extensions/StubManagerExtensions.cs | 49 ++++++++++++++++++- 9 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 src/StubGenerator.Test.Models/GenericModel`1.cs create mode 100644 src/StubGenerator.Test.Models/GenericModel`2.cs create mode 100644 src/StubMiddleware.Core/Core/Conventions/CountryConventionMap.cs create mode 100644 src/StubMiddleware.Core/Core/Conventions/StreetNameConventionMap.cs create mode 100644 src/StubMiddleware.Core/Core/Conventions/ZipCodeConventionMap.cs diff --git a/src/StubGenerator.Test.Models/GenericModel`1.cs b/src/StubGenerator.Test.Models/GenericModel`1.cs new file mode 100644 index 0000000..2ac194a --- /dev/null +++ b/src/StubGenerator.Test.Models/GenericModel`1.cs @@ -0,0 +1,9 @@ +namespace StubGenerator.Test.Models +{ + public class GenericModel where T : class + { + public int Status { get; set; } + + public T Data { get; set; } + } +} diff --git a/src/StubGenerator.Test.Models/GenericModel`2.cs b/src/StubGenerator.Test.Models/GenericModel`2.cs new file mode 100644 index 0000000..7484732 --- /dev/null +++ b/src/StubGenerator.Test.Models/GenericModel`2.cs @@ -0,0 +1,12 @@ +namespace StubGenerator.Test.Models +{ + public class GenericModel + where T1 : class + where T2 : class + { + public int Status { get; set; } + + public T1 GenericOne { get; set; } + public T2 GenericTwo { get; set; } + } +} diff --git a/src/StubGenerator.Test/StubManagerTests.cs b/src/StubGenerator.Test/StubManagerTests.cs index f8084b9..4d99b3a 100644 --- a/src/StubGenerator.Test/StubManagerTests.cs +++ b/src/StubGenerator.Test/StubManagerTests.cs @@ -16,7 +16,7 @@ public StubManagerTests() _stubManager = new StubManager(stubManagerOptions); } - [Fact(DisplayName = "Mapping_Check_By_Naming_Default_Conventions")] + [Fact(DisplayName = "Mapping Check By Naming Default Conventions")] public void Naming_Mapping_Check() { var stubDto = _stubManager.CreateNew(); @@ -26,7 +26,7 @@ public void Naming_Mapping_Check() } - [Fact(DisplayName = "Mapping_Check_By_Naming_Default_Conventions_List_Of")] + [Fact(DisplayName = "Mapping Check By Naming Default Conventions List Of")] public void Naming_Mapping_Check_List_Of() { var listOfDto = _stubManager.CreateListOfSize(10); @@ -37,7 +37,7 @@ public void Naming_Mapping_Check_List_Of() Assert.Equal(10, listOfDto.Count); } - [Fact(DisplayName = "Mapping_Check_By_Naming_Default_Conventions_Big_List")] + [Fact(DisplayName = "Mapping Check By Naming Default Conventions Big List")] public void Naming_Mapping_Check_Big_List() { var listOfDto = _stubManager.CreateListOfSize(100); @@ -49,7 +49,7 @@ public void Naming_Mapping_Check_Big_List() } - [Fact(DisplayName = "Mapping_Check_By_Naming_Default_Conventions_DE_Culture")] + [Fact(DisplayName = "Mapping Check By Naming Default Conventions DE Culture")] public void Naming_Mapping_Check_Culture() { var deCulture = new CultureInfo("de-DE"); @@ -164,5 +164,35 @@ public void Check_Unsupported_Types() Assert.NotNull(generatedStubData); Assert.Null(generatedStubData.ByteArray); } + + + [Fact(DisplayName = "Should Generate Generic Class")] + public void Should_Generate_Generic_Class() + { + var generatedStubData = _stubManager.InvokeCreateNew("StubGenerator.Test.Models.GenericModel, StubGenerator.Test.Models"); + Assert.NotNull(generatedStubData); + } + + [Fact(DisplayName = "Should Generate Generic Class With Argument Count Specified")] + public void Should_Generate_Generic_Class_With_Argument_Count_Specified() + { + var generatedStubData = _stubManager.InvokeCreateNew("StubGenerator.Test.Models.GenericModel`1, StubGenerator.Test.Models"); + Assert.NotNull(generatedStubData); + } + + + [Fact(DisplayName = "Should Generate Generic Class With 2 Argument")] + public void Should_Generate_Generic_Class_With_2_Argument() + { + var generatedStubData = _stubManager.InvokeCreateNew("StubGenerator.Test.Models.GenericModel, StubGenerator.Test.Models"); + Assert.NotNull(generatedStubData); + } + + [Fact(DisplayName = "Should Generate Generic Class With 2 Argument Count Specified")] + public void Should_Generate_Generic_Class_With_2_Argument_Count_Specified() + { + var generatedStubData = _stubManager.InvokeCreateNew("StubGenerator.Test.Models.GenericModel`2, StubGenerator.Test.Models"); + Assert.NotNull(generatedStubData); + } } } diff --git a/src/StubMiddleware.Core/Core/Conventions/CountryConventionMap.cs b/src/StubMiddleware.Core/Core/Conventions/CountryConventionMap.cs new file mode 100644 index 0000000..93fe545 --- /dev/null +++ b/src/StubMiddleware.Core/Core/Conventions/CountryConventionMap.cs @@ -0,0 +1,13 @@ +using System; +using System.Reflection; +using StubGenerator.Core.FakeDataGenerators; + +namespace StubGenerator.Core.Conventions +{ + public class CountryConventionMap : IConventionMap + { + public Predicate Condition => w => w.PropertyType == typeof(string) && w.Name.ToLowerInvariant().Contains("country"); + + public IValueGenerator Generator => new CountryValueGenerator(); + } +} diff --git a/src/StubMiddleware.Core/Core/Conventions/LastnameConvetionMap.cs b/src/StubMiddleware.Core/Core/Conventions/LastnameConvetionMap.cs index a011ee0..b4d10e7 100644 --- a/src/StubMiddleware.Core/Core/Conventions/LastnameConvetionMap.cs +++ b/src/StubMiddleware.Core/Core/Conventions/LastnameConvetionMap.cs @@ -7,7 +7,8 @@ namespace StubGenerator.Defaults { public class LastnameConvetionMap : IConventionMap { - public Predicate Condition => w => w.PropertyType == typeof(string) && w.Name.ToLowerInvariant().Contains("name") && w.Name.ToLowerInvariant().Contains("last"); + public Predicate Condition => w => w.PropertyType == typeof(string) && + ((w.Name.ToLowerInvariant().Contains("name") && w.Name.ToLowerInvariant().Contains("last")) || w.Name.ToLower().Contains("surname")); public IValueGenerator Generator => new LastNameValueGenerator(); } diff --git a/src/StubMiddleware.Core/Core/Conventions/StreetNameConventionMap.cs b/src/StubMiddleware.Core/Core/Conventions/StreetNameConventionMap.cs new file mode 100644 index 0000000..a9c4ecd --- /dev/null +++ b/src/StubMiddleware.Core/Core/Conventions/StreetNameConventionMap.cs @@ -0,0 +1,13 @@ +using System; +using System.Reflection; +using StubGenerator.Core.FakeDataGenerators; + +namespace StubGenerator.Core.Conventions +{ + public class StreetNameConventionMap : IConventionMap + { + public Predicate Condition => w => w.PropertyType == typeof(string) && w.Name.ToLowerInvariant().Contains("street"); + + public IValueGenerator Generator => new StreetNameValueGenerator(); + } +} diff --git a/src/StubMiddleware.Core/Core/Conventions/ZipCodeConventionMap.cs b/src/StubMiddleware.Core/Core/Conventions/ZipCodeConventionMap.cs new file mode 100644 index 0000000..90a5127 --- /dev/null +++ b/src/StubMiddleware.Core/Core/Conventions/ZipCodeConventionMap.cs @@ -0,0 +1,13 @@ +using System; +using System.Reflection; +using StubGenerator.Core.FakeDataGenerators; + +namespace StubGenerator.Core.Conventions +{ + public class ZipCodeConventionMap : IConventionMap + { + public Predicate Condition => w => w.PropertyType == typeof(string) && (w.Name.ToLowerInvariant().Contains("zipcode")); + + public IValueGenerator Generator => new ZipCodeValueGenerator(); + } +} diff --git a/src/StubMiddleware.Core/Defaults/DefaultConventionMappingProfile.cs b/src/StubMiddleware.Core/Defaults/DefaultConventionMappingProfile.cs index 88ba6aa..fb63747 100644 --- a/src/StubMiddleware.Core/Defaults/DefaultConventionMappingProfile.cs +++ b/src/StubMiddleware.Core/Defaults/DefaultConventionMappingProfile.cs @@ -7,15 +7,18 @@ namespace StubGenerator.Defaults public class DefaultConventionMappingProfile : IConventionMappingProfile { private readonly List _conventions; - public DefaultConventionMappingProfile() - { - _conventions = new List(); - _conventions.Add(new FirstnameConventionMap()); - _conventions.Add(new LastnameConvetionMap()); - _conventions.Add(new EmailConventionMap()); - _conventions.Add(new PhoneNumberConventionMap()); - _conventions.Add(new CompanyNameConventionMap()); - } + public DefaultConventionMappingProfile() => _conventions = new List + { + new FirstnameConventionMap(), + new LastnameConvetionMap(), + new EmailConventionMap(), + new PhoneNumberConventionMap(), + new CompanyNameConventionMap(), + new UserNameConventionMap(), + new StreetNameConventionMap(), + new CountryConventionMap(), + new ZipCodeConventionMap() + }; public IEnumerable Conventions => _conventions; } diff --git a/src/StubMiddleware.Core/Extensions/StubManagerExtensions.cs b/src/StubMiddleware.Core/Extensions/StubManagerExtensions.cs index 1d1a6f4..3edf0fa 100644 --- a/src/StubMiddleware.Core/Extensions/StubManagerExtensions.cs +++ b/src/StubMiddleware.Core/Extensions/StubManagerExtensions.cs @@ -1,18 +1,65 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Text.RegularExpressions; namespace StubGenerator.Core { public static class StubManagerExtensions { + private static readonly Regex genericTypeRegex = new Regex("<(.+?)>", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static Type LoadType(string typeName) { if (string.IsNullOrWhiteSpace(typeName)) { throw new ArgumentException("message", nameof(typeName)); } - var result = Type.GetType(typeName); + Type result = null; + var match = genericTypeRegex.Match(typeName); + if (match.Success) + { + var matchValue = match.Value; + var outerClassName = typeName.Replace(matchValue, ""); + var innerClassNames = matchValue.Trim('<', '>').Split(';'); + var genericArgumentTypes = new HashSet(); + + foreach (var innerClassName in innerClassNames) + { + var innerType = Type.GetType(innerClassName, false); + if (innerType == null) + throw new TypeLoadException($"The type '{innerClassName}' couldn't be loaded"); + + genericArgumentTypes.Add(innerType); + } + + if (!outerClassName.Contains("`")) + { + //If generic argument count doesn't specified + //Rewrite generic class name with generic argument count + var splittedClassName = outerClassName.Split(','); + if (splittedClassName.Count()!=2) + throw new TypeLoadException($"The type '{outerClassName}' couldn't be loaded"); + outerClassName = $"{splittedClassName[0]}`{genericArgumentTypes.Count}, {splittedClassName[1]}"; + } + + var outerType = Type.GetType(outerClassName, false); + if (outerType == null) + throw new TypeLoadException($"The type '{outerClassName}' couldn't be loaded"); + + if (!outerType.IsGenericType) + throw new TypeAccessException($"The type '{outerClassName}' must be a generic class"); + + if (outerType.GetGenericArguments().Count() != genericArgumentTypes.Count) + throw new TypeAccessException($"The type '{outerClassName}' generic arguments mismatch"); + + result = outerType.MakeGenericType(genericArgumentTypes.ToArray()); + } + else + { + result = Type.GetType(typeName, false); + } + if (result == null) throw new TypeLoadException($"The type '{typeName}' couldn't be loaded"); return result;