diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2025-01-24 16:47:32 +0100 |
|---|---|---|
| committer | Bug Magnet <marco.nikic@mullvad.net> | 2025-01-27 09:34:30 +0100 |
| commit | e8eebb0370f7a093bf464b79ef2b190cbd2a44a2 (patch) | |
| tree | 1fe704e128584725fe8999c590063eed43123381 | |
| parent | cfc132e61f34c2b39819e22a134cec25c687c987 (diff) | |
| download | mullvadvpn-sendable-tutorial.tar.xz mullvadvpn-sendable-tutorial.zip | |
Add a sendable tutorialsendable-tutorial
7 files changed, 513 insertions, 90 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index ac7b7bc054..01df7fa0bb 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ @@ -1322,6 +1322,13 @@ remoteGlobalIDString = 58D223D4294C8E5E0029F5F8; remoteInfo = MullvadTypes; }; + A955EF252D43E5C50025E1B1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 58CE5E58224146200008646E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 58CE5E5F224146200008646E; + remoteInfo = MullvadVPN; + }; A9609B6D2D004D1F0065A3D3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 58CE5E58224146200008646E /* Project object */; @@ -2144,6 +2151,7 @@ A944F2712B8E02E800473F4C /* libmullvad_ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmullvad_ios.a; path = "../target/aarch64-apple-ios/debug/libmullvad_ios.a"; sourceTree = "<group>"; }; A9467E7E2A29DEFE000DC21F /* RelayCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayCacheTests.swift; sourceTree = "<group>"; }; A948809A2BC9308D0090A44C /* EphemeralPeerExchangeActor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerExchangeActor.swift; sourceTree = "<group>"; }; + A955EF212D43E5C50025E1B1 /* MullvadVPNSendableTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadVPNSendableTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitorState.swift; sourceTree = "<group>"; }; A95EEE372B722DFC00A8A39B /* PingStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PingStats.swift; sourceTree = "<group>"; }; A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Socks5UsernamePasswordCommand.swift; sourceTree = "<group>"; }; @@ -2321,6 +2329,10 @@ F998EFF92D3656B100D88D01 /* SKProduct+Sorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SKProduct+Sorting.swift"; sourceTree = "<group>"; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedRootGroup section */ + A955EF222D43E5C50025E1B1 /* MullvadVPNSendableTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = MullvadVPNSendableTests; sourceTree = "<group>"; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 06799AB928F98E1D00ACD94E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -2470,6 +2482,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A955EF1E2D43E5C50025E1B1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; A992DA1A2C24709F00DE7CE5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -3678,6 +3697,7 @@ 58695A9E2A4ADA9200328DB3 /* TunnelObfuscationTests */, A992DA1E2C24709F00DE7CE5 /* MullvadRustRuntime */, A9D9A4C12C36D53C004088DD /* MullvadRustRuntimeTests */, + A955EF222D43E5C50025E1B1 /* MullvadVPNSendableTests */, 58CE5E61224146200008646E /* Products */, 584F991F2902CBDD001F858D /* Frameworks */, ); @@ -3704,6 +3724,7 @@ F0ACE3082BE4E478006D5333 /* MullvadMockData.framework */, A992DA1D2C24709F00DE7CE5 /* MullvadRustRuntime.framework */, A9D9A4C02C36D53C004088DD /* MullvadRustRuntimeTests.xctest */, + A955EF212D43E5C50025E1B1 /* MullvadVPNSendableTests.xctest */, ); name = Products; sourceTree = "<group>"; @@ -5034,6 +5055,29 @@ productReference = 852969252B4D9C1F007EAD4C /* MullvadVPNUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; + A955EF202D43E5C50025E1B1 /* MullvadVPNSendableTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = A955EF2B2D43E5C50025E1B1 /* Build configuration list for PBXNativeTarget "MullvadVPNSendableTests" */; + buildPhases = ( + A955EF1D2D43E5C50025E1B1 /* Sources */, + A955EF1E2D43E5C50025E1B1 /* Frameworks */, + A955EF1F2D43E5C50025E1B1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + A955EF262D43E5C50025E1B1 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + A955EF222D43E5C50025E1B1 /* MullvadVPNSendableTests */, + ); + name = MullvadVPNSendableTests; + packageProductDependencies = ( + ); + productName = MullvadVPNSendableTests; + productReference = A955EF212D43E5C50025E1B1 /* MullvadVPNSendableTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; A992DA1C2C24709F00DE7CE5 /* MullvadRustRuntime */ = { isa = PBXNativeTarget; buildConfigurationList = A992DA252C24709F00DE7CE5 /* Build configuration list for PBXNativeTarget "MullvadRustRuntime" */; @@ -5108,7 +5152,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 1520; + LastSwiftUpdateCheck = 1620; LastUpgradeCheck = 1430; ORGANIZATIONNAME = "Mullvad VPN AB"; TargetAttributes = { @@ -5176,6 +5220,10 @@ CreatedOnToolsVersion = 15.1; TestTargetID = 58CE5E5F224146200008646E; }; + A955EF202D43E5C50025E1B1 = { + CreatedOnToolsVersion = 16.2; + TestTargetID = 58CE5E5F224146200008646E; + }; A992DA1C2C24709F00DE7CE5 = { CreatedOnToolsVersion = 15.2; LastSwiftMigration = 1520; @@ -5224,6 +5272,7 @@ F0ACE3072BE4E478006D5333 /* MullvadMockData */, A992DA1C2C24709F00DE7CE5 /* MullvadRustRuntime */, A9D9A4BF2C36D53C004088DD /* MullvadRustRuntimeTests */, + A955EF202D43E5C50025E1B1 /* MullvadVPNSendableTests */, ); }; /* End PBXProject section */ @@ -5337,6 +5386,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A955EF1F2D43E5C50025E1B1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; A992DA1B2C24709F00DE7CE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -6097,7 +6153,6 @@ 5868585524054096000B8131 /* CustomButton.swift in Sources */, 58E25F812837BBBB002CFB2C /* SceneDelegate.swift in Sources */, 7A1A26492A29D48A00B978AA /* RelayFilterCellFactory.swift in Sources */, - 5867771629097C5B006F721F /* ProductState.swift in Sources */, F0D5591E2D38051C0072B63F /* LatestChangesNotificationProvider.swift in Sources */, 7A28826A2BA8336600FD9F20 /* VPNSettingsCoordinator.swift in Sources */, 7A6389DE2B7E3BD6008E77E1 /* CustomListItemIdentifier.swift in Sources */, @@ -6521,6 +6576,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A955EF1D2D43E5C50025E1B1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; A992DA192C24709F00DE7CE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -6763,6 +6825,11 @@ target = 58D223D4294C8E5E0029F5F8 /* MullvadTypes */; targetProxy = A9173C332C36CCFB00F6A08C /* PBXContainerItemProxy */; }; + A955EF262D43E5C50025E1B1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 58CE5E5F224146200008646E /* MullvadVPN */; + targetProxy = A955EF252D43E5C50025E1B1 /* PBXContainerItemProxy */; + }; A9609B6E2D004D1F0065A3D3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 58FBDA9722A519BC00EB69A3 /* WireGuardGoBridge */; @@ -8412,6 +8479,107 @@ }; name = MockRelease; }; + A955EF272D43E5C50025E1B1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = ""; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = CKG9MXH72F; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.mullvad.MullvadVPNSendableTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = ""; + }; + name = Debug; + }; + A955EF282D43E5C50025E1B1 /* Staging */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = ""; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = CKG9MXH72F; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.mullvad.MullvadVPNSendableTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = ""; + }; + name = Staging; + }; + A955EF292D43E5C50025E1B1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = ""; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = CKG9MXH72F; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.mullvad.MullvadVPNSendableTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = ""; + }; + name = Release; + }; + A955EF2A2D43E5C50025E1B1 /* MockRelease */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = ""; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = CKG9MXH72F; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.mullvad.MullvadVPNSendableTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = ""; + }; + name = MockRelease; + }; A992DA262C24709F00DE7CE5 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 5808273928487E3E006B77A4 /* Base.xcconfig */; @@ -9585,6 +9753,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + A955EF2B2D43E5C50025E1B1 /* Build configuration list for PBXNativeTarget "MullvadVPNSendableTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A955EF272D43E5C50025E1B1 /* Debug */, + A955EF282D43E5C50025E1B1 /* Staging */, + A955EF292D43E5C50025E1B1 /* Release */, + A955EF2A2D43E5C50025E1B1 /* MockRelease */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; A992DA252C24709F00DE7CE5 /* Build configuration list for PBXNativeTarget "MullvadRustRuntime" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme index 8e3306fc2b..ff88bf15a5 100644 --- a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme @@ -70,20 +70,6 @@ buildForAnalyzing = "YES"> <BuildableReference BuildableIdentifier = "primary" - BlueprintIdentifier = "063F02722902B63F001FA09F" - BuildableName = "RelayCache.framework" - BlueprintName = "RelayCache" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </BuildActionEntry> - <BuildActionEntry - buildForTesting = "YES" - buildForRunning = "YES" - buildForProfiling = "YES" - buildForArchiving = "YES" - buildForAnalyzing = "YES"> - <BuildableReference - BuildableIdentifier = "primary" BlueprintIdentifier = "58D223D4294C8E5E0029F5F8" BuildableName = "MullvadTypes.framework" BlueprintName = "MullvadTypes" @@ -118,48 +104,6 @@ ReferencedContainer = "container:MullvadVPN.xcodeproj"> </BuildableReference> </BuildActionEntry> - <BuildActionEntry - buildForTesting = "YES" - buildForRunning = "YES" - buildForProfiling = "YES" - buildForArchiving = "YES" - buildForAnalyzing = "YES"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "5898D28829017BD300EB5EBA" - BuildableName = "libTunnelProviderMessaging.a" - BlueprintName = "TunnelProviderMessaging" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </BuildActionEntry> - <BuildActionEntry - buildForTesting = "YES" - buildForRunning = "YES" - buildForProfiling = "YES" - buildForArchiving = "YES" - buildForAnalyzing = "YES"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "5898D29729017DAC00EB5EBA" - BuildableName = "libRelaySelector.a" - BlueprintName = "RelaySelector" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </BuildActionEntry> - <BuildActionEntry - buildForTesting = "YES" - buildForRunning = "NO" - buildForProfiling = "NO" - buildForArchiving = "NO" - buildForAnalyzing = "NO"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "A98F1B4D2C19C48D003C869E" - BuildableName = "MullvadPostQuantumTests.xctest" - BlueprintName = "MullvadPostQuantumTests" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </BuildActionEntry> </BuildActionEntries> </BuildAction> <TestAction @@ -211,26 +155,6 @@ </BuildableReference> </TestableReference> <TestableReference - skipped = "NO"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "58D0C79223F1CE7000FE9BA7" - BuildableName = "MullvadVPNScreenshots.xctest" - BlueprintName = "MullvadVPNScreenshots" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </TestableReference> - <TestableReference - skipped = "NO"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "58695A9C2A4ADA9100328DB3" - BuildableName = "TunnelObfuscationTests.xctest" - BlueprintName = "TunnelObfuscationTests" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </TestableReference> - <TestableReference skipped = "NO" parallelizable = "YES"> <BuildableReference @@ -282,6 +206,17 @@ ReferencedContainer = "container:MullvadVPN.xcodeproj"> </BuildableReference> </TestableReference> + <TestableReference + skipped = "NO" + parallelizable = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "A955EF202D43E5C50025E1B1" + BuildableName = "MullvadVPNSendableTests.xctest" + BlueprintName = "MullvadVPNSendableTests" + ReferencedContainer = "container:MullvadVPN.xcodeproj"> + </BuildableReference> + </TestableReference> </Testables> </TestAction> <LaunchAction diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNSendableTests.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNSendableTests.xcscheme new file mode 100644 index 0000000000..10b2f4b13d --- /dev/null +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNSendableTests.xcscheme @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1620" + version = "1.7"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> + <Testables> + <TestableReference + skipped = "NO" + parallelizable = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "A955EF202D43E5C50025E1B1" + BuildableName = "MullvadVPNSendableTests.xctest" + BlueprintName = "MullvadVPNSendableTests" + ReferencedContainer = "container:MullvadVPN.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme index c7c011fb01..2dc3edef06 100644 --- a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPNUITests.xcscheme @@ -28,6 +28,17 @@ ReferencedContainer = "container:MullvadVPN.xcodeproj"> </BuildableReference> </TestableReference> + <TestableReference + skipped = "NO" + parallelizable = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "A955EF202D43E5C50025E1B1" + BuildableName = "MullvadVPNSendableTests.xctest" + BlueprintName = "MullvadVPNSendableTests" + ReferencedContainer = "container:MullvadVPN.xcodeproj"> + </BuildableReference> + </TestableReference> </Testables> </TestAction> <LaunchAction diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/PacketTunnel.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/PacketTunnel.xcscheme index e3d0f107cf..18e34fd94f 100644 --- a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/PacketTunnel.xcscheme +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/PacketTunnel.xcscheme @@ -51,6 +51,19 @@ reference = "container:TestPlans/MullvadVPNCI.xctestplan"> </TestPlanReference> </TestPlans> + <Testables> + <TestableReference + skipped = "NO" + parallelizable = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "A955EF202D43E5C50025E1B1" + BuildableName = "MullvadVPNSendableTests.xctest" + BlueprintName = "MullvadVPNSendableTests" + ReferencedContainer = "container:MullvadVPN.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> </TestAction> <LaunchAction buildConfiguration = "Debug" @@ -80,6 +93,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES" + askForAppToLaunch = "Yes" launchAutomaticallySubstyle = "2"> <BuildableProductRunnable runnableDebuggingMode = "0"> diff --git a/ios/MullvadVPNSendableTests/MullvadVPNSendableTests.swift b/ios/MullvadVPNSendableTests/MullvadVPNSendableTests.swift new file mode 100644 index 0000000000..1a5c39e831 --- /dev/null +++ b/ios/MullvadVPNSendableTests/MullvadVPNSendableTests.swift @@ -0,0 +1,221 @@ +// +// SendableTests.swift +// MullvadVPNTests +// +// Created by Marco Nikic on 2025-01-24. +// Copyright © 2025 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import Testing + +// Cannot be sendable unless marked `final` +class NonSendable { + var name = "Do not send me" + + func doNonSendableThings() { + print("really \(name)") + } + + deinit { + print("bye \(name)") + } +} + +struct SendableButNonCopyableValue: Sendable, ~Copyable { + let name = "Please send me senpai :3" +} + +nonisolated(unsafe) var plainSendableTypeCounter = 0 + +class PlainSendableType { + var name = "I have been sent here" + + init() { + plainSendableTypeCounter += 1 + + print("I am instance #\(plainSendableTypeCounter) of PlainSendableType") + } + + deinit { + print("Instance #\(plainSendableTypeCounter) of PlainSendableType has been terminated") + plainSendableTypeCounter -= 1 + } +} + +struct InvalidUse { + private let ns: NonSendable + + init(nonSendable: NonSendable) { + self.ns = nonSendable + } + + func sendValue() async -> sending NonSendable { + ns.doNonSendableThings() + // return ns // Sending 'self.ns' risks causing data races + return NonSendable() + } +} + +struct ValidUse { + func sendValue() async -> sending NonSendable { + NonSendable() + } +} + +struct SendableTests { + @Test func firstExample() async { + let nonSendable = NonSendable() + let invalid = InvalidUse(nonSendable: nonSendable) + + let valid = ValidUse() + + let invalidUse = await invalid.sendValue() + let validUse = await valid.sendValue() + print(invalidUse) + print(validUse) + } +} + +struct ReceivingSendable { + func receiveSending(_ nonSendable: sending NonSendable) async { + print(nonSendable.name) + } + + /// `borrowing + sending` is technically valid, + /// but the Language steering group decided to ban it for now, preferring internal compiler exclusivity + /// to preserve ABI compatibility + /// https://forums.swift.org/t/borrowing-sending-not-allowed/74711/2 + func borrowSendingSendable(_ sendableValue: borrowing /* sending */ SendableButNonCopyableValue) async { + print(sendableValue.name) + } + + func consumeSendingSendable(_ sendableValue: consuming sending SendableButNonCopyableValue) async { + print(sendableValue.name) + } + + @Test + mutating func secondExample() async { + /// `nonSendable` is in a disconnected isolation region from `ReceivingSendable`, the current test instance + let nonSendable = NonSendable() + + /// `nonSendable` is being sent into `ReceivingSendable`'s isolation region, it cannot be used anymore in the disconnected region + /// because that is a potential race condition + await receiveSending(nonSendable) // ❌ Sending 'nonSendable' risks causing data races + /// Uncommenting the next line will trigger the error in the comment above +// nonSendable.name = "Invalid operation" + + /// Is it okay to borrow `~Copyable & Sendable` values between isolated regions, no risk of race conditions occur + let sendableValue = SendableButNonCopyableValue() // ❌'sendableValue' used after consume + await borrowSendingSendable(sendableValue) + print(sendableValue.name) + + /// However, even if a value is `Sendable`, if it is `~Copyable` + /// It cannot be used across different isolated regions once it is consumed + await consumeSendingSendable(sendableValue) + /// Uncommenting the next line triggers the error at L82 +// print(sendableValue.name) + } +} + +class HasDelegate { + var borrowingDelegateCallback: ((borrowing SendableButNonCopyableValue) -> Void)? + + var impossibleSendingDelegateCallback: ((consuming sending SendableButNonCopyableValue) -> Void)? + + typealias CompletionHandler = (sending Result<NonSendable, Never>) -> Void + + var completionHandler: CompletionHandler? + + func callBorrowingDelegate() { + let argument = SendableButNonCopyableValue() + borrowingDelegateCallback?(argument) + } + + func callSendingDelegate() { + let argument = SendableButNonCopyableValue() + impossibleSendingDelegateCallback?(argument) + } + + func callCompletionHandler() { + let result: Result<NonSendable, Never> = Result.success(NonSendable()) + completionHandler?(result) // ❌ Sending 'result' risks causing data races + +// _ = result.map { print($0) } + } +} + +class HasDifferentDelegate { + typealias OtherCompletionHandler = () -> sending PlainSendableType + + var otherHandler: OtherCompletionHandler? + + let plainSendableType: PlainSendableType + + init(plainSendableType: PlainSendableType) { + self.plainSendableType = plainSendableType + } + + func callOtherHandler() { + let value = otherHandler!() + print(value.name) + } +} + +class SendingClosures { + func extractNameFrom(_ argument: borrowing SendableButNonCopyableValue) -> String { + argument.name + } + + func stealNameFrom(_ argument: consuming sending SendableButNonCopyableValue) -> String { + argument.name + } + + @Test func sendCannotBorrowAndConsume() { + let hasDelegate = HasDelegate() + + hasDelegate.borrowingDelegateCallback = { argument in // ❌ 'argument' is borrowed and cannot be consumed + let borrowedName = self.extractNameFrom(argument) + print(borrowedName) + +// let stolenName = self.stealNameFrom(argument) +// print(stolenName) + } + + hasDelegate.callBorrowingDelegate() + } + + @Test func nonsenseSendingCallback() { + let hasDelegate = HasDelegate() + + hasDelegate.impossibleSendingDelegateCallback = { _ in // ❌ 'argument' is borrowed and cannot be consumed +// let stolenName = self.stealNameFrom(argument) +// print(stolenName) + } + + hasDelegate.callSendingDelegate() + } + + @Test func sendCustomCallback() { + let hasDelegate = HasDelegate() + + hasDelegate.completionHandler = { maybeResult in + print(maybeResult.get().name) + } + + hasDelegate.callCompletionHandler() + } + + @Test func sendCustomCallbackDifferently() { + let plainType = PlainSendableType() + let hasDelegate = HasDifferentDelegate(plainSendableType: plainType) + + hasDelegate.otherHandler = { +// return plainType // ❌ Sending 'plainType' risks causing data races + PlainSendableType() + } + + plainType.name = "hello" + hasDelegate.callOtherHandler() + } +} diff --git a/ios/TestPlans/MullvadVPNApp.xctestplan b/ios/TestPlans/MullvadVPNApp.xctestplan index 5a849a2e94..70e5780c9e 100644 --- a/ios/TestPlans/MullvadVPNApp.xctestplan +++ b/ios/TestPlans/MullvadVPNApp.xctestplan @@ -9,6 +9,7 @@ } ], "defaultOptions" : { + "codeCoverage" : false, "targetForVariableExpansion" : { "containerPath" : "container:MullvadVPN.xcodeproj", "identifier" : "58CE5E5F224146200008646E", @@ -21,16 +22,22 @@ "parallelizable" : true, "target" : { "containerPath" : "container:MullvadVPN.xcodeproj", - "identifier" : "58FBFBE5291622580020E046", - "name" : "MullvadRESTTests" + "identifier" : "58C7A43C2A863F450060C66F", + "name" : "PacketTunnelCoreTests" } }, { - "parallelizable" : true, "target" : { "containerPath" : "container:MullvadVPN.xcodeproj", - "identifier" : "58B0A29F238EE67E00BC001D", - "name" : "MullvadVPNTests" + "identifier" : "A9D9A4BF2C36D53C004088DD", + "name" : "MullvadRustRuntimeTests" + } + }, + { + "target" : { + "containerPath" : "container:MullvadVPN.xcodeproj", + "identifier" : "A955EF202D43E5C50025E1B1", + "name" : "MullvadVPNSendableTests" } }, { @@ -45,23 +52,24 @@ "parallelizable" : true, "target" : { "containerPath" : "container:MullvadVPN.xcodeproj", - "identifier" : "58C7A43C2A863F450060C66F", - "name" : "PacketTunnelCoreTests" + "identifier" : "58B0A29F238EE67E00BC001D", + "name" : "MullvadVPNTests" } }, { "parallelizable" : true, "target" : { "containerPath" : "container:MullvadVPN.xcodeproj", - "identifier" : "7A88DCD62A8FABBE00D2FF0E", - "name" : "RoutingTests" + "identifier" : "58FBFBE5291622580020E046", + "name" : "MullvadRESTTests" } }, { + "parallelizable" : true, "target" : { "containerPath" : "container:MullvadVPN.xcodeproj", - "identifier" : "A9D9A4BF2C36D53C004088DD", - "name" : "MullvadRustRuntimeTests" + "identifier" : "7A88DCD62A8FABBE00D2FF0E", + "name" : "RoutingTests" } } ], |
