From 022ef5bc71ccc257a2bf7ac2b290ad9808e2bf6c Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 21 Feb 2022 18:27:07 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E5=BC=95=E5=85=A5=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=88=86=E6=9E=90=E5=99=A8=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SKIT.FlurlHttpClient.Wechat.sln | 22 +- test/NuGet.config | 6 + ...lurlHttpClient.Wechat.Ads.UnitTests.csproj | 6 +- .../TestCase_CodeReview.cs | 28 + .../TestCase_CodeReviewAnalyzer.cs | 57 -- .../TestConfigs.cs | 8 +- .../appsettings.json | 4 +- ...lurlHttpClient.Wechat.Api.UnitTests.csproj | 6 +- .../TestCase_CodeReview.cs | 26 + .../TestCase_CodeReviewAnalyzer.cs | 69 -- .../TestConfigs.cs | 8 +- .../appsettings.json | 4 +- ...lHttpClient.Wechat.OpenAI.UnitTests.csproj | 6 +- .../TestCase_CodeReview.cs | 28 + .../TestCase_CodeReviewAnalyzer.cs | 69 -- .../TestConfigs.cs | 8 +- .../appsettings.json | 4 +- ...ttpClient.Wechat.TenpayV2.UnitTests.csproj | 6 +- .../TestCase_CodeReview.cs | 28 + .../TestCase_CodeReviewAnalyzer.cs | 69 -- .../TestConfigs.cs | 8 +- .../appsettings.json | 4 +- ...ttpClient.Wechat.TenpayV3.UnitTests.csproj | 6 +- .../TestCase_CodeReview.cs | 28 + .../TestCase_CodeReviewAnalyzer.cs | 69 -- .../TestConfigs.cs | 8 +- .../appsettings.json | 4 +- .../CodeStyleUtil.cs | 690 ------------------ ...IT.FlurlHttpClient.Wechat.TestTools.csproj | 13 - .../TestIOUtil.cs | 27 - .../TestReflectionUtil.cs | 179 ----- ...urlHttpClient.Wechat.Work.UnitTests.csproj | 6 +- .../TestCase_CodeReview.cs | 28 + .../TestCase_CodeReviewAnalyzer.cs | 68 -- .../TestConfigs.cs | 8 +- .../appsettings.json | 4 +- 36 files changed, 232 insertions(+), 1380 deletions(-) create mode 100644 test/NuGet.config create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReview.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReviewAnalyzer.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReview.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReviewAnalyzer.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReview.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReviewAnalyzer.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReview.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReviewAnalyzer.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReview.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReviewAnalyzer.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.TestTools/CodeStyleUtil.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.TestTools/SKIT.FlurlHttpClient.Wechat.TestTools.csproj delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.TestTools/TestIOUtil.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.TestTools/TestReflectionUtil.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReview.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs diff --git a/SKIT.FlurlHttpClient.Wechat.sln b/SKIT.FlurlHttpClient.Wechat.sln index 9a1259d8..be88cb6f 100644 --- a/SKIT.FlurlHttpClient.Wechat.sln +++ b/SKIT.FlurlHttpClient.Wechat.sln @@ -24,13 +24,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SKIT.FlurlHttpClient.Wechat EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C95AF531-CF44-44AA-AC90-F4DF9F941674}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{4C48D9D5-1D7F-4616-A05D-256555C310FC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SKIT.FlurlHttpClient.Wechat.TestTools", "test\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj", "{A8453835-4EE8-4FD4-9766-9C0DCB54CDB3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SKIT.FlurlHttpClient.Wechat.Api.UnitTests", "test\SKIT.FlurlHttpClient.Wechat.Api.UnitTests\SKIT.FlurlHttpClient.Wechat.Api.UnitTests.csproj", "{0C87A7D9-26EA-4821-AF3F-6D28B3006B24}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests", "test\SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests\SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests.csproj", "{574A567A-6D2C-49F6-9A98-0133CA9B007D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests", "test\SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests\SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests.csproj", "{574A567A-6D2C-49F6-9A98-0133CA9B007D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests", "test\SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests\SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests.csproj", "{5ECE2E7A-9AE8-49BF-902D-41A7756C3E78}" EndProject @@ -78,14 +74,14 @@ Global {AAE2E9BC-4D0B-4495-8825-DF8C405DB4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU {AAE2E9BC-4D0B-4495-8825-DF8C405DB4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU {AAE2E9BC-4D0B-4495-8825-DF8C405DB4A0}.Release|Any CPU.Build.0 = Release|Any CPU - {A8453835-4EE8-4FD4-9766-9C0DCB54CDB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8453835-4EE8-4FD4-9766-9C0DCB54CDB3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8453835-4EE8-4FD4-9766-9C0DCB54CDB3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8453835-4EE8-4FD4-9766-9C0DCB54CDB3}.Release|Any CPU.Build.0 = Release|Any CPU {0C87A7D9-26EA-4821-AF3F-6D28B3006B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0C87A7D9-26EA-4821-AF3F-6D28B3006B24}.Debug|Any CPU.Build.0 = Debug|Any CPU {0C87A7D9-26EA-4821-AF3F-6D28B3006B24}.Release|Any CPU.ActiveCfg = Release|Any CPU {0C87A7D9-26EA-4821-AF3F-6D28B3006B24}.Release|Any CPU.Build.0 = Release|Any CPU + {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Release|Any CPU.Build.0 = Release|Any CPU {5ECE2E7A-9AE8-49BF-902D-41A7756C3E78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5ECE2E7A-9AE8-49BF-902D-41A7756C3E78}.Debug|Any CPU.Build.0 = Debug|Any CPU {5ECE2E7A-9AE8-49BF-902D-41A7756C3E78}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -114,10 +110,6 @@ Global {7667F0D3-B41D-43C2-B69D-A68FE230EBF7}.Debug|Any CPU.Build.0 = Debug|Any CPU {7667F0D3-B41D-43C2-B69D-A68FE230EBF7}.Release|Any CPU.ActiveCfg = Release|Any CPU {7667F0D3-B41D-43C2-B69D-A68FE230EBF7}.Release|Any CPU.Build.0 = Release|Any CPU - {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {574A567A-6D2C-49F6-9A98-0133CA9B007D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -129,9 +121,8 @@ Global {CDD123E6-2622-4368-BAEE-8B95F05F1AB2} = {3E34ADB9-1F52-4C96-9A42-DE782DE1AAA3} {7F155EFB-152F-4798-9984-99102B21D2F8} = {3E34ADB9-1F52-4C96-9A42-DE782DE1AAA3} {AAE2E9BC-4D0B-4495-8825-DF8C405DB4A0} = {3E34ADB9-1F52-4C96-9A42-DE782DE1AAA3} - {4C48D9D5-1D7F-4616-A05D-256555C310FC} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} - {A8453835-4EE8-4FD4-9766-9C0DCB54CDB3} = {4C48D9D5-1D7F-4616-A05D-256555C310FC} {0C87A7D9-26EA-4821-AF3F-6D28B3006B24} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} + {574A567A-6D2C-49F6-9A98-0133CA9B007D} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} {5ECE2E7A-9AE8-49BF-902D-41A7756C3E78} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} {DBF84F66-1436-4599-93AB-7C16A3A2C3A4} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} {561E0BFB-7817-41FE-BAF2-D78817679AC1} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} @@ -139,7 +130,6 @@ Global {D1B321C9-3004-4645-A78D-A85C152062FA} = {35C901ED-C234-4A91-9561-AD89B3BB788D} {65E51735-73CE-4E9B-AA65-4BF5E4C8A705} = {35C901ED-C234-4A91-9561-AD89B3BB788D} {7667F0D3-B41D-43C2-B69D-A68FE230EBF7} = {35C901ED-C234-4A91-9561-AD89B3BB788D} - {574A567A-6D2C-49F6-9A98-0133CA9B007D} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F08ED64E-2517-4B51-A4BE-D33D56CC7B39} diff --git a/test/NuGet.config b/test/NuGet.config new file mode 100644 index 00000000..bc884927 --- /dev/null +++ b/test/NuGet.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests.csproj index 7e11db16..84c97e62 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests.csproj @@ -1,7 +1,7 @@  - net472; netcoreapp3.1; net6.0 + net472; net6.0 latest enable true @@ -22,7 +22,8 @@ - + + all @@ -32,7 +33,6 @@ - diff --git a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReview.cs b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReview.cs new file mode 100644 index 00000000..a705a099 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReview.cs @@ -0,0 +1,28 @@ +using SKIT.FlurlHttpClient.Tools.CodeAnalyzer; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.Ads.UnitTests +{ + public class TestCase_CodeReview + { + [Fact(DisplayName = "测试用例:代码质量分析")] + public void TestCodeAnalyzer() + { + Assert.Null(Record.Exception(() => + { + CodeAnalyzerOptions options = new CodeAnalyzerOptions() + { + AssemblyName = "SKIT.FlurlHttpClient.Wechat.Ads", + WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk, + WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest, + AllowNotFoundEventTypes = true, + AllowNotFoundEventSamples = true + }; + CodeAnalyzer analyzer = new CodeAnalyzer(options); + analyzer.Start(); + analyzer.Assert(); + analyzer.Flush(); + })); + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReviewAnalyzer.cs b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReviewAnalyzer.cs deleted file mode 100644 index 67eb5b8b..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestCase_CodeReviewAnalyzer.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.IO; -using System.Reflection; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Ads.UnitTests -{ - public class TestCase_CodeReviewAnalyzer - { - private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.Ads"); - - [Fact(DisplayName = "代码评审:分析 API 模型命名")] - public void TestApiModelsNaming() - { - CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 模型定义")] - public void TestApiModelsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 接口命名")] - public void TestApiExtensionsNaming() - { - CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析代码规范")] - public void TestCodeStyle() - { - string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); - CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestConfigs.cs index 508e1764..38ce046e 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/TestConfigs.cs @@ -23,8 +23,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Ads.UnitTests WechatAgencyApiKey = config.GetProperty("AgencyApiKey").GetString()!; WechatAccessToken = config.GetProperty("AccessToken").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; + WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!; + WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!; } catch (Exception ex) { @@ -37,7 +37,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Ads.UnitTests public static readonly string WechatAgencyApiKey; public static readonly string WechatAccessToken; - public static readonly string ProjectSourceDirectory; - public static readonly string ProjectTestDirectory; + public static readonly string WorkDirectoryForSdk; + public static readonly string WorkDirectoryForTest; } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/appsettings.json b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/appsettings.json index 20ff060d..9b53c147 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/appsettings.json +++ b/test/SKIT.FlurlHttpClient.Wechat.Ads.UnitTests/appsettings.json @@ -5,6 +5,6 @@ "AgencyApiKey": "请在此填写用于测试的微信广告 AgencyApiKey", "AccessToken": "请在此填写用于测试的微信广告 AccessToken" }, - "ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.Ads\\", - "ProjectTestDirectory": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.Ads.UnitTests\\" + "WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.Ads\\", + "WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.Ads.UnitTests\\" } \ No newline at end of file diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/SKIT.FlurlHttpClient.Wechat.Api.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/SKIT.FlurlHttpClient.Wechat.Api.UnitTests.csproj index de3e4aca..47c4e4ec 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/SKIT.FlurlHttpClient.Wechat.Api.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/SKIT.FlurlHttpClient.Wechat.Api.UnitTests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1; net6.0 + net472; net6.0 latest enable true @@ -24,7 +24,8 @@ - + + all @@ -34,7 +35,6 @@ - diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReview.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReview.cs new file mode 100644 index 00000000..65bbcf9e --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReview.cs @@ -0,0 +1,26 @@ +using SKIT.FlurlHttpClient.Tools.CodeAnalyzer; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests +{ + public class TestCase_CodeReview + { + [Fact(DisplayName = "测试用例:代码质量分析")] + public void TestCodeAnalyzer() + { + Assert.Null(Record.Exception(() => + { + CodeAnalyzerOptions options = new CodeAnalyzerOptions() + { + AssemblyName = "SKIT.FlurlHttpClient.Wechat.Api", + WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk, + WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest + }; + CodeAnalyzer analyzer = new CodeAnalyzer(options); + analyzer.Start(); + analyzer.Assert(); + analyzer.Flush(); + })); + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReviewAnalyzer.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReviewAnalyzer.cs deleted file mode 100644 index f95386cb..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_CodeReviewAnalyzer.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.IO; -using System.Reflection; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests -{ - public class TestCase_CodeReviewAnalyzer - { - private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.Api"); - - [Fact(DisplayName = "代码评审:分析 API 模型命名")] - public void TestApiModelsNaming() - { - CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 模型定义")] - public void TestApiModelsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 事件定义")] - public void TestApiEventsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples"); - CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 接口命名")] - public void TestApiExtensionsNaming() - { - CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析代码规范")] - public void TestCodeStyle() - { - string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); - CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestConfigs.cs index 4c3d861b..116cc649 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestConfigs.cs @@ -23,8 +23,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests WechatAccessToken = config.GetProperty("AccessToken").GetString()!; WechatOpenId = config.GetProperty("OpenId").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; + WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!; + WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!; } catch (Exception ex) { @@ -37,7 +37,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests public static readonly string WechatAccessToken; public static readonly string WechatOpenId; - public static readonly string ProjectSourceDirectory; - public static readonly string ProjectTestDirectory; + public static readonly string WorkDirectoryForSdk; + public static readonly string WorkDirectoryForTest; } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/appsettings.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/appsettings.json index afbea056..1caa4cdf 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/appsettings.json +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/appsettings.json @@ -5,6 +5,6 @@ "AccessToken": "请在此填写用于测试的微信 AccessToken", "OpenId": "请在此填写用于测试的微信用户唯一标识" }, - "ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.Api\\", - "ProjectTestDirectory": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.Api.UnitTests\\" + "WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.Api\\", + "WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.Api.UnitTests\\" } \ No newline at end of file diff --git a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests.csproj index f452d823..c3869729 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests.csproj @@ -1,7 +1,7 @@  - net472; netcoreapp3.1; net6.0 + net472; net6.0 latest enable true @@ -23,7 +23,8 @@ - + + all @@ -33,7 +34,6 @@ - diff --git a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReview.cs b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReview.cs new file mode 100644 index 00000000..5e82dff0 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReview.cs @@ -0,0 +1,28 @@ +using SKIT.FlurlHttpClient.Tools.CodeAnalyzer; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests +{ + public class TestCase_CodeReview + { + [Fact(DisplayName = "测试用例:代码质量分析")] + public void TestCodeAnalyzer() + { + Assert.Null(Record.Exception(() => + { + CodeAnalyzerOptions options = new CodeAnalyzerOptions() + { + AssemblyName = "SKIT.FlurlHttpClient.Wechat.OpenAI", + WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk, + WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest, + AllowNotFoundEventTypes = true, + AllowNotFoundEventSamples = true + }; + CodeAnalyzer analyzer = new CodeAnalyzer(options); + analyzer.Start(); + analyzer.Assert(); + analyzer.Flush(); + })); + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReviewAnalyzer.cs b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReviewAnalyzer.cs deleted file mode 100644 index 61dee698..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestCase_CodeReviewAnalyzer.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.IO; -using System.Reflection; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests -{ - public class TestCase_CodeReviewAnalyzer - { - private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.OpenAI"); - - [Fact(DisplayName = "代码评审:分析 API 模型命名")] - public void TestApiModelsNaming() - { - CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 模型定义")] - public void TestApiModelsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 事件定义")] - public void TestApiEventsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples"); - CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 接口命名")] - public void TestApiExtensionsNaming() - { - CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析代码规范")] - public void TestCodeStyle() - { - string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); - CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestConfigs.cs index c412f441..1ce5f913 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/TestConfigs.cs @@ -25,8 +25,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests WechatEncodingAESKey = config.GetProperty("EncodingAESKey").GetString()!; WechatAccessToken = config.GetProperty("AccessToken").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; + WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!; + WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!; } catch (Exception ex) { @@ -41,7 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests public static readonly string WechatEncodingAESKey; public static readonly string WechatAccessToken; - public static readonly string ProjectSourceDirectory; - public static readonly string ProjectTestDirectory; + public static readonly string WorkDirectoryForSdk; + public static readonly string WorkDirectoryForTest; } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/appsettings.json b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/appsettings.json index 6836cff5..3d8a30ee 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/appsettings.json +++ b/test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/appsettings.json @@ -7,6 +7,6 @@ "EncodingAESKey": "请在此填写用于测试的微信智能对话 EncodingAESKey", "AccessToken": "请在此填写用于测试的微信智能对话 AccessToken" }, - "ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.OpenAI\\", - "ProjectTestDirectory": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests\\" + "WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.OpenAI\\", + "WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests\\" } \ No newline at end of file diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests.csproj index 4f0fc5dd..b67e6090 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests.csproj @@ -1,7 +1,7 @@  - net472; netcoreapp3.1; net6.0 + net472; net6.0 latest enable true @@ -25,7 +25,8 @@ - + + all @@ -35,7 +36,6 @@ - diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReview.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReview.cs new file mode 100644 index 00000000..3660cdb1 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReview.cs @@ -0,0 +1,28 @@ +using SKIT.FlurlHttpClient.Tools.CodeAnalyzer; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests +{ + public class TestCase_CodeReview + { + [Fact(DisplayName = "测试用例:代码质量分析")] + public void TestCodeAnalyzer() + { + Assert.Null(Record.Exception(() => + { + CodeAnalyzerOptions options = new CodeAnalyzerOptions() + { + AssemblyName = "SKIT.FlurlHttpClient.Wechat.TenpayV2", + WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk, + WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest, + AllowNotFoundEventTypes = true, + AllowNotFoundEventSamples = true + }; + CodeAnalyzer analyzer = new CodeAnalyzer(options); + analyzer.Start(); + analyzer.Assert(); + analyzer.Flush(); + })); + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReviewAnalyzer.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReviewAnalyzer.cs deleted file mode 100644 index 64cba07b..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestCase_CodeReviewAnalyzer.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.IO; -using System.Reflection; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests -{ - public class TestCase_CodeReviewAnalyzer - { - private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.TenpayV2"); - - [Fact(DisplayName = "代码评审:分析 API 模型命名")] - public void TestApiModelsNaming() - { - CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 模型定义")] - public void TestApiModelsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 事件定义")] - public void ApiEventsDefinitionTest() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples"); - CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 接口命名")] - public void TestApiExtensionsNaming() - { - CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析代码规范")] - public void TestCodeStyle() - { - string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); - CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestConfigs.cs index 254a52de..0563b181 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/TestConfigs.cs @@ -24,8 +24,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests WechatMerchantCertificateBytes = config.GetProperty("MerchantCertificateBase64String").GetBytesFromBase64(); WechatOpenId = config.GetProperty("OpenId").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; + WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!; + WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!; } catch (Exception ex) { @@ -39,7 +39,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests public static readonly byte[] WechatMerchantCertificateBytes; public static readonly string WechatOpenId; - public static readonly string ProjectSourceDirectory; - public static readonly string ProjectTestDirectory; + public static readonly string WorkDirectoryForSdk; + public static readonly string WorkDirectoryForTest; } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/appsettings.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/appsettings.json index 333d7065..2f30945d 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/appsettings.json +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests/appsettings.json @@ -6,6 +6,6 @@ "AppId": "请在此填写用于测试的微信 AppId", "OpenId": "请在此填写用于测试的微信用户唯一标识" }, - "ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.TenpayV2\\", - "ProjectTestDirectory": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests\\" + "WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.TenpayV2\\", + "WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.TenpayV2.UnitTests\\" } \ No newline at end of file diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests.csproj index e8d4557b..0d4861fa 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests.csproj @@ -1,7 +1,7 @@  - net472; netcoreapp3.1; net6.0 + net472; net6.0 latest enable true @@ -23,7 +23,8 @@ - + + all @@ -33,7 +34,6 @@ - diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReview.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReview.cs new file mode 100644 index 00000000..9e6796d4 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReview.cs @@ -0,0 +1,28 @@ +using SKIT.FlurlHttpClient.Tools.CodeAnalyzer; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests +{ + public class TestCase_CodeReview + { + [Fact(DisplayName = "测试用例:代码质量分析")] + public void TestCodeAnalyzer() + { + Assert.Null(Record.Exception(() => + { + CodeAnalyzerOptions options = new CodeAnalyzerOptions() + { + AssemblyName = "SKIT.FlurlHttpClient.Wechat.TenpayV3", + WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk, + WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest, + AllowNotFoundEventTypes = true, + AllowNotFoundEventSamples = true + }; + CodeAnalyzer analyzer = new CodeAnalyzer(options); + analyzer.Start(); + analyzer.Assert(); + analyzer.Flush(); + })); + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReviewAnalyzer.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReviewAnalyzer.cs deleted file mode 100644 index a9c984d4..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_CodeReviewAnalyzer.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.IO; -using System.Reflection; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests -{ - public class TestCase_CodeReviewAnalyzer - { - private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.TenpayV3"); - - [Fact(DisplayName = "代码评审:分析 API 模型命名")] - public void ApiModelsNamingTest() - { - CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 模型定义")] - public void ApiModelsDefinitionTest() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 事件定义")] - public void ApiEventsDefinitionTest() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples"); - CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 接口命名")] - public void ApiExtensionsNamingTest() - { - CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析代码规范")] - public void CodeStyleTest() - { - string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); - CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestConfigs.cs index 68d5073a..c493e278 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestConfigs.cs @@ -24,8 +24,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests WechatAppId = config.GetProperty("AppId").GetString()!; WechatOpenId = config.GetProperty("OpenId").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; + WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!; + WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!; } catch (Exception ex) { @@ -40,7 +40,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests public static readonly string WechatAppId; public static readonly string WechatOpenId; - public static readonly string ProjectSourceDirectory; - public static readonly string ProjectTestDirectory; + public static readonly string WorkDirectoryForSdk; + public static readonly string WorkDirectoryForTest; } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/appsettings.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/appsettings.json index fb96b4a4..9de2e63b 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/appsettings.json +++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/appsettings.json @@ -7,6 +7,6 @@ "AppId": "请在此填写用于测试的微信 AppId", "OpenId": "请在此填写用于测试的微信用户唯一标识" }, - "ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.TenpayV3\\", - "ProjectTestDirectory": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests\\" + "WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.TenpayV3\\", + "WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests\\" } \ No newline at end of file diff --git a/test/SKIT.FlurlHttpClient.Wechat.TestTools/CodeStyleUtil.cs b/test/SKIT.FlurlHttpClient.Wechat.TestTools/CodeStyleUtil.cs deleted file mode 100644 index 91edb918..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.TestTools/CodeStyleUtil.cs +++ /dev/null @@ -1,690 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Text.RegularExpressions; -using System.Xml.Serialization; - -namespace SKIT.FlurlHttpClient.Wechat -{ - public static class CodeStyleUtil - { - private static readonly Regex CODESTYLE_RULE_REGEX_NO_JSONABLE_PROPERTY_IN_REQUEST = new Regex(@"\/\* \@codestyle-disable[a-zA-Z0-9,\-\s]*no-jsonable-property-in-request-get[a-zA-Z0-9,\-\s]*\*\/", RegexOptions.Compiled); - private static readonly Regex CODESTYLE_RULE_REGEX_NO_INSTANTIATED_PROPERTY_IN_RESPONSE = new Regex(@"\/\* \@codestyle-disable[a-zA-Z0-9,\-\s]*no-instantiated-property-in-response[a-zA-Z0-9,\-\s]*\*\/", RegexOptions.Compiled); - - private static bool TryJsonize(Type type, string json, out Exception exception) - { - exception = null; - - var newtonsoftJsonSettings = FlurlNewtonsoftJsonSerializer.GetDefaultSerializerSettings(); - newtonsoftJsonSettings.CheckAdditionalContent = true; - newtonsoftJsonSettings.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Error; - var newtonsoftJsonSerializer = new FlurlNewtonsoftJsonSerializer(newtonsoftJsonSettings); - - var systemTextJsonOptions = FlurlSystemTextJsonSerializer.GetDefaultSerializerOptions(); - systemTextJsonOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles; - var systemTextJsonSerializer = new FlurlSystemTextJsonSerializer(systemTextJsonOptions); - - try - { - newtonsoftJsonSerializer.Deserialize(json, type); - systemTextJsonSerializer.Deserialize(json, type); - } - catch (Exception ex) - { - if (ex is Newtonsoft.Json.JsonException) - exception = new Exception($"[模型] 通过 Newtonsoft.Json 反序列化 `{type.Name}` 失败。", ex); - else if (ex is System.Text.Json.JsonException) - exception = new Exception($"[模型] 通过 System.Text.Json 反序列化 `{type.Name}` 失败。", ex); - else - exception = new Exception($"[模型] JSON 反序列化 `{type.Name}` 遇到问题。", ex); - - return false; - } - - try - { - object instance = Activator.CreateInstance(type); - TestReflectionUtil.InitializeProperties(instance); - - newtonsoftJsonSerializer.Serialize(instance, type); - systemTextJsonSerializer.Serialize(instance, type); - } - catch (Exception ex) - { - if (ex is Newtonsoft.Json.JsonException) - exception = new Exception($"[模型] 通过 Newtonsoft.Json 序列化 `{type.Name}` 失败。", ex); - else if (ex is System.Text.Json.JsonException) - exception = new Exception($"[模型] 通过 System.Text.Json 序列化 `{type.Name}` 失败。", ex); - else - exception = new Exception($"[模型] JSON 序列化 `{type.Name}` 遇到问题。", ex); - - return false; - } - - try - { - PropertyInfo[] lstPropInfo = TestReflectionUtil.GetAllProperties(type); - foreach (PropertyInfo propInfo in lstPropInfo) - { - var newtonsoftJsonAttribute = propInfo.GetCustomAttribute(inherit: true); - var systemTextJsonAttribute = propInfo.GetCustomAttribute(inherit: true); - if (newtonsoftJsonAttribute?.PropertyName != systemTextJsonAttribute?.Name) - { - exception = new Exception($"[模型] 类型 `{type.Name}` 的可 JSON 序列化字段 `{propInfo.Name}` 声明不一致:`{newtonsoftJsonAttribute.PropertyName}` & `{systemTextJsonAttribute.Name}`。"); - return false; - } - } - } - catch (Exception ex) - { - exception = new Exception($"[模型] JSON 分析 `{type.Name}` 遇到问题。", ex); - return false; - } - - return exception == null; - } - - private static bool TryXmlize(Type type, string xml, out Exception exception) - { - exception = null; - - try - { - using var reader = new StringReader(xml); - var xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml")); - xmlSerializer.Deserialize(reader); - } - catch (Exception ex) - { - exception = new Exception($"[模型] XML 反序列化 `{type.Name}` 遇到问题。", ex); - return false; - } - - try - { - var xmlDoc = new System.Xml.XmlDocument(); - xmlDoc.LoadXml(xml); - - Func fn = default; - fn = new Func((xmlNode) => - { - if (xmlNode.NodeType == System.Xml.XmlNodeType.Element) - { - PropertyInfo[] lstPropInfo = TestReflectionUtil.GetAllProperties(type); - var xmlElementAttributes = lstPropInfo.SelectMany(e => e.GetCustomAttributes(inherit: true)).ToArray(); - var xmlArrayAttributes = lstPropInfo.SelectMany(e => e.GetCustomAttributes(inherit: true)).ToArray(); - var xmlArrayItemAttributes = lstPropInfo.SelectMany(e => e.GetCustomAttributes(inherit: true)).ToArray(); - if (!xmlElementAttributes.Any(e => e.ElementName == xmlNode.Name) && - !xmlArrayAttributes.Any(e => e.ElementName == xmlNode.Name) && - !xmlArrayItemAttributes.Any(e => e.ElementName == xmlNode.Name)) - { - return new Exception($"[模型] 类型 `{type.Name}` 的可 XML 序列化字段缺失项:`{xmlNode.Name}`。"); - } - } - - for (int i = 0; i < xmlNode.ChildNodes.Count; i++) - { - Exception ex = fn.Invoke(xmlNode.ChildNodes[i]); - if (ex != null) - return ex; - } - - return null; - }); - - for (int i = 0; i < xmlDoc.DocumentElement.ChildNodes.Count; i++) - { - exception = fn.Invoke(xmlDoc.DocumentElement.ChildNodes[i]); - if (exception != null) - return false; - } - } - catch (Exception ex) - { - exception = new Exception($"[模型] XML 分析 `{type.Name}` 遇到问题。", ex); - return false; - } - - return exception == null; - } - - public static bool VerifyApiModelsNaming(Assembly assembly, out Exception exception) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - - var lstModelType = TestReflectionUtil.GetAllApiModelsTypes(assembly); - var lstError = new List(); - - Parallel.ForEach(lstModelType, (modelType) => - { - string name = modelType.Name.Split('`')[0]; - - if (!name.EndsWith("Request") && !name.EndsWith("Response")) - { - lstError.Add(new Exception($"[模型] `{name}` 类名结尾应为 \"Request\" 或 \"Response\"。")); - } - - if (name.EndsWith("Request")) - { - if (!typeof(ICommonRequest).IsAssignableFrom(modelType)) - { - lstError.Add(new Exception($"[模型] `{name}` 是请求模型,需实现自 `{nameof(ICommonRequest)}`。")); - } - - if (!lstModelType.Any(e => e.Name == $"{name.Substring(0, name.Length - "Request".Length)}Response")) - { - lstError.Add(new Exception($"[模型] `{name}` 是请求模型,但不存在对应的响应模型。")); - } - } - - if (name.EndsWith("Response")) - { - if (!typeof(ICommonResponse).IsAssignableFrom(modelType)) - { - lstError.Add(new Exception($"[模型] `{name}` 是响应模型,需实现自 `{nameof(ICommonResponse)}`。")); - } - - if (!lstModelType.Any(e => e.Name == $"{name.Substring(0, name.Length - "Response".Length)}Request")) - { - lstError.Add(new Exception($"[模型] `{name}` 是响应模型,但不存在对应的请求模型。")); - } - } - }); - - if (lstError.Any()) - { - exception = new AggregateException(lstError); - return false; - } - - exception = null; - return true; - } - - public static bool VerifyApiModelsDefinition(Assembly assembly, string workdir, out Exception exception) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - if (workdir == null) throw new ArgumentNullException(nameof(workdir)); - - var lstModelType = TestReflectionUtil.GetAllApiModelsTypes(assembly); - var lstError = new List(); - - var lstFilePath = TestIOUtil.GetAllFiles(workdir) - .Where(e => string.Equals(Path.GetExtension(e), ".json", StringComparison.OrdinalIgnoreCase)) - .ToList(); - if (!lstFilePath.Any()) - { - lstError.Add(new Exception($"[模型] \"{workdir}\" 下不存在示例文件,请检查配置的扫描路径是否正确。")); - } - - Parallel.ForEach(lstFilePath, (filePath) => - { - string name = Path.GetFileNameWithoutExtension(filePath).Split('.')[0]; - - Type type = assembly.GetTypes().FirstOrDefault(e => e.FullName.StartsWith($"{assembly.GetName().Name}.Models.") && e.Name == name); - if (type == null) - { - lstError.Add(new Exception($"[模型] 扫描到示例文件 \"{filePath}\",但类型 `{name}` 不存在。")); - return; - } - - if (string.Equals(Path.GetExtension(filePath), ".json", StringComparison.OrdinalIgnoreCase)) - { - string json = File.ReadAllText(filePath); - if (!TryJsonize(type, json, out Exception ex)) - { - lstError.Add(ex); - } - } - }); - - if (lstError.Any()) - { - exception = new AggregateException(lstError); - return false; - } - - exception = null; - return true; - } - - public static bool VerifyApiEventsDefinition(Assembly assembly, string workdir, out Exception exception) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - if (workdir == null) throw new ArgumentNullException(nameof(workdir)); - - var lstModelType = TestReflectionUtil.GetAllApiModelsTypes(assembly); - var lstError = new List(); - - var lstFilePath = TestIOUtil.GetAllFiles(workdir) - .Where(e => - string.Equals(Path.GetExtension(e), ".json", StringComparison.OrdinalIgnoreCase) || - string.Equals(Path.GetExtension(e), ".xml", StringComparison.OrdinalIgnoreCase) - ) - .ToArray(); - if (!lstFilePath.Any()) - { - lstError.Add(new Exception($"[模型] \"{workdir}\" 下不存在示例文件,请检查配置的扫描路径是否正确。")); - } - - Parallel.ForEach(lstFilePath, (filePath) => - { - string name = Path.GetFileNameWithoutExtension(filePath).Split('.')[0]; - - Type type = assembly.GetTypes().SingleOrDefault(e => e.FullName.StartsWith($"{assembly.GetName().Name}.Events.") && e.Name == name); - if (type == null) - { - lstError.Add(new Exception($"[模型] 扫描到示例文件 \"{filePath}\",但类型 `{name}` 不存在。")); - return; - } - - if (string.Equals(Path.GetExtension(filePath), ".json", StringComparison.OrdinalIgnoreCase)) - { - string json = File.ReadAllText(filePath); - - if (!TryJsonize(type, json, out Exception ex)) - { - lstError.Add(ex); - } - } - else if (string.Equals(Path.GetExtension(filePath), ".xml", StringComparison.OrdinalIgnoreCase)) - { - string xml = File.ReadAllText(filePath); - - if (!TryXmlize(type, xml, out Exception ex)) - { - lstError.Add(ex); - } - } - }); - - if (lstError.Any()) - { - exception = new AggregateException(lstError); - return false; - } - - exception = null; - return true; - } - - public static bool VerifyApiExtensionsNaming(Assembly assembly, out Exception exception) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - - var lstExtType = TestReflectionUtil.GetAllApiExtensionsTypes(assembly); - var lstError = new List(); - - Parallel.ForEach(lstExtType, (extensionsType) => - { - MethodInfo[] lstMethod = extensionsType.GetMethods() - .Where(e => - e.IsPublic && e.IsStatic && - typeof(ICommonClient).IsAssignableFrom(e.GetParameters().FirstOrDefault().ParameterType) - ) - .ToArray(); - - foreach (MethodInfo methodInfo in lstMethod) - { - ParameterInfo[] lstParamInfo = methodInfo.GetParameters(); - - if (lstParamInfo.Length != 3) - { - lstError.Add(new Exception($"[接口] `{extensionsType.Name}.{methodInfo.Name}` 方法需有且仅有 3 个入参。")); - continue; - } - - if (!typeof(ICommonRequest).IsAssignableFrom(lstParamInfo[1].ParameterType)) - { - lstError.Add(new Exception($"[接口] `{extensionsType.Name}.{methodInfo.Name}` 方法第 1 个入参未实现 `{nameof(ICommonRequest)}`。")); - continue; - } - - // 方法名与第二个参数、返回值均有相同命名 - string func = methodInfo.Name; - string para = lstParamInfo[1].ParameterType.Name; - string retv = methodInfo.ReturnType.GenericTypeArguments.FirstOrDefault()?.Name; - if (para == null || !para.EndsWith("Request")) - { - lstError.Add(new Exception($"[接口] `{extensionsType.Name}.{methodInfo.Name}` 方法第 1 个入参类名未以 `Request` 结尾。")); - continue; - } - else if (retv == null || !retv.EndsWith("Response")) - { - if (!methodInfo.ReturnType.GenericTypeArguments.First().IsGenericType) - { - lstError.Add(new Exception($"[接口] `{extensionsType.Name}.{methodInfo.Name}` 方法返回值类名未以 `Response` 结尾。")); - } - continue; - } - else if (!string.Equals(func, $"Execute{para.Substring(0, para.Length - "Request".Length)}Async")) - { - lstError.Add(new Exception($"[接口] `{extensionsType.Name}.{methodInfo.Name}` 方法与请求模型不同名。")); - continue; - } - else if (!string.Equals(func, $"Execute{retv.Substring(0, retv.Length - "Response".Length)}Async")) - { - lstError.Add(new Exception($"[接口] `{extensionsType.Name}.{methodInfo.Name}` 方法与响应模型不同名。")); - continue; - } - } - }); - - if (lstError.Any()) - { - exception = new AggregateException(lstError); - return false; - } - - exception = null; - return true; - } - - public static bool VerifySourceCodeStyle(string workdir, out Exception exception) - { - if (workdir == null) throw new ArgumentNullException(nameof(workdir)); - - var lstError = new List(); - - var lstExtensionsCodeFile = TestIOUtil.GetAllFiles(workdir) - .Where(e => string.Equals(Path.GetExtension(e), ".cs", StringComparison.OrdinalIgnoreCase)) - .Where(e => Path.GetDirectoryName(e).StartsWith(Path.Combine(workdir, "Extensions"))) - .Where(e => Path.GetFileNameWithoutExtension(e).Contains("ClientExecute")) - .Where(e => Path.GetFileNameWithoutExtension(e).EndsWith("Extensions")) - .ToArray(); - var lstModelsCodeFile = TestIOUtil.GetAllFiles(workdir) - .Where(e => string.Equals(Path.GetExtension(e), ".cs", StringComparison.OrdinalIgnoreCase)) - .Where(e => Path.GetDirectoryName(e).StartsWith(Path.Combine(workdir, "Models"))) - .Where(e => Path.GetFileNameWithoutExtension(e).EndsWith("Request") || Path.GetFileNameWithoutExtension(e).EndsWith("Response")) - .ToArray(); - if (!lstExtensionsCodeFile.Any() || !lstModelsCodeFile.Any()) - { - lstError.Add(new Exception($"[风格] \"{workdir}\" 下不存在源代码文件,请检查配置的扫描路径是否正确。")); - } - - Parallel.ForEach(lstExtensionsCodeFile, (extCodeFilePath) => - { - string extCodeFileName = Path.GetFileName(extCodeFilePath); - - string[] segments = File.ReadAllText(extCodeFilePath) - .Split(new string[] { "" }, StringSplitOptions.RemoveEmptyEntries) - .Where(e => e.Contains("Async") && !e.Contains("public static class")) - .ToArray(); - for (int i = 0; i < segments.Length; i++) - { - bool TryCheckExtensionSourceCode(string sourceCode, out (string Name, string Method, string Url)? request) - { - request = null; - - // 匹配 ... 结构 - var regexPara = new Regex("").Match(sourceCode); - if (!regexPara.Success) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释不齐全,未能匹配到 \" ... \"。")); - return false; - } - - // 匹配 [...] ... 结构 - var regexApi = new Regex("\\[(\\S*)\\]\\s*(\\S*)").Match(regexPara.Groups[1].Value); - if (!regexApi.Success) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释不齐全,未能匹配到 \"异步调用 ... 接口\"。")); - return false; - } - - // 比对请求谓词 - string expectedMethod = regexApi.Groups[1].Value.Trim(); - string expectedUrl = regexApi.Groups[2].Value.Split('?')[0].Trim(); - string actualMethod = sourceCode.Contains(".CreateRequest(request, new HttpMethod(\"") ? - sourceCode.Split(new string[] { ".CreateRequest(request, new HttpMethod(\"" }, StringSplitOptions.None)[1].Split('\"')[0] : - sourceCode.Contains(".CreateRequest(request, HttpMethod.") ? - sourceCode.Split(new string[] { ".CreateRequest(request, HttpMethod." }, StringSplitOptions.None)[1].Split(',')[0].Split(')')[0] : - string.Empty; - if (!string.Equals(expectedMethod, actualMethod, StringComparison.OrdinalIgnoreCase)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释有误,`[{expectedMethod}] {expectedUrl}` 与实际接口谓词不一致。")); - return false; - } - - // 比对请求路由 - string actualUrl = sourceCode - .Split(new string[] { "CreateRequest(request," }, StringSplitOptions.RemoveEmptyEntries)[1] - .Substring(sourceCode.Split(new string[] { "CreateRequest(request," }, StringSplitOptions.RemoveEmptyEntries)[1].Split(',')[0].Length + 1) - .Split('\n')[0] - .Trim() - .TrimEnd(')', ';') - .Trim(); - string[] expectedUrlSegments = expectedUrl.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries); - string[] actualUrlSegments = actualUrl.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(e => e.Trim()).ToArray(); - if (expectedUrlSegments.Length != actualUrlSegments.Length) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释有误,`[{expectedMethod}] {expectedUrl}` 与实际接口路由不一致:节长不等(实际 {actualUrlSegments.Length},期望 {expectedUrlSegments.Length})。")); - return false; - } - else - { - for (int urlSegmentIndex = 0; urlSegmentIndex < expectedUrlSegments.Length; urlSegmentIndex++) - { - string expectedUrlSegment = expectedUrlSegments[urlSegmentIndex].Trim('/'); - string actualUrlSegment = actualUrlSegments[urlSegmentIndex].Trim('/'); - if (expectedUrlSegment.Contains("{")) - { - if (actualUrlSegment.StartsWith("\"")) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释有误,`[{expectedMethod}] {expectedUrl}` 与实际接口路由不一致:第 {urlSegmentIndex} 节值不同。")); - break; - } - } - else - { - actualUrlSegment = actualUrlSegment.Replace("\"", string.Empty).Trim('/'); - if (!string.Equals(expectedUrlSegment, actualUrlSegment)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释有误,`[{expectedMethod}] {expectedUrl}` 与实际接口路由不一致:第 {urlSegmentIndex} 节值不同。")); - break; - } - } - } - } - - // 比对 .SendRequestAsync() 方法 - if (!"GET".Equals(actualMethod, StringComparison.OrdinalIgnoreCase)) - { - if (sourceCode.Contains("flurlReq, cancellationToken")) - { - lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段代码有误,`[{expectedMethod}] {expectedUrl}` 为非简单请求但不包含请求正文。")); - return false; - } - } - - string apiName = new Regex("Execute([a-zA-Z0-9]*)Async").Match(sourceCode).Groups[1].Value; - request = (apiName, expectedMethod, expectedUrl); - return true; - } - bool TryCheckRequestModelSourceCode(string filePath, string expectedRequestMethod, string expectedRequestUrl) - { - if (!File.Exists(filePath)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{filePath}\" 不存在。")); - return false; - } - - string reqCodeFileName = Path.GetFileName(filePath); - string reqCodeSourceCode = File.ReadAllText(filePath); - - // 匹配 ... 结构 - var regexPara = new Regex("").Match(reqCodeSourceCode); - if (!regexPara.Success) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下文档注释不齐全,未能匹配到 \" ... \"。")); - return false; - } - - // 匹配 [...] ... 结构 - var regexApi = new Regex("\\[(\\S*)\\]\\s*(\\S*)").Match(regexPara.Groups[1].Value); - if (!regexApi.Success) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下文档注释不齐全,未能匹配到 \"异步调用 ... 接口\"。")); - return false; - } - - // 比对请求谓词 - string actualMethod = regexApi.Groups[1].Value.Trim(); - if (!string.Equals(expectedRequestMethod, actualMethod, StringComparison.OrdinalIgnoreCase)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下文档注释有误,与实际接口谓词不一致。")); - return false; - } - - // 对比请求路由 - string actualUrl = regexApi.Groups[2].Value.Split('?')[0].Trim(); - if (!string.Equals(expectedRequestUrl, actualUrl, StringComparison.OrdinalIgnoreCase)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下文档注释有误,与实际接口路由不一致。")); - return false; - } - - // 检验是否包含 `default!` 的赋值 - if (new Regex("=\\s*default!").IsMatch(reqCodeSourceCode)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下代码有误,请求模型不应包含 `= default!` 赋值。")); - return false; - } - - // 检验是否包含数组类型字段 - if (new Regex("public\\s*[a-zA-Z0-9.]*\\[\\]\\s*[a-zA-Z0-9]*\\s*{\\s*get;\\s*set;\\s*}").IsMatch(reqCodeSourceCode.Replace("byte[]", string.Empty).Replace("Byte[]", string.Empty))) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下代码有误,请求模型不应包含数组类型字段。")); - return false; - } - - // 校验是否包含可空字段的初始化 - if (new Regex("\\? [a-zA-Z0-9]* \\{ get; set; \\} =").IsMatch(reqCodeSourceCode)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下代码有误,可空字段不应初始化。")); - return false; - } - - // 如果是 GET 请求,检查是否包含 JSON 序列化字段 - if ("GET".Equals(expectedRequestMethod, StringComparison.OrdinalIgnoreCase)) - { - if (!(CODESTYLE_RULE_REGEX_NO_JSONABLE_PROPERTY_IN_REQUEST.IsMatch(reqCodeSourceCode))) - { - if (new Regex("\\[Newtonsoft.Json.JsonProperty\\(\"[a-zA-Z0-9_]*\"\\)\\]").IsMatch(reqCodeSourceCode)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下代码有误,请求模型为简单请求、不应包含可 JSON 序列化字段。")); - return false; - } - - if (new Regex("\\[System.Text.Json.Serialization.JsonPropertyName\\(\"[a-zA-Z0-9_]*\"\\)\\]").IsMatch(reqCodeSourceCode)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下代码有误,请求模型为简单请求、不应包含可 JSON 序列化字段。")); - return false; - } - } - } - - return true; - } - bool TryCheckResponseModelSourceCode(string filePath, string expectedRequestMethod, string expectedRequestUrl) - { - if (!File.Exists(filePath)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{filePath}\" 不存在。")); - return false; - } - - string resCodeFileName = Path.GetFileName(filePath); - string resCodeSourceCode = File.ReadAllText(filePath); - - // 匹配 ... 结构 - var regexPara = new Regex("").Match(resCodeSourceCode); - if (!regexPara.Success) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下文档注释不齐全,未能匹配到 \" ... \"。")); - return false; - } - - // 匹配 [...] ... 结构 - var regexApi = new Regex("\\[(\\S*)\\]\\s*(\\S*)").Match(regexPara.Groups[1].Value); - if (!regexApi.Success) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下文档注释不齐全,未能匹配到 \"异步调用 ... 接口\"。")); - return false; - } - - // 比对请求谓词 - string actualMethod = regexApi.Groups[1].Value.Trim(); - if (!string.Equals(expectedRequestMethod, actualMethod, StringComparison.OrdinalIgnoreCase)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下文档注释有误,与实际接口谓词不一致。")); - return false; - } - - // 对比请求路由 - string actualUrl = regexApi.Groups[2].Value.Split('?')[0].Trim(); - if (!string.Equals(expectedRequestUrl, actualUrl, StringComparison.OrdinalIgnoreCase)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下文档注释有误,与实际接口路由不一致。")); - return false; - } - - // 检验是否包含 `string.Empty` 的赋值 - if (new Regex("=\\s*string.Empty").IsMatch(resCodeSourceCode)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下代码有误,响应模型不应包含 `= string.Empty` 赋值。")); - return false; - } - - // 检验是否包含 `new class()` 的赋值 - if (new Regex("=\\s*new\\s[a-zA-Z0-9.]*\\(\\)").IsMatch(resCodeSourceCode)) - { - if (!(CODESTYLE_RULE_REGEX_NO_INSTANTIATED_PROPERTY_IN_RESPONSE.IsMatch(resCodeSourceCode))) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下代码有误,响应模型不应包含 `= new class()` 赋值。")); - return false; - } - } - - // 检验是否包含列表类型字段 - if (new Regex("public\\s*IList<[a-zA-Z0-9.]*>\\s*[a-zA-Z0-9]*\\s*{\\s*get;\\s*set;\\s*}").IsMatch(resCodeSourceCode)) - { - lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下代码有误,响应模型不应包含列表类型字段。")); - return false; - } - - return true; - } - - if (!TryCheckExtensionSourceCode(segments[i], out var request)) - { - continue; - } - else - { - string reqModelFileName = lstModelsCodeFile.FirstOrDefault(e => string.Equals(Path.GetFileNameWithoutExtension(e), $"{request.Value.Name}Request")); - string resModelFileName = lstModelsCodeFile.FirstOrDefault(e => string.Equals(Path.GetFileNameWithoutExtension(e), $"{request.Value.Name}Response")); - bool isValidReq = TryCheckRequestModelSourceCode(reqModelFileName, request.Value.Method, request.Value.Url); - bool isValidRes = TryCheckResponseModelSourceCode(resModelFileName, request.Value.Method, request.Value.Url); - if (!isValidReq || !isValidRes) - { - continue; - } - } - } - }); - - if (lstError.Any()) - { - exception = new AggregateException(lstError); - return false; - } - - exception = null; - return true; - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.TestTools/SKIT.FlurlHttpClient.Wechat.TestTools.csproj b/test/SKIT.FlurlHttpClient.Wechat.TestTools/SKIT.FlurlHttpClient.Wechat.TestTools.csproj deleted file mode 100644 index e2262421..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.TestTools/SKIT.FlurlHttpClient.Wechat.TestTools.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net472; netcoreapp3.1; net6.0 - latest - false - - - - - - - diff --git a/test/SKIT.FlurlHttpClient.Wechat.TestTools/TestIOUtil.cs b/test/SKIT.FlurlHttpClient.Wechat.TestTools/TestIOUtil.cs deleted file mode 100644 index 2c786d8d..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.TestTools/TestIOUtil.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace SKIT.FlurlHttpClient.Wechat -{ - public static class TestIOUtil - { - public static string[] GetAllFiles(string path) - { - if (path == null) throw new ArgumentNullException(nameof(path)); - - List results = new List(); - string[] dirs = Directory.GetDirectories(path); - string[] files = Directory.GetFiles(path); - - results.AddRange(files); - - foreach (string dir in dirs) - { - results.AddRange(GetAllFiles(dir)); - } - - return results.ToArray(); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.TestTools/TestReflectionUtil.cs b/test/SKIT.FlurlHttpClient.Wechat.TestTools/TestReflectionUtil.cs deleted file mode 100644 index 1217f4ed..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.TestTools/TestReflectionUtil.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace SKIT.FlurlHttpClient.Wechat -{ - public static class TestReflectionUtil - { - public static Type[] GetAllApiModelsTypes(Assembly assembly) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - - return assembly.GetTypes() - .Where(e => - e.Namespace != null && - e.Namespace.Equals(assembly.GetName().Name + ".Models") && - e.IsClass && - !e.IsAbstract && - !e.IsInterface && - !e.IsNested - ) - .ToArray(); - } - - public static Type[] GetAllApiExtensionsTypes(Assembly assembly) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - - return assembly.GetTypes() - .Where(e => - e.Namespace != null && - e.Namespace.Equals(assembly.GetName().Name) && - e.Name.StartsWith("Wechat") && - e.Name.Contains("ClientExecute") && - e.Name.EndsWith("Extensions") - ) - .ToArray(); - } - - public static Type[] GetAllApiEventsTypes(Assembly assembly) - { - if (assembly == null) throw new ArgumentNullException(nameof(assembly)); - - return assembly.GetTypes() - .Where(e => - e.Namespace != null && - e.Namespace.Equals(assembly.GetName().Name + ".Events") && - e.IsClass && - !e.IsAbstract && - !e.IsInterface && - !e.IsNested - ) - .ToArray(); - } - - public static PropertyInfo[] GetAllProperties(Type type) - { - if (type == null) throw new ArgumentNullException(nameof(type)); - - static Type[] GetAllNestedTypes(Type externalType) - { - List lstType = new List(); - foreach (Type innerType in externalType.GetNestedTypes()) - { - if (innerType.IsClass) - { - lstType.Add(innerType); - lstType.AddRange(GetAllNestedTypes(innerType)); - } - } - - return lstType - .Where(e => - !e.IsAbstract && - e.IsNestedPublic - ) - .ToArray(); - } - - var lstProperty = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList(); - GetAllNestedTypes(type) - .ToList() - .ForEach(e => - { - lstProperty.AddRange(GetAllProperties(e)); - }); - - return lstProperty.Distinct().ToArray(); - } - - public static object InitializeProperties(object obj) - { - const int MAX_DEPTH = 10; // 防止无限递归 - int CUR_DEPTH = 0; - - Func func = null; - func = new Func((obj) => - { - CUR_DEPTH++; - - if (CUR_DEPTH >= MAX_DEPTH) - return obj; - - PropertyInfo[] lstPropInfo = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); - foreach (PropertyInfo propInfo in lstPropInfo) - { - if (propInfo.SetMethod == null || !propInfo.SetMethod.IsPublic) - continue; - - if (propInfo.PropertyType.IsPrimitive) - { - // noop - } - else if (propInfo.PropertyType.IsArray) - { - if (propInfo.PropertyType.FullName.Contains("[][]")) - { - // noop - } - else - { - Type elType = propInfo.PropertyType.Assembly.GetType(propInfo.PropertyType.FullName.Replace("[]", string.Empty)); - object elObj = (elType == typeof(string)) ? string.Empty : Activator.CreateInstance(elType); - elObj = Convert.ChangeType(elObj, elType); - func(elObj); - - Array prop = Array.CreateInstance(elType, 1); - prop.SetValue(elObj, 0); - - propInfo.SetValue(obj, prop); - } - } - else if (propInfo.PropertyType == typeof(string)) - { - propInfo.SetValue(obj, string.Empty); - } - else if (propInfo.PropertyType.Namespace == "System" && - propInfo.PropertyType.Name.StartsWith("Nullable")) - { - // noop - } - else if (propInfo.PropertyType.Namespace == "System.Collections.Generic" && - (propInfo.PropertyType.Name.StartsWith("IDictionary") || propInfo.PropertyType.Name.StartsWith("Dictionary"))) - { - // noop - } - else if (propInfo.PropertyType.Namespace == "System.Collections.Generic" && - (propInfo.PropertyType.Name.StartsWith("IList") || propInfo.PropertyType.Name.StartsWith("List"))) - { - Type elElementType = propInfo.PropertyType.GetGenericArguments().Single(); - object elElementObj = (elElementType == typeof(string)) ? string.Empty : Activator.CreateInstance(elElementType); - elElementObj = Convert.ChangeType(elElementObj, elElementType); - func(elElementObj); - - Type elListType = typeof(List<>).MakeGenericType(new Type[] { elElementType }); - object elListObj = Activator.CreateInstance(elListType); - elListType.GetMethod("Add").Invoke(elListObj, new[] { elElementObj }); - - propInfo.SetValue(obj, elListObj); - } - else - { - object elObj = Activator.CreateInstance(propInfo.PropertyType); - func(elObj); - - propInfo.SetValue(obj, elObj); - } - } - - return obj; - }); - - return func(obj); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj index 9a53d103..d3d7da95 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj @@ -1,7 +1,7 @@  - net472; netcoreapp3.1; net6.0 + net472; net6.0 latest enable true @@ -24,7 +24,8 @@ - + + all @@ -34,7 +35,6 @@ - diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReview.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReview.cs new file mode 100644 index 00000000..2cde4290 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReview.cs @@ -0,0 +1,28 @@ +using SKIT.FlurlHttpClient.Tools.CodeAnalyzer; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests +{ + public class TestCase_CodeReview + { + [Fact(DisplayName = "测试用例:代码质量分析")] + public void TestCodeAnalyzer() + { + Assert.Null(Record.Exception(() => + { + CodeAnalyzerOptions options = new CodeAnalyzerOptions() + { + AssemblyName = "SKIT.FlurlHttpClient.Wechat.Work", + WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk, + WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest, + AllowNotFoundEventTypes = true, + AllowNotFoundEventSamples = true + }; + CodeAnalyzer analyzer = new CodeAnalyzer(options); + analyzer.Start(); + analyzer.Assert(); + analyzer.Flush(); + })); + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs deleted file mode 100644 index dd097d11..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.IO; -using System.Reflection; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests -{ - public class TestCase_CodeReviewAnalyzer - { - private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.Work"); - - [Fact(DisplayName = "代码评审:分析 API 模型命名")] - public void TestApiModelsNaming() - { - CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 模型定义")] - public void TestApiModelsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 事件定义")] - public void TestApiEventsDefinition() - { - string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples"); - CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析 API 接口命名")] - public void TestApiExtensionsNaming() - { - CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - - [Fact(DisplayName = "代码评审:分析代码规范")] - public void TestCodeStyle() - { - string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); - CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); - - if (ex != null) - throw ex; - - Assert.Null(ex); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs index df0f5bb8..5acc91f0 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs @@ -22,8 +22,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests WechatAgentId = int.Parse(config.GetProperty("AgentId").GetString())!; WechatAgentSecret = config.GetProperty("AgentSecret").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; + WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!; + WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!; } catch (Exception ex) { @@ -35,7 +35,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests public static readonly int WechatAgentId; public static readonly string WechatAgentSecret; - public static readonly string ProjectSourceDirectory; - public static readonly string ProjectTestDirectory; + public static readonly string WorkDirectoryForSdk; + public static readonly string WorkDirectoryForTest; } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/appsettings.json b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/appsettings.json index f097e314..82a79009 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/appsettings.json +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/appsettings.json @@ -4,6 +4,6 @@ "AgentId": "请在此填写用于测试的企业微信 AgentId", "AgentSecret": "请在此填写用于测试的企业微信 AgentSecret" }, - "ProjectSourceDirectory": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.Work\\", - "ProjectTestDirectory": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.Work.UnitTests\\" + "WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.Work\\", + "WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.Work.UnitTests\\" } \ No newline at end of file