PageRenderTime 28ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/test/Microsoft.Web.Mvc.Test/ModelBinding/Test/CollectionModelBinderUtilTest.cs

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