public void ExecuteBindingAsync_Traces_And_Throws_When_Inner_Throws()
        {
            // Arrange
            Mock<HttpParameterDescriptor> mockParamDescriptor = new Mock<HttpParameterDescriptor>() { CallBase = true };
            mockParamDescriptor.Setup(d => d.ParameterName).Returns("paramName");
            mockParamDescriptor.Setup(d => d.ParameterType).Returns(typeof(string));
            Mock<FormatterParameterBinding> mockBinding = new Mock<FormatterParameterBinding>(mockParamDescriptor.Object, new MediaTypeFormatterCollection(), null) { CallBase = true };
            InvalidOperationException exception = new InvalidOperationException("test");
            mockBinding.Setup(
                b =>
                b.ExecuteBindingAsync(It.IsAny<ModelMetadataProvider>(), It.IsAny<HttpActionContext>(),
                                      It.IsAny<CancellationToken>())).Throws(exception);

            TestTraceWriter traceWriter = new TestTraceWriter();
            FormatterParameterBindingTracer tracer = new FormatterParameterBindingTracer(mockBinding.Object, traceWriter);
            HttpActionContext actionContext = ContextUtil.CreateActionContext();
            ModelMetadataProvider metadataProvider = new EmptyModelMetadataProvider();

            TraceRecord[] expectedTraces = new TraceRecord[]
            {
                new TraceRecord(actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.Begin, Operation = "ExecuteBindingAsync" },
                new TraceRecord(actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Error) { Kind = TraceKind.End, Operation = "ExecuteBindingAsync" }
            };

            // Act & Assert
            Exception thrown = Assert.Throws<InvalidOperationException>(() => tracer.ExecuteBindingAsync(metadataProvider, actionContext, CancellationToken.None));

            // Assert
            Assert.Same(exception, thrown);
            Assert.Same(exception, traceWriter.Traces[1].Exception);
            Assert.Equal<TraceRecord>(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
        }
        public void ExecuteBindingAsync_Traces_And_Invokes_Inner()
        {
            // Arrange
            Mock<HttpParameterDescriptor> mockParamDescriptor = new Mock<HttpParameterDescriptor>() { CallBase = true };
            mockParamDescriptor.Setup(d => d.ParameterName).Returns("paramName");
            mockParamDescriptor.Setup(d => d.ParameterType).Returns(typeof(string));
            Mock<HttpParameterBinding> mockBinding = new Mock<HttpParameterBinding>(mockParamDescriptor.Object) { CallBase = true };
            bool innerInvoked = false;
            mockBinding.Setup(
                b =>
                b.ExecuteBindingAsync(It.IsAny<ModelMetadataProvider>(), It.IsAny<HttpActionContext>(),
                                      It.IsAny<CancellationToken>())).Returns(TaskHelpers.Completed()).Callback(() => innerInvoked = true);

            TestTraceWriter traceWriter = new TestTraceWriter();
            HttpParameterBindingTracer tracer = new HttpParameterBindingTracer(mockBinding.Object, traceWriter);
            HttpActionContext actionContext = ContextUtil.CreateActionContext();
            ModelMetadataProvider metadataProvider = new EmptyModelMetadataProvider();

            TraceRecord[] expectedTraces = new TraceRecord[]
            {
                new TraceRecord(actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.Begin, Operation = "ExecuteBindingAsync" },
                new TraceRecord(actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.End, Operation = "ExecuteBindingAsync" }
            };

            // Act
            Task task = tracer.ExecuteBindingAsync(metadataProvider, actionContext, CancellationToken.None);
            task.Wait();

            // Assert
            Assert.Equal<TraceRecord>(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
            Assert.True(innerInvoked);
        }
        public void ExecuteBindingAsync_Traces_And_Invokes_Inner_ReadAsync()
        {
            // Arrange
            Mock<HttpParameterDescriptor> mockParamDescriptor = new Mock<HttpParameterDescriptor>() { CallBase = true };
            mockParamDescriptor.Setup(d => d.ParameterName).Returns("paramName");
            mockParamDescriptor.Setup(d => d.ParameterType).Returns(typeof (string));
            FormatterParameterBinding binding = new FormatterParameterBinding(mockParamDescriptor.Object, new MediaTypeFormatterCollection(), null);
            TestTraceWriter traceWriter = new TestTraceWriter();
            FormatterParameterBindingTracer tracer = new FormatterParameterBindingTracer(binding, traceWriter);
            HttpActionContext actionContext = ContextUtil.CreateActionContext();
            actionContext.Request.Content = new StringContent("true");
            actionContext.Request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            ModelMetadataProvider metadataProvider = new EmptyModelMetadataProvider();

            TraceRecord[] expectedTraces = new TraceRecord[]
            {
                new TraceRecord(actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.Begin, Operation = "ExecuteBindingAsync" },
                new TraceRecord(actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.End, Operation = "ExecuteBindingAsync" }
            };

            // Act
            Task task = tracer.ExecuteBindingAsync(metadataProvider, actionContext, CancellationToken.None);
            task.Wait();

            // Assert
            Assert.Equal<TraceRecord>(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
            Assert.Equal("True", actionContext.ActionArguments["paramName"]);
        }
        public void GetModelValidator_DoesNotReadPropertyValues()
        {
            // Arrange
            IEnumerable<ModelValidatorProvider> validatorProviders = new[] { new ObservableModelValidatorProvider() };
            ObservableModel model = new ObservableModel();
            ModelMetadata metadata = new EmptyModelMetadataProvider().GetMetadataForType(() => model, typeof(ObservableModel));

            // Act
            ModelValidator validator = ModelValidator.GetModelValidator(validatorProviders);
            ModelValidationResult[] results = validator.Validate(metadata, model).ToArray();

            // Assert
            Assert.False(model.PropertyWasRead());
        }
        public void Validate_SkipsRemainingValidationIfModelStateIsInvalid()
        {
            // Because a property validator fails, the model validator shouldn't run

            // Arrange
            List<string> log = new List<string>();
            LoggingValidatableObject model = new LoggingValidatableObject(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);
            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));
            node.Validating += (sender, e) => log.Add("In OnValidating()");
            node.Validated += (sender, e) => log.Add("In OnValidated()");
            HttpActionContext context = ContextUtil.CreateActionContext();

            // Act
            node.Validate(context);

            // Assert
            Assert.Equal(new[] { "In OnValidating()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray());
            Assert.Equal("Sample error message", context.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
        }
        public void Validate_Ordering()
        {
            // Proper order of invocation:
            // 1. OnValidating()
            // 2. Child validators
            // 3. This validator
            // 4. OnValidated()

            // Arrange
            List<string> log = new List<string>();
            LoggingValidatableObject model = new LoggingValidatableObject(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);
            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
            node.Validating += (sender, e) => log.Add("In OnValidating()");
            node.Validated += (sender, e) => log.Add("In OnValidated()");
            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty"));

            // Act
            node.Validate(ContextUtil.CreateActionContext());

            // Assert
            Assert.Equal(new[] { "In OnValidating()", "In LoggingValidatonAttribute.IsValid()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray());
        }
        public void BindModel()
        {
            // Arrange
            MyModel model = new MyModel();
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => model, typeof(MyModel));
            ComplexModelDto dto = new ComplexModelDto(modelMetadata, modelMetadata.Properties);
            Mock<IModelBinder> mockStringBinder = new Mock<IModelBinder>();
            Mock<IModelBinder> mockIntBinder = new Mock<IModelBinder>();
            Mock<IModelBinder> mockDateTimeBinder = new Mock<IModelBinder>();
            HttpActionContext context = ContextUtil.CreateActionContext();
            context.ControllerContext.Configuration.ServiceResolver.SetServices(typeof(ModelBinderProvider),
                    new SimpleModelBinderProvider(typeof(string), mockStringBinder.Object) { SuppressPrefixCheck = true },
                    new SimpleModelBinderProvider(typeof(int), mockIntBinder.Object) { SuppressPrefixCheck = true },
                    new SimpleModelBinderProvider(typeof(DateTime), mockDateTimeBinder.Object) { SuppressPrefixCheck = true });

            mockStringBinder
                .Setup(b => b.BindModel(context, It.IsAny<ModelBindingContext>()))
                .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
                {
                    Assert.Equal(typeof(string), mbc.ModelType);
                    Assert.Equal("theModel.StringProperty", mbc.ModelName);
                    mbc.ValidationNode = new ModelValidationNode(mbc.ModelMetadata, "theModel.StringProperty");
                    mbc.Model = "someStringValue";
                    return true;
                });
            mockIntBinder
                .Setup(b => b.BindModel(context, It.IsAny<ModelBindingContext>()))
                .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
                {
                    Assert.Equal(typeof(int), mbc.ModelType);
                    Assert.Equal("theModel.IntProperty", mbc.ModelName);
                    mbc.ValidationNode = new ModelValidationNode(mbc.ModelMetadata, "theModel.IntProperty");
                    mbc.Model = 42;
                    return true;
                });
            mockDateTimeBinder
                .Setup(b => b.BindModel(context, It.IsAny<ModelBindingContext>()))
                .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
                {
                    Assert.Equal(typeof(DateTime), mbc.ModelType);
                    Assert.Equal("theModel.DateTimeProperty", mbc.ModelName);
                    return false;
                });
            ModelBindingContext parentBindingContext = new ModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => dto, typeof(ComplexModelDto)),
                ModelName = "theModel",
            };
            ComplexModelDtoModelBinder binder = new ComplexModelDtoModelBinder();

            // Act
            bool retVal = binder.BindModel(context, parentBindingContext);

            // Assert
            Assert.True(retVal);
            Assert.Equal(dto, parentBindingContext.Model);

            ComplexModelDtoResult stringDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(string)).First()];
            Assert.Equal("someStringValue", stringDtoResult.Model);
            Assert.Equal("theModel.StringProperty", stringDtoResult.ValidationNode.ModelStateKey);

            ComplexModelDtoResult intDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(int)).First()];
            Assert.Equal(42, intDtoResult.Model);
            Assert.Equal("theModel.IntProperty", intDtoResult.ValidationNode.ModelStateKey);

            ComplexModelDtoResult dateTimeDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(DateTime)).First()];
            Assert.Null(dateTimeDtoResult);
        }
 private static ModelValidationNode GetValidationNode()
 {
     EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
     ModelMetadata metadata = provider.GetMetadataForType(null, typeof(object));
     return new ModelValidationNode(metadata, "someKey");
 }
            public ControllerData(Type type)
            {
                var metadataProvider = new EmptyModelMetadataProvider();

                this.Properties =
                   (from p in type.GetProperties()
                let attr = p.GetCustomAttributes(typeof(FromRouteAttribute), inherit: true)
                  .Cast<FromRouteAttribute>()
                  .SingleOrDefault()
                where attr != null
                select new PropertyData(
                   property: p,
                   attribute: attr,
                   metadata: metadataProvider.GetMetadataForType(null, p.PropertyType)
                )).ToArray();
            }
        public void SimpleDisplayTextReturnsEmptyStringForNonNullModelWithNoVisibleProperties()
        {
            // Arrange
            SimpleDisplayTextModelWithNoProperties model = new SimpleDisplayTextModelWithNoProperties();
            EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
            ModelMetadata metadata = new ModelMetadata(provider, null, () => model, typeof(SimpleDisplayTextModelWithNoProperties), null);

            // Act
            string result = metadata.SimpleDisplayText;

            // Assert
            Assert.Equal(String.Empty, result);
        }
        public void SimpleDisplayTextReturnsFirstPropertyNullDisplayTextForNonNullModelWithNullDisplayColumnPropertyValue()
        {
            // Arrange
            SimpleDisplayTextModelWithoutToString model = new SimpleDisplayTextModelWithoutToString();
            EmptyModelMetadataProvider propertyProvider = new EmptyModelMetadataProvider();
            ModelMetadata propertyMetadata = propertyProvider.GetMetadataForProperty(() => model.FirstProperty, typeof(SimpleDisplayTextModelWithoutToString), "FirstProperty");
            propertyMetadata.NullDisplayText = "Null Display Text";
            Mock<ModelMetadataProvider> provider = new Mock<ModelMetadataProvider>();
            provider.Setup(p => p.GetMetadataForProperties(model, typeof(SimpleDisplayTextModelWithoutToString)))
                .Returns(new[] { propertyMetadata });
            ModelMetadata metadata = new ModelMetadata(provider.Object, null, () => model, typeof(SimpleDisplayTextModelWithoutToString), null);

            // Act
            string result = metadata.SimpleDisplayText;

            // Assert
            Assert.Equal(propertyMetadata.NullDisplayText, result);
        }
        public void SimpleDisplayTextReturnsFirstPropertyValueForNonNullModel()
        {
            // Arrange
            SimpleDisplayTextModelWithoutToString model = new SimpleDisplayTextModelWithoutToString
            {
                FirstProperty = "First Property Value"
            };
            EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
            ModelMetadata metadata = new ModelMetadata(provider, null, () => model, typeof(SimpleDisplayTextModelWithoutToString), null);

            // Act
            string result = metadata.SimpleDisplayText;

            // Assert
            Assert.Equal(model.FirstProperty, result);
        }
        public void SimpleDisplayTextReturnsToStringValueWhenOverridden()
        {
            // Arrange
            SimpleDisplayTextModelWithToString model = new SimpleDisplayTextModelWithToString();
            EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
            ModelMetadata metadata = new ModelMetadata(provider, null, () => model, typeof(SimpleDisplayTextModelWithToString), null);

            // Act
            string result = metadata.SimpleDisplayText;

            // Assert
            Assert.Equal(model.ToString(), result);
        }
        public void BindingUnboundedCollection_WithRecursiveRelation_ProducesSingleLengthCollection()
        {
            // Arrange
            string propertyName = "People";
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(
                                                            modelAccessor: null,
                                                            containerType: typeof(PeopleModel),
                                                            propertyName: propertyName);
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = modelMetadata,
                ModelName = propertyName,
                ValueProvider = new SimpleHttpValueProvider { { propertyName, "test value" } }
            };
            HttpActionContext context = ContextUtil.CreateActionContext();
            CollectionModelBinder<Person> binder =
                new CollectionModelBinder<Person>();

            // Act
            bool result = binder.BindModel(context, bindingContext);

            // Assert
            Assert.True(result);
            List<Person> boundModel =
                Assert.IsType<List<Person>>(bindingContext.Model);
            Person type = Assert.Single(boundModel);
            Assert.Null(type.Name);
        }
        public void BindingListsWithIndex_ProducesSingleLengthCollection_WithNullValues()
        {
            // Arrange
            string propertyName = "Addresses";
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(
                                                            modelAccessor: null,
                                                            containerType: typeof(UserWithAddress),
                                                            propertyName: propertyName);
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = modelMetadata,
                ModelName = propertyName,
                ValueProvider = new SimpleHttpValueProvider { { "Addresses.index", "10000" } }
            };
            HttpActionContext context = ContextUtil.CreateActionContext();
            CollectionModelBinder<UserWithAddress> binder = new CollectionModelBinder<UserWithAddress>();

            // Act
            bool result = binder.BindModel(context, bindingContext);

            // Assert
            Assert.True(result);
            List<UserWithAddress> boundModel = Assert.IsType<List<UserWithAddress>>(bindingContext.Model);
            UserWithAddress listModel = Assert.Single(boundModel);
            Assert.Null(listModel);
        }
        public void BindingNestedUnboundedCollection_WhenNoValuesArePresent_ProducesEmptyCollection()
        {
            // Arrange
            string propertyName = "Addresses";
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(
                                                            modelAccessor: null,
                                                            containerType: typeof(UserWithAddress),
                                                            propertyName: propertyName);
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = modelMetadata,
                ModelName = propertyName,
                ValueProvider = new SimpleHttpValueProvider { { "Addresses.AddressLines", "some value" } }
            };
            HttpActionContext context = ContextUtil.CreateActionContext();
            CollectionModelBinder<UserWithAddress> binder = new CollectionModelBinder<UserWithAddress>();

            // Act
            bool result = binder.BindModel(context, bindingContext);

            // Assert
            Assert.True(result);
            List<UserWithAddress> boundModel = Assert.IsType<List<UserWithAddress>>(bindingContext.Model);
            Assert.Empty(boundModel);
        }