Coder Social home page Coder Social logo

modelbuilder's People

Contributors

andynish avatar bermo avatar dependabot[bot] avatar roryprimrose avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

mahfuzali bermo

modelbuilder's Issues

Apply ExecuteOrderRules when generating parameters

Currently the parameters for a constructor are generated within the loop of the identified parameters on a constructor. This set of parameters could be created by applying the ExecuteOrderRules on the build configuration so that related data could be populated and then resorting them to their constructor parameter order

Interpretation of Type on ExecuteOrderRule is confusing and used in two different ways

The DefaultBuildStrategyCompiler uses type on ExecuteOrderRules to identify the ordering of evaluation by property type. The DefaultExecuteStrategy uses the rules against the property type so this works as intended.

The expression extension methods however use the owning type of the property to register a rule. This work syntactically but is very broken when the rule is used by DefaultExecuteStrategy.

For example:


    public static partial class Create
    {
        public static T Model<T>()
        {
            var compiler = ModelBuilder.Model.BuildStrategy.Clone();

            compiler.AddExecuteOrderRule<Skill>(x => x.YearStarted, 4000);
            compiler.AddExecuteOrderRule<Skill>(x => x.YearLastUsed, 3000);

            compiler.AddValueGenerator<YearInPastValueGenerator>();

            var builder = compiler.Compile();

            return builder.Create<T>();
        }
    }

This should add order rules such that YearStarted is evaluated first and YearLastUsed is evaluated afterwards. The bug is that AddExecuteOrderRule creates an order rule against typeof(Skill) instead of typeof(int?) which is the property type determined from the expression.

Both scenarios are valid cases. There should be the option to target the ExecuteOrderRule against a property type as well as owning type of the property. This would cater for being able to run strings after enums for example, while also using expressions to target specific properties.

BuildConfigurationExtensions does not support all OOTB types

Some of the types in the new refactor do not have supported extension methods on IBuildConfiguration. For example, you can only add a creation rule using an expression but not regex or predicate. Other types of extensibility points are also missing overloads

Ignoring from Model should return a IBuildStrategy<T>

Consider the following:

Model.Ignoring<ValueTypeException>(x => x.Data).Create<ValueTypeException>();

This should already know the type being created such that it can be written as

Model.Ignoring<ValueTypeException>(x => x.Data).Create();

and still have it being strongly typed.

Models with read-only instance properties are not populated

DefaultExecuteStrategy does not populate a public read-only (no setter) property of an instance class that has a value returned for it. The issue here is that PropertyInfo.CanWrite returns false if there is no setter whereas it returns true if there is a private setter. A property that is truly read-only is excluded from the instance population logic.

The code at https://github.com/roryprimrose/ModelBuilder/blob/master/ModelBuilder/DefaultExecuteStrategy.cs#L259 should have better logic for filtering out unsupported properties.

Add support for mapping types

An example would be that a property or parameter is either an abstract class or an interface. Add fluent support and builder strategy support for using a mapping of types that the execute strategy can use when creating the values

Refactor use strong typed properties and parameters

The current interface design uses (Type, string) signatures to identity scenarios of

  • Type
  • Parameter type + name
  • Property type + name

Writing custom implementations of these interfaces can be very confusing to understand how to target specific scenarios. For example, a property that is being evaluated, is the type the type that declares the property or the return type of the property.

Updating these signatures will solve this confusion by providing the following overloads

  • ParameterInfo
  • PropertyInfo
  • Type

Support configuring IBuildConfiguration held instances

There needs to be extension methods on IBuildConfiguration to allow configuration of any instances held in a collection. This will include ValueGenerators, TypeCreators, IgnoreRules, CreationRules etc.

For example, the idea behind ValueGenerators exposing static properties was a single place to control configuration of the ValueGenerator. This is going to change to use instance properties where extension methods on IBuildConfiguration will allow for configuring those types.

Parsing resource data does not work on Unix

