diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9cb4496c..4dcddab6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,10 @@ on: - 'v2rayN/ServiceLib/Handler/Fmt/**' - '.github/workflows/test.yml' +permissions: + checks: write + pull-requests: write + jobs: test: runs-on: ubuntu-latest @@ -27,4 +31,11 @@ jobs: - name: Test Code working-directory: ./v2rayN - run: dotnet run --project ./ServiceLib.Tests -c Release + run: dotnet test ./ServiceLib.Tests -c Release --no-build --results-directory ./TestResults -- --report-trx + + - name: Comment PR with results + if: always() + uses: EnricoMi/publish-unit-test-result-action@v2 + with: + files: ./v2rayN/TestResults/*.trx + comment_mode: failures diff --git a/v2rayN/Directory.Packages.props b/v2rayN/Directory.Packages.props index bafc2993..ecbd8676 100644 --- a/v2rayN/Directory.Packages.props +++ b/v2rayN/Directory.Packages.props @@ -28,10 +28,12 @@ + + - + \ No newline at end of file diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs index 10531092..73688f67 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs @@ -1,15 +1,8 @@ -using AwesomeAssertions; -using ServiceLib.Enums; -using ServiceLib.Handler.Builder; -using ServiceLib.Helper; -using ServiceLib.Models; -using Xunit; - namespace ServiceLib.Tests.CoreConfig.Context; public class CoreConfigContextBuilderTests { - [Fact] + [Test] public async Task ResolveNodeAsync_DirectCycleDependency_ShouldFailWithCycleError() { var config = CoreConfigTestFactory.CreateConfig(); @@ -27,13 +20,13 @@ public class CoreConfigContextBuilderTests var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false); - validatorResult.Success.Should().BeFalse(); - validatorResult.Errors.Should().Contain(msg => ContainsCycleDependencyMessage(msg)); - context.AllProxiesMap.Should().NotContainKey(groupA.IndexId); - context.AllProxiesMap.Should().NotContainKey(groupB.IndexId); + await validatorResult.Success.Should().BeFalse(); + await validatorResult.Errors.Should().Contain(ContainsCycleDependencyMessage); + await context.AllProxiesMap.Should().NotContainKey(groupA.IndexId); + await context.AllProxiesMap.Should().NotContainKey(groupB.IndexId); } - [Fact] + [Test] public async Task ResolveNodeAsync_IndirectCycleDependency_ShouldFailWithCycleError() { var config = CoreConfigTestFactory.CreateConfig(); @@ -53,14 +46,14 @@ public class CoreConfigContextBuilderTests var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false); - validatorResult.Success.Should().BeFalse(); - validatorResult.Errors.Should().Contain(msg => ContainsCycleDependencyMessage(msg)); - context.AllProxiesMap.Should().NotContainKey(groupA.IndexId); - context.AllProxiesMap.Should().NotContainKey(groupB.IndexId); - context.AllProxiesMap.Should().NotContainKey(groupC.IndexId); + await validatorResult.Success.Should().BeFalse(); + await validatorResult.Errors.Should().Contain(ContainsCycleDependencyMessage); + await context.AllProxiesMap.Should().NotContainKey(groupA.IndexId); + await context.AllProxiesMap.Should().NotContainKey(groupB.IndexId); + await context.AllProxiesMap.Should().NotContainKey(groupC.IndexId); } - [Fact] + [Test] public async Task ResolveNodeAsync_CycleWithValidBranch_ShouldSkipCycleAndKeepValidChild() { var config = CoreConfigTestFactory.CreateConfig(); @@ -80,14 +73,14 @@ public class CoreConfigContextBuilderTests var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false); - validatorResult.Success.Should().BeTrue(); - validatorResult.Errors.Should().BeEmpty(); - validatorResult.Warnings.Should().Contain(msg => ContainsCycleDependencyMessage(msg)); + await validatorResult.Success.Should().BeTrue(); + await validatorResult.Errors.Should().BeEmpty(); + await validatorResult.Warnings.Should().Contain(ContainsCycleDependencyMessage); - context.AllProxiesMap.Should().ContainKey(leaf.IndexId); - context.AllProxiesMap.Should().ContainKey(groupA.IndexId); - context.AllProxiesMap.Should().NotContainKey(groupB.IndexId); - groupA.GetProtocolExtra().ChildItems.Should().Be(leaf.IndexId); + await context.AllProxiesMap.Should().ContainKey(leaf.IndexId); + await context.AllProxiesMap.Should().ContainKey(groupA.IndexId); + await context.AllProxiesMap.Should().NotContainKey(groupB.IndexId); + await groupA.GetProtocolExtra().ChildItems.Should().BeEqualTo(leaf.IndexId); } private static string NewId(string prefix) diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs index f1692f7c..1055a248 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs @@ -1,19 +1,9 @@ -using AwesomeAssertions; -using ServiceLib.Common; -using ServiceLib.Enums; -using ServiceLib.Handler.Fmt; -using ServiceLib.Manager; -using ServiceLib.Models; -using ServiceLib.Models.Dto; -using ServiceLib.Services.CoreConfig; -using Xunit; - namespace ServiceLib.Tests.CoreConfig.Singbox; public class CoreConfigSingboxServiceTests { - [Fact] - public void GenerateClientConfigContent_ShouldGenerateBasicProxyConfig() + [Test] + public async Task GenerateClientConfigContent_ShouldGenerateBasicProxyConfig() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -22,17 +12,17 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); - result.Data.Should().NotBeNull(); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); + await result.Data.Should().NotBeNull(); var singboxConfig = JsonUtils.Deserialize(result.Data!.ToString()); - singboxConfig.Should().NotBeNull(); - singboxConfig!.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "socks"); - singboxConfig.inbounds.Should().Contain(i => i.type == nameof(EInboundProtocol.mixed)); + await singboxConfig.Should().NotBeNull(); + await singboxConfig!.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "socks"); + await singboxConfig.inbounds.Should().Contain(i => i.type == nameof(EInboundProtocol.mixed)); } - [Fact] - public void GenerateClientConfigContent_TunWithLoopbackPreSocks_ShouldKeepMixedInbound() + [Test] + public async Task GenerateClientConfigContent_TunWithLoopbackPreSocks_ShouldKeepMixedInbound() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -46,18 +36,18 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.inbounds.Should().Contain(i => + await cfg.inbounds.Should().Contain(i => i.type == nameof(EInboundProtocol.mixed) && i.listen == Global.Loopback && i.listen_port == AppManager.Instance.GetLocalPort(EInboundProtocol.socks)); - cfg.inbounds.Should().Contain(i => i.type == "tun"); + await cfg.inbounds.Should().Contain(i => i.type == "tun"); } - [Fact] - public void GenerateClientConfigContent_TunEnabled_ShouldKeepEmbeddedTunRules() + [Test] + public async Task GenerateClientConfigContent_TunEnabled_ShouldKeepEmbeddedTunRules() { // The embedded tun rules reject local-network noise (NetBIOS/mDNS, multicast). // They are deserialized into List, so a schema mismatch in the @@ -75,22 +65,22 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.route.rules.Should().Contain( + await cfg.route.rules.Should().Contain( r => r.action == "reject" && r.network != null && r.network.Contains("udp") && r.port != null && r.port.Contains(5353), "the embedded tun rules must reject mDNS/NetBIOS noise"); - cfg.route.rules.Should().Contain( + await cfg.route.rules.Should().Contain( r => r.action == "reject" && r.ip_cidr != null && r.ip_cidr.Contains("224.0.0.0/3"), "the embedded tun rules must reject multicast traffic"); } - [Fact] - public void GenerateClientConfigContent_TunEnabled_ShouldRejectTrafficToTunOwnAddresses() + [Test] + public async Task GenerateClientConfigContent_TunEnabled_ShouldRejectTrafficToTunOwnAddresses() { // Regression test: traffic addressed to the TUN interface's own addresses must // never reach an outbound. auto_route hijacks the default route, so `direct` @@ -111,17 +101,19 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var tun = cfg.inbounds.First(i => i.type == "tun"); - tun.address.Should().NotBeNullOrEmpty(); + //tun.address.Should().NotBeNullOrEmpty(); + await tun.address.Should().NotBeNull(); + await tun.address.Should().NotBeEmpty(); foreach (var address in tun.address!) { var self = IPAddress.Parse(address.Split('/').First()); var hostBits = self.AddressFamily == AddressFamily.InterNetworkV6 ? 128 : 32; var expected = $"{self}/{hostBits}"; - cfg.route.rules.Should().Contain( + await cfg.route.rules.Should().Contain( r => r.action == "reject" && r.ip_cidr != null && r.ip_cidr.Contains(expected), $"traffic to the TUN's own address '{address}' must be rejected, not routed"); } @@ -131,12 +123,13 @@ public class CoreConfigSingboxServiceTests // here leaves room for it, so a prefix match would drop system name lookups too. var dropRule = cfg.route.rules.First(r => r.action == "reject" && r.method == "drop" && r.ip_cidr?.Count > 0); - dropRule.ip_cidr!.Should().OnlyContain(c => - c.EndsWith("/32", StringComparison.Ordinal) || c.EndsWith("/128", StringComparison.Ordinal)); + //dropRule.ip_cidr!.Should().OnlyContain(c => + // c.EndsWith("/32", StringComparison.Ordinal) || c.EndsWith("/128", StringComparison.Ordinal)); + await dropRule.ip_cidr.Should().All(c => c.EndsWith("/32", StringComparison.Ordinal) || c.EndsWith("/128", StringComparison.Ordinal)); } - [Fact] - public void GenerateClientConfigContent_BindInterface_ShouldUseDialBindInterface() + [Test] + public async Task GenerateClientConfigContent_BindInterface_ShouldUseDialBindInterface() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); config.CoreBasicItem.BindInterface = "eth0"; @@ -150,16 +143,16 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var proxy = cfg.outbounds.First(o => o.tag == Global.ProxyTag); - proxy.bind_interface.Should().Be("eth0"); - proxy.detour.Should().BeNullOrEmpty(); + await proxy.bind_interface.Should().BeEqualTo("eth0"); + await proxy.detour.Should().BeNull().Or.BeEmpty(); } - [Fact] - public void GenerateClientConfigContent_PolicyGroup_ShouldExpandChildrenAndBuildSelector() + [Test] + public async Task GenerateClientConfigContent_PolicyGroup_ShouldExpandChildrenAndBuildSelector() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -176,17 +169,17 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "selector"); - cfg.outbounds.Should().Contain(o => o.tag == $"{Global.ProxyTag}-auto" && o.type == "urltest"); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "selector"); + await cfg.outbounds.Should().Contain(o => o.tag == $"{Global.ProxyTag}-auto" && o.type == "urltest"); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); } - [Fact] - public void GenerateClientConfigContent_ProxyChain_ShouldBuildDetourChain() + [Test] + public async Task GenerateClientConfigContent_ProxyChain_ShouldBuildDetourChain() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -203,18 +196,18 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "socks"); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => + await cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "socks"); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && (o.detour ?? string.Empty).StartsWith("chain-proxy-1-", StringComparison.Ordinal)); } - [Fact] - public void GenerateClientConfigContent_PolicyGroupWithProxyChain_ShouldBuildCombinedOutbounds() + [Test] + public async Task GenerateClientConfigContent_PolicyGroupWithProxyChain_ShouldBuildCombinedOutbounds() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -236,18 +229,18 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "selector"); - cfg.outbounds.Should().Contain(o => o.tag == $"{Global.ProxyTag}-auto" && o.type == "urltest"); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "selector"); + await cfg.outbounds.Should().Contain(o => o.tag == $"{Global.ProxyTag}-auto" && o.type == "urltest"); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); } - [Fact] - public void GenerateClientConfigContent_ProxyChainWithPolicyGroup_ShouldBuildClonedChainBranches() + [Test] + public async Task GenerateClientConfigContent_ProxyChainWithPolicyGroup_ShouldBuildClonedChainBranches() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -269,25 +262,25 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "selector"); - cfg.outbounds.Should().Contain(o => o.tag == $"{Global.ProxyTag}-auto" && o.type == "urltest"); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-2-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.type == "selector"); + await cfg.outbounds.Should().Contain(o => o.tag == $"{Global.ProxyTag}-auto" && o.type == "urltest"); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-2-", StringComparison.Ordinal)); var proxyCloneCount = cfg.outbounds.Count(o => o.tag.StartsWith("proxy-clone-", StringComparison.Ordinal)); - proxyCloneCount.Should().Be(2); + await proxyCloneCount.Should().BeEqualTo(2); var allCloneDetoursPointToGroupBranches = cfg.outbounds .Where(o => o.tag.StartsWith("proxy-clone-", StringComparison.Ordinal)) .All(o => (o.detour ?? string.Empty).StartsWith("chain-proxy-1-group-", StringComparison.Ordinal)); - allCloneDetoursPointToGroupBranches.Should().BeTrue(); + await allCloneDetoursPointToGroupBranches.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_RoutingSplit_DirectAndBlock_ShouldApplyRules() + [Test] + public async Task GenerateClientConfigContent_RoutingSplit_DirectAndBlock_ShouldApplyRules() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -323,24 +316,24 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var hasDirectRule = cfg.route.rules.Any(r => r.domain != null && r.domain.Contains("direct.example.com") && r.outbound == Global.DirectTag); - hasDirectRule.Should().BeTrue(); + await hasDirectRule.Should().BeTrue(); var hasBlockRule = cfg.route.rules.Any(r => r.domain != null && r.domain.Contains("block.example.com") && r.action == "reject"); - hasBlockRule.Should().BeTrue(); + await hasBlockRule.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_RoutingSplit_ByRemark_ShouldGenerateTargetOutbound() + [Test] + public async Task GenerateClientConfigContent_RoutingSplit_ByRemark_ShouldGenerateTargetOutbound() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -372,21 +365,21 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var expectedPrefix = $"{routeNode.IndexId}-{Global.ProxyTag}-{routeNode.Remarks}"; - cfg.outbounds.Should().Contain(o => o.tag.StartsWith(expectedPrefix, StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith(expectedPrefix, StringComparison.Ordinal)); var hasRouteRule = cfg.route.rules.Any(r => r.domain != null && r.domain.Contains("route.example.com") && (r.outbound ?? string.Empty).StartsWith(expectedPrefix, StringComparison.Ordinal)); - hasRouteRule.Should().BeTrue(); + await hasRouteRule.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_DirectExpectedIPs_ShouldApplyGeoipAndCidrToDirectDnsRule() + [Test] + public async Task GenerateClientConfigContent_DirectExpectedIPs_ShouldApplyGeoipAndCidrToDirectDnsRule() { var config = CoreConfigTestFactory.CreateConfigWithDirectExpectedIPs( ECoreType.sing_box, @@ -417,7 +410,7 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var hasExpectedRule = cfg.dns.rules?.Any(r => @@ -426,11 +419,11 @@ public class CoreConfigSingboxServiceTests && r.rule_set?.Contains("geosite-cn") == true && r.rule_set?.Contains("geoip-cn") == true) ?? false; - hasExpectedRule.Should().BeTrue(); + await hasExpectedRule.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_BootstrapDNS_ShouldConfigurePureIPResolver() + [Test] + public async Task GenerateClientConfigContent_BootstrapDNS_ShouldConfigurePureIPResolver() { var bootstrapDns = "8.8.8.8"; var config = CoreConfigTestFactory.CreateConfigWithBootstrapDNS(ECoreType.sing_box, bootstrapDns); @@ -441,17 +434,17 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); - config.SimpleDNSItem.BootstrapDNS.Should().Be(bootstrapDns); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); + await config.SimpleDNSItem.BootstrapDNS.Should().BeEqualTo(bootstrapDns); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - var bootstrapServer = cfg.dns.servers?.FirstOrDefault(s => s.tag == Global.SingboxLocalDNSTag); - bootstrapServer.Should().NotBeNull(); - (bootstrapServer?.server ?? string.Empty).Should().Contain(bootstrapDns); + var bootstrapServer = cfg.dns?.servers.FirstOrDefault(s => s.tag == Global.SingboxLocalDNSTag); + await bootstrapServer.Should().NotBeNull(); + await bootstrapServer!.server.Should().Contain(bootstrapDns); } - [Fact] - public void GenerateClientConfigContent_DnsFallback_LastRuleDirect_ShouldUseDirectFinalDns() + [Test] + public async Task GenerateClientConfigContent_DnsFallback_LastRuleDirect_ShouldUseDirectFinalDns() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); config.SimpleDNSItem.DirectDNS = "1.1.1.1"; @@ -484,14 +477,14 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.dns.final.Should().Be(Global.SingboxDirectDNSTag); + await cfg.dns.final.Should().BeEqualTo(Global.SingboxDirectDNSTag); } - [Fact] - public void GenerateClientConfigContent_DirectExpectedIPs_NonMatchingRegion_ShouldNotApplyExpectedRule() + [Test] + public async Task GenerateClientConfigContent_DirectExpectedIPs_NonMatchingRegion_ShouldNotApplyExpectedRule() { var config = CoreConfigTestFactory.CreateConfigWithDirectExpectedIPs(ECoreType.sing_box, "192.168.0.0/16,geoip:cn"); @@ -521,21 +514,21 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var hasExpectedRule = cfg.dns.rules?.Any(r => r.server == Global.SingboxDirectDNSTag && r.ip_cidr?.Contains("192.168.0.0/16") == true && r.rule_set?.Contains("geoip-cn") == true) ?? false; - hasExpectedRule.Should().BeFalse(); + await hasExpectedRule.Should().BeFalse(); } - [Theory] - [InlineData("geosite:cn", "geosite-cn")] - [InlineData("geosite:geolocation-cn", "geosite-geolocation-cn")] - [InlineData("geosite:tld-cn", "geosite-tld-cn")] - public void GenerateClientConfigContent_DirectExpectedIPs_RegionVariant_ShouldApplyExpectedRule(string domainTag, + [Test] + [Arguments("geosite:cn", "geosite-cn")] + [Arguments("geosite:geolocation-cn", "geosite-geolocation-cn")] + [Arguments("geosite:tld-cn", "geosite-tld-cn")] + public async Task GenerateClientConfigContent_DirectExpectedIPs_RegionVariant_ShouldApplyExpectedRule(string domainTag, string expectedRuleSetTag) { var config = @@ -563,7 +556,7 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var hasExpectedRule = cfg.dns.rules?.Any(r => @@ -571,11 +564,11 @@ public class CoreConfigSingboxServiceTests && r.ip_cidr?.Contains("192.168.0.0/16") == true && r.rule_set?.Contains(expectedRuleSetTag) == true && r.rule_set?.Contains("geoip-cn") == true) ?? false; - hasExpectedRule.Should().BeTrue(); + await hasExpectedRule.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_Hosts_ShouldPopulateHostsServerAndDomainResolver() + [Test] + public async Task GenerateClientConfigContent_Hosts_ShouldPopulateHostsServerAndDomainResolver() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); config.SimpleDNSItem.Hosts = "resolver.example 1.1.1.1"; @@ -587,21 +580,21 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var hostsServer = cfg.dns.servers.FirstOrDefault(s => s.tag == Global.SingboxHostsDNSTag); - hostsServer.Should().NotBeNull(); - hostsServer!.predefined.Should().ContainKey("resolver.example"); - hostsServer.predefined!["resolver.example"].Should().Contain("1.1.1.1"); + await hostsServer.Should().NotBeNull(); + await hostsServer!.predefined.Should().ContainKey("resolver.example"); + await hostsServer.predefined!["resolver.example"].Should().Contain("1.1.1.1"); var directServer = cfg.dns.servers.FirstOrDefault(s => s.tag == Global.SingboxDirectDNSTag); - directServer.Should().NotBeNull(); - directServer!.domain_resolver.Should().Be(Global.SingboxHostsDNSTag); + await directServer.Should().NotBeNull(); + await directServer!.domain_resolver.Should().BeEqualTo(Global.SingboxHostsDNSTag); } - [Fact] - public void GenerateClientConfigContent_RawDnsEnabled_ShouldUseCustomDnsAndInjectLocalResolver() + [Test] + public async Task GenerateClientConfigContent_RawDnsEnabled_ShouldUseCustomDnsAndInjectLocalResolver() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -630,22 +623,22 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.dns.servers.Should().Contain(s => s.tag == "remote" && s.type == "udp" && s.server == "8.8.8.8"); - cfg.dns.servers.Should().Contain(s => s.tag == Global.SingboxLocalDNSTag); - cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Global)); - cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Direct)); + await cfg.dns.servers.Should().Contain(s => s.tag == "remote" && s.type == "udp" && s.server == "8.8.8.8"); + await cfg.dns.servers.Should().Contain(s => s.tag == Global.SingboxLocalDNSTag); + await cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Global)); + await cfg.dns.rules.Should().Contain(r => r.clash_mode == nameof(ERuleMode.Direct)); } - [Fact] - public void GenerateClientConfigContent_Hysteria2Realm_ShouldEmitHttpsServerUrl() + [Test] + public async Task GenerateClientConfigContent_Hysteria2Realm_ShouldEmitHttpsServerUrl() { var shareLink = "hysteria2+realm://public@realm.hy2.io/my-realm-id?auth=uuid&stun=turn.cloudflare.com%3A3478&sni=cloudflare.com&pinSHA256=xxx#Realm-Test"; var node = Hysteria2Fmt.ResolveRealm(shareLink, out _); - node.Should().NotBeNull(); + await node.Should().NotBeNull(); node!.CoreType = ECoreType.sing_box; var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); @@ -658,22 +651,22 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var proxy = cfg.outbounds.First(o => o.tag == Global.ProxyTag); - proxy.type.Should().Be("hysteria2"); - proxy.realm.Should().NotBeNull(); - proxy.realm!.server_url.Should().StartWith("https://"); - proxy.realm.server_url.Should().Contain("realm.hy2.io"); - proxy.realm.token.Should().Be("public"); - proxy.realm.realm_id.Should().Be("my-realm-id"); - proxy.realm.stun_servers.Should().Contain("turn.cloudflare.com:3478"); - proxy.server.Should().BeNull(); + await proxy.type.Should().BeEqualTo("hysteria2"); + await proxy.realm.Should().NotBeNull(); + await proxy.realm!.server_url.Should().StartWith("https://"); + await proxy.realm.server_url.Should().Contain("realm.hy2.io"); + await proxy.realm.token.Should().BeEqualTo("public"); + await proxy.realm.realm_id.Should().BeEqualTo("my-realm-id"); + await proxy.realm.stun_servers.Should().Contain("turn.cloudflare.com:3478"); + await proxy.server.Should().BeNull(); } - [Fact] - public void GenerateClientConfigContent_TunSystemStackWithIpv6_ShouldUsePrefixWithPeerAddress() + [Test] + public async Task GenerateClientConfigContent_TunSystemStackWithIpv6_ShouldUsePrefixWithPeerAddress() { // Regression test for #9820: sing-box fails with "need one more IPv6 address in // first prefix for system stack" when the TUN inbound uses a /128 IPv6 prefix. @@ -691,23 +684,24 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var tun = cfg.inbounds.First(i => i.type == "tun"); - tun.address.Should().NotBeNullOrEmpty(); + await tun.address.Should().NotBeNull(); + await tun.address.Should().NotBeEmpty(); foreach (var address in tun.address!) { var prefixLength = int.Parse(address[(address.LastIndexOf('/') + 1)..]); var isIpv6 = address.Contains(':'); - prefixLength.Should().BeLessThanOrEqualTo(isIpv6 ? 126 : 30, + await prefixLength.Should().BeLessThanOrEqualTo(isIpv6 ? 126 : 30, $"'{address}' must leave room for the peer address the system stack derives"); } } - [Fact] - public void GenerateClientConfigContent_CustomOutbound_ShouldReplaceWithUserCustomOutboundJson() + [Test] + public async Task GenerateClientConfigContent_CustomOutbound_ShouldReplaceWithUserCustomOutboundJson() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -728,17 +722,17 @@ public class CoreConfigSingboxServiceTests var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); - result.Data.Should().NotBeNull(); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); + await result.Data.Should().NotBeNull(); var cfg = JsonUtils.Deserialize(result.Data!.ToString()); - cfg.Should().NotBeNull(); + await cfg.Should().NotBeNull(); var proxyOutbound = cfg!.outbounds.FirstOrDefault(o => o.tag == Global.ProxyTag); - proxyOutbound.Should().NotBeNull(); - proxyOutbound!.type.Should().Be("shadowsocks"); - proxyOutbound.server.Should().Be("1.2.3.4"); - proxyOutbound.server_port.Should().Be(8388); - proxyOutbound.method.Should().Be("aes-128-gcm"); - proxyOutbound.password.Should().Be("custom_password"); + await proxyOutbound.Should().NotBeNull(); + await proxyOutbound!.type.Should().BeEqualTo("shadowsocks"); + await proxyOutbound.server.Should().BeEqualTo("1.2.3.4"); + await proxyOutbound.server_port.Should().BeEqualTo(8388); + await proxyOutbound.method.Should().BeEqualTo("aes-128-gcm"); + await proxyOutbound.password.Should().BeEqualTo("custom_password"); } } diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs index bad78c06..ed7154be 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs @@ -1,16 +1,9 @@ -using AwesomeAssertions; -using ServiceLib.Common; -using ServiceLib.Enums; -using ServiceLib.Models; -using ServiceLib.Services.CoreConfig; -using Xunit; - namespace ServiceLib.Tests.CoreConfig.V2ray; public class CoreConfigV2rayServiceTests { - [Fact] - public void GenerateClientConfigContent_ShouldGenerateBasicProxyConfig() + [Test] + public async Task GenerateClientConfigContent_ShouldGenerateBasicProxyConfig() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -19,17 +12,17 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); - result.Data.Should().NotBeNull(); + await result.Success.Should().BeTrue(); + await result.Data.Should().NotBeNull(); var v2rayConfig = JsonUtils.Deserialize(result.Data!.ToString()); - v2rayConfig.Should().NotBeNull(); - v2rayConfig!.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.protocol == "vmess"); - v2rayConfig.inbounds.Should().Contain(i => i.protocol == nameof(EInboundProtocol.mixed)); + await v2rayConfig.Should().NotBeNull(); + await v2rayConfig!.outbounds.Should().Contain(o => o.tag == Global.ProxyTag && o.protocol == "vmess"); + await v2rayConfig.inbounds.Should().Contain(i => i.protocol == nameof(EInboundProtocol.mixed)); } - [Fact] - public void GenerateClientConfigContent_HttpOutbound_ShouldEmitHeadersInSettings() + [Test] + public async Task GenerateClientConfigContent_HttpOutbound_ShouldEmitHeadersInSettings() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -42,27 +35,27 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var outbound = cfg.outbounds.First(o => o.tag == Global.ProxyTag && o.protocol == "http"); - outbound.settings.address?.ToString().Should().Be("proxy.example.com"); - outbound.settings.port.Should().Be(8080); - outbound.settings.user.Should().Be("user"); - outbound.settings.pass.Should().Be("pass"); - outbound.settings.level.Should().Be(1); - outbound.settings.headers.Should().NotBeNull(); - var headers = JsonUtils.ParseJson(outbound.settings.headers.ToString()); - headers["User-Agent"]!.GetValue().Should().Be("v2rayN"); - headers["Set-Cookie"]!.AsArray() + await outbound.settings.address!.ToString().Should().BeEqualTo("proxy.example.com"); + await outbound.settings.port.Should().BeEqualTo(8080); + await outbound.settings.user.Should().BeEqualTo("user"); + await outbound.settings.pass.Should().BeEqualTo("pass"); + await outbound.settings.level.Should().BeEqualTo(1); + await outbound.settings.headers.Should().NotBeNull(); + var headers = JsonUtils.ParseJson(outbound.settings.headers!.ToString()); + await headers["User-Agent"]!.GetValue().Should().BeEqualTo("v2rayN"); + await headers["Set-Cookie"]!.AsArray() .Select(item => item!.GetValue()) - .Should().Equal("a=1", "b=2"); - outbound.settings.servers.Should().BeNull(); - outbound.settings.vnext.Should().BeNull(); + .Should().BeEquivalentTo(["a=1", "b=2"]); + await outbound.settings.servers.Should().BeNull(); + await outbound.settings.vnext.Should().BeNull(); } - [Fact] - public void GenerateClientConfigContent_PolicyGroup_ShouldExpandChildrenAndBuildBalancer() + [Test] + public async Task GenerateClientConfigContent_PolicyGroup_ShouldExpandChildrenAndBuildBalancer() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -79,17 +72,17 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); - cfg.routing.balancers.Should().NotBeNull(); - cfg.routing.balancers!.Should().Contain(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); + await cfg.routing.balancers.Should().NotBeNull(); + await cfg.routing.balancers!.Should().Contain(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix); } - [Fact] - public void GenerateClientConfigContent_ProxyChain_ShouldBuildDialerProxyChain() + [Test] + public async Task GenerateClientConfigContent_ProxyChain_ShouldBuildDialerProxyChain() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -105,21 +98,21 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); var hasDialerChain = cfg.outbounds.Any(o => o.tag == Global.ProxyTag && o.streamSettings is not null && o.streamSettings.sockopt is not null && (o.streamSettings.sockopt.dialerProxy ?? string.Empty).StartsWith("chain-proxy-1-", StringComparison.Ordinal)); - hasDialerChain.Should().BeTrue(); + await hasDialerChain.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_PolicyGroupWithProxyChain_ShouldBuildCombinedOutbounds() + [Test] + public async Task GenerateClientConfigContent_PolicyGroupWithProxyChain_ShouldBuildCombinedOutbounds() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -140,18 +133,18 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); - cfg.routing.balancers.Should().NotBeNull(); - cfg.routing.balancers!.Should().Contain(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("proxy-2-", StringComparison.Ordinal)); + await cfg.routing.balancers.Should().NotBeNull(); + await cfg.routing.balancers!.Should().Contain(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix); } - [Fact] - public void GenerateClientConfigContent_ProxyChainWithPolicyGroup_ShouldBuildClonedChainBranches() + [Test] + public async Task GenerateClientConfigContent_ProxyChainWithPolicyGroup_ShouldBuildClonedChainBranches() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -173,27 +166,27 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-1-", StringComparison.Ordinal)); - cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-2-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-1-", StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith("chain-proxy-1-group-2-", StringComparison.Ordinal)); var proxyCloneCount = cfg.outbounds.Count(o => o.tag.StartsWith("proxy-clone-", StringComparison.Ordinal)); - proxyCloneCount.Should().Be(2); + await proxyCloneCount.Should().BeEqualTo(2); var allCloneDialersPointToGroupBranches = cfg.outbounds .Where(o => o.tag.StartsWith("proxy-clone-", StringComparison.Ordinal)) .All(o => (o.streamSettings?.sockopt?.dialerProxy ?? string.Empty).StartsWith("chain-proxy-1-group-", StringComparison.Ordinal)); - allCloneDialersPointToGroupBranches.Should().BeTrue(); + await allCloneDialersPointToGroupBranches.Should().BeTrue(); - cfg.routing.balancers.Should().NotBeNull(); - cfg.routing.balancers!.Should().Contain(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix); + await cfg.routing.balancers.Should().NotBeNull(); + await cfg.routing.balancers!.Should().Contain(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix); } - [Fact] - public void GenerateClientConfigContent_RoutingSplit_DirectAndBlock_ShouldApplyRules() + [Test] + public async Task GenerateClientConfigContent_RoutingSplit_DirectAndBlock_ShouldApplyRules() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -229,24 +222,24 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var hasDirectRule = cfg.routing.rules.Any(r => r.domain != null && r.domain.Contains("full:direct.example.com") && r.outboundTag == Global.DirectTag); - hasDirectRule.Should().BeTrue(); + await hasDirectRule.Should().BeTrue(); var hasBlockRule = cfg.routing.rules.Any(r => r.domain != null && r.domain.Contains("full:block.example.com") && r.outboundTag == Global.BlockTag); - hasBlockRule.Should().BeTrue(); + await hasBlockRule.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_RoutingSplit_ByRemark_ShouldGenerateTargetOutbound() + [Test] + public async Task GenerateClientConfigContent_RoutingSplit_ByRemark_ShouldGenerateTargetOutbound() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -278,20 +271,20 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var expectedPrefix = $"{routeNode.IndexId}-{Global.ProxyTag}-{routeNode.Remarks}"; - cfg.outbounds.Should().Contain(o => o.tag.StartsWith(expectedPrefix, StringComparison.Ordinal)); + await cfg.outbounds.Should().Contain(o => o.tag.StartsWith(expectedPrefix, StringComparison.Ordinal)); var hasRouteRule = cfg.routing.rules.Any(r => r.domain != null && r.domain.Contains("full:route.example.com") && (r.outboundTag ?? string.Empty).StartsWith(expectedPrefix, StringComparison.Ordinal)); - hasRouteRule.Should().BeTrue(); + await hasRouteRule.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_DirectExpectedIPs_ShouldApplyExpectedIPsToDirectDnsServer() + [Test] + public async Task GenerateClientConfigContent_DirectExpectedIPs_ShouldApplyExpectedIPsToDirectDnsServer() { var config = CoreConfigTestFactory.CreateConfigWithDirectExpectedIPs(ECoreType.Xray, "192.168.0.0/16,geoip:cn"); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -320,7 +313,7 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; @@ -335,11 +328,11 @@ public class CoreConfigV2rayServiceTests && s.domains?.Contains("geosite:cn") == true && s.expectedIPs?.Contains("192.168.0.0/16") == true && s.expectedIPs?.Contains("geoip:cn") == true); - hasExpectedServer.Should().BeTrue(); + await hasExpectedServer.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_BootstrapDNS_ShouldApplyToDnsServerDomains() + [Test] + public async Task GenerateClientConfigContent_BootstrapDNS_ShouldApplyToDnsServerDomains() { var bootstrapDns = "8.8.8.8"; var config = CoreConfigTestFactory.CreateConfigWithBootstrapDNS(ECoreType.Xray, bootstrapDns); @@ -352,7 +345,7 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; @@ -366,11 +359,11 @@ public class CoreConfigV2rayServiceTests s.address == bootstrapDns && s.domains?.Contains("full:dns-direct.example") == true && s.domains?.Contains("full:dns-remote.example") == true); - hasBootstrapServer.Should().BeTrue(); + await hasBootstrapServer.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_DnsFallback_LastRuleDirect_ShouldUseDirectDnsServers() + [Test] + public async Task GenerateClientConfigContent_DnsFallback_LastRuleDirect_ShouldUseDirectDnsServers() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); config.SimpleDNSItem.DirectDNS = "1.1.1.1"; @@ -403,7 +396,7 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; var dnsServers = dns.servers @@ -415,14 +408,14 @@ public class CoreConfigV2rayServiceTests var hasDirectFallback = dnsServers.Any(s => (s.tag ?? string.Empty).StartsWith(Global.DirectDnsTag, StringComparison.Ordinal) && s.address == "1.1.1.1"); - hasDirectFallback.Should().BeTrue(); + await hasDirectFallback.Should().BeTrue(); var hasRemoteFallback = dnsServers.Any(s => s.address == "9.9.9.9"); - hasRemoteFallback.Should().BeFalse(); + await hasRemoteFallback.Should().BeFalse(); } - [Fact] - public void GenerateClientConfigContent_DirectExpectedIPs_NonMatchingRegion_ShouldNotApplyExpectedIPs() + [Test] + public async Task GenerateClientConfigContent_DirectExpectedIPs_NonMatchingRegion_ShouldNotApplyExpectedIPs() { var config = CoreConfigTestFactory.CreateConfigWithDirectExpectedIPs(ECoreType.Xray, "192.168.0.0/16,geoip:cn"); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -451,7 +444,7 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; var dnsServers = dns.servers @@ -463,14 +456,14 @@ public class CoreConfigV2rayServiceTests var hasExpectedIPs = dnsServers.Any(s => s.expectedIPs?.Contains("192.168.0.0/16") == true || s.expectedIPs?.Contains("geoip:cn") == true); - hasExpectedIPs.Should().BeFalse(); + await hasExpectedIPs.Should().BeFalse(); } - [Theory] - [InlineData("geosite:cn")] - [InlineData("geosite:geolocation-cn")] - [InlineData("geosite:tld-cn")] - public void GenerateClientConfigContent_DirectExpectedIPs_RegionVariant_ShouldApplyExpectedIPs(string domainTag) + [Test] + [Arguments("geosite:cn")] + [Arguments("geosite:geolocation-cn")] + [Arguments("geosite:tld-cn")] + public async Task GenerateClientConfigContent_DirectExpectedIPs_RegionVariant_ShouldApplyExpectedIPs(string domainTag) { var config = CoreConfigTestFactory.CreateConfigWithDirectExpectedIPs(ECoreType.Xray, "192.168.0.0/16,geoip:cn"); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -496,7 +489,7 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; var dnsServers = dns.servers @@ -510,11 +503,11 @@ public class CoreConfigV2rayServiceTests && s.domains?.Contains(domainTag) == true && s.expectedIPs?.Contains("192.168.0.0/16") == true && s.expectedIPs?.Contains("geoip:cn") == true); - hasExpectedServer.Should().BeTrue(); + await hasExpectedServer.Should().BeTrue(); } - [Fact] - public void GenerateClientConfigContent_Hosts_ShouldPopulateDnsHosts() + [Test] + public async Task GenerateClientConfigContent_Hosts_ShouldPopulateDnsHosts() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); config.SimpleDNSItem.Hosts = "resolver.example 1.1.1.1"; @@ -525,17 +518,17 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; - dns.hosts.Should().NotBeNull(); - dns.hosts!.Should().ContainKey("resolver.example"); - JsonUtils.Serialize(dns.hosts!["resolver.example"]).Should().Contain("1.1.1.1"); + await dns.hosts.Should().NotBeNull(); + await dns.hosts!.Should().ContainKey("resolver.example"); + await JsonUtils.Serialize(dns.hosts!["resolver.example"]).Should().Contain("1.1.1.1"); } - [Fact] - public void GenerateClientConfigContent_RawDnsEnabled_ShouldUseCustomDnsConfig() + [Test] + public async Task GenerateClientConfigContent_RawDnsEnabled_ShouldUseCustomDnsConfig() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -556,24 +549,24 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var dns = JsonUtils.Deserialize(JsonUtils.Serialize(cfg.dns))!; - JsonUtils.Serialize(dns.servers).Should().Contain("8.8.8.8"); - dns.hosts.Should().NotBeNull(); - dns.hosts!.Should().ContainKey("raw.example"); - JsonUtils.Serialize(dns.hosts!["raw.example"]).Should().Contain("1.1.1.1"); + await JsonUtils.Serialize(dns.servers).Should().Contain("8.8.8.8"); + await dns.hosts.Should().NotBeNull(); + await dns.hosts!.Should().ContainKey("raw.example"); + await JsonUtils.Serialize(dns.hosts!["raw.example"]).Should().Contain("1.1.1.1"); var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom"); - directOutbound.Should().NotBeNull(); - directOutbound!.streamSettings.sockopt!.domainStrategy.Should().Be("UseIPv4"); + await directOutbound.Should().NotBeNull(); + await directOutbound!.streamSettings.sockopt!.domainStrategy.Should().BeEqualTo("UseIPv4"); } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void GenerateClientConfigContent_Tun_ShouldRouteIPv6IntoTunnel(bool enableIPv6Address) + [Test] + [Arguments(false)] + [Arguments(true)] + public async Task GenerateClientConfigContent_Tun_ShouldRouteIPv6IntoTunnel(bool enableIPv6Address) { var config = CoreConfigTestFactory.CreateConfigWithTun(ECoreType.Xray, enableIPv6Address); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -583,20 +576,20 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var tunInbound = cfg.inbounds.FirstOrDefault(i => i.protocol == "tun"); - tunInbound.Should().NotBeNull(); - tunInbound!.settings.autoSystemRoutingTable.Should().Contain("0.0.0.0/0"); - tunInbound.settings.autoSystemRoutingTable.Should().Contain("::/0"); + await tunInbound.Should().NotBeNull(); + await tunInbound!.settings.autoSystemRoutingTable.Should().Contain("0.0.0.0/0"); + await tunInbound.settings.autoSystemRoutingTable.Should().Contain("::/0"); // EnableIPv6Address governs the interface address only, never the routing table. - tunInbound.settings.gateway.Should().HaveCount(enableIPv6Address ? 2 : 1); + await tunInbound.settings.gateway.Should().HaveCount(enableIPv6Address ? 2 : 1); } - [Fact] - public void GenerateClientConfigContent_TunRouteExcludeAddress_ShouldIncludeIPv6Ranges() + [Test] + public async Task GenerateClientConfigContent_TunRouteExcludeAddress_ShouldIncludeIPv6Ranges() { var config = CoreConfigTestFactory.CreateConfigWithTunRouteExcludeAddress(ECoreType.Xray); config.TunModeItem.EnableIPv6Address = false; @@ -607,16 +600,16 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var tunInbound = cfg.inbounds.FirstOrDefault(i => i.protocol == "tun"); - tunInbound.Should().NotBeNull(); - tunInbound!.settings.autoSystemRoutingTable.Should().Contain(x => x.Contains(':')); + await tunInbound.Should().NotBeNull(); + await tunInbound!.settings.autoSystemRoutingTable.Should().Contain(x => x.Contains(':')); } - [Fact] - public void GenerateClientConfigContent_TunRouteExcludeAddress() + [Test] + public async Task GenerateClientConfigContent_TunRouteExcludeAddress() { var config = CoreConfigTestFactory.CreateConfigWithTunRouteExcludeAddress(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -626,20 +619,20 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue(); + await result.Success.Should().BeTrue(); var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; var tunInbound = cfg.inbounds.FirstOrDefault(i => i.protocol == "tun"); - tunInbound.Should().NotBeNull(); + await tunInbound.Should().NotBeNull(); - tunInbound!.settings.autoSystemRoutingTable.Should().NotContain("0.0.0.0/0"); - tunInbound!.settings.autoSystemRoutingTable.Should().Contain("10.0.0.0/32"); - tunInbound!.settings.autoSystemRoutingTable.Should().Contain("10.0.0.2/31"); + await tunInbound!.settings.autoSystemRoutingTable.Should().NotContain("0.0.0.0/0"); + await tunInbound!.settings.autoSystemRoutingTable.Should().Contain("10.0.0.0/32"); + await tunInbound!.settings.autoSystemRoutingTable.Should().Contain("10.0.0.2/31"); } - [Fact] - public void GenerateClientConfigContent_CustomOutbound_ShouldReplaceWithUserCustomOutboundJson() + [Test] + public async Task GenerateClientConfigContent_CustomOutbound_ShouldReplaceWithUserCustomOutboundJson() { var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray); CoreConfigTestFactory.BindAppManagerConfig(config); @@ -666,14 +659,14 @@ public class CoreConfigV2rayServiceTests var result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); - result.Success.Should().BeTrue($"ret msg: {result.Msg}"); - result.Data.Should().NotBeNull(); + await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}"); + await result.Data.Should().NotBeNull(); var cfg = JsonUtils.Deserialize(result.Data!.ToString()); - cfg.Should().NotBeNull(); + await cfg.Should().NotBeNull(); var proxyOutbound = cfg!.outbounds.FirstOrDefault(o => o.tag == Global.ProxyTag); - proxyOutbound.Should().NotBeNull(); - proxyOutbound!.protocol.Should().Be("shadowsocks"); - proxyOutbound.settings.servers.Should().NotBeNull(); + await proxyOutbound.Should().NotBeNull(); + await proxyOutbound!.protocol.Should().BeEqualTo("shadowsocks"); + await proxyOutbound.settings.servers.Should().NotBeNull(); } } diff --git a/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs b/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs index 143fa3e5..bca21685 100644 --- a/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs +++ b/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs @@ -1,103 +1,99 @@ -using AwesomeAssertions; -using ServiceLib.Enums; -using ServiceLib.Handler.Fmt; -using ServiceLib.Models; -using Xunit; - namespace ServiceLib.Tests.Fmt; public class FmtHandlerTests { - [Fact] - public void GetShareUriAndResolveConfig_Vmess_ShouldRoundTripBasicFields() + [Test] + public async Task GetShareUriAndResolveConfig_Vmess_ShouldRoundTripBasicFields() { var source = CreateVmessProfile(); - var resolved = ExportThenImport(source); + var resolved = await ExportThenImport(source); - resolved.ConfigType.Should().Be(EConfigType.VMess); - resolved.Remarks.Should().Be(source.Remarks); - resolved.Address.Should().Be(source.Address); - resolved.Port.Should().Be(source.Port); - resolved.Password.Should().Be(source.Password); - resolved.GetProtocolExtra().AlterId.Should().Be(source.GetProtocolExtra().AlterId); + await resolved.ConfigType.Should().BeEqualTo(EConfigType.VMess); + await resolved.Remarks.Should().BeEqualTo(source.Remarks); + await resolved.Address.Should().BeEqualTo(source.Address); + await resolved.Port.Should().BeEqualTo(source.Port); + await resolved.Password.Should().BeEqualTo(source.Password); + await resolved.GetProtocolExtra().AlterId.Should().BeEqualTo(source.GetProtocolExtra().AlterId); } - [Fact] - public void GetShareUriAndResolveConfig_Vless_ShouldRoundTripBasicFields() + [Test] + public async Task GetShareUriAndResolveConfig_Vless_ShouldRoundTripBasicFields() { var source = CreateVlessProfile(); - var resolved = ExportThenImport(source); + var resolved = await ExportThenImport(source); - resolved.ConfigType.Should().Be(EConfigType.VLESS); - resolved.Remarks.Should().Be(source.Remarks); - resolved.Address.Should().Be(source.Address); - resolved.Port.Should().Be(source.Port); - resolved.Password.Should().Be(source.Password); - resolved.GetProtocolExtra().VlessEncryption.Should().Be(Global.None); + await resolved.ConfigType.Should().BeEqualTo(EConfigType.VLESS); + await resolved.Remarks.Should().BeEqualTo(source.Remarks); + await resolved.Address.Should().BeEqualTo(source.Address); + await resolved.Port.Should().BeEqualTo(source.Port); + await resolved.Password.Should().BeEqualTo(source.Password); + await resolved.GetProtocolExtra().VlessEncryption.Should().BeEqualTo(Global.None); } - [Fact] - public void GetShareUriAndResolveConfig_Shadowsocks_ShouldRoundTripBasicFields() + [Test] + public async Task GetShareUriAndResolveConfig_Shadowsocks_ShouldRoundTripBasicFields() { var source = CreateShadowsocksProfile(); - var resolved = ExportThenImport(source); + var resolved = await ExportThenImport(source); - resolved.ConfigType.Should().Be(EConfigType.Shadowsocks); - resolved.Remarks.Should().Be(source.Remarks); - resolved.Address.Should().Be(source.Address); - resolved.Port.Should().Be(source.Port); - resolved.Password.Should().Be(source.Password); - resolved.GetProtocolExtra().SsMethod.Should().Be(source.GetProtocolExtra().SsMethod); + await resolved.ConfigType.Should().BeEqualTo(EConfigType.Shadowsocks); + await resolved.Remarks.Should().BeEqualTo(source.Remarks); + await resolved.Address.Should().BeEqualTo(source.Address); + await resolved.Port.Should().BeEqualTo(source.Port); + await resolved.Password.Should().BeEqualTo(source.Password); + await resolved.GetProtocolExtra().SsMethod.Should().BeEqualTo(source.GetProtocolExtra().SsMethod); } - [Fact] - public void GetShareUriAndResolveConfig_Socks_ShouldRoundTripBasicFields() + [Test] + public async Task GetShareUriAndResolveConfig_Socks_ShouldRoundTripBasicFields() { var source = CreateSocksProfile(); - var resolved = ExportThenImport(source); + var resolved = await ExportThenImport(source); - resolved.ConfigType.Should().Be(EConfigType.SOCKS); - resolved.Remarks.Should().Be(source.Remarks); - resolved.Address.Should().Be(source.Address); - resolved.Port.Should().Be(source.Port); - resolved.Username.Should().Be(source.Username); - resolved.Password.Should().Be(source.Password); + await resolved.ConfigType.Should().BeEqualTo(EConfigType.SOCKS); + await resolved.Remarks.Should().BeEqualTo(source.Remarks); + await resolved.Address.Should().BeEqualTo(source.Address); + await resolved.Port.Should().BeEqualTo(source.Port); + await resolved.Username.Should().BeEqualTo(source.Username); + await resolved.Password.Should().BeEqualTo(source.Password); } - [Fact] - public void ResolveConfig_UnsupportedProtocol_ShouldReturnNull() + [Test] + public async Task ResolveConfig_UnsupportedProtocol_ShouldReturnNull() { var resolved = FmtHandler.ResolveConfig("not-a-share-uri", out var msg); - resolved.Should().BeNull(); - msg.Should().NotBeNullOrWhiteSpace(); + await resolved.Should().BeNull(); + await msg.Should().NotBeNull(); + await msg.Should().NotBeEmpty(); } - [Fact] - public void GetShareUri_UnsupportedConfigType_ShouldReturnNull() + [Test] + public async Task GetShareUri_UnsupportedConfigType_ShouldReturnNull() { var item = new ProfileItem { ConfigType = EConfigType.PolicyGroup, Remarks = "group", }; var uri = FmtHandler.GetShareUri(item); - uri.Should().BeNull(); + await uri.Should().BeNull(); } - private static ProfileItem ExportThenImport(ProfileItem source) + private static async Task ExportThenImport(ProfileItem source) { var uri = FmtHandler.GetShareUri(source); - uri.Should().NotBeNullOrWhiteSpace(); - uri!.StartsWith(Global.ProtocolShares[source.ConfigType], StringComparison.OrdinalIgnoreCase).Should() + await uri.Should().NotBeNull(); + await uri.Should().NotBeEmpty(); + await uri!.StartsWith(Global.ProtocolShares[source.ConfigType], StringComparison.OrdinalIgnoreCase).Should() .BeTrue(); var resolved = FmtHandler.ResolveConfig(uri, out var msg); - resolved.Should().NotBeNull($"uri: {uri}, msg: {msg}"); + await resolved.Should().NotBeNull().Because($"uri: {uri}, msg: {msg}"); return resolved!; } diff --git a/v2rayN/ServiceLib.Tests/Fmt/HyRealmTests.cs b/v2rayN/ServiceLib.Tests/Fmt/HyRealmTests.cs index 3cce2ed5..42eb5e86 100644 --- a/v2rayN/ServiceLib.Tests/Fmt/HyRealmTests.cs +++ b/v2rayN/ServiceLib.Tests/Fmt/HyRealmTests.cs @@ -1,32 +1,27 @@ -using AwesomeAssertions; -using ServiceLib.Handler.Fmt; -using ServiceLib.Models.Dto; -using Xunit; - namespace ServiceLib.Tests.Fmt; public class HyRealmTests { - [Fact] - public void TryParse_ShouldParseValidRealm() + [Test] + public async Task TryParse_ShouldParseValidRealm() { var str = "realm://public@realm.hy2.io/57f9be7c-2810-4f5b-8cb9-260bc84d6c90?stun=example.stun:3478&stun=example2.stun:3478"; var result = HyRealm.TryParse(str, out var realm); - result.Should().BeTrue(); - realm.Should().NotBeNull(); + await result.Should().BeTrue(); + await realm.Should().NotBeNull(); - realm.IsHttp.Should().BeFalse(); - realm.Token.Should().Be("public"); - realm.RendezvousHost.Should().Be("realm.hy2.io"); - realm.RendezvousPort.Should().Be(443); - realm.RealmName.Should().Be("57f9be7c-2810-4f5b-8cb9-260bc84d6c90"); - realm.StunList.Should().HaveCount(2); - realm.StunList.Should().Contain("example.stun:3478"); - realm.StunList.Should().Contain("example2.stun:3478"); + await realm.IsHttp.Should().BeFalse(); + await realm.Token.Should().BeEqualTo("public"); + await realm.RendezvousHost.Should().BeEqualTo("realm.hy2.io"); + await realm.RendezvousPort.Should().BeEqualTo(443); + await realm.RealmName.Should().BeEqualTo("57f9be7c-2810-4f5b-8cb9-260bc84d6c90"); + await realm.StunList.Should().HaveCount(2); + await realm.StunList.Should().Contain("example.stun:3478"); + await realm.StunList.Should().Contain("example2.stun:3478"); } - [Fact] - public void ToUri_ShouldGenerateValidUri() + [Test] + public async Task ToUri_ShouldGenerateValidUri() { var realm = new HyRealm( IsHttp: false, @@ -37,32 +32,32 @@ public class HyRealmTests StunList: ["example.stun:3478", "example2.stun:3478"] ); var uri = realm.ToUri(); - uri.Should().Contain("realm://public@realm.hy2.io"); - uri.Should().Contain("/57f9be7c-2810-4f5b-8cb9-260bc84d6c90"); - uri.Should().Contain("stun=example.stun:3478"); - uri.Should().Contain("stun=example2.stun:3478"); + await uri.Should().Contain("realm://public@realm.hy2.io"); + await uri.Should().Contain("/57f9be7c-2810-4f5b-8cb9-260bc84d6c90"); + await uri.Should().Contain("stun=example.stun:3478"); + await uri.Should().Contain("stun=example2.stun:3478"); } - [Fact] - public void GetShareUriAndResolveConfig_Hy2Realm_ShouldRoundTripBasicFields() + [Test] + public async Task GetShareUriAndResolveConfig_Hy2Realm_ShouldRoundTripBasicFields() { var str = "hysteria2+realm://mytoken@rendezvous.example.com/my-cabin-1f3a8c2e9b?auth=your_password&insecure=1&pinSHA256=deadbeef#remark"; var resolved = Hysteria2Fmt.ResolveRealm(str, out var msg); - resolved.Should().NotBeNull(); - resolved.Password.Should().Be("your_password"); + await resolved.Should().NotBeNull(); + await resolved.Password.Should().BeEqualTo("your_password"); var result = HyRealm.TryParse(resolved.GetProtocolExtra().Hy2RealmUrl, out var realm); - result.Should().BeTrue(); - realm.Should().NotBeNull(); - realm.Token.Should().Be("mytoken"); + await result.Should().BeTrue(); + await realm.Should().NotBeNull(); + await realm.Token.Should().BeEqualTo("mytoken"); // To uri var uri = Hysteria2Fmt.ToUri(resolved); - uri.Should().Contain("hysteria2+realm://mytoken@rendezvous.example.com"); - uri.Should().EndWith("#remark"); + await uri.Should().Contain("hysteria2+realm://mytoken@rendezvous.example.com"); + await uri.Should().EndWith("#remark"); } - [Fact] - public void ToServerUrl_ShouldIncludeSchemeForSingbox() + [Test] + public async Task ToServerUrl_ShouldIncludeSchemeForSingbox() { var realm = new HyRealm( IsHttp: false, @@ -73,19 +68,19 @@ public class HyRealmTests StunList: ["turn.cloudflare.com:3478"] ); - realm.ToServerUrl().Should().Be("https://realm.hy2.io:443"); + await realm.ToServerUrl().Should().BeEqualTo("https://realm.hy2.io:443"); } - [Fact] - public void ResolveRealm_Issue9635_ShouldProduceHttpsServerUrl() + [Test] + public async Task ResolveRealm_Issue9635_ShouldProduceHttpsServerUrl() { var str = "hysteria2+realm://public@realm.hy2.io/my-realm-id?auth=uuid&stun=turn.cloudflare.com%3A3478&sni=cloudflare.com&pinSHA256=xxx#Realm-Test"; var resolved = Hysteria2Fmt.ResolveRealm(str, out _); - resolved.Should().NotBeNull(); + await resolved.Should().NotBeNull(); - HyRealm.TryParse(resolved!.GetProtocolExtra().Hy2RealmUrl, out var realm).Should().BeTrue(); - realm!.ToServerUrl().Should().StartWith("https://"); - realm.ToServerUrl().Should().Contain("realm.hy2.io"); - realm.StunList.Should().Contain("turn.cloudflare.com:3478"); + await HyRealm.TryParse(resolved!.GetProtocolExtra().Hy2RealmUrl, out var realm).Should().BeTrue(); + await realm!.ToServerUrl().Should().StartWith("https://"); + await realm.ToServerUrl().Should().Contain("realm.hy2.io"); + await realm.StunList.Should().Contain("turn.cloudflare.com:3478"); } } diff --git a/v2rayN/ServiceLib.Tests/Fmt/InnerFmtTests.cs b/v2rayN/ServiceLib.Tests/Fmt/InnerFmtTests.cs index 91df67f4..962fdd82 100644 --- a/v2rayN/ServiceLib.Tests/Fmt/InnerFmtTests.cs +++ b/v2rayN/ServiceLib.Tests/Fmt/InnerFmtTests.cs @@ -1,15 +1,11 @@ -using AwesomeAssertions; -using ServiceLib.Enums; -using ServiceLib.Handler.Fmt; using ServiceLib.Tests.CoreConfig; -using Xunit; namespace ServiceLib.Tests.Fmt; public class InnerFmtTests { - [Fact] - public void ToUriAndResolve_ShouldRoundTripPolicyGroupReferences() + [Test] + public async Task ToUriAndResolve_ShouldRoundTripPolicyGroupReferences() { var childA = CoreConfigTestFactory.CreateSocksNode(ECoreType.Xray, "child-a", "child-a"); var childB = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray, "child-b", "child-b"); @@ -19,19 +15,20 @@ public class InnerFmtTests var uri = InnerFmt.ToUri([group, childA, childB]); - uri.Should().NotBeNullOrWhiteSpace(); + await uri.Should().NotBeNull(); + await uri.Should().NotBeEmpty(); var resolved = InnerFmt.Resolve(uri!, "sub-123"); - resolved.Should().NotBeNull(); - resolved.Should().HaveCount(3); + await resolved.Should().NotBeNull(); + await resolved.Should().HaveCount(3); var resolvedGroup = resolved!.Single(x => x.Remarks == group.Remarks); var resolvedChildA = resolved.Single(x => x.Remarks == childA.Remarks); var resolvedChildB = resolved.Single(x => x.Remarks == childB.Remarks); - resolvedGroup.ConfigType.Should().Be(EConfigType.PolicyGroup); - resolvedGroup.GetProtocolExtra().SubChildItems.Should().Be("sub-123"); - resolvedGroup.GetProtocolExtra().ChildItems.Should().Be($"{resolvedChildA.IndexId},{resolvedChildB.IndexId}"); + await resolvedGroup.ConfigType.Should().BeEqualTo(EConfigType.PolicyGroup); + await resolvedGroup.GetProtocolExtra().SubChildItems.Should().BeEqualTo("sub-123"); + await resolvedGroup.GetProtocolExtra().ChildItems.Should().BeEqualTo($"{resolvedChildA.IndexId},{resolvedChildB.IndexId}"); } } diff --git a/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs b/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs index 717fa1bc..8f156b47 100644 --- a/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs +++ b/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs @@ -1,13 +1,9 @@ -using AwesomeAssertions; -using ServiceLib.Handler.Fmt; -using Xunit; - namespace ServiceLib.Tests.Fmt; public class WireguardFmtTests { - [Fact] - public void ResolveConfig_ShouldParsePeersAndIgnoreInlineComments() + [Test] + public async Task ResolveConfig_ShouldParsePeersAndIgnoreInlineComments() { const string config = """ @@ -29,19 +25,19 @@ public class WireguardFmtTests var resolved = WireguardFmt.ResolveConfig(config); - resolved.Should().NotBeNull(); - resolved.Should().HaveCount(2); + await resolved.Should().NotBeNull(); + await resolved.Should().HaveCount(2); var first = resolved![0]; - first.Address.Should().Be("2001:db8::1"); - first.Port.Should().Be(51820); - first.Password.Should().Be("interface-private-key"); - first.GetProtocolExtra().WgReserved.Should().Be("1, 2, 3"); - first.GetProtocolExtra().WgInterfaceAddress.Should().Be("10.0.0.2/32, fd00::2/128"); - first.GetProtocolExtra().WgMtu.Should().Be(1420); + await first.Address.Should().BeEqualTo("2001:db8::1"); + await first.Port.Should().BeEqualTo(51820); + await first.Password.Should().BeEqualTo("interface-private-key"); + await first.GetProtocolExtra().WgReserved.Should().BeEqualTo("1, 2, 3"); + await first.GetProtocolExtra().WgInterfaceAddress.Should().BeEqualTo("10.0.0.2/32, fd00::2/128"); + await first.GetProtocolExtra().WgMtu.Should().BeEqualTo(1420); var second = resolved[1]; - second.Address.Should().Be("example.com"); - second.Port.Should().Be(12345); + await second.Address.Should().BeEqualTo("example.com"); + await second.Port.Should().BeEqualTo(12345); } } diff --git a/v2rayN/ServiceLib.Tests/Manager/CoreManagerTests.cs b/v2rayN/ServiceLib.Tests/Manager/CoreManagerTests.cs index d4135758..0c7f0ebc 100644 --- a/v2rayN/ServiceLib.Tests/Manager/CoreManagerTests.cs +++ b/v2rayN/ServiceLib.Tests/Manager/CoreManagerTests.cs @@ -1,44 +1,39 @@ -using AwesomeAssertions; -using ServiceLib.Enums; -using ServiceLib.Manager; -using Xunit; - namespace ServiceLib.Tests.Manager; public class CoreManagerTests { - [Theory] - [InlineData(ECoreType.sing_box)] - [InlineData(ECoreType.mihomo)] - [InlineData(ECoreType.Xray)] - public void ShouldRunAsSudo_TunLaunchOnNonWindows_RequiresElevation(ECoreType coreType) + [Test] + [Arguments(ECoreType.sing_box)] + [Arguments(ECoreType.mihomo)] + [Arguments(ECoreType.Xray)] + public async Task ShouldRunAsSudo_TunLaunchOnNonWindows_RequiresElevation(ECoreType coreType) { - CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeTrue(); + await CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeTrue(); } - [Fact] - public void ShouldRunAsSudo_NonTunLaunch_ShouldNotElevate() + [Test] + public async Task ShouldRunAsSudo_NonTunLaunch_ShouldNotElevate() { // Regression guard for the macOS TUN failure: the elevation decision must follow // the context snapshot that generated the config. A launch whose snapshot has TUN // disabled must never elevate, and a launch whose snapshot has TUN enabled must // elevate regardless of later changes to the live config. - CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.sing_box, isNonWindows: true).Should().BeFalse(); - CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.Xray, isNonWindows: true).Should().BeFalse(); + await CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.sing_box, isNonWindows: true).Should().BeFalse(); + await CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.Xray, isNonWindows: true).Should().BeFalse(); } - [Fact] - public void ShouldRunAsSudo_OnWindows_ShouldNotElevate() + [Test] + public async Task ShouldRunAsSudo_OnWindows_ShouldNotElevate() { - CoreManager.ShouldRunAsSudo(isTunLaunch: true, ECoreType.sing_box, isNonWindows: false).Should().BeFalse(); + await CoreManager.ShouldRunAsSudo(isTunLaunch: true, ECoreType.sing_box, isNonWindows: false).Should().BeFalse(); } - [Theory] - [InlineData(ECoreType.v2fly)] - [InlineData(ECoreType.hysteria)] - [InlineData(null)] - public void ShouldRunAsSudo_UnsupportedCoreType_ShouldNotElevate(ECoreType? coreType) + [Test] + [Arguments(ECoreType.v2fly)] + [Arguments(ECoreType.hysteria)] + [Arguments(null)] + public async Task ShouldRunAsSudo_UnsupportedCoreType_ShouldNotElevate(ECoreType? coreType) { - CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeFalse(); + await CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeFalse(); } } diff --git a/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj b/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj index adefda0d..2dd3c7a3 100644 --- a/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj +++ b/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj @@ -1,18 +1,23 @@ - - Exe - false - true - + + Exe + false + enable + - - - - + + + + - - - + + + + + + + +