예제 #1
0
파일: Mock.cs 프로젝트: tomchavakis/moq4
        internal object GetDefaultValue(MethodInfo method, DefaultValueProvider useAlternateProvider = null)
        {
            Debug.Assert(method != null);
            Debug.Assert(method.ReturnType != null);
            Debug.Assert(method.ReturnType != typeof(void));

            if (this.ConfiguredDefaultValues.TryGetValue(method.ReturnType, out object configuredDefaultValue))
            {
                return(configuredDefaultValue);
            }

            var result          = (useAlternateProvider ?? this.DefaultValueProvider).GetDefaultReturnValue(method, this);
            var unwrappedResult = TryUnwrapResultFromCompletedTaskRecursively(result);

            if (unwrappedResult is IMocked unwrappedMockedResult)
            {
                // TODO: Perhaps the following `InnerMocks` update isn't in quite the right place yet.
                // There are two main places in Moq where `InnerMocks` are used: `Mock<T>.FluentMock` and
                // the `HandleMockRecursion` interception strategy. Both places first query `InnerMocks`,
                // and if no value for a given member is present, the default value provider get invoked
                // via the present method. Querying and updating `InnerMocks` is thus spread over two
                // code locations and therefore non-atomic. It would be good if those could be combined
                // (`InnerMocks.GetOrAdd`), but that might not be easily possible since `InnerMocks` is
                // only mocks while default value providers can also return plain, unmocked values.
                this.InnerMocks.TryAdd(method, new MockWithWrappedMockObject(unwrappedMockedResult.Mock, result));
            }

            return(result);
        }
예제 #2
0
            public InvocationObservation(Mock mock, Invocation invocation)
            {
                this.Mock       = mock;
                this.Invocation = invocation;

                this.defaultValueProvider = mock.DefaultValueProvider;
                mock.DefaultValueProvider = DefaultValueProvider.Mock;
            }
예제 #3
0
            public MockInvocation(Mock mock, Invocation invocation, Match matcher)
            {
                this.Mock                 = mock;
                this.Invocation           = invocation;
                this.Match                = matcher;
                this.defaultValueProvider = mock.DefaultValueProvider;

                // Temporarily set mock default value to Mock so that recursion works.
                mock.DefaultValue = DefaultValue.Mock;
            }
예제 #4
0
        public Mock(MockBehavior behavior, params object[] args)
        {
            if (args == null)
            {
                args = new object[] { null };
            }

            this.additionalInterfaces    = new List <Type>();
            this.behavior                = behavior;
            this.configuredDefaultValues = new Dictionary <Type, object>();
            this.constructorArguments    = args;
            this.defaultValueProvider    = DefaultValueProvider.Empty;
            this.eventHandlers           = new EventHandlerCollection();
            this.innerMocks              = new ConcurrentDictionary <MethodInfo, MockWithWrappedMockObject>();
            this.invocations             = new InvocationCollection();
            this.name     = CreateUniqueDefaultMockName();
            this.setups   = new SetupCollection();
            this.switches = Switches.Default;

            this.CheckParameters();
        }
