Пример #1
0
        public CreationResult TryResolveDummyValue(Type typeOfDummy, LoopDetectingResolutionContext resolutionContext)
        {
            // Make sure we're not already resolving typeOfDummy. It may seem that we could skip this check when we have
            // a cached resolution strategy in strategyCache, but it's necessary in case multiple threads are involved and
            // typeOfDummy has a constructor that takes typeOfDummy as a parameter.
            // In that situation, perhaps this thread starts trying to resolve a Dummy using the constructor that takes a
            // typeOfDummy. Meanwhile another thread does the same thing, but gets more processing time and eventually fails to
            // use that constructor, but then it succeeds in making a typeOfDummy using a different constructor. Then the strategy
            // is cached. This thread sees the cached strategy, creates a typeOfDummy for the constructor parameter, and then
            // uses it to make the "outer" typeOfDummy. Then we'd have Dummies created via two different constructors, which
            // might have different behavior. This is essentially the problem that arose in issue 1639.
            if (!resolutionContext.TryBeginToResolve(typeOfDummy))
            {
                return(CreationResult.FailedToCreateDummy(typeOfDummy, "Recursive dependency detected. Already resolving " + typeOfDummy + '.'));
            }

            try
            {
                return(this.strategyCache.TryGetValue(typeOfDummy, out ResolveStrategy cachedStrategy)
                    ? cachedStrategy.TryCreateDummyValue(typeOfDummy, this, resolutionContext)
                    : this.TryResolveDummyValueWithAllAvailableStrategies(typeOfDummy, resolutionContext));
            }
            finally
            {
                resolutionContext.EndResolve(typeOfDummy);
            }
        }
Пример #2
0
            public CreationResult CreateFake(
                Type typeOfFake,
                IProxyOptions proxyOptions,
                IDummyValueResolver resolver,
                LoopDetectingResolutionContext resolutionContext)
            {
                if (!CastleDynamicProxyGenerator.CanGenerateProxy(typeOfFake, out string?reasonCannotGenerate))
                {
                    return(CreationResult.FailedToCreateFake(typeOfFake, reasonCannotGenerate));
                }

                if (proxyOptions.ArgumentsForConstructor is not null)
                {
                    var proxyGeneratorResult = this.GenerateProxy(typeOfFake, proxyOptions, proxyOptions.ArgumentsForConstructor);

                    return(proxyGeneratorResult.ProxyWasSuccessfullyGenerated
                        ? CreationResult.SuccessfullyCreated(proxyGeneratorResult.GeneratedProxy)
                        : CreationResult.FailedToCreateFake(typeOfFake, proxyGeneratorResult.ReasonForFailure !));
                }

                return(this.TryCreateFakeWithDummyArgumentsForConstructor(
                           typeOfFake,
                           proxyOptions,
                           resolver,
                           resolutionContext));
            }
Пример #3
0
            public override CreationResult TryCreateDummyValue(Type typeOfDummy, IDummyValueResolver resolver)
            {
                var success = this.DummyFactory.TryCreateDummyObject(typeOfDummy, out object result);

                return(success
                    ? CreationResult.SuccessfullyCreated(result)
                    : CreationResult.FailedToCreateDummy(typeOfDummy, "No Dummy Factory produced a result."));
            }
