/test/System.Web.Http.Test/Metadata/Providers/AssociatedMetadataProviderTest.cs

https://bitbucket.org/mdavid/aspnetwebstack · C# · 309 lines · 219 code · 53 blank · 37 comment · 10 complexity · 147a06f71414ff20beb2ea93027fbeed MD5 · raw file

  1. using System.Collections.Generic;
  2. using System.ComponentModel;
  3. using System.ComponentModel.DataAnnotations;
  4. using System.Linq;
  5. using Microsoft.TestCommon;
  6. using Xunit;
  7. using Assert = Microsoft.TestCommon.AssertEx;
  8. namespace System.Web.Http.Metadata.Providers
  9. {
  10. public class AssociatedMetadataProviderTest : MarshalByRefObject
  11. {
  12. // GetMetadataForProperties
  13. [Fact]
  14. public void GetMetadataForPropertiesNullContainerTypeThrows()
  15. {
  16. // Arrange
  17. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  18. // Act & Assert
  19. Assert.ThrowsArgumentNull(
  20. () => provider.GetMetadataForProperties(new Object(), containerType: null),
  21. "containerType");
  22. }
  23. [Fact]
  24. public void GetMetadataForPropertiesCreatesMetadataForAllPropertiesOnModelWithPropertyValues()
  25. {
  26. // Arrange
  27. PropertyModel model = new PropertyModel { LocalAttributes = 42, MetadataAttributes = "hello", MixedAttributes = 21.12 };
  28. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  29. // Act
  30. provider.GetMetadataForProperties(model, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
  31. // Assert
  32. CreateMetadataParams local =
  33. provider.CreateMetadataLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
  34. m.PropertyName == "LocalAttributes");
  35. Assert.Equal(typeof(int), local.ModelType);
  36. Assert.Equal(42, local.Model);
  37. Assert.True(local.Attributes.Any(a => a is RequiredAttribute));
  38. CreateMetadataParams metadata =
  39. provider.CreateMetadataLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
  40. m.PropertyName == "MetadataAttributes");
  41. Assert.Equal(typeof(string), metadata.ModelType);
  42. Assert.Equal("hello", metadata.Model);
  43. Assert.True(metadata.Attributes.Any(a => a is RangeAttribute));
  44. CreateMetadataParams mixed =
  45. provider.CreateMetadataLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
  46. m.PropertyName == "MixedAttributes");
  47. Assert.Equal(typeof(double), mixed.ModelType);
  48. Assert.Equal(21.12, mixed.Model);
  49. Assert.True(mixed.Attributes.Any(a => a is RequiredAttribute));
  50. Assert.True(mixed.Attributes.Any(a => a is RangeAttribute));
  51. }
  52. [Fact]
  53. public void GetMetadataForPropertyWithNullContainerReturnsMetadataWithNullValuesForProperties()
  54. {
  55. // Arrange
  56. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  57. // Act
  58. provider.GetMetadataForProperties(null, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
  59. // Assert
  60. Assert.True(provider.CreateMetadataLog.Any());
  61. foreach (var parms in provider.CreateMetadataLog)
  62. {
  63. Assert.Null(parms.Model);
  64. }
  65. }
  66. // GetMetadataForProperty
  67. [Fact]
  68. public void GetMetadataForPropertyNullContainerTypeThrows()
  69. {
  70. // Arrange
  71. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  72. // Act & Assert
  73. Assert.ThrowsArgumentNull(
  74. () => provider.GetMetadataForProperty(modelAccessor: null, containerType: null, propertyName: "propertyName"),
  75. "containerType");
  76. }
  77. [Fact]
  78. public void GetMetadataForPropertyNullOrEmptyPropertyNameThrows()
  79. {
  80. // Arrange
  81. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  82. // Act & Assert
  83. Assert.ThrowsArgument(
  84. () => provider.GetMetadataForProperty(modelAccessor: null, containerType: typeof(object), propertyName: null),
  85. "propertyName",
  86. "The argument 'propertyName' is null or empty.");
  87. Assert.ThrowsArgument(
  88. () => provider.GetMetadataForProperty(modelAccessor: null, containerType: typeof(object), propertyName: String.Empty),
  89. "propertyName",
  90. "The argument 'propertyName' is null or empty.");
  91. }
  92. [Fact]
  93. public void GetMetadataForPropertyInvalidPropertyNameThrows()
  94. {
  95. // Arrange
  96. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  97. // Act & Assert
  98. Assert.ThrowsArgument(
  99. () => provider.GetMetadataForProperty(modelAccessor: null, containerType: typeof(object), propertyName: "BadPropertyName"),
  100. "propertyName",
  101. "The property System.Object.BadPropertyName could not be found.");
  102. }
  103. [Fact]
  104. public void GetMetadataForPropertyWithLocalAttributes()
  105. {
  106. // Arrange
  107. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  108. ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(int), "LocalAttributes");
  109. provider.CreateMetadataReturnValue = metadata;
  110. // Act
  111. ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
  112. // Assert
  113. Assert.Same(metadata, result);
  114. Assert.True(provider.CreateMetadataLog.Single().Attributes.Any(a => a is RequiredAttribute));
  115. }
  116. [Fact]
  117. public void GetMetadataForPropertyWithMetadataAttributes()
  118. {
  119. // Arrange
  120. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  121. ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(string), "MetadataAttributes");
  122. provider.CreateMetadataReturnValue = metadata;
  123. // Act
  124. ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
  125. // Assert
  126. Assert.Same(metadata, result);
  127. CreateMetadataParams parms = provider.CreateMetadataLog.Single(p => p.PropertyName == "MetadataAttributes");
  128. Assert.True(parms.Attributes.Any(a => a is RangeAttribute));
  129. }
  130. [Fact]
  131. public void GetMetadataForPropertyWithMixedAttributes()
  132. {
  133. // Arrange
  134. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  135. ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(double), "MixedAttributes");
  136. provider.CreateMetadataReturnValue = metadata;
  137. // Act
  138. ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
  139. // Assert
  140. Assert.Same(metadata, result);
  141. CreateMetadataParams parms = provider.CreateMetadataLog.Single(p => p.PropertyName == "MixedAttributes");
  142. Assert.True(parms.Attributes.Any(a => a is RequiredAttribute));
  143. Assert.True(parms.Attributes.Any(a => a is RangeAttribute));
  144. }
  145. // GetMetadataForType
  146. [Fact]
  147. public void GetMetadataForTypeNullModelTypeThrows()
  148. {
  149. // Arrange
  150. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  151. // Act & Assert
  152. Assert.ThrowsArgumentNull(
  153. () => provider.GetMetadataForType(() => new Object(), modelType: null),
  154. "modelType");
  155. }
  156. [Fact]
  157. public void GetMetadataForTypeIncludesAttributesOnType()
  158. {
  159. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  160. ModelMetadata metadata = new ModelMetadata(provider, null, null, typeof(TypeModel), null);
  161. provider.CreateMetadataReturnValue = metadata;
  162. // Act
  163. ModelMetadata result = provider.GetMetadataForType(null, typeof(TypeModel));
  164. // Assert
  165. Assert.Same(metadata, result);
  166. CreateMetadataParams parms = provider.CreateMetadataLog.Single(p => p.ModelType == typeof(TypeModel));
  167. Assert.True(parms.Attributes.Any(a => a is ReadOnlyAttribute));
  168. }
  169. [AdditionalMetadata("ClassName", "ClassValue")]
  170. class ClassWithAdditionalMetadata
  171. {
  172. [AdditionalMetadata("PropertyName", "PropertyValue")]
  173. public int MyProperty { get; set; }
  174. }
  175. [Fact]
  176. public void MetadataAwareAttributeCanModifyTypeMetadata()
  177. {
  178. // Arrange
  179. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  180. provider.CreateMetadataReturnValue = new ModelMetadata(provider, null, null, typeof(ClassWithAdditionalMetadata), null);
  181. // Act
  182. ModelMetadata metadata = provider.GetMetadataForType(null, typeof(ClassWithAdditionalMetadata));
  183. // Assert
  184. var kvp = metadata.AdditionalValues.Single();
  185. Assert.Equal("ClassName", kvp.Key);
  186. Assert.Equal("ClassValue", kvp.Value);
  187. }
  188. [Fact]
  189. public void MetadataAwareAttributeCanModifyPropertyMetadata()
  190. {
  191. // Arrange
  192. TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
  193. provider.CreateMetadataReturnValue = new ModelMetadata(provider, typeof(ClassWithAdditionalMetadata), null, typeof(int), "MyProperty");
  194. // Act
  195. ModelMetadata metadata = provider.GetMetadataForProperty(null, typeof(ClassWithAdditionalMetadata), "MyProperty");
  196. // Assert
  197. var kvp = metadata.AdditionalValues.Single();
  198. Assert.Equal("PropertyName", kvp.Key);
  199. Assert.Equal("PropertyValue", kvp.Value);
  200. }
  201. // Helpers
  202. [MetadataType(typeof(Metadata))]
  203. private class PropertyModel
  204. {
  205. [Required]
  206. public int LocalAttributes { get; set; }
  207. public string MetadataAttributes { get; set; }
  208. [Required]
  209. public double MixedAttributes { get; set; }
  210. private class Metadata
  211. {
  212. [Range(10, 100)]
  213. public object MetadataAttributes { get; set; }
  214. [Range(10, 100)]
  215. public object MixedAttributes { get; set; }
  216. }
  217. }
  218. private class ModelWithReadOnlyProperty
  219. {
  220. public int ReadOnlyProperty { get; private set; }
  221. }
  222. [ReadOnly(true)]
  223. private class TypeModel
  224. {
  225. }
  226. class TestableAssociatedMetadataProvider : AssociatedMetadataProvider
  227. {
  228. public List<CreateMetadataParams> CreateMetadataLog = new List<CreateMetadataParams>();
  229. public ModelMetadata CreateMetadataReturnValue = null;
  230. protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
  231. Func<object> modelAccessor, Type modelType,
  232. string propertyName)
  233. {
  234. CreateMetadataLog.Add(new CreateMetadataParams
  235. {
  236. Attributes = attributes,
  237. ContainerType = containerType,
  238. Model = modelAccessor == null ? null : modelAccessor(),
  239. ModelType = modelType,
  240. PropertyName = propertyName
  241. });
  242. return CreateMetadataReturnValue;
  243. }
  244. }
  245. class CreateMetadataParams
  246. {
  247. public IEnumerable<Attribute> Attributes { get; set; }
  248. public Type ContainerType { get; set; }
  249. public object Model { get; set; }
  250. public Type ModelType { get; set; }
  251. public string PropertyName { get; set; }
  252. }
  253. }
  254. [RunWith(typeof(PartialTrustRunner))]
  255. public class PartialTrustAssociatedMetadataProviderTest : AssociatedMetadataProviderTest { }
  256. }