Skip to content

Commit

Permalink
Granularize app features (#671)
Browse files Browse the repository at this point in the history
Split .networkSettings and add .sharing for #668
  • Loading branch information
keeshux authored Oct 3, 2024
1 parent 63b0199 commit 0917e47
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 38 deletions.
2 changes: 2 additions & 0 deletions Passepartout.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
/* Begin PBXFileReference section */
0E06D18F2B87629100176E1D /* Passepartout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Passepartout.app; sourceTree = BUILT_PRODUCTS_DIR; };
0E7C3CCC2C9AF44600B72E69 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
0E7D0EAD2CAEA47700A2F28D /* Passepartout.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Passepartout.xctestplan; sourceTree = "<group>"; };
0E7E3D5B2B9345FD002BBDB4 /* App.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
0E7E3D5C2B9345FD002BBDB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0E7E3D5F2B9345FD002BBDB4 /* PassepartoutApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PassepartoutApp.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -152,6 +153,7 @@
isa = PBXGroup;
children = (
0E8D852F2C328CA1005493DE /* Config.xcconfig */,
0E7D0EAD2CAEA47700A2F28D /* Passepartout.xctestplan */,
0E7E3D5A2B9345FD002BBDB4 /* App */,
0EDE56E82CABE40D0082D21C /* Intents */,
0E7E3D612B9345FD002BBDB4 /* Shared */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:Passepartout/Passepartout.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand Down
19 changes: 14 additions & 5 deletions Passepartout/Library/Sources/AppUI/IAP/AppFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,33 @@

import Foundation

public enum AppFeature: String, CaseIterable {
public enum AppFeature: String {
case appleTV

case interactiveLogin
case dns

case httpProxy

case networkSettings
case interactiveLogin

case onDemand

case providers

case routing

case sharing

case siri

public static let allCases: [AppFeature] = [
public static let fullVersionFeaturesV2: [AppFeature] = [
.dns,
.httpProxy,
.interactiveLogin,
.networkSettings,
.onDemand,
.providers,
.routing,
.sharing,
.siri
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ extension AppProduct: AppFeatureProviding {
return [.appleTV]

case .Features.networkSettings:
return [.networkSettings]
return [.dns, .httpProxy, .routing]

case .Features.siriShortcuts:
return [.siri]
Expand All @@ -90,18 +90,18 @@ extension AppProduct: AppFeatureProviding {
return [.onDemand]

case .Full.allPlatforms:
return AppFeature.allCases
return AppFeature.fullVersionFeaturesV2

case .Full.iOS:
#if os(iOS)
return AppFeature.allCases
return AppFeature.fullVersionFeaturesV2
#else
return []
#endif

case .Full.macOS:
#if os(macOS)
return AppFeature.allCases
return AppFeature.fullVersionFeaturesV2
#else
return []
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ extension AppUserLevel: AppFeatureProviding {
var features: [AppFeature] {
switch self {
case .fullVersion:
return AppFeature.allCases
return AppFeature.fullVersionFeaturesV2

case .fullVersionPlusTV:
var list = AppFeature.allCases
var list = AppFeature.fullVersionFeaturesV2
list.append(.appleTV)
return list

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,17 @@ private extension ProfileCoordinator {
private extension ProfileCoordinator {
func onNewModule(_ moduleType: ModuleType) {
switch moduleType {
case .onDemand:
break
case .dns:
paywallReason = iapManager.paywallReason(forFeature: .dns)

case .httpProxy:
paywallReason = iapManager.paywallReason(forFeature: .httpProxy)

default:
paywallReason = iapManager.paywallReason(forFeature: .networkSettings)
case .ip:
paywallReason = iapManager.paywallReason(forFeature: .routing)

case .onDemand, .openVPN, .wireGuard:
break
}
guard paywallReason == nil else {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ extension ConnectionObserverTests {
XCTAssertEqual(sut.dataCount, nil)

try await tunnel.install(profile, connect: true, title: \.name)
try await Task.sleep(for: .milliseconds(200))
try await Task.sleep(for: .milliseconds(300))
XCTAssertEqual(sut.dataCount, dataCount)
}
}
41 changes: 22 additions & 19 deletions Passepartout/Library/Tests/AppUITests/IAPManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extension IAPManagerTests {
return []
}
await sut.reloadReceipt()
XCTAssertTrue(sut.isEligible(for: AppFeature.allCases))
XCTAssertTrue(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
}

func test_givenBuildProducts_whenNewer_thenFreeVersion() async {
Expand All @@ -65,7 +65,7 @@ extension IAPManagerTests {
return []
}
await sut.reloadReceipt()
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
}

// MARK: Eligibility
Expand All @@ -74,13 +74,13 @@ extension IAPManagerTests {
let reader = MockReceiptReader()
let sut = IAPManager(receiptReader: reader)

XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))

await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.allPlatforms])
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))

await sut.reloadReceipt()
XCTAssertTrue(sut.isEligible(for: AppFeature.allCases))
XCTAssertTrue(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
}

func test_givenPurchasedFeatures_thenIsOnlyEligibleForFeatures() async {
Expand All @@ -92,10 +92,13 @@ extension IAPManagerTests {
let sut = IAPManager(receiptReader: reader)

await sut.reloadReceipt()
XCTAssertTrue(sut.isEligible(for: .siri))
XCTAssertTrue(sut.isEligible(for: .networkSettings))
XCTAssertTrue(sut.isEligible(for: .dns))
XCTAssertTrue(sut.isEligible(for: .httpProxy))
XCTAssertFalse(sut.isEligible(for: .onDemand))
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertTrue(sut.isEligible(for: .routing))
XCTAssertFalse(sut.isEligible(for: .sharing))
XCTAssertTrue(sut.isEligible(for: .siri))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
}

func test_givenPurchasedAndCancelledFeature_thenIsNotEligible() async {
Expand All @@ -108,7 +111,7 @@ extension IAPManagerTests {
let sut = IAPManager(receiptReader: reader)

await sut.reloadReceipt()
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
}

func test_givenFreeVersion_thenIsNotEligibleForAnyFeature() async {
Expand All @@ -118,7 +121,7 @@ extension IAPManagerTests {

await sut.reloadReceipt()
XCTAssertFalse(sut.userLevel.isFullVersion)
AppFeature.allCases.forEach {
AppFeature.fullVersionFeaturesV2.forEach {
XCTAssertFalse(sut.isEligible(for: $0))
}
}
Expand All @@ -138,7 +141,7 @@ extension IAPManagerTests {
let sut = IAPManager(receiptReader: reader)

await sut.reloadReceipt()
AppFeature.allCases.forEach {
AppFeature.fullVersionFeaturesV2.forEach {
XCTAssertTrue(sut.isEligible(for: $0))
}
XCTAssertFalse(sut.isEligible(for: .appleTV))
Expand All @@ -160,11 +163,11 @@ extension IAPManagerTests {
#if os(macOS)
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.macOS, .Features.networkSettings])
await sut.reloadReceipt()
XCTAssertTrue(sut.isEligible(for: AppFeature.allCases))
XCTAssertTrue(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
#else
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.iOS, .Features.networkSettings])
await sut.reloadReceipt()
XCTAssertTrue(sut.isEligible(for: AppFeature.allCases))
XCTAssertTrue(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
#endif
}

Expand All @@ -175,11 +178,11 @@ extension IAPManagerTests {
#if os(macOS)
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.iOS, .Features.networkSettings])
await sut.reloadReceipt()
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
#else
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.macOS, .Features.networkSettings])
await sut.reloadReceipt()
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
#endif
}

Expand Down Expand Up @@ -264,15 +267,15 @@ extension IAPManagerTests {
let sut = IAPManager(customUserLevel: .beta, receiptReader: reader)

await sut.reloadReceipt()
XCTAssertFalse(sut.isEligible(for: AppFeature.allCases))
XCTAssertFalse(sut.isEligible(for: AppFeature.fullVersionFeaturesV2))
}

func test_givenBetaApp_thenIsEligibleForUnrestrictedFeature() async {
let reader = MockReceiptReader()
let sut = IAPManager(customUserLevel: .beta, receiptReader: reader, unrestrictedFeatures: [.onDemand])

await sut.reloadReceipt()
AppFeature.allCases.forEach {
AppFeature.fullVersionFeaturesV2.forEach {
if $0 == .onDemand {
XCTAssertTrue(sut.isEligible(for: $0))
} else {
Expand Down Expand Up @@ -302,7 +305,7 @@ extension IAPManagerTests {
let sut = IAPManager(customUserLevel: .fullVersion, receiptReader: reader)

await sut.reloadReceipt()
AppFeature.allCases.forEach {
AppFeature.fullVersionFeaturesV2.forEach {
XCTAssertTrue(sut.isEligible(for: $0))
}
XCTAssertFalse(sut.isEligible(for: .appleTV))
Expand All @@ -313,7 +316,7 @@ extension IAPManagerTests {
let sut = IAPManager(customUserLevel: .fullVersionPlusTV, receiptReader: reader)

await sut.reloadReceipt()
AppFeature.allCases.forEach {
AppFeature.fullVersionFeaturesV2.forEach {
XCTAssertTrue(sut.isEligible(for: $0))
}
XCTAssertTrue(sut.isEligible(for: .appleTV))
Expand Down
31 changes: 31 additions & 0 deletions Passepartout/Passepartout.xctestplan
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"configurations" : [
{
"id" : "880EB747-73AE-45F8-B6D3-95D06B161AB1",
"name" : "Configuration 1",
"options" : {

}
}
],
"defaultOptions" : {
"testTimeoutsEnabled" : true
},
"testTargets" : [
{
"target" : {
"containerPath" : "container:Passepartout\/Library",
"identifier" : "AppLibraryTests",
"name" : "AppLibraryTests"
}
},
{
"target" : {
"containerPath" : "container:Passepartout\/Library",
"identifier" : "AppUITests",
"name" : "AppUITests"
}
}
],
"version" : 1
}
2 changes: 1 addition & 1 deletion Passepartout/Shared/Shared+AppUI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extension IAPManager {
customUserLevel: customUserLevel,
receiptReader: KvittoReceiptReader(),
// FIXME: #662, omit unrestrictedFeatures on release!
unrestrictedFeatures: [.interactiveLogin],
unrestrictedFeatures: [.interactiveLogin, .sharing],
productsAtBuild: productsAtBuild
)

Expand Down

0 comments on commit 0917e47

Please sign in to comment.