Skip to content

Commit

Permalink
Work on context, saving some cache lookups etc
Browse files Browse the repository at this point in the history
Cleanup
  • Loading branch information
soenneker committed Jan 27, 2024
1 parent 6e699a1 commit 4dea920
Show file tree
Hide file tree
Showing 26 changed files with 170 additions and 205 deletions.
2 changes: 1 addition & 1 deletion Soenneker.Utils.AutoBogus.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E355F0FD-6
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DD733813-BAA4-429B-90A7-8E7ADE196683}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Soenneker.Utils.AutoBogus.Console", "test\Soenneker.Utils.AutoBogus.Console\Soenneker.Utils.AutoBogus.Console.csproj", "{4BC4BD23-23A3-407D-8EA7-261FAD46E653}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Soenneker.Utils.AutoBogus.Tests.Console", "test\Soenneker.Utils.AutoBogus.Console\Soenneker.Utils.AutoBogus.Tests.Console.csproj", "{4BC4BD23-23A3-407D-8EA7-261FAD46E653}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
21 changes: 10 additions & 11 deletions src/AutoFaker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ List<TType> IAutoFaker.Generate<TType>(int count, Action<IAutoGenerateConfigBuil
return context.GenerateMany<TType>(count);
}


/// <summary>
/// Configures all faker instances and generate requests.
/// </summary>
Expand All @@ -54,12 +53,12 @@ public static AutoFaker Create(Action<IAutoGenerateConfigBuilder>? configure = n
{
var config = new AutoFakerConfig(DefaultConfigService.Config);

if (configure != null)
{
var builder = new AutoFakerConfigBuilder(config);
if (configure == null)
return new AutoFaker(config);

var builder = new AutoFakerConfigBuilder(config);

configure.Invoke(builder);
}
configure.Invoke(builder);

return new AutoFaker(config);
}
Expand Down Expand Up @@ -93,11 +92,11 @@ private AutoFakerContext CreateContext(Action<IAutoGenerateConfigBuilder>? confi
{
var config = new AutoFakerConfig(FakerConfig);

if (configure != null)
{
var builder = new AutoFakerConfigBuilder(config);
configure.Invoke(builder);
}
if (configure == null)
return new AutoFakerContext(config);

var builder = new AutoFakerConfigBuilder(config);
configure.Invoke(builder);

return new AutoFakerContext(config);
}
Expand Down
77 changes: 17 additions & 60 deletions src/AutoFakerBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ public class AutoFakerBinder : Binder, IAutoFakerBinder
/// <returns>The created instance of <typeparamref name="TType"/>.</returns>
public virtual TType? CreateInstance<TType>(AutoFakerContext? context)
{
if (context == null)
if (context == null)
return default;

Type type = typeof(TType);
CachedConstructor? constructor = GetConstructor<TType>();

CachedConstructor? constructor = GetConstructor(context.CachedType);

if (constructor == null)
return default;
Expand Down Expand Up @@ -60,7 +61,7 @@ public class AutoFakerBinder : Binder, IAutoFakerBinder
/// Due to the boxing nature of value types, the <paramref name="instance"/> parameter is an object. This means the populated
/// values are applied to the provided instance and not a copy.
/// </remarks>
public virtual void PopulateInstance<TType>(object instance, AutoFakerContext context, MemberInfo[]? members = null)
public virtual void PopulateInstance<TType>(object? instance, AutoFakerContext? context, MemberInfo[]? members = null)
{
// We can only populate non-null instances
if (instance == null || context == null)
Expand All @@ -86,9 +87,7 @@ public virtual void PopulateInstance<TType>(object instance, AutoFakerContext co
continue;
}

context.ParentType = type;
context.GenerateType = member.Type;
context.GenerateName = member.Name;
context.Setup(type, member.Type, member.Name);

context.TypesStack.Push(member.Type);

Expand All @@ -102,11 +101,11 @@ public virtual void PopulateInstance<TType>(object instance, AutoFakerContext co
{
member.Setter.Invoke(instance, value);
}
else if (member.Type.IsDictionary())
else if (member.CachedType.IsDictionary())
{
PopulateDictionary(value, instance, member);
}
else if (member.Type.IsCollection())
else if (member.CachedType.IsCollection())
{
PopulateCollection(value, instance, member);
}
Expand All @@ -124,62 +123,34 @@ public virtual void PopulateInstance<TType>(object instance, AutoFakerContext co
private static bool ShouldSkip(Type type, string path, AutoFakerContext context)
{
// Skip if the type is found
if (context.FakerConfig.SkipTypes.Contains(type))
if (context.AutoFakerConfig.SkipTypes.Contains(type))
{
return true;
}

// Skip if the path is found
if (context.FakerConfig.SkipPaths.Contains(path))
if (context.AutoFakerConfig.SkipPaths.Contains(path))
{
return true;
}

//check if tree depth is reached
int? treeDepth = context.FakerConfig.TreeDepth.Invoke(context);
int? treeDepth = context.AutoFakerConfig.TreeDepth.Invoke(context);

if (treeDepth.HasValue && context.TypesStack.Count >= treeDepth)
return true;

// Finally check if the recursive depth has been reached

int count = context.TypesStack.Count(t => t == type);
int recursiveDepth = context.FakerConfig.RecursiveDepth.Invoke(context);
int recursiveDepth = context.AutoFakerConfig.RecursiveDepth.Invoke(context);

return count >= recursiveDepth;
}

//private ConstructorInfo GetConstructor<TType>()
//{
// Type type = typeof(TType);
// ConstructorInfo[] constructors = type.GetConstructors();

// // For dictionaries and enumerables locate a constructor that is used for populating as well
// if (type.IsDictionary())
// {
// return ResolveTypedConstructor(typeof(IDictionary<,>), constructors);
// }

// if (type.IsEnumerable())
// {
// return ResolveTypedConstructor(typeof(IEnumerable<>), constructors);
// }

// // Attempt to find a default constructor
// // If one is not found, simply use the first in the list
// ConstructorInfo? defaultConstructor = (from c in constructors
// let p = c.GetParameters()
// where p.Count() == 0
// select c).SingleOrDefault();

// return defaultConstructor ?? constructors.FirstOrDefault();
//}

private static CachedConstructor? GetConstructor<TType>()
private static CachedConstructor? GetConstructor(CachedType type)
{
Type type = typeof(TType);

CachedConstructor[]? constructors = CacheService.Cache.GetCachedType(type).GetCachedConstructors();
CachedConstructor[]? constructors = type.GetCachedConstructors();

if (type.IsDictionary())
{
Expand All @@ -202,19 +173,6 @@ private static bool ShouldSkip(Type type, string path, AutoFakerContext context)
return constructors.Length > 0 ? constructors[0] : null;
}

//private static ConstructorInfo ResolveTypedConstructor(Type type, IEnumerable<ConstructorInfo> constructors)
//{
// // Find the first constructor that matches the passed generic definition
// return (from c in constructors
// let p = c.GetParameters()
// where p.Count() == 1
// let m = p.Single()
// where m.ParameterType.IsGenericType()
// let d = m.ParameterType.GetGenericTypeDefinition()
// where d == type
// select c).SingleOrDefault();
//}

private static CachedConstructor? ResolveTypedConstructor(Type type, CachedConstructor[] constructors)
{
for (int i = 0; i < constructors.Length; i++)
Expand Down Expand Up @@ -245,9 +203,7 @@ private static bool ShouldSkip(Type type, string path, AutoFakerContext context)

private static IAutoFakerGenerator GetParameterGenerator(Type type, ParameterInfo parameter, AutoFakerContext context)
{
context.ParentType = type;
context.GenerateType = parameter.ParameterType;
context.GenerateName = parameter.Name;
context.Setup(type, parameter.ParameterType, parameter.Name);

return GeneratorFactory.GetGenerator(context);
}
Expand All @@ -258,6 +214,7 @@ private List<AutoMember> GetMembersToPopulate(CachedType type, MemberInfo[]? mem
if (members != null)
{
var autoMembersList = new List<AutoMember>(members.Length);

for (int i = 0; i < members.Length; i++)
{
autoMembersList.Add(new AutoMember(members[i]));
Expand Down Expand Up @@ -297,11 +254,11 @@ private List<AutoMember> GetMembersToPopulate(CachedType type, MemberInfo[]? mem
if (!found)
{
// A readonly dictionary or collection member can use the Add() method
if (autoMember.IsReadOnly && autoMember.Type.IsDictionary())
if (autoMember.IsReadOnly && autoMember.CachedType.IsDictionary())
{
autoMembers.Add(autoMember);
}
else if (autoMember.IsReadOnly && autoMember.Type.IsCollection())
else if (autoMember.IsReadOnly && autoMember.CachedType.IsCollection())
{
autoMembers.Add(autoMember);
}
Expand Down
1 change: 0 additions & 1 deletion src/Config/AutoFakerConfigBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Linq;
using Bogus;
using Soenneker.Utils.AutoBogus.Abstract;
using Soenneker.Utils.AutoBogus.Config.Abstract;
using Soenneker.Utils.AutoBogus.Config.Base;
using Soenneker.Utils.AutoBogus.Context;
Expand Down
40 changes: 31 additions & 9 deletions src/Context/AutoFakerContext.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using Bogus;
using Soenneker.Reflection.Cache.Types;
using Soenneker.Utils.AutoBogus.Abstract;
using Soenneker.Utils.AutoBogus.Config;
using Soenneker.Utils.AutoBogus.Generators;
using Soenneker.Utils.AutoBogus.Services;

namespace Soenneker.Utils.AutoBogus.Context;

Expand All @@ -15,17 +17,19 @@ public sealed class AutoFakerContext
/// <summary>
/// The parent type of the type associated with the current generate request.
/// </summary>
public Type ParentType { get; set; }
public Type ParentType { get; private set; }

/// <summary>
/// The type associated with the current generate request.
/// </summary>
public Type GenerateType { get; internal set; }
public Type GenerateType { get; private set; }

public CachedType CachedType { get; private set; }

/// <summary>
/// The name associated with the current generate request.
/// </summary>
public string GenerateName { get; internal set; }
public string GenerateName { get; private set; }

/// <summary>
/// The underlying <see cref="Bogus.Faker"/> instance used to generate random values.
Expand All @@ -37,23 +41,41 @@ public sealed class AutoFakerContext
/// </summary>
public List<string> RuleSets { get; internal set; }

internal AutoFakerConfig FakerConfig { get; }
internal AutoFakerConfig AutoFakerConfig { get; }

internal Stack<Type> TypesStack { get; }

internal object Instance { get; set; }

internal IAutoFakerBinder FakerBinder => FakerConfig.FakerBinder;
internal IAutoFakerBinder FakerBinder => AutoFakerConfig.FakerBinder;

internal List<GeneratorOverride> Overrides => FakerConfig.Overrides;
internal List<GeneratorOverride> Overrides => AutoFakerConfig.Overrides;

internal AutoFakerContext(AutoFakerConfig fakerConfig)
internal AutoFakerContext(AutoFakerConfig autoFakerConfig, Type? type = null)
{
FakerConfig = fakerConfig;
AutoFakerConfig = autoFakerConfig;

Faker = fakerConfig.Faker!;
Faker = autoFakerConfig.Faker!;

TypesStack = new Stack<Type>();

RuleSets = [];

if (type != null)
Setup(type);
}

internal void Setup(Type parentType, Type generateType, string name)
{
ParentType = parentType;
GenerateType = generateType;
GenerateName = name;
CachedType = CacheService.Cache.GetCachedType(generateType);
}

internal void Setup(Type generateType)
{
GenerateType = generateType;
CachedType = CacheService.Cache.GetCachedType(generateType);
}
}
Loading

0 comments on commit 4dea920

Please sign in to comment.