PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Web.Http.Test/Internal/CollectionModelBinderUtilTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 394 lines | 263 code | 66 blank | 65 comment | 0 complexity | 4af79587c654e80552608d974ac8661e MD5 | raw file
  1. using System.Collections.Generic;
  2. using System.Collections.ObjectModel;
  3. using System.Linq;
  4. using System.Web.Http.Metadata;
  5. using System.Web.Http.Metadata.Providers;
  6. using System.Web.Http.ModelBinding;
  7. using System.Web.Http.ValueProviders;
  8. using Xunit;
  9. using Assert = Microsoft.TestCommon.AssertEx;
  10. namespace System.Web.Http.Internal
  11. {
  12. public class CollectionModelBinderUtilTest
  13. {
  14. [Fact]
  15. public void CreateOrReplaceCollection_OriginalModelImmutable_CreatesNewInstance()
  16. {
  17. // Arrange
  18. ModelBindingContext bindingContext = new ModelBindingContext
  19. {
  20. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new ReadOnlyCollection<int>(new int[0]), typeof(ICollection<int>))
  21. };
  22. // Act
  23. CollectionModelBinderUtil.CreateOrReplaceCollection(bindingContext, new[] { 10, 20, 30 }, () => new List<int>());
  24. // Assert
  25. int[] newModel = (bindingContext.Model as ICollection<int>).ToArray();
  26. Assert.Equal(new[] { 10, 20, 30 }, newModel);
  27. }
  28. [Fact]
  29. public void CreateOrReplaceCollection_OriginalModelMutable_UpdatesOriginalInstance()
  30. {
  31. // Arrange
  32. List<int> originalInstance = new List<int> { 10, 20, 30 };
  33. ModelBindingContext bindingContext = new ModelBindingContext
  34. {
  35. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => originalInstance, typeof(ICollection<int>))
  36. };
  37. // Act
  38. CollectionModelBinderUtil.CreateOrReplaceCollection(bindingContext, new[] { 40, 50, 60 }, () => new List<int>());
  39. // Assert
  40. Assert.Same(originalInstance, bindingContext.Model);
  41. Assert.Equal(new[] { 40, 50, 60 }, originalInstance.ToArray());
  42. }
  43. [Fact]
  44. public void CreateOrReplaceCollection_OriginalModelNotCollection_CreatesNewInstance()
  45. {
  46. // Arrange
  47. ModelBindingContext bindingContext = new ModelBindingContext
  48. {
  49. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(ICollection<int>))
  50. };
  51. // Act
  52. CollectionModelBinderUtil.CreateOrReplaceCollection(bindingContext, new[] { 10, 20, 30 }, () => new List<int>());
  53. // Assert
  54. int[] newModel = (bindingContext.Model as ICollection<int>).ToArray();
  55. Assert.Equal(new[] { 10, 20, 30 }, newModel);
  56. }
  57. [Fact]
  58. public void CreateOrReplaceDictionary_DisallowsDuplicateKeys()
  59. {
  60. // Arrange
  61. ModelBindingContext bindingContext = new ModelBindingContext
  62. {
  63. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(Dictionary<string, int>))
  64. };
  65. // Act
  66. CollectionModelBinderUtil.CreateOrReplaceDictionary(
  67. bindingContext,
  68. new[]
  69. {
  70. new KeyValuePair<string, int>("forty-two", 40),
  71. new KeyValuePair<string, int>("forty-two", 2),
  72. new KeyValuePair<string, int>("forty-two", 42)
  73. },
  74. () => new Dictionary<string, int>());
  75. // Assert
  76. IDictionary<string, int> newModel = bindingContext.Model as IDictionary<string, int>;
  77. Assert.Equal(new[] { "forty-two" }, newModel.Keys.ToArray());
  78. Assert.Equal(42, newModel["forty-two"]);
  79. }
  80. [Fact]
  81. public void CreateOrReplaceDictionary_DisallowsNullKeys()
  82. {
  83. // Arrange
  84. ModelBindingContext bindingContext = new ModelBindingContext
  85. {
  86. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(Dictionary<string, int>))
  87. };
  88. // Act
  89. CollectionModelBinderUtil.CreateOrReplaceDictionary(
  90. bindingContext,
  91. new[]
  92. {
  93. new KeyValuePair<string, int>("forty-two", 42),
  94. new KeyValuePair<string, int>(null, 84)
  95. },
  96. () => new Dictionary<string, int>());
  97. // Assert
  98. IDictionary<string, int> newModel = bindingContext.Model as IDictionary<string, int>;
  99. Assert.Equal(new[] { "forty-two" }, newModel.Keys.ToArray());
  100. Assert.Equal(42, newModel["forty-two"]);
  101. }
  102. [Fact]
  103. public void CreateOrReplaceDictionary_OriginalModelImmutable_CreatesNewInstance()
  104. {
  105. // Arrange
  106. ReadOnlyDictionary<string, string> originalModel = new ReadOnlyDictionary<string, string>();
  107. ModelBindingContext bindingContext = new ModelBindingContext
  108. {
  109. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => originalModel, typeof(IDictionary<string, string>))
  110. };
  111. // Act
  112. CollectionModelBinderUtil.CreateOrReplaceDictionary(
  113. bindingContext,
  114. new Dictionary<string, string>
  115. {
  116. { "Hello", "World" }
  117. },
  118. () => new Dictionary<string, string>());
  119. // Assert
  120. IDictionary<string, string> newModel = bindingContext.Model as IDictionary<string, string>;
  121. Assert.NotSame(originalModel, newModel);
  122. Assert.Equal(new[] { "Hello" }, newModel.Keys.ToArray());
  123. Assert.Equal("World", newModel["Hello"]);
  124. }
  125. [Fact]
  126. public void CreateOrReplaceDictionary_OriginalModelMutable_UpdatesOriginalInstance()
  127. {
  128. // Arrange
  129. Dictionary<string, string> originalInstance = new Dictionary<string, string>
  130. {
  131. { "dog", "Canidae" },
  132. { "cat", "Felidae" }
  133. };
  134. ModelBindingContext bindingContext = new ModelBindingContext
  135. {
  136. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => originalInstance, typeof(IDictionary<string, string>))
  137. };
  138. // Act
  139. CollectionModelBinderUtil.CreateOrReplaceDictionary(
  140. bindingContext,
  141. new Dictionary<string, string>
  142. {
  143. { "horse", "Equidae" },
  144. { "bear", "Ursidae" }
  145. },
  146. () => new Dictionary<string, string>());
  147. // Assert
  148. Assert.Same(originalInstance, bindingContext.Model);
  149. Assert.Equal(new[] { "horse", "bear" }, originalInstance.Keys.ToArray());
  150. Assert.Equal("Equidae", originalInstance["horse"]);
  151. Assert.Equal("Ursidae", originalInstance["bear"]);
  152. }
  153. [Fact]
  154. public void CreateOrReplaceDictionary_OriginalModelNotDictionary_CreatesNewInstance()
  155. {
  156. // Arrange
  157. ModelBindingContext bindingContext = new ModelBindingContext
  158. {
  159. ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IDictionary<string, string>))
  160. };
  161. // Act
  162. CollectionModelBinderUtil.CreateOrReplaceDictionary(
  163. bindingContext,
  164. new Dictionary<string, string>
  165. {
  166. { "horse", "Equidae" },
  167. { "bear", "Ursidae" }
  168. },
  169. () => new Dictionary<string, string>());
  170. // Assert
  171. IDictionary<string, string> newModel = bindingContext.Model as IDictionary<string, string>;
  172. Assert.Equal(new[] { "horse", "bear" }, newModel.Keys.ToArray());
  173. Assert.Equal("Equidae", newModel["horse"]);
  174. Assert.Equal("Ursidae", newModel["bear"]);
  175. }
  176. [Fact]
  177. public void GetIndexNamesFromValueProviderResult_ValueProviderResultIsNull_ReturnsNull()
  178. {
  179. // Act
  180. IEnumerable<string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(null);
  181. // Assert
  182. Assert.Null(indexNames);
  183. }
  184. [Fact]
  185. public void GetIndexNamesFromValueProviderResult_ValueProviderResultReturnsEmptyArray_ReturnsNull()
  186. {
  187. // Arrange
  188. ValueProviderResult vpResult = new ValueProviderResult(new string[0], "", null);
  189. // Act
  190. IEnumerable<string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(vpResult);
  191. // Assert
  192. Assert.Null(indexNames);
  193. }
  194. [Fact]
  195. public void GetIndexNamesFromValueProviderResult_ValueProviderResultReturnsNonEmptyArray_ReturnsArray()
  196. {
  197. // Arrange
  198. ValueProviderResult vpResult = new ValueProviderResult(new[] { "foo", "bar", "baz" }, "foo,bar,baz", null);
  199. // Act
  200. IEnumerable<string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(vpResult);
  201. // Assert
  202. Assert.NotNull(indexNames);
  203. Assert.Equal(new[] { "foo", "bar", "baz" }, indexNames.ToArray());
  204. }
  205. [Fact]
  206. public void GetIndexNamesFromValueProviderResult_ValueProviderResultReturnsNull_ReturnsNull()
  207. {
  208. // Arrange
  209. ValueProviderResult vpResult = new ValueProviderResult(null, null, null);
  210. // Act
  211. IEnumerable<string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(vpResult);
  212. // Assert
  213. Assert.Null(indexNames);
  214. }
  215. [Fact]
  216. public void GetTypeArgumentsForUpdatableGenericCollection_ModelTypeNotGeneric_Fail()
  217. {
  218. // Arrange
  219. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int));
  220. // Act
  221. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(null, null, modelMetadata);
  222. // Assert
  223. Assert.Null(typeArguments);
  224. }
  225. [Fact]
  226. public void GetTypeArgumentsForUpdatableGenericCollection_ModelTypeOpenGeneric_Fail()
  227. {
  228. // Arrange
  229. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IList<>));
  230. // Act
  231. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(null, null, modelMetadata);
  232. // Assert
  233. Assert.Null(typeArguments);
  234. }
  235. [Fact]
  236. public void GetTypeArgumentsForUpdatableGenericCollection_ModelTypeWrongNumberOfGenericArguments_Fail()
  237. {
  238. // Arrange
  239. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(KeyValuePair<int, string>));
  240. // Act
  241. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection<>), null, modelMetadata);
  242. // Assert
  243. Assert.Null(typeArguments);
  244. }
  245. [Fact]
  246. public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelInstanceImmutable_Valid()
  247. {
  248. // Arrange
  249. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new int[0], typeof(IList<int>));
  250. modelMetadata.IsReadOnly = true;
  251. // Act
  252. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(IList<>), typeof(List<>), modelMetadata);
  253. // Assert
  254. Assert.Null(typeArguments);
  255. }
  256. [Fact]
  257. public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelInstanceMutable_Valid()
  258. {
  259. // Arrange
  260. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new List<int>(), typeof(IList<int>));
  261. modelMetadata.IsReadOnly = true;
  262. // Act
  263. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(IList<>), typeof(List<>), modelMetadata);
  264. // Assert
  265. Assert.Equal(new[] { typeof(int) }, typeArguments);
  266. }
  267. [Fact]
  268. public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelInstanceOfWrongType_Fail()
  269. {
  270. // Arrange
  271. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new HashSet<int>(), typeof(ICollection<int>));
  272. modelMetadata.IsReadOnly = true;
  273. // Act
  274. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(IList<>), typeof(List<>), modelMetadata);
  275. // Assert
  276. // HashSet<> is not an IList<>, so we can't update
  277. Assert.Null(typeArguments);
  278. }
  279. [Fact]
  280. public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelIsNull_Fail()
  281. {
  282. // Arrange
  283. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IList<int>));
  284. modelMetadata.IsReadOnly = true;
  285. // Act
  286. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection<>), typeof(List<>), modelMetadata);
  287. // Assert
  288. Assert.Null(typeArguments);
  289. }
  290. [Fact]
  291. public void GetTypeArgumentsForUpdatableGenericCollection_ReadWriteReference_NewInstanceAssignableToModelType_Success()
  292. {
  293. // Arrange
  294. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IList<int>));
  295. modelMetadata.IsReadOnly = false;
  296. // Act
  297. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection<>), typeof(List<>), modelMetadata);
  298. // Assert
  299. Assert.Equal(new[] { typeof(int) }, typeArguments);
  300. }
  301. [Fact]
  302. public void GetTypeArgumentsForUpdatableGenericCollection_ReadWriteReference_NewInstanceNotAssignableToModelType_MutableInstance_Success()
  303. {
  304. // Arrange
  305. ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new Collection<int>(), typeof(Collection<int>));
  306. modelMetadata.IsReadOnly = false;
  307. // Act
  308. Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection<>), typeof(List<>), modelMetadata);
  309. // Assert
  310. Assert.Equal(new[] { typeof(int) }, typeArguments);
  311. }
  312. [Fact]
  313. public void GetZeroBasedIndexes()
  314. {
  315. // Act
  316. string[] indexes = CollectionModelBinderUtil.GetZeroBasedIndexes().Take(5).ToArray();
  317. // Assert
  318. Assert.Equal(new[] { "0", "1", "2", "3", "4" }, indexes);
  319. }
  320. private class ReadOnlyDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>
  321. {
  322. bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
  323. {
  324. get { return true; }
  325. }
  326. }
  327. }
  328. }