/* * Copyright (c) 2026 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using NSubstitute; using NSubstitute.Core; using ProtonVPN.Common.Core.Dns; using ProtonVPN.Common.Core.Networking; using ProtonVPN.Common.Legacy; using ProtonVPN.Common.Legacy.Vpn; using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Dns; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Common.Legacy.Vpn; namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; [TestClass] public class VpnConfigMapperTest { private IEntityMapper _entityMapper; private VpnConfigMapper _mapper; private SplitTunnelModeIpcEntity? _expectedSplitTunnelModeIpcEntity; private List _expectedVpnProtocolIpcEntities; private SplitTunnelMode? _expectedSplitTunnelMode; private List _expectedVpnProtocols; [TestInitialize] public void Initialize() { _entityMapper = Substitute.For(); _mapper = new(_entityMapper); _expectedSplitTunnelModeIpcEntity = SplitTunnelModeIpcEntity.Block; _entityMapper.Map(Arg.Any()) .Returns(_expectedSplitTunnelModeIpcEntity.Value); _entityMapper.Map(Arg.Any()) .Returns((CallInfo callInfo) => (VpnProtocolIpcEntity)(int)callInfo[0]); _expectedVpnProtocolIpcEntities = new List() { VpnProtocolIpcEntity.OpenVpnUdp }; _entityMapper.Map(Arg.Any>()) .Returns(_expectedVpnProtocolIpcEntities); _expectedSplitTunnelMode = SplitTunnelMode.Block; _entityMapper.Map(Arg.Any()) .Returns(_expectedSplitTunnelMode.Value); _entityMapper.Map(Arg.Any()) .Returns((CallInfo callInfo) => (VpnProtocol)(int)callInfo[0]); _expectedVpnProtocols = new List() { VpnProtocol.OpenVpnUdp }; _entityMapper.Map(Arg.Any>()) .Returns(_expectedVpnProtocols); _entityMapper.Map(Arg.Any()) .Returns((CallInfo callInfo) => (DnsBlockModeIpcEntity)(int)callInfo[0]); _entityMapper.Map(Arg.Any()) .Returns((CallInfo callInfo) => (DnsBlockMode)(int)callInfo[0]); } [TestCleanup] public void Cleanup() { _entityMapper = null; _mapper = null; _expectedSplitTunnelModeIpcEntity = null; _expectedVpnProtocolIpcEntities = null; _expectedSplitTunnelMode = null; _expectedVpnProtocols = null; } [TestMethod] public void TestMapLeftToRight_ThrowsWhenNull() { VpnConfig entityToTest = null; Assert.Throws(() => _mapper.Map(entityToTest)); } [TestMethod] public void TestMapLeftToRight() { VpnConfig entityToTest = new(new VpnConfigParameters() { Ports = new Dictionary>() { { VpnProtocol.WireGuardUdp, new List() { 80, 443 } }, { VpnProtocol.ProTunUdp, new List() { 1, 80, 443 } }, { VpnProtocol.OpenVpnUdp, new List() { 8080, 1 } } }, CustomDns = new List() { "172.16.0.0" }, SplitTunnelMode = SplitTunnelMode.Block, SplitTunnelIPs = new List() { "192.168.0.0" }, OpenVpnAdapter = OpenVpnAdapter.Tun, VpnProtocol = VpnProtocol.OpenVpnUdp, PreferredProtocols = new List() { VpnProtocol.OpenVpnTcp }, NetShieldMode = 2, SplitTcp = true, ModerateNat = true, PortForwarding = true, IsIpv6Enabled = true, ShouldDisableWeakHostSetting = true, IsWireGuardServerRouteEnabled = true, DnsBlockMode = DnsBlockMode.Callout, }); VpnConfigIpcEntity result = _mapper.Map(entityToTest); Assert.IsNotNull(result); AssertPortsAreEquivalent(entityToTest, result); CollectionAssert.AreEqual(entityToTest.CustomDns.ToList(), result.CustomDns); Assert.AreEqual(_expectedSplitTunnelModeIpcEntity, result.SplitTunnelMode); CollectionAssert.AreEqual(entityToTest.SplitTunnelIPs.ToList(), result.SplitTunnelIPs); Assert.AreEqual(entityToTest.NetShieldMode, result.NetShieldMode); Assert.AreEqual((int)entityToTest.VpnProtocol, (int)result.VpnProtocol); Assert.AreEqual(entityToTest.ModerateNat, result.ModerateNat); Assert.AreEqual(_expectedVpnProtocolIpcEntities, result.PreferredProtocols); Assert.AreEqual(entityToTest.SplitTcp, result.SplitTcp); Assert.AreEqual(entityToTest.PortForwarding, result.PortForwarding); Assert.AreEqual(entityToTest.IsIpv6Enabled, result.IsIpv6Enabled); Assert.AreEqual(entityToTest.ShouldDisableWeakHostSetting, result.ShouldDisableWeakHostSetting); Assert.AreEqual(entityToTest.IsWireGuardServerRouteEnabled, result.IsWireGuardServerRouteEnabled); Assert.AreEqual((int)entityToTest.DnsBlockMode, (int)result.DnsBlockMode); } private void AssertPortsAreEquivalent(VpnConfig entityToTest, VpnConfigIpcEntity result) { Assert.IsNotNull(result.Ports); List>> leftEntityDictionary = entityToTest.Ports.ToList(); List> rightEntityDictionary = result.Ports.ToList(); Assert.HasCount(leftEntityDictionary.Count, rightEntityDictionary); for (int keyValuePairIndex = 0; keyValuePairIndex < leftEntityDictionary.Count; keyValuePairIndex++) { Assert.AreEqual((int)leftEntityDictionary[keyValuePairIndex].Key, (int)rightEntityDictionary[keyValuePairIndex].Key); CollectionAssert.AreEqual( leftEntityDictionary[keyValuePairIndex].Value.ToList(), rightEntityDictionary[keyValuePairIndex].Value); } } [TestMethod] public void TestMapRightToLeft_ThrowsWhenNull() { VpnConfigIpcEntity entityToTest = null; Assert.Throws(() => _mapper.Map(entityToTest)); } [TestMethod] public void TestMapRightToLeft() { VpnConfigIpcEntity entityToTest = new() { Ports = new Dictionary() { { VpnProtocolIpcEntity.WireGuardUdp, new int[] { 80, 443 } }, { VpnProtocolIpcEntity.ProTunUdp, new int[] { 1, 80, 443 } }, { VpnProtocolIpcEntity.OpenVpnUdp, new int[] { 8080, 1 } } }, CustomDns = new List() { "172.16.0.0" }, SplitTunnelMode = SplitTunnelModeIpcEntity.Block, SplitTunnelIPs = new List() { "192.168.0.0" }, NetShieldMode = 2, VpnProtocol = VpnProtocolIpcEntity.OpenVpnUdp, PreferredProtocols = new List() { VpnProtocolIpcEntity.OpenVpnTcp }, SplitTcp = true, ModerateNat = true, PortForwarding = true, ShouldDisableWeakHostSetting = true, IsWireGuardServerRouteEnabled = true, DnsBlockMode = DnsBlockModeIpcEntity.Disabled, }; VpnConfig result = _mapper.Map(entityToTest); Assert.IsNotNull(result); AssertPortsAreEquivalent(entityToTest, result); CollectionAssert.AreEqual(entityToTest.CustomDns, result.CustomDns.ToList()); Assert.AreEqual(_expectedSplitTunnelMode, result.SplitTunnelMode); CollectionAssert.AreEqual(entityToTest.SplitTunnelIPs, result.SplitTunnelIPs.ToList()); Assert.AreEqual(entityToTest.NetShieldMode, result.NetShieldMode); Assert.AreEqual((int)entityToTest.VpnProtocol, (int)result.VpnProtocol); Assert.AreEqual(_expectedVpnProtocols, result.PreferredProtocols); Assert.AreEqual(entityToTest.SplitTcp, result.SplitTcp); Assert.AreEqual(entityToTest.ModerateNat, result.ModerateNat); Assert.AreEqual(entityToTest.PortForwarding, result.PortForwarding); Assert.AreEqual(entityToTest.ShouldDisableWeakHostSetting, result.ShouldDisableWeakHostSetting); Assert.AreEqual(entityToTest.IsWireGuardServerRouteEnabled, result.IsWireGuardServerRouteEnabled); Assert.AreEqual((int)entityToTest.DnsBlockMode, (int)result.DnsBlockMode); } private void AssertPortsAreEquivalent(VpnConfigIpcEntity entityToTest, VpnConfig result) { Assert.IsNotNull(result.Ports); List> leftEntityDictionary = entityToTest.Ports.ToList(); List>> rightEntityDictionary = result.Ports.ToList(); Assert.HasCount(leftEntityDictionary.Count, rightEntityDictionary); for (int keyValuePairIndex = 0; keyValuePairIndex < leftEntityDictionary.Count; keyValuePairIndex++) { Assert.AreEqual((int)leftEntityDictionary[keyValuePairIndex].Key, (int)rightEntityDictionary[keyValuePairIndex].Key); CollectionAssert.AreEqual( leftEntityDictionary[keyValuePairIndex].Value, rightEntityDictionary[keyValuePairIndex].Value.ToList()); } } }