Пример #4
0
            public override CreationResult TryCreateDummyValue(DummyCreationSession session, Type typeOfDummy)
            {
                if (typeof(Delegate).IsAssignableFrom(typeOfDummy))
                {
                    return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is a Delegate."));
                }

                if (typeOfDummy.GetTypeInfo().IsAbstract)
                {
                    return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is abstract."));
                }

                // Save the constructors as we try them. Avoids eager evaluation and double evaluation
                // of constructors enumerable.
                var consideredConstructors = new List <ResolvedConstructor>();

                if (this.cachedConstructors.TryGetValue(typeOfDummy, out ConstructorInfo cachedConstructor))
                {
                    var resolvedConstructor = new ResolvedConstructor(
                        cachedConstructor.GetParameters().Select(pi => pi.ParameterType),
                        session,
                        this.Resolver);
                    if (resolvedConstructor.WasSuccessfullyResolved)
                    {
                        if (TryCreateDummyValueUsingConstructor(cachedConstructor, resolvedConstructor, out object result))
                        {
                            return(CreationResult.SuccessfullyCreated(result));
                        }

                        consideredConstructors.Add(resolvedConstructor);
                    }
                }
                else
                {
                    foreach (var constructor in GetConstructorsInOrder(typeOfDummy))
                    {
                        var resolvedConstructor = new ResolvedConstructor(
                            constructor.GetParameters().Select(pi => pi.ParameterType),
                            session,
                            this.Resolver);

                        if (resolvedConstructor.WasSuccessfullyResolved && TryCreateDummyValueUsingConstructor(constructor, resolvedConstructor, out object result))
                        {
                            this.cachedConstructors[typeOfDummy] = constructor;
                            return(CreationResult.SuccessfullyCreated(result));
                        }

                        consideredConstructors.Add(resolvedConstructor);
                    }
                }

                if (consideredConstructors.Any())
                {
                    return(CreationResult.FailedToCreateDummy(typeOfDummy, consideredConstructors));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It has no public constructors."));
            }
Пример #5
0
            public override CreationResult TryCreateDummyValue(Type typeOfDummy, IDummyValueResolver resolver)
            {
                if (typeOfDummy.GetTypeInfo().IsValueType&& typeOfDummy != typeof(void))
                {
                    return(CreationResult.SuccessfullyCreated(Activator.CreateInstance(typeOfDummy)));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is not a value type."));
            }
Пример #6
0
            public override CreationResult TryCreateDummyValue(
                Type typeOfDummy,
                IDummyValueResolver resolver,
                LoopDetectingResolutionContext resolutionContext)
            {
                if (typeOfDummy.GetTypeInfo().IsGenericType&& typeOfDummy.GetGenericTypeDefinition() == typeof(Lazy <>))
                {
                    var typeOfLazyResult = typeOfDummy.GetGenericArguments()[0];
                    var method           = CreateLazyDummyGenericDefinition.MakeGenericMethod(typeOfLazyResult);
                    var dummy            = method.Invoke(null, new object[] { resolver });
                    return(CreationResult.SuccessfullyCreated(dummy));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is not a Lazy."));
            }
Пример #7
0
        public CreationResult TryResolveDummyValue(DummyCreationSession session, Type typeOfDummy)
        {
            if (!session.TryBeginToResolveType(typeOfDummy))
            {
                return(CreationResult.FailedToCreateDummy(typeOfDummy, "Recursive dependency detected. Already resolving " + typeOfDummy + '.'));
            }

            var creationResult = this.TryResolveDummyValueWithAllAvailableStrategies(session, typeOfDummy);

            if (creationResult.WasSuccessful)
            {
                session.OnSuccessfulResolve(typeOfDummy);
            }

            return(creationResult);
        }
Пример #8
0
            public override CreationResult MergeIntoDummyResult(CreationResult other)
            {
                Guard.AgainstNull(other, "other");

                if (other.WasSuccessful)
                {
                    return(other);
                }

                var failedOther = (FailedCreationResult)other;

                return(new FailedCreationResult(
                           this.type,
                           CreationMode.Dummy,
                           MergeReasonsForFailure(this.reasonsForFailure, failedOther.reasonsForFailure),
                           MergeConsideredConstructors(this.consideredConstructors, failedOther.consideredConstructors)));
            }
Пример #9
0
            public CreationResult CreateFakeInterface(Type typeOfFake, IProxyOptions proxyOptions)
            {
                if (proxyOptions.ArgumentsForConstructor is not null)
                {
                    throw new ArgumentException(DynamicProxyMessages.ArgumentsForConstructorOnInterfaceType);
                }

                var fakeCallProcessorProvider = this.fakeCallProcessorProviderFactory(typeOfFake, proxyOptions);
                var proxyGeneratorResult      = CastleDynamicProxyGenerator.GenerateInterfaceProxy(
                    typeOfFake,
                    proxyOptions.AdditionalInterfacesToImplement,
                    proxyOptions.Attributes,
                    fakeCallProcessorProvider);

                return(proxyGeneratorResult.ProxyWasSuccessfullyGenerated
                    ? CreationResult.SuccessfullyCreated(proxyGeneratorResult.GeneratedProxy)
                    : CreationResult.FailedToCreateFake(typeOfFake, proxyGeneratorResult.ReasonForFailure !));
            }
Пример #10
0
            public override CreationResult TryCreateDummyValue(
                Type typeOfDummy,
                IDummyValueResolver resolver,
                LoopDetectingResolutionContext resolutionContext)
            {
                if (typeOfDummy == typeof(Task))
                {
                    return(CreationResult.SuccessfullyCreated(TaskHelper.CompletedTask));
                }

                if (typeOfDummy.IsGenericType && typeOfDummy.GetGenericTypeDefinition() == typeof(Task <>))
                {
                    var    typeOfTaskResult = typeOfDummy.GetGenericArguments()[0];
                    var    creationResult   = resolver.TryResolveDummyValue(typeOfTaskResult, resolutionContext);
                    object?taskResult       = creationResult.WasSuccessful
                        ? creationResult.Result
                        : typeOfTaskResult.GetDefaultValue();

                    var method = GenericFromResultMethodDefinition.MakeGenericMethod(typeOfTaskResult);
                    return(CreationResult.SuccessfullyCreated(method.Invoke(null, new[] { taskResult })));
                }

                if (typeOfDummy.FullName == "System.Threading.Tasks.ValueTask")
                {
                    return(CreationResult.SuccessfullyCreated(typeOfDummy.GetDefaultValue()));
                }

                if (typeOfDummy.IsGenericType &&
                    !typeOfDummy.IsGenericTypeDefinition &&
                    typeOfDummy.FullName is string fullName &&
                    fullName.StartsWith("System.Threading.Tasks.ValueTask`", StringComparison.Ordinal))
                {
                    var    typeOfTaskResult = typeOfDummy.GetGenericArguments()[0];
                    var    creationResult   = resolver.TryResolveDummyValue(typeOfTaskResult, resolutionContext);
                    object?taskResult       = creationResult.WasSuccessful
                        ? creationResult.Result
                        : typeOfTaskResult.GetDefaultValue();

                    var ctor = typeOfDummy.GetConstructor(new[] { typeOfTaskResult }) !;
                    return(CreationResult.SuccessfullyCreated(ctor.Invoke(new[] { taskResult })));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is not a Task."));
            }
Пример #11
0
            public CreationResult TryResolveDummyValueWithAllAvailableStrategies(Type typeOfDummy)
            {
                CreationResult creationResult = null;

                foreach (var strategy in this.strategies)
                {
                    var thisCreationResult = strategy.TryCreateDummyValue(typeOfDummy, this);
                    if (thisCreationResult.WasSuccessful)
                    {
                        this.strategyCache.TryAdd(typeOfDummy, strategy);
                        return(thisCreationResult);
                    }

                    creationResult = CreationResult.MergeIntoDummyResult(creationResult, thisCreationResult);
                }

                this.strategyCache.TryAdd(typeOfDummy, new UnableToResolveStrategy(creationResult));
                return(creationResult);
            }
Пример #12
0
        /// <summary>
        /// Returns a creation result for a dummy by combining two results.
        /// Successful results are preferred to failed. Failed results will have their reasons for failure aggregated.
        /// </summary>
        /// <param name="one">One result to merge. May be <code>null</code>.</param>
        /// <param name="other">The other result to merge. Must not be <code>null</code>.</param>
        /// <returns>A combined creation result. Successful if either input was successful, and failed otherwise.</returns>
        public static CreationResult MergeIntoDummyResult(CreationResult one, CreationResult other)
        {
            Guard.AgainstNull(other, "other");

            if (one == null || other.WasSuccessful)
            {
                return(other.AsDummyResult());
            }

            if (one.WasSuccessful)
            {
                return(one.AsDummyResult());
            }

            return(new CreationResult(
                       one.type,
                       CreationMode.Dummy,
                       MergeReasonsForFailure(one.reasonsForFailure, other.reasonsForFailure),
                       MergeConsideredConstructors(one.consideredConstructors, other.consideredConstructors)));
        }
Пример #13
0
            public override CreationResult TryCreateDummyValue(Type typeOfDummy, IDummyValueResolver resolver)
            {
                if (typeOfDummy.GetTypeInfo().IsGenericType&& typeOfDummy.GetGenericTypeDefinition() == typeof(Lazy <>))
                {
                    var    typeOfLazyResult = typeOfDummy.GetGenericArguments()[0];
                    var    creationResult   = resolver.TryResolveDummyValue(typeOfLazyResult);
                    object lazyResult       = creationResult.WasSuccessful
                        ? creationResult.Result
                        : typeOfLazyResult.GetDefaultValue();

                    var funcType = typeof(Func <>).MakeGenericType(typeOfLazyResult);

                    var method = CreateGenericFromResultMethodDefinition().MakeGenericMethod(typeOfLazyResult);
                    var func   = method.Invoke(null, new[] { lazyResult });
                    var dummy  = typeOfDummy.GetConstructor(new[] { funcType, typeof(bool) }).Invoke(new[] { func, true });
                    return(CreationResult.SuccessfullyCreated(dummy));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is not a Lazy."));
            }
Пример #14
0
            public override CreationResult TryCreateDummyValue(Type typeOfDummy, IDummyValueResolver resolver)
            {
                if (typeOfDummy == typeof(Task))
                {
                    return(CreationResult.SuccessfullyCreated(TaskHelper.FromResult(default(object))));
                }

                if (typeOfDummy.GetTypeInfo().IsGenericType&& typeOfDummy.GetGenericTypeDefinition() == typeof(Task <>))
                {
                    var    typeOfTaskResult = typeOfDummy.GetGenericArguments()[0];
                    var    creationResult   = resolver.TryResolveDummyValue(typeOfTaskResult);
                    object taskResult       = creationResult.WasSuccessful
                        ? creationResult.Result
                        : typeOfTaskResult.GetDefaultValue();

                    var method = GenericFromResultMethodDefinition.MakeGenericMethod(typeOfTaskResult);
                    return(CreationResult.SuccessfullyCreated(method.Invoke(null, new[] { taskResult })));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is not a Task."));
            }
Пример #15
0
        private CreationResult TryResolveDummyValueWithAllAvailableStrategies(
            Type typeOfDummy,
            LoopDetectingResolutionContext resolutionContext)
        {
            CreationResult creationResult = CreationResult.Untried;

            foreach (var strategy in this.strategies)
            {
                var thisCreationResult = strategy.TryCreateDummyValue(typeOfDummy, this, resolutionContext);
                if (thisCreationResult.WasSuccessful)
                {
                    this.strategyCache.TryAdd(typeOfDummy, strategy);
                    return(thisCreationResult);
                }

                creationResult = creationResult.MergeIntoDummyResult(thisCreationResult);
            }

            this.strategyCache.TryAdd(typeOfDummy, new UnableToResolveStrategy(creationResult));
            return(creationResult);
        }
Пример #16
0
        public CreationResult TryResolveDummyValue(Type typeOfDummy, LoopDetectingResolutionContext resolutionContext)
        {
            if (this.strategyCache.TryGetValue(typeOfDummy, out ResolveStrategy cachedStrategy))
            {
                return(cachedStrategy.TryCreateDummyValue(typeOfDummy, this, resolutionContext));
            }

            if (!resolutionContext.TryBeginToResolve(typeOfDummy))
            {
                return(CreationResult.FailedToCreateDummy(typeOfDummy, "Recursive dependency detected. Already resolving " + typeOfDummy + '.'));
            }

            var creationResult = this.TryResolveDummyValueWithAllAvailableStrategies(typeOfDummy, resolutionContext);

            if (creationResult.WasSuccessful)
            {
                resolutionContext.OnSuccessfulResolve(typeOfDummy);
            }

            return(creationResult);
        }
Пример #17
0
            public override CreationResult TryCreateDummyValue(Type typeOfDummy, IDummyValueResolver resolver, LoopDetectingResolutionContext resolutionContext)
            {
                if (IsTuple(typeOfDummy))
                {
                    var argTypes = typeOfDummy.GetTypeInfo().GetGenericArguments();
                    var args     = new object[argTypes.Length];
                    for (int i = 0; i < argTypes.Length; i++)
                    {
                        var argType        = argTypes[i];
                        var creationResult = resolver.TryResolveDummyValue(argType, resolutionContext);
                        args[i] = creationResult.WasSuccessful
                            ? creationResult.Result
                            : argType.GetDefaultValue();
                    }

                    var dummy = Activator.CreateInstance(typeOfDummy, args);
                    return(CreationResult.SuccessfullyCreated(dummy));
                }

                return(CreationResult.FailedToCreateDummy(typeOfDummy, "It is not a tuple."));
            }
Пример #18
0
            public CreationResult CreateFake(Type typeOfFake, IProxyOptions proxyOptions, DummyCreationSession session, IDummyValueResolver resolver)
            {
                if (proxyOptions.Attributes.Any())
                {
                    return(CreationResult.FailedToCreateFake(typeOfFake, "Faked delegates cannot have custom attributes applied to them."));
                }

                if (proxyOptions.ArgumentsForConstructor != null && proxyOptions.ArgumentsForConstructor.Any())
                {
                    return(CreationResult.FailedToCreateFake(typeOfFake, "Faked delegates cannot be made using explicit constructor arguments."));
                }

                if (proxyOptions.AdditionalInterfacesToImplement.Any())
                {
                    return(CreationResult.FailedToCreateFake(typeOfFake, "Faked delegates cannot be made to implement additional interfaces."));
                }

                var fakeCallProcessorProvider = this.fakeCallProcessorProviderFactory(typeOfFake, proxyOptions);
                var proxyGeneratorResult      = DelegateProxyGenerator.GenerateProxy(typeOfFake, fakeCallProcessorProvider);

                return(proxyGeneratorResult.ProxyWasSuccessfullyGenerated
                    ? CreationResult.SuccessfullyCreated(proxyGeneratorResult.GeneratedProxy)
                    : CreationResult.FailedToCreateFake(typeOfFake, proxyGeneratorResult.ReasonForFailure));
            }
Пример #19
0
        private CreationResult TryResolveDummyValueWithAllAvailableStrategies(DummyCreationSession session, Type typeOfDummy)
        {
            if (this.strategyCache.TryGetValue(typeOfDummy, out ResolveStrategy cachedStrategy))
            {
                return(cachedStrategy.TryCreateDummyValue(session, typeOfDummy));
            }

            CreationResult creationResult = null;

            foreach (var strategy in this.strategies)
            {
                var thisCreationResult = strategy.TryCreateDummyValue(session, typeOfDummy);
                if (thisCreationResult.WasSuccessful)
                {
                    this.strategyCache.TryAdd(typeOfDummy, strategy);
                    return(thisCreationResult);
                }

                creationResult = CreationResult.MergeIntoDummyResult(creationResult, thisCreationResult);
            }

            this.strategyCache.TryAdd(typeOfDummy, new UnableToResolveStrategy(creationResult));
            return(creationResult);
        }
        public CreationResult CreateFake(
            Type typeOfFake,
            IProxyOptions proxyOptions,
            IDummyValueResolver resolver,
            LoopDetectingResolutionContext resolutionContext)
        {
            if (!resolutionContext.TryBeginToResolve(typeOfFake))
            {
                return(CreationResult.FailedToCreateFake(typeOfFake, "Recursive dependency detected. Already resolving " + typeOfFake + '.'));
            }

            var result = this.CreateFakeWithoutLoopDetection(
                typeOfFake,
                proxyOptions,
                resolver,
                resolutionContext);

            if (result.WasSuccessful)
            {
                resolutionContext.OnSuccessfulResolve(typeOfFake);
            }

            return(result);
        }
Пример #21
0
        public CreationResult CreateFake(
            Type typeOfFake,
            IProxyOptions proxyOptions,
            IDummyValueResolver resolver,
            LoopDetectingResolutionContext resolutionContext)
        {
            if (!resolutionContext.TryBeginToResolve(typeOfFake))
            {
                return(CreationResult.FailedToCreateFake(typeOfFake, "Recursive dependency detected. Already resolving " + typeOfFake + '.'));
            }

            try
            {
                return(this.CreateFakeWithoutLoopDetection(
                           typeOfFake,
                           proxyOptions,
                           resolver,
                           resolutionContext));
            }
            finally
            {
                resolutionContext.EndResolve(typeOfFake);
            }
        }
Пример #22
0
 public override CreationResult MergeIntoDummyResult(CreationResult other) => this;
Пример #23
0
 /// <summary>
 /// Returns a creation result for a dummy by combining two results.
 /// Successful results are preferred to failed. Failed results will have their reasons for failure aggregated.
 /// </summary>
 /// <param name="other">The other result to merge. Must not be <c>null</c>.</param>
 /// <returns>A combined creation result. Successful if either input was successful, and failed otherwise.</returns>
 public abstract CreationResult MergeIntoDummyResult(CreationResult other);
Пример #24
0
 public UnableToResolveStrategy(CreationResult creationResult)
 {
     this.creationResult = creationResult;
 }