mirror of
https://github.com/2dust/v2rayN.git
synced 2026-08-01 04:42:04 +03:00
* deps: bump ZXing.Net.Bindings.SkiaSharp from 0.16.14 to 0.16.22 Patch update to the latest stable release on the 0.16.x line. No breaking changes, no public API changes - purely internal fixes. Verified by a full Release build of v2rayN.sln on .NET 10; no new warnings or errors are introduced. * chore: remove NoWarn and fix .NET 10 build warnings Removes the repository-level NoWarn suppression from Directory.Build.props and addresses the warnings that surface on top of the .NET 10 migration in #9179, keeping Debug, Release, and cross-platform publishes warning-free without suppressing warnings globally. Changes: - Removes <NoWarn>CA1031;CS1591;NU1507;CA1416;IDE0058;IDE0053;IDE0200</NoWarn> from Directory.Build.props. - Annotates Windows-only APIs with [SupportedOSPlatform] and [SupportedOSPlatformGuard] so CA1416 accepts that the Windows surface is gated behind Utils.IsWindows() / Utils.IsNonWindows(). - Splits Utils.SetUnixFileMode into a cross-platform wrapper and a private [UnsupportedOSPlatform("windows")] implementation so File.SetUnixFileMode never reaches the analyzer on Windows builds. - Adds a parameterless constructor to MessageBoxDialog so Avalonia's runtime XAML loader (AVLN3001) can instantiate the dialog. - Moves the WPF high-DPI configuration from app.manifest to <ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode> in v2rayN.csproj, fixing WFO0003. - Adds global using System.Runtime.Versioning; to ServiceLib and v2rayN.Desktop so the platform attributes are usable project-wide. * test: make cycle dependency tests locale-independent Accept the localized Russian cycle dependency diagnostic in CoreConfigContextBuilderTests so the assertions pass when tests run under a Russian UI culture. * fix: tighten Unix platform handling Adds Linux and macOS platform guards so the analyzer can narrow calls through Utils.IsLinux() and Utils.IsMacOS(). Marks the Linux/macOS autostart and system proxy helpers with explicit platform attributes. Updates Utils.GetSystemHosts() to read /etc/hosts on Linux and macOS while keeping the existing Windows hosts and hosts.ics merge behavior.
115 lines
4.9 KiB
C#
115 lines
4.9 KiB
C#
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]
|
|
public async Task ResolveNodeAsync_DirectCycleDependency_ShouldFailWithCycleError()
|
|
{
|
|
var config = CoreConfigTestFactory.CreateConfig();
|
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
|
|
|
var groupAId = NewId("group-a");
|
|
var groupBId = NewId("group-b");
|
|
var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId]);
|
|
var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupAId]);
|
|
|
|
await UpsertProfilesAsync(groupA, groupB);
|
|
|
|
var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
|
|
context.AllProxiesMap.Clear();
|
|
|
|
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);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResolveNodeAsync_IndirectCycleDependency_ShouldFailWithCycleError()
|
|
{
|
|
var config = CoreConfigTestFactory.CreateConfig();
|
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
|
|
|
var groupAId = NewId("group-a");
|
|
var groupBId = NewId("group-b");
|
|
var groupCId = NewId("group-c");
|
|
var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId]);
|
|
var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupCId]);
|
|
var groupC = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupCId, "group-c", [groupAId]);
|
|
|
|
await UpsertProfilesAsync(groupA, groupB, groupC);
|
|
|
|
var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
|
|
context.AllProxiesMap.Clear();
|
|
|
|
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);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResolveNodeAsync_CycleWithValidBranch_ShouldSkipCycleAndKeepValidChild()
|
|
{
|
|
var config = CoreConfigTestFactory.CreateConfig();
|
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
|
|
|
var groupAId = NewId("group-a");
|
|
var groupBId = NewId("group-b");
|
|
var leafId = NewId("leaf");
|
|
var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId, leafId]);
|
|
var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupAId]);
|
|
var leaf = CoreConfigTestFactory.CreateSocksNode(ECoreType.Xray, leafId, "leaf");
|
|
|
|
await UpsertProfilesAsync(groupA, groupB, leaf);
|
|
|
|
var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
|
|
context.AllProxiesMap.Clear();
|
|
|
|
var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
|
|
|
|
validatorResult.Success.Should().BeTrue();
|
|
validatorResult.Errors.Should().BeEmpty();
|
|
validatorResult.Warnings.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
|
|
|
|
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);
|
|
}
|
|
|
|
private static string NewId(string prefix)
|
|
{
|
|
return $"{prefix}-{Guid.NewGuid():N}";
|
|
}
|
|
|
|
private static bool ContainsCycleDependencyMessage(string message)
|
|
{
|
|
return message.Contains("cycle dependency", StringComparison.OrdinalIgnoreCase)
|
|
|| message.Contains("循环依赖", StringComparison.Ordinal)
|
|
|| message.Contains("循環依賴", StringComparison.Ordinal)
|
|
|| message.Contains("циклическую зависимость", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private static async Task UpsertProfilesAsync(params ProfileItem[] profiles)
|
|
{
|
|
SQLiteHelper.Instance.CreateTable<ProfileItem>();
|
|
foreach (var profile in profiles)
|
|
{
|
|
await SQLiteHelper.Instance.ReplaceAsync(profile);
|
|
}
|
|
}
|
|
}
|