Parsing the embedded resources uses Environment.NewLine which is fine on non-Unix platforms because the files using CRLF as the new line delimiter. This will not work on Unix however as it uses LF as the new line delimiter but the embedded file is still delimited by CRLF

Update SetEach to avoid multiple enumerations

If an IEnumerable<T> is passed to SetEach then the instance returned is the same IEnumerable. This would cause a potential multiple enumeration problem. In this case the code should use yield. If it is something other than strictly IEnumerable<T> then it should return the original parameter value.

Uniqueness collisions with random person information

Some properties use other properties to help define their values. For example, an object that has first name and last name uses these values to help populate an email property. The source of these values is from a data set stored as an embedded resource. This resource has 1000 entries.

The issue is that a single record from that dataset is used. There may be 1000 unique first names and 1000 unique last names. The single record means that there are only 1000 unique combinations that could be determined rather than 1000 x 1000.

This applies to many of the other property values as well. A better job could be done by providing better combinations of predefined random values. Primarily this would be done by splitting up groups of information:

  • First names
  • Last names
  • Domains
  • Company names
  • Locations (Country + State + City + PostCode)

Support convention based configuration for build strategies

Implement app domain scanning of types to look for an interface that will support the configuration of a build strategy. This will decouple the logic of configuring custom build strategies from the Create static class.

Some considerations in designing this will be:

  • caching the build strategy (probably not required because it should already be cached against the Create class)
  • Clearing existing configuration in the external method
  • Resetting the build strategy so that re-configuration can occur again

Creating a custom BuildStrategy is clunky

The current constraint is that BuildStrategy must provide all information. This is clunky when you want to take something like a strategy from the default compiler and then tweak it. The solution here would be to at least add a IBuildStrategy copy constructor.

Streamline build strategy and complication

The current implementations of BuildStrategy and compilation is overly complex. This should be streamlined to allow for a simple build configuration that will drive the object generation process. The one sacrifice in this change of design will be that the build configuration will no longer be immutable after compilation from a BuildStrategy.

RelativeValueGenerator throws exception on GetValue<int?>()

Trying to get a int? value from another property throws an exception when the other property has a value.

Creating property YearLastUsed (System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]) on type DevMentorApi.Model.Skill
	Creating System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] value using DevMentorApi.AcceptanceTests.YearInPastValueGenerator
		System.InvalidCastException: Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'.
		   at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
		   at ModelBuilder.RelativeValueGenerator.GetValue[T](Regex expression, Object context) in C:\Repos\ModelBuilder\ModelBuilder\RelativeValueGenerator.cs:line 159

Enhance IPropertyResolver

IPropertyResolver should include a GetProperties member that also takes care of ordering as per ExecuteOrderRules.

Getting properties and ordering how they are evaluated should be moved from DefaultExecuteStrategy to DefaultPropertyResolver

TimeZoneValueGenerator throws ArgumentOutOfRangeException when no people found

The following exception is thrown when TimeZoneValueGenerator is building an instance that has a Country value that does not exist in any time zone name.

Failed to create value for type System.String using value generator ModelBuilder.TimeZoneValueGenerator, ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: min

At the time of the failure, the build log was:

