FBSDKCoreKit/FBSDKCoreKitTests/SettingsTests.swift (1,400 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
@testable import FBSDKCoreKit
import XCTest
final class SettingsTests: XCTestCase {
// swiftlint:disable implicitly_unwrapped_optional
var logger: TestEventLogger!
var appEventsConfigurationProvider: TestAppEventsConfigurationProvider!
var userDefaultsSpy: UserDefaultsSpy!
var settings: Settings!
var bundle: InfoDictionaryProviding!
// swiftlint:enable implicitly_unwrapped_optional
var testBundle: TestBundle {
bundle as! TestBundle // swiftlint:disable:this force_cast
}
var userAgentSuffix = ""
static let emptyString = ""
static let whiteSpaceToken = " "
override func setUp() {
super.setUp()
logger = TestEventLogger()
appEventsConfigurationProvider = TestAppEventsConfigurationProvider()
userDefaultsSpy = UserDefaultsSpy()
bundle = TestBundle()
settings = Settings()
configureSettings()
}
override func tearDown() {
logger = nil
appEventsConfigurationProvider = nil
userDefaultsSpy = nil
bundle = nil
settings = nil
super.tearDown()
}
private func configureSettings() {
settings.configure(
store: userDefaultsSpy,
appEventsConfigurationProvider: appEventsConfigurationProvider,
infoDictionaryProvider: bundle,
eventLogger: logger
)
}
func testDefaultUserDefaultsSpy() {
settings.reset()
XCTAssertNil(
settings.store,
"Settings should not have a default data userDefaultsSpy"
)
}
func testConfiguringWithUserDefaultsSpy() {
XCTAssertTrue(
settings.store === userDefaultsSpy,
"Should be able to set a persistent data userDefaultsSpy"
)
}
func testDefaultAppEventsConfigurationProvider() {
settings.reset()
XCTAssertNil(
settings.appEventsConfigurationProvider,
"Settings should not have a default app events configuration provider"
)
}
func testConfiguringWithAppEventsConfigurationProvider() {
XCTAssertTrue(
settings.appEventsConfigurationProvider === appEventsConfigurationProvider,
"Should be able to set an app events configuration provider"
)
}
func testDefaultInfoDictionaryProvider() {
settings.reset()
XCTAssertNil(
settings.infoDictionaryProvider,
"Settings should not have a default info dictionary provider"
)
}
func testConfiguringWithInfoDictionaryProvider() {
XCTAssertTrue(
settings.infoDictionaryProvider === bundle,
"Should be able to set an info dictionary provider"
)
}
func testDefaultEventLogger() {
settings.reset()
XCTAssertNil(
settings.eventLogger,
"Settings should not have a default event logger"
)
}
func testConfiguringWithEventLogger() {
XCTAssertTrue(
settings.eventLogger === logger,
"Should be able to set an event logger"
)
}
// MARK: Advertiser Tracking Status
func testFacebookAdvertiserTrackingStatusDefaultValue() {
let configuration = TestAppEventsConfiguration(defaultATEStatus: .disallowed)
appEventsConfigurationProvider.stubbedConfiguration = configuration
XCTAssertEqual(
settings.advertisingTrackingStatus,
configuration.defaultATEStatus,
"""
Advertiser tracking status should use the cached app events configuration
when there is no persisted overridden value
"""
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
"com.facebook.sdk:FBSDKSettingsAdvertisingTrackingStatus",
"""
Should attempt to retrieve the tracking status from the data userDefaultsSpy before
checking the cached configuration
"""
)
XCTAssertTrue(
appEventsConfigurationProvider.didRetrieveCachedConfiguration,
"Should attempt to retrieve the tracking status from a cached configuration"
)
}
func testGettingExplicitlySetFacebookAdvertiserTrackingStatus() {
settings.setAdvertiserTrackingStatus(.disallowed)
XCTAssertEqual(
settings.advertisingTrackingStatus,
.disallowed,
"Should return the explicitly set tracking status"
)
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to retrieve the tracking status from the data userDefaultsSpy"
)
XCTAssertFalse(
appEventsConfigurationProvider.didRetrieveCachedConfiguration,
"Should not attempt to retrieve the tracking status from a cached configuration"
)
}
func testGettingPersistedFacebookAdvertiserTrackingStatus() {
let key = "com.facebook.sdk:FBSDKSettingsAdvertisingTrackingStatus"
userDefaultsSpy.set(
NSNumber(value: AdvertisingTrackingStatus.allowed.rawValue),
forKey: key
)
XCTAssertEqual(
settings.advertisingTrackingStatus,
.allowed,
"Should return the tracking status from the data userDefaultsSpy"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
key,
"Should retrieve the tracking status from the data userDefaultsSpy"
)
XCTAssertFalse(
appEventsConfigurationProvider.didRetrieveCachedConfiguration,
"Should not attempt to retrieve the tracking status from a cached configuration"
)
}
func testGettingCachedFacebookAdvertiserTrackingStatus() {
let key = "com.facebook.sdk:FBSDKSettingsAdvertisingTrackingStatus"
userDefaultsSpy.set(
NSNumber(value: AdvertisingTrackingStatus.allowed.rawValue),
forKey: key
)
XCTAssertEqual(
settings.advertisingTrackingStatus,
.allowed,
"Should return the tracking status from the data userDefaultsSpy"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
key,
"Should retrieve the tracking status from the data userDefaultsSpy"
)
XCTAssertFalse(
appEventsConfigurationProvider.didRetrieveCachedConfiguration,
"Should not attempt to retrieve the tracking status from a cached configuration"
)
}
func testSettingFacebookAdvertiserTrackingStatusToEnabled() {
settings.isAdvertiserTrackingEnabled = true
XCTAssertEqual(
userDefaultsSpy.capturedSetObjectKey,
"com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp",
"Should persist the time when the tracking status is set to enabled"
)
}
func testSettingFacebookAdvertiserTrackingStatusToDisallowed() {
settings.isAdvertiserTrackingEnabled = false
XCTAssertEqual(
userDefaultsSpy.capturedSetObjectKey,
"com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp",
"Should persist the time when the tracking status is set to disallowed"
)
}
func testSettingFacebookAdvertiserTrackingStatusToEnabledProperty() {
settings.isAdvertiserTrackingEnabled = true
XCTAssertTrue(
settings.isAdvertiserTrackingEnabled,
"Setting advertiser tracking status should be allowed"
)
XCTAssertEqual(
userDefaultsSpy.capturedSetObjectKey,
"com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp",
"Should persist the time when the tracking status is set to enabled"
)
}
func testSettingFacebookAdvertiserTrackingStatusToDisallowedProperty() {
settings.isAdvertiserTrackingEnabled = false
XCTAssertFalse(
settings.isAdvertiserTrackingEnabled,
"Setting advertiser tracking status should be disallowed"
)
XCTAssertEqual(
userDefaultsSpy.capturedSetObjectKey,
"com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp",
"Should persist the time when the tracking status is set to disallowed"
)
}
func testSettingFacebookAdvertiserTrackingStatusToUnspecified() {
settings.setAdvertiserTrackingStatus(.unspecified)
XCTAssertNil(
userDefaultsSpy.object(forKey: "com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp"),
"Should not capture the time the status is set to unspecified"
)
}
// MARK: - Logging behaviors
func testLoggingBehaviors() {
let behaviors = Set([LoggingBehavior.accessTokens, .appEvents])
settings.loggingBehaviors = behaviors
XCTAssertEqual(
settings.loggingBehaviors,
behaviors,
"Should be able to set and retrieve logging behaviors"
)
}
func testEnableLoggingBehaviors() {
let appEvents = LoggingBehavior(rawValue: "app_events")
let networkRequests = LoggingBehavior(rawValue: "network_requests")
let mockLoggingBehaviors = Set([appEvents, networkRequests])
let informationBehaviort = LoggingBehavior(rawValue: "informational")
settings.setLoggingBehaviors(mockLoggingBehaviors)
XCTAssertEqual(mockLoggingBehaviors, settings.loggingBehaviors)
// test enable logging behavior
settings.enableLoggingBehavior(LoggingBehavior(rawValue: "informational"))
XCTAssertTrue(settings.loggingBehaviors.contains(informationBehaviort))
settings.disableLoggingBehavior(informationBehaviort)
XCTAssertFalse(settings.loggingBehaviors.contains(informationBehaviort))
}
// MARK: - Graph Error Recovery Enabled
func testDefaultGraphErrorRecoveryEnabled() {
XCTAssertTrue(
settings.isGraphErrorRecoveryEnabled,
"isGraphErrorRecoveryEnabled should be enabled by default"
)
}
func testDefaultGraphAPIVersion() {
XCTAssertEqual(
settings.graphAPIVersion,
FBSDK_DEFAULT_GRAPH_API_VERSION,
"Settings should provide a default graph api version"
)
}
// MARK: - Logging Behaviors
func testSettingsBehaviorsFromMissingPlistEntry() {
let expected: Set = [LoggingBehavior.developerErrors]
XCTAssertEqual(
settings.loggingBehaviors,
expected,
"Logging behaviors should default to developer errors when there is no plist entry"
)
}
func testSettingBehaviorsFromPlistWithInvalidEntry() {
bundle = TestBundle(infoDictionary: ["FacebookLoggingBehavior": ["Foo"]])
configureSettings()
XCTAssertEqual(
settings.loggingBehaviors.first,
LoggingBehavior(rawValue: "Foo"),
"Logging behaviors should default to developer errors when"
+ "settings are created with a plist that only has invalid entries but it does not"
)
}
func testSettingBehaviorsFromPlistWithValidEntry() {
bundle = Bundle(for: Settings.self)
configureSettings()
let expected = Set([LoggingBehavior.developerErrors])
XCTAssertEqual(settings.loggingBehaviors, expected)
}
func testLoggingBehaviorsInternalStorage() throws {
settings.loggingBehaviors = Set([LoggingBehavior.informational])
XCTAssertNotNil(settings.loggingBehaviors, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Domain Prefix
func testSettingDomainPrefixFromMissingPlistEntry() {
XCTAssertNil(
settings.facebookDomainPart,
"There should be no default value for a facebook domain prefix"
)
}
func testSettingDomainPrefixFromEmptyPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookDomainPart": Self.emptyString])
configureSettings()
XCTAssertEqual(
settings.facebookDomainPart,
Self.emptyString,
"Should not use an empty string as a facebook domain prefix but it does"
)
}
func testSettingFacebookDomainPrefixFromPlist() {
bundle = TestBundle(infoDictionary: ["FacebookDomainPart": "beta"])
configureSettings()
XCTAssertEqual(
settings.facebookDomainPart,
"beta",
"A developer should be able to set any string as the facebook domain prefix to use in building urls"
)
}
func testSettingDomainPrefixWithPlistEntry() {
let domainPrefix = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookDomainPart": domainPrefix])
configureSettings()
settings.facebookDomainPart = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDomainPart"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.facebookDomainPart,
"foo",
"Settings should return the explicitly set domain prefix over one gleaned from a plist entry"
)
}
func testSettingDomainPrefixWithoutPlistEntry() {
settings.facebookDomainPart = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDomainPart"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.facebookDomainPart,
"foo",
"Settings should return the explicitly set domain prefix"
)
}
func testSettingEmptyDomainPrefix() {
settings.facebookDomainPart = Self.emptyString
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDomainPart"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.facebookDomainPart,
Self.emptyString,
"Settings should return the explicitly set domain prefix"
)
}
func testSettingWhitespaceOnlyDomainPrefix() {
settings.facebookDomainPart = Self.whiteSpaceToken
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDomainPart"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.facebookDomainPart,
Self.whiteSpaceToken,
"Settings should return the explicitly set domain prefix"
)
}
func testDomainPartInternalStorage() {
settings.facebookDomainPart = "foo"
resetLoggingSideEffects()
XCTAssertNotNil(settings.facebookDomainPart, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Client Token
func testClientTokenFromPlist() {
let clientToken = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookClientToken": clientToken])
configureSettings()
XCTAssertEqual(
settings.clientToken,
clientToken,
"A developer should be able to set any string as the client token"
)
}
func testClientTokenFromMissingPlistEntry() {
XCTAssertNil(
settings.clientToken,
"A client token should not have a default value if it is not available in the plist"
)
}
func testSettingClientTokenFromEmptyPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookClientToken": Self.emptyString])
configureSettings()
XCTAssertEqual(
settings.clientToken,
Self.emptyString,
"Should not use an empty string as a facebook client token but it will"
)
}
func testSettingClientTokenWithPlistEntry() {
let clientToken = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookClientToken": clientToken])
configureSettings()
settings.clientToken = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookClientToken"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookClientToken"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.clientToken,
"foo",
"Settings should return the explicitly set client token over one gleaned from a plist entry"
)
}
func testSettingClientTokenWithoutPlistEntry() {
settings.clientToken = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookClientToken"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.clientToken,
"foo",
"Settings should return the explicitly set client token"
)
}
func testSettingEmptyClientToken() {
settings.clientToken = Self.emptyString
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookClientToken"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.clientToken,
Self.emptyString,
"Should not userDefaultsSpy an invalid token but it will"
)
}
func testSettingWhitespaceOnlyClientToken() {
settings.clientToken = Self.whiteSpaceToken
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookClientToken"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.clientToken,
Self.whiteSpaceToken,
"Should not userDefaultsSpy a whitespace only client token but it will"
)
}
func testClientTokenInternalStorage() {
settings.clientToken = "foo"
resetLoggingSideEffects()
XCTAssertNotNil(settings.clientToken, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - App Identifier
func testAppIdentifierFromPlist() {
let appIdentifier = "abc1234"
bundle = TestBundle(infoDictionary: ["FacebookAppID": appIdentifier])
configureSettings()
XCTAssertEqual(
settings.appID,
appIdentifier,
"A developer should be able to set any string as the app identifier"
)
}
func testAppIdentifierFromMissingPlistEntry() {
XCTAssertNil(
settings.appID,
"An app identifier should not have a default value if it is not available in the plist"
)
}
func testSettingAppIdentifierFromEmptyPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookAppID": Self.emptyString])
configureSettings()
XCTAssertEqual(
settings.appID,
Self.emptyString,
"Should not use an empty string as an app identifier but it will"
)
}
func testSettingAppIdentifierWithPlistEntry() {
let appIdentifier = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookClientToken": appIdentifier])
configureSettings()
settings.appID = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookAppID"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appID,
"foo",
"Settings should return the explicitly set app identifier over one gleaned from a plist entry"
)
}
func testSettingAppIdentifierWithoutPlistEntry() {
settings.appID = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookAppID"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appID,
"foo",
"Settings should return the explicitly set app identifier"
)
}
func testSettingEmptyAppIdentifier() {
settings.appID = Self.emptyString
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookAppID"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appID,
Self.emptyString,
"Should not userDefaultsSpy an empty app identifier but it will"
)
}
func testSettingWhitespaceOnlyAppIdentifier() {
settings.appID = Self.whiteSpaceToken
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookAppID"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appID,
Self.whiteSpaceToken,
"Should not userDefaultsSpy a whitespace only app identifier but it will"
)
}
func testAppIdentifierInternalStorage() {
settings.appID = "foo"
resetLoggingSideEffects()
XCTAssertNotNil(settings.appID, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Display Name
func testDisplayNameFromPlist() {
let displayName = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookDisplayName": displayName])
configureSettings()
XCTAssertEqual(
settings.displayName,
displayName,
"A developer should be able to set any string as the display name"
)
}
func testDisplayNameFromMissingPlistEntry() {
XCTAssertNil(
settings.displayName,
"A display name should not have a default value if it is not available in the plist"
)
}
func testSettingDisplayNameFromEmptyPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookDisplayName": Self.emptyString])
configureSettings()
XCTAssertEqual(
settings.displayName,
Self.emptyString,
"Should not use an empty string as a display name but it will"
)
}
func testSettingDisplayNameWithPlistEntry() {
let displayName = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookDisplayName": displayName])
configureSettings()
settings.displayName = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDisplayName"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.displayName,
"foo",
"Settings should return the explicitly set display name over one gleaned from a plist entry"
)
}
func testSettingDisplayNameWithoutPlistEntry() {
settings.displayName = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDisplayName"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.displayName,
"foo",
"Settings should return the explicitly set display name"
)
}
func testSettingEmptyDisplayName() {
settings.displayName = Self.emptyString
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDisplayName"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.displayName,
Self.emptyString,
"Should not userDefaultsSpy an empty display name but it will"
)
}
func testSettingWhitespaceOnlyDisplayName() {
settings.displayName = Self.whiteSpaceToken
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookDisplayName"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.displayName,
Self.whiteSpaceToken,
"Should not userDefaultsSpy a whitespace only display name but it will"
)
}
func testDisplayNameInternalStorage() {
settings.displayName = "foo"
resetLoggingSideEffects()
XCTAssertNotNil(settings.displayName, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - JPEG Compression Quality
func testJPEGCompressionQualityFromPlist() {
let jpegCompressionQuality = 0.1
bundle = TestBundle(infoDictionary: ["FacebookJpegCompressionQuality": jpegCompressionQuality])
configureSettings()
XCTAssertEqual(
Double(settings.jpegCompressionQuality),
jpegCompressionQuality,
accuracy: 0.01,
"A developer should be able to set a jpeg compression quality via the plist"
)
}
func testJPEGCompressionQualityFromMissingPlistEntry() {
XCTAssertEqual(
settings.jpegCompressionQuality,
0.9,
accuracy: 0.01,
"There should be a known default value for jpeg compression quality"
)
}
func testSettingJPEGCompressionQualityFromInvalidPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookJpegCompressionQuality": -2.0])
configureSettings()
XCTAssertNotEqual(
settings.jpegCompressionQuality,
-0.2,
"Should not use a negative value as a jpeg compression quality"
)
}
func testSettingJPEGCompressionQualityWithPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookJpegCompressionQuality": 0.2])
configureSettings()
settings.jpegCompressionQuality = 0.3
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookJpegCompressionQuality"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.jpegCompressionQuality,
0.3,
accuracy: 0.01,
"Settings should return the explicitly set jpeg compression quality over one gleaned from a plist entry"
)
}
func testSettingJPEGCompressionQualityWithoutPlistEntry() {
settings.jpegCompressionQuality = 1.0
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookJpegCompressionQuality"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.jpegCompressionQuality,
1.0,
"Settings should return the explicitly set jpeg compression quality"
)
}
func testSettingJPEGCompressionQualityTooLow() {
settings.jpegCompressionQuality = -0.1
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookJpegCompressionQuality"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertNotEqual(
settings.jpegCompressionQuality,
-0.1,
"Should not userDefaultsSpy a negative jpeg compression quality"
)
}
func testSettingJPEGCompressionQualityTooHigh() {
settings.jpegCompressionQuality = 1.1
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookJpegCompressionQuality"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertNotEqual(
settings.jpegCompressionQuality,
1.1,
"Should not userDefaultsSpy a jpeg compression quality that is larger than 1.0"
)
}
func testJPEGCompressionQualityInternalStorage() {
settings.jpegCompressionQuality = 1
resetLoggingSideEffects()
XCTAssertEqual(settings.jpegCompressionQuality, 1, "Sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - URL Scheme Suffix
func testURLSchemeSuffixFromPlist() {
let urlSchemeSuffix = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookUrlSchemeSuffix": urlSchemeSuffix])
configureSettings()
XCTAssertEqual(
settings.appURLSchemeSuffix,
urlSchemeSuffix,
"A developer should be able to set any string as the url scheme suffix"
)
}
func testURLSchemeSuffixFromMissingPlistEntry() {
XCTAssertNil(
settings.appURLSchemeSuffix,
"A url scheme suffix should not have a default value if it is not available in the plist"
)
}
func testSettingURLSchemeSuffixFromEmptyPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookUrlSchemeSuffix": Self.emptyString])
configureSettings()
XCTAssertEqual(
settings.appURLSchemeSuffix,
Self.emptyString,
"Should not use an empty string as a url scheme suffix but it will"
)
}
func testSettingURLSchemeSuffixWithPlistEntry() {
let urlSchemeSuffix = "abc123"
bundle = TestBundle(infoDictionary: ["FacebookUrlSchemeSuffix": urlSchemeSuffix])
configureSettings()
settings.appURLSchemeSuffix = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookUrlSchemeSuffix"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appURLSchemeSuffix,
"foo",
"Settings should return the explicitly set url scheme suffix over one gleaned from a plist entry"
)
}
func testSettingURLSchemeSuffixWithoutPlistEntry() {
settings.appURLSchemeSuffix = "foo"
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookUrlSchemeSuffix"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appURLSchemeSuffix,
"foo",
"Settings should return the explicitly set url scheme suffix"
)
}
func testSettingEmptyURLSchemeSuffix() {
settings.appURLSchemeSuffix = Self.emptyString
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookUrlSchemeSuffix"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appURLSchemeSuffix,
Self.emptyString,
"Should not userDefaultsSpy an empty url scheme suffix but it will"
)
}
func testSettingWhitespaceOnlyURLSchemeSuffix() {
settings.appURLSchemeSuffix = Self.whiteSpaceToken
XCTAssertNil(
userDefaultsSpy.capturedValues["FacebookUrlSchemeSuffix"],
"Should not persist the value of a non-cachable property when setting it"
)
XCTAssertEqual(
settings.appURLSchemeSuffix,
Self.whiteSpaceToken,
"Should not userDefaultsSpy a whitespace only url scheme suffix but it will"
)
}
func testURLSchemeSuffixInternalStorage() {
settings.appURLSchemeSuffix = "foo"
resetLoggingSideEffects()
XCTAssertNotNil(settings.appURLSchemeSuffix, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Auto Log App Events Enabled
func testAutoLogAppEventsEnabledFromPlist() {
bundle = TestBundle(infoDictionary: ["FacebookAutoLogAppEventsEnabled": false])
configureSettings()
XCTAssertFalse(
settings.isAutoLogAppEventsEnabled,
"A developer should be able to set the value of auto log app events from the plist"
)
}
func testAutoLogAppEventsEnabledDefaultValue() {
XCTAssertTrue(
settings.isAutoLogAppEventsEnabled,
"Auto logging of app events should default to true when there is no plist value given"
)
}
func testAutoLogAppEventsEnabledInvalidPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookAutoLogAppEventsEnabled": Self.emptyString])
configureSettings()
XCTAssertFalse(
settings.isAutoLogAppEventsEnabled,
"Auto logging of app events should default to true when there is an invalid plist value given but it does not"
)
}
func testSettingAutoLogAppEventsEnabled() {
settings.isAutoLogAppEventsEnabled = false
XCTAssertNotNil(
userDefaultsSpy.capturedValues["FacebookAutoLogAppEventsEnabled"],
"Should persist the value of a cachable property when setting it"
)
XCTAssertFalse(
settings.isAutoLogAppEventsEnabled,
"Should use the explicitly set property"
)
}
func testOverridingCachedAutoLogAppEventsEnabled() {
XCTAssertTrue(settings.isAutoLogAppEventsEnabled)
bundle = TestBundle(infoDictionary: ["FacebookAutoLogAppEventsEnabled": false])
configureSettings()
XCTAssertTrue(
settings.isAutoLogAppEventsEnabled,
"Should favor cached properties over those set in the plist"
)
}
func testAutoLogAppEventsEnabledInternalStorage() {
settings.isAutoLogAppEventsEnabled = true
resetLoggingSideEffects()
XCTAssertTrue(settings.isAutoLogAppEventsEnabled, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Advertiser Identifier Collection Enabled
func testFacebookAdvertiserIDCollectionEnabled() {
bundle = TestBundle(infoDictionary: ["FacebookAdvertiserIDCollectionEnabled": false])
configureSettings()
XCTAssertFalse(
settings.isAdvertiserIDCollectionEnabled,
"A developer should be able to set whether advertiser ID collection is enabled from the plist"
)
}
func testFacebookAdvertiserIDCollectionEnabledDefaultValue() {
XCTAssertTrue(
settings.isAdvertiserIDCollectionEnabled,
"Auto collection of advertiser Any should default to true when there is no plist value given"
)
}
func testFacebookAdvertiserIDCollectionEnabledInvalidPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookAdvertiserIDCollectionEnabled": Self.emptyString])
configureSettings()
XCTAssertFalse(
settings.isAdvertiserIDCollectionEnabled,
"Auto collection of advertiser Any should default to true when"
+ "there is an invalid plist value given but it does not"
)
}
func testSettingFacebookAdvertiserIDCollectionEnabled() {
settings.isAdvertiserIDCollectionEnabled = false
XCTAssertNotNil(
userDefaultsSpy.capturedValues["FacebookAdvertiserIDCollectionEnabled"],
"Should persist the value of a cachable property when setting it"
)
XCTAssertFalse(
settings.isAdvertiserIDCollectionEnabled,
"Should use the explicitly set property"
)
}
func testOverridingCachedFacebookAdvertiserIDCollectionEnabled() {
settings.isAdvertiserIDCollectionEnabled = true
XCTAssertTrue(settings.isAdvertiserIDCollectionEnabled)
bundle = TestBundle(infoDictionary: ["FacebookAdvertiserIDCollectionEnabled": false])
configureSettings()
XCTAssertTrue(
settings.isAdvertiserIDCollectionEnabled,
"Should favor cached properties over those set in the plist"
)
}
func testAdvertiserIDCollectionEnabledInternalStorage() {
settings.isAdvertiserIDCollectionEnabled = true
resetLoggingSideEffects()
XCTAssertTrue(settings.isAdvertiserIDCollectionEnabled, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - SKAdNetwork Report Enabled
func testFacebookSKAdNetworkReportEnabledFromPlist() {
bundle = TestBundle(infoDictionary: ["FacebookSKAdNetworkReportEnabled": false])
configureSettings()
XCTAssertFalse(
settings.isSKAdNetworkReportEnabled,
"A developer should be able to set the value of SKAdNetwork Report from the plist"
)
}
func testFacebookSKAdNetworkReportEnabledDefaultValue() {
XCTAssertTrue(
settings.isSKAdNetworkReportEnabled,
"SKAdNetwork Report should default to true when there is no plist value given"
)
}
func testFacebookSKAdNetworkReportEnabledInvalidPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookSKAdNetworkReportEnabled": Self.emptyString])
configureSettings()
XCTAssertFalse(
settings.isSKAdNetworkReportEnabled,
"SKAdNetwork Report should default to true when there is an invalid plist value given but it does not"
)
}
func testSettingFacebookSKAdNetworkReportEnabled() {
settings.isSKAdNetworkReportEnabled = false
XCTAssertNotNil(
userDefaultsSpy.capturedValues["FacebookSKAdNetworkReportEnabled"],
"Should persist the value of a cachable property when setting it"
)
XCTAssertFalse(
settings.isSKAdNetworkReportEnabled,
"Should use the explicitly set property"
)
}
func testOverridingCachedFacebookSKAdNetworkReportEnabled() {
XCTAssertTrue(settings.isSKAdNetworkReportEnabled)
bundle = TestBundle(infoDictionary: ["FacebookSKAdNetworkReportEnabled": false])
configureSettings()
XCTAssertTrue(
settings.isSKAdNetworkReportEnabled,
"Should favor cached properties over those set in the plist"
)
}
func testFacebookSKAdNetworkReportEnabledInternalStorage() {
settings.isSKAdNetworkReportEnabled = true
resetLoggingSideEffects()
XCTAssertTrue(settings.isSKAdNetworkReportEnabled, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Codeless Debug Log Enabled
func testFacebookCodelessDebugLogEnabled() {
bundle = TestBundle(infoDictionary: ["FacebookCodelessDebugLogEnabled": false])
configureSettings()
XCTAssertFalse(
settings.isCodelessDebugLogEnabled,
"A developer should be able to set whether codeless debug logging is enabled from the plist"
)
}
func testFacebookCodelessDebugLogEnabledDefaultValue() {
bundle = TestBundle(infoDictionary: [:])
configureSettings()
XCTAssertFalse(
settings.isCodelessDebugLogEnabled,
"Codeless debug logging enabled should default to false when there is no plist value given"
)
}
func testFacebookCodelessDebugLogEnabledInvalidPlistEntry() {
bundle = TestBundle(infoDictionary: ["FacebookCodelessDebugLogEnabled": Self.emptyString])
configureSettings()
XCTAssertFalse(
settings.isCodelessDebugLogEnabled,
"Codeless debug logging enabled should default to true when there is an invalid plist value given but it does not"
)
}
func testSettingFacebookCodelessDebugLogEnabled() {
settings.isCodelessDebugLogEnabled = false
XCTAssertNotNil(
userDefaultsSpy.capturedValues["FacebookCodelessDebugLogEnabled"],
"Should persist the value of a cachable property when setting it"
)
XCTAssertFalse(
settings.isCodelessDebugLogEnabled,
"Should use the explicitly set property"
)
}
func testOverridingCachedFacebookCodelessDebugLogEnabled() {
settings.isCodelessDebugLogEnabled = true
XCTAssertTrue(settings.isCodelessDebugLogEnabled)
bundle = TestBundle(infoDictionary: ["FacebookCodelessDebugLogEnabled": false])
configureSettings()
XCTAssertTrue(
settings.isCodelessDebugLogEnabled,
"Should favor cached properties over those set in the plist"
)
}
func testCachedFacebookCodelessDebugLogEnabledInternalStorage() {
settings.isCodelessDebugLogEnabled = true
resetLoggingSideEffects()
XCTAssertTrue(settings.isCodelessDebugLogEnabled, "sanity check")
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
// MARK: - Caching Properties
func testInitialAccessForCachablePropertyWithNonEmptyCache() {
// Using false because it is not the default value for `isAutoInitializationEnabled`
userDefaultsSpy.capturedValues = ["FacebookAutoLogAppEventsEnabled": false]
XCTAssertFalse(
settings.isAutoLogAppEventsEnabled,
"Should retrieve an initial value for a cachable property when there is a non-empty cache"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
"FacebookAutoLogAppEventsEnabled",
"Should attempt to access the cache to retrieve the initial value for a cachable property"
)
XCTAssertFalse(
testBundle.capturedKeys.contains("FacebookAutoLogAppEventsEnabled"),
"Should not attempt to access the plist for cachable properties that have a value in the cache"
)
}
func testInitialAccessForCachablePropertyWithEmptyCacheNonEmptyPlist() {
// Using false because it is not the default value for `isAutoInitializationEnabled`
bundle = TestBundle(infoDictionary: ["FacebookAutoLogAppEventsEnabled": false])
configureSettings()
XCTAssertFalse(
settings.isAutoLogAppEventsEnabled,
"Should retrieve an initial value from the property list"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
"FacebookAutoLogAppEventsEnabled",
"Should attempt to access the cache to retrieve the initial value for a cachable property"
)
XCTAssertEqual(
testBundle.capturedKeys.last,
"FacebookAutoLogAppEventsEnabled",
"Should attempt to access the plist for cachable properties that have no value in the cache"
)
}
func testInitialAccessForCachablePropertyWithEmptyCacheEmptyPlistAndDefaultValue() {
XCTAssertTrue(
settings.isAutoLogAppEventsEnabled,
"Should use the default value for a property when there are no values in the cache or plist"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
"FacebookAutoLogAppEventsEnabled",
"Should attempt to access the cache to retrieve the initial value for a cachable property"
)
XCTAssertEqual(
testBundle.capturedKeys.last,
"FacebookAutoLogAppEventsEnabled",
"Should attempt to access the plist for cachable properties that have no value in the cache"
)
}
func testInitialAccessForNonCachablePropertyWithEmptyPlist() {
XCTAssertNil(
settings.clientToken,
"A non-cachable property with no default value and no plist entry should not have a value"
)
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache for a non-cachable property"
)
XCTAssertEqual(
testBundle.capturedKeys.last,
"FacebookClientToken",
"Should attempt to access the plist for non-cachable properties"
)
}
func testInitialAccessForNonCachablePropertyWithNonEmptyPlist() {
bundle = TestBundle(infoDictionary: ["FacebookClientToken": "abc123"])
configureSettings()
XCTAssertEqual(
settings.clientToken,
"abc123",
"Should retrieve the initial value from the property list"
)
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache for a non-cachable property"
)
XCTAssertEqual(
testBundle.capturedKeys.last,
"FacebookClientToken",
"Should attempt to access the plist for non-cachable properties"
)
}
// MARK: - Graph Error Recovery Enabled
func testSetGraphErrorRecoveryEnabled() {
settings.isGraphErrorRecoveryEnabled = true
XCTAssertTrue(settings.isGraphErrorRecoveryEnabled)
settings.isGraphErrorRecoveryEnabled = false
XCTAssertFalse(settings.isGraphErrorRecoveryEnabled)
}
// MARK: - Limit Event and Data Usage
func testSetLimitEventAndDataUsageDefault() {
XCTAssertFalse(
settings.isEventDataUsageLimited,
"Should limit event data usage by default"
)
}
func testSetUseCachedValuesForExpensiveMetadata() {
settings.shouldUseCachedValuesForExpensiveMetadata = true
XCTAssertTrue(
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsUseCachedValuesForExpensiveMetadata"] as? Int != 0,
"Should userDefaultsSpy whether or not to limit event and data usage in the user defaults"
)
XCTAssertTrue(
settings.shouldUseCachedValuesForExpensiveMetadata,
"should use cached values for expensive metadata"
)
}
func testSetUseTokenOptimizations() {
settings.shouldUseTokenOptimizations = false
XCTAssertTrue(
userDefaultsSpy.capturedValues["com.facebook.sdk.FBSDKSettingsUseTokenOptimizations"] as? Int == 0,
"Should userDefaultsSpy whether or not to use token optimizations"
)
XCTAssertFalse(
settings.shouldUseTokenOptimizations,
"Should use token optimizations"
)
}
func testSetLimitEventAndDataUsageWithEmptyCache() {
settings.isEventDataUsageLimited = true
XCTAssertTrue(
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsUseCachedValuesForExpensiveMetadata"] as? Int != 0,
"Should userDefaultsSpy whether or not to limit event and data usage in the user defaults"
)
XCTAssertTrue(
settings.isEventDataUsageLimited,
"Should be able to set whether event data usage is limited"
)
}
func testSetLimitEventAndDataUsageWithNonEmptyCache() {
settings.isEventDataUsageLimited = true
XCTAssertTrue(settings.isEventDataUsageLimited, "sanity check")
settings.isEventDataUsageLimited = false
XCTAssertFalse(
settings.isEventDataUsageLimited,
"Should be able to override the existing value of should limit event data usage"
)
XCTAssertTrue(
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsLimitEventAndDataUsage"] as? Int == 0,
"Should userDefaultsSpy the overridden preference for limiting event data usage in the user defaults"
)
}
// MARK: - Data Processing Options
func testDataProcessingOptionDefaults() {
settings.setDataProcessingOptions([])
let dataProcessingOptions = settings.persistableDataProcessingOptions
XCTAssertEqual(
dataProcessingOptions?[DATA_PROCESSING_OPTIONS_COUNTRY] as! Int, // swiftlint:disable:this force_cast
0,
"Country should default to zero when not provided"
)
XCTAssertEqual(
dataProcessingOptions?[DATA_PROCESSING_OPTIONS_STATE] as! Int, // swiftlint:disable:this force_cast
0,
"State should default to zero when not provided"
)
}
func testSettingEmptyDataProcessingOptions() {
settings.setDataProcessingOptions([])
XCTAssertNotNil(
settings.persistableDataProcessingOptions,
"Should not be able to set data processing options to an empty list of options but you can"
)
}
func testSettingInvalidDataProcessOptions() throws {
settings.setDataProcessingOptions(["Foo", "Bar"])
XCTAssertNotNil(
settings.persistableDataProcessingOptions,
"Should not be able to set data processing options to invalid list of options but you can"
)
let persistedData = NSKeyedArchiver.archivedData(withRootObject: settings.persistableDataProcessingOptions as Any)
let capturedValues = userDefaultsSpy.capturedValues
let capturedData = try XCTUnwrap(capturedValues["com.facebook.sdk:FBSDKSettingsDataProcessingOptions"] as? Data)
let dict1 = try? NSKeyedUnarchiver.unarchivedObject(
ofClasses: [NSDictionary.self, NSString.self, NSNumber.self, NSDate.self, NSSet.self, NSArray.self],
from: capturedData
)
let dict2 = try? NSKeyedUnarchiver.unarchivedObject(
ofClasses: [NSDictionary.self, NSString.self, NSNumber.self, NSDate.self, NSSet.self, NSArray.self],
from: persistedData
)
let array1 = (dict1 as? [String: Any])?["data_processing_options"] as? [String]
let array2 = (dict2 as? [String: Any])?["data_processing_options"] as? [String]
XCTAssertEqual(array1, ["Foo", "Bar"])
XCTAssertEqual(array2, ["Foo", "Bar"])
}
func testSettingDataProcessingOptionsWithCountryAndState() {
let countryCode = -1000000000
let stateCode = 100000000
settings.setDataProcessingOptions([], country: Int32(countryCode), state: Int32(stateCode))
let dataProcessingOptions = settings.persistableDataProcessingOptions
XCTAssertEqual(
(settings.persistableDataProcessingOptions?[DATA_PROCESSING_OPTIONS] as? [Any])?.isEmpty,
true,
"Should use the provided array of processing options"
)
XCTAssertEqual(
dataProcessingOptions?[DATA_PROCESSING_OPTIONS_COUNTRY] as? Int,
countryCode,
"Should use the provided country code"
)
XCTAssertEqual(
dataProcessingOptions?[DATA_PROCESSING_OPTIONS_STATE] as? Int,
stateCode,
"Should use the provided state code"
)
}
func testDataProcessingOptionsWithEmptyCache() {
XCTAssertNil(
settings.persistableDataProcessingOptions,
"Should not be able to get data processing options if there is none cached"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
"com.facebook.sdk:FBSDKSettingsDataProcessingOptions",
"Should attempt to access the cache to retrieve the initial value for a cachable property"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist for data processing options"
)
}
func testDataProcessingOptionsWithNonEmptyCache() {
settings.setDataProcessingOptions([])
// Reset internal storage
settings.reset()
configureSettings()
XCTAssertNotNil(
settings.persistableDataProcessingOptions,
"Should be able to retrieve data processing options from the cache"
)
XCTAssertEqual(
userDefaultsSpy.capturedObjectRetrievalKey,
"com.facebook.sdk:FBSDKSettingsDataProcessingOptions",
"Should attempt to access the cache to retrieve the initial value for a cachable property"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist for data processing options"
)
}
func testDataProcessingOptionsInternalStorage() {
settings.setDataProcessingOptions([])
XCTAssertNotNil(
settings.persistableDataProcessingOptions,
"sanity check"
)
XCTAssertNil(
userDefaultsSpy.capturedObjectRetrievalKey,
"Should not attempt to access the cache to retrieve objects that have a current value"
)
XCTAssertNil(
testBundle.capturedKeys.last,
"Should not attempt to access the plist to retrieve objects that have a current value"
)
}
func testRecordInstall() {
XCTAssertNil(
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsInstallTimestamp"],
"Should not persist the value of before setting it"
)
settings.recordInstall()
XCTAssertNotNil(
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsInstallTimestamp"],
"Should persist the value after setting it"
)
let date = userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsInstallTimestamp"]
settings.recordInstall()
XCTAssertEqual(
date as? Date,
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsInstallTimestamp"] as? Date,
"Should not change the cached install timesstamp"
)
}
func testRecordSetAdvertiserTrackingEnabled() {
settings.recordSetAdvertiserTrackingEnabled()
XCTAssertNotNil(
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp"],
"Should persist the value after setting it"
)
let date = userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp"]
settings.recordSetAdvertiserTrackingEnabled()
XCTAssertNotEqual(
date as? Date,
userDefaultsSpy.capturedValues["com.facebook.sdk:FBSDKSettingsSetAdvertiserTrackingEnabledTimestamp"] as? Date,
"Should update set advertiser tracking enabled timesstamp"
)
}
func testIsEventDelayTimerExpired() {
settings.recordInstall()
XCTAssertFalse(settings.isEventDelayTimerExpired())
let today = Date()
let calendar = Calendar(identifier: .gregorian)
var addComponents = DateComponents()
addComponents.month = -1
let expiredDate = calendar.date(byAdding: addComponents, to: today, wrappingComponents: false)
userDefaultsSpy.setValue(expiredDate, forKey: "com.facebook.sdk:FBSDKSettingsInstallTimestamp")
XCTAssertTrue(settings.isEventDelayTimerExpired())
}
func testIsSetATETimeExceedsInstallTime() {
settings.recordInstall()
settings.recordSetAdvertiserTrackingEnabled()
XCTAssertFalse(settings.isSetATETimeExceedsInstallTime)
settings.recordSetAdvertiserTrackingEnabled()
let today = Date()
let calendar = Calendar(identifier: .gregorian)
var addComponents = DateComponents()
addComponents.month = -1
let expiredDate = calendar.date(byAdding: addComponents, to: today, wrappingComponents: false)
userDefaultsSpy.setValue(expiredDate, forKey: "com.facebook.sdk:FBSDKSettingsInstallTimestamp")
XCTAssertTrue(settings.isSetATETimeExceedsInstallTime)
}
// MARK: - test for internal functions
// MARK: - User Agent Suffix
func testSettingEmptyUserAgentSuffix() {
userAgentSuffix = Self.emptyString
XCTAssertEqual(
userAgentSuffix,
Self.emptyString,
"Should not userDefaultsSpy an empty user agent suffix but it will"
)
}
func testSettingWhitespaceOnlyUserAgentSuffix() {
userAgentSuffix = Self.whiteSpaceToken
XCTAssertEqual(
userAgentSuffix,
Self.whiteSpaceToken,
"Should not userDefaultsSpy a whitespace only user agent suffix but it will"
)
}
func testSetGraphAPIVersion() {
let mockGraphAPIVersion = "mockGraphAPIVersion"
settings.graphAPIVersion = mockGraphAPIVersion
XCTAssertEqual(mockGraphAPIVersion, settings.graphAPIVersion)
}
func testIsDataProcessingRestricted() {
settings.setDataProcessingOptions(["LDU"])
XCTAssertTrue(settings.isDataProcessingRestricted)
settings.setDataProcessingOptions([])
XCTAssertFalse(settings.isDataProcessingRestricted)
settings.setDataProcessingOptions(["ldu"])
XCTAssertTrue(settings.isDataProcessingRestricted)
settings.setDataProcessingOptions(nil)
XCTAssertFalse(settings.isDataProcessingRestricted)
}
func resetLoggingSideEffects() {
bundle = TestBundle()
userDefaultsSpy = UserDefaultsSpy()
}
}