From 294807481dd42dc3c660e29630b36462e7bcfaaf Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 27 Oct 2019 22:52:21 +0800 Subject: Add error code tests. --- .gitignore | 4 + Timeline.Tests/ErrorCodeTest.cs | 52 +++++++++ Timeline.Tests/IntegratedTests/UserAvatarTest.cs | 9 +- Timeline/ErrorCodes.cs | 19 ++-- Timeline/Filters/ContentHeaderAttributes.cs | 52 --------- Timeline/Filters/Header.cs | 99 +++++++++++++++++ Timeline/Models/Http/Common.cs | 17 +-- Timeline/Resources/Filters.Designer.cs | 90 +++++++++++++++ Timeline/Resources/Filters.resx | 129 ++++++++++++++++++++++ Timeline/Resources/Filters.zh.resx | 129 ++++++++++++++++++++++ Timeline/Resources/Models/Http/Common.Designer.cs | 31 +----- Timeline/Resources/Models/Http/Common.resx | 11 +- Timeline/Resources/Models/Http/Common.zh.resx | 13 +-- Timeline/Timeline.csproj | 17 ++- 14 files changed, 535 insertions(+), 137 deletions(-) create mode 100644 Timeline.Tests/ErrorCodeTest.cs delete mode 100644 Timeline/Filters/ContentHeaderAttributes.cs create mode 100644 Timeline/Filters/Header.cs create mode 100644 Timeline/Resources/Filters.Designer.cs create mode 100644 Timeline/Resources/Filters.resx create mode 100644 Timeline/Resources/Filters.zh.resx diff --git a/.gitignore b/.gitignore index 41ffa34d..10d8a462 100644 --- a/.gitignore +++ b/.gitignore @@ -229,3 +229,7 @@ _Pvt_Extensions # FAKE - F# Make .fake/ + + +# My draft files. +*.draft diff --git a/Timeline.Tests/ErrorCodeTest.cs b/Timeline.Tests/ErrorCodeTest.cs new file mode 100644 index 00000000..78a58131 --- /dev/null +++ b/Timeline.Tests/ErrorCodeTest.cs @@ -0,0 +1,52 @@ +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Xunit; +using Xunit.Abstractions; + +namespace Timeline.Tests +{ + public class ErrorCodeTest + { + private readonly ITestOutputHelper _output; + + public ErrorCodeTest(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void ShouldWork() + { + var errorCodes = new Dictionary(); + + void RecursiveCheckErrorCode(Type type) + { + foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) + .Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(int))) + { + var name = type.FullName + "." + field.Name; + var value = (int)field.GetRawConstantValue(); + _output.WriteLine($"Find error code {name} , value is {value}."); + + value.Should().BeInRange(1000_0000, 9999_9999, "Error code should have exactly 8 digits."); + + errorCodes.Should().NotContainKey(value, + "identical error codes are found and conflict paths are {0} and {1}", + name, errorCodes.GetValueOrDefault(value)); + + errorCodes.Add(value, name); + } + + foreach (var nestedType in type.GetNestedTypes()) + { + RecursiveCheckErrorCode(nestedType); + } + } + + RecursiveCheckErrorCode(typeof(ErrorCodes)); + } + } +} diff --git a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs index ce389046..ad2e11df 100644 --- a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs @@ -13,7 +13,6 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; -using Timeline.Controllers; using Timeline.Services; using Timeline.Tests.Helpers; using Timeline.Tests.Helpers.Authentication; @@ -95,7 +94,7 @@ namespace Timeline.Tests.IntegratedTests request.Headers.TryAddWithoutValidation("If-None-Match", "\"dsdfd"); var res = await client.SendAsync(request); res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Common.Header.BadFormat_IfNonMatch); + .And.Should().HaveCommonBody().Which.Code.Should().Be(Header.IfNonMatch.BadFormat); } { @@ -125,7 +124,7 @@ namespace Timeline.Tests.IntegratedTests content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); var res = await client.PutAsync("users/user/avatar", content); res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Common.Header.Missing_ContentLength); + .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Filter.Header.ContentLength.Missing); ; } { @@ -133,7 +132,7 @@ namespace Timeline.Tests.IntegratedTests content.Headers.ContentLength = 1; var res = await client.PutAsync("users/user/avatar", content); res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Common.Header.Missing_ContentType); + .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Filter.Header.ContentType.Missing); } { @@ -142,7 +141,7 @@ namespace Timeline.Tests.IntegratedTests content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); var res = await client.PutAsync("users/user/avatar", content); res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Common.Header.Zero_ContentLength); + .And.Should().HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Http.Filter.Header.ContentLength.Zero); } { diff --git a/Timeline/ErrorCodes.cs b/Timeline/ErrorCodes.cs index 5e7f003a..c246953b 100644 --- a/Timeline/ErrorCodes.cs +++ b/Timeline/ErrorCodes.cs @@ -15,22 +15,21 @@ { public const int InvalidModel = 10000000; - public static class Header // cc = 01 + public static class Header // cc = 0x { - public const int Missing_ContentType = 10000101; // dd = 01 - public const int Missing_ContentLength = 10000102; // dd = 02 - public const int Zero_ContentLength = 10000103; // dd = 03 - public const int BadFormat_IfNonMatch = 10000104; // dd = 04 + public static class IfNonMatch // cc = 01 + { + public const int BadFormat = 10000101; + } } - public static class Content // cc = 02 + public static class Content // cc = 11 { - public const int TooBig = 1000201; - public const int UnmatchedLength_Smaller = 10030202; - public const int UnmatchedLength_Bigger = 10030203; + public const int TooBig = 10001101; + public const int UnmatchedLength_Smaller = 10001102; + public const int UnmatchedLength_Bigger = 10001103; } } } - } } diff --git a/Timeline/Filters/ContentHeaderAttributes.cs b/Timeline/Filters/ContentHeaderAttributes.cs deleted file mode 100644 index 99bd1540..00000000 --- a/Timeline/Filters/ContentHeaderAttributes.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Localization; -using Timeline.Models.Http; - -namespace Timeline.Filters -{ - public class RequireContentTypeAttribute : ActionFilterAttribute - { - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods")] - public override void OnActionExecuting(ActionExecutingContext context) - { - if (context.HttpContext.Request.ContentType == null) - { - context.Result = new BadRequestObjectResult(HeaderErrorResponse.MissingContentType()); - } - } - } - - public class RequireContentLengthAttribute : ActionFilterAttribute - { - public RequireContentLengthAttribute() - : this(true) - { - - } - - public RequireContentLengthAttribute(bool requireNonZero) - { - RequireNonZero = requireNonZero; - } - - public bool RequireNonZero { get; set; } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods")] - public override void OnActionExecuting(ActionExecutingContext context) - { - if (context.HttpContext.Request.ContentLength == null) - { - context.Result = new BadRequestObjectResult(HeaderErrorResponse.MissingContentLength()); - return; - } - - if (RequireNonZero && context.HttpContext.Request.ContentLength.Value == 0) - { - context.Result = new BadRequestObjectResult(HeaderErrorResponse.ZeroContentLength()); - return; - } - } - } -} diff --git a/Timeline/Filters/Header.cs b/Timeline/Filters/Header.cs new file mode 100644 index 00000000..f5fb16aa --- /dev/null +++ b/Timeline/Filters/Header.cs @@ -0,0 +1,99 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Timeline.Models.Http; +using static Timeline.Resources.Filters; + +namespace Timeline +{ + public static partial class ErrorCodes + { + public static partial class Http + { + public static partial class Filter // bxx = 1xx + { + public static partial class Header // bbb = 100 + { + public static class ContentType // cc = 01 + { + public const int Missing = 11000101; // dd = 01 + } + + public static class ContentLength // cc = 02 + { + public const int Missing = 11000201; // dd = 01 + public const int Zero = 11000202; // dd = 02 + } + } + } + + } + } +} + +namespace Timeline.Filters +{ + public class RequireContentTypeAttribute : ActionFilterAttribute + { + internal static CommonResponse CreateResponse() + { + return new CommonResponse( + ErrorCodes.Http.Filter.Header.ContentType.Missing, + MessageHeaderContentTypeMissing); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods")] + public override void OnActionExecuting(ActionExecutingContext context) + { + if (context.HttpContext.Request.ContentType == null) + { + context.Result = new BadRequestObjectResult(CreateResponse()); + } + } + } + + public class RequireContentLengthAttribute : ActionFilterAttribute + { + internal static CommonResponse CreateMissingResponse() + { + return new CommonResponse( + ErrorCodes.Http.Filter.Header.ContentLength.Missing, + MessageHeaderContentLengthMissing); + } + + internal static CommonResponse CreateZeroResponse() + { + return new CommonResponse( + ErrorCodes.Http.Filter.Header.ContentLength.Zero, + MessageHeaderContentLengthZero); + } + + public RequireContentLengthAttribute() + : this(true) + { + + } + + public RequireContentLengthAttribute(bool requireNonZero) + { + RequireNonZero = requireNonZero; + } + + public bool RequireNonZero { get; set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods")] + public override void OnActionExecuting(ActionExecutingContext context) + { + if (context.HttpContext.Request.ContentLength == null) + { + context.Result = new BadRequestObjectResult(CreateMissingResponse()); + return; + } + + if (RequireNonZero && context.HttpContext.Request.ContentLength.Value == 0) + { + context.Result = new BadRequestObjectResult(CreateZeroResponse()); + return; + } + } + } +} diff --git a/Timeline/Models/Http/Common.cs b/Timeline/Models/Http/Common.cs index 2c9ee9e7..2a88b3a3 100644 --- a/Timeline/Models/Http/Common.cs +++ b/Timeline/Models/Http/Common.cs @@ -27,24 +27,9 @@ namespace Timeline.Models.Http internal static class HeaderErrorResponse { - internal static CommonResponse MissingContentType() - { - return new CommonResponse(ErrorCodes.Http.Common.Header.Missing_ContentType, MessageHeaderMissingContentType); - } - - internal static CommonResponse MissingContentLength() - { - return new CommonResponse(ErrorCodes.Http.Common.Header.Missing_ContentLength, MessageHeaderMissingContentLength); - } - - internal static CommonResponse ZeroContentLength() - { - return new CommonResponse(ErrorCodes.Http.Common.Header.Zero_ContentLength, MessageHeaderZeroContentLength); - } - internal static CommonResponse BadIfNonMatch() { - return new CommonResponse(ErrorCodes.Http.Common.Header.BadFormat_IfNonMatch, MessageHeaderBadIfNonMatch); + return new CommonResponse(ErrorCodes.Http.Common.Header.IfNonMatch.BadFormat, MessageHeaderIfNonMatchBad); } } diff --git a/Timeline/Resources/Filters.Designer.cs b/Timeline/Resources/Filters.Designer.cs new file mode 100644 index 00000000..ae3565f7 --- /dev/null +++ b/Timeline/Resources/Filters.Designer.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Timeline.Resources { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Filters { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Filters() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Resources.Filters", typeof(Filters).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Header Content-Length is missing or of bad format.. + /// + internal static string MessageHeaderContentLengthMissing { + get { + return ResourceManager.GetString("MessageHeaderContentLengthMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Header Content-Length must not be 0.. + /// + internal static string MessageHeaderContentLengthZero { + get { + return ResourceManager.GetString("MessageHeaderContentLengthZero", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Header Content-Type is required.. + /// + internal static string MessageHeaderContentTypeMissing { + get { + return ResourceManager.GetString("MessageHeaderContentTypeMissing", resourceCulture); + } + } + } +} diff --git a/Timeline/Resources/Filters.resx b/Timeline/Resources/Filters.resx new file mode 100644 index 00000000..d2b7e68a --- /dev/null +++ b/Timeline/Resources/Filters.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Header Content-Length is missing or of bad format. + + + Header Content-Length must not be 0. + + + Header Content-Type is required. + + \ No newline at end of file diff --git a/Timeline/Resources/Filters.zh.resx b/Timeline/Resources/Filters.zh.resx new file mode 100644 index 00000000..90e97e49 --- /dev/null +++ b/Timeline/Resources/Filters.zh.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 请求头Content-Length缺失或者格式不对。 + + + 请求头Content-Length不能为0。 + + + 缺少必需的请求头Content-Type。 + + \ No newline at end of file diff --git a/Timeline/Resources/Models/Http/Common.Designer.cs b/Timeline/Resources/Models/Http/Common.Designer.cs index 2df1e447..4eebd2bc 100644 --- a/Timeline/Resources/Models/Http/Common.Designer.cs +++ b/Timeline/Resources/Models/Http/Common.Designer.cs @@ -108,36 +108,9 @@ namespace Timeline.Resources.Models.Http { /// /// Looks up a localized string similar to Header If-Non-Match is of bad format.. /// - internal static string MessageHeaderBadIfNonMatch { + internal static string MessageHeaderIfNonMatchBad { get { - return ResourceManager.GetString("MessageHeaderBadIfNonMatch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Header Content-Length is missing or of bad format.. - /// - internal static string MessageHeaderMissingContentLength { - get { - return ResourceManager.GetString("MessageHeaderMissingContentLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Header Content-Type is required.. - /// - internal static string MessageHeaderMissingContentType { - get { - return ResourceManager.GetString("MessageHeaderMissingContentType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Header Content-Length must not be 0.. - /// - internal static string MessageHeaderZeroContentLength { - get { - return ResourceManager.GetString("MessageHeaderZeroContentLength", resourceCulture); + return ResourceManager.GetString("MessageHeaderIfNonMatchBad", resourceCulture); } } diff --git a/Timeline/Resources/Models/Http/Common.resx b/Timeline/Resources/Models/Http/Common.resx index 433c341c..540c6c58 100644 --- a/Timeline/Resources/Models/Http/Common.resx +++ b/Timeline/Resources/Models/Http/Common.resx @@ -132,18 +132,9 @@ The item does not exist, so nothing is changed. - + Header If-Non-Match is of bad format. - - Header Content-Length is missing or of bad format. - - - Header Content-Type is required. - - - Header Content-Length must not be 0. - A new item is created. diff --git a/Timeline/Resources/Models/Http/Common.zh.resx b/Timeline/Resources/Models/Http/Common.zh.resx index cbdd6fb9..467916a2 100644 --- a/Timeline/Resources/Models/Http/Common.zh.resx +++ b/Timeline/Resources/Models/Http/Common.zh.resx @@ -132,17 +132,8 @@ 要删除的项目不存在,什么都没有修改。 - - 头If-Non-Match格式不对。 - - - 头Content-Length缺失或者格式不对。 - - - 缺少必需的头Content-Type。 - - - 头Content-Length不能为0。 + + 请求头If-Non-Match格式不对。 创建了一个新项目。 diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj index 0260d725..bd195475 100644 --- a/Timeline/Timeline.csproj +++ b/Timeline/Timeline.csproj @@ -64,6 +64,11 @@ True UserController.resx + + True + True + Filters.resx + True True @@ -119,10 +124,6 @@ ResXFileCodeGenerator TokenController.Designer.cs - - Designer - - ResXFileCodeGenerator UserAvatarController.Designer.cs @@ -131,6 +132,10 @@ ResXFileCodeGenerator UserController.Designer.cs + + ResXFileCodeGenerator + Filters.Designer.cs + ResXFileCodeGenerator Common.Designer.cs @@ -160,4 +165,8 @@ UserService.Designer.cs + + + + -- cgit v1.2.3