Start creating type System.Collections.Generic.List`1[[TestingDemo.Model.Person, TestingDemo.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
    Start creating type TestingDemo.Model.Person
        Start populating instance TestingDemo.Model.Person
            Creating property Gender (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property FirstName (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property LastName (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property Email (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property Address (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property City (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property Company (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property Country (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property Domain (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property Phone (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property PostCode (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property State (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            Creating property TimeZone (System.String) on type TestingDemo.Model.Person
            Creating System.String value
            System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
            Parameter name: min
               at ModelBuilder.RandomGenerator.NextValue[T](Double min, Double max, Boolean roundValue) in C:\\Repos\\ModelBuilder\\ModelBuilder\\RandomGenerator.cs:line 289
               at ModelBuilder.RandomGenerator.NextValue(Type type, Object min, Object max) in C:\\Repos\\ModelBuilder\\ModelBuilder\\RandomGenerator.cs:line 234
               at ModelBuilder.RandomGeneratorExtensions.NextValue[T](IRandomGenerator generator, T min, T max) in C:\\Repos\\ModelBuilder\\ModelBuilder\\RandomGeneratorExtensions.cs:line 69
               at ModelBuilder.TimeZoneValueGenerator.GenerateValue(Type type, String referenceName, LinkedList`1 buildChain) in C:\\Repos\\ModelBuilder\\ModelBuilder\\TimeZoneValueGenerator.cs:line 51
               at ModelBuilder.ValueGeneratorBase.Generate(Type type, String referenceName, LinkedList`1 buildChain) in C:\\Repos\\ModelBuilder\\ModelBuilder\\ValueGeneratorBase.cs:line 21
               at ModelBuilder.DefaultExecuteStrategy.Build(Type type, String referenceName, Object context, Object[] args) in C:\\Repos\\ModelBuilder\\ModelBuilder\\DefaultExecuteStrategy.cs:line 158

Build throws ArgumentOutOfRangeException using StringBuilder

The following exception was thrown building a class.

System.ArgumentOutOfRangeException
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: chunkLength
   at System.Text.StringBuilder.ToString()
   at ModelBuilder.DefaultExecuteStrategy.Build(Type type, String referenceName, Object context, Object[] args) in C:\Repos\ModelBuilder\ModelBuilder\DefaultExecuteStrategy.cs:line 198
   at ModelBuilder.DefaultExecuteStrategy`1.CreateWith(Object[] args) in C:\Repos\ModelBuilder\ModelBuilder\DefaultExecuteStrategyT.cs:line 22

DateTimeValueGenerator creates values outside supported boundaries

The DateTimeValueGenerator is creating values that cannot be supported by DateTime, DateTimeOffset and TimeSpan.

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks.
    Parameter name: ticks
       at System.DateTime..ctor(Int64 ticks)
       at System.DateTimeOffset..ctor(Int64 ticks, TimeSpan offset)

There needs to be some constraints around the dates to ensure random shift values don't go too far.

Does not detect recursive type relationships

The issue here is that if TypeA has a property of TypeB and TypeB has a property of TypeA, ModelBuilder will continue to recursively create the relationships until either a StackOverflowException or OutOfMemoryException is thrown.

Populate executes AutoPopulate but not TypeCreator.Populate or PostBuildActions

The following test should populate an existing instance correctly.

        [Fact]
        public void PopulateUsesResolvedTypeCreatorToPopulateInstanceTest()
        {
            var actual = new List<Person>();

            actual = Model.Populate(actual);

            actual.Should().NotBeEmpty();
            actual.Count.Should().Be(EnumerableTypeCreator.DefaultAutoPopulateCount);
        }

Remove support for full .net framework

The future progression of build systems is leaving the full .net framework behind. It's time to say goodbye to the support for the full .net framework.

ITypeCreator needs to distinguish between supporting creating and populating

There can be situations where a type creator cannot create an instance of a type, but it can populate it. This is proven by having a read-only IEnumerable property. EnumerableTypeCreator currently says that it is supported, but that is only taking into consideration creating the instance. If a initialized read-only instance is already provided then this fails because IsSupported returns true, but it should be false because IEnumerable can't be populated unless the underlying type can be converted to ICollection.

Refactor TypeMapping

TypeMapping needs to move into an ITypeResolver and move from DefaultExecuteStrategy down to TypeCreator IBuildAction

DefaultExecuteStrategy overwrites properties assigned via constructor

Building a model that assigns property values from constructor parameters should skip over those properties. The logic for building property values should be something like:

  • If getter only, populate non-null reference types
  • If getter only, skip null reference types
  • If getter only, skip value types
  • If has setter, skip if reference type equals constructor parameter instance (using ReferenceEquals)
  • If has setter, skip if value type and property matches constructor parameter name and type and property is not default value
  • Build new value for property

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.