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

/test/System.Web.Http.Test/Validation/Providers/DataAnnotationsModelValidatorProviderTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 517 lines | 363 code | 92 blank | 62 comment | 0 complexity | ef326cfe863f4a77523469841ba3f3c9 MD5 | raw file
  1. using System.Collections.Generic;
  2. using System.ComponentModel.DataAnnotations;
  3. using System.Linq;
  4. using System.Web.Http.Metadata;
  5. using System.Web.Http.Metadata.Providers;
  6. using System.Web.Http.Validation.Validators;
  7. using Moq;
  8. using Xunit;
  9. using Assert = Microsoft.TestCommon.AssertEx;
  10. namespace System.Web.Http.Validation.Providers
  11. {
  12. public class DataAnnotationsModelValidatorProviderTest
  13. {
  14. private static CachedDataAnnotationsModelMetadataProvider _metadataProvider = new CachedDataAnnotationsModelMetadataProvider();
  15. private static IEnumerable<ModelValidatorProvider> _noValidatorProviders = Enumerable.Empty<ModelValidatorProvider>();
  16. // Validation attribute adapter registration
  17. private class MyValidationAttribute : ValidationAttribute
  18. {
  19. public override bool IsValid(object value)
  20. {
  21. throw new NotImplementedException();
  22. }
  23. }
  24. private class MyValidationAttributeAdapter : DataAnnotationsModelValidator
  25. {
  26. public MyValidationAttributeAdapter(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, ValidationAttribute attribute)
  27. : base(metadata, validatorProviders, attribute)
  28. {
  29. }
  30. }
  31. private class MyValidationAttributeAdapterBadCtor : ModelValidator
  32. {
  33. public MyValidationAttributeAdapterBadCtor(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders)
  34. : base(metadata, validatorProviders)
  35. {
  36. }
  37. public override IEnumerable<ModelValidationResult> Validate(object container)
  38. {
  39. throw new NotImplementedException();
  40. }
  41. }
  42. private class MyDefaultValidationAttributeAdapter : DataAnnotationsModelValidator
  43. {
  44. public MyDefaultValidationAttributeAdapter(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, ValidationAttribute attribute)
  45. : base(metadata, validatorProviders, attribute)
  46. {
  47. }
  48. }
  49. [MyValidation]
  50. private class MyValidatedClass
  51. {
  52. }
  53. [Fact]
  54. public void RegisterAdapter()
  55. {
  56. // Arrange
  57. var provider = new DataAnnotationsModelValidatorProvider();
  58. provider.AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
  59. // Act
  60. provider.RegisterAdapter(typeof(MyValidationAttribute), typeof(MyValidationAttributeAdapter));
  61. // Assert
  62. var type = provider.AttributeFactories.Keys.Single();
  63. Assert.Equal(typeof(MyValidationAttribute), type);
  64. var factory = provider.AttributeFactories.Values.Single();
  65. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(object));
  66. var attribute = new MyValidationAttribute();
  67. var validator = factory(metadata, _noValidatorProviders, attribute);
  68. Assert.IsType<MyValidationAttributeAdapter>(validator);
  69. }
  70. [Fact]
  71. public void RegisterAdapterGuardClauses()
  72. {
  73. var provider = new DataAnnotationsModelValidatorProvider();
  74. // Attribute type cannot be null
  75. Assert.ThrowsArgumentNull(
  76. () => provider.RegisterAdapter(null, typeof(MyValidationAttributeAdapter)),
  77. "attributeType");
  78. // Adapter type cannot be null
  79. Assert.ThrowsArgumentNull(
  80. () => provider.RegisterAdapter(typeof(MyValidationAttribute), null),
  81. "adapterType");
  82. // Validation attribute must derive from ValidationAttribute
  83. Assert.ThrowsArgument(
  84. () => provider.RegisterAdapter(typeof(object), typeof(MyValidationAttributeAdapter)),
  85. "attributeType",
  86. "The type Object must derive from ValidationAttribute");
  87. // Adapter must derive from ModelValidator
  88. Assert.ThrowsArgument(
  89. () => provider.RegisterAdapter(typeof(MyValidationAttribute), typeof(object)),
  90. "adapterType",
  91. "The type Object must derive from ModelValidator");
  92. // Adapter must have the expected constructor
  93. Assert.ThrowsArgument(
  94. () => provider.RegisterAdapter(typeof(MyValidationAttribute), typeof(MyValidationAttributeAdapterBadCtor)),
  95. "adapterType",
  96. "The type MyValidationAttributeAdapterBadCtor must have a public constructor which accepts three parameters of types ModelMetadata, IEnumerable<ModelValidatorProvider>, and MyValidationAttribute");
  97. }
  98. [Fact]
  99. public void RegisterAdapterFactory()
  100. {
  101. // Arrange
  102. var provider = new DataAnnotationsModelValidatorProvider();
  103. provider.AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
  104. DataAnnotationsModelValidationFactory factory = delegate { return null; };
  105. // Act
  106. provider.RegisterAdapterFactory(typeof(MyValidationAttribute), factory);
  107. // Assert
  108. var type = provider.AttributeFactories.Keys.Single();
  109. Assert.Equal(typeof(MyValidationAttribute), type);
  110. Assert.Same(factory, provider.AttributeFactories.Values.Single());
  111. }
  112. [Fact]
  113. public void RegisterAdapterFactoryGuardClauses()
  114. {
  115. var provider = new DataAnnotationsModelValidatorProvider();
  116. DataAnnotationsModelValidationFactory factory = (metadata, validatorProviders, attribute) => null;
  117. // Attribute type cannot be null
  118. Assert.ThrowsArgumentNull(
  119. () => provider.RegisterAdapterFactory(null, factory),
  120. "attributeType");
  121. // Factory cannot be null
  122. Assert.ThrowsArgumentNull(
  123. () => provider.RegisterAdapterFactory(typeof(MyValidationAttribute), null),
  124. "factory");
  125. // Validation attribute must derive from ValidationAttribute
  126. Assert.ThrowsArgument(
  127. () => provider.RegisterAdapterFactory(typeof(object), factory),
  128. "attributeType",
  129. "The type Object must derive from ValidationAttribute");
  130. }
  131. [Fact]
  132. public void RegisterDefaultAdapter()
  133. {
  134. // Arrange
  135. var provider = new DataAnnotationsModelValidatorProvider();
  136. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatedClass));
  137. provider.RegisterDefaultAdapter(typeof(MyDefaultValidationAttributeAdapter));
  138. // Act
  139. var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
  140. // Assert
  141. Assert.IsType<MyDefaultValidationAttributeAdapter>(result);
  142. }
  143. [Fact]
  144. public void RegisterDefaultAdapterGuardClauses()
  145. {
  146. var provider = new DataAnnotationsModelValidatorProvider();
  147. // Adapter type cannot be null
  148. Assert.ThrowsArgumentNull(
  149. () => provider.RegisterDefaultAdapter(null),
  150. "adapterType");
  151. // Adapter must derive from ModelValidator
  152. Assert.ThrowsArgument(
  153. () => provider.RegisterDefaultAdapter(typeof(object)),
  154. "adapterType",
  155. "The type Object must derive from ModelValidator");
  156. // Adapter must have the expected constructor
  157. Assert.ThrowsArgument(
  158. () => provider.RegisterDefaultAdapter(typeof(MyValidationAttributeAdapterBadCtor)),
  159. "adapterType",
  160. "The type MyValidationAttributeAdapterBadCtor must have a public constructor which accepts three parameters of types ModelMetadata, IEnumerable<ModelValidatorProvider>, and ValidationAttribute");
  161. }
  162. [Fact]
  163. public void RegisterDefaultAdapterFactory()
  164. {
  165. // Arrange
  166. var provider = new DataAnnotationsModelValidatorProvider();
  167. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatedClass));
  168. ModelValidator validator = new Mock<ModelValidator>(metadata, _noValidatorProviders).Object;
  169. DataAnnotationsModelValidationFactory factory = delegate { return validator; };
  170. provider.RegisterDefaultAdapterFactory(factory);
  171. // Act
  172. var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
  173. // Assert
  174. Assert.Same(validator, result);
  175. }
  176. [Fact]
  177. public void RegisterDefaultAdapterFactoryGuardClauses()
  178. {
  179. var provider = new DataAnnotationsModelValidatorProvider();
  180. // Factory cannot be null
  181. Assert.ThrowsArgumentNull(
  182. () => provider.RegisterDefaultAdapterFactory(null),
  183. "factory");
  184. }
  185. // IValidatableObject adapter registration
  186. private class MyValidatableAdapter : ModelValidator
  187. {
  188. public MyValidatableAdapter(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders)
  189. : base(metadata, validatorProviders)
  190. {
  191. }
  192. public override IEnumerable<ModelValidationResult> Validate(object container)
  193. {
  194. throw new NotImplementedException();
  195. }
  196. }
  197. private class MyValidatableAdapterBadCtor : ModelValidator
  198. {
  199. public MyValidatableAdapterBadCtor(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, int unused)
  200. : base(metadata, validatorProviders)
  201. {
  202. }
  203. public override IEnumerable<ModelValidationResult> Validate(object container)
  204. {
  205. throw new NotImplementedException();
  206. }
  207. }
  208. private class MyValidatableClass : IValidatableObject
  209. {
  210. public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
  211. {
  212. throw new NotImplementedException();
  213. }
  214. }
  215. [Fact]
  216. public void RegisterValidatableObjectAdapter()
  217. {
  218. // Arrange
  219. var provider = new DataAnnotationsModelValidatorProvider();
  220. provider.ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
  221. IValidatableObject validatable = new Mock<IValidatableObject>().Object;
  222. // Act
  223. provider.RegisterValidatableObjectAdapter(validatable.GetType(), typeof(MyValidatableAdapter));
  224. // Assert
  225. var type = provider.ValidatableFactories.Keys.Single();
  226. Assert.Equal(validatable.GetType(), type);
  227. var factory = provider.ValidatableFactories.Values.Single();
  228. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(object));
  229. var validator = factory(metadata, _noValidatorProviders);
  230. Assert.IsType<MyValidatableAdapter>(validator);
  231. }
  232. [Fact]
  233. public void RegisterValidatableObjectAdapterGuardClauses()
  234. {
  235. var provider = new DataAnnotationsModelValidatorProvider();
  236. // Attribute type cannot be null
  237. Assert.ThrowsArgumentNull(
  238. () => provider.RegisterValidatableObjectAdapter(null, typeof(MyValidatableAdapter)),
  239. "modelType");
  240. // Adapter type cannot be null
  241. Assert.ThrowsArgumentNull(
  242. () => provider.RegisterValidatableObjectAdapter(typeof(MyValidatableClass), null),
  243. "adapterType");
  244. // Validation attribute must derive from ValidationAttribute
  245. Assert.ThrowsArgument(
  246. () => provider.RegisterValidatableObjectAdapter(typeof(object), typeof(MyValidatableAdapter)),
  247. "modelType",
  248. "The type Object must derive from IValidatableObject.");
  249. // Adapter must derive from ModelValidator
  250. Assert.ThrowsArgument(
  251. () => provider.RegisterValidatableObjectAdapter(typeof(MyValidatableClass), typeof(object)),
  252. "adapterType",
  253. "The type Object must derive from ModelValidator");
  254. // Adapter must have the expected constructor
  255. Assert.ThrowsArgument(
  256. () => provider.RegisterValidatableObjectAdapter(typeof(MyValidatableClass), typeof(MyValidatableAdapterBadCtor)),
  257. "adapterType",
  258. "The type MyValidatableAdapterBadCtor must have a public constructor which accepts two parameters of types ModelMetadata and IEnumerable<ModelValidatorProvider>");
  259. }
  260. [Fact]
  261. public void RegisterValidatableObjectAdapterFactory()
  262. {
  263. // Arrange
  264. var provider = new DataAnnotationsModelValidatorProvider();
  265. provider.ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
  266. DataAnnotationsValidatableObjectAdapterFactory factory = delegate { return null; };
  267. // Act
  268. provider.RegisterValidatableObjectAdapterFactory(typeof(MyValidatableClass), factory);
  269. // Assert
  270. var type = provider.ValidatableFactories.Keys.Single();
  271. Assert.Equal(typeof(MyValidatableClass), type);
  272. Assert.Same(factory, provider.ValidatableFactories.Values.Single());
  273. }
  274. [Fact]
  275. public void RegisterValidatableObjectAdapterFactoryGuardClauses()
  276. {
  277. var provider = new DataAnnotationsModelValidatorProvider();
  278. DataAnnotationsValidatableObjectAdapterFactory factory = (metadata, context) => null;
  279. // Attribute type cannot be null
  280. Assert.ThrowsArgumentNull(
  281. () => provider.RegisterValidatableObjectAdapterFactory(null, factory),
  282. "modelType");
  283. // Factory cannot be null
  284. Assert.ThrowsArgumentNull(
  285. () => provider.RegisterValidatableObjectAdapterFactory(typeof(MyValidatableClass), null),
  286. "factory");
  287. // Validation attribute must derive from ValidationAttribute
  288. Assert.ThrowsArgument(
  289. () => provider.RegisterValidatableObjectAdapterFactory(typeof(object), factory),
  290. "modelType",
  291. "The type Object must derive from IValidatableObject");
  292. }
  293. [Fact]
  294. public void RegisterDefaultValidatableObjectAdapter()
  295. {
  296. // Arrange
  297. var provider = new DataAnnotationsModelValidatorProvider();
  298. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatableClass));
  299. provider.RegisterDefaultValidatableObjectAdapter(typeof(MyValidatableAdapter));
  300. // Act
  301. var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
  302. // Assert
  303. Assert.IsType<MyValidatableAdapter>(result);
  304. }
  305. [Fact]
  306. public void RegisterDefaultValidatableObjectAdapterGuardClauses()
  307. {
  308. var provider = new DataAnnotationsModelValidatorProvider();
  309. // Adapter type cannot be null
  310. Assert.ThrowsArgumentNull(
  311. () => provider.RegisterDefaultValidatableObjectAdapter(null),
  312. "adapterType");
  313. // Adapter must derive from ModelValidator
  314. Assert.ThrowsArgument(
  315. () => provider.RegisterDefaultValidatableObjectAdapter(typeof(object)),
  316. "adapterType",
  317. "The type Object must derive from ModelValidator");
  318. // Adapter must have the expected constructor
  319. Assert.ThrowsArgument(
  320. () => provider.RegisterDefaultValidatableObjectAdapter(typeof(MyValidatableAdapterBadCtor)),
  321. "adapterType",
  322. "The type MyValidatableAdapterBadCtor must have a public constructor which accepts two parameters of types ModelMetadata and IEnumerable<ModelValidatorProvider>");
  323. }
  324. [Fact]
  325. public void RegisterDefaultValidatableObjectAdapterFactory()
  326. {
  327. // Arrange
  328. var provider = new DataAnnotationsModelValidatorProvider();
  329. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatableClass));
  330. ModelValidator validator = new Mock<ModelValidator>(metadata, _noValidatorProviders).Object;
  331. DataAnnotationsValidatableObjectAdapterFactory factory = delegate { return validator; };
  332. provider.RegisterDefaultValidatableObjectAdapterFactory(factory);
  333. // Act
  334. var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
  335. // Assert
  336. Assert.Same(validator, result);
  337. }
  338. [Fact]
  339. public void RegisterDefaultValidatableObjectAdapterFactoryGuardClauses()
  340. {
  341. var provider = new DataAnnotationsModelValidatorProvider();
  342. // Factory cannot be null
  343. Assert.ThrowsArgumentNull(
  344. () => provider.RegisterDefaultValidatableObjectAdapterFactory(null),
  345. "factory");
  346. }
  347. // Default adapter factory for unknown attribute type
  348. [Fact]
  349. public void UnknownValidationAttributeGetsDefaultAdapter()
  350. {
  351. // Arrange
  352. var provider = new DataAnnotationsModelValidatorProvider();
  353. var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(DummyClassWithDummyValidationAttribute));
  354. // Act
  355. IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, _noValidatorProviders);
  356. // Assert
  357. var validator = validators.Single();
  358. Assert.IsType<DataAnnotationsModelValidator>(validator);
  359. }
  360. private class DummyValidationAttribute : ValidationAttribute
  361. {
  362. }
  363. [DummyValidation]
  364. private class DummyClassWithDummyValidationAttribute
  365. {
  366. }
  367. // Default IValidatableObject adapter factory
  368. [Fact]
  369. public void IValidatableObjectGetsAValidator()
  370. {
  371. // Arrange
  372. var provider = new DataAnnotationsModelValidatorProvider();
  373. var mockValidatable = new Mock<IValidatableObject>();
  374. var metadata = _metadataProvider.GetMetadataForType(() => null, mockValidatable.Object.GetType());
  375. // Act
  376. IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, _noValidatorProviders);
  377. // Assert
  378. Assert.Single(validators);
  379. }
  380. // Integration with metadata system
  381. [Fact]
  382. public void DoesNotReadPropertyValue()
  383. {
  384. // Arrange
  385. var provider = new DataAnnotationsModelValidatorProvider();
  386. var model = new ObservableModel();
  387. ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => model.TheProperty, typeof(ObservableModel), "TheProperty");
  388. // Act
  389. ModelValidator[] validators = provider.GetValidators(metadata, _noValidatorProviders).ToArray();
  390. ModelValidationResult[] results = validators.SelectMany(o => o.Validate(model)).ToArray();
  391. // Assert
  392. Assert.Empty(validators);
  393. Assert.False(model.PropertyWasRead());
  394. }
  395. private class ObservableModel
  396. {
  397. private bool _propertyWasRead;
  398. public string TheProperty
  399. {
  400. get
  401. {
  402. _propertyWasRead = true;
  403. return "Hello";
  404. }
  405. }
  406. public bool PropertyWasRead()
  407. {
  408. return _propertyWasRead;
  409. }
  410. }
  411. private class BaseModel
  412. {
  413. public virtual string MyProperty { get; set; }
  414. }
  415. private class DerivedModel : BaseModel
  416. {
  417. [StringLength(10)]
  418. public override string MyProperty
  419. {
  420. get { return base.MyProperty; }
  421. set { base.MyProperty = value; }
  422. }
  423. }
  424. }
  425. }