예제 #5
0
        /// <summary>
        /// Invokes the given delegate when the method being set up is invoked, typically used
        /// to access and set ref/out arguments in a typed fashion. Used in combination
        /// with <see cref="SetupExtension.Setup{TDelegate}(object, TDelegate)"/>.
        /// </summary>
        /// <typeparam name="TDelegate">The lambda to invoke when the setup method runs.</typeparam>
        /// <param name="target">The setup being performed.</param>
        /// <param name="handler">The lambda to invoke when the setup is matched.</param>
        public static void Returns <TDelegate>(this ISetup <TDelegate> target, TDelegate handler)
        {
            if (handler is not Delegate @delegate)
            {
                throw new ArgumentException(ThisAssembly.Strings.Returns.DelegateExpected, nameof(handler));
            }

            using (new SetupScope())
            {
                // Simulate Any<T> matchers for each member parameter
                var       parameters   = @delegate.Method.GetParameters();
                object?[] arguments    = new object[parameters.Length];
                var       defaultValue = new DefaultValueProvider(false);
                for (var i = 0; i < arguments.Length; i++)
                {
                    var parameter = parameters[i];

                    MockSetup.Push(new AnyMatcher(parameter.IsOut ? parameter.ParameterType.GetElementType() : parameter.ParameterType));
                    if (!parameter.IsOut)
                    {
                        arguments[i] = defaultValue.GetDefault(parameter.ParameterType);
                    }
                }

                target.Delegate.DynamicInvoke(arguments);

                // Now we'd have a setup in place and an actual invocation.
                var setup = MockContext.CurrentSetup;
                if (setup != null)
                {
                    setup.Invocation.Target
                    .AsMock()
                    .GetPipeline(setup)
                    .Behaviors.Add(new ReturnsDelegateBehavior(@delegate));
                }
            }
        }
예제 #6
0
 /// <summary>
 /// Initializes the repository with the given <paramref name="defaultBehavior"/>
 /// for newly created mocks from the repository.
 /// </summary>
 /// <param name="defaultBehavior">The behavior to use for mocks created
 /// using the <see cref="Create{T}()"/> repository method if not overridden
 /// by using the <see cref="Create{T}(MockBehavior)"/> overload.</param>
 public MockRepository(MockBehavior defaultBehavior)
 {
     this.defaultBehavior      = defaultBehavior;
     this.defaultValueProvider = DefaultValueProvider.Empty;
     this.switches             = Switches.Default;
 }
예제 #7
0
파일: Mock.cs 프로젝트: tomchavakis/moq4
        private static void SetupAllPropertiesPexProtected(Mock mock, DefaultValueProvider defaultValueProvider)
        {
            var mockType = mock.MockedType;

            var properties =
                mockType
                .GetAllPropertiesInDepthFirstOrder()
                // ^ Depth-first traversal is important because properties in derived interfaces
                //   that shadow properties in base interfaces should be set up last. This
                //   enables the use case where a getter-only property is redeclared in a derived
                //   interface as a getter-and-setter property.
                .Where(p =>
                       p.CanRead && p.CanOverrideGet() &&
                       p.CanWrite == p.CanOverrideSet() &&
                       // ^ This condition will be true for two kinds of properties:
                       //    (a) those that are read-only; and
                       //    (b) those that are writable and whose setter can be overridden.
                       p.GetIndexParameters().Length == 0 &&
                       ProxyFactory.Instance.IsMethodVisible(p.GetGetMethod(), out _))
                .Distinct();

            foreach (var property in properties)
            {
                var expression = GetPropertyExpression(mockType, property);
                var getter     = property.GetGetMethod(true);

                object value       = null;
                bool   valueNotSet = true;

                mock.Setups.Add(new PropertyGetterMethodCall(mock, expression, getter, () =>
                {
                    if (valueNotSet)
                    {
                        object initialValue;
                        try
                        {
                            initialValue = mock.GetDefaultValue(getter, useAlternateProvider: defaultValueProvider);
                        }
                        catch
                        {
                            // Since this method performs a batch operation, a single failure of the default value
                            // provider should not tear down the whole operation. The empty default value provider
                            // is a safe fallback because it does not throw.
                            initialValue = mock.GetDefaultValue(getter, useAlternateProvider: DefaultValueProvider.Empty);
                        }

                        if (initialValue is IMocked mocked)
                        {
                            SetupAllPropertiesPexProtected(mocked.Mock, defaultValueProvider);
                        }

                        value       = initialValue;
                        valueNotSet = false;
                    }
                    return(value);
                }));

                if (property.CanWrite)
                {
                    mock.Setups.Add(new PropertySetterMethodCall(mock, expression, property.GetSetMethod(true), (newValue) =>
                    {
                        value       = newValue;
                        valueNotSet = false;
                    }));
                }
            }
        }