diff --git a/README.md b/README.md index 00c39db..e12fc58 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,7 @@ # ![](https://user-images.githubusercontent.com/4441470/224455560-91ed3ee7-f510-4041-a8d2-3fc093025112.png) Soenneker.Utils.AutoBogus ### The .NET Autogenerator -This project is an automatic creator and populator for the fake data generator [Bogus](https://github.com/bchavez/Bogus). - -It's a replacement for the abandoned [AutoBogus](https://github.com/nickdodd79/AutoBogus) library. +This project is an automatic creator and populator for the fake data generator [Bogus](https://github.com/bchavez/Bogus). It's a replacement for the abandoned [AutoBogus](https://github.com/nickdodd79/AutoBogus) library. The goals are to be *fast*, and support the latest types in .NET. @@ -21,28 +19,29 @@ dotnet add package Soenneker.Utils.AutoBogus ## Usage -- Create an AutoFaker instance: -```csharp -var autoFaker = new AutoFaker(); +- Create an `AutoFaker` instance: +```csharp +var optionalConfig = new AutoFakerConfig(); +var autoFaker = new AutoFaker(optionalConfig); ``` - Call `Generate<>()` on any type you want: ```csharp -var someRandomWord = autoFaker.Generate(); +var randomWord = autoFaker.Generate(); var dictionary = autoFaker.Generate>(); var order = autoFaker.Generate(); ``` -- Set a faker, configuration, rulesets, etc: +- Set a faker, configuration, rules, etc: ```csharp autoFaker.Config.Faker = new Faker("de"); -autoFaker.Config.RecursiveDepth = 3; +autoFaker.Config.RepeatCount = 3; ... ``` -- `AutoFakerOverride` can be used for type customization: +### `AutoFakerOverride` can be used for type customization: ```csharp public class OrderOverride : AutoFakerOverride @@ -61,7 +60,7 @@ public class OrderOverride : AutoFakerOverride } ``` -- Configuring `AutoFakerOverride` on the `AutoFaker`: +Then just add `AutoFakerOverride` to the `AutoFaker.Config` instance: ```csharp autoFaker.Config.Overrides = new AutoFakerOverrides(); @@ -79,11 +78,11 @@ autoFaker.Config.Overrides.Add(new OrderOverride()); ### Soenneker.Utils.AutoBogus -| Method | Mean | Error | StdDev | -|----------------- |-------------:|-----------:|-----------:| -| Generate_int | 73.86 ns | 0.843 ns | 0.747 ns | -| Generate_string | 227.31 ns | 2.601 ns | 2.433 ns | -| Generate_complex | 17,681.91 ns | 128.889 ns | 120.563 ns | +| Method | Mean | Error | StdDev | +|----------------- |------------:|----------:|----------:| +| Generate_int | 81.44 ns | 1.603 ns | 1.499 ns | +| Generate_string | 249.01 ns | 2.095 ns | 1.959 ns | +| Generate_complex | 6,949.16 ns | 57.973 ns | 54.228 ns | ### AutoBogus diff --git a/src/Abstract/IAutoFakerBinder.cs b/src/Abstract/IAutoFakerBinder.cs index 8b1759e..1b6d3fe 100644 --- a/src/Abstract/IAutoFakerBinder.cs +++ b/src/Abstract/IAutoFakerBinder.cs @@ -4,7 +4,7 @@ namespace Soenneker.Utils.AutoBogus.Abstract; /// -/// An interface for binding generated instances. +/// For binding generated instances. /// public interface IAutoFakerBinder { diff --git a/src/AutoFaker.cs b/src/AutoFaker.cs index a17e351..fdcb6d0 100644 --- a/src/AutoFaker.cs +++ b/src/AutoFaker.cs @@ -21,7 +21,19 @@ public sealed class AutoFaker : IAutoFaker public Faker Faker { get; set; } - public AutoFaker(Action? configure = null) + public AutoFaker(AutoFakerConfig? autoFakerConfig = null) + { + Faker = new Faker(); + + if (autoFakerConfig == null) + Config = new AutoFakerConfig(); + else + Config = autoFakerConfig; + + Binder = new AutoFakerBinder(Config); + } + + public AutoFaker(Action? configure) { Faker = new Faker(); diff --git a/src/AutoFakerBinder.cs b/src/AutoFakerBinder.cs index 2499a2b..80ca2f5 100644 --- a/src/AutoFakerBinder.cs +++ b/src/AutoFakerBinder.cs @@ -18,19 +18,20 @@ namespace Soenneker.Utils.AutoBogus; -/// -/// A class for binding generated instances. -/// +/// public class AutoFakerBinder : IAutoFakerBinder { private readonly AutoFakerConfig _autoFakerConfig; + internal readonly GeneratorService GeneratorService; + private readonly Dictionary> _autoMembersCache = []; private readonly Dictionary _constructorsCache = []; public AutoFakerBinder(AutoFakerConfig autoFakerConfig) { _autoFakerConfig = autoFakerConfig; + GeneratorService = new GeneratorService(); } /// @@ -81,6 +82,7 @@ public void PopulateInstance(object instance, AutoFakerContext context, C for (var i = 0; i < autoMembers.Count; i++) { AutoMember member = autoMembers[i]; + // Check if the member has a skip config or the type has already been generated as a parent // If so skip this generation otherwise track it for use later in the object tree if (ShouldSkip(member, context)) @@ -249,6 +251,7 @@ private List GetMembersToPopulate(CachedType cachedType) autoMembers.Add(new AutoMember(field, _autoFakerConfig)); } } + _autoMembersCache.TryAdd(cachedType, autoMembers); return autoMembers; diff --git a/src/AutoMember.cs b/src/AutoMember.cs index 1da478c..25b9062 100644 --- a/src/AutoMember.cs +++ b/src/AutoMember.cs @@ -16,20 +16,18 @@ internal sealed class AutoMember internal readonly Func Getter; - internal readonly Action Setter; + internal readonly Action? Setter; - internal readonly bool ShouldSkip = false; + internal bool ShouldSkip; - internal readonly bool IsDictionary = false; + internal readonly bool IsDictionary; - internal readonly bool IsCollection = false; + internal readonly bool IsCollection; internal AutoMember(FieldInfo fieldInfo, AutoFakerConfig config) { Name = fieldInfo.Name; - // Extract the required member info - CachedType = CacheService.Cache.GetCachedType(fieldInfo.FieldType); IsReadOnly = !fieldInfo.IsPrivate && fieldInfo.IsInitOnly; Getter = fieldInfo.GetValue; @@ -40,16 +38,7 @@ internal AutoMember(FieldInfo fieldInfo, AutoFakerConfig config) IsDictionary = CachedType.IsDictionary; IsCollection = CachedType.IsCollection; - if (config.SkipTypes != null && config.SkipTypes.Contains(CachedType.Type)) - { - ShouldSkip = true; - } - - // Skip if the path is found - if (config.SkipPaths != null && config.SkipPaths.Contains($"{CachedType.Type.FullName}.{Name}")) - { - ShouldSkip = true; - } + SetShouldSkip(config); } internal AutoMember(PropertyInfo propertyInfo, AutoFakerConfig config) @@ -66,6 +55,11 @@ internal AutoMember(PropertyInfo propertyInfo, AutoFakerConfig config) IsDictionary = CachedType.IsDictionary; IsCollection = CachedType.IsCollection; + SetShouldSkip(config); + } + + private void SetShouldSkip(AutoFakerConfig config) + { if (config.SkipTypes != null && config.SkipTypes.Contains(CachedType.Type)) { ShouldSkip = true; diff --git a/src/Config/AutoFakerConfig.cs b/src/Config/AutoFakerConfig.cs index 1c2c444..9d4fa9b 100644 --- a/src/Config/AutoFakerConfig.cs +++ b/src/Config/AutoFakerConfig.cs @@ -6,8 +6,14 @@ namespace Soenneker.Utils.AutoBogus.Config; public sealed class AutoFakerConfig { + /// + /// The Bogus.Faker locale to use when generating values. + /// public string Locale; + /// + /// Registers the number of items to generate for a collection. + /// public int RepeatCount; public int DataTableRowCount; @@ -25,11 +31,11 @@ public sealed class AutoFakerConfig public AutoFakerConfig() { - Locale = AutoFakerDefaultConfigOptions.DefaultLocale; - RepeatCount = AutoFakerDefaultConfigOptions.DefaultRepeatCount; - DataTableRowCount = AutoFakerDefaultConfigOptions.DefaultDataTableRowCount; - RecursiveDepth = AutoFakerDefaultConfigOptions.DefaultRecursiveDepth; - TreeDepth = AutoFakerDefaultConfigOptions.DefaultTreeDepth; - DateTimeKind = AutoFakerDefaultConfigOptions.DefaultDateTimeKind; + Locale = AutoFakerDefaultConfigOptions.Locale; + RepeatCount = AutoFakerDefaultConfigOptions.RepeatCount; + DataTableRowCount = AutoFakerDefaultConfigOptions.DataTableRowCount; + RecursiveDepth = AutoFakerDefaultConfigOptions.RecursiveDepth; + TreeDepth = AutoFakerDefaultConfigOptions.TreeDepth; + DateTimeKind = AutoFakerDefaultConfigOptions.DateTimeKind; } } \ No newline at end of file diff --git a/src/Config/AutoFakerConfigBuilder.cs b/src/Config/AutoFakerConfigBuilder.cs index d762078..eb39a4d 100644 --- a/src/Config/AutoFakerConfigBuilder.cs +++ b/src/Config/AutoFakerConfigBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using Bogus; using Soenneker.Utils.AutoBogus.Config.Abstract; using Soenneker.Utils.AutoBogus.Config.Base; using Soenneker.Utils.AutoBogus.Generators; @@ -20,10 +19,7 @@ internal AutoFakerConfigBuilder(AutoFakerConfig autoFakerConfig, AutoFaker autoF } internal object[]? Args { get; private set; } - - IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder.WithLocale(string locale) => WithLocale(locale, this); - IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder.WithRepeatCount(int count) => WithRepeatCount(count, this); IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder.WithDataTableRowCount(int count) => WithDataTableRowCount(count, this); IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder.WithRecursiveDepth(int depth) => WithRecursiveDepth(depth, this); @@ -41,9 +37,6 @@ IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder.WithOverride(AutoFakerGeneratorOverride autoFakerGeneratorOverride) => WithOverride(autoFakerGeneratorOverride, this); - IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder.WithLocale(string locale) => WithLocale(locale, this); - IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder.WithRepeatCount(int count) => WithRepeatCount(count, this); - IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder.WithDataTableRowCount(int count) => WithDataTableRowCount(count, this); IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder.WithRecursiveDepth(int depth) => WithRecursiveDepth(depth, this); @@ -59,9 +52,6 @@ IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder.WithOverride(AutoFakerGeneratorOverride autoFakerGeneratorOverride) => WithOverride(autoFakerGeneratorOverride, this); - IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder.WithLocale(string locale) => WithLocale(locale, this); - IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder.WithRepeatCount(int count) => WithRepeatCount(count, this); - IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder.WithDataTableRowCount(int count) => WithDataTableRowCount(count, this); IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder.WithRecursiveDepth(int depth) => WithRecursiveDepth(depth, this); @@ -78,20 +68,6 @@ IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder.Wit IAutoFakerConfigBuilder IAutoFakerConfigBuilder.WithArgs(params object[] args) => WithArgs(args, this); - internal TBuilder WithLocale(string locale, TBuilder builder) - { - _autoFakerConfig.Locale = locale; - - return builder; - } - - internal TBuilder WithRepeatCount(int count, TBuilder builder) - { - _autoFakerConfig.RepeatCount = count; - - return builder; - } - internal TBuilder WithDataTableRowCount(int count, TBuilder builder) { _autoFakerConfig.DataTableRowCount = count; @@ -113,19 +89,13 @@ internal TBuilder WithTreeDepth(int? depth, TBuilder builder) return builder; } - private TBuilder WithBinder(AutoFakerBinder? fakerBinder, TBuilder builder) + private TBuilder WithBinder(AutoFakerBinder fakerBinder, TBuilder builder) { _autoFaker.Binder = fakerBinder; return builder; } - internal TBuilder WithFaker(Faker faker, TBuilder builder) - { - _autoFaker.Faker = faker; - return builder; - } - internal TBuilder WithSkip(Type type, TBuilder builder) { _autoFakerConfig.SkipTypes ??= []; diff --git a/src/Config/AutoFakerDefaultConfigOptions.cs b/src/Config/AutoFakerDefaultConfigOptions.cs index 499880b..6a686bc 100644 --- a/src/Config/AutoFakerDefaultConfigOptions.cs +++ b/src/Config/AutoFakerDefaultConfigOptions.cs @@ -4,15 +4,15 @@ namespace Soenneker.Utils.AutoBogus.Config; public static class AutoFakerDefaultConfigOptions { - internal const string DefaultLocale = "en"; + internal const string Locale = "en"; internal const int GenerateAttemptsThreshold = 3; - internal const int DefaultRepeatCount = 3; - internal const int DefaultDataTableRowCount = 15; + internal const int RepeatCount = 1; + internal const int DataTableRowCount = 15; - internal const int DefaultRecursiveDepth = 2; + internal const int RecursiveDepth = 2; - internal static readonly int? DefaultTreeDepth = null; + internal static readonly int? TreeDepth = null; - internal static readonly DateTimeKind DefaultDateTimeKind = DateTimeKind.Utc; + internal static readonly DateTimeKind DateTimeKind = DateTimeKind.Utc; } \ No newline at end of file diff --git a/src/Config/Base/IBaseAutoFakerConfigBuilder.cs b/src/Config/Base/IBaseAutoFakerConfigBuilder.cs index 0735fec..e2b61c3 100644 --- a/src/Config/Base/IBaseAutoFakerConfigBuilder.cs +++ b/src/Config/Base/IBaseAutoFakerConfigBuilder.cs @@ -10,20 +10,6 @@ namespace Soenneker.Utils.AutoBogus.Config.Base; /// The builder type. public interface IBaseAutoFakerConfigBuilder { - /// - /// Registers the locale to use when generating values. - /// - /// The locale to use. - /// The current configuration builder instance. - TBuilder WithLocale(string locale); - - /// - /// Registers the number of items to generate for a collection. - /// - /// The repeat count to use. - /// The current configuration builder instance. - TBuilder WithRepeatCount(int count); - /// /// Registers the number of rows to generate in a . /// diff --git a/src/Generators/AutoFakerGeneratorFactory.cs b/src/Generators/AutoFakerGeneratorFactory.cs index 0f57352..df0c387 100644 --- a/src/Generators/AutoFakerGeneratorFactory.cs +++ b/src/Generators/AutoFakerGeneratorFactory.cs @@ -13,7 +13,7 @@ public static class AutoFakerGeneratorFactory { internal static IAutoFakerGenerator GetGenerator(AutoFakerContext context) { - IAutoFakerGenerator? cachedGenerator = GeneratorService.GetGenerator(context.CachedType); + IAutoFakerGenerator? cachedGenerator = context.Binder.GeneratorService.GetGenerator(context.CachedType); if (cachedGenerator != null) return cachedGenerator; @@ -37,19 +37,19 @@ internal static IAutoFakerGenerator GetGenerator(AutoFakerContext context) if (overrides == null || overrides.Count == 0) { - GeneratorService.SetGenerator(context.CachedType, generator); + context.Binder.GeneratorService.SetGenerator(context.CachedType, generator); return generator; } var newOverrideGenerator = new AutoFakerGeneratorOverrideInvoker(generator, overrides); - GeneratorService.SetGenerator(context.CachedType, newOverrideGenerator); + context.Binder.GeneratorService.SetGenerator(context.CachedType, newOverrideGenerator); return newOverrideGenerator; } internal static IAutoFakerGenerator CreateGenerator(AutoFakerContext context) { - IAutoFakerGenerator? fundamentalGenerator = GeneratorService.GetFundamentalGenerator(context.CachedType); + IAutoFakerGenerator? fundamentalGenerator = context.Binder.GeneratorService.GetFundamentalGenerator(context.CachedType); if (fundamentalGenerator != null) return fundamentalGenerator; diff --git a/src/Services/CachedTypeService.cs b/src/Services/CachedTypeService.cs index be95924..06bfd5b 100644 --- a/src/Services/CachedTypeService.cs +++ b/src/Services/CachedTypeService.cs @@ -3,21 +3,20 @@ using Soenneker.Reflection.Cache.Types; using Soenneker.Utils.AutoBogus.Generators.Types; -namespace Soenneker.Utils.AutoBogus.Services +namespace Soenneker.Utils.AutoBogus.Services; + +internal static class CachedTypeService { - internal static class CachedTypeService - { - internal static readonly Lazy TypeGenerator = new(() => CacheService.Cache.GetCachedType(typeof(TypeGenerator<>))); - internal static readonly Lazy EnumerableGenerator = new(() => CacheService.Cache.GetCachedType(typeof(EnumerableGenerator<>))); - internal static readonly Lazy ListGenerator = new(() => CacheService.Cache.GetCachedType(typeof(ListGenerator<>))); - internal static readonly Lazy SetGenerator = new(() => CacheService.Cache.GetCachedType(typeof(SetGenerator<>))); - internal static readonly Lazy ReadOnlyDictionaryGenerator = new(() => CacheService.Cache.GetCachedType(typeof(ReadOnlyDictionaryGenerator<,>))); - internal static readonly Lazy NullableGenerator = new(() => CacheService.Cache.GetCachedType(typeof(NullableGenerator<>))); - internal static readonly Lazy EnumGenerator = new(() => CacheService.Cache.GetCachedType(typeof(EnumGenerator<>))); - internal static readonly Lazy ArrayGenerator = new(() => CacheService.Cache.GetCachedType(typeof(ArrayGenerator<>))); - internal static readonly Lazy DictionaryGenerator = new(() => CacheService.Cache.GetCachedType(typeof(DictionaryGenerator<,>))); + internal static readonly Lazy TypeGenerator = new(() => CacheService.Cache.GetCachedType(typeof(TypeGenerator<>))); + internal static readonly Lazy EnumerableGenerator = new(() => CacheService.Cache.GetCachedType(typeof(EnumerableGenerator<>))); + internal static readonly Lazy ListGenerator = new(() => CacheService.Cache.GetCachedType(typeof(ListGenerator<>))); + internal static readonly Lazy SetGenerator = new(() => CacheService.Cache.GetCachedType(typeof(SetGenerator<>))); + internal static readonly Lazy ReadOnlyDictionaryGenerator = new(() => CacheService.Cache.GetCachedType(typeof(ReadOnlyDictionaryGenerator<,>))); + internal static readonly Lazy NullableGenerator = new(() => CacheService.Cache.GetCachedType(typeof(NullableGenerator<>))); + internal static readonly Lazy EnumGenerator = new(() => CacheService.Cache.GetCachedType(typeof(EnumGenerator<>))); + internal static readonly Lazy ArrayGenerator = new(() => CacheService.Cache.GetCachedType(typeof(ArrayGenerator<>))); + internal static readonly Lazy DictionaryGenerator = new(() => CacheService.Cache.GetCachedType(typeof(DictionaryGenerator<,>))); - internal static readonly Lazy IDictionary = new(() => CacheService.Cache.GetCachedType(typeof(IDictionary<,>))); - internal static readonly Lazy IEnumerable = new(() => CacheService.Cache.GetCachedType(typeof(IEnumerable<>))); - } -} + internal static readonly Lazy IDictionary = new(() => CacheService.Cache.GetCachedType(typeof(IDictionary<,>))); + internal static readonly Lazy IEnumerable = new(() => CacheService.Cache.GetCachedType(typeof(IEnumerable<>))); +} \ No newline at end of file diff --git a/src/Services/GeneratorService.cs b/src/Services/GeneratorService.cs index dd01c3e..d082a51 100644 --- a/src/Services/GeneratorService.cs +++ b/src/Services/GeneratorService.cs @@ -9,58 +9,64 @@ namespace Soenneker.Utils.AutoBogus.Services; -internal static class GeneratorService +internal class GeneratorService { + // I believe this can be static because there aren't context/config adjustments private static readonly Dictionary> _cachedFundamentalGenerators = new() { - { typeof(string), new Lazy(() => new StringGenerator()) }, - { typeof(int), new Lazy(() => new IntGenerator()) }, - { typeof(bool), new Lazy(() => new BoolGenerator()) }, - { typeof(double), new Lazy(() => new DoubleGenerator()) }, - { typeof(DateTime), new Lazy(() => new DateTimeGenerator()) }, - { typeof(byte), new Lazy(() => new ByteGenerator()) }, - { typeof(char), new Lazy(() => new CharGenerator()) }, - { typeof(decimal), new Lazy(() => new DecimalGenerator()) }, - { typeof(float), new Lazy(() => new FloatGenerator()) }, - { typeof(long), new Lazy(() => new LongGenerator()) }, - { typeof(Guid), new Lazy(() => new GuidGenerator()) }, - { typeof(sbyte), new Lazy(() => new SByteGenerator()) }, - { typeof(short), new Lazy(() => new ShortGenerator()) }, - { typeof(uint), new Lazy(() => new UIntGenerator()) }, - { typeof(ulong), new Lazy(() => new ULongGenerator()) }, - { typeof(Uri), new Lazy(() => new UriGenerator()) }, - { typeof(ushort), new Lazy(() => new UShortGenerator()) }, - { typeof(DateTimeOffset), new Lazy(() => new DateTimeOffsetGenerator()) }, - { typeof(DateOnly), new Lazy(() => new DateOnlyGenerator()) }, - { typeof(TimeOnly), new Lazy(() => new TimeOnlyGenerator()) }, - { typeof(IPAddress), new Lazy(() => new IpAddressGenerator()) }, + {typeof(string), new Lazy(() => new StringGenerator())}, + {typeof(int), new Lazy(() => new IntGenerator())}, + {typeof(bool), new Lazy(() => new BoolGenerator())}, + {typeof(double), new Lazy(() => new DoubleGenerator())}, + {typeof(DateTime), new Lazy(() => new DateTimeGenerator())}, + {typeof(byte), new Lazy(() => new ByteGenerator())}, + {typeof(char), new Lazy(() => new CharGenerator())}, + {typeof(decimal), new Lazy(() => new DecimalGenerator())}, + {typeof(float), new Lazy(() => new FloatGenerator())}, + {typeof(long), new Lazy(() => new LongGenerator())}, + {typeof(Guid), new Lazy(() => new GuidGenerator())}, + {typeof(sbyte), new Lazy(() => new SByteGenerator())}, + {typeof(short), new Lazy(() => new ShortGenerator())}, + {typeof(uint), new Lazy(() => new UIntGenerator())}, + {typeof(ulong), new Lazy(() => new ULongGenerator())}, + {typeof(Uri), new Lazy(() => new UriGenerator())}, + {typeof(ushort), new Lazy(() => new UShortGenerator())}, + {typeof(DateTimeOffset), new Lazy(() => new DateTimeOffsetGenerator())}, + {typeof(DateOnly), new Lazy(() => new DateOnlyGenerator())}, + {typeof(TimeOnly), new Lazy(() => new TimeOnlyGenerator())}, + {typeof(IPAddress), new Lazy(() => new IpAddressGenerator())}, }; - private static readonly Lazy>> _cachedFundamentalGeneratorsByInt = new(() => - { - Dictionary> hashCodesMap = _cachedFundamentalGenerators.ToDictionary( - kvp => kvp.Key.GetHashCode(), - kvp => kvp.Value - ); + private readonly Lazy>> _cachedFundamentalGeneratorsByInt; + + private readonly ConcurrentDictionary _cachedGenerators = []; - return hashCodesMap; - }); + internal GeneratorService() + { + _cachedFundamentalGeneratorsByInt = new Lazy>>(() => + { + Dictionary> hashCodesMap = _cachedFundamentalGenerators.ToDictionary( + kvp => kvp.Key.GetHashCode(), + kvp => kvp.Value + ); - private static readonly ConcurrentDictionary _cachedGenerators = []; + return hashCodesMap; + }); + } - public static IAutoFakerGenerator? GetFundamentalGenerator(CachedType cachedType) + public IAutoFakerGenerator? GetFundamentalGenerator(CachedType cachedType) { IAutoFakerGenerator? result = _cachedFundamentalGeneratorsByInt.Value.GetValueOrDefault(cachedType.CacheKey!.Value)?.Value; return result; } - public static IAutoFakerGenerator? GetGenerator(CachedType cachedType) + public IAutoFakerGenerator? GetGenerator(CachedType cachedType) { IAutoFakerGenerator? result = _cachedGenerators.GetValueOrDefault(cachedType.CacheKey!.Value); return result; } - public static void SetGenerator(CachedType cachedType, IAutoFakerGenerator generator) + public void SetGenerator(CachedType cachedType, IAutoFakerGenerator generator) { _cachedGenerators.TryAdd(cachedType.CacheKey!.Value, generator); } @@ -74,7 +80,7 @@ public static List GetSupportedFundamentalTypes() return _cachedFundamentalGenerators.Select(c => c.Key).ToList(); } - public static void Clear() + public void Clear() { _cachedGenerators.Clear(); } diff --git a/test/Soenneker.Utils.AutoBogus.Tests/AutoConfigBuilderFixture.cs b/test/Soenneker.Utils.AutoBogus.Tests/AutoConfigBuilderFixture.cs index bb9382b..52c8e4b 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/AutoConfigBuilderFixture.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/AutoConfigBuilderFixture.cs @@ -25,20 +25,6 @@ public AutoConfigBuilderFixture() _builder = new AutoFakerConfigBuilder(_fakerConfig, autoFaker); } - public class WithLocale - : AutoConfigBuilderFixture - { - [Fact] - public void Should_Set_Config_Locale() - { - string? locale = _faker.Random.String(); - - _builder.WithLocale(locale, null); - - _fakerConfig.Locale.Should().Be(locale); - } - } - public class WithDateTimeKind : AutoConfigBuilderFixture { [Fact] @@ -49,20 +35,6 @@ public void Should_BeUniversal() } } - public class WithRepeatCount - : AutoConfigBuilderFixture - { - [Fact] - public void Should_Set_Config_RepeatCount() - { - int count = _faker.Random.Int(); - - _builder.WithRepeatCount(count, null); - - _fakerConfig.RepeatCount.Should().Be(count); - } - } - public class WithRecursiveDepth : AutoConfigBuilderFixture { @@ -94,7 +66,7 @@ public void Should_Set_Config_TreeDepth() [Fact] public void Should_Set_Config_TreeDepth_To_Default_If_Null() { - int? depth = AutoFakerDefaultConfigOptions.DefaultTreeDepth; + int? depth = AutoFakerDefaultConfigOptions.TreeDepth; _builder.WithTreeDepth(null, null); diff --git a/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerFixture.cs b/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerFixture.cs index c681bb4..4f8e6d6 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerFixture.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerFixture.cs @@ -69,10 +69,10 @@ public void Should_Generate_Type(Type type, Type? expectedType) } [Theory] - [MemberData(nameof(GetTypes))] - public void Should_Generate_Many_Types(Type type) + [ClassData(typeof(TypeTestData))] + public void Should_Generate_Many_Types(Type type, Type expectedType) { - int count = AutoFakerDefaultConfigOptions.DefaultRepeatCount; + int count = AutoFakerDefaultConfigOptions.RepeatCount; Action configure = CreateConfigure(); AssertGenerateMany(type, _generateMany, null, count, configure); @@ -88,7 +88,7 @@ public void Should_Generate_Complex_Type() [Fact] public void Should_Generate_Many_Complex_Types() { - int count = AutoFakerDefaultConfigOptions.DefaultRepeatCount; + int count = AutoFakerDefaultConfigOptions.RepeatCount; Action configure = CreateConfigure(); List instances = AutoFaker.GenerateStatic(count, configure); @@ -112,34 +112,42 @@ public void Should_Not_Generate_Abstract_Class_Type() } } - public class Behaviors_Recursive - : AutoFakerFixture + public class Behaviors_Recursive: AutoFakerFixture { private readonly TestRecursiveClass _instance; + readonly AutoFaker _autoFaker; + public Behaviors_Recursive() { - _instance = AutoFaker.GenerateStatic(builder => { builder.WithRecursiveDepth(3); }); + var config = new AutoFakerConfig(); + config.RecursiveDepth = 3; + config.RepeatCount = 3; + + _autoFaker = new AutoFaker(config); } [Fact] public void Should_Generate_Recursive_Types() { - _instance.Child.Should().NotBeNull(); - _instance.Child.Child.Should().NotBeNull(); - _instance.Child.Child.Child.Should().NotBeNull(); - _instance.Child.Child.Child.Child.Should().BeNull(); + TestRecursiveClass instance = _autoFaker.Generate(); + + instance.Child.Should().NotBeNull(); + instance.Child.Child.Should().NotBeNull(); + instance.Child.Child.Child.Should().NotBeNull(); + instance.Child.Child.Child.Child.Should().BeNull(); } [Fact] public void Should_Generate_Recursive_Lists() { - IEnumerable children = _instance.Children; - List children1 = children.SelectMany(c => c.Children).ToList(); + TestRecursiveClass instance = _autoFaker.Generate(); + + List children1 = instance.Children.SelectMany(c => c.Children).ToList(); List children2 = children1.SelectMany(c => c.Children).ToList(); List children3 = children2.Where(c => c.Children != null).ToList(); - children.Should().HaveCount(3); + instance.Children.Should().HaveCount(3); children1.Should().HaveCount(9); children2.Should().HaveCount(27); children3.Should().HaveCount(0); @@ -148,25 +156,13 @@ public void Should_Generate_Recursive_Lists() [Fact] public void Should_Generate_Recursive_Sub_Types() { - _instance.Sub.Should().NotBeNull(); - _instance.Sub.Value.Sub.Should().NotBeNull(); - _instance.Sub.Value.Sub.Value.Sub.Should().NotBeNull(); - _instance.Sub.Value.Sub.Value.Sub.Value.Sub.Should().BeNull(); - } - } + TestRecursiveClass instance = _autoFaker.Generate(); - public static IEnumerable GetTypes() - { - foreach (Type? type in GeneratorService.GetSupportedFundamentalTypes()) - { - yield return [type]; + instance.Sub.Should().NotBeNull(); + instance.Sub.Value.Sub.Should().NotBeNull(); + instance.Sub.Value.Sub.Value.Sub.Should().NotBeNull(); + instance.Sub.Value.Sub.Value.Sub.Value.Sub.Should().BeNull(); } - - yield return [typeof(string[])]; - yield return [typeof(TestEnum)]; - yield return [typeof(IDictionary)]; - yield return [typeof(IEnumerable)]; - yield return [typeof(int?)]; } private static Action CreateConfigure(Action? configure = null) @@ -190,7 +186,7 @@ public static void AssertGenerate(Type type, MethodInfo methodInfo, AutoFaker au public static void AssertGenerateMany(Type type, MethodInfo methodInfo, AutoFaker autoFaker, params object[] args) { - int count = AutoFakerDefaultConfigOptions.DefaultRepeatCount; + int count = AutoFakerDefaultConfigOptions.RepeatCount; MethodInfo method = methodInfo.MakeGenericMethod(type); var instances = method.Invoke(autoFaker, args) as ICollection; @@ -204,7 +200,7 @@ public static void AssertGenerateMany(Type type, MethodInfo methodInfo, AutoFake public static void AssertGenerateMany(IEnumerable instances) { - int count = AutoFakerDefaultConfigOptions.DefaultRepeatCount; + int count = AutoFakerDefaultConfigOptions.RepeatCount; instances.Should().HaveCount(count); diff --git a/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerTests.cs b/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerTests.cs index c14ae21..8c02c90 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerTests.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/AutoFakerTests.cs @@ -5,6 +5,8 @@ using Soenneker.Utils.AutoBogus.Tests.Dtos.Simple; using Xunit; using Soenneker.Utils.AutoBogus.Tests.Overrides; +using System.Linq; +using Soenneker.Utils.AutoBogus.Config; namespace Soenneker.Utils.AutoBogus.Tests; @@ -50,7 +52,7 @@ public void Generate_Product_should_generate() product.Should().NotBeNull(); product.GetRevisions.Should().NotBeNullOrEmpty(); // product.Reviews.Count.Should().BeGreaterThan(0); - // product. + // product. } [Fact] @@ -85,35 +87,65 @@ public void Generate_many_int_should_generate() } [Fact] - public void ConfigureOverride_after_initialization_should_succeed() + public void Generate_with_override_should_give_result() + { + for (var i = 0; i < 100; i++) + { + var config = new AutoFakerConfig + { + Overrides = + [ + new BaseCustomOrderOverride(), + new LongitudeOverride(), + new CustomOrderOverride() + ] + }; + + var autoFaker = new AutoFaker(config); + + var order = autoFaker.Generate(); + order.CustomId.Should().Be("Blah"); + } + } + + [Fact] + public void Generate_with_default_RepeatCount_should_generate_correct_count() { var autoFaker = new AutoFaker(); - autoFaker.Config.TreeDepth = 1; - SetOverride(autoFaker); + var order = autoFaker.Generate(); + order.Items.Count().Should().Be(1); + } + + [Fact] + public void Generate_with_set_RepeatCount_should_generate_correct_count() + { + var autoFaker = new AutoFaker(); + autoFaker.Config.RepeatCount = 3; var order = autoFaker.Generate(); - order.CustomId.Should().Be("Blah"); + order.Items.Count().Should().Be(3); } [Fact] public void Generate_with_smartenum_should_generate() { - var autoFaker = new AutoFaker(); + var config = new AutoFakerConfig + { + Overrides = + [ + new BaseCustomOrderOverride(), + new LongitudeOverride(), + new CustomOrderOverride() + ] + }; - SetOverride(autoFaker); + var autoFaker = new AutoFaker(config); var order = autoFaker.Generate(); order.DaysOfWeek.Should().NotBeNull(); order.NullableDaysOfWeek.Should().NotBeNull(); order.Longitude.Should().NotBeNull(); CustomOrder.Constant.Should().Be("Order2x89ei"); - } - - private void SetOverride(AutoFaker autoFaker) - { - autoFaker.Configure(c => c.WithOverride(new BaseCustomOrderOverride())); - autoFaker.Configure(c => c.WithOverride(new LongitudeOverride())); - autoFaker.Configure(c => c.WithOverride(new CustomOrderOverride())); } } \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/AutoGeneratorsFixture.cs b/test/Soenneker.Utils.AutoBogus.Tests/AutoGeneratorsFixture.cs index 2e679d5..9fa5810 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/AutoGeneratorsFixture.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/AutoGeneratorsFixture.cs @@ -260,7 +260,9 @@ public class RegisteredGenerator public void Generate_Should_Return_Value(Type type) { CachedType cachedType = CacheService.Cache.GetCachedType(type); - IAutoFakerGenerator generator = GeneratorService.GetFundamentalGenerator(cachedType); + AutoFakerBinder binder = new AutoFakerBinder(new AutoFakerConfig()); + + IAutoFakerGenerator generator = binder.GeneratorService.GetFundamentalGenerator(cachedType); InvokeGenerator(type, generator).Should().BeOfType(type); } @@ -271,9 +273,9 @@ public void GetGenerator_Should_Return_Generator(Type type) { CachedType cachedType = CacheService.Cache.GetCachedType(type); AutoFakerContext context = CreateContext(type); - IAutoFakerGenerator generator = GeneratorService.GetFundamentalGenerator(cachedType); + IAutoFakerGenerator generator = context.Binder.GeneratorService.GetFundamentalGenerator(cachedType); - GeneratorService.Clear(); + context.Binder.GeneratorService.Clear(); AutoFakerGeneratorFactory.GetGenerator(context).Should().Be(generator); } diff --git a/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/BaseCustomOrder.cs b/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/BaseCustomOrder.cs index 79876ac..b8c04f0 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/BaseCustomOrder.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/BaseCustomOrder.cs @@ -1,7 +1,6 @@ -namespace Soenneker.Utils.AutoBogus.Tests.Dtos.Complex +namespace Soenneker.Utils.AutoBogus.Tests.Dtos.Complex; + +public class BaseCustomOrder { - public class BaseCustomOrder - { - public int Test { get; set; } - } -} + public int Test { get; set; } +} \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Human.cs b/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Human.cs index fe6cf06..affec88 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Human.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Human.cs @@ -1,9 +1,8 @@ using System; -namespace Soenneker.Utils.AutoBogus.Tests.Dtos.Complex +namespace Soenneker.Utils.AutoBogus.Tests.Dtos.Complex; + +internal class Human { - internal class Human - { - public DateTime Birthday { get; set; } - } -} + public DateTime Birthday { get; set; } +} \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Longitude.cs b/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Longitude.cs index 82e7573..b4f1d16 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Longitude.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/Dtos/Complex/Longitude.cs @@ -1,7 +1,6 @@ -namespace Soenneker.Utils.AutoBogus.Tests.Dtos.Complex +namespace Soenneker.Utils.AutoBogus.Tests.Dtos.Complex; + +public class Longitude { - public class Longitude - { - public double Value { get; set; } - } -} + public double Value { get; set; } +} \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/Enums/DayOfWeekType.cs b/test/Soenneker.Utils.AutoBogus.Tests/Enums/DayOfWeekType.cs index 05cbad0..e006ddd 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/Enums/DayOfWeekType.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/Enums/DayOfWeekType.cs @@ -1,19 +1,18 @@ using Ardalis.SmartEnum; -namespace Soenneker.Utils.AutoBogus.Tests.Enums +namespace Soenneker.Utils.AutoBogus.Tests.Enums; + +public sealed class DayOfWeekType : SmartEnum { - public sealed class DayOfWeekType : SmartEnum - { - public static readonly DayOfWeekType Sunday = new(nameof(Sunday), 0); - public static readonly DayOfWeekType Monday = new(nameof(Monday), 1); - public static readonly DayOfWeekType Tuesday = new(nameof(Tuesday), 2); - public static readonly DayOfWeekType Wednesday = new(nameof(Wednesday), 3); - public static readonly DayOfWeekType Thursday = new(nameof(Thursday), 4); - public static readonly DayOfWeekType Friday = new(nameof(Friday), 5); - public static readonly DayOfWeekType Saturday = new(nameof(Saturday), 6); + public static readonly DayOfWeekType Sunday = new(nameof(Sunday), 0); + public static readonly DayOfWeekType Monday = new(nameof(Monday), 1); + public static readonly DayOfWeekType Tuesday = new(nameof(Tuesday), 2); + public static readonly DayOfWeekType Wednesday = new(nameof(Wednesday), 3); + public static readonly DayOfWeekType Thursday = new(nameof(Thursday), 4); + public static readonly DayOfWeekType Friday = new(nameof(Friday), 5); + public static readonly DayOfWeekType Saturday = new(nameof(Saturday), 6); - private DayOfWeekType(string name, int value) : base(name, value) - { - } + private DayOfWeekType(string name, int value) : base(name, value) + { } -} +} \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/Overrides/CustomOrderOverride.cs b/test/Soenneker.Utils.AutoBogus.Tests/Overrides/CustomOrderOverride.cs index c6353c2..404dae9 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/Overrides/CustomOrderOverride.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/Overrides/CustomOrderOverride.cs @@ -2,15 +2,14 @@ using Soenneker.Utils.AutoBogus.Override; using Soenneker.Utils.AutoBogus.Tests.Dtos.Complex; -namespace Soenneker.Utils.AutoBogus.Tests.Overrides +namespace Soenneker.Utils.AutoBogus.Tests.Overrides; + +public class CustomOrderOverride : AutoFakerOverride { - public class CustomOrderOverride : AutoFakerOverride + public override void Generate(AutoFakerOverrideContext context) { - public override void Generate(AutoFakerOverrideContext context) - { - var target = (context.Instance as CustomOrder)!; + var target = (context.Instance as CustomOrder)!; - target.CustomId = "Blah"; - } + target.CustomId = "Blah"; } -} +} \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/Overrides/LongituteOverride.cs b/test/Soenneker.Utils.AutoBogus.Tests/Overrides/LongituteOverride.cs index c4d22e1..83cfb02 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/Overrides/LongituteOverride.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/Overrides/LongituteOverride.cs @@ -2,14 +2,13 @@ using Soenneker.Utils.AutoBogus.Override; using Soenneker.Utils.AutoBogus.Tests.Dtos.Complex; -namespace Soenneker.Utils.AutoBogus.Tests.Overrides +namespace Soenneker.Utils.AutoBogus.Tests.Overrides; + +public class LongitudeOverride : AutoFakerOverride { - public class LongitudeOverride : AutoFakerOverride + public override void Generate(AutoFakerOverrideContext context) { - public override void Generate(AutoFakerOverrideContext context) - { - var target = (context.Instance as Longitude)!; + var target = (context.Instance as Longitude)!; - } } -} +} \ No newline at end of file diff --git a/test/Soenneker.Utils.AutoBogus.Tests/TestData/TypeTestData.cs b/test/Soenneker.Utils.AutoBogus.Tests/TestData/TypeTestData.cs index bf6edbe..27d798f 100644 --- a/test/Soenneker.Utils.AutoBogus.Tests/TestData/TypeTestData.cs +++ b/test/Soenneker.Utils.AutoBogus.Tests/TestData/TypeTestData.cs @@ -3,108 +3,107 @@ using System.Collections.Generic; using System.Net; -namespace Soenneker.Utils.AutoBogus.Tests.TestData +namespace Soenneker.Utils.AutoBogus.Tests.TestData; + +public class TypeTestData : IEnumerable { - public class TypeTestData : IEnumerable + public IEnumerator GetEnumerator() { - public IEnumerator GetEnumerator() - { - // Nullable types - yield return [typeof(string), typeof(string)]; - yield return [typeof(bool?), typeof(bool)]; - yield return [typeof(int?), typeof(int)]; - yield return [typeof(double?), typeof(double)]; - yield return [typeof(DateTime?), typeof(DateTime)]; - yield return [typeof(byte?), typeof(byte)]; - yield return [typeof(char?), typeof(char)]; - yield return [typeof(decimal?), typeof(decimal)]; - yield return [typeof(float?), typeof(float)]; - yield return [typeof(long?), typeof(long)]; - yield return [typeof(Guid?), typeof(Guid)]; - yield return [typeof(sbyte?), typeof(sbyte)]; - yield return [typeof(short?), typeof(short)]; - yield return [typeof(uint?), typeof(uint)]; - yield return [typeof(ulong?), typeof(ulong)]; - yield return [typeof(Uri), typeof(Uri)]; // Uri is a reference type - - // Non-nullable types - yield return [typeof(string), typeof(string)]; - yield return [typeof(bool), typeof(bool)]; - yield return [typeof(int), typeof(int)]; - yield return [typeof(double), typeof(double)]; - yield return [typeof(DateTime), typeof(DateTime)]; - yield return [typeof(byte), typeof(byte)]; - yield return [typeof(char), typeof(char)]; - yield return [typeof(decimal), typeof(decimal)]; - yield return [typeof(float), typeof(float)]; - yield return [typeof(long), typeof(long)]; - yield return [typeof(Guid), typeof(Guid)]; - yield return [typeof(sbyte), typeof(sbyte)]; - yield return [typeof(short), typeof(short)]; - yield return [typeof(uint), typeof(uint)]; - yield return [typeof(ulong), typeof(ulong)]; - yield return [typeof(Uri), typeof(Uri)]; // Uri is a reference type + // Nullable types + yield return [typeof(string), typeof(string)]; + yield return [typeof(bool?), typeof(bool)]; + yield return [typeof(int?), typeof(int)]; + yield return [typeof(double?), typeof(double)]; + yield return [typeof(DateTime?), typeof(DateTime)]; + yield return [typeof(byte?), typeof(byte)]; + yield return [typeof(char?), typeof(char)]; + yield return [typeof(decimal?), typeof(decimal)]; + yield return [typeof(float?), typeof(float)]; + yield return [typeof(long?), typeof(long)]; + yield return [typeof(Guid?), typeof(Guid)]; + yield return [typeof(sbyte?), typeof(sbyte)]; + yield return [typeof(short?), typeof(short)]; + yield return [typeof(uint?), typeof(uint)]; + yield return [typeof(ulong?), typeof(ulong)]; + yield return [typeof(Uri), typeof(Uri)]; // Uri is a reference type - // Enumerable types - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(IEnumerable), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(ICollection), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - yield return [typeof(IList), typeof(List)]; - } + // Non-nullable types + yield return [typeof(string), typeof(string)]; + yield return [typeof(bool), typeof(bool)]; + yield return [typeof(int), typeof(int)]; + yield return [typeof(double), typeof(double)]; + yield return [typeof(DateTime), typeof(DateTime)]; + yield return [typeof(byte), typeof(byte)]; + yield return [typeof(char), typeof(char)]; + yield return [typeof(decimal), typeof(decimal)]; + yield return [typeof(float), typeof(float)]; + yield return [typeof(long), typeof(long)]; + yield return [typeof(Guid), typeof(Guid)]; + yield return [typeof(sbyte), typeof(sbyte)]; + yield return [typeof(short), typeof(short)]; + yield return [typeof(uint), typeof(uint)]; + yield return [typeof(ulong), typeof(ulong)]; + yield return [typeof(Uri), typeof(Uri)]; // Uri is a reference type - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + // Enumerable types + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(IEnumerable), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(ICollection), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; + yield return [typeof(IList), typeof(List)]; } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } \ No newline at end of file