From 1a998040268282086549e67ae81f8e059ee885a9 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Wed, 21 Aug 2019 23:55:42 +0800 Subject: Add validators. --- Timeline.Tests/UserDetailValidatorTest.cs | 97 +++++++++++++++++++ Timeline.Tests/UsernameValidatorUnitTest.cs | 1 - Timeline/Entities/UserDetail.cs | 2 +- Timeline/Models/UserDetail.cs | 7 ++ Timeline/Models/Validation/UserDetailValidator.cs | 113 +++++++++++++++++++++- 5 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 Timeline.Tests/UserDetailValidatorTest.cs diff --git a/Timeline.Tests/UserDetailValidatorTest.cs b/Timeline.Tests/UserDetailValidatorTest.cs new file mode 100644 index 00000000..9b112946 --- /dev/null +++ b/Timeline.Tests/UserDetailValidatorTest.cs @@ -0,0 +1,97 @@ +using FluentAssertions; +using System.Collections.Generic; +using Timeline.Models.Validation; +using Xunit; + +namespace Timeline.Tests +{ + public static class UserDetailValidatorsTest + { + private static void SucceedWith(object value) where TValidator : class, IValidator, new() + { + var result = new TValidator().Validate(value, out var message); + result.Should().BeTrue(); + message.Should().Equals(ValidationConstants.SuccessMessage); + } + + private static void FailWith(object value, params string[] messageContains) where TValidator : class, IValidator, new() + { + var result = new TValidator().Validate(value, out var message); + result.Should().BeFalse(); + + foreach (var m in messageContains) + { + message.Should().ContainEquivalentOf(m); + } + } + + public class QQ + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("12345678")] + public void Success(object qq) + { + SucceedWith(qq); + } + + [Theory] + [InlineData(123, "type")] + [InlineData("123", "short")] + [InlineData("111111111111111111111111111111111111", "long")] + [InlineData("aaaaaaaa", "digit")] + public void Fail(object qq, string messageContains) + { + FailWith(qq, messageContains); + } + } + + public class EMail + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("aaa@aaa.net")] + public void Success(object email) + { + SucceedWith(email); + } + + public static IEnumerable FailTestData() + { + yield return new object[] { 123, "type" }; + yield return new object[] { new string('a', 100), "long" }; + yield return new object[] { "aaaaaaaa", "format" }; + } + + [Theory] + [MemberData(nameof(FailTestData))] + public void Fail(object email, string messageContains) + { + FailWith(email, messageContains); + } + } + + public class PhoneNumber + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("12345678910")] + public void Success(object phoneNumber) + { + SucceedWith(phoneNumber); + } + + [Theory] + [InlineData(123, "type")] + [InlineData("111111111111111111111111111111111111", "long")] + [InlineData("aaaaaaaa", "digit")] + public void Fail(object phoneNumber, string messageContains) + { + FailWith(phoneNumber, messageContains); + } + } + } +} diff --git a/Timeline.Tests/UsernameValidatorUnitTest.cs b/Timeline.Tests/UsernameValidatorUnitTest.cs index 20558d0e..6a635ba1 100644 --- a/Timeline.Tests/UsernameValidatorUnitTest.cs +++ b/Timeline.Tests/UsernameValidatorUnitTest.cs @@ -1,5 +1,4 @@ using FluentAssertions; -using System; using Timeline.Models.Validation; using Xunit; diff --git a/Timeline/Entities/UserDetail.cs b/Timeline/Entities/UserDetail.cs index ee829717..9bc6f5e5 100644 --- a/Timeline/Entities/UserDetail.cs +++ b/Timeline/Entities/UserDetail.cs @@ -12,7 +12,7 @@ namespace Timeline.Entities [Column("qq"), MaxLength(15)] public string QQ { get; set; } - [Column("email"), MaxLength(30)] + [Column("email"), MaxLength(50)] public string EMail { get; set; } [Column("phone_number"), MaxLength(15)] diff --git a/Timeline/Models/UserDetail.cs b/Timeline/Models/UserDetail.cs index 91439c6a..4af88450 100644 --- a/Timeline/Models/UserDetail.cs +++ b/Timeline/Models/UserDetail.cs @@ -1,12 +1,19 @@ using Timeline.Entities; +using Timeline.Models.Validation; namespace Timeline.Models { public class UserDetail { + [ValidateWith(typeof(UserDetailValidators.QQValidator))] public string QQ { get; set; } + + [ValidateWith(typeof(UserDetailValidators.EMailValidator))] public string EMail { get; set; } + + [ValidateWith(typeof(UserDetailValidators.PhoneNumberValidator))] public string PhoneNumber { get; set; } + public string Description { get; set; } private static string CoerceEmptyToNull(string value) diff --git a/Timeline/Models/Validation/UserDetailValidator.cs b/Timeline/Models/Validation/UserDetailValidator.cs index 5fdaec00..19c82edb 100644 --- a/Timeline/Models/Validation/UserDetailValidator.cs +++ b/Timeline/Models/Validation/UserDetailValidator.cs @@ -1,11 +1,116 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Net.Mail; namespace Timeline.Models.Validation { - public class UserDetailValidator + public abstract class OptionalStringValidator : IValidator { + public bool Validate(object value, out string message) + { + if (value == null) + { + message = ValidationConstants.SuccessMessage; + return true; + } + + if (value is string s) + { + if (s.Length == 0) + { + message = ValidationConstants.SuccessMessage; + return true; + } + return DoValidate(s, out message); + } + else + { + message = "Value is not of type string."; + return false; + } + } + + protected abstract bool DoValidate(string value, out string message); + } + + public static class UserDetailValidators + { + + public class QQValidator : OptionalStringValidator + { + protected override bool DoValidate(string value, out string message) + { + if (value.Length < 5) + { + message = "QQ is too short."; + return false; + } + + if (value.Length > 11) + { + message = "QQ is too long."; + return false; + } + + foreach (var c in value) + { + if (!char.IsDigit(c)) + { + message = "QQ must only contain digit."; + return false; + } + } + + message = ValidationConstants.SuccessMessage; + return true; + } + } + + public class EMailValidator : OptionalStringValidator + { + protected override bool DoValidate(string value, out string message) + { + if (value.Length > 50) + { + message = "E-Mail is too long."; + return false; + } + + try + { + var _ = new MailAddress(value); + } + catch (FormatException) + { + message = "The format of E-Mail is bad."; + return false; + } + message = ValidationConstants.SuccessMessage; + return true; + } + } + + public class PhoneNumberValidator : OptionalStringValidator + { + protected override bool DoValidate(string value, out string message) + { + if (value.Length > 14) + { + message = "Phone number is too long."; + return false; + } + + foreach (var c in value) + { + if (!char.IsDigit(c)) + { + message = "Phone number can only contain digit."; + return false; + } + } + + message = ValidationConstants.SuccessMessage; + return true; + } + } } } -- cgit v1.2.3