diff --git a/coverage.cmd b/coverage.cmd index ae6c7d7..ac1b4eb 100644 --- a/coverage.cmd +++ b/coverage.cmd @@ -30,7 +30,7 @@ @SET test_assemblies=%~dp0test\Abioc.Tests\bin\%config%\Abioc.Tests.dll @SET test_assemblies=%test_assemblies% %~dp0test\Abioc.Tests.Internal\bin\%config%\Abioc.Tests.Internal.dll @SET xunit_results=%results_path%\Xunit.Tests.html -@SET coverage_filter=+[abioc*]* -[*.Tests]* +@SET coverage_filter=+[abioc*]* -[*.Tests]* -[Abioc.Tests.Internal]* @SET coverage_results=%results_path%\Test.Coverage.xml @IF NOT EXIST "%results_path%" MD "%results_path%" diff --git a/src/Abioc/Composition/Compositions/CompositionBase.cs b/src/Abioc/Composition/Compositions/CompositionBase.cs index 059a930..c9ca153 100644 --- a/src/Abioc/Composition/Compositions/CompositionBase.cs +++ b/src/Abioc/Composition/Compositions/CompositionBase.cs @@ -17,13 +17,13 @@ public abstract class CompositionBase : IComposition public abstract Type Type { get; } /// - public abstract string GetInstanceExpression(GenerationContext context); + public abstract string GetInstanceExpression(IGenerationContext context); /// - public abstract string GetComposeMethodName(GenerationContext context); + public abstract string GetComposeMethodName(IGenerationContext context); /// - public virtual IEnumerable GetMethods(GenerationContext context) + public virtual IEnumerable GetMethods(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -32,7 +32,7 @@ public virtual IEnumerable GetMethods(GenerationContext context) } /// - public virtual IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context) + public virtual IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -41,7 +41,7 @@ public virtual IEnumerable GetMethods(GenerationContext context) } /// - public IEnumerable GetAdditionalInitializations(GenerationContext context) + public IEnumerable GetAdditionalInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -50,7 +50,7 @@ public IEnumerable GetAdditionalInitializations(GenerationContext contex } /// - public virtual IEnumerable GetFields(GenerationContext context) + public virtual IEnumerable GetFields(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -59,6 +59,6 @@ public virtual IEnumerable GetFields(GenerationContext context) } /// - public abstract bool RequiresConstructionContext(GenerationContext context); + public abstract bool RequiresConstructionContext(IGenerationContext context); } } diff --git a/src/Abioc/Composition/Compositions/ConstructorComposition.cs b/src/Abioc/Composition/Compositions/ConstructorComposition.cs index 40d1908..a99825e 100644 --- a/src/Abioc/Composition/Compositions/ConstructorComposition.cs +++ b/src/Abioc/Composition/Compositions/ConstructorComposition.cs @@ -59,15 +59,17 @@ public ConstructorComposition( public bool IsDefault { get; } /// - public override string GetInstanceExpression(GenerationContext context) + public override string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); // Get the expressions for the all the constructor parameters. - IEnumerable compositions = GetParameterExpressions(context); + IEnumerable expressions = GetParameterExpressions(context); IEnumerable parameterExpressions = - compositions.Select(c => c.GetInstanceExpression(context)); + from e in expressions + let ctx = context.Customize(recipientType: Type, serviceType: e.Type) + select e.GetInstanceExpression(ctx); // Join the parameters expressions. string parameters = @@ -83,7 +85,7 @@ public override string GetInstanceExpression(GenerationContext context) } /// - public override string GetComposeMethodName(GenerationContext context) + public override string GetComposeMethodName(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -93,7 +95,7 @@ public override string GetComposeMethodName(GenerationContext context) } /// - public override IEnumerable GetMethods(GenerationContext context) + public override IEnumerable GetMethods(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -114,12 +116,12 @@ public override IEnumerable GetMethods(GenerationContext context) } /// - public override bool RequiresConstructionContext(GenerationContext context) + public override bool RequiresConstructionContext(IGenerationContext context) { return GetParameterExpressions(context).Any(c => c.RequiresConstructionContext(context)); } - private IEnumerable GetParameterExpressions(GenerationContext context) + private IEnumerable GetParameterExpressions(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/EnumerableParameterExpression.cs b/src/Abioc/Composition/Compositions/EnumerableParameterExpression.cs index 2284b61..e2a2fa9 100644 --- a/src/Abioc/Composition/Compositions/EnumerableParameterExpression.cs +++ b/src/Abioc/Composition/Compositions/EnumerableParameterExpression.cs @@ -38,7 +38,10 @@ public EnumerableParameterExpression(Type enumerableType, bool requiresConstruct public Type EnumerableType { get; } /// - public string GetInstanceExpression(GenerationContext context) + public Type Type => EnumerableType; + + /// + public string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -52,7 +55,7 @@ public string GetInstanceExpression(GenerationContext context) } /// - public bool RequiresConstructionContext(GenerationContext context) + public bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/FactoryComposition.cs b/src/Abioc/Composition/Compositions/FactoryComposition.cs index f6ea560..4397e56 100644 --- a/src/Abioc/Composition/Compositions/FactoryComposition.cs +++ b/src/Abioc/Composition/Compositions/FactoryComposition.cs @@ -55,7 +55,7 @@ public FactoryComposition( public Type ConstructionContextType { get; } /// - public override string GetComposeMethodName(GenerationContext context) + public override string GetComposeMethodName(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -65,7 +65,7 @@ public override string GetComposeMethodName(GenerationContext context) } /// - public override IEnumerable GetMethods(GenerationContext context) + public override IEnumerable GetMethods(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -86,8 +86,8 @@ public override IEnumerable GetMethods(GenerationContext context) string factoryCall = requiresConstructionContext - ? $"{GetFactoryFieldName()}(context)" - : $"{GetFactoryFieldName()}()"; + ? GetFactoryFieldName() + "(context)" + : GetFactoryFieldName() + "()"; string method = string.Format( @"{0} @@ -115,23 +115,26 @@ public override IEnumerable GetMethods(GenerationContext context) } /// - public override string GetInstanceExpression(GenerationContext context) + public override string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); string factoryFieldName = GetComposeMethodName(context); + IEnumerable expressions = context.GetUpdateParameterExpressions(implementationType: Type); + string updateParameters = string.Join(", ", expressions); + string instanceExpression = RequiresConstructionContext() - ? factoryFieldName + "(context)" + ? factoryFieldName + $"(context.Update({updateParameters}))" : factoryFieldName + "()"; return instanceExpression; } /// - public override IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context) + public override IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -147,7 +150,7 @@ public override string GetInstanceExpression(GenerationContext context) } /// - public override IEnumerable GetFields(GenerationContext context) + public override IEnumerable GetFields(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -163,7 +166,7 @@ public override IEnumerable GetFields(GenerationContext context) } /// - public override bool RequiresConstructionContext(GenerationContext context) + public override bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/IParameterExpression.cs b/src/Abioc/Composition/Compositions/IParameterExpression.cs index 2059f52..0d2ac59 100644 --- a/src/Abioc/Composition/Compositions/IParameterExpression.cs +++ b/src/Abioc/Composition/Compositions/IParameterExpression.cs @@ -11,6 +11,11 @@ namespace Abioc.Composition.Compositions /// internal interface IParameterExpression { + /// + /// Gets the type of the . + /// + Type Type { get; } + /// /// Gets the code for the expression (e.g. method call or instance field) to retrieve an instance of the /// . @@ -20,7 +25,7 @@ internal interface IParameterExpression /// The code for the expression (e.g. method call or instance field) to retrieve an instance of the /// . /// - string GetInstanceExpression(GenerationContext context); + string GetInstanceExpression(IGenerationContext context); /// /// Returns the value indicating whether the requires a @@ -31,6 +36,6 @@ internal interface IParameterExpression /// The value indicating whether the requires a /// . /// - bool RequiresConstructionContext(GenerationContext context); + bool RequiresConstructionContext(IGenerationContext context); } } diff --git a/src/Abioc/Composition/Compositions/InjectedSingletonComposition.cs b/src/Abioc/Composition/Compositions/InjectedSingletonComposition.cs index d1db5a8..6717d15 100644 --- a/src/Abioc/Composition/Compositions/InjectedSingletonComposition.cs +++ b/src/Abioc/Composition/Compositions/InjectedSingletonComposition.cs @@ -37,7 +37,7 @@ public InjectedSingletonComposition(TImplementation value) public TImplementation Value { get; } /// - public override string GetComposeMethodName(GenerationContext context) + public override string GetComposeMethodName(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -47,7 +47,7 @@ public override string GetComposeMethodName(GenerationContext context) } /// - public override IEnumerable GetMethods(GenerationContext context) + public override IEnumerable GetMethods(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -73,7 +73,7 @@ public override IEnumerable GetMethods(GenerationContext context) } /// - public override string GetInstanceExpression(GenerationContext context) + public override string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -83,7 +83,7 @@ public override string GetInstanceExpression(GenerationContext context) } /// - public override IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context) + public override IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -96,7 +96,7 @@ public override string GetInstanceExpression(GenerationContext context) } /// - public override IEnumerable GetFields(GenerationContext context) + public override IEnumerable GetFields(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -109,7 +109,7 @@ public override IEnumerable GetFields(GenerationContext context) } /// - public override bool RequiresConstructionContext(GenerationContext context) + public override bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/PropertyDependencyComposition.cs b/src/Abioc/Composition/Compositions/PropertyDependencyComposition.cs index e1d315f..36480c4 100644 --- a/src/Abioc/Composition/Compositions/PropertyDependencyComposition.cs +++ b/src/Abioc/Composition/Compositions/PropertyDependencyComposition.cs @@ -50,7 +50,7 @@ public PropertyDependencyComposition( public (string property, Type type)[] PropertiesToInject { get; } /// - public string GetInstanceExpression(GenerationContext context) + public string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -63,7 +63,7 @@ public string GetInstanceExpression(GenerationContext context) } /// - public string GetComposeMethodName(GenerationContext context) + public string GetComposeMethodName(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -73,7 +73,7 @@ public string GetComposeMethodName(GenerationContext context) } /// - public IEnumerable GetMethods(GenerationContext context) + public IEnumerable GetMethods(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -96,9 +96,9 @@ public IEnumerable GetMethods(GenerationContext context) instanceExpression = CodeGen.Indent(instanceExpression); IEnumerable propertyExpressions = - GetPropertyExpressions(context) - .Select( - pe => $"instance.{pe.property} = {pe.expression.GetInstanceExpression(context)};"); + from pe in GetPropertyExpressions(context) + let ctx = context.Customize(recipientType: Type, serviceType: pe.expression.Type) + select $"instance.{pe.property} = {pe.expression.GetInstanceExpression(ctx)};"; string propertySetters = NewLine + string.Join(NewLine, propertyExpressions); propertySetters = CodeGen.Indent(propertySetters); @@ -113,7 +113,7 @@ public IEnumerable GetMethods(GenerationContext context) } /// - public IEnumerable GetFields(GenerationContext context) + public IEnumerable GetFields(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -122,7 +122,7 @@ public IEnumerable GetFields(GenerationContext context) } /// - public IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context) + public IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -131,7 +131,7 @@ public IEnumerable GetFields(GenerationContext context) } /// - public IEnumerable GetAdditionalInitializations(GenerationContext context) + public IEnumerable GetAdditionalInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -140,7 +140,7 @@ public IEnumerable GetAdditionalInitializations(GenerationContext contex } /// - public bool RequiresConstructionContext(GenerationContext context) + public bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -150,7 +150,7 @@ public bool RequiresConstructionContext(GenerationContext context) } private IEnumerable<(string property, IParameterExpression expression)> GetPropertyExpressions( - GenerationContext context) + IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/SimpleParameterExpression.cs b/src/Abioc/Composition/Compositions/SimpleParameterExpression.cs index b21b071..23aa337 100644 --- a/src/Abioc/Composition/Compositions/SimpleParameterExpression.cs +++ b/src/Abioc/Composition/Compositions/SimpleParameterExpression.cs @@ -29,7 +29,10 @@ public SimpleParameterExpression(IComposition composition) public IComposition Composition { get; } /// - public string GetInstanceExpression(GenerationContext context) + public Type Type => Composition.Type; + + /// + public string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -38,7 +41,7 @@ public string GetInstanceExpression(GenerationContext context) } /// - public bool RequiresConstructionContext(GenerationContext context) + public bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/SingletonComposition.cs b/src/Abioc/Composition/Compositions/SingletonComposition.cs index 41897a2..74d24f0 100644 --- a/src/Abioc/Composition/Compositions/SingletonComposition.cs +++ b/src/Abioc/Composition/Compositions/SingletonComposition.cs @@ -38,7 +38,7 @@ public SingletonComposition(IComposition inner) public Type Type => Inner.Type; /// - public string GetInstanceExpression(GenerationContext context) + public string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -49,7 +49,7 @@ public string GetInstanceExpression(GenerationContext context) } /// - public string GetComposeMethodName(GenerationContext context) + public string GetComposeMethodName(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -59,7 +59,7 @@ public string GetComposeMethodName(GenerationContext context) } /// - public IEnumerable GetMethods(GenerationContext context) + public IEnumerable GetMethods(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -82,7 +82,7 @@ public IEnumerable GetMethods(GenerationContext context) } /// - public IEnumerable GetFields(GenerationContext context) + public IEnumerable GetFields(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -98,7 +98,7 @@ public IEnumerable GetFields(GenerationContext context) } /// - public IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context) + public IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -107,7 +107,7 @@ public IEnumerable GetFields(GenerationContext context) } /// - public IEnumerable GetAdditionalInitializations(GenerationContext context) + public IEnumerable GetAdditionalInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -139,7 +139,7 @@ public IEnumerable GetAdditionalInitializations(GenerationContext contex } /// - public bool RequiresConstructionContext(GenerationContext context) + public bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/Compositions/TypedFactoryComposition.cs b/src/Abioc/Composition/Compositions/TypedFactoryComposition.cs index a155b46..b418083 100644 --- a/src/Abioc/Composition/Compositions/TypedFactoryComposition.cs +++ b/src/Abioc/Composition/Compositions/TypedFactoryComposition.cs @@ -51,7 +51,7 @@ public TypedFactoryComposition(object factory, Type constructionContextType = nu public Type ConstructionContextType { get; } /// - public override string GetComposeMethodName(GenerationContext context) + public override string GetComposeMethodName(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -61,23 +61,26 @@ public override string GetComposeMethodName(GenerationContext context) } /// - public override string GetInstanceExpression(GenerationContext context) + public override string GetInstanceExpression(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); string factoryFieldName = GetFactoryFieldName(); + IEnumerable expressions = context.GetUpdateParameterExpressions(implementationType: Type); + string updateParameters = string.Join(", ", expressions); + string instanceExpression = RequiresConstructionContext() - ? factoryFieldName + "(context)" + ? factoryFieldName + $"(context.Update({updateParameters}))" : factoryFieldName + "()"; return instanceExpression; } /// - public override IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context) + public override IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -94,7 +97,7 @@ public override string GetInstanceExpression(GenerationContext context) } /// - public override IEnumerable GetFields(GenerationContext context) + public override IEnumerable GetFields(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -111,7 +114,7 @@ public override IEnumerable GetFields(GenerationContext context) } /// - public override bool RequiresConstructionContext(GenerationContext context) + public override bool RequiresConstructionContext(IGenerationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/src/Abioc/Composition/IComposition.cs b/src/Abioc/Composition/IComposition.cs index e8766bf..08140a0 100644 --- a/src/Abioc/Composition/IComposition.cs +++ b/src/Abioc/Composition/IComposition.cs @@ -27,7 +27,7 @@ public interface IComposition /// The code for the expression (e.g. method call or instance field) to retrieve an instance of the /// . /// - string GetInstanceExpression(GenerationContext context); + string GetInstanceExpression(IGenerationContext context); /// /// Gets the name for the composition method, this is the method that will be called by an external service @@ -37,7 +37,7 @@ public interface IComposition /// /// The name for the composition method, this is the method that will be called by an external service request. /// - string GetComposeMethodName(GenerationContext context); + string GetComposeMethodName(IGenerationContext context); /// /// Returns the code of the methods required for the of the . @@ -46,7 +46,7 @@ public interface IComposition /// /// The code of the methods required for the of the . /// - IEnumerable GetMethods(GenerationContext context); + IEnumerable GetMethods(IGenerationContext context); /// /// Returns the code of the fields required for the of the . @@ -55,7 +55,7 @@ public interface IComposition /// /// The code of the fields required for the of the . /// - IEnumerable GetFields(GenerationContext context); + IEnumerable GetFields(IGenerationContext context); /// /// Returns the code of the fields required for the of the . @@ -64,14 +64,14 @@ public interface IComposition /// /// The code of the fields required for the of the . /// - IEnumerable<(string snippet, object value)> GetFieldInitializations(GenerationContext context); + IEnumerable<(string snippet, object value)> GetFieldInitializations(IGenerationContext context); /// /// Returns the code of additional initializations to the executes after the field initializations. /// /// The context for code generation. /// The code of additional initializations to the executes after the field initializations. - IEnumerable GetAdditionalInitializations(GenerationContext context); + IEnumerable GetAdditionalInitializations(IGenerationContext context); /// /// Returns the value indicating whether the requires a @@ -81,6 +81,6 @@ public interface IComposition /// /// The value indicating whether the requires a . /// - bool RequiresConstructionContext(GenerationContext context); + bool RequiresConstructionContext(IGenerationContext context); } } diff --git a/src/Abioc/ConstructionContext.cs b/src/Abioc/ConstructionContext.cs index 334abe4..24f8315 100644 --- a/src/Abioc/ConstructionContext.cs +++ b/src/Abioc/ConstructionContext.cs @@ -17,26 +17,8 @@ public struct ConstructionContext /// /// The default construction context to be used when one cannot be provided. /// - public static readonly ConstructionContext Default = default(ConstructionContext); - - /// - /// Initializes a new instance of the struct. - /// - /// The . - /// The . - /// The . - /// The construction context information. - public ConstructionContext( - Type implementationType = null, - Type serviceType = null, - Type recipientType = null, - TExtra extra = default(TExtra)) - { - ImplementationType = implementationType; - ServiceType = serviceType; - RecipientType = recipientType; - Extra = extra; - } + public static readonly ConstructionContext Default = + new ConstructionContext(typeof(void), typeof(void), typeof(void)); /// /// Gets the of the service to be provided that satisfies the @@ -45,7 +27,7 @@ public ConstructionContext( /// /// The should be assignable to the /// - public Type ImplementationType { get; } + public readonly Type ImplementationType; /// /// Gets the of the requested service. @@ -54,16 +36,42 @@ public ConstructionContext( /// The should be satisfied by being /// the . /// - public Type ServiceType { get; } + public readonly Type ServiceType; /// /// Gets the type of the component into which the service is injected. /// - public Type RecipientType { get; } + public readonly Type RecipientType; /// /// Gets the construction context information to be propitiated through all construction. /// - public TExtra Extra { get; } + public readonly TExtra Extra; + + /// + /// Initializes a new instance of the struct. + /// + /// The . + /// The . + /// The . + /// The construction context information. + public ConstructionContext( + Type implementationType, + Type serviceType, + Type recipientType, + TExtra extra = default(TExtra)) + { + if (implementationType == null) + throw new ArgumentNullException(nameof(implementationType)); + if (serviceType == null) + throw new ArgumentNullException(nameof(serviceType)); + if (recipientType == null) + throw new ArgumentNullException(nameof(recipientType)); + + ImplementationType = implementationType; + ServiceType = serviceType; + RecipientType = recipientType; + Extra = extra; + } } } diff --git a/src/Abioc/ConstructionContextExtensions.cs b/src/Abioc/ConstructionContextExtensions.cs index 42e02f3..e063781 100644 --- a/src/Abioc/ConstructionContextExtensions.cs +++ b/src/Abioc/ConstructionContextExtensions.cs @@ -34,28 +34,28 @@ public static ConstructionContext Initialize( extra); } - /////// - /////// Creates a updated with the specified parameters. - /////// - /////// - /////// The type of the construction context information. - /////// - /////// The source . - /////// The . - /////// The . - /////// The . - /////// An updated . - ////public static ConstructionContext Update( - //// this ConstructionContext context, - //// Type implementationType = null, - //// Type serviceType = null, - //// Type recipientType = null) - ////{ - //// return new ConstructionContext( - //// implementationType ?? context.ImplementationType, - //// serviceType ?? context.ServiceType, - //// recipientType ?? context.RecipientType, - //// context.Extra); - ////} + /// + /// Creates a updated with the specified parameters. + /// + /// + /// The type of the construction context information. + /// + /// The source . + /// The . + /// The . + /// The . + /// An updated . + public static ConstructionContext Update( + this ConstructionContext context, + Type implementationType = null, + Type serviceType = null, + Type recipientType = null) + { + implementationType = implementationType ?? context.ImplementationType; + serviceType = serviceType ?? context.ServiceType; + recipientType = recipientType ?? context.RecipientType; + + return new ConstructionContext(implementationType, serviceType, recipientType, context.Extra); + } } } diff --git a/src/Abioc/Generation/CodeGeneration.cs b/src/Abioc/Generation/CodeGeneration.cs index 44c8c40..634fc64 100644 --- a/src/Abioc/Generation/CodeGeneration.cs +++ b/src/Abioc/Generation/CodeGeneration.cs @@ -31,7 +31,7 @@ public static (string generatedCode, object[] fieldValues) GenerateCode(this Com throw new ArgumentNullException(nameof(container)); // First try with simple method names. - GenerationContext context = new GenerationContext( + GenerationContext context = new GenerationContextWrapper( registrations: container.Registrations, compositions: container.Compositions, usingSimpleNames: true, @@ -42,7 +42,7 @@ public static (string generatedCode, object[] fieldValues) GenerateCode(this Com // Check if there are any name conflicts. if (context.ComposeMethodsNames.Select(c => c.name).Distinct().Count() != context.ComposeMethodsNames.Count) { - context = new GenerationContext( + context = new GenerationContextWrapper( registrations: container.Registrations, compositions: container.Compositions, usingSimpleNames: false, @@ -253,8 +253,9 @@ orderby kvp.Key.GetHashCode() string GetCaseSnippet(Type key, IComposition composition) { + var definition = new ConstructionContextDefinition(composition.Type, key, typeof(void)); string keyComment = key.ToCompileName(); - string instanceExpression = composition.GetInstanceExpression(context); + string instanceExpression = composition.GetInstanceExpression(context.Customize(definition)); instanceExpression = CodeGen.Indent(instanceExpression); string caseSnippet = @@ -307,9 +308,11 @@ string GetCaseSnippet(Type key, IEnumerable compositions) string keyComment = key.ToCompileName(); IEnumerable instanceExpressions = - compositions - .Select(c => $"{NewLine}yield return {c.GetInstanceExpression(context)};") - .Select(instanceExpression => CodeGen.Indent(instanceExpression)); + from composition in compositions + let definition = new ConstructionContextDefinition(composition.Type, key, typeof(void)) + let snippet = composition.GetInstanceExpression(context.Customize(definition)) + let instanceExpression = $"{NewLine}yield return {snippet};" + select CodeGen.Indent(instanceExpression); string yieldStatements = string.Join(string.Empty, instanceExpressions); diff --git a/src/Abioc/Generation/ConstructionContextDefinition.cs b/src/Abioc/Generation/ConstructionContextDefinition.cs new file mode 100644 index 0000000..b0c80db --- /dev/null +++ b/src/Abioc/Generation/ConstructionContextDefinition.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc.Generation +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Defines the requirements of a during composition. + /// + public class ConstructionContextDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + /// The . + public ConstructionContextDefinition( + Type implementationType, + Type serviceType, + Type recipientType) + { + if (implementationType == null) + throw new ArgumentNullException(nameof(implementationType)); + if (serviceType == null) + throw new ArgumentNullException(nameof(serviceType)); + if (recipientType == null) + throw new ArgumentNullException(nameof(recipientType)); + + ImplementationType = implementationType; + ServiceType = serviceType; + RecipientType = recipientType; + } + + /// + /// Gets the of the service to be provided that satisfies the . + /// + public Type ImplementationType { get; } + + /// + /// Gets the of the requested service. + /// + public Type ServiceType { get; } + + /// + /// Gets the type of the component into which the service is injected. + /// + public Type RecipientType { get; } + } +} diff --git a/src/Abioc/Generation/GenerationContext.cs b/src/Abioc/Generation/GenerationContext.cs index 5b9d3ba..611dac1 100644 --- a/src/Abioc/Generation/GenerationContext.cs +++ b/src/Abioc/Generation/GenerationContext.cs @@ -12,7 +12,7 @@ namespace Abioc.Generation /// /// The context for generated code snippets. /// - public class GenerationContext + internal abstract class GenerationContext : IGenerationContext { private readonly List<(string name, Type type, bool requiresContext)> _composeMethodsNames = new List<(string, Type, bool)>(32); @@ -35,7 +35,7 @@ public class GenerationContext /// /// The type of the data. /// The type of the . - public GenerationContext( + protected GenerationContext( IReadOnlyDictionary> registrations, IReadOnlyDictionary compositions, bool usingSimpleNames, @@ -118,6 +118,12 @@ public GenerationContext( /// public bool UsingSimpleNames { get; } + /// + public abstract ConstructionContextDefinition ConstructionContextDefinition { get; } + + /// + public abstract IGenerationContext Customize(ConstructionContextDefinition constructionContextDefinition); + /// /// Adds a to the collection. /// diff --git a/src/Abioc/Generation/GenerationContextExtensions.cs b/src/Abioc/Generation/GenerationContextExtensions.cs new file mode 100644 index 0000000..137df5c --- /dev/null +++ b/src/Abioc/Generation/GenerationContextExtensions.cs @@ -0,0 +1,83 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc.Generation +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Abioc.Composition; + + /// + /// Extension helper methods on . + /// + public static class GenerationContextExtensions + { + /// + /// Creates a customized where the + /// is updated with the specified parameters. + /// + /// The to customize. + /// + /// The . + /// + /// The . + /// The . + /// + /// A customized where the + /// is updated with the specified parameters. + /// + public static IGenerationContext Customize( + this IGenerationContext context, + Type implementationType = null, + Type serviceType = null, + Type recipientType = null) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + implementationType = implementationType ?? context.ConstructionContextDefinition.ImplementationType; + serviceType = serviceType ?? context.ConstructionContextDefinition.ServiceType; + recipientType = recipientType ?? context.ConstructionContextDefinition.RecipientType; + + var definition = new ConstructionContextDefinition(implementationType, serviceType, recipientType); + IGenerationContext customization = context.Customize(definition); + return customization; + } + + /// + /// Gets the + /// parameter expressions for this . + /// + /// The to customize. + /// + /// The . + /// + /// The . + /// The . + /// + /// The + /// parameter expressions for this . + /// + public static IEnumerable GetUpdateParameterExpressions( + this IGenerationContext context, + Type implementationType = null, + Type serviceType = null, + Type recipientType = null) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + implementationType = implementationType ?? context.ConstructionContextDefinition.ImplementationType; + serviceType = serviceType ?? context.ConstructionContextDefinition.ServiceType; + recipientType = recipientType ?? context.ConstructionContextDefinition.RecipientType; + + if (implementationType != typeof(void)) + yield return $"implementationType: typeof({implementationType.ToCompileName()})"; + if (serviceType != typeof(void)) + yield return $"serviceType: typeof({serviceType.ToCompileName()})"; + if (recipientType != typeof(void)) + yield return $"recipientType: typeof({recipientType.ToCompileName()})"; + } + } +} diff --git a/src/Abioc/Generation/GenerationContextWrapper.cs b/src/Abioc/Generation/GenerationContextWrapper.cs new file mode 100644 index 0000000..99ba40c --- /dev/null +++ b/src/Abioc/Generation/GenerationContextWrapper.cs @@ -0,0 +1,76 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc.Generation +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Abioc.Composition; + using Abioc.Registration; + + /// + /// Wraps a with providing a specific instance of a + /// . + /// + internal class GenerationContextWrapper : GenerationContext + { + /// + /// Initializes a new instance of the class. + /// + /// The setup . + /// The for code generation. + /// + /// A value indicating whether simple names should be generated for compose methods. + /// + /// The type of the data. + /// The type of the . + public GenerationContextWrapper( + IReadOnlyDictionary> registrations, + IReadOnlyDictionary compositions, + bool usingSimpleNames, + string extraDataType = null, + string constructionContext = null) + : base(registrations, compositions, usingSimpleNames, extraDataType, constructionContext) + { + ConstructionContextDefinition = + new ConstructionContextDefinition(typeof(void), typeof(void), typeof(void)); + Inner = this; + } + + /// + /// Initializes a new instance of the class. + /// + /// The inner wrapped by this instance. + /// The + private GenerationContextWrapper( + GenerationContext inner, + ConstructionContextDefinition constructionContextDefinition) + : base(inner.Registrations, inner.Compositions, inner.UsingSimpleNames, inner.ExtraDataType, inner.ConstructionContext) + { + if (constructionContextDefinition == null) + throw new ArgumentNullException(nameof(constructionContextDefinition)); + + Inner = inner; + ConstructionContextDefinition = constructionContextDefinition; + } + + /// + /// Gets the inner wrapped by this instance. + /// + public GenerationContext Inner { get; } + + /// + public override ConstructionContextDefinition ConstructionContextDefinition { get; } + + /// + public override IGenerationContext Customize(ConstructionContextDefinition constructionContextDefinition) + { + if (constructionContextDefinition == null) + throw new ArgumentNullException(nameof(constructionContextDefinition)); + + var wrapper = new GenerationContextWrapper(Inner, constructionContextDefinition); + return wrapper; + } + } +} diff --git a/src/Abioc/Generation/IGenerationContext.cs b/src/Abioc/Generation/IGenerationContext.cs new file mode 100644 index 0000000..1841832 --- /dev/null +++ b/src/Abioc/Generation/IGenerationContext.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc.Generation +{ + using System; + using System.Collections.Generic; + using Abioc.Composition; + + /// + /// The context for generated code snippets. + /// + public interface IGenerationContext + { + /// + /// Gets the compositions for code generation. + /// + IReadOnlyDictionary Compositions { get; } + + /// + /// Gets the type of the ; otherwise if there + /// is no . + /// + string ConstructionContext { get; } + + /// + /// Gets a value indicating whether a is required for service + /// resolution. + /// + bool HasConstructionContext { get; } + + /// + /// Gets a value indicating whether simple names should be generated for compose methods. Simple names may not + /// be unique, and if not, complex names will be generated. + /// + bool UsingSimpleNames { get; } + + /// + /// Gets the definition for the requirements of a . + /// + ConstructionContextDefinition ConstructionContextDefinition { get; } + + /// + /// Creates a customized with the specific + /// . + /// + /// + /// The specific . + /// + /// + /// A customized with the specific + /// . + /// + IGenerationContext Customize(ConstructionContextDefinition constructionContextDefinition); + } +} diff --git a/test/Abioc.Tests.Internal/RequiresArgNullEx.cs b/test/Abioc.Tests.Internal/RequiresArgNullEx.cs index a54b394..0a21fc0 100644 --- a/test/Abioc.Tests.Internal/RequiresArgNullEx.cs +++ b/test/Abioc.Tests.Internal/RequiresArgNullEx.cs @@ -9,6 +9,7 @@ namespace Abioc using System.Threading.Tasks; using Abioc.Composition.Compositions; using Abioc.Composition.Visitors; + using Abioc.Generation; using Abioc.Registration; using AutoTest.ArgNullEx; using AutoTest.ArgNullEx.Xunit; @@ -36,6 +37,10 @@ public RequiresArgNullEx(ITestOutputHelper output) [Exclude( Type = typeof(ConstructionContextExtensions), Parameter = "extra")] + [Exclude( + Type = typeof(GenerationContextWrapper), + Method = ".ctor", + Parameter = "inner")] [Substitute(typeof(AbiocContainer<>), typeof(AbiocContainer))] [Substitute(typeof(ConstructionContext<>), typeof(ConstructionContext))] [Substitute(typeof(FactoryRegistration<>), typeof(FactoryRegistration))] diff --git a/test/Abioc.Tests.Internal/RequiresArgNullExAutoMoqAttribute.cs b/test/Abioc.Tests.Internal/RequiresArgNullExAutoMoqAttribute.cs index 48949c4..94ef028 100644 --- a/test/Abioc.Tests.Internal/RequiresArgNullExAutoMoqAttribute.cs +++ b/test/Abioc.Tests.Internal/RequiresArgNullExAutoMoqAttribute.cs @@ -8,6 +8,7 @@ namespace Abioc using System.Linq; using System.Linq.Expressions; using System.Reflection; + using Abioc.Generation; using AutoTest.ArgNullEx; using AutoTest.ArgNullEx.Xunit; using Ploeh.AutoFixture; @@ -37,6 +38,7 @@ private static IArgumentNullExceptionFixture CreateFixture(Assembly assemblyUnde var fixture = new Fixture().Customize(new AbiocCustomization()); fixture.Register(fixture.Create>); + fixture.Register(fixture.Create); var argNullFixture = new ArgumentNullExceptionFixture(assemblyUnderTest, fixture); diff --git a/test/Abioc.Tests/Abioc.Tests.csproj b/test/Abioc.Tests/Abioc.Tests.csproj index 106bc1f..d7e8d31 100644 --- a/test/Abioc.Tests/Abioc.Tests.csproj +++ b/test/Abioc.Tests/Abioc.Tests.csproj @@ -31,15 +31,6 @@ 4 - - ..\..\packages\AutoTest.ArgumentNullException.0.8.0\lib\net45\AutoTest.ArgumentNullException.dll - - - ..\..\packages\AutoTest.ArgumentNullException.Xunit.0.8.0\lib\net45\AutoTest.ArgumentNullException.Xunit.dll - - - ..\..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll - ..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.dll @@ -47,18 +38,6 @@ ..\..\packages\FluentAssertions.4.19.2\lib\net45\FluentAssertions.Core.dll - - ..\..\packages\Moq.4.7.10\lib\net45\Moq.dll - - - ..\..\packages\AutoFixture.3.50.2\lib\net40\Ploeh.AutoFixture.dll - - - ..\..\packages\AutoFixture.AutoMoq.3.50.2\lib\net40\Ploeh.AutoFixture.AutoMoq.dll - - - ..\..\packages\AutoFixture.Xunit2.3.50.2\lib\net45\Ploeh.AutoFixture.Xunit2.dll - ..\..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll @@ -96,11 +75,14 @@ + + + diff --git a/test/Abioc.Tests/ConstructionContextExtensionsTests.cs b/test/Abioc.Tests/ConstructionContextExtensionsTests.cs new file mode 100644 index 0000000..379396e --- /dev/null +++ b/test/Abioc.Tests/ConstructionContextExtensionsTests.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc +{ + using System; + using System.Collections.Generic; + using System.Linq; + using FluentAssertions; + using Xunit; + + public class WhenUpdatingAConstructionContext + { + private readonly ConstructionContext _initialValue; + + public WhenUpdatingAConstructionContext() + { + string extra = Guid.NewGuid().ToString("D").ToUpperInvariant(); + _initialValue = ConstructionContext.Default.Initialize(extra); + } + + [Fact] + public void ItShouldUpdateImplementationTypeIfSpecified() + { + // Act + ConstructionContext context = _initialValue.Update(implementationType: GetType()); + + // Assert + context.ImplementationType.Should().Be(GetType()); + context.ServiceType.Should().Be(typeof(void)); + context.RecipientType.Should().Be(typeof(void)); + context.Extra.Should().Be(_initialValue.Extra); + } + + [Fact] + public void ItShouldUpdateServiceTypeIfSpecified() + { + // Act + ConstructionContext context = _initialValue.Update(serviceType: GetType()); + + // Assert + context.ImplementationType.Should().Be(typeof(void)); + context.ServiceType.Should().Be(GetType()); + context.RecipientType.Should().Be(typeof(void)); + context.Extra.Should().Be(_initialValue.Extra); + } + + [Fact] + public void ItShouldUpdateRecipientTypeIfSpecified() + { + // Act + ConstructionContext context = _initialValue.Update(recipientType: GetType()); + + // Assert + context.ImplementationType.Should().Be(typeof(void)); + context.ServiceType.Should().Be(typeof(void)); + context.RecipientType.Should().Be(GetType()); + context.Extra.Should().Be(_initialValue.Extra); + } + } +} diff --git a/test/Abioc.Tests/ConstructionContextTests.cs b/test/Abioc.Tests/ConstructionContextTests.cs new file mode 100644 index 0000000..f2d194c --- /dev/null +++ b/test/Abioc.Tests/ConstructionContextTests.cs @@ -0,0 +1,315 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using Abioc.ConstructionContextTests; + using Abioc.Registration; + using FluentAssertions; + using Xunit; + using Xunit.Abstractions; + + namespace ConstructionContextTests + { + public interface IClassCreatedWithAContext + { + ConstructionContext Context { get; } + } + + public class ClassCreatedWithAContext : IClassCreatedWithAContext + { + private ClassCreatedWithAContext(ConstructionContext context) + { + Context = context; + } + + public ConstructionContext Context { get; } + + internal static ClassCreatedWithAContext StrongCreate(ConstructionContext context) + { + var service = new ClassCreatedWithAContext(context); + return service; + } + + internal static object WeakCreate(ConstructionContext context) + { + return StrongCreate(context); + } + } + + public class ConstructorDependentClass + { + public ConstructorDependentClass( + ClassCreatedWithAContext concreteDependency, + IClassCreatedWithAContext abstractDependency) + { + ConcreteDependency = + concreteDependency ?? throw new ArgumentNullException(nameof(concreteDependency)); + AbstractDependency = + abstractDependency ?? throw new ArgumentNullException(nameof(abstractDependency)); + } + + public ClassCreatedWithAContext ConcreteDependency { get; } + public IClassCreatedWithAContext AbstractDependency { get; } + } + + public class PropertyDependentClass + { + public ClassCreatedWithAContext ConcreteDependency { get; set; } + public IClassCreatedWithAContext AbstractDependency { get; set; } + } + } + + public abstract class FactoringClassWithAContextBase + { + protected AbiocContainer Container; + + [Fact] + public void ItShouldSpecifyTheImplementationTypeAsTheConcreteClassIfRequestingTheConcreteClass() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + ClassCreatedWithAContext actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull(); + actual.Context.Extra.Should().Be(data); + actual.Context.ImplementationType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.Context.RecipientType.Should().Be(typeof(void)); + } + + [Fact] + public void ItShouldSpecifyTheServiceTypeAsTheConcreteClassIfRequestingTheConcreteClass() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + ClassCreatedWithAContext actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull(); + actual.Context.Extra.Should().Be(data); + actual.Context.ServiceType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.Context.RecipientType.Should().Be(typeof(void)); + } + + [Fact] + public void ItShouldSpecifyTheImplementationTypeAsTheConcreteClassIfRequestingTheInterface() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + IClassCreatedWithAContext actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull().And.BeOfType(); + actual.Context.Extra.Should().Be(data); + actual.Context.ImplementationType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.Context.RecipientType.Should().Be(typeof(void)); + } + + [Fact] + public void ItShouldSpecifyTheServiceTypeTheAsInterfaceIfRequestingTheInterface() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + IClassCreatedWithAContext actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull().And.BeOfType(); + actual.Context.Extra.Should().Be(data); + actual.Context.ServiceType.Should().Be(typeof(IClassCreatedWithAContext)); + actual.Context.RecipientType.Should().Be(typeof(void)); + } + } + + public class WhenFactoringAStronglyTypedClassWithAContext : FactoringClassWithAContextBase + { + public WhenFactoringAStronglyTypedClassWithAContext(ITestOutputHelper output) + { + Container = + new RegistrationSetup() + .RegisterFactory(ClassCreatedWithAContext.StrongCreate) + .Register() + .Construct(GetType().GetTypeInfo().Assembly, out string code); + + output.WriteLine(code); + } + } + + public class WhenFactoringAWeaklyTypedClassWithAContext : FactoringClassWithAContextBase + { + public WhenFactoringAWeaklyTypedClassWithAContext(ITestOutputHelper output) + { + Container = + new RegistrationSetup() + .RegisterFactory(typeof(ClassCreatedWithAContext), ClassCreatedWithAContext.WeakCreate) + .Register() + .Construct(GetType().GetTypeInfo().Assembly, out string code); + + output.WriteLine(code); + } + } + + public abstract class FactoringClassWithAContextAsAConstructorDependencyBase + { + protected AbiocContainer Container; + + [Fact] + public void ItShouldSpecifyRecipientTypeAsTheDependentClassForTheConcreteDependency() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + ConstructorDependentClass actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull(); + actual.ConcreteDependency.Should().NotBeNull(); + actual.ConcreteDependency.Context.Extra.Should().Be(data); + actual.ConcreteDependency.Context.RecipientType.Should().Be(typeof(ConstructorDependentClass)); + actual.ConcreteDependency.Context.ImplementationType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.ConcreteDependency.Context.ServiceType.Should().Be(typeof(ClassCreatedWithAContext)); + } + + [Fact] + public void ItShouldSpecifyRecipientTypeAsTheDependentClassForTheAbstractDependency() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + ConstructorDependentClass actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull(); + actual.AbstractDependency.Should().NotBeNull(); + actual.AbstractDependency.Context.Extra.Should().Be(data); + actual.AbstractDependency.Context.RecipientType.Should().Be(typeof(ConstructorDependentClass)); + actual.AbstractDependency.Context.ImplementationType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.AbstractDependency.Context.ServiceType.Should().Be(typeof(ClassCreatedWithAContext)); + } + } + + public class WhenFactoringAStronglyTypedClassWithAContextAsAConstructorDependency + : FactoringClassWithAContextAsAConstructorDependencyBase + { + public WhenFactoringAStronglyTypedClassWithAContextAsAConstructorDependency(ITestOutputHelper output) + { + Container = + new RegistrationSetup() + .RegisterFactory( + ClassCreatedWithAContext.StrongCreate, + compose => compose.Internal()) + .Register() + .Construct(GetType().GetTypeInfo().Assembly, out string code); + + output.WriteLine(code); + } + } + + public class WhenFactoringAWeaklyTypedClassWithAContextAsAConstructorDependency + : FactoringClassWithAContextAsAConstructorDependencyBase + { + public WhenFactoringAWeaklyTypedClassWithAContextAsAConstructorDependency(ITestOutputHelper output) + { + Container = + new RegistrationSetup() + .RegisterFactory( + typeof(IClassCreatedWithAContext), + typeof(ClassCreatedWithAContext), + ClassCreatedWithAContext.WeakCreate, compose => compose.Internal()) + .Register() + .Construct(GetType().GetTypeInfo().Assembly, out string code); + + output.WriteLine(code); + } + } + + public abstract class FactoringClassWithAContextAsAPropertyDependencyBase + { + protected AbiocContainer Container; + + [Fact] + public void ItShouldSpecifyRecipientTypeAsTheDependentClassForTheConcreteDependency() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + PropertyDependentClass actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull(); + actual.ConcreteDependency.Should().NotBeNull(); + actual.ConcreteDependency.Context.Extra.Should().Be(data); + actual.ConcreteDependency.Context.RecipientType.Should().Be(typeof(PropertyDependentClass)); + actual.ConcreteDependency.Context.ImplementationType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.ConcreteDependency.Context.ServiceType.Should().Be(typeof(ClassCreatedWithAContext)); + } + + [Fact] + public void ItShouldSpecifyRecipientTypeAsTheDependentClassForTheAbstractDependency() + { + // Arrange + Guid data = Guid.NewGuid(); + + // Act + PropertyDependentClass actual = Container.GetService(data); + + // Assert + actual.Should().NotBeNull(); + actual.AbstractDependency.Should().NotBeNull(); + actual.AbstractDependency.Context.Extra.Should().Be(data); + actual.AbstractDependency.Context.RecipientType.Should().Be(typeof(PropertyDependentClass)); + actual.AbstractDependency.Context.ImplementationType.Should().Be(typeof(ClassCreatedWithAContext)); + actual.AbstractDependency.Context.ServiceType.Should().Be(typeof(ClassCreatedWithAContext)); + } + } + + public class WhenFactoringAStronglyTypedClassWithAContextAsAPropertyDependency + : FactoringClassWithAContextAsAPropertyDependencyBase + { + public WhenFactoringAStronglyTypedClassWithAContextAsAPropertyDependency(ITestOutputHelper output) + { + Container = + new RegistrationSetup() + .RegisterFactory( + ClassCreatedWithAContext.StrongCreate, + compose => compose.Internal()) + .Register(composer => composer.InjectAllProperties()) + .Construct(GetType().GetTypeInfo().Assembly, out string code); + + output.WriteLine(code); + } + } + + public class WhenFactoringAWeaklyTypedClassWithAContextAsAPropertyDependency + : FactoringClassWithAContextAsAPropertyDependencyBase + { + public WhenFactoringAWeaklyTypedClassWithAContextAsAPropertyDependency(ITestOutputHelper output) + { + Container = + new RegistrationSetup() + .RegisterFactory( + typeof(IClassCreatedWithAContext), + typeof(ClassCreatedWithAContext), + ClassCreatedWithAContext.WeakCreate, compose => compose.Internal()) + .Register(composer => composer.InjectAllProperties()) + .Construct(GetType().GetTypeInfo().Assembly, out string code); + + output.WriteLine(code); + } + } +} diff --git a/test/Abioc.Tests/GenerationContextExtensionsTests.cs b/test/Abioc.Tests/GenerationContextExtensionsTests.cs new file mode 100644 index 0000000..a872530 --- /dev/null +++ b/test/Abioc.Tests/GenerationContextExtensionsTests.cs @@ -0,0 +1,142 @@ +// Copyright (c) 2017 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Abioc +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Abioc.Generation; + using Abioc.GenerationContextExtensionsTests; + using FluentAssertions; + using Xunit; + + namespace GenerationContextExtensionsTests + { + using Abioc.Composition; + + internal class TestGenerationContext : IGenerationContext + { + public IReadOnlyDictionary Compositions { get; set; } + + public string ConstructionContext { get; set; } + + public bool HasConstructionContext { get; set; } + + public bool UsingSimpleNames { get; set; } + + public ConstructionContextDefinition ConstructionContextDefinition { get; set; } + + public IGenerationContext Customize(ConstructionContextDefinition constructionContextDefinition) + { + return new TestGenerationContext { ConstructionContextDefinition = constructionContextDefinition }; + } + } + } + + public class WhenCustomizingAGenerationContext + { + private readonly IGenerationContext _initialValue; + + public WhenCustomizingAGenerationContext() + { + _initialValue = new TestGenerationContext() + { + ConstructionContextDefinition = + new ConstructionContextDefinition(typeof(void), typeof(void), typeof(void)), + }; + } + + [Fact] + public void ItShouldUpdateImplementationTypeIfSpecified() + { + // Act + IGenerationContext context = _initialValue.Customize(implementationType: GetType()); + + // Assert + context.ConstructionContextDefinition.ImplementationType.Should().Be(GetType()); + context.ConstructionContextDefinition.ServiceType.Should().Be(typeof(void)); + context.ConstructionContextDefinition.RecipientType.Should().Be(typeof(void)); + } + + [Fact] + public void ItShouldUpdateServiceTypeIfSpecified() + { + // Act + IGenerationContext context = _initialValue.Customize(serviceType: GetType()); + + // Assert + context.ConstructionContextDefinition.ImplementationType.Should().Be(typeof(void)); + context.ConstructionContextDefinition.ServiceType.Should().Be(GetType()); + context.ConstructionContextDefinition.RecipientType.Should().Be(typeof(void)); + } + + [Fact] + public void ItShouldUpdateRecipientTypeIfSpecified() + { + // Act + IGenerationContext context = _initialValue.Customize(recipientType: GetType()); + + // Assert + context.ConstructionContextDefinition.ImplementationType.Should().Be(typeof(void)); + context.ConstructionContextDefinition.ServiceType.Should().Be(typeof(void)); + context.ConstructionContextDefinition.RecipientType.Should().Be(GetType()); + } + } + + public class WhenGettingUpdateParameterExpressionsOfAGenerationContext + { + private readonly IGenerationContext _initialValue; + + public WhenGettingUpdateParameterExpressionsOfAGenerationContext() + { + _initialValue = new TestGenerationContext() + { + ConstructionContextDefinition = + new ConstructionContextDefinition(typeof(void), typeof(void), typeof(void)), + }; + } + + [Fact] + public void ItShouldReturnAnExpressionGotTheImplementationType() + { + // Arrange + string expected = $"implementationType: typeof({GetType()})"; + + // Act + IEnumerable expressions = + _initialValue.GetUpdateParameterExpressions(implementationType: GetType()); + + // Assert + expressions.ToList().Should().OnlyContain(e => e == expected); + } + + [Fact] + public void ItShouldReturnAnExpressionGotTheServiceType() + { + // Arrange + string expected = $"serviceType: typeof({GetType()})"; + + // Act + IEnumerable expressions = + _initialValue.GetUpdateParameterExpressions(serviceType: GetType()); + + // Assert + expressions.ToList().Should().OnlyContain(e => e == expected); + } + + [Fact] + public void ItShouldReturnAnExpressionGotTheRecipientType() + { + // Arrange + string expected = $"recipientType: typeof({GetType()})"; + + // Act + IEnumerable expressions = + _initialValue.GetUpdateParameterExpressions(recipientType: GetType()); + + // Assert + expressions.ToList().Should().OnlyContain(e => e == expected); + } + } +} diff --git a/test/Abioc.Tests/app.config b/test/Abioc.Tests/app.config index dd0e71a..4fb3f2e 100644 --- a/test/Abioc.Tests/app.config +++ b/test/Abioc.Tests/app.config @@ -2,14 +2,6 @@ - - - - - - - - @@ -26,14 +18,6 @@ - - - - - - - - \ No newline at end of file diff --git a/test/Abioc.Tests/packages.config b/test/Abioc.Tests/packages.config index 1384540..704bf87 100644 --- a/test/Abioc.Tests/packages.config +++ b/test/Abioc.Tests/packages.config @@ -1,15 +1,6 @@  - - - - - - - - -