// Copyright 2019 Google // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h" #import #if __has_include() #import #else #import "FBLPromises.h" #endif #import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h" #import "Crashlytics/UnitTests/Mocks/FIRAppFake.h" #pragma mark - Tests for FIRCLSDataCollectionArbiter @interface FIRCLSDataCollectionArbiterTest : XCTestCase @property(nonatomic, readwrite) FIRAppFake *fakeApp; @end @implementation FIRCLSDataCollectionArbiterTest - (void)setUp { [super setUp]; self.fakeApp = [[FIRAppFake alloc] init]; [[FIRCLSUserDefaults standardUserDefaults] removeAllObjects]; [[FIRCLSUserDefaults standardUserDefaults] synchronize]; } - (void)tearDown { [[FIRCLSUserDefaults standardUserDefaults] removeAllObjects]; [[FIRCLSUserDefaults standardUserDefaults] synchronize]; [super tearDown]; } - (void)testNothingSet { self.fakeApp.isDefaultCollectionEnabled = YES; FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:@{}]; XCTAssertTrue([arbiter isCrashlyticsCollectionEnabled]); } - (void)testOnlyStickyOff { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:@{}]; [arbiter setCrashlyticsCollectionEnabled:NO]; XCTAssertFalse([arbiter isCrashlyticsCollectionEnabled]); } - (void)testOnlyFlagOff { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:[self fabricConfigWithDataCollectionValue:NO]]; XCTAssertFalse([arbiter isCrashlyticsCollectionEnabled]); } - (void)testOnlyFIRAppOff { self.fakeApp.isDefaultCollectionEnabled = NO; FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:@{}]; XCTAssertFalse([arbiter isCrashlyticsCollectionEnabled]); } - (void)testStickyPrecedent { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:[self fabricConfigWithDataCollectionValue:NO]]; self.fakeApp.isDefaultCollectionEnabled = NO; [arbiter setCrashlyticsCollectionEnabled:YES]; XCTAssertTrue([arbiter isCrashlyticsCollectionEnabled]); XCTAssertFalse([arbiter isLegacyDataCollectionKeyInPlist]); } - (void)testPlistPrecedent { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:[self fabricConfigWithDataCollectionValue:YES]]; self.fakeApp.isDefaultCollectionEnabled = NO; XCTAssertTrue([arbiter isCrashlyticsCollectionEnabled]); XCTAssertFalse([arbiter isLegacyDataCollectionKeyInPlist]); } - (void)testLegacyFlag { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:[self fabricConfigWithLegacyDataCollectionValue:YES]]; XCTAssertTrue([arbiter isLegacyDataCollectionKeyInPlist]); } - (void)testLegacyAndNewImplementationsAreIndependent { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:[self fabricConfigWithLegacyDataCollectionValue:YES]]; self.fakeApp.isDefaultCollectionEnabled = NO; XCTAssertFalse([arbiter isCrashlyticsCollectionEnabled]); XCTAssertTrue([arbiter isLegacyDataCollectionKeyInPlist]); } - (void)testLegacyAndNewFlagsAreIndependent { FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:[self fabricConfigWithDataCollectionValue:YES andLegacy:NO]]; self.fakeApp.isDefaultCollectionEnabled = YES; XCTAssertTrue([arbiter isCrashlyticsCollectionEnabled]); XCTAssertTrue([arbiter isLegacyDataCollectionKeyInPlist]); } - (XCTestExpectation *)expectationForPromise:(FBLPromise *)promise { XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"promise"]; [promise then:^id _Nullable(id _Nullable value) { [expectation fulfill]; return nil; }]; return expectation; } - (void)testWaitForCrashlyticsCollectionEnabled { // true, wait FIRCLSDataCollectionArbiter *arbiter = [self arbiterWithDictionary:@{}]; [arbiter setCrashlyticsCollectionEnabled:YES]; FBLPromise *promise = [arbiter waitForCrashlyticsCollectionEnabled]; [self waitForExpectations:@[ [self expectationForPromise:promise] ] timeout:1.0]; // false, wait, true [arbiter setCrashlyticsCollectionEnabled:NO]; promise = [arbiter waitForCrashlyticsCollectionEnabled]; [arbiter setCrashlyticsCollectionEnabled:YES]; [self waitForExpectations:@[ [self expectationForPromise:promise] ] timeout:1.0]; // false, wait, false, true [arbiter setCrashlyticsCollectionEnabled:NO]; promise = [arbiter waitForCrashlyticsCollectionEnabled]; [arbiter setCrashlyticsCollectionEnabled:NO]; [arbiter setCrashlyticsCollectionEnabled:YES]; [self waitForExpectations:@[ [self expectationForPromise:promise] ] timeout:1.0]; } #pragma mark - Helper functions - (FIRCLSDataCollectionArbiter *)arbiterWithDictionary:(NSDictionary *)dict { id fakeApp = self.fakeApp; return [[FIRCLSDataCollectionArbiter alloc] initWithApp:fakeApp withAppInfo:dict]; } - (NSDictionary *)fabricConfigWithDataCollectionValue:(BOOL)enabled { return @{@"FirebaseCrashlyticsCollectionEnabled" : @(enabled)}; } - (NSDictionary *)fabricConfigWithLegacyDataCollectionValue:(BOOL)enabled { return @{@"firebase_crashlytics_collection_enabled" : @(enabled)}; } - (NSDictionary *)fabricConfigWithDataCollectionValue:(BOOL)enabled andLegacy:(BOOL)legacyEnabled { return @{ @"FirebaseCrashlyticsCollectionEnabled" : @(enabled), @"firebase_crashlytics_collection_enabled" : @(legacyEnabled) }; } @end