Skip to content

Commit

Permalink
AutoFaker ctor now takes a config obj
Browse files Browse the repository at this point in the history
Removes some static config options
GeneratorService is now an instance to prevent cross AutoFaker contamination
Additional tests
Makes default repeat as 1
Updates Readme some
  • Loading branch information
soenneker committed Feb 11, 2024
1 parent b0e9120 commit 44efd67
Show file tree
Hide file tree
Showing 23 changed files with 344 additions and 374 deletions.
31 changes: 15 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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<string>();
var randomWord = autoFaker.Generate<string>();
var dictionary = autoFaker.Generate<Dictionary<int, string>>();
var order = autoFaker.Generate<Order>();
```

- 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<Order>
Expand All @@ -61,7 +60,7 @@ public class OrderOverride : AutoFakerOverride<Order>
}
```

- Configuring `AutoFakerOverride` on the `AutoFaker`:
Then just add `AutoFakerOverride` to the `AutoFaker.Config` instance:

```csharp
autoFaker.Config.Overrides = new AutoFakerOverrides();
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/Abstract/IAutoFakerBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Soenneker.Utils.AutoBogus.Abstract;

/// <summary>
/// An interface for binding generated instances.
/// For binding generated instances.
/// </summary>
public interface IAutoFakerBinder
{
Expand Down
14 changes: 13 additions & 1 deletion src/AutoFaker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ public sealed class AutoFaker : IAutoFaker

public Faker Faker { get; set; }

public AutoFaker(Action<IAutoGenerateConfigBuilder>? 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<IAutoGenerateConfigBuilder>? configure)
{
Faker = new Faker();

Expand Down
9 changes: 6 additions & 3 deletions src/AutoFakerBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@

namespace Soenneker.Utils.AutoBogus;

/// <summary>
/// A class for binding generated instances.
/// </summary>
///<inheritdoc cref="IAutoFakerBinder"/>
public class AutoFakerBinder : IAutoFakerBinder
{
private readonly AutoFakerConfig _autoFakerConfig;

internal readonly GeneratorService GeneratorService;

private readonly Dictionary<CachedType, List<AutoMember>> _autoMembersCache = [];
private readonly Dictionary<CachedType, CachedConstructor> _constructorsCache = [];

public AutoFakerBinder(AutoFakerConfig autoFakerConfig)
{
_autoFakerConfig = autoFakerConfig;
GeneratorService = new GeneratorService();
}

/// <summary>
Expand Down Expand Up @@ -81,6 +82,7 @@ public void PopulateInstance<TType>(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))
Expand Down Expand Up @@ -249,6 +251,7 @@ private List<AutoMember> GetMembersToPopulate(CachedType cachedType)
autoMembers.Add(new AutoMember(field, _autoFakerConfig));
}
}

_autoMembersCache.TryAdd(cachedType, autoMembers);

return autoMembers;
Expand Down
26 changes: 10 additions & 16 deletions src/AutoMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,18 @@ internal sealed class AutoMember

internal readonly Func<object, object?> Getter;

internal readonly Action<object, object?> Setter;
internal readonly Action<object, object?>? 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;
Expand All @@ -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)
Expand All @@ -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;
Expand Down
18 changes: 12 additions & 6 deletions src/Config/AutoFakerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ namespace Soenneker.Utils.AutoBogus.Config;

public sealed class AutoFakerConfig
{
/// <summary>
/// The Bogus.Faker locale to use when generating values.
/// </summary>
public string Locale;

/// <summary>
/// Registers the number of items to generate for a collection.
/// </summary>
public int RepeatCount;

public int DataTableRowCount;
Expand All @@ -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;
}
}
32 changes: 1 addition & 31 deletions src/Config/AutoFakerConfigBuilder.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -20,10 +19,7 @@ internal AutoFakerConfigBuilder(AutoFakerConfig autoFakerConfig, AutoFaker autoF
}

internal object[]? Args { get; private set; }

IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConfigBuilder>.WithLocale(string locale) => WithLocale<IAutoFakerDefaultConfigBuilder>(locale, this);

IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConfigBuilder>.WithRepeatCount(int count) => WithRepeatCount<IAutoFakerDefaultConfigBuilder>(count, this);
IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConfigBuilder>.WithDataTableRowCount(int count) => WithDataTableRowCount<IAutoFakerDefaultConfigBuilder>(count, this);

IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConfigBuilder>.WithRecursiveDepth(int depth) => WithRecursiveDepth<IAutoFakerDefaultConfigBuilder>(depth, this);
Expand All @@ -41,9 +37,6 @@ IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConf
IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConfigBuilder>.WithOverride(AutoFakerGeneratorOverride autoFakerGeneratorOverride) =>
WithOverride<IAutoFakerDefaultConfigBuilder>(autoFakerGeneratorOverride, this);

IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder<IAutoGenerateConfigBuilder>.WithLocale(string locale) => WithLocale<IAutoGenerateConfigBuilder>(locale, this);
IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder<IAutoGenerateConfigBuilder>.WithRepeatCount(int count) => WithRepeatCount<IAutoGenerateConfigBuilder>(count, this);

IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder<IAutoGenerateConfigBuilder>.WithDataTableRowCount(int count) => WithDataTableRowCount<IAutoGenerateConfigBuilder>(count, this);

IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder<IAutoGenerateConfigBuilder>.WithRecursiveDepth(int depth) => WithRecursiveDepth<IAutoGenerateConfigBuilder>(depth, this);
Expand All @@ -59,9 +52,6 @@ IAutoFakerDefaultConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerDefaultConf
IAutoGenerateConfigBuilder IBaseAutoFakerConfigBuilder<IAutoGenerateConfigBuilder>.WithOverride(AutoFakerGeneratorOverride autoFakerGeneratorOverride) =>
WithOverride<IAutoGenerateConfigBuilder>(autoFakerGeneratorOverride, this);

IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerConfigBuilder>.WithLocale(string locale) => WithLocale<IAutoFakerConfigBuilder>(locale, this);
IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerConfigBuilder>.WithRepeatCount(int count) => WithRepeatCount<IAutoFakerConfigBuilder>(count, this);

IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerConfigBuilder>.WithDataTableRowCount(int count) => WithDataTableRowCount<IAutoFakerConfigBuilder>(count, this);

IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerConfigBuilder>.WithRecursiveDepth(int depth) => WithRecursiveDepth<IAutoFakerConfigBuilder>(depth, this);
Expand All @@ -78,20 +68,6 @@ IAutoFakerConfigBuilder IBaseAutoFakerConfigBuilder<IAutoFakerConfigBuilder>.Wit

IAutoFakerConfigBuilder IAutoFakerConfigBuilder.WithArgs(params object[] args) => WithArgs<IAutoFakerConfigBuilder>(args, this);

internal TBuilder WithLocale<TBuilder>(string locale, TBuilder builder)
{
_autoFakerConfig.Locale = locale;

return builder;
}

internal TBuilder WithRepeatCount<TBuilder>(int count, TBuilder builder)
{
_autoFakerConfig.RepeatCount = count;

return builder;
}

internal TBuilder WithDataTableRowCount<TBuilder>(int count, TBuilder builder)
{
_autoFakerConfig.DataTableRowCount = count;
Expand All @@ -113,19 +89,13 @@ internal TBuilder WithTreeDepth<TBuilder>(int? depth, TBuilder builder)
return builder;
}

private TBuilder WithBinder<TBuilder>(AutoFakerBinder? fakerBinder, TBuilder builder)
private TBuilder WithBinder<TBuilder>(AutoFakerBinder fakerBinder, TBuilder builder)
{
_autoFaker.Binder = fakerBinder;

return builder;
}

internal TBuilder WithFaker<TBuilder>(Faker faker, TBuilder builder)
{
_autoFaker.Faker = faker;
return builder;
}

internal TBuilder WithSkip<TBuilder>(Type type, TBuilder builder)
{
_autoFakerConfig.SkipTypes ??= [];
Expand Down
12 changes: 6 additions & 6 deletions src/Config/AutoFakerDefaultConfigOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
14 changes: 0 additions & 14 deletions src/Config/Base/IBaseAutoFakerConfigBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,6 @@ namespace Soenneker.Utils.AutoBogus.Config.Base;
/// <typeparam name="TBuilder">The builder type.</typeparam>
public interface IBaseAutoFakerConfigBuilder<TBuilder>
{
/// <summary>
/// Registers the locale to use when generating values.
/// </summary>
/// <param name="locale">The locale to use.</param>
/// <returns>The current configuration builder instance.</returns>
TBuilder WithLocale(string locale);

/// <summary>
/// Registers the number of items to generate for a collection.
/// </summary>
/// <param name="count">The repeat count to use.</param>
/// <returns>The current configuration builder instance.</returns>
TBuilder WithRepeatCount(int count);

/// <summary>
/// Registers the number of rows to generate in a <see cref="System.Data.DataTable"/>.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions src/Generators/AutoFakerGeneratorFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Loading

0 comments on commit 44efd67

Please sign in to comment.