mirror of
https://github.com/passepartoutvpn/passepartout-apple.git
synced 2025-02-22 15:52:08 +00:00
Simplify products (#1024)
Only offer compensations to former purchasers: - .appleTV to .full purchasers - .full to .appleTV purchasers Always suggest .fullTV to new purchasers. Finally rename: - .full to .iOS_macOS - .fullTV to .allFeatures (lifetime)
This commit is contained in:
parent
2eca757dc6
commit
c527171957
@ -37,11 +37,11 @@ extension AppProduct {
|
|||||||
|
|
||||||
public enum Full {
|
public enum Full {
|
||||||
static let all: [AppProduct] = [
|
static let all: [AppProduct] = [
|
||||||
.Full.OneTime.full,
|
.Full.OneTime.allFeatures,
|
||||||
.Full.OneTime.fullTV,
|
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
//
|
//
|
||||||
|
.Full.OneTime.iOS_macOS,
|
||||||
.Full.OneTime.iOS,
|
.Full.OneTime.iOS,
|
||||||
.Full.OneTime.macOS
|
.Full.OneTime.macOS
|
||||||
]
|
]
|
||||||
@ -66,12 +66,7 @@ extension AppProduct.Features {
|
|||||||
|
|
||||||
extension AppProduct.Full {
|
extension AppProduct.Full {
|
||||||
public enum OneTime {
|
public enum OneTime {
|
||||||
|
public static let allFeatures = AppProduct(featureId: "full.lifetime")
|
||||||
// iOS/macOS
|
|
||||||
public static let full = AppProduct(featureId: "full_multi_version")
|
|
||||||
|
|
||||||
// iOS/macOS + tvOS
|
|
||||||
public static let fullTV = AppProduct(featureId: "full.lifetime")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Recurring {
|
public enum Recurring {
|
||||||
@ -84,7 +79,10 @@ extension AppProduct.Full {
|
|||||||
extension AppProduct {
|
extension AppProduct {
|
||||||
public var isFullVersion: Bool {
|
public var isFullVersion: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case .Full.OneTime.full, .Full.OneTime.fullTV, .Full.Recurring.monthly, .Full.Recurring.yearly:
|
case .Full.Recurring.yearly,
|
||||||
|
.Full.Recurring.monthly,
|
||||||
|
.Full.OneTime.allFeatures,
|
||||||
|
.Full.OneTime.iOS_macOS:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@ -113,6 +111,9 @@ extension AppProduct.Features {
|
|||||||
|
|
||||||
extension AppProduct.Full.OneTime {
|
extension AppProduct.Full.OneTime {
|
||||||
|
|
||||||
|
@available(*, deprecated)
|
||||||
|
public static let iOS_macOS = AppProduct(featureId: "full_multi_version")
|
||||||
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
public static let iOS = AppProduct(featureId: "full_version")
|
public static let iOS = AppProduct(featureId: "full_version")
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ public enum AppUserLevel: Int, Sendable {
|
|||||||
|
|
||||||
case beta = 1
|
case beta = 1
|
||||||
|
|
||||||
case full = 2
|
case fullV2 = 2 // without .appleTV
|
||||||
|
|
||||||
case fullTV = 3
|
case fullV3 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppUserLevel {
|
extension AppUserLevel {
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// AppFeature+Full.swift
|
|
||||||
// Passepartout
|
|
||||||
//
|
|
||||||
// Created by Davide De Rosa on 11/20/24.
|
|
||||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
|
||||||
//
|
|
||||||
// https://github.com/passepartoutvpn
|
|
||||||
//
|
|
||||||
// This file is part of Passepartout.
|
|
||||||
//
|
|
||||||
// Passepartout 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.
|
|
||||||
//
|
|
||||||
// Passepartout 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 Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
extension AppFeature {
|
|
||||||
public static let fullFeatures = AppFeature.allCases.filter {
|
|
||||||
$0 != .appleTV
|
|
||||||
}
|
|
||||||
|
|
||||||
public static let fullTVFeatures = AppFeature.allCases
|
|
||||||
}
|
|
@ -35,11 +35,11 @@ extension AppUserLevel: AppFeatureProviding {
|
|||||||
.sharing
|
.sharing
|
||||||
]
|
]
|
||||||
|
|
||||||
case .full:
|
case .fullV2:
|
||||||
return AppFeature.fullFeatures
|
return AppProduct.Full.OneTime.iOS_macOS.features
|
||||||
|
|
||||||
case .fullTV:
|
case .fullV3:
|
||||||
return AppFeature.fullTVFeatures
|
return AppProduct.Full.OneTime.allFeatures.features
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return []
|
return []
|
||||||
|
@ -31,27 +31,29 @@ extension AppProduct: AppFeatureProviding {
|
|||||||
|
|
||||||
// MARK: Current
|
// MARK: Current
|
||||||
|
|
||||||
case .Full.OneTime.full:
|
case .Full.OneTime.allFeatures, .Full.Recurring.monthly, .Full.Recurring.yearly:
|
||||||
return AppFeature.fullFeatures
|
return AppFeature.allCases
|
||||||
|
|
||||||
case .Full.OneTime.fullTV, .Full.Recurring.monthly, .Full.Recurring.yearly:
|
|
||||||
return AppFeature.fullTVFeatures
|
|
||||||
|
|
||||||
case .Features.appleTV:
|
case .Features.appleTV:
|
||||||
return [.appleTV, .sharing]
|
return [.appleTV, .sharing]
|
||||||
|
|
||||||
// MARK: Discontinued
|
// MARK: Discontinued
|
||||||
|
|
||||||
|
case .Full.OneTime.iOS_macOS:
|
||||||
|
return AppFeature.allCases.filter {
|
||||||
|
$0 != .appleTV
|
||||||
|
}
|
||||||
|
|
||||||
case .Full.OneTime.iOS:
|
case .Full.OneTime.iOS:
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
return AppFeature.fullFeatures
|
return AppProduct.Full.OneTime.iOS_macOS.features
|
||||||
#else
|
#else
|
||||||
return []
|
return []
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case .Full.OneTime.macOS:
|
case .Full.OneTime.macOS:
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
return AppFeature.fullFeatures
|
return AppProduct.Full.OneTime.iOS_macOS.features
|
||||||
#else
|
#else
|
||||||
return []
|
return []
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,7 +30,7 @@ import PassepartoutKit
|
|||||||
|
|
||||||
extension IAPManager {
|
extension IAPManager {
|
||||||
public var isFullVersionPurchaser: Bool {
|
public var isFullVersionPurchaser: Bool {
|
||||||
purchasedProducts.contains(.Full.OneTime.full) || purchasedProducts.contains(.Full.OneTime.fullTV) || (purchasedProducts.contains(.Full.OneTime.iOS) && purchasedProducts.contains(.Full.OneTime.macOS))
|
purchasedProducts.contains(where: \.isFullVersion) || (purchasedProducts.contains(.Full.OneTime.iOS) && purchasedProducts.contains(.Full.OneTime.macOS))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func suggestedProducts(for requiredFeatures: Set<AppFeature>, withRecurring: Bool = true) -> Set<AppProduct>? {
|
public func suggestedProducts(for requiredFeatures: Set<AppFeature>, withRecurring: Bool = true) -> Set<AppProduct>? {
|
||||||
@ -51,20 +51,14 @@ extension IAPManager {
|
|||||||
assertionFailure("Full version purchaser requiring other than [.appleTV]")
|
assertionFailure("Full version purchaser requiring other than [.appleTV]")
|
||||||
}
|
}
|
||||||
} else { // !isFullVersionPurchaser
|
} else { // !isFullVersionPurchaser
|
||||||
if ineligibleFeatures == [.appleTV] {
|
if eligibleFeatures.contains(.appleTV) {
|
||||||
products.insert(.Features.appleTV)
|
products.insert(.Full.OneTime.iOS_macOS)
|
||||||
products.insert(.Full.OneTime.fullTV)
|
|
||||||
} else if ineligibleFeatures.contains(.appleTV) {
|
|
||||||
products.insert(.Full.OneTime.fullTV)
|
|
||||||
} else {
|
} else {
|
||||||
if !eligibleFeatures.contains(.appleTV) {
|
products.insert(.Full.OneTime.allFeatures)
|
||||||
products.insert(.Full.OneTime.fullTV)
|
|
||||||
}
|
|
||||||
products.insert(.Full.OneTime.full)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if withRecurring && products.contains(.Full.OneTime.fullTV) {
|
if withRecurring && products.contains(.Full.OneTime.allFeatures) {
|
||||||
products.insert(.Full.Recurring.monthly)
|
products.insert(.Full.Recurring.monthly)
|
||||||
products.insert(.Full.Recurring.yearly)
|
products.insert(.Full.Recurring.yearly)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import PassepartoutKit
|
|||||||
extension AppContext {
|
extension AppContext {
|
||||||
public static let forPreviews: AppContext = {
|
public static let forPreviews: AppContext = {
|
||||||
let iapManager = IAPManager(
|
let iapManager = IAPManager(
|
||||||
customUserLevel: .fullTV,
|
customUserLevel: .fullV3,
|
||||||
inAppHelper: FakeAppProductHelper(),
|
inAppHelper: FakeAppProductHelper(),
|
||||||
receiptReader: FakeAppReceiptReader(),
|
receiptReader: FakeAppReceiptReader(),
|
||||||
betaChecker: TestFlightChecker(),
|
betaChecker: TestFlightChecker(),
|
||||||
|
@ -90,7 +90,7 @@ private extension PaywallView {
|
|||||||
featureProductsView
|
featureProductsView
|
||||||
fullProductsView
|
fullProductsView
|
||||||
if !iapManager.isFullVersionPurchaser {
|
if !iapManager.isFullVersionPurchaser {
|
||||||
fullVersionFeaturesView
|
allFeaturesView
|
||||||
}
|
}
|
||||||
restoreView
|
restoreView
|
||||||
}
|
}
|
||||||
@ -142,11 +142,11 @@ private extension PaywallView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fullVersionFeaturesView: some View {
|
var allFeaturesView: some View {
|
||||||
FeatureListView(
|
FeatureListView(
|
||||||
style: allFeaturesStyle,
|
style: allFeaturesStyle,
|
||||||
header: Strings.Views.Paywall.Sections.AllFeatures.header,
|
header: Strings.Views.Paywall.Sections.AllFeatures.header,
|
||||||
features: fullVersionFeatures,
|
features: allFeatures,
|
||||||
content: featureView(for:)
|
content: featureView(for:)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -197,8 +197,8 @@ private extension PaywallView {
|
|||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
private extension PaywallView {
|
private extension PaywallView {
|
||||||
var fullVersionFeatures: [AppFeature] {
|
var allFeatures: [AppFeature] {
|
||||||
AppFeature.fullFeatures
|
AppProduct.Full.OneTime.allFeatures.features
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAvailableProducts() async {
|
func fetchAvailableProducts() async {
|
||||||
@ -285,9 +285,9 @@ private extension AppProduct {
|
|||||||
return .min
|
return .min
|
||||||
case .Full.Recurring.monthly:
|
case .Full.Recurring.monthly:
|
||||||
return 1
|
return 1
|
||||||
case .Full.OneTime.fullTV:
|
case .Full.OneTime.allFeatures:
|
||||||
return 2
|
return 2
|
||||||
case .Full.OneTime.full:
|
case .Full.OneTime.iOS_macOS:
|
||||||
return 3
|
return 3
|
||||||
default:
|
default:
|
||||||
return .max
|
return .max
|
||||||
|
@ -49,7 +49,7 @@ extension IAPManagerTests {
|
|||||||
let sut = IAPManager(receiptReader: reader)
|
let sut = IAPManager(receiptReader: reader)
|
||||||
|
|
||||||
let appProducts: [AppProduct] = [
|
let appProducts: [AppProduct] = [
|
||||||
.Full.OneTime.full,
|
.Full.OneTime.iOS_macOS,
|
||||||
.Donations.huge
|
.Donations.huge
|
||||||
]
|
]
|
||||||
let inAppProducts = try await sut.purchasableProducts(for: appProducts)
|
let inAppProducts = try await sut.purchasableProducts(for: appProducts)
|
||||||
@ -88,12 +88,12 @@ extension IAPManagerTests {
|
|||||||
await reader.setReceipt(withBuild: olderBuildNumber, identifiers: [])
|
await reader.setReceipt(withBuild: olderBuildNumber, identifiers: [])
|
||||||
let sut = IAPManager(receiptReader: reader) { build in
|
let sut = IAPManager(receiptReader: reader) { build in
|
||||||
if build <= self.defaultBuildNumber {
|
if build <= self.defaultBuildNumber {
|
||||||
return [.Full.OneTime.full]
|
return [.Full.OneTime.iOS_macOS]
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
XCTAssertTrue(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertTrue(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenBuildProducts_whenNewer_thenFreeVersion() async {
|
func test_givenBuildProducts_whenNewer_thenFreeVersion() async {
|
||||||
@ -101,12 +101,12 @@ extension IAPManagerTests {
|
|||||||
await reader.setReceipt(withBuild: newerBuildNumber, products: [])
|
await reader.setReceipt(withBuild: newerBuildNumber, products: [])
|
||||||
let sut = IAPManager(receiptReader: reader) { build in
|
let sut = IAPManager(receiptReader: reader) { build in
|
||||||
if build <= self.defaultBuildNumber {
|
if build <= self.defaultBuildNumber {
|
||||||
return [.Full.OneTime.full]
|
return [.Full.OneTime.iOS_macOS]
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
XCTAssertFalse(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertFalse(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,13 +117,13 @@ extension IAPManagerTests {
|
|||||||
let reader = FakeAppReceiptReader()
|
let reader = FakeAppReceiptReader()
|
||||||
let sut = IAPManager(receiptReader: reader)
|
let sut = IAPManager(receiptReader: reader)
|
||||||
|
|
||||||
XCTAssertFalse(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertFalse(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
|
|
||||||
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.full])
|
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.iOS_macOS])
|
||||||
XCTAssertFalse(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertFalse(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
|
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
XCTAssertTrue(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertTrue(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenPurchasedFeatures_thenIsOnlyEligibleForFeatures() async {
|
func test_givenPurchasedFeatures_thenIsOnlyEligibleForFeatures() async {
|
||||||
@ -139,20 +139,20 @@ extension IAPManagerTests {
|
|||||||
XCTAssertFalse(sut.isEligible(for: .onDemand))
|
XCTAssertFalse(sut.isEligible(for: .onDemand))
|
||||||
XCTAssertTrue(sut.isEligible(for: .routing))
|
XCTAssertTrue(sut.isEligible(for: .routing))
|
||||||
XCTAssertFalse(sut.isEligible(for: .sharing))
|
XCTAssertFalse(sut.isEligible(for: .sharing))
|
||||||
XCTAssertFalse(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertFalse(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenPurchasedAndCancelledFeature_thenIsNotEligible() async {
|
func test_givenPurchasedAndCancelledFeature_thenIsNotEligible() async {
|
||||||
let reader = FakeAppReceiptReader()
|
let reader = FakeAppReceiptReader()
|
||||||
await reader.setReceipt(
|
await reader.setReceipt(
|
||||||
withBuild: defaultBuildNumber,
|
withBuild: defaultBuildNumber,
|
||||||
products: [.Full.OneTime.full],
|
products: [.Full.OneTime.iOS_macOS],
|
||||||
cancelledProducts: [.Full.OneTime.full]
|
cancelledProducts: [.Full.OneTime.iOS_macOS]
|
||||||
)
|
)
|
||||||
let sut = IAPManager(receiptReader: reader)
|
let sut = IAPManager(receiptReader: reader)
|
||||||
|
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
XCTAssertFalse(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertFalse(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenFreeVersion_thenIsNotEligibleForAnyFeature() async {
|
func test_givenFreeVersion_thenIsNotEligibleForAnyFeature() async {
|
||||||
@ -161,7 +161,7 @@ extension IAPManagerTests {
|
|||||||
let sut = IAPManager(receiptReader: reader)
|
let sut = IAPManager(receiptReader: reader)
|
||||||
|
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
AppFeature.fullFeatures.forEach {
|
AppFeature.fullV2Features.forEach {
|
||||||
XCTAssertFalse(sut.isEligible(for: $0))
|
XCTAssertFalse(sut.isEligible(for: $0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ extension IAPManagerTests {
|
|||||||
|
|
||||||
func test_givenFullV2Version_thenIsEligibleForAnyFeatureExceptExcluded() async {
|
func test_givenFullV2Version_thenIsEligibleForAnyFeatureExceptExcluded() async {
|
||||||
let reader = FakeAppReceiptReader()
|
let reader = FakeAppReceiptReader()
|
||||||
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.full])
|
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.iOS_macOS])
|
||||||
let sut = IAPManager(receiptReader: reader)
|
let sut = IAPManager(receiptReader: reader)
|
||||||
|
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
@ -186,7 +186,7 @@ extension IAPManagerTests {
|
|||||||
.interactiveLogin
|
.interactiveLogin
|
||||||
]
|
]
|
||||||
AppFeature.allCases.forEach {
|
AppFeature.allCases.forEach {
|
||||||
if AppFeature.fullFeatures.contains($0) {
|
if AppFeature.fullV2Features.contains($0) {
|
||||||
XCTAssertTrue(sut.isEligible(for: $0))
|
XCTAssertTrue(sut.isEligible(for: $0))
|
||||||
} else {
|
} else {
|
||||||
XCTAssertTrue(excluded.contains($0))
|
XCTAssertTrue(excluded.contains($0))
|
||||||
@ -212,7 +212,7 @@ extension IAPManagerTests {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.macOS, .Features.networkSettings])
|
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.macOS, .Features.networkSettings])
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
XCTAssertTrue(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertTrue(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
#else
|
#else
|
||||||
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.iOS, .Features.networkSettings])
|
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.iOS, .Features.networkSettings])
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
@ -227,7 +227,7 @@ extension IAPManagerTests {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.iOS, .Features.networkSettings])
|
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.iOS, .Features.networkSettings])
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
XCTAssertFalse(sut.isEligible(for: AppFeature.fullFeatures))
|
XCTAssertFalse(sut.isEligible(for: AppFeature.fullV2Features))
|
||||||
#else
|
#else
|
||||||
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.macOS, .Features.networkSettings])
|
await reader.setReceipt(withBuild: defaultBuildNumber, products: [.Full.OneTime.macOS, .Features.networkSettings])
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
@ -266,23 +266,21 @@ extension IAPManagerTests {
|
|||||||
XCTAssertNil(sut.suggestedProducts(for: []))
|
XCTAssertNil(sut.suggestedProducts(for: []))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenFree_whenRequireFeature_thenSuggestsFullAndFullTV() async {
|
func test_givenFree_whenRequireFeature_thenSuggestsFullTV() async {
|
||||||
let sut = await IAPManager(products: [])
|
let sut = await IAPManager(products: [])
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.dns]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.dns]), [
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.full,
|
.Full.OneTime.allFeatures
|
||||||
.Full.OneTime.fullTV
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenFree_whenRequireAppleTV_thenSuggestsAppleTVAndFullTV() async {
|
func test_givenFree_whenRequireAppleTV_thenSuggestsFullTV() async {
|
||||||
let sut = await IAPManager(products: [])
|
let sut = await IAPManager(products: [])
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
||||||
.Features.appleTV,
|
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV
|
.Full.OneTime.allFeatures
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +289,7 @@ extension IAPManagerTests {
|
|||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV
|
.Full.OneTime.allFeatures
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,43 +298,39 @@ extension IAPManagerTests {
|
|||||||
XCTAssertNil(sut.suggestedProducts(for: [.dns]))
|
XCTAssertNil(sut.suggestedProducts(for: [.dns]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenCurrentPlatform_whenRequireAppleTV_thenSuggestsAppleTVAndFullTV() async {
|
func test_givenCurrentPlatform_whenRequireAppleTV_thenSuggestsFullTV() async {
|
||||||
let sut = await IAPManager.withFullCurrentPlatform()
|
let sut = await IAPManager.withFullCurrentPlatform()
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
||||||
.Features.appleTV,
|
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV
|
.Full.OneTime.allFeatures
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenCurrentPlatform_whenRequireFeatureAndAppleTV_thenSuggestsAppleTVAndFullTV() async {
|
func test_givenCurrentPlatform_whenRequireFeatureAndAppleTV_thenSuggestsFullTV() async {
|
||||||
let sut = await IAPManager.withFullCurrentPlatform()
|
let sut = await IAPManager.withFullCurrentPlatform()
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
||||||
.Features.appleTV,
|
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV
|
.Full.OneTime.allFeatures
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenOtherPlatform_whenRequireFeature_thenSuggestsFullAndFullTV() async {
|
func test_givenOtherPlatform_whenRequireFeature_thenSuggestsFullTV() async {
|
||||||
let sut = await IAPManager.withFullOtherPlatform()
|
let sut = await IAPManager.withFullOtherPlatform()
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.dns]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.dns]), [
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV,
|
.Full.OneTime.allFeatures
|
||||||
.Full.OneTime.full
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenOtherPlatform_whenRequireAppleTV_thenSuggestsAppleTVAndFullTV() async {
|
func test_givenOtherPlatform_whenRequireAppleTV_thenSuggestsFullTV() async {
|
||||||
let sut = await IAPManager.withFullOtherPlatform()
|
let sut = await IAPManager.withFullOtherPlatform()
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
||||||
.Features.appleTV,
|
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV
|
.Full.OneTime.allFeatures
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,24 +339,24 @@ extension IAPManagerTests {
|
|||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
||||||
.Full.Recurring.yearly,
|
.Full.Recurring.yearly,
|
||||||
.Full.Recurring.monthly,
|
.Full.Recurring.monthly,
|
||||||
.Full.OneTime.fullTV
|
.Full.OneTime.allFeatures
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenFull_whenRequireFeature_thenSuggestsNothing() async {
|
func test_givenFull_whenRequireFeature_thenSuggestsNothing() async {
|
||||||
let sut = await IAPManager(products: [.Full.OneTime.full])
|
let sut = await IAPManager(products: [.Full.OneTime.iOS_macOS])
|
||||||
XCTAssertNil(sut.suggestedProducts(for: [.dns]))
|
XCTAssertNil(sut.suggestedProducts(for: [.dns]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenFull_whenRequireAppleTV_thenSuggestsAppleTV() async {
|
func test_givenFull_whenRequireAppleTV_thenSuggestsAppleTV() async {
|
||||||
let sut = await IAPManager(products: [.Full.OneTime.full])
|
let sut = await IAPManager(products: [.Full.OneTime.iOS_macOS])
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV]), [
|
||||||
.Features.appleTV
|
.Features.appleTV
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenFull_whenRequireFeatureAndAppleTV_thenSuggestsAppleTV() async {
|
func test_givenFull_whenRequireFeatureAndAppleTV_thenSuggestsAppleTV() async {
|
||||||
let sut = await IAPManager(products: [.Full.OneTime.full])
|
let sut = await IAPManager(products: [.Full.OneTime.iOS_macOS])
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
||||||
.Features.appleTV
|
.Features.appleTV
|
||||||
])
|
])
|
||||||
@ -371,7 +365,7 @@ extension IAPManagerTests {
|
|||||||
func test_givenAppleTV_whenRequireFeature_thenSuggestsFull() async {
|
func test_givenAppleTV_whenRequireFeature_thenSuggestsFull() async {
|
||||||
let sut = await IAPManager(products: [.Features.appleTV])
|
let sut = await IAPManager(products: [.Features.appleTV])
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.dns]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.dns]), [
|
||||||
.Full.OneTime.full
|
.Full.OneTime.iOS_macOS
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,22 +377,22 @@ extension IAPManagerTests {
|
|||||||
func test_givenAppleTV_whenRequireFeatureAndAppleTV_thenSuggestsFull() async {
|
func test_givenAppleTV_whenRequireFeatureAndAppleTV_thenSuggestsFull() async {
|
||||||
let sut = await IAPManager(products: [.Features.appleTV])
|
let sut = await IAPManager(products: [.Features.appleTV])
|
||||||
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
XCTAssertEqual(sut.suggestedProducts(for: [.appleTV, .providers]), [
|
||||||
.Full.OneTime.full
|
.Full.OneTime.iOS_macOS
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenAll_whenRequireFeature_thenSuggestsNothing() async {
|
func test_givenFullTV_whenRequireFeature_thenSuggestsNothing() async {
|
||||||
let sut = await IAPManager(products: [.Full.OneTime.fullTV])
|
let sut = await IAPManager(products: [.Full.OneTime.allFeatures])
|
||||||
XCTAssertNil(sut.suggestedProducts(for: [.dns]))
|
XCTAssertNil(sut.suggestedProducts(for: [.dns]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenAll_whenRequireAppleTV_thenSuggestsNothing() async {
|
func test_givenFullTV_whenRequireAppleTV_thenSuggestsNothing() async {
|
||||||
let sut = await IAPManager(products: [.Full.OneTime.fullTV])
|
let sut = await IAPManager(products: [.Full.OneTime.allFeatures])
|
||||||
XCTAssertNil(sut.suggestedProducts(for: [.appleTV]))
|
XCTAssertNil(sut.suggestedProducts(for: [.appleTV]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_givenAll_whenRequireFeatureAndAppleTV_thenSuggestsNothing() async {
|
func test_givenFullTV_whenRequireFeatureAndAppleTV_thenSuggestsNothing() async {
|
||||||
let sut = await IAPManager(products: [.Full.OneTime.fullTV])
|
let sut = await IAPManager(products: [.Full.OneTime.allFeatures])
|
||||||
XCTAssertNil(sut.suggestedProducts(for: [.appleTV, .providers]))
|
XCTAssertNil(sut.suggestedProducts(for: [.appleTV, .providers]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,7 +440,7 @@ extension IAPManagerTests {
|
|||||||
|
|
||||||
func test_givenFullV2App_thenIsEligibleForAnyFeatureExceptExcluded() async {
|
func test_givenFullV2App_thenIsEligibleForAnyFeatureExceptExcluded() async {
|
||||||
let reader = FakeAppReceiptReader()
|
let reader = FakeAppReceiptReader()
|
||||||
let sut = IAPManager(customUserLevel: .full, receiptReader: reader)
|
let sut = IAPManager(customUserLevel: .fullV2, receiptReader: reader)
|
||||||
|
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
let excluded: Set<AppFeature> = [
|
let excluded: Set<AppFeature> = [
|
||||||
@ -454,7 +448,7 @@ extension IAPManagerTests {
|
|||||||
.interactiveLogin
|
.interactiveLogin
|
||||||
]
|
]
|
||||||
AppFeature.allCases.forEach {
|
AppFeature.allCases.forEach {
|
||||||
if AppFeature.fullFeatures.contains($0) {
|
if AppFeature.fullV2Features.contains($0) {
|
||||||
XCTAssertTrue(sut.isEligible(for: $0))
|
XCTAssertTrue(sut.isEligible(for: $0))
|
||||||
} else {
|
} else {
|
||||||
XCTAssertTrue(excluded.contains($0))
|
XCTAssertTrue(excluded.contains($0))
|
||||||
@ -465,10 +459,10 @@ extension IAPManagerTests {
|
|||||||
|
|
||||||
func test_givenSubscriberApp_thenIsEligibleForAnyFeature() async {
|
func test_givenSubscriberApp_thenIsEligibleForAnyFeature() async {
|
||||||
let reader = FakeAppReceiptReader()
|
let reader = FakeAppReceiptReader()
|
||||||
let sut = IAPManager(customUserLevel: .fullTV, receiptReader: reader)
|
let sut = IAPManager(customUserLevel: .fullV3, receiptReader: reader)
|
||||||
|
|
||||||
await sut.reloadReceipt()
|
await sut.reloadReceipt()
|
||||||
AppFeature.fullFeatures.forEach {
|
AppFeature.fullV2Features.forEach {
|
||||||
XCTAssertTrue(sut.isEligible(for: $0))
|
XCTAssertTrue(sut.isEligible(for: $0))
|
||||||
}
|
}
|
||||||
XCTAssertTrue(sut.isEligible(for: .appleTV))
|
XCTAssertTrue(sut.isEligible(for: .appleTV))
|
||||||
@ -545,7 +539,7 @@ extension IAPManagerTests {
|
|||||||
extension IAPManagerTests {
|
extension IAPManagerTests {
|
||||||
func test_givenManager_whenObserveObjects_thenReloadsReceipt() async {
|
func test_givenManager_whenObserveObjects_thenReloadsReceipt() async {
|
||||||
let reader = FakeAppReceiptReader()
|
let reader = FakeAppReceiptReader()
|
||||||
await reader.setReceipt(withBuild: .max, products: [.Full.OneTime.full])
|
await reader.setReceipt(withBuild: .max, products: [.Full.OneTime.iOS_macOS])
|
||||||
let sut = IAPManager(receiptReader: reader)
|
let sut = IAPManager(receiptReader: reader)
|
||||||
|
|
||||||
XCTAssertEqual(sut.userLevel, .undefined)
|
XCTAssertEqual(sut.userLevel, .undefined)
|
||||||
@ -620,3 +614,7 @@ private extension IAPManager {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension AppFeature {
|
||||||
|
static let fullV2Features = AppProduct.Full.OneTime.iOS_macOS.features
|
||||||
|
}
|
||||||
|
@ -33,7 +33,7 @@ extension AppContext {
|
|||||||
static func forUITesting(withRegistry registry: Registry) -> AppContext {
|
static func forUITesting(withRegistry registry: Registry) -> AppContext {
|
||||||
let dependencies: Dependencies = .shared
|
let dependencies: Dependencies = .shared
|
||||||
let iapManager = IAPManager(
|
let iapManager = IAPManager(
|
||||||
customUserLevel: .fullTV,
|
customUserLevel: .fullV3,
|
||||||
inAppHelper: dependencies.appProductHelper(),
|
inAppHelper: dependencies.appProductHelper(),
|
||||||
receiptReader: FakeAppReceiptReader(),
|
receiptReader: FakeAppReceiptReader(),
|
||||||
betaChecker: TestFlightChecker(),
|
betaChecker: TestFlightChecker(),
|
||||||
|
Loading…
Reference in New Issue
Block a user