From b74305588207e7fd5382edaa339c801e83d8f98c Mon Sep 17 00:00:00 2001 From: Basyras Date: Mon, 23 Nov 2020 18:34:22 +0100 Subject: [PATCH 1/2] UseConstructor(), SkipConstructor() and fixing StrictMode() error --- Source/Bogus.Tests/FakerTests.cs | 237 +++++++++++++++ .../Models/HiddenParameterlessClass.cs | 15 + .../Models/NoParameterlessCtorClass.cs | 14 + .../Models/ParameterlessCtorClass.cs | 15 + Source/Bogus/Faker[T].cs | 269 +++++++++++++----- Source/Bogus/NoParameterelessCtorException.cs | 20 ++ 6 files changed, 497 insertions(+), 73 deletions(-) create mode 100644 Source/Bogus.Tests/FakerTests.cs create mode 100644 Source/Bogus.Tests/Models/HiddenParameterlessClass.cs create mode 100644 Source/Bogus.Tests/Models/NoParameterlessCtorClass.cs create mode 100644 Source/Bogus.Tests/Models/ParameterlessCtorClass.cs create mode 100644 Source/Bogus/NoParameterelessCtorException.cs diff --git a/Source/Bogus.Tests/FakerTests.cs b/Source/Bogus.Tests/FakerTests.cs new file mode 100644 index 00000000..dfb150bb --- /dev/null +++ b/Source/Bogus.Tests/FakerTests.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Bogus.DataSets; +using Bogus.Extensions; +using Bogus.Tests.Models; +using FluentAssertions; +using Xunit; + + +namespace Bogus.Tests +{ + public class FakerTests + { + [Fact] + public void SkipConstructor_Default_StrictMode_Satisfied() + { + _ = new Faker() + .SkipConstructor() + .RuleFor(x => x.Obj, x => null) + .RuleFor(x => x.Obj2, x => null) + .RuleFor(x => x.Obj3, x => null) + .Generate(1); + } + + [Fact] + public void SkipConstructor_WithRule_Default_StrictMode_Not_Satisfied() + { + Assert.Throws(() => + { + _ = new Faker() + .SkipConstructor() + .RuleFor(x => x.Obj, x => null) + .Generate(1); + }); + } + + [Fact] + public void SkipConstructor_WithoutRules_Default_StrictMode_Not_Satisfied() + { + Assert.Throws(() => + { + _ = new Faker() + .SkipConstructor() + .Generate(1); + }); + } + + [Fact] + public void Not_Skipping_Constructor_Without_Parameterless_Ctor() + { + Assert.Throws>(() => + { + _ = new Faker() + .Generate(1); + }); + } + + [Fact] + public void Skipping_Constructor_Overiding_StrictMode() + { + + var faker = new Faker() + .SkipConstructor() + .StrictMode(false); + + Assert.Contains(faker.StrictModes, (x => x.Value == false)); + _ = faker.Generate(1); + + + + Assert.Throws(() => + { + faker = new Faker() + .SkipConstructor() + .StrictMode(true); + + Assert.Contains(faker.StrictModes, (x => x.Value == true)); + _ = faker.Generate(1); + + }); + + } + + + [Fact] + public void UseConstructor() + { + var faker = new Faker() + .UseConstructor(x => new NoParameterlessCtorClass(new Order(), 5)); + faker.Generate(1); + + var faker2 = new Faker() + .UseConstructor(x => new Order() { OrderId = 68 }); + var order = faker2.Generate(1)[0]; + + Assert.Equal(68, order.OrderId); + } + + + [Fact] + public void UseConstructor_WithRule_Default_StrictMode_Not_Satisfied() + { + Assert.Throws(() => + { + _ = new Faker() + .UseConstructor(x => new NoParameterlessCtorClass(default, default)) + .StrictMode(true) + .RuleFor(x => x.Obj, x => null) + .Generate(1); + }); + } + + [Fact] + public void UseConstructor_WithoutRules_Default_StrictMode_Not_Satisfied() + { + Assert.Throws(() => + { + _ = new Faker() + .StrictMode(true) + .UseConstructor(x => new NoParameterlessCtorClass(default, default)) + .Generate(1); + }); + } + + + [Fact] + public void UseContructor_After_SkipConstructor() + { + var faker = new Faker() + .StrictMode(false) + .UseConstructor(x => throw new Exception("Use Constructor was not overriden")) + .SkipConstructor(); + _ = faker.Generate(1); + + var faker2 = new Faker() + .StrictMode(false) + .UseConstructor(x => throw new Exception("Use Constructor was not overriden")) + .SkipConstructor(); + + _ = faker2.Generate(1); + + } + + [Fact] + public void SkipConstructor_After_UseContructor() + { + + var faker = new Faker() + .StrictMode(false) + .SkipConstructor() + .UseConstructor(x => new NoParameterlessCtorClass(new Order(), 5)); + var instance = faker.Generate(1)[0]; + Assert.Equal(5, instance.Obj2); + + var faker2 = new Faker() + .StrictMode(false) + .SkipConstructor() + .UseConstructor(x => new Order() { OrderId = 68 }); + var order = faker2.Generate(1)[0]; + Assert.Equal(68, order.OrderId); + + } + + + [Fact] + public void UseParameterlessConstructor_Hidden_Ctor() + { + Assert.Throws>(() => + { + var faker = new Faker() + .UseConstructor(true); + _ = faker.Generate(1); + }); + + Assert.Throws>(() => + { + var faker2 = new Faker() + .UseConstructor(true); + _ = faker2.Generate(1); + }); + + var faker2 = new Faker() + .UseConstructor(true); + _ = faker2.Generate(1); + } + + [Fact] + public void UseParameterlessConstructor_Public_Ctor() + { + Assert.Throws>(() => + { + var faker = new Faker() + .UseConstructor(false); + _ = faker.Generate(1); + }); + + var faker2 = new Faker() + .UseConstructor(false); + _ = faker2.Generate(1); + + Assert.Throws>(() => + { + var faker3 = new Faker() + .UseConstructor(false); + _ = faker3.Generate(1); + }); + } + + [Fact] + public void GenerateDefaultConstructor() + { + + Assert.Throws>(() => + { + var faker = new Faker(); + _ = faker.Generate(1); + }); + + var faker2 = new Faker(); + _ = faker2.Generate(1); + + Assert.Throws>(() => + { + + var faker3 = new Faker(); + _ = faker3.Generate(1); + }); + + } + + + + } + + +} diff --git a/Source/Bogus.Tests/Models/HiddenParameterlessClass.cs b/Source/Bogus.Tests/Models/HiddenParameterlessClass.cs new file mode 100644 index 00000000..e36e2c84 --- /dev/null +++ b/Source/Bogus.Tests/Models/HiddenParameterlessClass.cs @@ -0,0 +1,15 @@ +using System; + +public class HiddenParameterlessCtorClass +{ + + + protected HiddenParameterlessCtorClass() + { + + } + + public object Obj { get; } + public object Obj2 { get; set; } + public object Obj3; +} diff --git a/Source/Bogus.Tests/Models/NoParameterlessCtorClass.cs b/Source/Bogus.Tests/Models/NoParameterlessCtorClass.cs new file mode 100644 index 00000000..3599e8bd --- /dev/null +++ b/Source/Bogus.Tests/Models/NoParameterlessCtorClass.cs @@ -0,0 +1,14 @@ +using System; + +public class NoParameterlessCtorClass +{ + public NoParameterlessCtorClass(object obj, object obj2) + { + Obj = obj; + Obj2 = obj2; + } + + public object Obj { get; } + public object Obj2 { get; set; } + public object Obj3; +} diff --git a/Source/Bogus.Tests/Models/ParameterlessCtorClass.cs b/Source/Bogus.Tests/Models/ParameterlessCtorClass.cs new file mode 100644 index 00000000..02beb319 --- /dev/null +++ b/Source/Bogus.Tests/Models/ParameterlessCtorClass.cs @@ -0,0 +1,15 @@ +using System; + +public class ParameterlessCtorClass +{ + + + public ParameterlessCtorClass() + { + + } + + public object Obj { get; } + public object Obj2 { get; set; } + public object Obj3; +} diff --git a/Source/Bogus/Faker[T].cs b/Source/Bogus/Faker[T].cs index 4e8537d7..1386b490 100644 --- a/Source/Bogus/Faker[T].cs +++ b/Source/Bogus/Faker[T].cs @@ -44,7 +44,7 @@ public class Faker : IFakerTInternal, ILocaleAware, IRuleSet where T : cla { #pragma warning disable 1591 protected const string Default = "default"; - private static readonly string[] DefaultRuleSet = {Default}; + private static readonly string[] DefaultRuleSet = { Default }; protected internal Faker FakerHub; protected internal IBinder binder; @@ -55,8 +55,9 @@ public class Faker : IFakerTInternal, ILocaleAware, IRuleSet where T : cla protected internal Dictionary> CreateActions = new Dictionary>(StringComparer.OrdinalIgnoreCase); protected internal readonly Dictionary TypeProperties; protected internal readonly Dictionary> SetterCache = new Dictionary>(StringComparer.OrdinalIgnoreCase); - + protected internal Dictionary StrictModes = new Dictionary(); + protected internal bool? IsValid; protected internal string currentRuleSet = Default; protected internal int? localSeed; // if null, the global Randomizer.Seed is used. @@ -81,32 +82,32 @@ public Faker Clone() //copy internal state. //strict modes. - foreach( var root in this.StrictModes ) + foreach (var root in this.StrictModes) { clone.StrictModes.Add(root.Key, root.Value); } //create actions - foreach( var root in this.CreateActions ) + foreach (var root in this.CreateActions) { clone.CreateActions[root.Key] = root.Value; } //finalize actions - foreach( var root in this.FinalizeActions ) + foreach (var root in this.FinalizeActions) { clone.FinalizeActions.Add(root.Key, root.Value); } //actions - foreach( var root in this.Actions ) + foreach (var root in this.Actions) { - foreach( var kv in root.Value ) + foreach (var kv in root.Value) { clone.Actions.Add(root.Key, kv.Key, kv.Value); } } - if( localSeed.HasValue ) + if (localSeed.HasValue) { clone.UseSeed(localSeed.Value); } @@ -140,11 +141,27 @@ public Faker(string locale) : this(locale, null) /// A binder that discovers properties or fields on T that are candidates for faking. Null uses the default Binder. public Faker(string locale = "en", IBinder binder = null) { +#warning In future add record autodecetion this.binder = binder ?? new Binder(); this.Locale = locale; FakerHub = new Faker(locale); TypeProperties = this.binder.GetMembers(typeof(T)); - this.CreateActions[Default] = faker => Activator.CreateInstance(); + + this.CreateActions[Default] = GetDefaultCreateAction; + //this.UseConstructor(); + } + + private static T GetDefaultCreateAction(Faker faker) + { + try + { + return Activator.CreateInstance(); + } + catch (MissingMethodException ex) + { + throw new NoParameterlessCtorException(false,ex); + } + } /// @@ -159,16 +176,108 @@ public virtual Faker UseSeed(int seed) return this; } + /// /// Instructs to use the factory method as a source /// for new instances of . /// + [Obsolete(nameof(CustomInstantiator) + "() has been renamed. Use " + nameof(UseConstructor) + " instead.")] public virtual Faker CustomInstantiator(Func factoryMethod) + { + return UseConstructor(factoryMethod); + } + + /// + /// Instructs to use the factory method as a source + /// for new instances of . + /// + public virtual Faker UseConstructor(Func factoryMethod) { this.CreateActions[currentRuleSet] = factoryMethod; return this; + + + } + + /// + /// Will use public parameterless constructor. If parameterless constructor does not exits exception is thrown + /// + /// + public virtual Faker UseConstructor() + { + return UseConstructor(false); } + + /// + /// Will use default public/private/protected parameterless constructor (based on ). If parameterless constructor does not exits exception is thrown + /// + /// + /// + public virtual Faker UseConstructor(bool isConstructorHidden) + { + +#if NETSTANDARD1_3 + throw new NotSupportedException($"{nameof(UseConstructor)}() is not supported in .net standart 1.3. Consider using {nameof(UseConstructor)}()."); +#else + + var constructorModifier = isConstructorHidden ? BindingFlags.NonPublic : BindingFlags.Public; + var constructor = typeof(T).GetConstructor(BindingFlags.Instance | constructorModifier, null, Type.EmptyTypes, null); + if (constructor == null) + { + throw new NoParameterlessCtorException(isConstructorHidden, null); + } + + + this.CreateActions[currentRuleSet] = (Faker f) => + { + T instance; + try + { + //var constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null); + instance = (T)Activator.CreateInstance(typeof(T), nonPublic: isConstructorHidden); + } + catch (MissingMethodException ex) + { + throw new NoParameterlessCtorException(isConstructorHidden, ex); + } + return instance; + }; + + return this; +#endif + } + + + + /// + /// Creates instance of without calling any constructor. + /// Use only when atleast one apply:
+ /// - is record / struct or does not have any logic in constructor excpect setting properties or public fields
+ /// - If you need features that can't be used with + /// Consider using or + ///
+ /// + public virtual Faker SkipConstructor() + { +#if NETSTANDARD1_3 + throw new NotSupportedException($"{nameof(SkipConstructor)}() is not supported in .net standart 1.3. Consider using {nameof(UseConstructor)}()."); +#else + //Not sure wich works better + //this.CreateActions[Default] = (Faker faker) => (T)FormatterServices.GetUninitializedObject(typeof(T)); + UseConstructor((Faker faker) => (T)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(T))); + //When StrictMode is not manually called by SetStrictMode() it should by default true when skipping contructor + if (StrictModes.Count == 0) + { + StrictModes.Add(Default, true); + } + return this; +#endif + + } + + + /// /// Creates a rule for a compound property and providing access to the instance being generated. /// @@ -237,18 +346,18 @@ public virtual Faker RuleFor(string propertyOrFieldName, Func with the appropriate " + $"System.Reflection.BindingFlags that allows deeper reflection into {typeof(T)}."); - + return AddRule(propertyOrFieldName, (f, t) => setter(f, t)); } protected virtual Faker AddRule(string propertyOrField, Func invoker) { var rule = new PopulateAction - { - Action = invoker, - RuleSet = currentRuleSet, - PropertyName = propertyOrField, - }; + { + Action = invoker, + RuleSet = currentRuleSet, + PropertyName = propertyOrField, + }; this.Actions.Add(currentRuleSet, propertyOrField, rule); @@ -270,12 +379,12 @@ public virtual Faker Rules(Action setActions) }; var guid = Guid.NewGuid().ToString(); var rule = new PopulateAction - { - Action = invoker, - RuleSet = currentRuleSet, - PropertyName = guid, - ProhibitInStrictMode = true - }; + { + Action = invoker, + RuleSet = currentRuleSet, + PropertyName = guid, + ProhibitInStrictMode = true + }; this.Actions.Add(currentRuleSet, guid, rule); return this; } @@ -288,17 +397,17 @@ public virtual Faker Rules(Action setActions) ///
public virtual Faker RuleForType(Type type, Func setterForType) { - if( typeof(TType) != type ) + if (typeof(TType) != type) { throw new ArgumentException($"{nameof(TType)} must be the same type as parameter named '{nameof(type)}'"); } - foreach( var kvp in this.TypeProperties ) + foreach (var kvp in this.TypeProperties) { var propOrFieldType = GetFieldOrPropertyType(kvp.Value); var propOrFieldName = kvp.Key; - if( propOrFieldType == type ) + if (propOrFieldType == type) { RuleFor(propOrFieldName, setterForType); } @@ -312,11 +421,11 @@ public virtual Faker RuleForType(Type type, Func setterF /// protected virtual Type GetFieldOrPropertyType(MemberInfo mi) { - if( mi is PropertyInfo pi ) + if (mi is PropertyInfo pi) { return pi.PropertyType; } - if( mi is FieldInfo fi ) + if (mi is FieldInfo fi) { return fi.FieldType; } @@ -332,7 +441,8 @@ protected virtual Type GetFieldOrPropertyType(MemberInfo mi) /// The set of rules to apply when this rules set is specified. public virtual Faker RuleSet(string ruleSetName, Action> action) { - if( currentRuleSet != Default ) throw new ArgumentException("Cannot create a rule set within a rule set."); + if (currentRuleSet != Default) + throw new ArgumentException("Cannot create a rule set within a rule set."); currentRuleSet = ruleSetName; action(this); currentRuleSet = Default; @@ -364,11 +474,11 @@ public virtual Faker Ignore(string propertyOrFieldName) $"System.Reflection.BindingFlags that allows deeper reflection into {typeof(T)}."); var rule = new PopulateAction - { - Action = null, - RuleSet = currentRuleSet, - PropertyName = propertyOrFieldName - }; + { + Action = null, + RuleSet = currentRuleSet, + PropertyName = propertyOrFieldName + }; this.Actions.Add(currentRuleSet, propertyOrFieldName, rule); @@ -404,10 +514,10 @@ public virtual Faker StrictMode(bool ensureRulesForAllProperties) public virtual Faker FinishWith(Action action) { var rule = new FinalizeAction - { - Action = action, - RuleSet = currentRuleSet - }; + { + Action = action, + RuleSet = currentRuleSet + }; this.FinalizeActions[currentRuleSet] = rule; return this; } @@ -418,7 +528,8 @@ public virtual Faker FinishWith(Action action) protected virtual string[] ParseDirtyRulesSets(string dirtyRules) { dirtyRules = dirtyRules?.Trim(',').Trim(); - if( string.IsNullOrWhiteSpace(dirtyRules) ) return DefaultRuleSet; + if (string.IsNullOrWhiteSpace(dirtyRules)) + return DefaultRuleSet; return dirtyRules.Split(',') .Where(s => !string.IsNullOrWhiteSpace(s)) .Select(s => s.Trim()).ToArray(); @@ -440,7 +551,7 @@ public virtual T Generate(string ruleSets = null) Func createRule = null; var cleanRules = ParseDirtyRulesSets(ruleSets); - if( string.IsNullOrWhiteSpace(ruleSets) ) + if (string.IsNullOrWhiteSpace(ruleSets)) { createRule = CreateActions[Default]; } @@ -514,7 +625,7 @@ public virtual IEnumerable GenerateLazy(int count, string ruleSets = null) /// public virtual IEnumerable GenerateForever(string ruleSets = null) { - while( true ) + while (true) { yield return this.Generate(ruleSets); } @@ -553,40 +664,41 @@ public virtual void Populate(T instance, string ruleSets = null) protected virtual void PopulateInternal(T instance, string[] ruleSets) { ValidationResult vr = null; - if( !IsValid.HasValue ) + if (!IsValid.HasValue) { //run validation vr = ValidateInternal(ruleSets); this.IsValid = vr.IsValid; } - if( !IsValid.GetValueOrDefault() ) + if (!IsValid.GetValueOrDefault()) { throw MakeValidationException(vr ?? ValidateInternal(ruleSets)); } - lock( Randomizer.Locker.Value ) + lock (Randomizer.Locker.Value) { //Issue 57 - Make sure you generate a new context // before executing any rules. //Issue 143 - If the FakerHub doesn't have any context // (eg NewContext() has never been called), then call it // so we can increment IndexGlobal and IndexFaker. - if( !this.FakerHub.HasContext ) FakerHub.NewContext(); + if (!this.FakerHub.HasContext) + FakerHub.NewContext(); - foreach( var ruleSet in ruleSets ) + foreach (var ruleSet in ruleSets) { - if( this.Actions.TryGetValue(ruleSet, out var populateActions) ) + if (this.Actions.TryGetValue(ruleSet, out var populateActions)) { - foreach( var action in populateActions.Values ) + foreach (var action in populateActions.Values) { PopulateProperty(instance, action); } } } - foreach( var ruleSet in ruleSets ) + foreach (var ruleSet in ruleSets) { - if( this.FinalizeActions.TryGetValue(ruleSet, out FinalizeAction finalizer) ) + if (this.FinalizeActions.TryGetValue(ruleSet, out FinalizeAction finalizer)) { finalizer.Action(this.FakerHub, instance); } @@ -598,20 +710,23 @@ protected virtual void PopulateInternal(T instance, string[] ruleSets) private void PopulateProperty(T instance, PopulateAction action) { var valueFactory = action.Action; - if (valueFactory is null) return; // An .Ignore() rule. + if (valueFactory is null) + return; // An .Ignore() rule. var value = valueFactory(FakerHub, instance); - + if (SetterCache.TryGetValue(action.PropertyName, out var setter)) { setter(instance, value); return; } - - if (!TypeProperties.TryGetValue(action.PropertyName, out var member)) return; - if (member == null) return; // Member would be null if this was a .Rules() - // The valueFactory is already invoked - // which does not select a property or field. + + if (!TypeProperties.TryGetValue(action.PropertyName, out var member)) + return; + if (member == null) + return; // Member would be null if this was a .Rules() + // The valueFactory is already invoked + // which does not select a property or field. lock (_setterCreateLock) { @@ -626,8 +741,9 @@ private void PopulateProperty(T instance, PopulateAction action) // TODO FieldInfo will need to rely on ILEmit to create a delegate else if (member is FieldInfo field) setter = (i, v) => field?.SetValue(i, v); - if (setter == null) return; - + if (setter == null) + return; + SetterCache.Add(action.PropertyName, setter); setter(instance, value); } @@ -662,7 +778,7 @@ public virtual bool Validate(string ruleSets = null) public virtual void AssertConfigurationIsValid(string ruleSets = null) { string[] rules; - if( ruleSets is null ) + if (ruleSets is null) { rules = this.Actions.Keys.ToArray(); } @@ -672,7 +788,7 @@ public virtual void AssertConfigurationIsValid(string ruleSets = null) } var result = ValidateInternal(rules); - if( !result.IsValid ) + if (!result.IsValid) { throw MakeValidationException(result); } @@ -692,26 +808,32 @@ protected virtual ValidationException MakeValidationException(ValidationResult r builder.AppendLine(); }); - builder.AppendLine("Validation was called to ensure all properties / fields have rules.") - .AppendLine($"There are missing rules for Faker '{typeof(T).Name}'.") - .AppendLine("=========== Missing Rules ==========="); - foreach( var fieldOrProp in result.MissingRules ) + if (result.MissingRules.Count > 0) { - builder.AppendLine(fieldOrProp); + builder.AppendLine("Validation was called to ensure all properties / fields have rules.") + .AppendLine($"There are missing rules for Faker '{typeof(T).Name}'.") + .AppendLine("=========== Missing Rules ==========="); + + foreach (var fieldOrProp in result.MissingRules) + { + builder.AppendLine(fieldOrProp); + } } + + return new ValidationException(builder.ToString().Trim()); } private ValidationResult ValidateInternal(string[] ruleSets) { - var result = new ValidationResult {IsValid = true}; + var result = new ValidationResult { IsValid = true }; var binderPropsOrFieldsOfT = this.TypeProperties.Keys; - foreach( var rule in ruleSets ) + foreach (var rule in ruleSets) { - if( this.StrictModes.TryGetValue(rule, out var strictMode) ) + if (this.StrictModes.TryGetValue(rule, out var strictMode)) { } else @@ -720,13 +842,14 @@ private ValidationResult ValidateInternal(string[] ruleSets) } //If strictMode is not enabled, skip and move on to the next ruleSet. - if( !strictMode ) continue; + if (!strictMode) + continue; this.Actions.TryGetValue(rule, out var populateActions); var userSet = new HashSet(StringComparer.OrdinalIgnoreCase); - if( populateActions != null ) + if (populateActions != null) { userSet.UnionWith(populateActions.Keys); } @@ -740,14 +863,14 @@ private ValidationResult ValidateInternal(string[] ruleSets) //What's left in userSet is the set of properties or fields //that the user does not know about + .Rule() methods. - if( userSet.Count > 0 ) + if (userSet.Count > 0) { - foreach( var propOrFieldOfT in userSet ) + foreach (var propOrFieldOfT in userSet) { - if( populateActions.TryGetValue(propOrFieldOfT, out var populateAction) ) + if (populateActions != null && populateActions.TryGetValue(propOrFieldOfT, out var populateAction)) { // Very much a .Rules() action - if( populateAction.ProhibitInStrictMode ) + if (populateAction.ProhibitInStrictMode) { result.ExtraMessages.Add( $"When StrictMode is set to True the Faker<{typeof(T).Name}>.Rules(...) method cannot verify that all properties have rules. You need to use Faker<{typeof(T).Name}>.RuleFor( x => x.Prop, ...) for each property to ensure each property has an associated rule when StrictMode is true; otherwise, set StrictMode to False in order to use Faker<{typeof(T).Name}>.Rules() method."); diff --git a/Source/Bogus/NoParameterelessCtorException.cs b/Source/Bogus/NoParameterelessCtorException.cs new file mode 100644 index 00000000..e43d2d1d --- /dev/null +++ b/Source/Bogus/NoParameterelessCtorException.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Bogus +{ + /// + /// Used when + /// + public class NoParameterlessCtorException : Exception where T : class + { + public NoParameterlessCtorException(bool isHiddenConstructor,MissingMethodException innerException = null) + : base($"Could not find {(isHiddenConstructor ? "hidden" : "public")} parameterless constructor in {typeof(T).Name}. Consider using {nameof(Faker.SkipConstructor)}(), {nameof(Faker.UseConstructor)}() or provide {(isHiddenConstructor ? "hidden" : "public")} parameterless contructor in {typeof(T).Name}", innerException) + { + + } + + } +} From 4994e5e3bb8f6f9e617fdd717a712857834d98f8 Mon Sep 17 00:00:00 2001 From: Basyras Date: Mon, 23 Nov 2020 19:05:41 +0100 Subject: [PATCH 2/2] Fixing xml comment --- Source/Bogus/Faker[T].cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Bogus/Faker[T].cs b/Source/Bogus/Faker[T].cs index 1386b490..dc7ac674 100644 --- a/Source/Bogus/Faker[T].cs +++ b/Source/Bogus/Faker[T].cs @@ -255,7 +255,7 @@ public virtual Faker UseConstructor(bool isConstructorHidden) /// Use only when atleast one apply:
/// - is record / struct or does not have any logic in constructor excpect setting properties or public fields
/// - If you need features that can't be used with - /// Consider using or + /// Consider using /> /// /// public virtual Faker SkipConstructor()