mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-04-05 08:37:22 +08:00
test: 引入代码分析器工具
This commit is contained in:
parent
ab96ebba31
commit
022ef5bc71
@ -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}
|
||||
|
6
test/NuGet.config
Normal file
6
test/NuGet.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" value="https://www.myget.org/F/skit/api/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
@ -22,7 +22,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -32,7 +33,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.Ads\SKIT.FlurlHttpClient.Wechat.Ads.csproj" />
|
||||
<ProjectReference Include="..\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\\"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
@ -24,7 +24,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -34,7 +35,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.Api\SKIT.FlurlHttpClient.Wechat.Api.csproj" />
|
||||
<ProjectReference Include="..\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\\"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
@ -23,7 +23,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -33,7 +34,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.OpenAI\SKIT.FlurlHttpClient.Wechat.OpenAI.csproj" />
|
||||
<ProjectReference Include="..\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\\"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
@ -25,7 +25,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -35,7 +36,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.TenpayV2\SKIT.FlurlHttpClient.Wechat.TenpayV2.csproj" />
|
||||
<ProjectReference Include="..\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\\"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
@ -23,7 +23,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -33,7 +34,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.TenpayV3\SKIT.FlurlHttpClient.Wechat.TenpayV3.csproj" />
|
||||
<ProjectReference Include="..\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\\"
|
||||
}
|
@ -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<Newtonsoft.Json.JsonPropertyAttribute>(inherit: true);
|
||||
var systemTextJsonAttribute = propInfo.GetCustomAttribute<System.Text.Json.Serialization.JsonPropertyNameAttribute>(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<System.Xml.XmlNode, Exception> fn = default;
|
||||
fn = new Func<System.Xml.XmlNode, Exception>((xmlNode) =>
|
||||
{
|
||||
if (xmlNode.NodeType == System.Xml.XmlNodeType.Element)
|
||||
{
|
||||
PropertyInfo[] lstPropInfo = TestReflectionUtil.GetAllProperties(type);
|
||||
var xmlElementAttributes = lstPropInfo.SelectMany(e => e.GetCustomAttributes<XmlElementAttribute>(inherit: true)).ToArray();
|
||||
var xmlArrayAttributes = lstPropInfo.SelectMany(e => e.GetCustomAttributes<XmlArrayAttribute>(inherit: true)).ToArray();
|
||||
var xmlArrayItemAttributes = lstPropInfo.SelectMany(e => e.GetCustomAttributes<XmlArrayItemAttribute>(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<Exception>();
|
||||
|
||||
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<Exception>();
|
||||
|
||||
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<Exception>();
|
||||
|
||||
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<Exception>();
|
||||
|
||||
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<Exception>();
|
||||
|
||||
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[] { "<summary>" }, 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;
|
||||
|
||||
// 匹配 <para> ... </para> 结构
|
||||
var regexPara = new Regex("<para(([\\s\\S])*?)</para>").Match(sourceCode);
|
||||
if (!regexPara.Success)
|
||||
{
|
||||
lstError.Add(new Exception($"[风格] 源代码 \"{extCodeFileName}\" 下第 {i + 1} 段文档注释不齐全,未能匹配到 \"<para> ... </para>\"。"));
|
||||
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);
|
||||
|
||||
// 匹配 <para> ... </para> 结构
|
||||
var regexPara = new Regex("<para(([\\s\\S])*?)</para>").Match(reqCodeSourceCode);
|
||||
if (!regexPara.Success)
|
||||
{
|
||||
lstError.Add(new Exception($"[风格] 源代码 \"{reqCodeFileName}\" 下文档注释不齐全,未能匹配到 \"<para> ... </para>\"。"));
|
||||
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);
|
||||
|
||||
// 匹配 <para> ... </para> 结构
|
||||
var regexPara = new Regex("<para(([\\s\\S])*?)</para>").Match(resCodeSourceCode);
|
||||
if (!regexPara.Success)
|
||||
{
|
||||
lstError.Add(new Exception($"[风格] 源代码 \"{resCodeFileName}\" 下文档注释不齐全,未能匹配到 \"<para> ... </para>\"。"));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Common" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -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<string> results = new List<string>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Type> lstType = new List<Type>();
|
||||
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<object, object> func = null;
|
||||
func = new Func<object, object>((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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472; netcoreapp3.1; net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net472; net6.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NullableReferenceTypes>true</NullableReferenceTypes>
|
||||
@ -24,7 +24,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@ -34,7 +35,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SKIT.FlurlHttpClient.Wechat.Work\SKIT.FlurlHttpClient.Wechat.Work.csproj" />
|
||||
<ProjectReference Include="..\SKIT.FlurlHttpClient.Wechat.TestTools\SKIT.FlurlHttpClient.Wechat.TestTools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\\"
|
||||
}
|
Loading…
Reference in New Issue
Block a user