chrisfaustin
4/25/2014 - 3:09 PM

#NBuilder

#NBuilder

using System;
using System.Linq;

using FizzWare.NBuilder;


namespace MarkGibaud.UnitTest.Utilities
{
    public static class NBuilderUtility
    {
        public static T Create<T>()
        {
            return (T)Create(typeof(T));
        }

        private static object Create(Type type)
        {
            if (type.IsInterface)
            {
                var firstConcreteImplementation = type.Assembly.GetTypes().FirstOrDefault(t => type.IsAssignableFrom(t) && !t.IsInterface);
                if (firstConcreteImplementation != null)
                    type = firstConcreteImplementation;
                else
                    return null;
            }

            var baseType = Build(type) ?? Build(Nullable.GetUnderlyingType(type));

            var complexTypeProperties = baseType.GetType().GetProperties().Where(
                    p => !p.PropertyType.Namespace.Contains("System")).ToList();
                        
            if (!complexTypeProperties.Any())
                return baseType;

            foreach (var complexTypeProperty in complexTypeProperties)
                complexTypeProperty.SetValue(baseType, Create(complexTypeProperty.PropertyType), null);

            return baseType;
        }

        private static object Build(Type type)
        {
            var builderClassType = typeof(Builder<>);
            Type[] args = { type };
            var genericBuilderType = builderClassType.MakeGenericType(args);
            var builder = Activator.CreateInstance(genericBuilderType);
            var createNewMethodInfo = builder.GetType().GetMethod("CreateNew");
            var objectBuilder = createNewMethodInfo.Invoke(builder, null);
            var buildMethodInfo = objectBuilder.GetType().GetMethod("Build");
            return buildMethodInfo.Invoke(objectBuilder, null);
        }
    }
}