1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Web.Http.Controllers;
6 using System.Web.Http.Metadata.Providers;
7 using System.Web.Http.Util;
8 using Moq;
9 using Xunit;
10 
11 namespace System.Web.Http.ModelBinding.Binders
12 {
13     public class KeyValuePairModelBinderTest
14     {
15         [Fact]
BindModel_MissingKey_ReturnsFalse()16         public void BindModel_MissingKey_ReturnsFalse()
17         {
18             // Arrange
19             KeyValuePairModelBinder<int, string> binder = new KeyValuePairModelBinder<int, string>();
20             ModelBindingContext bindingContext = new ModelBindingContext
21             {
22                 ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(KeyValuePair<int, string>)),
23                 ModelName = "someName",
24                 ValueProvider = new SimpleHttpValueProvider()
25             };
26             HttpActionContext context = ContextUtil.CreateActionContext();
27             context.ControllerContext.Configuration.Services.Replace(typeof(ModelBinderProvider), new SimpleModelBinderProvider(typeof(KeyValuePair<int, string>), binder));
28 
29             // Act
30             bool retVal = binder.BindModel(context, bindingContext);
31 
32             // Assert
33             Assert.False(retVal);
34             Assert.Null(bindingContext.Model);
35             Assert.Empty(bindingContext.ValidationNode.ChildNodes);
36         }
37 
38         [Fact]
BindModel_MissingValue_ReturnsTrue()39         public void BindModel_MissingValue_ReturnsTrue()
40         {
41             // Arrange
42             Mock<IModelBinder> mockIntBinder = new Mock<IModelBinder>();
43             ModelBindingContext bindingContext = new ModelBindingContext
44             {
45                 ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(KeyValuePair<int, string>)),
46                 ModelName = "someName",
47                 ValueProvider = new SimpleHttpValueProvider()
48             };
49             HttpActionContext context = ContextUtil.CreateActionContext();
50             context.ControllerContext.Configuration.Services.Replace(typeof(ModelBinderProvider), new SimpleModelBinderProvider(typeof(int), mockIntBinder.Object) { SuppressPrefixCheck = true });
51 
52             mockIntBinder
53                 .Setup(o => o.BindModel(context, It.IsAny<ModelBindingContext>()))
54                 .Returns((HttpActionContext cc, ModelBindingContext mbc) =>
55                 {
56                     mbc.Model = 42;
57                     return true;
58                 });
59             KeyValuePairModelBinder<int, string> binder = new KeyValuePairModelBinder<int, string>();
60 
61             // Act
62             bool retVal = binder.BindModel(context, bindingContext);
63 
64             // Assert
65             Assert.True(retVal);
66             Assert.Null(bindingContext.Model);
67             Assert.Equal(new[] { "someName.key" }, bindingContext.ValidationNode.ChildNodes.Select(n => n.ModelStateKey).ToArray());
68         }
69 
70         [Fact]
BindModel_SubBindingSucceeds()71         public void BindModel_SubBindingSucceeds()
72         {
73             // Arrange
74             Mock<IModelBinder> mockIntBinder = new Mock<IModelBinder>();
75             Mock<IModelBinder> mockStringBinder = new Mock<IModelBinder>();
76             ModelBindingContext bindingContext = new ModelBindingContext
77             {
78                 ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(KeyValuePair<int, string>)),
79                 ModelName = "someName",
80                 ValueProvider = new SimpleHttpValueProvider()
81             };
82             HttpActionContext context = ContextUtil.CreateActionContext();
83             context.ControllerContext.Configuration.Services.ReplaceRange(typeof(ModelBinderProvider),
84                 new ModelBinderProvider[] {
85                     new SimpleModelBinderProvider(typeof(int), mockIntBinder.Object) { SuppressPrefixCheck = true },
86                     new SimpleModelBinderProvider(typeof(string), mockStringBinder.Object) { SuppressPrefixCheck = true }
87                 });
88 
89             mockIntBinder
90                 .Setup(o => o.BindModel(context, It.IsAny<ModelBindingContext>()))
91                 .Returns((HttpActionContext cc, ModelBindingContext mbc) =>
92                 {
93                     mbc.Model = 42;
94                     return true;
95                 });
96             mockStringBinder
97                 .Setup(o => o.BindModel(context, It.IsAny<ModelBindingContext>()))
98                 .Returns((HttpActionContext cc, ModelBindingContext mbc) =>
99                 {
100                     mbc.Model = "forty-two";
101                     return true;
102                 });
103             KeyValuePairModelBinder<int, string> binder = new KeyValuePairModelBinder<int, string>();
104 
105             // Act
106             bool retVal = binder.BindModel(context, bindingContext);
107 
108             // Assert
109             Assert.True(retVal);
110             Assert.Equal(new KeyValuePair<int, string>(42, "forty-two"), bindingContext.Model);
111             Assert.Equal(new[] { "someName.key", "someName.value" }, bindingContext.ValidationNode.ChildNodes.Select(n => n.ModelStateKey).ToArray());
112         }
113     }
114 }
115