aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--.travis.yml33
-rw-r--r--CMakeLists.txt21
-rw-r--r--Example/Auth/ApiTests/AuthCredentialsTemplate.h4
-rw-r--r--Example/Auth/ApiTests/FirebaseAuthApiTests.m141
-rw-r--r--Example/Auth/App/GoogleService-Info.plist2
-rw-r--r--Example/Auth/App/tvOS/AppDelegate.h21
-rw-r--r--Example/Auth/App/tvOS/AppDelegate.m63
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json17
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json17
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json32
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json16
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json16
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/Contents.json6
-rw-r--r--Example/Auth/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json22
-rw-r--r--Example/Auth/App/tvOS/Info.plist32
-rw-r--r--Example/Auth/App/tvOS/Main.storyboard28
-rw-r--r--Example/Auth/App/tvOS/ViewController.h19
-rw-r--r--Example/Auth/App/tvOS/ViewController.m33
-rw-r--r--Example/Auth/App/tvOS/main.m22
-rw-r--r--Example/Auth/Sample/MainViewController.m58
-rw-r--r--Example/Auth/Tests/FIRAuthAPNSTokenManagerTests.m2
-rw-r--r--Example/Auth/Tests/FIRAuthDispatcherTests.m2
-rw-r--r--Example/Auth/Tests/FIRAuthTests.m12
-rw-r--r--Example/Auth/Tests/FIRAuthURLPresenterTests.m2
-rw-r--r--Example/Auth/Tests/FIRPhoneAuthProviderTests.m2
-rw-r--r--Example/Auth/Tests/FIRUserTests.m2
-rw-r--r--Example/Auth/Tests/FIRVerifyPasswordRequestTest.m16
-rw-r--r--Example/Core/App/GoogleService-Info.plist2
-rw-r--r--Example/Core/App/tvOS/AppDelegate.h21
-rw-r--r--Example/Core/App/tvOS/AppDelegate.m62
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json17
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json17
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json32
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json16
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json16
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/Contents.json6
-rw-r--r--Example/Core/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json22
-rw-r--r--Example/Core/App/tvOS/Info.plist32
-rw-r--r--Example/Core/App/tvOS/Main.storyboard28
-rw-r--r--Example/Core/App/tvOS/ViewController.h19
-rw-r--r--Example/Core/App/tvOS/ViewController.m33
-rw-r--r--Example/Core/App/tvOS/main.m22
-rw-r--r--Example/Core/Tests/FIRAppAssociationRegistrationUnitTests.m2
-rw-r--r--Example/Core/Tests/FIRAppTest.m21
-rw-r--r--Example/Core/Tests/FIRLoggerTest.m17
-rw-r--r--Example/Core/Tests/FIROptionsTest.m66
-rw-r--r--Example/Core/Tests/FIRTestCase.m1
-rw-r--r--Example/Database/App/GoogleService-Info.plist2
-rw-r--r--Example/Database/App/tvOS/AppDelegate.h21
-rw-r--r--Example/Database/App/tvOS/AppDelegate.m59
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json17
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json17
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json32
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json16
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json16
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/Contents.json6
-rw-r--r--Example/Database/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json22
-rw-r--r--Example/Database/App/tvOS/Info.plist32
-rw-r--r--Example/Database/App/tvOS/Main.storyboard28
-rw-r--r--Example/Database/App/tvOS/ViewController.h19
-rw-r--r--Example/Database/App/tvOS/ViewController.m33
-rw-r--r--Example/Database/App/tvOS/main.m22
-rw-r--r--Example/Firebase.xcodeproj/project.pbxproj3422
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/AllUnitTests_tvOS.xcscheme131
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Example_tvOS.xcscheme103
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Tests_tvOS.xcscheme68
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Example_tvOS.xcscheme103
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Tests_tvOS.xcscheme58
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Example_tvOS.xcscheme103
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Tests_tvOS.xcscheme58
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Example_tvOS.xcscheme103
-rw-r--r--Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Tests_tvOS.xcscheme58
-rw-r--r--Example/Messaging/App/GoogleService-Info.plist2
-rw-r--r--Example/Messaging/App/iOS/Messaging-Info.plist2
-rw-r--r--Example/Messaging/Tests/FIRMessagingServiceTest.m11
-rw-r--r--Example/Messaging/Tests/FIRMessagingTest.m14
-rw-r--r--Example/Messaging/Tests/Info.plist2
-rw-r--r--Example/Podfile56
-rw-r--r--Example/Storage/App/GoogleService-Info.plist2
-rw-r--r--Example/Storage/App/tvOS/AppDelegate.h21
-rw-r--r--Example/Storage/App/tvOS/AppDelegate.m63
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json17
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json17
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json32
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json16
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json16
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/Contents.json6
-rw-r--r--Example/Storage/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json22
-rw-r--r--Example/Storage/App/tvOS/Info.plist32
-rw-r--r--Example/Storage/App/tvOS/Main.storyboard28
-rw-r--r--Example/Storage/App/tvOS/ViewController.h19
-rw-r--r--Example/Storage/App/tvOS/ViewController.m33
-rw-r--r--Example/Storage/App/tvOS/main.m22
-rw-r--r--Example/Storage/Tests/Unit/FIRStorageTests.m2
-rw-r--r--Example/tvOSSample/Podfile14
-rw-r--r--Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj424
-rw-r--r--Example/tvOSSample/tvOSSample/AppDelegate.swift29
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json17
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json11
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json17
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json16
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json32
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json16
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json16
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/Contents.json6
-rw-r--r--Example/tvOSSample/tvOSSample/Assets.xcassets/LaunchImage.launchimage/Contents.json22
-rw-r--r--Example/tvOSSample/tvOSSample/AuthLoginViewController.swift40
-rw-r--r--Example/tvOSSample/tvOSSample/AuthViewController.swift86
-rw-r--r--Example/tvOSSample/tvOSSample/Base.lproj/Main.storyboard355
-rw-r--r--Example/tvOSSample/tvOSSample/DatabaseViewController.swift83
-rw-r--r--Example/tvOSSample/tvOSSample/EmailLoginViewController.swift93
-rw-r--r--Example/tvOSSample/tvOSSample/Info.plist32
-rw-r--r--Example/tvOSSample/tvOSSample/StorageViewController.swift148
-rw-r--r--Firebase/Auth/CHANGELOG.md5
-rw-r--r--Firebase/Auth/FirebaseAuth.podspec1
-rw-r--r--Firebase/Auth/Source/FIRAuth.m54
-rw-r--r--Firebase/Auth/Source/FIRAuthAPNSTokenManager.m2
-rw-r--r--Firebase/Auth/Source/Public/FIREmailAuthProvider.h2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m2
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m2
-rw-r--r--Firebase/Core/CHANGELOG.md30
-rw-r--r--Firebase/Core/FIRApp.m13
-rw-r--r--Firebase/Core/FIRErrors.m4
-rw-r--r--Firebase/Core/FIRLogger.m16
-rw-r--r--Firebase/Core/FIRNetworkURLSession.m1
-rw-r--r--Firebase/Core/FIROptions.m20
-rw-r--r--Firebase/Core/FIRReachabilityChecker.m4
-rw-r--r--Firebase/Core/FIRVersion.m36
-rw-r--r--Firebase/Core/Private/FIRErrors.h10
-rw-r--r--Firebase/Core/Private/FIRVersion.h (renamed from Firestore/core/src/firebase/firestore/base/port.h)20
-rw-r--r--Firebase/Core/third_party/FIRAppEnvironmentUtil.h14
-rw-r--r--Firebase/Core/third_party/FIRAppEnvironmentUtil.m48
-rw-r--r--Firebase/Database/CHANGELOG.md6
-rw-r--r--Firebase/Database/Core/FPersistentConnection.m2
-rw-r--r--Firebase/Database/Core/FRepo.m4
-rw-r--r--Firebase/Database/Persistence/FLevelDBStorageEngine.m2
-rw-r--r--Firebase/Database/Realtime/FWebSocketConnection.m4
-rw-r--r--Firebase/Database/third_party/SocketRocket/FSRWebSocket.m4
-rw-r--r--Firebase/Messaging/FIRMessaging.m63
-rw-r--r--Firebase/Messaging/FIRMessagingContextManagerService.m5
-rw-r--r--Firebase/Messaging/FIRMessagingPubSub.h15
-rw-r--r--Firebase/Messaging/FIRMessagingPubSub.m10
-rw-r--r--Firebase/Messaging/FIRMessagingRmq2PersistentStore.m5
-rw-r--r--Firebase/Messaging/FIRMessagingTopicOperation.m1
-rw-r--r--Firebase/Messaging/FIRMessaging_Private.h3
-rw-r--r--Firebase/Messaging/Protos/GtalkCore.pbobjc.h56
-rw-r--r--Firebase/Messaging/Protos/GtalkCore.pbobjc.m122
-rw-r--r--Firebase/Messaging/Public/FIRMessaging.h15
-rw-r--r--Firebase/Storage/CHANGELOG.md6
-rw-r--r--Firebase/Storage/FIRStorageErrors.m4
-rw-r--r--Firebase/Storage/FIRStorageObservableTask.m2
-rw-r--r--Firebase/Storage/FIRStorageUtils.m2
-rw-r--r--FirebaseAuth.podspec10
-rw-r--r--FirebaseCore.podspec12
-rw-r--r--FirebaseDatabase.podspec3
-rw-r--r--FirebaseFirestore.podspec34
-rw-r--r--FirebaseMessaging.podspec2
-rw-r--r--FirebaseStorage.podspec3
-rw-r--r--Firestore/CHANGELOG.md28
-rw-r--r--Firestore/CMakeLists.txt54
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj707
-rw-r--r--Firestore/Example/Podfile2
-rw-r--r--Firestore/Example/SwiftBuildTest/main.swift101
-rw-r--r--Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm43
-rw-r--r--Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm43
-rw-r--r--Firestore/Example/Tests/API/FIRDocumentSnapshotTests.mm59
-rw-r--r--Firestore/Example/Tests/API/FIRFieldPathTests.mm46
-rw-r--r--Firestore/Example/Tests/API/FIRFieldValueTests.mm46
-rw-r--r--Firestore/Example/Tests/API/FIRGeoPointTests.mm (renamed from Firestore/Example/Tests/API/FIRGeoPointTests.m)23
-rw-r--r--Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm58
-rw-r--r--Firestore/Example/Tests/API/FIRQueryTests.mm85
-rw-r--r--Firestore/Example/Tests/API/FIRSnapshotMetadataTests.mm52
-rw-r--r--Firestore/Example/Tests/API/FSTAPIHelpers.h74
-rw-r--r--Firestore/Example/Tests/API/FSTAPIHelpers.mm115
-rw-r--r--Firestore/Example/Tests/Core/FSTDatabaseInfoTests.mm (renamed from Firestore/Example/Tests/Core/FSTDatabaseInfoTests.m)0
-rw-r--r--Firestore/Example/Tests/Core/FSTEventManagerTests.mm (renamed from Firestore/Example/Tests/Core/FSTEventManagerTests.m)16
-rw-r--r--Firestore/Example/Tests/Core/FSTQueryListenerTests.mm (renamed from Firestore/Example/Tests/Core/FSTQueryListenerTests.m)52
-rw-r--r--Firestore/Example/Tests/Core/FSTQueryTests.mm (renamed from Firestore/Example/Tests/Core/FSTQueryTests.m)105
-rw-r--r--Firestore/Example/Tests/Core/FSTTargetIDGeneratorTests.m94
-rw-r--r--Firestore/Example/Tests/Core/FSTTimestampTests.mm (renamed from Firestore/Example/Tests/Core/FSTTimestampTests.m)0
-rw-r--r--Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm (renamed from Firestore/Example/Tests/Core/FSTViewSnapshotTest.m)2
-rw-r--r--Firestore/Example/Tests/Core/FSTViewTests.mm (renamed from Firestore/Example/Tests/Core/FSTViewTests.m)0
-rw-r--r--Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm3
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRCursorTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRCursorTests.m)2
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRDatabaseTests.m)39
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRFieldsTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRFieldsTests.m)2
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRListenerRegistrationTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRListenerRegistrationTests.m)33
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRQueryTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRQueryTests.m)110
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.m183
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.mm318
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRTypeTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRTypeTests.m)5
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRValidationTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRValidationTests.m)4
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.mm (renamed from Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.m)33
-rw-r--r--Firestore/Example/Tests/Integration/FSTDatastoreTests.mm (renamed from Firestore/Example/Tests/Integration/FSTDatastoreTests.m)2
-rw-r--r--Firestore/Example/Tests/Integration/FSTSmokeTests.mm (renamed from Firestore/Example/Tests/Integration/FSTSmokeTests.m)8
-rw-r--r--Firestore/Example/Tests/Integration/FSTStreamTests.mm (renamed from Firestore/Example/Tests/Integration/FSTStreamTests.m)0
-rw-r--r--Firestore/Example/Tests/Integration/FSTTransactionTests.mm (renamed from Firestore/Example/Tests/Integration/FSTTransactionTests.m)2
-rw-r--r--Firestore/Example/Tests/Local/FSTEagerGarbageCollectorTests.mm (renamed from Firestore/Example/Tests/Local/FSTEagerGarbageCollectorTests.m)12
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBLocalStoreTests.mm (renamed from Firestore/Example/Tests/Local/FSTLevelDBLocalStoreTests.m)0
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm75
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm5
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBQueryCacheTests.mm (renamed from Firestore/Example/Tests/Local/FSTLevelDBQueryCacheTests.m)0
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBRemoteDocumentCacheTests.mm5
-rw-r--r--Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm (renamed from Firestore/Example/Tests/Local/FSTLocalSerializerTests.m)4
-rw-r--r--Firestore/Example/Tests/Local/FSTLocalStoreTests.mm (renamed from Firestore/Example/Tests/Local/FSTLocalStoreTests.m)29
-rw-r--r--Firestore/Example/Tests/Local/FSTMemoryLocalStoreTests.mm (renamed from Firestore/Example/Tests/Local/FSTMemoryLocalStoreTests.m)0
-rw-r--r--Firestore/Example/Tests/Local/FSTMemoryMutationQueueTests.mm (renamed from Firestore/Example/Tests/Local/FSTMemoryMutationQueueTests.m)0
-rw-r--r--Firestore/Example/Tests/Local/FSTMemoryQueryCacheTests.mm (renamed from Firestore/Example/Tests/Local/FSTMemoryQueryCacheTests.m)0
-rw-r--r--Firestore/Example/Tests/Local/FSTMemoryRemoteDocumentCacheTests.mm (renamed from Firestore/Example/Tests/Local/FSTMemoryRemoteDocumentCacheTests.m)0
-rw-r--r--Firestore/Example/Tests/Local/FSTMutationQueueTests.mm (renamed from Firestore/Example/Tests/Local/FSTMutationQueueTests.m)2
-rw-r--r--Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h6
-rw-r--r--Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.mm (renamed from Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.m)9
-rw-r--r--Firestore/Example/Tests/Local/FSTQueryCacheTests.mm (renamed from Firestore/Example/Tests/Local/FSTQueryCacheTests.m)118
-rw-r--r--Firestore/Example/Tests/Local/FSTReferenceSetTests.mm (renamed from Firestore/Example/Tests/Local/FSTReferenceSetTests.m)9
-rw-r--r--Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm (renamed from Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.m)2
-rw-r--r--Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm (renamed from Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.m)0
-rw-r--r--Firestore/Example/Tests/Model/FSTDatabaseIDTests.mm (renamed from Firestore/Example/Tests/Model/FSTDatabaseIDTests.m)0
-rw-r--r--Firestore/Example/Tests/Model/FSTDocumentKeyTests.mm (renamed from Firestore/Example/Tests/Model/FSTDocumentKeyTests.m)0
-rw-r--r--Firestore/Example/Tests/Model/FSTDocumentSetTests.mm (renamed from Firestore/Example/Tests/Model/FSTDocumentSetTests.m)8
-rw-r--r--Firestore/Example/Tests/Model/FSTDocumentTests.mm (renamed from Firestore/Example/Tests/Model/FSTDocumentTests.m)63
-rw-r--r--Firestore/Example/Tests/Model/FSTFieldValueTests.mm (renamed from Firestore/Example/Tests/Model/FSTFieldValueTests.m)18
-rw-r--r--Firestore/Example/Tests/Model/FSTMutationTests.mm (renamed from Firestore/Example/Tests/Model/FSTMutationTests.m)49
-rw-r--r--Firestore/Example/Tests/Model/FSTPathTests.mm (renamed from Firestore/Example/Tests/Model/FSTPathTests.m)0
-rw-r--r--Firestore/Example/Tests/Remote/FSTDatastoreTests.mm (renamed from Firestore/Example/Tests/Remote/FSTDatastoreTests.m)2
-rw-r--r--Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm (renamed from Firestore/Example/Tests/Remote/FSTRemoteEventTests.m)0
-rw-r--r--Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm (renamed from Firestore/Example/Tests/Remote/FSTSerializerBetaTests.m)52
-rw-r--r--Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm (renamed from Firestore/Example/Tests/Remote/FSTWatchChange+Testing.m)0
-rw-r--r--Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm (renamed from Firestore/Example/Tests/Remote/FSTWatchChangeTests.m)0
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm (renamed from Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.m)0
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm (renamed from Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.m)0
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm (renamed from Firestore/Example/Tests/SpecTests/FSTMockDatastore.m)0
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTSpecTests.mm (renamed from Firestore/Example/Tests/SpecTests/FSTSpecTests.m)13
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h3
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm (renamed from Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m)14
-rw-r--r--Firestore/Example/Tests/SpecTests/json/listen_spec_test.json14
-rw-r--r--Firestore/Example/Tests/SpecTests/json/offline_spec_test.json419
-rw-r--r--Firestore/Example/Tests/Util/FSTAssertTests.mm (renamed from Firestore/Example/Tests/Util/FSTAssertTests.m)0
-rw-r--r--Firestore/Example/Tests/Util/FSTComparisonTests.m143
-rw-r--r--Firestore/Example/Tests/Util/FSTEventAccumulator.h5
-rw-r--r--Firestore/Example/Tests/Util/FSTEventAccumulator.mm (renamed from Firestore/Example/Tests/Util/FSTEventAccumulator.m)5
-rw-r--r--Firestore/Example/Tests/Util/FSTHelpers.h4
-rw-r--r--Firestore/Example/Tests/Util/FSTHelpers.mm (renamed from Firestore/Example/Tests/Util/FSTHelpers.m)22
-rw-r--r--Firestore/Example/Tests/Util/FSTIntegrationTestCase.h5
-rw-r--r--Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm39
-rw-r--r--Firestore/Example/Tests/Util/FSTTestDispatchQueue.mm (renamed from Firestore/Example/Tests/Util/FSTTestDispatchQueue.m)0
-rw-r--r--Firestore/Example/Tests/Util/XCTestCase+Await.h8
-rw-r--r--Firestore/Example/Tests/Util/XCTestCase+Await.mm (renamed from Firestore/Example/Tests/Util/XCTestCase+Await.m)12
-rw-r--r--Firestore/Port/absl/absl_attributes.h644
-rw-r--r--Firestore/Port/absl/absl_config.h306
-rw-r--r--Firestore/Port/absl/absl_endian.h342
-rw-r--r--Firestore/Port/absl/absl_integral_types.h148
-rw-r--r--Firestore/Port/absl/absl_port.h535
-rw-r--r--Firestore/Port/string_util.h66
-rw-r--r--Firestore/Source/API/FIRCollectionReference.mm21
-rw-r--r--Firestore/Source/API/FIRDocumentChange+Internal.h1
-rw-r--r--Firestore/Source/API/FIRDocumentChange.mm (renamed from Firestore/Source/API/FIRDocumentChange.m)22
-rw-r--r--Firestore/Source/API/FIRDocumentReference.mm (renamed from Firestore/Source/API/FIRDocumentReference.m)9
-rw-r--r--Firestore/Source/API/FIRDocumentSnapshot.mm (renamed from Firestore/Source/API/FIRDocumentSnapshot.m)137
-rw-r--r--Firestore/Source/API/FIRFieldPath.mm (renamed from Firestore/Source/API/FIRFieldPath.m)2
-rw-r--r--Firestore/Source/API/FIRFieldValue.mm (renamed from Firestore/Source/API/FIRFieldValue.m)0
-rw-r--r--Firestore/Source/API/FIRFirestore.mm (renamed from Firestore/Source/API/FIRFirestore.m)117
-rw-r--r--Firestore/Source/API/FIRFirestoreSettings.mm (renamed from Firestore/Source/API/FIRFirestoreSettings.m)0
-rw-r--r--Firestore/Source/API/FIRFirestoreVersion.mm (renamed from Firestore/Source/API/FIRFirestoreVersion.m)2
-rw-r--r--Firestore/Source/API/FIRGeoPoint.mm (renamed from Firestore/Source/API/FIRGeoPoint.m)17
-rw-r--r--Firestore/Source/API/FIRListenerRegistration.mm (renamed from Firestore/Source/API/FIRListenerRegistration.m)0
-rw-r--r--Firestore/Source/API/FIRQuery.mm (renamed from Firestore/Source/API/FIRQuery.m)96
-rw-r--r--Firestore/Source/API/FIRQuerySnapshot.mm (renamed from Firestore/Source/API/FIRQuerySnapshot.m)40
-rw-r--r--Firestore/Source/API/FIRSetOptions.mm (renamed from Firestore/Source/API/FIRSetOptions.m)4
-rw-r--r--Firestore/Source/API/FIRSnapshotMetadata.mm (renamed from Firestore/Source/API/FIRSnapshotMetadata.m)21
-rw-r--r--Firestore/Source/API/FIRSnapshotOptions+Internal.h38
-rw-r--r--Firestore/Source/API/FIRSnapshotOptions.mm72
-rw-r--r--Firestore/Source/API/FIRTransaction.mm (renamed from Firestore/Source/API/FIRTransaction.m)0
-rw-r--r--Firestore/Source/API/FIRWriteBatch.mm (renamed from Firestore/Source/API/FIRWriteBatch.m)6
-rw-r--r--Firestore/Source/API/FSTUserDataConverter.mm (renamed from Firestore/Source/API/FSTUserDataConverter.m)0
-rw-r--r--Firestore/Source/Auth/FSTCredentialsProvider.mm (renamed from Firestore/Source/Auth/FSTCredentialsProvider.m)0
-rw-r--r--Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm (renamed from Firestore/Source/Auth/FSTEmptyCredentialsProvider.m)0
-rw-r--r--Firestore/Source/Auth/FSTUser.mm (renamed from Firestore/Source/Auth/FSTUser.m)0
-rw-r--r--Firestore/Source/Core/FSTDatabaseInfo.mm (renamed from Firestore/Source/Core/FSTDatabaseInfo.m)0
-rw-r--r--Firestore/Source/Core/FSTEventManager.h2
-rw-r--r--Firestore/Source/Core/FSTEventManager.mm (renamed from Firestore/Source/Core/FSTEventManager.m)8
-rw-r--r--Firestore/Source/Core/FSTFirestoreClient.h2
-rw-r--r--Firestore/Source/Core/FSTFirestoreClient.mm (renamed from Firestore/Source/Core/FSTFirestoreClient.m)15
-rw-r--r--Firestore/Source/Core/FSTListenSequence.h37
-rw-r--r--Firestore/Source/Core/FSTListenSequence.mm50
-rw-r--r--Firestore/Source/Core/FSTQuery.mm (renamed from Firestore/Source/Core/FSTQuery.m)26
-rw-r--r--Firestore/Source/Core/FSTSnapshotVersion.mm (renamed from Firestore/Source/Core/FSTSnapshotVersion.m)0
-rw-r--r--Firestore/Source/Core/FSTSyncEngine.h3
-rw-r--r--Firestore/Source/Core/FSTSyncEngine.mm (renamed from Firestore/Source/Core/FSTSyncEngine.m)36
-rw-r--r--Firestore/Source/Core/FSTTargetIDGenerator.h55
-rw-r--r--Firestore/Source/Core/FSTTargetIDGenerator.m105
-rw-r--r--Firestore/Source/Core/FSTTimestamp.mm (renamed from Firestore/Source/Core/FSTTimestamp.m)9
-rw-r--r--Firestore/Source/Core/FSTTransaction.mm (renamed from Firestore/Source/Core/FSTTransaction.m)32
-rw-r--r--Firestore/Source/Core/FSTTypes.h11
-rw-r--r--Firestore/Source/Core/FSTView.h7
-rw-r--r--Firestore/Source/Core/FSTView.mm (renamed from Firestore/Source/Core/FSTView.m)50
-rw-r--r--Firestore/Source/Core/FSTViewSnapshot.mm (renamed from Firestore/Source/Core/FSTViewSnapshot.m)0
-rw-r--r--Firestore/Source/Local/FSTDocumentReference.h4
-rw-r--r--Firestore/Source/Local/FSTDocumentReference.mm (renamed from Firestore/Source/Local/FSTDocumentReference.m)13
-rw-r--r--Firestore/Source/Local/FSTEagerGarbageCollector.mm (renamed from Firestore/Source/Local/FSTEagerGarbageCollector.m)0
-rw-r--r--Firestore/Source/Local/FSTLevelDB.h17
-rw-r--r--Firestore/Source/Local/FSTLevelDB.mm17
-rw-r--r--Firestore/Source/Local/FSTLevelDBKey.h12
-rw-r--r--Firestore/Source/Local/FSTLevelDBKey.mm51
-rw-r--r--Firestore/Source/Local/FSTLevelDBMigrations.h41
-rw-r--r--Firestore/Source/Local/FSTLevelDBMigrations.mm95
-rw-r--r--Firestore/Source/Local/FSTLevelDBMutationQueue.h11
-rw-r--r--Firestore/Source/Local/FSTLevelDBMutationQueue.mm6
-rw-r--r--Firestore/Source/Local/FSTLevelDBQueryCache.h17
-rw-r--r--Firestore/Source/Local/FSTLevelDBQueryCache.mm101
-rw-r--r--Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h11
-rw-r--r--Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm4
-rw-r--r--Firestore/Source/Local/FSTLocalDocumentsView.mm (renamed from Firestore/Source/Local/FSTLocalDocumentsView.m)4
-rw-r--r--Firestore/Source/Local/FSTLocalSerializer.mm (renamed from Firestore/Source/Local/FSTLocalSerializer.m)5
-rw-r--r--Firestore/Source/Local/FSTLocalStore.mm (renamed from Firestore/Source/Local/FSTLocalStore.m)29
-rw-r--r--Firestore/Source/Local/FSTLocalViewChanges.mm (renamed from Firestore/Source/Local/FSTLocalViewChanges.m)0
-rw-r--r--Firestore/Source/Local/FSTLocalWriteResult.mm (renamed from Firestore/Source/Local/FSTLocalWriteResult.m)0
-rw-r--r--Firestore/Source/Local/FSTMemoryMutationQueue.mm (renamed from Firestore/Source/Local/FSTMemoryMutationQueue.m)7
-rw-r--r--Firestore/Source/Local/FSTMemoryPersistence.mm (renamed from Firestore/Source/Local/FSTMemoryPersistence.m)0
-rw-r--r--Firestore/Source/Local/FSTMemoryQueryCache.mm (renamed from Firestore/Source/Local/FSTMemoryQueryCache.m)9
-rw-r--r--Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm (renamed from Firestore/Source/Local/FSTMemoryRemoteDocumentCache.m)0
-rw-r--r--Firestore/Source/Local/FSTNoOpGarbageCollector.mm (renamed from Firestore/Source/Local/FSTNoOpGarbageCollector.m)0
-rw-r--r--Firestore/Source/Local/FSTQueryCache.h5
-rw-r--r--Firestore/Source/Local/FSTQueryData.h4
-rw-r--r--Firestore/Source/Local/FSTQueryData.mm (renamed from Firestore/Source/Local/FSTQueryData.m)5
-rw-r--r--Firestore/Source/Local/FSTReferenceSet.mm (renamed from Firestore/Source/Local/FSTReferenceSet.m)0
-rw-r--r--Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm (renamed from Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.m)0
-rw-r--r--Firestore/Source/Local/FSTWriteGroup.h13
-rw-r--r--Firestore/Source/Local/FSTWriteGroup.mm3
-rw-r--r--Firestore/Source/Local/FSTWriteGroupTracker.mm (renamed from Firestore/Source/Local/FSTWriteGroupTracker.m)0
-rw-r--r--Firestore/Source/Local/StringView.h16
-rw-r--r--Firestore/Source/Model/FSTDatabaseID.mm (renamed from Firestore/Source/Model/FSTDatabaseID.m)2
-rw-r--r--Firestore/Source/Model/FSTDocument.mm (renamed from Firestore/Source/Model/FSTDocument.m)0
-rw-r--r--Firestore/Source/Model/FSTDocumentDictionary.mm (renamed from Firestore/Source/Model/FSTDocumentDictionary.m)0
-rw-r--r--Firestore/Source/Model/FSTDocumentKey.mm (renamed from Firestore/Source/Model/FSTDocumentKey.m)0
-rw-r--r--Firestore/Source/Model/FSTDocumentKeySet.mm (renamed from Firestore/Source/Model/FSTDocumentKeySet.m)0
-rw-r--r--Firestore/Source/Model/FSTDocumentSet.h10
-rw-r--r--Firestore/Source/Model/FSTDocumentSet.mm (renamed from Firestore/Source/Model/FSTDocumentSet.m)10
-rw-r--r--Firestore/Source/Model/FSTDocumentVersionDictionary.mm (renamed from Firestore/Source/Model/FSTDocumentVersionDictionary.m)0
-rw-r--r--Firestore/Source/Model/FSTFieldValue.h103
-rw-r--r--Firestore/Source/Model/FSTFieldValue.mm (renamed from Firestore/Source/Model/FSTFieldValue.m)158
-rw-r--r--Firestore/Source/Model/FSTMutation.h16
-rw-r--r--Firestore/Source/Model/FSTMutation.mm (renamed from Firestore/Source/Model/FSTMutation.m)56
-rw-r--r--Firestore/Source/Model/FSTMutationBatch.mm (renamed from Firestore/Source/Model/FSTMutationBatch.m)2
-rw-r--r--Firestore/Source/Model/FSTPath.mm (renamed from Firestore/Source/Model/FSTPath.m)2
-rw-r--r--Firestore/Source/Public/FIRDocumentChange.h4
-rw-r--r--Firestore/Source/Public/FIRDocumentReference.h2
-rw-r--r--Firestore/Source/Public/FIRDocumentSnapshot.h143
-rw-r--r--Firestore/Source/Public/FIRFirestore.h17
-rw-r--r--Firestore/Source/Public/FIRQuery.h13
-rw-r--r--Firestore/Source/Public/FIRQuerySnapshot.h4
-rw-r--r--Firestore/Source/Public/FIRWriteBatch.h7
-rw-r--r--Firestore/Source/Remote/FSTBufferedWriter.mm (renamed from Firestore/Source/Remote/FSTBufferedWriter.m)0
-rw-r--r--Firestore/Source/Remote/FSTDatastore.mm (renamed from Firestore/Source/Remote/FSTDatastore.m)0
-rw-r--r--Firestore/Source/Remote/FSTExistenceFilter.mm (renamed from Firestore/Source/Remote/FSTExistenceFilter.m)0
-rw-r--r--Firestore/Source/Remote/FSTRemoteEvent.mm (renamed from Firestore/Source/Remote/FSTRemoteEvent.m)12
-rw-r--r--Firestore/Source/Remote/FSTRemoteStore.h2
-rw-r--r--Firestore/Source/Remote/FSTRemoteStore.mm (renamed from Firestore/Source/Remote/FSTRemoteStore.m)129
-rw-r--r--Firestore/Source/Remote/FSTSerializerBeta.mm (renamed from Firestore/Source/Remote/FSTSerializerBeta.m)30
-rw-r--r--Firestore/Source/Remote/FSTStream.mm (renamed from Firestore/Source/Remote/FSTStream.m)5
-rw-r--r--Firestore/Source/Remote/FSTWatchChange.mm (renamed from Firestore/Source/Remote/FSTWatchChange.m)0
-rw-r--r--Firestore/Source/Util/FSTAsyncQueryListener.mm (renamed from Firestore/Source/Util/FSTAsyncQueryListener.m)0
-rw-r--r--Firestore/Source/Util/FSTComparison.h66
-rw-r--r--Firestore/Source/Util/FSTComparison.m175
-rw-r--r--Firestore/Source/Util/FSTDispatchQueue.mm (renamed from Firestore/Source/Util/FSTDispatchQueue.m)0
-rw-r--r--Firestore/Source/Util/FSTLogger.h8
-rw-r--r--Firestore/Source/Util/FSTLogger.mm (renamed from Firestore/Source/Util/FSTLogger.m)0
-rw-r--r--Firestore/Source/Util/FSTUsageValidation.h8
-rw-r--r--Firestore/Source/Util/FSTUsageValidation.mm (renamed from Firestore/Source/Util/FSTUsageValidation.m)0
-rw-r--r--Firestore/core/CMakeLists.txt11
-rw-r--r--Firestore/core/include/firebase/firestore/geo_point.h89
-rw-r--r--Firestore/core/src/firebase/firestore/CMakeLists.txt22
-rw-r--r--Firestore/core/src/firebase/firestore/core/CMakeLists.txt20
-rw-r--r--Firestore/core/src/firebase/firestore/core/target_id_generator.cc62
-rw-r--r--Firestore/core/src/firebase/firestore/core/target_id_generator.h83
-rw-r--r--Firestore/core/src/firebase/firestore/core/types.h32
-rw-r--r--Firestore/core/src/firebase/firestore/geo_point.cc50
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt21
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/array_sorted_map.cc30
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h318
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/map_entry.h62
-rw-r--r--Firestore/core/src/firebase/firestore/model/CMakeLists.txt28
-rw-r--r--Firestore/core/src/firebase/firestore/model/database_id.cc40
-rw-r--r--Firestore/core/src/firebase/firestore/model/database_id.h92
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.cc388
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.h169
-rw-r--r--Firestore/core/src/firebase/firestore/model/timestamp.cc54
-rw-r--r--Firestore/core/src/firebase/firestore/model/timestamp.h94
-rw-r--r--Firestore/core/src/firebase/firestore/remote/CMakeLists.txt22
-rw-r--r--Firestore/core/src/firebase/firestore/remote/datastore.cc31
-rw-r--r--Firestore/core/src/firebase/firestore/remote/datastore.h40
-rw-r--r--Firestore/core/src/firebase/firestore/util/CMakeLists.txt114
-rw-r--r--Firestore/core/src/firebase/firestore/util/assert_apple.mm51
-rw-r--r--Firestore/core/src/firebase/firestore/util/assert_stdio.cc54
-rw-r--r--Firestore/core/src/firebase/firestore/util/bits.cc (renamed from Firestore/Port/bits.cc)14
-rw-r--r--Firestore/core/src/firebase/firestore/util/bits.h (renamed from Firestore/Port/bits.h)26
-rw-r--r--Firestore/core/src/firebase/firestore/util/comparison.cc112
-rw-r--r--Firestore/core/src/firebase/firestore/util/comparison.h181
-rw-r--r--Firestore/core/src/firebase/firestore/util/config.h.in35
-rw-r--r--Firestore/core/src/firebase/firestore/util/firebase_assert.h105
-rw-r--r--Firestore/core/src/firebase/firestore/util/iterator_adaptors.h812
-rw-r--r--Firestore/core/src/firebase/firestore/util/log.h63
-rw-r--r--Firestore/core/src/firebase/firestore/util/log_apple.mm123
-rw-r--r--Firestore/core/src/firebase/firestore/util/log_stdio.cc97
-rw-r--r--Firestore/core/src/firebase/firestore/util/ordered_code.cc (renamed from Firestore/Port/ordered_code.cc)247
-rw-r--r--Firestore/core/src/firebase/firestore/util/ordered_code.h (renamed from Firestore/Port/ordered_code.h)75
-rw-r--r--Firestore/core/src/firebase/firestore/util/secure_random.h16
-rw-r--r--Firestore/core/src/firebase/firestore/util/secure_random_arc4random.cc2
-rw-r--r--Firestore/core/src/firebase/firestore/util/secure_random_openssl.cc46
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_apple.h52
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_printf.cc102
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_printf.h47
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_util.cc (renamed from Firestore/Port/string_util.cc)18
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_util.h72
-rw-r--r--Firestore/core/test/firebase/firestore/CMakeLists.txt21
-rw-r--r--Firestore/core/test/firebase/firestore/core/CMakeLists.txt21
-rw-r--r--Firestore/core/test/firebase/firestore/core/target_id_generator_test.cc80
-rw-r--r--Firestore/core/test/firebase/firestore/geo_point_test.cc41
-rw-r--r--Firestore/core/test/firebase/firestore/immutable/CMakeLists.txt22
-rw-r--r--Firestore/core/test/firebase/firestore/immutable/array_sorted_map_test.cc326
-rw-r--r--Firestore/core/test/firebase/firestore/model/CMakeLists.txt23
-rw-r--r--Firestore/core/test/firebase/firestore/model/database_id_test.cc47
-rw-r--r--Firestore/core/test/firebase/firestore/model/field_value_test.cc462
-rw-r--r--Firestore/core/test/firebase/firestore/model/timestamp_test.cc49
-rw-r--r--Firestore/core/test/firebase/firestore/remote/CMakeLists.txt21
-rw-r--r--Firestore/core/test/firebase/firestore/remote/datastore_test.cc28
-rw-r--r--Firestore/core/test/firebase/firestore/util/CMakeLists.txt62
-rw-r--r--Firestore/core/test/firebase/firestore/util/assert_test.cc63
-rw-r--r--Firestore/core/test/firebase/firestore/util/autoid_test.cc6
-rw-r--r--Firestore/core/test/firebase/firestore/util/bits_test.cc (renamed from Firestore/Port/bits_test.cc)56
-rw-r--r--Firestore/core/test/firebase/firestore/util/comparison_test.cc211
-rw-r--r--Firestore/core/test/firebase/firestore/util/iterator_adaptors_test.cc1277
-rw-r--r--Firestore/core/test/firebase/firestore/util/log_test.cc61
-rw-r--r--Firestore/core/test/firebase/firestore/util/ordered_code_test.cc (renamed from Firestore/Port/ordered_code_test.cc)264
-rw-r--r--Firestore/core/test/firebase/firestore/util/secure_random_test.cc27
-rw-r--r--Firestore/core/test/firebase/firestore/util/string_printf_test.cc78
-rw-r--r--Firestore/core/test/firebase/firestore/util/string_util_test.cc (renamed from Firestore/Port/string_util_test.cc)24
-rw-r--r--Firestore/third_party/Immutable/FSTArraySortedDictionary.m13
-rw-r--r--Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h8
-rw-r--r--Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m4
-rw-r--r--Firestore/third_party/Immutable/FSTImmutableSortedSet.h2
-rw-r--r--Firestore/third_party/Immutable/FSTImmutableSortedSet.m4
-rw-r--r--Firestore/third_party/Immutable/FSTTreeSortedDictionary.m30
-rw-r--r--Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m22
-rw-r--r--Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m19
-rw-r--r--Firestore/third_party/abseil-cpp/CMakeLists.txt1
-rw-r--r--Firestore/third_party/abseil-cpp/absl/CMakeLists.txt7
-rw-r--r--Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt277
-rw-r--r--Firestore/third_party/abseil-cpp/absl/base/config_test.cc17
-rw-r--r--Firestore/third_party/abseil-cpp/absl/base/macros.h2
-rw-r--r--Firestore/third_party/abseil-cpp/absl/meta/CMakeLists.txt3
-rw-r--r--Firestore/third_party/abseil-cpp/absl/numeric/int128_test.cc1
-rw-r--r--Firestore/third_party/abseil-cpp/absl/strings/CMakeLists.txt1
-rw-r--r--Gemfile.lock30
-rw-r--r--README.md25
-rw-r--r--cmake/CompilerSetup.cmake96
-rw-r--r--cmake/ExternalProjectFlags.cmake71
-rw-r--r--cmake/FindFirebaseCore.cmake56
-rw-r--r--cmake/FindGRPC.cmake142
-rw-r--r--cmake/FindLevelDB.cmake55
-rw-r--r--cmake/external/FirebaseCore.cmake23
-rw-r--r--cmake/external/firestore.cmake27
-rw-r--r--cmake/external/googletest.cmake26
-rw-r--r--cmake/external/grpc.cmake83
-rw-r--r--cmake/external/leveldb.cmake79
-rw-r--r--cmake/utils.cmake80
-rw-r--r--cmake/xcodebuild.cmake89
-rw-r--r--patch/FirebaseAnalytics.h16
-rw-r--r--scripts/cpplint.py6228
-rwxr-xr-xscripts/lint.sh18
-rwxr-xr-xscripts/style.sh41
-rwxr-xr-xtest.sh20
537 files changed, 26258 insertions, 5944 deletions
diff --git a/.gitignore b/.gitignore
index 93e3974..7645c89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,9 @@ DerivedData
*.hmap
*.ipa
+# IntelliJ
+.idea
+
# Vim
*.swo
*.swp
@@ -55,5 +58,10 @@ Pods/
Podfile.lock
*.xcworkspace
+# Firestore's build configuration, as generated by CocoaPods
+Firestore/core/src/firebase/firestore/util/config.h
+
# CMake
.downloads
+Debug
+Release
diff --git a/.travis.yml b/.travis.yml
index 351bb85..5ee84f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-osx_image: xcode9.1
+osx_image: xcode9.2
language: objective-c
cache:
- bundler
@@ -12,11 +12,38 @@ before_install:
- gem install xcpretty
- bundle exec pod install --project-directory=Example --repo-update
- bundle exec pod install --project-directory=Firestore/Example --no-repo-update
+ - brew install clang-format
+ - echo "$TRAVIS_COMMIT_RANGE"
+ - echo "$TRAVIS_PULL_REQUEST"
+ - |
+ if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
+ SKIP_FIREBASE=0
+ SKIP_FIRESTORE=0
+ else
+ git diff --name-only $TRAVIS_COMMIT_RANGE | grep -Eq '^(Firebase|Example)'
+ SKIP_FIREBASE="$?"
+ git diff --name-only $TRAVIS_COMMIT_RANGE | grep -q Firestore
+ SKIP_FIRESTORE="$?"
+ fi
script:
- "! git grep -I ' $'" # Fail on trailing whitespace in non-binary files
- - ./test.sh
- - bundle exec pod lib lint FirebaseCore.podspec
+ - "! git grep -EL --name-only 'Copyright [0-9]{4}.*Google' | grep -v third_party | egrep '\\.(m|h|cc|mm|c)$'"
+ - ./scripts/style.sh test-only # Validate clang-format compliance
+ - |
+ if [ $SKIP_FIREBASE != 1 ]; then
+ ./test.sh
+ fi
+ - |
+ if [ $SKIP_FIRESTORE != 1 ]; then
+ ./Firestore/test.sh
+ fi
+
+# TODO fix os_log deprecation warning in FIRLogger to remove --allow-warnings
+ - |
+ if [ $SKIP_FIREBASE != 1 ]; then
+ bundle exec pod lib lint FirebaseCore.podspec --allow-warnings
+ fi
# TODO - Uncomment subsequent lines once FirebaseCore source repo is in public Specs repo
# - bundle exec pod lib lint FirebaseAuth.podspec
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f9e7527..f58a980 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,14 +17,27 @@
cmake_minimum_required(VERSION 2.8.11)
project(firebase C CXX)
+# If no build type is specified, make it a debug build
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Debug)
+endif()
+
+if(APPLE)
+ # When building on the apple platform certain Objective-C++ classes bridge
+ # back into other Firebase Cocoapods. This requires shelling out to xcodebuild
+ # to verify the built frameworks are up-to-date. You can disable this to speed
+ # up the build.
+ option(BUILD_PODS, "Always build dependent cocoapods." ON)
+endif(APPLE)
+
list(INSERT CMAKE_MODULE_PATH 0 ${PROJECT_SOURCE_DIR}/cmake)
-# External Projects install into this prefix and download into the source tree
-# to avoid re-downloading repeatedly during development.
-set(FIREBASE_INSTALL_DIR "${PROJECT_BINARY_DIR}/usr")
-set(FIREBASE_DOWNLOAD_DIR "${PROJECT_SOURCE_DIR}/.downloads")
+set(FIREBASE_INSTALL_DIR ${PROJECT_BINARY_DIR})
enable_testing()
+include(external/FirebaseCore)
include(external/googletest)
+include(external/leveldb)
+include(external/grpc)
include(external/firestore)
diff --git a/Example/Auth/ApiTests/AuthCredentialsTemplate.h b/Example/Auth/ApiTests/AuthCredentialsTemplate.h
index a8bf379..09eb62a 100644
--- a/Example/Auth/ApiTests/AuthCredentialsTemplate.h
+++ b/Example/Auth/ApiTests/AuthCredentialsTemplate.h
@@ -50,6 +50,9 @@ The name of the test user for Facebook Login.
$KCUSTOM_AUTH_TOKEN_URL
A URL to return a Custom Auth token.
+$KCUSTOM_AUTH_TOKEN_EXPIRED_URL
+A URL to return an expired Custom Auth token.
+
$KCUSTOM_AUTH_USER_ID
The ID of the test user in the Custom Auth token.
*/
@@ -61,4 +64,5 @@ The ID of the test user in the Custom Auth token.
#define KFACEBOOK_APP_ACCESS_TOKEN $KFACEBOOK_APP_ACCESS_TOKEN
#define KFACEBOOK_USER_NAME $KFACEBOOK_USER_NAME
#define KCUSTOM_AUTH_TOKEN_URL $KCUSTOM_AUTH_TOKEN_URL
+#define KCUSTOM_AUTH_TOKEN_EXPIRED_URL $KCUSTOM_AUTH_TOKEN_EXPIRED_URL
#define KCUSTOM_AUTH_USER_ID $KCUSTOM_AUTH_USER_ID
diff --git a/Example/Auth/ApiTests/FirebaseAuthApiTests.m b/Example/Auth/ApiTests/FirebaseAuthApiTests.m
index 454d9dd..741814c 100644
--- a/Example/Auth/ApiTests/FirebaseAuthApiTests.m
+++ b/Example/Auth/ApiTests/FirebaseAuthApiTests.m
@@ -36,6 +36,10 @@ static NSString *const kCustomAuthTestingAccountUserID = KCUSTOM_AUTH_USER_ID;
/** The url for obtaining a valid custom token string used to test Custom Auth. */
static NSString *const kCustomTokenUrl = KCUSTOM_AUTH_TOKEN_URL;
+/** The url for obtaining an expired but valid custom token string used to test Custom Auth failure.
+ */
+static NSString *const kExpiredCustomTokenUrl = KCUSTOM_AUTH_TOKEN_EXPIRED_URL;
+
/** Facebook app access token that will be used for Facebook Graph API, which is different from
* account access token.
*/
@@ -59,6 +63,12 @@ static NSString *const kTestingEmailToCreateUser = @"abc@xyz.com";
/** The testing email address for testSignInExistingUserWithEmailAndPassword. */
static NSString *const kExistingTestingEmailToSignIn = @"456@abc.com";
+/** The testing email address for testUpdatingUsersEmail. */
+static NSString *const kNewTestingEmail = @"updatedEmail@abc.com";
+
+/** The testing password for testSignInExistingUserWithModifiedEmailAndPassword. */
+static NSString *const kNewTestingPasswordToSignIn = @"password_new";
+
/** Error message for invalid custom token sign in. */
NSString *kInvalidTokenErrorMessage =
@"The custom token format is incorrect. Please check the documentation.";
@@ -71,7 +81,7 @@ NSString *kGoogleCliendId = KGOOGLE_CLIENT_ID;
*/
NSString *kGoogleTestAccountRefreshToken = KGOOGLE_TEST_ACCOUNT_REFRESH_TOKEN;
-static NSTimeInterval const kExpectationsTimeout = 30;
+static NSTimeInterval const kExpectationsTimeout = 10;
#ifdef NO_NETWORK
#define SKIP_IF_ON_MOBILE_HARNESS \
@@ -141,6 +151,38 @@ static NSTimeInterval const kExpectationsTimeout = 30;
[self deleteCurrentFirebaseUser];
}
+- (void)testUpdatingUsersEmail {
+ SKIP_IF_ON_MOBILE_HARNESS
+ FIRAuth *auth = [FIRAuth auth];
+ if (!auth) {
+ XCTFail(@"Could not obtain auth object.");
+ }
+
+ __block NSError *apiError;
+ XCTestExpectation *expectation =
+ [self expectationWithDescription:@"Created account with email and password."];
+ [auth createUserWithEmail:kTestingEmailToCreateUser
+ password:@"password"
+ completion:^(FIRUser *user, NSError *error) {
+ apiError = error;
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil];
+ expectation = [self expectationWithDescription:@"Created account with email and password."];
+ XCTAssertEqualObjects(auth.currentUser.email, kTestingEmailToCreateUser);
+ XCTAssertNil(apiError);
+ [auth.currentUser updateEmail:kNewTestingEmail
+ completion:^(NSError *_Nullable error) {
+ apiError = error;
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil];
+ XCTAssertNil(apiError);
+ XCTAssertEqualObjects(auth.currentUser.email, kNewTestingEmail);
+ // Clean up the created Firebase user for future runs.
+ [self deleteCurrentFirebaseUser];
+}
+
- (void)testLinkAnonymousAccountToFacebookAccount {
FIRAuth *auth = [FIRAuth auth];
if (!auth) {
@@ -253,6 +295,92 @@ static NSTimeInterval const kExpectationsTimeout = 30;
XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID);
}
+- (void)testSignInWithValidCustomAuthExpiredToken {
+ FIRAuth *auth = [FIRAuth auth];
+ if (!auth) {
+ XCTFail(@"Could not obtain auth object.");
+ }
+
+ NSError *error;
+ NSString *customToken =
+ [NSString stringWithContentsOfURL:[NSURL URLWithString:kExpiredCustomTokenUrl]
+ encoding:NSUTF8StringEncoding
+ error:&error];
+ if (!customToken) {
+ XCTFail(@"There was an error retrieving the custom token: %@", error);
+ }
+ XCTestExpectation *expectation =
+ [self expectationWithDescription:@"CustomAuthToken sign-in finished."];
+
+ __block NSError *apiError;
+ [auth signInWithCustomToken:customToken
+ completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
+ if (error) {
+ apiError = error;
+ }
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationsTimeout
+ handler:^(NSError *error) {
+ if (error != nil) {
+ XCTFail(@"Failed to wait for expectations "
+ @"in CustomAuthToken sign in. Error: %@",
+ error.localizedDescription);
+ }
+ }];
+
+ XCTAssertNil(auth.currentUser);
+ XCTAssertEqual(apiError.code, FIRAuthErrorCodeInvalidCustomToken);
+}
+
+- (void)testInMemoryUserAfterSignOut {
+ FIRAuth *auth = [FIRAuth auth];
+ if (!auth) {
+ XCTFail(@"Could not obtain auth object.");
+ }
+ NSError *error;
+ NSString *customToken = [NSString stringWithContentsOfURL:[NSURL URLWithString:kCustomTokenUrl]
+ encoding:NSUTF8StringEncoding
+ error:&error];
+ if (!customToken) {
+ XCTFail(@"There was an error retrieving the custom token: %@", error);
+ }
+ XCTestExpectation *expectation =
+ [self expectationWithDescription:@"CustomAuthToken sign-in finished."];
+ __block NSError *rpcError;
+ [auth signInWithCustomToken:customToken
+ completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
+ if (error) {
+ rpcError = error;
+ }
+ [expectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationsTimeout
+ handler:^(NSError *error) {
+ if (error != nil) {
+ XCTFail(@"Failed to wait for expectations "
+ @"in CustomAuthToken sign in. Error: %@",
+ error.localizedDescription);
+ }
+ }];
+ XCTAssertEqualObjects(auth.currentUser.uid, kCustomAuthTestingAccountUserID);
+ XCTAssertNil(rpcError);
+ FIRUser *inMemoryUser = auth.currentUser;
+ XCTestExpectation *expectation1 = [self expectationWithDescription:@"Profile data change."];
+ [auth signOut:NULL];
+ rpcError = nil;
+ NSString *newEmailAddress = [self fakeRandomEmail];
+ XCTAssertNotEqualObjects(newEmailAddress, inMemoryUser.email);
+ [inMemoryUser updateEmail:newEmailAddress completion:^(NSError *_Nullable error) {
+ rpcError = error;
+ [expectation1 fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationsTimeout handler:nil];
+ XCTAssertEqualObjects(inMemoryUser.email, newEmailAddress);
+ XCTAssertNil(rpcError);
+ XCTAssertNil(auth.currentUser);
+}
+
- (void)testSignInWithInvalidCustomAuthToken {
FIRAuth *auth = [FIRAuth auth];
if (!auth) {
@@ -354,6 +482,17 @@ static NSTimeInterval const kExpectationsTimeout = 30;
#pragma mark - Helpers
+/** Generate fake random email address */
+- (NSString *)fakeRandomEmail {
+ NSMutableString *fakeEmail = [[NSMutableString alloc] init];
+ for (int i=0; i<10; i++) {
+ [fakeEmail appendString:
+ [NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]];
+ }
+ [fakeEmail appendString:@"@gmail.com"];
+ return fakeEmail;
+}
+
/** Sign out current account. */
- (void)signOut {
NSError *signOutError;
diff --git a/Example/Auth/App/GoogleService-Info.plist b/Example/Auth/App/GoogleService-Info.plist
index 89afffe..3f7547f 100644
--- a/Example/Auth/App/GoogleService-Info.plist
+++ b/Example/Auth/App/GoogleService-Info.plist
@@ -10,8 +10,6 @@
<string>correct_client_id</string>
<key>REVERSED_CLIENT_ID</key>
<string>correct_reversed_client_id</string>
- <key>ANDROID_CLIENT_ID</key>
- <string>correct_android_client_id</string>
<key>GOOGLE_APP_ID</key>
<string>1:123:ios:123abc</string>
<key>GCM_SENDER_ID</key>
diff --git a/Example/Auth/App/tvOS/AppDelegate.h b/Example/Auth/App/tvOS/AppDelegate.h
new file mode 100644
index 0000000..013891c
--- /dev/null
+++ b/Example/Auth/App/tvOS/AppDelegate.h
@@ -0,0 +1,21 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/Example/Auth/App/tvOS/AppDelegate.m b/Example/Auth/App/tvOS/AppDelegate.m
new file mode 100644
index 0000000..3935032
--- /dev/null
+++ b/Example/Auth/App/tvOS/AppDelegate.m
@@ -0,0 +1,63 @@
+// Copyright 2017 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 FirebaseCore;
+@import FirebaseAuth;
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ [FIRApp configure];
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+ // Sent when the application is about to move from active to inactive state. This can occur for
+ // certain types of temporary interruptions (such as an incoming phone call or SMS message) or
+ // when the user quits the application and it begins the transition to the background state. Use
+ // this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates.
+ // Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ // Use this method to release shared resources, save user data, invalidate timers, and store
+ // enough application state information to restore your application to its current state in case
+ // it is terminated later. If your application supports background execution, this method is
+ // called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ // Called as part of the transition from the background to the active state; here you can undo
+ // many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If
+ // the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+ // Called when the application is about to terminate. Save data if appropriate. See also
+ // applicationDidEnterBackground:.
+}
+
+@end
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
new file mode 100644
index 0000000..b03ded1
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
@@ -0,0 +1,32 @@
+{
+ "assets" : [
+ {
+ "size" : "1280x768",
+ "idiom" : "tv",
+ "filename" : "App Icon - App Store.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "400x240",
+ "idiom" : "tv",
+ "filename" : "App Icon.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "2320x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image Wide.imageset",
+ "role" : "top-shelf-image-wide"
+ },
+ {
+ "size" : "1920x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image.imageset",
+ "role" : "top-shelf-image"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json b/Example/Auth/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..d746a60
--- /dev/null
+++ b/Example/Auth/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "11.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "9.0",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Auth/App/tvOS/Info.plist b/Example/Auth/App/tvOS/Info.plist
new file mode 100644
index 0000000..02942a3
--- /dev/null
+++ b/Example/Auth/App/tvOS/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>arm64</string>
+ </array>
+ <key>UIUserInterfaceStyle</key>
+ <string>Automatic</string>
+</dict>
+</plist>
diff --git a/Example/Auth/App/tvOS/Main.storyboard b/Example/Auth/App/tvOS/Main.storyboard
new file mode 100644
index 0000000..72d5e22
--- /dev/null
+++ b/Example/Auth/App/tvOS/Main.storyboard
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" systemVersion="17A278a" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+ <viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/Example/Auth/App/tvOS/ViewController.h b/Example/Auth/App/tvOS/ViewController.h
new file mode 100644
index 0000000..b6115b8
--- /dev/null
+++ b/Example/Auth/App/tvOS/ViewController.h
@@ -0,0 +1,19 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+@end
diff --git a/Example/Auth/App/tvOS/ViewController.m b/Example/Auth/App/tvOS/ViewController.m
new file mode 100644
index 0000000..6d4676b
--- /dev/null
+++ b/Example/Auth/App/tvOS/ViewController.m
@@ -0,0 +1,33 @@
+// Copyright 2017 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 "ViewController.h"
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/Example/Auth/App/tvOS/main.m b/Example/Auth/App/tvOS/main.m
new file mode 100644
index 0000000..d9e6654
--- /dev/null
+++ b/Example/Auth/App/tvOS/main.m
@@ -0,0 +1,22 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/Example/Auth/Sample/MainViewController.m b/Example/Auth/Sample/MainViewController.m
index 5326463..31c103a 100644
--- a/Example/Auth/Sample/MainViewController.m
+++ b/Example/Auth/Sample/MainViewController.m
@@ -38,12 +38,18 @@
#import "UserInfoViewController.h"
#import "UserTableViewCell.h"
+NS_ASSUME_NONNULL_BEGIN
-/*! @typedef textInputCompletionBlock
+/** @typedef textInputCompletionBlock
@brief The type of callback used to report text input prompt results.
*/
typedef void (^textInputCompletionBlock)(NSString *_Nullable userInput);
+/** @typedef testAutomationCallback
+ @brief The type of callback used when automatically testing an API.
+ */
+typedef void (^testAutomationCallback)(NSError *_Nullable error);
+
/** @var kTokenGetButtonText
@brief The text of the "Get Token" button.
*/
@@ -2187,18 +2193,20 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
@completion A completion block to be executed after the provider is unlinked.
*/
- (void)unlinkFromProvider:(NSString *)provider
- completion:(void(^)(NSError *_Nullable))completion {
+ completion:(nullable testAutomationCallback)completion {
[[self user] unlinkFromProvider:provider
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error) {
if (error) {
[self logFailure:@"unlink auth provider failed" error:error];
- completion(error);
- } else {
- [self logSuccess:@"unlink auth provider succeeded."];
if (completion) {
- completion(nil);
+ completion(error);
}
+ return;
+ }
+ [self logSuccess:@"unlink auth provider succeeded."];
+ if (completion) {
+ completion(nil);
}
[self showTypicalUIForUserUpdateResultsWithTitle:kUnlinkTitle error:error];
}];
@@ -2642,7 +2650,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
@completion A completion block to be executed after successful phone number sign in.
*/
- (void)signInWithPhoneNumber:(NSString *_Nullable)phoneNumber
- completion:(void(^)(NSError *_Nullable))completion {
+ completion:(nullable testAutomationCallback)completion {
[self showSpinner:^{
[[AppManager phoneAuthProvider] verifyPhoneNumber:phoneNumber
UIDelegate:nil
@@ -2707,15 +2715,23 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
FIRAuthCredential *credential =
[[AppManager phoneAuthProvider] credentialWithVerificationID:verificationID
verificationCode:verificationCode];
- [[AppManager auth] signInWithCredential:credential
- completion:^(FIRUser *_Nullable user,
- NSError *_Nullable error) {
+ [[AppManager auth] signInAndRetrieveDataWithCredential:credential
+ completion:^(FIRAuthDataResult *_Nullable result,
+ NSError *_Nullable error) {
[self hideSpinner:^{
if (error) {
[self logFailure:@"failed to verify phone number" error:error];
[self showMessagePrompt:error.localizedDescription];
return;
}
+ if (_isNewUserToggleOn) {
+ NSString *newUserString = result.additionalUserInfo.isNewUser ?
+ @"New user" : @"Existing user";
+ [self showMessagePromptWithTitle:@"New or Existing"
+ message:newUserString
+ showCancelButton:NO
+ completion:nil];
+ }
}];
}];
}];
@@ -2727,7 +2743,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
@completion A completion block to be executed after phone number is updated.
*/
- (void)updatePhoneNumber:(NSString *_Nullable)phoneNumber
- completion:(void(^)(NSError *_Nullable))completion{
+ completion:(nullable testAutomationCallback)completion {
[self showSpinner:^{
[[AppManager phoneAuthProvider] verifyPhoneNumber:phoneNumber
UIDelegate:nil
@@ -2736,7 +2752,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
if (error) {
[self logFailure:@"failed to send verification code" error:error];
[self showMessagePrompt:error.localizedDescription];
- completion(error);
+ if (completion) {
+ completion(error);
+ }
return;
}
[self logSuccess:@"Code sent"];
@@ -2757,7 +2775,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
if (error) {
[self logFailure:@"update phone number failed" error:error];
[self showMessagePrompt:error.localizedDescription];
- completion(error);
+ if (completion) {
+ completion(error);
+ }
} else {
[self logSuccess:@"update phone number succeeded."];
if (completion) {
@@ -2794,7 +2814,7 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
@completion A completion block to be executed after linking phone number.
*/
- (void)linkPhoneNumber:(NSString *_Nullable)phoneNumber
- completion:(void(^)(NSError *_Nullable))completion{
+ completion:(nullable testAutomationCallback)completion {
[self showSpinner:^{
[[AppManager phoneAuthProvider] verifyPhoneNumber:phoneNumber
UIDelegate:nil
@@ -2804,7 +2824,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
if (error) {
[self logFailure:@"failed to send verification code" error:error];
[self showMessagePrompt:error.localizedDescription];
- completion(error);
+ if (completion) {
+ completion(error);
+ }
return;
}
[self logSuccess:@"Code sent"];
@@ -2845,7 +2867,9 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
if (error) {
[self logFailure:@"failed to verify phone number" error:error];
[self showMessagePrompt:error.localizedDescription];
- completion(error);
+ if (completion) {
+ completion(error);
+ }
return;
}
}];
@@ -3147,3 +3171,5 @@ static NSDictionary<NSString *, NSString *> *parseURL(NSString *urlString) {
}
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Example/Auth/Tests/FIRAuthAPNSTokenManagerTests.m b/Example/Auth/Tests/FIRAuthAPNSTokenManagerTests.m
index 68e8bcf..79ffb7a 100644
--- a/Example/Auth/Tests/FIRAuthAPNSTokenManagerTests.m
+++ b/Example/Auth/Tests/FIRAuthAPNSTokenManagerTests.m
@@ -31,7 +31,7 @@ static const NSTimeInterval kRegistrationTimeout = .5;
@brief The test expectation timeout.
@remarks This must be considerably greater than @c kVerificationTimeout .
*/
-static const NSTimeInterval kExpectationTimeout = 1;
+static const NSTimeInterval kExpectationTimeout = 2;
/** @class FIRAuthLegacyUIApplication
@brief A fake legacy (< iOS 7) UIApplication class.
diff --git a/Example/Auth/Tests/FIRAuthDispatcherTests.m b/Example/Auth/Tests/FIRAuthDispatcherTests.m
index fc8cab1..193be4c 100644
--- a/Example/Auth/Tests/FIRAuthDispatcherTests.m
+++ b/Example/Auth/Tests/FIRAuthDispatcherTests.m
@@ -32,7 +32,7 @@ NSTimeInterval kTestDelay = 0.1;
/** @var kExpectationTimeout
@brief The maximum time waiting for expectations to fulfill.
*/
-static const NSTimeInterval kExpectationTimeout = 1;
+static const NSTimeInterval kExpectationTimeout = 2;
id<OS_dispatch_queue> testWorkQueue;
diff --git a/Example/Auth/Tests/FIRAuthTests.m b/Example/Auth/Tests/FIRAuthTests.m
index 80a9ae9..b22c600 100644
--- a/Example/Auth/Tests/FIRAuthTests.m
+++ b/Example/Auth/Tests/FIRAuthTests.m
@@ -170,7 +170,7 @@ static NSString *const kVerificationID = @"55432";
/** @var kExpectationTimeout
@brief The maximum time waiting for expectations to fulfill.
*/
-static const NSTimeInterval kExpectationTimeout = 1;
+static const NSTimeInterval kExpectationTimeout = 2;
/** @var kWaitInterval
@brief The time waiting for background tasks to finish before continue when necessary.
@@ -430,6 +430,8 @@ static const NSTimeInterval kWaitInterval = .5;
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
[self stubTokensWithMockResponse:mockVerifyPhoneResponse];
+ // Stub isNewUser flag in the response.
+ OCMStub([mockVerifyPhoneResponse isNewUser]).andReturn(YES);
callback(mockVerifyPhoneResponse, nil);
});
});
@@ -440,10 +442,12 @@ static const NSTimeInterval kWaitInterval = .5;
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
verificationCode:kVerificationCode];
- [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user,
- NSError *_Nullable error) {
+ [[FIRAuth auth] signInAndRetrieveDataWithCredential:credential
+ completion:^(FIRAuthDataResult *_Nullable authDataResult,
+ NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
- [self assertUser:user];
+ [self assertUser:authDataResult.user];
+ XCTAssertTrue(authDataResult.additionalUserInfo.isNewUser);
XCTAssertNil(error);
[expectation fulfill];
}];
diff --git a/Example/Auth/Tests/FIRAuthURLPresenterTests.m b/Example/Auth/Tests/FIRAuthURLPresenterTests.m
index fcc64e9..a4e6c53 100644
--- a/Example/Auth/Tests/FIRAuthURLPresenterTests.m
+++ b/Example/Auth/Tests/FIRAuthURLPresenterTests.m
@@ -26,7 +26,7 @@
/** @var kExpectationTimeout
@brief The maximum time waiting for expectations to fulfill.
*/
-static NSTimeInterval kExpectationTimeout = 1;
+static NSTimeInterval kExpectationTimeout = 2;
@interface FIRAuthDefaultUIDelegate : NSObject <FIRAuthUIDelegate>
/** @fn defaultUIDelegate
diff --git a/Example/Auth/Tests/FIRPhoneAuthProviderTests.m b/Example/Auth/Tests/FIRPhoneAuthProviderTests.m
index c5f4ec7..0dc0b44 100644
--- a/Example/Auth/Tests/FIRPhoneAuthProviderTests.m
+++ b/Example/Auth/Tests/FIRPhoneAuthProviderTests.m
@@ -180,7 +180,7 @@ static const NSTimeInterval kTestTimeout = 5;
/** @var kExpectationTimeout
@brief The maximum time waiting for expectations to fulfill.
*/
-static const NSTimeInterval kExpectationTimeout = 1;
+static const NSTimeInterval kExpectationTimeout = 2;
/** @class FIRPhoneAuthProviderTests
@brief Tests for @c FIRPhoneAuthProvider
diff --git a/Example/Auth/Tests/FIRUserTests.m b/Example/Auth/Tests/FIRUserTests.m
index c044e83..68ee265 100644
--- a/Example/Auth/Tests/FIRUserTests.m
+++ b/Example/Auth/Tests/FIRUserTests.m
@@ -231,7 +231,7 @@ static NSTimeInterval const kLastSignInDateTimeIntervalInSeconds = 1505858583;
/** @var kExpectationTimeout
@brief The maximum time waiting for expectations to fulfill.
*/
-static const NSTimeInterval kExpectationTimeout = 1;
+static const NSTimeInterval kExpectationTimeout = 2;
/** @class FIRUserTests
@brief Tests for @c FIRUser .
diff --git a/Example/Auth/Tests/FIRVerifyPasswordRequestTest.m b/Example/Auth/Tests/FIRVerifyPasswordRequestTest.m
index 54ba7b0..2359c46 100644
--- a/Example/Auth/Tests/FIRVerifyPasswordRequestTest.m
+++ b/Example/Auth/Tests/FIRVerifyPasswordRequestTest.m
@@ -18,9 +18,9 @@
#import "FIRAuthErrors.h"
#import "FIRAuthBackend.h"
+#import "FIRFakeBackendRPCIssuer.h"
#import "FIRVerifyPasswordRequest.h"
#import "FIRVerifyPasswordResponse.h"
-#import "FIRFakeBackendRPCIssuer.h"
/** @var kTestAPIKey
@brief Fake API key used for testing.
@@ -125,9 +125,10 @@ static NSString *const kExpectedAPIURL =
@brief Tests the verify password request.
*/
- (void)testVerifyPasswordRequest {
- FIRVerifyPasswordRequest * request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
- password:kTestPassword
- requestConfiguration:_requestConfiguration];
+ FIRVerifyPasswordRequest * request =
+ [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
+ password:kTestPassword
+ requestConfiguration:_requestConfiguration];
request.returnSecureToken = NO;
[FIRAuthBackend verifyPassword:request
callback:^(FIRVerifyPasswordResponse *_Nullable response,
@@ -147,9 +148,10 @@ static NSString *const kExpectedAPIURL =
@brief Tests the verify password request with optional fields.
*/
- (void)testVerifyPasswordRequestOptionalFields {
- FIRVerifyPasswordRequest * request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
- password:kTestPassword
- requestConfiguration:_requestConfiguration];
+ FIRVerifyPasswordRequest * request =
+ [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
+ password:kTestPassword
+ requestConfiguration:_requestConfiguration];
request.pendingIDToken = kTestPendingToken;
request.captchaChallenge = kTestCaptchaChallenge;
request.captchaResponse = kTestCaptchaResponse;
diff --git a/Example/Core/App/GoogleService-Info.plist b/Example/Core/App/GoogleService-Info.plist
index 89afffe..3f7547f 100644
--- a/Example/Core/App/GoogleService-Info.plist
+++ b/Example/Core/App/GoogleService-Info.plist
@@ -10,8 +10,6 @@
<string>correct_client_id</string>
<key>REVERSED_CLIENT_ID</key>
<string>correct_reversed_client_id</string>
- <key>ANDROID_CLIENT_ID</key>
- <string>correct_android_client_id</string>
<key>GOOGLE_APP_ID</key>
<string>1:123:ios:123abc</string>
<key>GCM_SENDER_ID</key>
diff --git a/Example/Core/App/tvOS/AppDelegate.h b/Example/Core/App/tvOS/AppDelegate.h
new file mode 100644
index 0000000..013891c
--- /dev/null
+++ b/Example/Core/App/tvOS/AppDelegate.h
@@ -0,0 +1,21 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/Example/Core/App/tvOS/AppDelegate.m b/Example/Core/App/tvOS/AppDelegate.m
new file mode 100644
index 0000000..9717ad4
--- /dev/null
+++ b/Example/Core/App/tvOS/AppDelegate.m
@@ -0,0 +1,62 @@
+// Copyright 2017 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 FirebaseCore;
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ [FIRApp configure];
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+ // Sent when the application is about to move from active to inactive state. This can occur for
+ // certain types of temporary interruptions (such as an incoming phone call or SMS message) or
+ // when the user quits the application and it begins the transition to the background state. Use
+ // this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates.
+ // Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ // Use this method to release shared resources, save user data, invalidate timers, and store
+ // enough application state information to restore your application to its current state in case
+ // it is terminated later. If your application supports background execution, this method is
+ // called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ // Called as part of the transition from the background to the active state; here you can undo
+ // many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If
+ // the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+ // Called when the application is about to terminate. Save data if appropriate. See also
+ // applicationDidEnterBackground:.
+}
+
+@end
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
new file mode 100644
index 0000000..b03ded1
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
@@ -0,0 +1,32 @@
+{
+ "assets" : [
+ {
+ "size" : "1280x768",
+ "idiom" : "tv",
+ "filename" : "App Icon - App Store.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "400x240",
+ "idiom" : "tv",
+ "filename" : "App Icon.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "2320x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image Wide.imageset",
+ "role" : "top-shelf-image-wide"
+ },
+ {
+ "size" : "1920x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image.imageset",
+ "role" : "top-shelf-image"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json b/Example/Core/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..d746a60
--- /dev/null
+++ b/Example/Core/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "11.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "9.0",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Core/App/tvOS/Info.plist b/Example/Core/App/tvOS/Info.plist
new file mode 100644
index 0000000..02942a3
--- /dev/null
+++ b/Example/Core/App/tvOS/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>arm64</string>
+ </array>
+ <key>UIUserInterfaceStyle</key>
+ <string>Automatic</string>
+</dict>
+</plist>
diff --git a/Example/Core/App/tvOS/Main.storyboard b/Example/Core/App/tvOS/Main.storyboard
new file mode 100644
index 0000000..72d5e22
--- /dev/null
+++ b/Example/Core/App/tvOS/Main.storyboard
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" systemVersion="17A278a" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+ <viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/Example/Core/App/tvOS/ViewController.h b/Example/Core/App/tvOS/ViewController.h
new file mode 100644
index 0000000..b6115b8
--- /dev/null
+++ b/Example/Core/App/tvOS/ViewController.h
@@ -0,0 +1,19 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+@end
diff --git a/Example/Core/App/tvOS/ViewController.m b/Example/Core/App/tvOS/ViewController.m
new file mode 100644
index 0000000..6d4676b
--- /dev/null
+++ b/Example/Core/App/tvOS/ViewController.m
@@ -0,0 +1,33 @@
+// Copyright 2017 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 "ViewController.h"
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/Example/Core/App/tvOS/main.m b/Example/Core/App/tvOS/main.m
new file mode 100644
index 0000000..d9e6654
--- /dev/null
+++ b/Example/Core/App/tvOS/main.m
@@ -0,0 +1,22 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/Example/Core/Tests/FIRAppAssociationRegistrationUnitTests.m b/Example/Core/Tests/FIRAppAssociationRegistrationUnitTests.m
index 2bc1de7..60f0651 100644
--- a/Example/Core/Tests/FIRAppAssociationRegistrationUnitTests.m
+++ b/Example/Core/Tests/FIRAppAssociationRegistrationUnitTests.m
@@ -34,7 +34,7 @@ static NSString *kKey2 = @"key2";
/** @var gCreateNewObject
@brief A block that returns a new object everytime it is called.
*/
-static id _Nullable (^gCreateNewObject)() = ^id _Nullable() {
+static id _Nullable (^gCreateNewObject)(void) = ^id _Nullable() {
return [[NSObject alloc] init];
};
diff --git a/Example/Core/Tests/FIRAppTest.m b/Example/Core/Tests/FIRAppTest.m
index 9b3554d..8466488 100644
--- a/Example/Core/Tests/FIRAppTest.m
+++ b/Example/Core/Tests/FIRAppTest.m
@@ -95,8 +95,11 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
}
- (void)testConfigureWithOptions {
- // nil options
+// nil options
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
XCTAssertThrows([FIRApp configureWithOptions:nil]);
+#pragma clang diagnostic pop
XCTAssertTrue([FIRApp allApps].count == 0);
NSDictionary *expectedUserInfo =
@@ -116,7 +119,10 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
}
- (void)testConfigureWithCustomizedOptions {
- // valid customized options
+// valid customized options
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID
bundleID:kBundleID
GCMSenderID:kGCMSenderID
@@ -127,7 +133,7 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
databaseURL:nil
storageBucket:nil
deepLinkURLScheme:nil];
-
+#pragma clang diagnostic pop
NSDictionary *expectedUserInfo =
[self expectedUserInfoWithAppName:kFIRDefaultAppName isDefaultApp:YES];
OCMExpect([self.notificationCenterMock postNotificationName:kFIRAppReadyToConfigureSDKNotification
@@ -146,8 +152,11 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
}
- (void)testConfigureWithNameAndOptions {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
XCTAssertThrows([FIRApp configureWithName:nil options:[FIROptions defaultOptions]]);
XCTAssertThrows([FIRApp configureWithName:kFIRTestAppName1 options:nil]);
+#pragma clang diagnostic pop
XCTAssertThrows([FIRApp configureWithName:@"" options:[FIROptions defaultOptions]]);
XCTAssertThrows(
[FIRApp configureWithName:kFIRDefaultAppName options:[FIROptions defaultOptions]]);
@@ -185,7 +194,10 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
XCTAssertTrue([FIRApp allApps].count == 1);
self.app = [FIRApp appNamed:kFIRTestAppName1];
- // Configure a different app with valid customized options
+// Configure a different app with valid customized options
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
FIROptions *customizedOptions = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID
bundleID:kBundleID
GCMSenderID:kGCMSenderID
@@ -196,6 +208,7 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2";
databaseURL:nil
storageBucket:nil
deepLinkURLScheme:nil];
+#pragma clang diagnostic pop
NSDictionary *expectedUserInfo2 =
[self expectedUserInfoWithAppName:kFIRTestAppName2 isDefaultApp:NO];
diff --git a/Example/Core/Tests/FIRLoggerTest.m b/Example/Core/Tests/FIRLoggerTest.m
index 7740527..5cc7465 100644
--- a/Example/Core/Tests/FIRLoggerTest.m
+++ b/Example/Core/Tests/FIRLoggerTest.m
@@ -28,13 +28,13 @@ extern const char *kFIRLoggerASLClientFacilityName;
extern const char *kFIRLoggerCustomASLMessageFormat;
-extern void FIRResetLogger();
+extern void FIRResetLogger(void);
-extern aslclient getFIRLoggerClient();
+extern aslclient getFIRLoggerClient(void);
-extern dispatch_queue_t getFIRClientQueue();
+extern dispatch_queue_t getFIRClientQueue(void);
-extern BOOL getFIRLoggerDebugMode();
+extern BOOL getFIRLoggerDebugMode(void);
// Define the message format again to make sure the format doesn't accidentally change.
static NSString *const kCorrectASLMessageFormat =
@@ -148,8 +148,12 @@ static NSString *const kMessageCode = @"I-COR000001";
// Lowercase should fail.
XCTAssertThrows(FIRLogError(kFIRLoggerCore, @"I-app000001", @"Message."));
- // nil or empty message code should fail.
+// nil or empty message code should fail.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
XCTAssertThrows(FIRLogError(kFIRLoggerCore, nil, @"Message."));
+#pragma clang diagnostic pop
+
XCTAssertThrows(FIRLogError(kFIRLoggerCore, @"", @"Message."));
// Android message code should fail.
@@ -241,6 +245,8 @@ static NSString *const kMessageCode = @"I-COR000001";
}
- (BOOL)messageWasLogged:(NSString *)message {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
aslmsg query = asl_new(ASL_TYPE_QUERY);
asl_set_query(query, ASL_KEY_FACILITY, kFIRLoggerASLClientFacilityName, ASL_QUERY_OP_EQUAL);
aslresponse r = asl_search(getFIRLoggerClient(), query);
@@ -257,6 +263,7 @@ static NSString *const kMessageCode = @"I-COR000001";
asl_free(m);
asl_release(r);
return [allMsg containsObject:message];
+#pragma clang pop
}
@end
diff --git a/Example/Core/Tests/FIROptionsTest.m b/Example/Core/Tests/FIROptionsTest.m
index d01eec5..8170405 100644
--- a/Example/Core/Tests/FIROptionsTest.m
+++ b/Example/Core/Tests/FIROptionsTest.m
@@ -25,7 +25,8 @@ extern NSString *const kFIRLibraryVersionID;
@interface FIROptions (Test)
-@property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary;
+- (nullable NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:
+ (nullable NSDictionary *)infoDictionary;
@end
@@ -80,23 +81,24 @@ extern NSString *const kFIRLibraryVersionID;
}
- (void)testInitCustomizedOptions {
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:kGoogleAppID
bundleID:kBundleID
GCMSenderID:kGCMSenderID
APIKey:kAPIKey
clientID:kClientID
trackingID:kTrackingID
- androidClientID:kAndroidClientID
+ androidClientID:(id _Nonnull)nil
databaseURL:kDatabaseURL
storageBucket:kStorageBucket
deepLinkURLScheme:kDeepLinkURLScheme];
+#pragma clang pop
[self assertOptionsMatchDefaults:options andProjectID:NO];
XCTAssertEqualObjects(options.deepLinkURLScheme, kDeepLinkURLScheme);
XCTAssertFalse(options.usingOptionsFromDefaultPlist);
FIROptions *options2 =
[[FIROptions alloc] initWithGoogleAppID:kGoogleAppID GCMSenderID:kGCMSenderID];
- options2.androidClientID = kAndroidClientID;
options2.APIKey = kAPIKey;
options2.bundleID = kBundleID;
options2.clientID = kClientID;
@@ -109,7 +111,10 @@ extern NSString *const kFIRLibraryVersionID;
XCTAssertEqualObjects(options2.deepLinkURLScheme, kDeepLinkURLScheme);
XCTAssertFalse(options.usingOptionsFromDefaultPlist);
- // nil GoogleAppID should throw an exception
+// nil GoogleAppID should throw an exception
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
XCTAssertThrows([[FIROptions alloc] initWithGoogleAppID:nil
bundleID:kBundleID
GCMSenderID:kGCMSenderID
@@ -120,6 +125,7 @@ extern NSString *const kFIRLibraryVersionID;
databaseURL:nil
storageBucket:nil
deepLinkURLScheme:nil]);
+#pragma clang diagnostic pop
}
- (void)testinitWithContentsOfFile {
@@ -130,7 +136,10 @@ extern NSString *const kFIRLibraryVersionID;
XCTAssertNil(options.deepLinkURLScheme);
XCTAssertFalse(options.usingOptionsFromDefaultPlist);
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
FIROptions *emptyOptions = [[FIROptions alloc] initWithContentsOfFile:nil];
+#pragma clang diagnostic pop
XCTAssertNil(emptyOptions);
FIROptions *invalidOptions = [[FIROptions alloc] initWithContentsOfFile:@"invalid.plist"];
@@ -143,7 +152,7 @@ extern NSString *const kFIRLibraryVersionID;
XCTAssertEqualObjects(options.clientID, kClientID);
XCTAssertEqualObjects(options.trackingID, kTrackingID);
XCTAssertEqualObjects(options.GCMSenderID, kGCMSenderID);
- XCTAssertEqualObjects(options.androidClientID, kAndroidClientID);
+ XCTAssertNil(options.androidClientID);
XCTAssertEqualObjects(options.libraryVersionID, kFIRLibraryVersionID);
XCTAssertEqualObjects(options.databaseURL, kDatabaseURL);
XCTAssertEqualObjects(options.storageBucket, kStorageBucket);
@@ -236,7 +245,7 @@ extern NSString *const kFIRLibraryVersionID;
APIKey:kAPIKey
clientID:kClientID
trackingID:kTrackingID
- androidClientID:kAndroidClientID
+ androidClientID:(id _Nonnull)nil
databaseURL:kDatabaseURL
storageBucket:kStorageBucket
deepLinkURLScheme:kDeepLinkURLScheme];
@@ -255,22 +264,20 @@ extern NSString *const kFIRLibraryVersionID;
}
- (void)testAnalyticsOptions {
- id mainBundleMock = OCMPartialMock([NSBundle mainBundle]);
-
// No keys anywhere.
NSDictionary *optionsDictionary = nil;
FIROptions *options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
NSDictionary *mainDictionary = nil;
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
NSDictionary *expectedAnalyticsOptions = @{};
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ NSDictionary *analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:nil];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
optionsDictionary = @{};
options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
mainDictionary = @{};
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = @{};
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
// Main has no keys.
optionsDictionary = @{
@@ -280,9 +287,9 @@ extern NSString *const kFIRLibraryVersionID;
};
options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
mainDictionary = @{};
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = optionsDictionary;
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
// Main overrides all the keys.
optionsDictionary = @{
@@ -296,9 +303,9 @@ extern NSString *const kFIRLibraryVersionID;
kFIRIsAnalyticsCollectionEnabled : @NO,
kFIRIsMeasurementEnabled : @NO
};
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = mainDictionary;
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
// Keys exist only in main.
optionsDictionary = @{};
@@ -308,9 +315,9 @@ extern NSString *const kFIRLibraryVersionID;
kFIRIsAnalyticsCollectionEnabled : @YES,
kFIRIsMeasurementEnabled : @YES
};
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = mainDictionary;
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
// Main overrides single keys.
optionsDictionary = @{
@@ -320,13 +327,13 @@ extern NSString *const kFIRLibraryVersionID;
};
options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
mainDictionary = @{ kFIRIsAnalyticsCollectionDeactivated : @NO };
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = @{
kFIRIsAnalyticsCollectionDeactivated : @NO, // override
kFIRIsAnalyticsCollectionEnabled : @YES,
kFIRIsMeasurementEnabled : @YES
};
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
optionsDictionary = @{
kFIRIsAnalyticsCollectionDeactivated : @YES,
@@ -335,13 +342,13 @@ extern NSString *const kFIRLibraryVersionID;
};
options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
mainDictionary = @{ kFIRIsAnalyticsCollectionEnabled : @NO };
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = @{
kFIRIsAnalyticsCollectionDeactivated : @YES,
kFIRIsAnalyticsCollectionEnabled : @NO, // override
kFIRIsMeasurementEnabled : @YES
};
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
optionsDictionary = @{
kFIRIsAnalyticsCollectionDeactivated : @YES,
@@ -350,18 +357,18 @@ extern NSString *const kFIRLibraryVersionID;
};
options = [[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
mainDictionary = @{ kFIRIsMeasurementEnabled : @NO };
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
expectedAnalyticsOptions = @{
kFIRIsAnalyticsCollectionDeactivated : @YES,
kFIRIsAnalyticsCollectionEnabled : @YES,
kFIRIsMeasurementEnabled : @NO // override
};
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+ analyticsOptions = [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
}
- (void)testAnalyticsOptions_combinatorial {
// Complete combinatorial test.
- id mainBundleMock = OCMPartialMock([NSBundle mainBundle]);
+
// Possible values for the flags in the plist, where NSNull means the flag is not present.
NSArray *values = @[ [NSNull null], @NO, @YES ];
@@ -390,6 +397,7 @@ extern NSString *const kFIRLibraryVersionID;
if (![optionsMeasurementEnabled isEqual:[NSNull null]]) {
optionsDictionary[kFIRIsMeasurementEnabled] = optionsMeasurementEnabled;
}
+
FIROptions *options =
[[FIROptions alloc] initInternalWithOptionsDictionary:optionsDictionary];
if (![uniqueOptionsCombinations containsObject:optionsDictionary]) {
@@ -407,7 +415,8 @@ extern NSString *const kFIRLibraryVersionID;
if (![mainMeasurementEnabled isEqual:[NSNull null]]) {
mainDictionary[kFIRIsMeasurementEnabled] = mainMeasurementEnabled;
}
- OCMExpect([mainBundleMock infoDictionary]).andReturn(mainDictionary);
+
+ // Add mainDictionary to uniqueMainCombinations if it isn't included yet.
if (![uniqueMainCombinations containsObject:mainDictionary]) {
[uniqueMainCombinations addObject:mainDictionary];
}
@@ -419,7 +428,10 @@ extern NSString *const kFIRLibraryVersionID;
NSMutableDictionary *expectedAnalyticsOptions =
[[NSMutableDictionary alloc] initWithDictionary:optionsDictionary];
[expectedAnalyticsOptions addEntriesFromDictionary:mainDictionary];
- XCTAssertEqualObjects(options.analyticsOptionsDictionary, expectedAnalyticsOptions);
+
+ NSDictionary *analyticsOptions =
+ [options analyticsOptionsDictionaryWithInfoDictionary:mainDictionary];
+ XCTAssertEqualObjects(analyticsOptions, expectedAnalyticsOptions);
combinationCount++;
}
diff --git a/Example/Core/Tests/FIRTestCase.m b/Example/Core/Tests/FIRTestCase.m
index 2c68b8d..b52886b 100644
--- a/Example/Core/Tests/FIRTestCase.m
+++ b/Example/Core/Tests/FIRTestCase.m
@@ -19,7 +19,6 @@ NSString *const kCustomizedAPIKey = @"customized_api_key";
NSString *const kClientID = @"correct_client_id";
NSString *const kTrackingID = @"correct_tracking_id";
NSString *const kGCMSenderID = @"correct_gcm_sender_id";
-NSString *const kAndroidClientID = @"correct_android_client_id";
NSString *const kGoogleAppID = @"1:123:ios:123abc";
NSString *const kDatabaseURL = @"https://abc-xyz-123.firebaseio.com";
NSString *const kStorageBucket = @"project-id-123.storage.firebase.com";
diff --git a/Example/Database/App/GoogleService-Info.plist b/Example/Database/App/GoogleService-Info.plist
index 89afffe..3f7547f 100644
--- a/Example/Database/App/GoogleService-Info.plist
+++ b/Example/Database/App/GoogleService-Info.plist
@@ -10,8 +10,6 @@
<string>correct_client_id</string>
<key>REVERSED_CLIENT_ID</key>
<string>correct_reversed_client_id</string>
- <key>ANDROID_CLIENT_ID</key>
- <string>correct_android_client_id</string>
<key>GOOGLE_APP_ID</key>
<string>1:123:ios:123abc</string>
<key>GCM_SENDER_ID</key>
diff --git a/Example/Database/App/tvOS/AppDelegate.h b/Example/Database/App/tvOS/AppDelegate.h
new file mode 100644
index 0000000..013891c
--- /dev/null
+++ b/Example/Database/App/tvOS/AppDelegate.h
@@ -0,0 +1,21 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/Example/Database/App/tvOS/AppDelegate.m b/Example/Database/App/tvOS/AppDelegate.m
new file mode 100644
index 0000000..2e4e32f
--- /dev/null
+++ b/Example/Database/App/tvOS/AppDelegate.m
@@ -0,0 +1,59 @@
+// Copyright 2017 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 "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+ // Sent when the application is about to move from active to inactive state. This can occur for
+ // certain types of temporary interruptions (such as an incoming phone call or SMS message) or
+ // when the user quits the application and it begins the transition to the background state. Use
+ // this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates.
+ // Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ // Use this method to release shared resources, save user data, invalidate timers, and store
+ // enough application state information to restore your application to its current state in case
+ // it is terminated later. If your application supports background execution, this method is
+ // called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ // Called as part of the transition from the background to the active state; here you can undo
+ // many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If
+ // the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+ // Called when the application is about to terminate. Save data if appropriate. See also
+ // applicationDidEnterBackground:.
+}
+
+@end
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
new file mode 100644
index 0000000..b03ded1
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
@@ -0,0 +1,32 @@
+{
+ "assets" : [
+ {
+ "size" : "1280x768",
+ "idiom" : "tv",
+ "filename" : "App Icon - App Store.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "400x240",
+ "idiom" : "tv",
+ "filename" : "App Icon.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "2320x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image Wide.imageset",
+ "role" : "top-shelf-image-wide"
+ },
+ {
+ "size" : "1920x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image.imageset",
+ "role" : "top-shelf-image"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json b/Example/Database/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..d746a60
--- /dev/null
+++ b/Example/Database/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "11.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "9.0",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Database/App/tvOS/Info.plist b/Example/Database/App/tvOS/Info.plist
new file mode 100644
index 0000000..02942a3
--- /dev/null
+++ b/Example/Database/App/tvOS/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>arm64</string>
+ </array>
+ <key>UIUserInterfaceStyle</key>
+ <string>Automatic</string>
+</dict>
+</plist>
diff --git a/Example/Database/App/tvOS/Main.storyboard b/Example/Database/App/tvOS/Main.storyboard
new file mode 100644
index 0000000..72d5e22
--- /dev/null
+++ b/Example/Database/App/tvOS/Main.storyboard
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" systemVersion="17A278a" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+ <viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/Example/Database/App/tvOS/ViewController.h b/Example/Database/App/tvOS/ViewController.h
new file mode 100644
index 0000000..b6115b8
--- /dev/null
+++ b/Example/Database/App/tvOS/ViewController.h
@@ -0,0 +1,19 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+@end
diff --git a/Example/Database/App/tvOS/ViewController.m b/Example/Database/App/tvOS/ViewController.m
new file mode 100644
index 0000000..6d4676b
--- /dev/null
+++ b/Example/Database/App/tvOS/ViewController.m
@@ -0,0 +1,33 @@
+// Copyright 2017 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 "ViewController.h"
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/Example/Database/App/tvOS/main.m b/Example/Database/App/tvOS/main.m
new file mode 100644
index 0000000..d9e6654
--- /dev/null
+++ b/Example/Database/App/tvOS/main.m
@@ -0,0 +1,22 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj
index 489c588..9431ae0 100644
--- a/Example/Firebase.xcodeproj/project.pbxproj
+++ b/Example/Firebase.xcodeproj/project.pbxproj
@@ -49,10 +49,22 @@
name = AllUnitTests_iOS;
productName = AllTests;
};
+ DE545C7F1FBCA3F000C637AE /* AllUnitTests_tvOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = DE545C821FBCA3F000C637AE /* Build configuration list for PBXAggregateTarget "AllUnitTests_tvOS" */;
+ buildPhases = (
+ );
+ dependencies = (
+ DE545C881FBCA43200C637AE /* PBXTargetDependency */,
+ DE545C861FBCA42C00C637AE /* PBXTargetDependency */,
+ DE545C841FBCA41C00C637AE /* PBXTargetDependency */,
+ );
+ name = AllUnitTests_tvOS;
+ productName = AllUnitTests_tvOS;
+ };
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
- 01E863BD40D23087B77F2F03 /* Pods_Storage_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8E6527440C118AC7C21D504 /* Pods_Storage_Tests_iOS.framework */; };
0624F3EB1EC0ED0800E5940D /* FConnectionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB46F1EBA7AEF00038A59 /* FConnectionTest.m */; };
0624F3EC1EC0ED1B00E5940D /* FData.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4711EBA7AEF00038A59 /* FData.m */; };
0624F3ED1EC0ED2300E5940D /* FDotInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4731EBA7AEF00038A59 /* FDotInfo.m */; };
@@ -79,7 +91,6 @@
0637BA711EC0F9DD00CAEFD4 /* FTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D891E8EF202009EB6DF /* FTestHelpers.m */; };
0637BA721EC0F9E000CAEFD4 /* FTupleEventTypeString.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D8B1E8EF203009EB6DF /* FTupleEventTypeString.m */; };
0637BA731EC0F9E400CAEFD4 /* SenTest+FWaiter.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D8D1E8EF203009EB6DF /* SenTest+FWaiter.m */; };
- 063825B4D58274CB24B25FF1 /* Pods_Storage_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F27F07800D6FD739BD094D3 /* Pods_Storage_Example_macOS.framework */; };
063CB4A71EBA7B0B00038A59 /* FCompoundWriteTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB46E1EBA7AEF00038A59 /* FCompoundWriteTest.m */; };
063CB4BE1EBA7B3100038A59 /* FIRDataSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB47B1EBA7AEF00038A59 /* FIRDataSnapshotTests.m */; };
063CB4BF1EBA7B3100038A59 /* FIRFakeApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB47E1EBA7AEF00038A59 /* FIRFakeApp.m */; };
@@ -105,30 +116,30 @@
0672F2F31EBBA7D900818E87 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0672F2F11EBBA7D900818E87 /* GoogleService-Info.plist */; };
069428831EC3B38C00F7BC69 /* 1mb.dat in Resources */ = {isa = PBXBuildFile; fileRef = 069428801EC3B35A00F7BC69 /* 1mb.dat */; };
06C24A061EC39BCB005208CA /* FIRStorageIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 06121ECA1EC39A0B0008D70E /* FIRStorageIntegrationTests.m */; };
- 0C1D425E4DA4FBFD5A08B985 /* Pods_Auth_Sample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D837E35351C0B844EA64B959 /* Pods_Auth_Sample.framework */; };
- 1A509E710C83B6D0A6CD286D /* Pods_Core_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68657030253DE5895E124F45 /* Pods_Core_Example_iOS.framework */; };
- 29136BCA0AD59481B07CFBB0 /* Pods_Core_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 86062A14985F49A3B99614A7 /* Pods_Core_Tests_macOS.framework */; };
- 2C8B39CFF9898AE4B29AD114 /* Pods_Auth_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1015568683E2DFCC2719C754 /* Pods_Auth_Tests_macOS.framework */; };
- 2ECC6F80E47D2646FA82B940 /* Pods_Messaging_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CCB3CEB7BF2E4994FBDB2E7 /* Pods_Messaging_Tests_iOS.framework */; };
- 431EBDD6071EF1AE6F6DBE5F /* Pods_Core_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C51650773603D9F827CB3F /* Pods_Core_Example_macOS.framework */; };
- 5207C8D12B9830DADB85FE67 /* Pods_Auth_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ABC4448E5917769098A4EEF /* Pods_Auth_Tests_iOS.framework */; };
- 529BBEFBB6D7A3653B6B3874 /* Pods_Storage_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 910D7A5DE7D5AF153328D243 /* Pods_Storage_Tests_macOS.framework */; };
- 53C9FD19788281F65D537548 /* Pods_Analytics_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29606A0F0B0782779D4E73A1 /* Pods_Analytics_Tests_iOS.framework */; };
- 6232ED3272E9C78C2A0E127F /* Pods_Storage_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 979DF124E3D1146A81188F78 /* Pods_Storage_IntegrationTests_iOS.framework */; };
- 67EA2F675D33B39CEB0D41B1 /* Pods_Auth_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4373FD322206E44A7CADC2A8 /* Pods_Auth_Example_iOS.framework */; };
- 6ADAC4BEBCE37253D2D7A50F /* Pods_Database_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4852BF989C85671F5D7EBD2A /* Pods_Database_Tests_iOS.framework */; };
- 6D6FA69218AB107C266E1B70 /* Pods_Auth_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7A35264721D3C8D9F96F91C /* Pods_Auth_Example_macOS.framework */; };
- 7CA435AB1A753CC9EEDFA648 /* Pods_Database_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE9C3D75207E5D1DC70BB364 /* Pods_Database_Tests_macOS.framework */; };
+ 0DADD37DFD4D9DC368B72DF8 /* Pods_Auth_ApiTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33C0463B7313FC8E23E5DAAD /* Pods_Auth_ApiTests.framework */; };
+ 2046226C96706813FEE60FAA /* Pods_Core_Example_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E9BD713FA8E0DDA1C631EFA7 /* Pods_Core_Example_tvOS.framework */; };
+ 284F39A3FED7FC1457A20DA3 /* Pods_Core_Tests_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 092A0E9B0100EB5D1592AD68 /* Pods_Core_Tests_tvOS.framework */; };
+ 2C61352BC0FA096866E11A13 /* Pods_Storage_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5656210C04D3CE12EDEC3A00 /* Pods_Storage_Example_macOS.framework */; };
+ 2EE6D7190CA87B2514217B5F /* Pods_Analytics_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48EC844B9B5B226AB409C04D /* Pods_Analytics_Tests_iOS.framework */; };
+ 2FFD1B3D1BD1A79B3EBCE10B /* Pods_Database_IntegrationTests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2FFB14744FBF59F4E89FE0F /* Pods_Database_IntegrationTests_macOS.framework */; };
+ 305C6268DB5BF4653F4843D6 /* Pods_Auth_SwiftSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E0B3F6C29D6072C4CD9665AD /* Pods_Auth_SwiftSample.framework */; };
+ 37CFACAA408191867DE00FEA /* Pods_Core_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48B19F642ED7795BE8C61702 /* Pods_Core_Tests_macOS.framework */; };
+ 451B83DCCB85173A0B5E15FB /* Pods_Database_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EC7975F05977AE75E90A12 /* Pods_Database_Example_macOS.framework */; };
+ 465CC1E7162634883C399206 /* Pods_Storage_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D89F11E328D414F78B66B2F2 /* Pods_Storage_IntegrationTests_iOS.framework */; };
+ 6462518AA418BF979F7ECD04 /* Pods_Messaging_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 984080F16FA41AF3AA9AD8C2 /* Pods_Messaging_Example_iOS.framework */; };
+ 66F5D2993433940E43128EFF /* Pods_Core_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6CD25911724B592A3988A50 /* Pods_Core_Tests_iOS.framework */; };
+ 7251EC9D9AA2AF1C7C6FFA27 /* Pods_Auth_Tests_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20AE8AA8E8EB8E0BEF84F161 /* Pods_Auth_Tests_tvOS.framework */; };
+ 77E3EE8071524513EE52506F /* Pods_Storage_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9D3351687EF7767B507F0E /* Pods_Storage_Tests_iOS.framework */; };
+ 77FC21C5B8BB3E10497C9893 /* Pods_Storage_Example_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBC238B93690B48A560707ED /* Pods_Storage_Example_tvOS.framework */; };
+ 7B6F7B081BE6A56CF0AE20F5 /* Pods_Storage_Tests_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B4F4F14C797493D606A23A8 /* Pods_Storage_Tests_tvOS.framework */; };
+ 7E26CF28514D041D284F00A5 /* Pods_Database_Tests_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5318F3AE32EEBCC9FF608813 /* Pods_Database_Tests_tvOS.framework */; };
+ 7E5BD38D202BFB8CD9CCEB53 /* Pods_Auth_EarlGreyTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FAA82401DA4259800B142EA /* Pods_Auth_EarlGreyTests.framework */; };
7E9485421F578AC4005A3939 /* FIRAuthURLPresenterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E94853F1F578A9D005A3939 /* FIRAuthURLPresenterTests.m */; };
7EFA2E041F71C93300DD354F /* FIRUserMetadataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EFA2E031F71C93300DD354F /* FIRUserMetadataTests.m */; };
- 825BE4C9299DAB7EFEB19B65 /* Pods_Database_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66544F771D53687DD73F8BE8 /* Pods_Database_Example_iOS.framework */; };
- 8313C96352C6C77D481B5937 /* Pods_Messaging_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0C1478ED7269FF2107F5B6F /* Pods_Messaging_Example_iOS.framework */; };
- 8FC590E7FF7C561991DC9DD6 /* Pods_Auth_ApiTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93491C87A390AB737849677E /* Pods_Auth_ApiTests.framework */; };
- 91BECF25F64620DEDF99A106 /* Pods_Storage_IntegrationTests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A28B39B3D707677EF59C110 /* Pods_Storage_IntegrationTests_macOS.framework */; };
- 930570CF84207AEB98440760 /* Pods_Auth_SwiftSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0C52364C5FCE5D3FBAEAF83 /* Pods_Auth_SwiftSample.framework */; };
- 9CD1CAC2BC2C39B755F7BF88 /* Pods_Storage_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3742438A60FCFAAF24CDE751 /* Pods_Storage_Example_iOS.framework */; };
- A553FD534066F62EE74F2D51 /* Pods_Database_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CF25C495716B3441849720B /* Pods_Database_Example_macOS.framework */; };
- ABA730C3E77B260C564C288A /* Pods_Core_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B9B568851BEE22B7FCB61FB /* Pods_Core_Tests_iOS.framework */; };
+ 7F41B0EFBDDA90CB9CE6CE5B /* Pods_Database_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61377AC9FE132A8D7BF71881 /* Pods_Database_Tests_macOS.framework */; };
+ 822CE316AE9827F7F0889B30 /* Pods_Auth_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9878B57CF73D2F865992E6EA /* Pods_Auth_Example_macOS.framework */; };
+ 91A0BCD9A296439CB7E7843C /* Pods_Core_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA298A99D536B60732EBCB7D /* Pods_Core_Example_macOS.framework */; };
+ A3C94871F590440BE6DDEBDB /* Pods_Database_Example_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 483A1D5066DE4B7EF0B8BF52 /* Pods_Database_Example_tvOS.framework */; };
AFAF36F51EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
AFAF36F61EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
AFAF36F71EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
@@ -141,7 +152,12 @@
AFD5630F1EB1402300EA2233 /* MessagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD563011EB13DF200EA2233 /* MessagingViewController.swift */; };
AFD563151EB29EDE00EA2233 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = AFD563131EB1466100EA2233 /* GoogleService-Info.plist */; };
AFD563171EBBEF7B00EA2233 /* Data+MessagingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD563161EBBEF7B00EA2233 /* Data+MessagingExtensions.swift */; };
- CD4DB22A28941C5FEE70686A /* Pods_Auth_EarlGreyTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDE126A5F0AFCA9956A4C5D9 /* Pods_Auth_EarlGreyTests.framework */; };
+ B1FF92C04BA1E704C11B0467 /* Pods_Auth_Example_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4384273DF1B662E4CE522BAF /* Pods_Auth_Example_tvOS.framework */; };
+ BB2055D8C835CBDABB419B1C /* Pods_Storage_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DFCD819598D37C1AD6F7D601 /* Pods_Storage_Example_iOS.framework */; };
+ BBFDB50D4B4632DF9A32B305 /* Pods_Core_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94427D25FE9C3A26EF1A8ABE /* Pods_Core_Example_iOS.framework */; };
+ BD84035FA14A8647DCB7AEE7 /* Pods_Database_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CCF6BD7264693FD98E10850 /* Pods_Database_Tests_iOS.framework */; };
+ C344068A9C3B2487279AB0BC /* Pods_Auth_Sample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACEE1E8A4E9B9D4455A09AB /* Pods_Auth_Sample.framework */; };
+ C521E0D6D9027DB7B2254B19 /* Pods_Storage_IntegrationTests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 249A92EF1ADB4E2186F9F788 /* Pods_Storage_IntegrationTests_macOS.framework */; };
D018534D1EDACED4003A645C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D01853491EDACED4003A645C /* LaunchScreen.storyboard */; };
D018534E1EDACED4003A645C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D018534B1EDACED4003A645C /* Main.storyboard */; };
D01853721EDAD084003A645C /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
@@ -199,6 +215,13 @@
D064E6B51ED9B31C001956DF /* FIRTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D7C1E844677006FA992 /* FIRTestCase.m */; };
D067EF831ED9BDE00095C27F /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
D067EF841ED9BDFF0095C27F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DEE14D711E844677006FA992 /* GoogleService-Info.plist */; };
+ D09005311EDB32D600154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
+ D09005331EDB32F100154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
+ D09005351EDB330E00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
+ D09005371EDB331C00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
+ D09005391EDB333A00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
+ D090053B1EDB334400154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
+ D090053D1EDB334D00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */; settings = {ATTRIBUTES = (); }; };
D0EDB2C51EDA04F800B6C31B /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; };
D0EDB2D71EDA057800B6C31B /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDB2D21EDA056A00B6C31B /* FIRAppDelegate.m */; };
D0EDB2D81EDA057800B6C31B /* FIRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D0EDB2D41EDA056A00B6C31B /* FIRViewController.m */; };
@@ -284,15 +307,29 @@
D0FE8A941ED9CAAE003F6722 /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FE8A1A1ED9C6D2003F6722 /* FIRAppDelegate.m */; };
D0FE8A951ED9CAAE003F6722 /* FIRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FE8A1C1ED9C6D2003F6722 /* FIRViewController.m */; };
D0FE8A961ED9CAAE003F6722 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FE8A1D1ED9C6D2003F6722 /* main.m */; };
+ D5DA1D0CD1B4A2D08B5296D6 /* Pods_Database_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1113F1AFA1EFE58780FE9294 /* Pods_Database_IntegrationTests_iOS.framework */; };
+ D8C9C50E6CF043E74755973F /* Pods_Storage_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A635330E6EB5E285D878626B /* Pods_Storage_Tests_macOS.framework */; };
D9B0D41E1F578F6D00A567C2 /* FIRGetProjectConfigRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D92C82C61F578DF000D5EAFF /* FIRGetProjectConfigRequestTests.m */; };
D9B0D41F1F578F6E00A567C2 /* FIRGetProjectConfigRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D92C82C61F578DF000D5EAFF /* FIRGetProjectConfigRequestTests.m */; };
D9B0D4201F578F7200A567C2 /* FIRGetProjectConfigResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D92C82C51F578DF000D5EAFF /* FIRGetProjectConfigResponseTests.m */; };
D9B0D4211F578F7300A567C2 /* FIRGetProjectConfigResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D92C82C51F578DF000D5EAFF /* FIRGetProjectConfigResponseTests.m */; };
- DA464BCB6574F7FE299CB48D /* Pods_Database_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DFC35EAB61A983056BE25D28 /* Pods_Database_IntegrationTests_iOS.framework */; };
+ DDAA23BBAF5FA178E01D89B6 /* Pods_Database_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F2C1255ABA57AFDFD587103 /* Pods_Database_Example_iOS.framework */; };
DE0E5BBB1EA7D92E00FAA825 /* FIRVerifyClientRequestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE0E5BB91EA7D92E00FAA825 /* FIRVerifyClientRequestTest.m */; };
DE0E5BBC1EA7D92E00FAA825 /* FIRVerifyClientResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE0E5BBA1EA7D92E00FAA825 /* FIRVerifyClientResponseTests.m */; };
DE0E5BBD1EA7D93100FAA825 /* FIRAuthAppCredentialTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE0E5BB51EA7D91C00FAA825 /* FIRAuthAppCredentialTests.m */; };
DE0E5BBE1EA7D93500FAA825 /* FIRAuthAppDelegateProxyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE0E5BB61EA7D91C00FAA825 /* FIRAuthAppDelegateProxyTests.m */; };
+ DE1EC2921FBA5EB5007D18D8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DE1EC28B1FBA5EB5007D18D8 /* AppDelegate.m */; };
+ DE1EC2931FBA5EB5007D18D8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE1EC28C1FBA5EB5007D18D8 /* Assets.xcassets */; };
+ DE1EC2951FBA5EB5007D18D8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DE1EC28E1FBA5EB5007D18D8 /* main.m */; };
+ DE1EC2961FBA5EB5007D18D8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE1EC28F1FBA5EB5007D18D8 /* Main.storyboard */; };
+ DE1EC2971FBA5EB5007D18D8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE1EC2911FBA5EB5007D18D8 /* ViewController.m */; };
+ DE1FAEB11FBCF60D00897AAA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DE53894D1FBB635400199FC2 /* AppDelegate.m */; };
+ DE1FAEB21FBCF60D00897AAA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DE5389501FBB635400199FC2 /* main.m */; };
+ DE1FAEB31FBCF60D00897AAA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE5389531FBB635400199FC2 /* ViewController.m */; };
+ DE1FAEB41FBCF60D00897AAA /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DE53894F1FBB635400199FC2 /* Info.plist */; };
+ DE1FAEB51FBCF60D00897AAA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE5389511FBB635400199FC2 /* Main.storyboard */; };
+ DE1FAEB61FBCF60D00897AAA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE53894E1FBB635400199FC2 /* Assets.xcassets */; };
+ DE1FAEB71FBCF6CA00897AAA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DE9314F61E86C6FF0083EDBF /* GoogleService-Info.plist */; };
DE26D20E1F70333E004AE1D3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DE26D1DA1F70333E004AE1D3 /* Localizable.strings */; };
DE26D2131F70333E004AE1D3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE26D1E41F70333E004AE1D3 /* Images.xcassets */; };
DE26D2441F7039BC004AE1D3 /* ApplicationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DE26D1D01F70333E004AE1D3 /* ApplicationDelegate.m */; };
@@ -346,6 +383,40 @@
DE7B8DCC1E8EF23A009EB6DF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D371E8EF202009EB6DF /* main.m */; };
DE7B8DD01E8EF246009EB6DF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE7B8D2C1E8EF202009EB6DF /* LaunchScreen.storyboard */; };
DE7B8DD11E8EF24F009EB6DF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE7B8D2E1E8EF202009EB6DF /* Main.storyboard */; };
+ DE9037291FBA5F2400E239D3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0672F2F11EBBA7D900818E87 /* GoogleService-Info.plist */; };
+ DE90372A1FBA5F8F00E239D3 /* FArraySortedDictionaryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4471EBA7AE200038A59 /* FArraySortedDictionaryTest.m */; };
+ DE90372B1FBA5F8F00E239D3 /* FCompoundHashTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4481EBA7AE200038A59 /* FCompoundHashTest.m */; };
+ DE90372C1FBA5F8F00E239D3 /* FCompoundWriteTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB46E1EBA7AEF00038A59 /* FCompoundWriteTest.m */; };
+ DE90372D1FBA5F8F00E239D3 /* FIRDataSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB47B1EBA7AEF00038A59 /* FIRDataSnapshotTests.m */; };
+ DE90372E1FBA5F8F00E239D3 /* FIRMutableDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB44A1EBA7AE200038A59 /* FIRMutableDataTests.m */; };
+ DE90372F1FBA5F8F00E239D3 /* FLevelDBStorageEngineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB44B1EBA7AE200038A59 /* FLevelDBStorageEngineTests.m */; };
+ DE9037301FBA5F8F00E239D3 /* FNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB44C1EBA7AE200038A59 /* FNodeTests.m */; };
+ DE9037311FBA5F8F00E239D3 /* FPathTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB44E1EBA7AE200038A59 /* FPathTests.m */; };
+ DE9037321FBA5F8F00E239D3 /* FPersistenceManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB44F1EBA7AE200038A59 /* FPersistenceManagerTest.m */; };
+ DE9037331FBA5F8F00E239D3 /* FPruneForestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4501EBA7AE200038A59 /* FPruneForestTest.m */; };
+ DE9037341FBA5F8F00E239D3 /* FPruningTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4511EBA7AE200038A59 /* FPruningTest.m */; };
+ DE9037351FBA5F8F00E239D3 /* FQueryParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4521EBA7AE200038A59 /* FQueryParamsTest.m */; };
+ DE9037361FBA5F8F00E239D3 /* FRangeMergeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4531EBA7AE200038A59 /* FRangeMergeTest.m */; };
+ DE9037371FBA5F8F00E239D3 /* FRepoInfoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4541EBA7AE200038A59 /* FRepoInfoTest.m */; };
+ DE9037381FBA5F8F00E239D3 /* FSparseSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4561EBA7AE200038A59 /* FSparseSnapshotTests.m */; };
+ DE9037391FBA5F8F00E239D3 /* FSyncPointTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4581EBA7AE200038A59 /* FSyncPointTests.m */; };
+ DE90373A1FBA5F8F00E239D3 /* FTrackedQueryManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB45B1EBA7AE200038A59 /* FTrackedQueryManagerTest.m */; };
+ DE90373B1FBA5F8F00E239D3 /* FTreeSortedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB4901EBA7AEF00038A59 /* FTreeSortedDictionaryTests.m */; };
+ DE90373C1FBA5F8F00E239D3 /* FUtilitiesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB45C1EBA7AE200038A59 /* FUtilitiesTest.m */; };
+ DE90373F1FBA675D00E239D3 /* FDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D791E8EF202009EB6DF /* FDevice.m */; };
+ DE9037401FBA675D00E239D3 /* FEventTester.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D7B1E8EF202009EB6DF /* FEventTester.m */; };
+ DE9037411FBA675D00E239D3 /* FIRFakeApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB47E1EBA7AEF00038A59 /* FIRFakeApp.m */; };
+ DE9037421FBA675D00E239D3 /* FIRTestAuthTokenProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D7D1E8EF202009EB6DF /* FIRTestAuthTokenProvider.m */; };
+ DE9037431FBA675D00E239D3 /* FMockStorageEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D7F1E8EF202009EB6DF /* FMockStorageEngine.m */; };
+ DE9037441FBA675D00E239D3 /* FTestAuthTokenGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D811E8EF202009EB6DF /* FTestAuthTokenGenerator.m */; };
+ DE9037451FBA675D00E239D3 /* FTestBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 063CB45A1EBA7AE200038A59 /* FTestBase.m */; };
+ DE9037461FBA675D00E239D3 /* FTestCachePolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D831E8EF202009EB6DF /* FTestCachePolicy.m */; };
+ DE9037471FBA675D00E239D3 /* FTestClock.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D851E8EF202009EB6DF /* FTestClock.m */; };
+ DE9037481FBA675D00E239D3 /* FTestExpectations.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D871E8EF202009EB6DF /* FTestExpectations.m */; };
+ DE9037491FBA675D00E239D3 /* FTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D891E8EF202009EB6DF /* FTestHelpers.m */; };
+ DE90374A1FBA675D00E239D3 /* FTupleEventTypeString.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D8B1E8EF203009EB6DF /* FTupleEventTypeString.m */; };
+ DE90374B1FBA675D00E239D3 /* SenTest+FWaiter.m in Sources */ = {isa = PBXBuildFile; fileRef = DE7B8D8D1E8EF203009EB6DF /* SenTest+FWaiter.m */; };
+ DE90374D1FBA70E400E239D3 /* syncPointSpec.json in Resources */ = {isa = PBXBuildFile; fileRef = DE7B8D8E1E8EF203009EB6DF /* syncPointSpec.json */; };
DE9315261E86C6FF0083EDBF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE9314ED1E86C6FF0083EDBF /* LaunchScreen.storyboard */; };
DE9315271E86C6FF0083EDBF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE9314EF1E86C6FF0083EDBF /* Main.storyboard */; };
DE9315291E86C6FF0083EDBF /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9314F31E86C6FF0083EDBF /* FIRAppDelegate.m */; };
@@ -409,6 +480,36 @@
DE9316031E8738E60083EDBF /* FIRMessagingSyncMessageManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315D41E8738B70083EDBF /* FIRMessagingSyncMessageManagerTest.m */; };
DE9316041E8738E60083EDBF /* FIRMessagingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315D51E8738B70083EDBF /* FIRMessagingTest.m */; };
DE9316051E8738E60083EDBF /* FIRMessagingTestNotificationUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315D71E8738B70083EDBF /* FIRMessagingTestNotificationUtilities.m */; };
+ DEAAD3C31FBA1CD90053BF48 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD3BD1FBA1CD80053BF48 /* main.m */; };
+ DEAAD3CE1FBA1EFA0053BF48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DEAAD3C51FBA1EF90053BF48 /* Assets.xcassets */; };
+ DEAAD3CF1FBA1EFA0053BF48 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD3C81FBA1EFA0053BF48 /* AppDelegate.m */; };
+ DEAAD3D01FBA1EFA0053BF48 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD3C91FBA1EFA0053BF48 /* ViewController.m */; };
+ DEAAD3D41FBA20480053BF48 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DEAAD3D21FBA1F850053BF48 /* Main.storyboard */; };
+ DEAAD3D51FBA34250053BF48 /* FIRAppAssociationRegistrationUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D751E844677006FA992 /* FIRAppAssociationRegistrationUnitTests.m */; };
+ DEAAD3D61FBA34250053BF48 /* FIRAppTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D761E844677006FA992 /* FIRAppTest.m */; };
+ DEAAD3D71FBA34250053BF48 /* FIRBundleUtilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D771E844677006FA992 /* FIRBundleUtilTest.m */; };
+ DEAAD3D81FBA34250053BF48 /* FIRConfigurationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D781E844677006FA992 /* FIRConfigurationTest.m */; };
+ DEAAD3D91FBA34250053BF48 /* FIRLoggerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D791E844677006FA992 /* FIRLoggerTest.m */; };
+ DEAAD3DA1FBA34250053BF48 /* FIROptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D7A1E844677006FA992 /* FIROptionsTest.m */; };
+ DEAAD3DB1FBA34250053BF48 /* FIRTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D7C1E844677006FA992 /* FIRTestCase.m */; };
+ DEAAD3DC1FBA36210053BF48 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DEE14D711E844677006FA992 /* GoogleService-Info.plist */; };
+ DEAAD41A1FBA470B0053BF48 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD4131FBA470A0053BF48 /* AppDelegate.m */; };
+ DEAAD41B1FBA470B0053BF48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DEAAD4141FBA470A0053BF48 /* Assets.xcassets */; };
+ DEAAD41D1FBA470B0053BF48 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD4161FBA470A0053BF48 /* main.m */; };
+ DEAAD41E1FBA470B0053BF48 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DEAAD4171FBA470A0053BF48 /* Main.storyboard */; };
+ DEAAD41F1FBA470B0053BF48 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DEAAD4191FBA470A0053BF48 /* ViewController.m */; };
+ DEAAD4201FBA47110053BF48 /* 1mb.dat in Resources */ = {isa = PBXBuildFile; fileRef = 069428801EC3B35A00F7BC69 /* 1mb.dat */; };
+ DEAAD4211FBA49D10053BF48 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DEB61EC11E7C5DBB00C04B96 /* GoogleService-Info.plist */; };
+ DEAAD4221FBA49ED0053BF48 /* FIRStorageDeleteTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C11E734D9D00AC236D /* FIRStorageDeleteTests.m */; };
+ DEAAD4231FBA49ED0053BF48 /* FIRStorageGetMetadataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C21E734D9D00AC236D /* FIRStorageGetMetadataTests.m */; };
+ DEAAD4241FBA49ED0053BF48 /* FIRStorageMetadataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C31E734D9D00AC236D /* FIRStorageMetadataTests.m */; };
+ DEAAD4251FBA49ED0053BF48 /* FIRStoragePathTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C41E734D9D00AC236D /* FIRStoragePathTests.m */; };
+ DEAAD4261FBA49ED0053BF48 /* FIRStorageReferenceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C51E734D9D00AC236D /* FIRStorageReferenceTests.m */; };
+ DEAAD4271FBA49ED0053BF48 /* FIRStorageTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C71E734D9D00AC236D /* FIRStorageTestHelpers.m */; };
+ DEAAD4281FBA49ED0053BF48 /* FIRStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C81E734D9D00AC236D /* FIRStorageTests.m */; };
+ DEAAD4291FBA49ED0053BF48 /* FIRStorageTokenAuthorizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139C91E734D9D00AC236D /* FIRStorageTokenAuthorizerTests.m */; };
+ DEAAD42A1FBA49ED0053BF48 /* FIRStorageUpdateMetadataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139CA1E734D9D00AC236D /* FIRStorageUpdateMetadataTests.m */; };
+ DEAAD42B1FBA49ED0053BF48 /* FIRStorageUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB139CB1E734D9D00AC236D /* FIRStorageUtilsTests.m */; };
DEB139F41E73506A00AC236D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
DEB139F51E73506A00AC236D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
DEB139F61E73506A00AC236D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
@@ -446,7 +547,52 @@
DEE14D941E84468D006FA992 /* FIRTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE14D7C1E844677006FA992 /* FIRTestCase.m */; };
DEF288411F9AB6E100D480CF /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DEF288401F9AB6E100D480CF /* Default-568h@2x.png */; };
DEF288421F9AB6E100D480CF /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DEF288401F9AB6E100D480CF /* Default-568h@2x.png */; };
- FF33B94B3A34331129E4E4D5 /* Pods_Database_IntegrationTests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81C1ABDD7BB039B4BF06A29E /* Pods_Database_IntegrationTests_macOS.framework */; };
+ DEF6C30D1FBCE72F005D0740 /* FIRAuthDispatcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9314FF1E86C6FF0083EDBF /* FIRAuthDispatcherTests.m */; };
+ DEF6C30F1FBCE775005D0740 /* FIRAdditionalUserInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9314FA1E86C6FF0083EDBF /* FIRAdditionalUserInfoTests.m */; };
+ DEF6C3101FBCE775005D0740 /* FIRApp+FIRAuthUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9314FC1E86C6FF0083EDBF /* FIRApp+FIRAuthUnitTests.m */; };
+ DEF6C3121FBCE775005D0740 /* FIRAuthAPNSTokenTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE750DB61EB3DD4000A75E47 /* FIRAuthAPNSTokenTests.m */; };
+ DEF6C3131FBCE775005D0740 /* FIRAuthAppCredentialManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE750DB71EB3DD4000A75E47 /* FIRAuthAppCredentialManagerTests.m */; };
+ DEF6C3141FBCE775005D0740 /* FIRAuthAppCredentialTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE0E5BB51EA7D91C00FAA825 /* FIRAuthAppCredentialTests.m */; };
+ DEF6C3161FBCE775005D0740 /* FIRAuthBackendCreateAuthURITests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9314FD1E86C6FF0083EDBF /* FIRAuthBackendCreateAuthURITests.m */; };
+ DEF6C3171FBCE775005D0740 /* FIRAuthBackendRPCImplementationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9314FE1E86C6FF0083EDBF /* FIRAuthBackendRPCImplementationTests.m */; };
+ DEF6C3181FBCE775005D0740 /* FIRAuthGlobalWorkQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315001E86C6FF0083EDBF /* FIRAuthGlobalWorkQueueTests.m */; };
+ DEF6C3191FBCE775005D0740 /* FIRAuthKeychainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315011E86C6FF0083EDBF /* FIRAuthKeychainTests.m */; };
+ DEF6C31A1FBCE775005D0740 /* FIRAuthNotificationManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE750DB81EB3DD4000A75E47 /* FIRAuthNotificationManagerTests.m */; };
+ DEF6C31B1FBCE775005D0740 /* FIRAuthSerialTaskQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315021E86C6FF0083EDBF /* FIRAuthSerialTaskQueueTests.m */; };
+ DEF6C31C1FBCE775005D0740 /* FIRAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315031E86C6FF0083EDBF /* FIRAuthTests.m */; };
+ DEF6C31E1FBCE775005D0740 /* FIRAuthUserDefaultsStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315041E86C6FF0083EDBF /* FIRAuthUserDefaultsStorageTests.m */; };
+ DEF6C31F1FBCE775005D0740 /* FIRCreateAuthURIRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315051E86C6FF0083EDBF /* FIRCreateAuthURIRequestTests.m */; };
+ DEF6C3201FBCE775005D0740 /* FIRCreateAuthURIResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315061E86C6FF0083EDBF /* FIRCreateAuthURIResponseTests.m */; };
+ DEF6C3211FBCE775005D0740 /* FIRDeleteAccountRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315071E86C6FF0083EDBF /* FIRDeleteAccountRequestTests.m */; };
+ DEF6C3221FBCE775005D0740 /* FIRDeleteAccountResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315081E86C6FF0083EDBF /* FIRDeleteAccountResponseTests.m */; };
+ DEF6C3231FBCE775005D0740 /* FIRFakeBackendRPCIssuer.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93150A1E86C6FF0083EDBF /* FIRFakeBackendRPCIssuer.m */; };
+ DEF6C3241FBCE775005D0740 /* FIRGetAccountInfoRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93150B1E86C6FF0083EDBF /* FIRGetAccountInfoRequestTests.m */; };
+ DEF6C3251FBCE775005D0740 /* FIRGetAccountInfoResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93150C1E86C6FF0083EDBF /* FIRGetAccountInfoResponseTests.m */; };
+ DEF6C3261FBCE775005D0740 /* FIRGetOOBConfirmationCodeRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93150D1E86C6FF0083EDBF /* FIRGetOOBConfirmationCodeRequestTests.m */; };
+ DEF6C3271FBCE775005D0740 /* FIRGetOOBConfirmationCodeResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93150E1E86C6FF0083EDBF /* FIRGetOOBConfirmationCodeResponseTests.m */; };
+ DEF6C3281FBCE775005D0740 /* FIRGetProjectConfigRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D92C82C61F578DF000D5EAFF /* FIRGetProjectConfigRequestTests.m */; };
+ DEF6C3291FBCE775005D0740 /* FIRGetProjectConfigResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D92C82C51F578DF000D5EAFF /* FIRGetProjectConfigResponseTests.m */; };
+ DEF6C32A1FBCE775005D0740 /* FIRGitHubAuthProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93150F1E86C6FF0083EDBF /* FIRGitHubAuthProviderTests.m */; };
+ DEF6C32C1FBCE775005D0740 /* FIRResetPasswordRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315111E86C6FF0083EDBF /* FIRResetPasswordRequestTests.m */; };
+ DEF6C32D1FBCE775005D0740 /* FIRResetPasswordResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315121E86C6FF0083EDBF /* FIRResetPasswordResponseTests.m */; };
+ DEF6C3301FBCE775005D0740 /* FIRSetAccountInfoRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315151E86C6FF0083EDBF /* FIRSetAccountInfoRequestTests.m */; };
+ DEF6C3311FBCE775005D0740 /* FIRSetAccountInfoResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315161E86C6FF0083EDBF /* FIRSetAccountInfoResponseTests.m */; };
+ DEF6C3321FBCE775005D0740 /* FIRSignUpNewUserRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315171E86C6FF0083EDBF /* FIRSignUpNewUserRequestTests.m */; };
+ DEF6C3331FBCE775005D0740 /* FIRSignUpNewUserResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315181E86C6FF0083EDBF /* FIRSignUpNewUserResponseTests.m */; };
+ DEF6C3341FBCE775005D0740 /* FIRTwitterAuthProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315191E86C6FF0083EDBF /* FIRTwitterAuthProviderTests.m */; };
+ DEF6C3351FBCE775005D0740 /* FIRUserMetadataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EFA2E031F71C93300DD354F /* FIRUserMetadataTests.m */; };
+ DEF6C3361FBCE775005D0740 /* FIRUserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151A1E86C6FF0083EDBF /* FIRUserTests.m */; };
+ DEF6C3371FBCE775005D0740 /* FIRVerifyAssertionRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151B1E86C6FF0083EDBF /* FIRVerifyAssertionRequestTests.m */; };
+ DEF6C3381FBCE775005D0740 /* FIRVerifyAssertionResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151C1E86C6FF0083EDBF /* FIRVerifyAssertionResponseTests.m */; };
+ DEF6C33B1FBCE775005D0740 /* FIRVerifyCustomTokenRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151D1E86C6FF0083EDBF /* FIRVerifyCustomTokenRequestTests.m */; };
+ DEF6C33C1FBCE775005D0740 /* FIRVerifyCustomTokenResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151E1E86C6FF0083EDBF /* FIRVerifyCustomTokenResponseTests.m */; };
+ DEF6C33D1FBCE775005D0740 /* FIRVerifyPasswordRequestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE93151F1E86C6FF0083EDBF /* FIRVerifyPasswordRequestTest.m */; };
+ DEF6C33E1FBCE775005D0740 /* FIRVerifyPasswordResponseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315201E86C6FF0083EDBF /* FIRVerifyPasswordResponseTests.m */; };
+ DEF6C3411FBCE775005D0740 /* OCMStubRecorder+FIRAuthUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE9315241E86C6FF0083EDBF /* OCMStubRecorder+FIRAuthUnitTests.m */; };
+ E0D25209B6EBC3F1C8902985 /* Pods_Auth_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F43E00CECD3298E770515E /* Pods_Auth_Example_iOS.framework */; };
+ E1AAE49ECC7CBAB74C290B25 /* Pods_Auth_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ECF3BF97E614E5E627B8AFF /* Pods_Auth_Tests_iOS.framework */; };
+ E3EE0971417119B44A7B6784 /* Pods_Messaging_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D1C7CFB87F3066712EF881B /* Pods_Messaging_Tests_iOS.framework */; };
+ ECBC321017C94478E9DCEB4E /* Pods_Auth_Tests_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B687E5985EC23880B5FB9C0 /* Pods_Auth_Tests_macOS.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -541,6 +687,20 @@
remoteGlobalIDString = D0FE8A1E1ED9C804003F6722;
remoteInfo = Database_Example_macOS;
};
+ DE1E3B301FEB1E7600EAEBB0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DE1FAE8F1FBCF5E100897AAA;
+ remoteInfo = Auth_Example_tvOS;
+ };
+ DE1EC2841FBA5E63007D18D8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DE1CD5961FBA55AF00FC031E;
+ remoteInfo = Database_Example_tvOS;
+ };
DE26D2621F7049F1004AE1D3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 6003F582195388D10070C39A /* Project object */;
@@ -583,6 +743,27 @@
remoteGlobalIDString = DEB13A0A1E73507E00AC236D;
remoteInfo = Storage_Tests_iOS;
};
+ DE545C831FBCA41C00C637AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DEAAD3941FBA11270053BF48;
+ remoteInfo = Core_Tests_tvOS;
+ };
+ DE545C851FBCA42C00C637AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DEAAD3F41FBA46AB0053BF48;
+ remoteInfo = Storage_Tests_tvOS;
+ };
+ DE545C871FBCA43200C637AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DE1EC27E1FBA5E63007D18D8;
+ remoteInfo = Database_Tests_tvOS;
+ };
DE6F01B91E957157004AEE01 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 6003F582195388D10070C39A /* Project object */;
@@ -611,6 +792,20 @@
remoteGlobalIDString = DE9314DD1E86C6BE0083EDBF;
remoteInfo = Auth_Tests_iOS;
};
+ DEAAD3961FBA11280053BF48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DEAAD3801FBA11270053BF48;
+ remoteInfo = Core_Example_tvOS;
+ };
+ DEAAD3F61FBA46AB0053BF48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6003F582195388D10070C39A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DEAAD3E01FBA46AA0053BF48;
+ remoteInfo = Storage_Example_tvOS;
+ };
DEB13A251E73512500AC236D /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 6003F582195388D10070C39A /* Project object */;
@@ -655,6 +850,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D09005311EDB32D600154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -664,6 +860,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D09005331EDB32F100154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -673,6 +870,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D09005351EDB330E00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -682,6 +880,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D09005371EDB331C00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -691,6 +890,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D09005391EDB333A00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -700,6 +900,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D090053B1EDB334400154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -709,14 +910,17 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
+ D090053D1EDB334D00154410 /* OCMock-iOS/OCMock.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 000DAC7D0D180A9FBB395BB6 /* Pods-Database_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 00BD45B2141C68C3F9809A4D /* Pods-Database_IntegrationTests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ 011545D4307696ABBF9658F2 /* Pods-Messaging_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 0118423DA26C4B44AEE1B9C1 /* Pods-Core_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ 01936C31BDE676F86CF8DA39 /* Pods-Auth_SwiftSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_SwiftSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample.debug.xcconfig"; sourceTree = "<group>"; };
+ 042AFA12FC20D0683FB59B9E /* Pods-Auth_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_tvOS/Pods-Auth_Tests_tvOS.release.xcconfig"; sourceTree = "<group>"; };
06121EBC1EC399C50008D70E /* Storage_IntegrationTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Storage_IntegrationTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
06121ECA1EC39A0B0008D70E /* FIRStorageIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRStorageIntegrationTests.m; sourceTree = "<group>"; };
0624F3E11EC0ECFA00E5940D /* Database_IntegrationTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Database_IntegrationTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -776,70 +980,83 @@
069428801EC3B35A00F7BC69 /* 1mb.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = 1mb.dat; sourceTree = "<group>"; };
0697B1201EC13D8A00542174 /* Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64.h; sourceTree = "<group>"; };
0697B1211EC13D8A00542174 /* Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Base64.m; sourceTree = "<group>"; };
- 09F55B0265DCD315B2DD3C2E /* Pods-Auth_ApiTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_ApiTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests.debug.xcconfig"; sourceTree = "<group>"; };
- 0ABC4448E5917769098A4EEF /* Pods_Auth_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 0C69403B9730C701BF2E0446 /* Pods-Auth_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 0CA98384DDFFEECB1D473552 /* Pods-Auth_SwiftSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_SwiftSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample.debug.xcconfig"; sourceTree = "<group>"; };
- 0D66D613C54F5BFF80D9AB63 /* Pods-Core_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 0DB176DCABEFDF6C19B302B0 /* Pods-Auth_EarlGreyTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_EarlGreyTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests.release.xcconfig"; sourceTree = "<group>"; };
- 1015568683E2DFCC2719C754 /* Pods_Auth_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 1068E64D36A3C656184168DE /* Pods-Database_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 1735157165B298F2A1EC36E3 /* Pods-Auth_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 1CCC00FFFC534F0E9B41CF29 /* Pods-Database_IntegrationTests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 1E6C076D38C1763E00A3DACA /* Pods-Core_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 20928A4E610E48E3EA4D9F4A /* Pods-Database_IntegrationTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 24B879B03BD82C7DE771CA61 /* Pods-Storage_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 287D8FC7F3129B28D8A29FBE /* Pods-Core_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
- 28B01131418E340D322829AC /* Pods-Auth_SwiftSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_SwiftSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample.release.xcconfig"; sourceTree = "<group>"; };
- 29606A0F0B0782779D4E73A1 /* Pods_Analytics_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Analytics_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 2B1B85CD0C7778447F3BFCD5 /* Pods-Database_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 2B3C652966760042D996247E /* Pods-Core_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 3742438A60FCFAAF24CDE751 /* Pods_Storage_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 3A304052F4122D3468145F6C /* Pods-Messaging_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 3B9B568851BEE22B7FCB61FB /* Pods_Core_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 3E26CB853AB2CAF1960A0F71 /* Pods-Storage_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 4373FD322206E44A7CADC2A8 /* Pods_Auth_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 456CD9478A63272C4397975E /* Pods-Analytics_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Analytics_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 46052D607615BD81295B65C6 /* Pods-Messaging_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 466C3694B6C68F69BA4DA448 /* Pods-Storage_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 48317719F315960780114559 /* Pods-Auth_Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample.debug.xcconfig"; sourceTree = "<group>"; };
- 4852BF989C85671F5D7EBD2A /* Pods_Database_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 4B490EFB675400675CA98196 /* Pods-Storage_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 4BF8EA84DF6AF0AB6E9BB6A0 /* Pods-Auth_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
- 4CC7C8B9E821151509BB3B64 /* Pods-Database_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
- 4D61AACC06F8E078EF051E4C /* Pods-Messaging_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 4ECAA105379B7E664C7FF223 /* Pods-Storage_IntegrationTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 5CA5A85B5A80F118F3247910 /* Pods-Storage_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 5DA6361D6B54362D073F3BA5 /* Pods-Database_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 06F3D16439F061DE9973902D /* Pods-Storage_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 0921DBEEC62AE8DCF318657D /* Pods-Core_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 092A0E9B0100EB5D1592AD68 /* Pods_Core_Tests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Tests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0B687E5985EC23880B5FB9C0 /* Pods_Auth_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0D4A8F333DE1D31AE14011D4 /* Pods-Auth_Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample.debug.xcconfig"; sourceTree = "<group>"; };
+ 0E086A7E5D54786963FBFC7D /* Pods-Auth_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 10C5FF4777A334F9F55ED95A /* Pods-Storage_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 1113F1AFA1EFE58780FE9294 /* Pods_Database_IntegrationTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_IntegrationTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 122B6EBA56EAB083239B83DE /* Pods-Auth_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 16182094A8A3749CA6D24429 /* Pods-Auth_EarlGreyTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_EarlGreyTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests.debug.xcconfig"; sourceTree = "<group>"; };
+ 1ACEE1E8A4E9B9D4455A09AB /* Pods_Auth_Sample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Sample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1D1C7CFB87F3066712EF881B /* Pods_Messaging_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Messaging_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1E5ECEF4C67573595335207D /* Pods-Auth_Example_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_tvOS/Pods-Auth_Example_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 1F2C1255ABA57AFDFD587103 /* Pods_Database_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1FAA82401DA4259800B142EA /* Pods_Auth_EarlGreyTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_EarlGreyTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 20AE8AA8E8EB8E0BEF84F161 /* Pods_Auth_Tests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Tests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 218DAA68383543E59864D4FA /* Pods-Storage_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 249A92EF1ADB4E2186F9F788 /* Pods_Storage_IntegrationTests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_IntegrationTests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2CCF6BD7264693FD98E10850 /* Pods_Database_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2DE182937C7CA58E63112FD2 /* Pods-Analytics_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Analytics_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 33C0463B7313FC8E23E5DAAD /* Pods_Auth_ApiTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_ApiTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 33C6BA3B4F6EEB1532A645E3 /* Pods-Database_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 37A2B647AFCDC9187D37529B /* Pods-Database_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_tvOS/Pods-Database_Tests_tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ 381D76A090B5EF6699CA3673 /* Pods-Database_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 39D965DC207D9E9C841AB1AF /* Pods-Auth_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 3A2BAC7CAFE05F790B1E34A1 /* Pods-Core_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 3B69D19E3FAF168C8EF37C81 /* Pods-Auth_Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample.release.xcconfig"; sourceTree = "<group>"; };
+ 3BDE00663D69912D5F2A7101 /* Pods-Storage_Tests_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_tvOS/Pods-Storage_Tests_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 3CF8F39CB220DE230DDAEC15 /* Pods-Database_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 4384273DF1B662E4CE522BAF /* Pods_Auth_Example_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Example_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 46EB9F652984D82936716B89 /* Pods-Auth_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 483A1D5066DE4B7EF0B8BF52 /* Pods_Database_Example_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Example_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 48B19F642ED7795BE8C61702 /* Pods_Core_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 48EC844B9B5B226AB409C04D /* Pods_Analytics_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Analytics_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4A7EFB64559F46B8A5FA288D /* Pods-Messaging_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 4CCB05296C6932B64AFBFB1A /* Pods-Database_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ 4ECF3BF97E614E5E627B8AFF /* Pods_Auth_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4F088699064170B6010B477A /* Pods-Storage_Example_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_tvOS/Pods-Storage_Example_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 5318F3AE32EEBCC9FF608813 /* Pods_Database_Tests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Tests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5656210C04D3CE12EDEC3A00 /* Pods_Storage_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 57876896413B7C97B317CCFD /* Pods-Storage_IntegrationTests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 5E0F451FE2DF377FEEE0C9CE /* Pods-Database_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 5FAFDE80DEFDE1EF5415939B /* Pods-Storage_IntegrationTests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS.release.xcconfig"; sourceTree = "<group>"; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
- 6029CD8D7E65D491083D5944 /* Pods-Auth_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 6098677E3698C58151DC2E85 /* Pods-Messaging_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 66544F771D53687DD73F8BE8 /* Pods_Database_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 68657030253DE5895E124F45 /* Pods_Core_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 6A28B39B3D707677EF59C110 /* Pods_Storage_IntegrationTests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_IntegrationTests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 6CCB3CEB7BF2E4994FBDB2E7 /* Pods_Messaging_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Messaging_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 6FD4B6DC35E3304CBECFEC61 /* Pods-Core_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 77FA2AB612D17244983008F7 /* Pods-Analytics_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Analytics_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 7879DCC8860E7CED0311D4E8 /* Pods-Database_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
- 7CF25C495716B3441849720B /* Pods_Database_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 61377AC9FE132A8D7BF71881 /* Pods_Database_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 63687A1F0EF54DDCBD13E4D4 /* Pods-Storage_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_tvOS/Pods-Storage_Tests_tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ 639B98AAF5AC93281CDF9DAF /* Pods-Database_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 66A4B7148EBB02E1A68EB8B0 /* Pods-Storage_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 692B433E797D83866B178F94 /* Pods-Storage_Example_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_tvOS/Pods-Storage_Example_tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ 6F9D3351687EF7767B507F0E /* Pods_Storage_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 70B04F7AEEC14B4E1E8C23D8 /* Pods-Auth_Tests_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_tvOS/Pods-Auth_Tests_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 72CFADA95DFD90718FDCFE19 /* Pods-Storage_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ 7981511F571E13DECA09B4B1 /* Pods-Core_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
7E94853F1F578A9D005A3939 /* FIRAuthURLPresenterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthURLPresenterTests.m; sourceTree = "<group>"; };
+ 7ED0DF69C095C21EFC81F672 /* Pods-Database_Example_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_tvOS/Pods-Database_Example_tvOS.release.xcconfig"; sourceTree = "<group>"; };
7EFA2E031F71C93300DD354F /* FIRUserMetadataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRUserMetadataTests.m; sourceTree = "<group>"; };
- 81C1ABDD7BB039B4BF06A29E /* Pods_Database_IntegrationTests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_IntegrationTests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8496034D8156555C5FCF8F14 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
- 84C51650773603D9F827CB3F /* Pods_Core_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 8602A8FB9AF04A0C9A8FE380 /* Pods-Auth_Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample.release.xcconfig"; sourceTree = "<group>"; };
- 86062A14985F49A3B99614A7 /* Pods_Core_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 86B8E0400070C72C0FE0C2F8 /* Pods-Database_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- 870F50EE08ED74C38B5CAF79 /* Pods-Core_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 8F27F07800D6FD739BD094D3 /* Pods_Storage_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 910D7A5DE7D5AF153328D243 /* Pods_Storage_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 93491C87A390AB737849677E /* Pods_Auth_ApiTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_ApiTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 94C0FA103316CB56F37E20EA /* Pods-Auth_EarlGreyTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_EarlGreyTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests.debug.xcconfig"; sourceTree = "<group>"; };
- 97790B1C788991008685954F /* Pods-Storage_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 979DF124E3D1146A81188F78 /* Pods_Storage_IntegrationTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_IntegrationTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- A8E6527440C118AC7C21D504 /* Pods_Storage_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 84EC7975F05977AE75E90A12 /* Pods_Database_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 86E271316861BA45BD9370FC /* Pods-Core_Example_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_tvOS/Pods-Core_Example_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 885461BA75A5FE1BF1CBC992 /* Pods-Database_IntegrationTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 8AB8C5932B72C705E2EBCF1B /* Pods-Auth_EarlGreyTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_EarlGreyTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests.release.xcconfig"; sourceTree = "<group>"; };
+ 91D2A751787B7FDD624919EB /* Pods-Auth_SwiftSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_SwiftSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample.release.xcconfig"; sourceTree = "<group>"; };
+ 920F3E71E6698FEADDA9D37A /* Pods-Analytics_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Analytics_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 94427D25FE9C3A26EF1A8ABE /* Pods_Core_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 984080F16FA41AF3AA9AD8C2 /* Pods_Messaging_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Messaging_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9878B57CF73D2F865992E6EA /* Pods_Auth_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 99BF1D5FC3F0CC27D845BCDE /* Pods-Messaging_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ 9B2AAD4EC2BD3FBC053CBD2A /* Pods-Auth_Example_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_tvOS/Pods-Auth_Example_tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ 9B4F4F14C797493D606A23A8 /* Pods_Storage_Tests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Tests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9E042E6047B5B5D409AD083F /* Pods-Auth_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ A1F43E00CECD3298E770515E /* Pods_Auth_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ A2339EEA1F050084D3214753 /* Pods-Storage_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ A635330E6EB5E285D878626B /* Pods_Storage_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ A91C660FB541A4CD17BD6559 /* Pods-Auth_ApiTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_ApiTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests.debug.xcconfig"; sourceTree = "<group>"; };
+ A94313324676D16235A36D32 /* Pods-Auth_ApiTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_ApiTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests.release.xcconfig"; sourceTree = "<group>"; };
AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Shared.xcassets; path = Shared/Shared.xcassets; sourceTree = "<group>"; };
AFC8BA9C1EBD230E00B8EEAE /* NotificationsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsController.swift; sourceTree = "<group>"; };
AFC8BA9E1EBD51A700B8EEAE /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = "<group>"; };
@@ -853,14 +1070,16 @@
AFD563131EB1466100EA2233 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "App/GoogleService-Info.plist"; sourceTree = "<group>"; };
AFD563141EB29B8C00EA2233 /* Messaging_Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Messaging_Example.entitlements; sourceTree = "<group>"; };
AFD563161EBBEF7B00EA2233 /* Data+MessagingExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+MessagingExtensions.swift"; sourceTree = "<group>"; };
- B0895BC929D50B20A69CEEEF /* Pods-Storage_IntegrationTests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS.release.xcconfig"; sourceTree = "<group>"; };
- B0C1478ED7269FF2107F5B6F /* Pods_Messaging_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Messaging_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- B0C52364C5FCE5D3FBAEAF83 /* Pods_Auth_SwiftSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_SwiftSample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- B1EFE04FF3C9650984C5E3C3 /* Pods-Storage_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- B4F2CCE27C567E675C27953C /* Pods-Auth_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- BA1AAFF4508A97F7B32533FC /* Pods-Auth_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
- BDE126A5F0AFCA9956A4C5D9 /* Pods_Auth_EarlGreyTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_EarlGreyTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- C1520E81B1BFD24ED1882137 /* Pods-Storage_IntegrationTests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ B183A98C3EA6EA2E11FA31E4 /* Pods-Auth_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ B2FFB14744FBF59F4E89FE0F /* Pods_Database_IntegrationTests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_IntegrationTests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ B44CC7B623B174C922C241EF /* Pods-Database_Example_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_tvOS/Pods-Database_Example_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ B55C9A02AA68737098994C79 /* Pods-Core_Example_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ B6BC99F9590CB7AAE33544C3 /* Pods-Core_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_tvOS/Pods-Core_Tests_tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ B7C4D4083183945C8A9CE722 /* Pods-Database_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ BA1FFE4321DBF890ADDCAAEE /* Pods-Storage_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ BC23B1A7390BEA04DE724F7C /* Pods-Database_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ C2C9D2EB11B351A0EEB3B93D /* Pods-Messaging_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Messaging_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ CDEE84B9D494E05B9F9D46FF /* Pods-Core_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
D018534A1EDACED4003A645C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
D018534C1EDACED4003A645C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
D01853791EDAD084003A645C /* Auth_Example_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Auth_Example_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -881,6 +1100,7 @@
D064E6A41ED9B1BF001956DF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
D064E6A61ED9B1BF001956DF /* Core-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Core-Info.plist"; sourceTree = "<group>"; };
D064E6BF1ED9B31C001956DF /* Core_Tests_macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Core_Tests_macOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = "OCMock-iOS/OCMock.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
D0EDB2CD1EDA04F800B6C31B /* Storage_Example_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Storage_Example_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
D0EDB2D01EDA056A00B6C31B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
D0EDB2D11EDA056A00B6C31B /* FIRAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FIRAppDelegate.h; sourceTree = "<group>"; };
@@ -901,15 +1121,29 @@
D0FE8A2F1ED9C804003F6722 /* Database_Example_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Database_Example_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
D0FE8A621ED9C870003F6722 /* Database_Tests_macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Database_Tests_macOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D0FE8A8C1ED9C87B003F6722 /* Database_IntegrationTests_macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Database_IntegrationTests_macOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- D6A450A39BCA3DB4138333D8 /* Pods-Auth_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- D837E35351C0B844EA64B959 /* Pods_Auth_Sample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Sample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ D2ACCDA6F5D95F900ADBC704 /* Pods-Database_IntegrationTests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ D440FB786B320FCF836B508F /* Pods-Storage_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ D63A20E34B2316DBCDD87E6C /* Pods-Database_Tests_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_tvOS/Pods-Database_Tests_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ D84F03BB958CAC55AF091002 /* Pods-Storage_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ D89F11E328D414F78B66B2F2 /* Pods_Storage_IntegrationTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_IntegrationTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D92C82C51F578DF000D5EAFF /* FIRGetProjectConfigResponseTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRGetProjectConfigResponseTests.m; sourceTree = "<group>"; };
D92C82C61F578DF000D5EAFF /* FIRGetProjectConfigRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRGetProjectConfigRequestTests.m; sourceTree = "<group>"; };
- DDF4A6C7CFF20DCCF96071EC /* Pods-Core_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ DA298A99D536B60732EBCB7D /* Pods_Core_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DE0E5BB51EA7D91C00FAA825 /* FIRAuthAppCredentialTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthAppCredentialTests.m; sourceTree = "<group>"; };
DE0E5BB61EA7D91C00FAA825 /* FIRAuthAppDelegateProxyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthAppDelegateProxyTests.m; sourceTree = "<group>"; };
DE0E5BB91EA7D92E00FAA825 /* FIRVerifyClientRequestTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRVerifyClientRequestTest.m; sourceTree = "<group>"; };
DE0E5BBA1EA7D92E00FAA825 /* FIRVerifyClientResponseTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRVerifyClientResponseTests.m; sourceTree = "<group>"; };
+ DE1CD5971FBA55AF00FC031E /* Database_Example_tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Database_Example_tvOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ DE1EC27F1FBA5E63007D18D8 /* Database_Tests_tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Database_Tests_tvOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ DE1EC28A1FBA5EB5007D18D8 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ DE1EC28B1FBA5EB5007D18D8 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ DE1EC28C1FBA5EB5007D18D8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ DE1EC28D1FBA5EB5007D18D8 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ DE1EC28E1FBA5EB5007D18D8 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ DE1EC28F1FBA5EB5007D18D8 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
+ DE1EC2901FBA5EB5007D18D8 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ DE1EC2911FBA5EB5007D18D8 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ DE1FAE901FBCF5E100897AAA /* Auth_Example_tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Auth_Example_tvOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
DE26D1C71F70330A004AE1D3 /* AuthCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthCredentials.h; sourceTree = "<group>"; };
DE26D1C81F70330A004AE1D3 /* AuthCredentialsTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthCredentialsTemplate.h; sourceTree = "<group>"; };
DE26D1C91F70330A004AE1D3 /* FirebaseAuthApiTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseAuthApiTests.m; sourceTree = "<group>"; };
@@ -974,6 +1208,15 @@
DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_EarlGreyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DE26D27D1F705EC7004AE1D3 /* SwiftSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
DE45C6641E7DA8CB009E6ACD /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
+ DE53893E1FBB62E100199FC2 /* Auth_Tests_tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Auth_Tests_tvOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ DE53894C1FBB635400199FC2 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ DE53894D1FBB635400199FC2 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ DE53894E1FBB635400199FC2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ DE53894F1FBB635400199FC2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ DE5389501FBB635400199FC2 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ DE5389511FBB635400199FC2 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
+ DE5389521FBB635400199FC2 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ DE5389531FBB635400199FC2 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
DE750DB51EB3DD4000A75E47 /* FIRAuthAPNSTokenManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthAPNSTokenManagerTests.m; sourceTree = "<group>"; };
DE750DB61EB3DD4000A75E47 /* FIRAuthAPNSTokenTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthAPNSTokenTests.m; sourceTree = "<group>"; };
DE750DB71EB3DD4000A75E47 /* FIRAuthAppCredentialManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthAppCredentialManagerTests.m; sourceTree = "<group>"; };
@@ -1089,7 +1332,26 @@
DE9315D61E8738B70083EDBF /* FIRMessagingTestNotificationUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRMessagingTestNotificationUtilities.h; sourceTree = "<group>"; };
DE9315D71E8738B70083EDBF /* FIRMessagingTestNotificationUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRMessagingTestNotificationUtilities.m; sourceTree = "<group>"; };
DE9315D81E8738B70083EDBF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- DE9C3D75207E5D1DC70BB364 /* Pods_Database_Tests_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_Tests_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ DEAAD3811FBA11270053BF48 /* Core_Example_tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Core_Example_tvOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ DEAAD3951FBA11270053BF48 /* Core_Tests_tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Core_Tests_tvOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ DEAAD3BD1FBA1CD80053BF48 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ DEAAD3C41FBA1EF90053BF48 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ DEAAD3C51FBA1EF90053BF48 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ DEAAD3C61FBA1EF90053BF48 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ DEAAD3C71FBA1EF90053BF48 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ DEAAD3C81FBA1EFA0053BF48 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ DEAAD3C91FBA1EFA0053BF48 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ DEAAD3D21FBA1F850053BF48 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
+ DEAAD3E11FBA46AA0053BF48 /* Storage_Example_tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Storage_Example_tvOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ DEAAD3F51FBA46AB0053BF48 /* Storage_Tests_tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Storage_Tests_tvOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ DEAAD4121FBA470A0053BF48 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ DEAAD4131FBA470A0053BF48 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ DEAAD4141FBA470A0053BF48 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ DEAAD4151FBA470A0053BF48 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ DEAAD4161FBA470A0053BF48 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ DEAAD4171FBA470A0053BF48 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
+ DEAAD4181FBA470A0053BF48 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ DEAAD4191FBA470A0053BF48 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
DEB139C11E734D9D00AC236D /* FIRStorageDeleteTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRStorageDeleteTests.m; sourceTree = "<group>"; };
DEB139C21E734D9D00AC236D /* FIRStorageGetMetadataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRStorageGetMetadataTests.m; sourceTree = "<group>"; };
DEB139C31E734D9D00AC236D /* FIRStorageMetadataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRStorageMetadataTests.m; sourceTree = "<group>"; };
@@ -1140,16 +1402,21 @@
DEE14D7C1E844677006FA992 /* FIRTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRTestCase.m; sourceTree = "<group>"; };
DEE14D7D1E844677006FA992 /* Tests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
DEF288401F9AB6E100D480CF /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
- DFC35EAB61A983056BE25D28 /* Pods_Database_IntegrationTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Database_IntegrationTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- E0EF5EDDB1FD839F03FC02AA /* Pods-Storage_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ DFCD819598D37C1AD6F7D601 /* Pods_Storage_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ E0B3F6C29D6072C4CD9665AD /* Pods_Auth_SwiftSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_SwiftSample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ E18F9020BB494E59BB0DDA2E /* Pods-Core_Tests_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_tvOS/Pods-Core_Tests_tvOS.debug.xcconfig"; sourceTree = "<group>"; };
+ E262D06D71EE92227622D747 /* Pods-Storage_IntegrationTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_IntegrationTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
E2C2834C90DBAB56D568189F /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
- E5978C421A9123C9D34CBA43 /* Pods-Database_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- E8A8A21551A3D8557757AD0D /* Pods-Auth_ApiTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_ApiTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests.release.xcconfig"; sourceTree = "<group>"; };
- EDA33867CB04D0AADD09321A /* Pods-Database_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- F7649E1B594D8101939746EA /* Pods-Core_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
- F7A35264721D3C8D9F96F91C /* Pods_Auth_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Auth_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- FD3AEF097DFCF2ADAC345D2A /* Pods-Storage_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
- FDBC4B909E617B02D7E741F6 /* Pods-Auth_Tests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Tests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ E6CD25911724B592A3988A50 /* Pods_Core_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ E9BD713FA8E0DDA1C631EFA7 /* Pods_Core_Example_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Core_Example_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ EAB8C42B67530BE1F6913791 /* Pods-Database_Tests_macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_Tests_macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS.debug.xcconfig"; sourceTree = "<group>"; };
+ EBC238B93690B48A560707ED /* Pods_Storage_Example_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Storage_Example_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ ECDA16775B57C6E80011DD9B /* Pods-Core_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ EE6603729203B76D9914EE06 /* Pods-Core_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ F2A878FAEAB3ACF41E7D630C /* Pods-Database_IntegrationTests_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database_IntegrationTests_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS.release.xcconfig"; sourceTree = "<group>"; };
+ F55411158F1D5AD6FC20B9B9 /* Pods-Core_Example_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Core_Example_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Core_Example_tvOS/Pods-Core_Example_tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ FF3BDAACC6424BF110DC26F2 /* Pods-Auth_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ FFFFFD100F6720BBBA4176CC /* Pods-Auth_Example_macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth_Example_macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -1157,7 +1424,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 6232ED3272E9C78C2A0E127F /* Pods_Storage_IntegrationTests_iOS.framework in Frameworks */,
+ 465CC1E7162634883C399206 /* Pods_Storage_IntegrationTests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1165,7 +1432,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- DA464BCB6574F7FE299CB48D /* Pods_Database_IntegrationTests_iOS.framework in Frameworks */,
+ D5DA1D0CD1B4A2D08B5296D6 /* Pods_Database_IntegrationTests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1173,7 +1440,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 8313C96352C6C77D481B5937 /* Pods_Messaging_Example_iOS.framework in Frameworks */,
+ 6462518AA418BF979F7ECD04 /* Pods_Messaging_Example_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1181,7 +1448,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 6D6FA69218AB107C266E1B70 /* Pods_Auth_Example_macOS.framework in Frameworks */,
+ 822CE316AE9827F7F0889B30 /* Pods_Auth_Example_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1189,7 +1456,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2C8B39CFF9898AE4B29AD114 /* Pods_Auth_Tests_macOS.framework in Frameworks */,
+ ECBC321017C94478E9DCEB4E /* Pods_Auth_Tests_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1197,7 +1464,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 431EBDD6071EF1AE6F6DBE5F /* Pods_Core_Example_macOS.framework in Frameworks */,
+ 91A0BCD9A296439CB7E7843C /* Pods_Core_Example_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1205,7 +1472,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 29136BCA0AD59481B07CFBB0 /* Pods_Core_Tests_macOS.framework in Frameworks */,
+ 37CFACAA408191867DE00FEA /* Pods_Core_Tests_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1213,7 +1480,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 063825B4D58274CB24B25FF1 /* Pods_Storage_Example_macOS.framework in Frameworks */,
+ 2C61352BC0FA096866E11A13 /* Pods_Storage_Example_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1221,7 +1488,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 529BBEFBB6D7A3653B6B3874 /* Pods_Storage_Tests_macOS.framework in Frameworks */,
+ D8C9C50E6CF043E74755973F /* Pods_Storage_Tests_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1229,7 +1496,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 91BECF25F64620DEDF99A106 /* Pods_Storage_IntegrationTests_macOS.framework in Frameworks */,
+ C521E0D6D9027DB7B2254B19 /* Pods_Storage_IntegrationTests_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1237,7 +1504,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- A553FD534066F62EE74F2D51 /* Pods_Database_Example_macOS.framework in Frameworks */,
+ 451B83DCCB85173A0B5E15FB /* Pods_Database_Example_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1245,7 +1512,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 7CA435AB1A753CC9EEDFA648 /* Pods_Database_Tests_macOS.framework in Frameworks */,
+ 7F41B0EFBDDA90CB9CE6CE5B /* Pods_Database_Tests_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1253,7 +1520,31 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- FF33B94B3A34331129E4E4D5 /* Pods_Database_IntegrationTests_macOS.framework in Frameworks */,
+ 2FFD1B3D1BD1A79B3EBCE10B /* Pods_Database_IntegrationTests_macOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1CD5941FBA55AF00FC031E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A3C94871F590440BE6DDEBDB /* Pods_Database_Example_tvOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1EC27C1FBA5E63007D18D8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7E26CF28514D041D284F00A5 /* Pods_Database_Tests_tvOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1FAE8D1FBCF5E100897AAA /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1FF92C04BA1E704C11B0467 /* Pods_Auth_Example_tvOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1261,7 +1552,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 0C1D425E4DA4FBFD5A08B985 /* Pods_Auth_Sample.framework in Frameworks */,
+ C344068A9C3B2487279AB0BC /* Pods_Auth_Sample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1269,7 +1560,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 8FC590E7FF7C561991DC9DD6 /* Pods_Auth_ApiTests.framework in Frameworks */,
+ 0DADD37DFD4D9DC368B72DF8 /* Pods_Auth_ApiTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1277,7 +1568,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- CD4DB22A28941C5FEE70686A /* Pods_Auth_EarlGreyTests.framework in Frameworks */,
+ 7E5BD38D202BFB8CD9CCEB53 /* Pods_Auth_EarlGreyTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1285,7 +1576,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 930570CF84207AEB98440760 /* Pods_Auth_SwiftSample.framework in Frameworks */,
+ 305C6268DB5BF4653F4843D6 /* Pods_Auth_SwiftSample.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE53893B1FBB62E100199FC2 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7251EC9D9AA2AF1C7C6FFA27 /* Pods_Auth_Tests_tvOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1293,7 +1592,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 825BE4C9299DAB7EFEB19B65 /* Pods_Database_Example_iOS.framework in Frameworks */,
+ DDAA23BBAF5FA178E01D89B6 /* Pods_Database_Example_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1301,7 +1600,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 6ADAC4BEBCE37253D2D7A50F /* Pods_Database_Tests_iOS.framework in Frameworks */,
+ BD84035FA14A8647DCB7AEE7 /* Pods_Database_Tests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1309,7 +1608,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 67EA2F675D33B39CEB0D41B1 /* Pods_Auth_Example_iOS.framework in Frameworks */,
+ E0D25209B6EBC3F1C8902985 /* Pods_Auth_Example_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1317,7 +1616,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 5207C8D12B9830DADB85FE67 /* Pods_Auth_Tests_iOS.framework in Frameworks */,
+ E1AAE49ECC7CBAB74C290B25 /* Pods_Auth_Tests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1325,7 +1624,39 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2ECC6F80E47D2646FA82B940 /* Pods_Messaging_Tests_iOS.framework in Frameworks */,
+ E3EE0971417119B44A7B6784 /* Pods_Messaging_Tests_iOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD37E1FBA11270053BF48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2046226C96706813FEE60FAA /* Pods_Core_Example_tvOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3921FBA11270053BF48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 284F39A3FED7FC1457A20DA3 /* Pods_Core_Tests_tvOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3DE1FBA46AA0053BF48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 77FC21C5B8BB3E10497C9893 /* Pods_Storage_Example_tvOS.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3F21FBA46AB0053BF48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7B6F7B081BE6A56CF0AE20F5 /* Pods_Storage_Tests_tvOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1336,7 +1667,7 @@
DEB139F41E73506A00AC236D /* CoreGraphics.framework in Frameworks */,
DEB139F51E73506A00AC236D /* UIKit.framework in Frameworks */,
DEB139F61E73506A00AC236D /* Foundation.framework in Frameworks */,
- 9CD1CAC2BC2C39B755F7BF88 /* Pods_Storage_Example_iOS.framework in Frameworks */,
+ BB2055D8C835CBDABB419B1C /* Pods_Storage_Example_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1344,7 +1675,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 01E863BD40D23087B77F2F03 /* Pods_Storage_Tests_iOS.framework in Frameworks */,
+ 77E3EE8071524513EE52506F /* Pods_Storage_Tests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1352,7 +1683,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 53C9FD19788281F65D537548 /* Pods_Analytics_Tests_iOS.framework in Frameworks */,
+ 2EE6D7190CA87B2514217B5F /* Pods_Analytics_Tests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1360,7 +1691,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 1A509E710C83B6D0A6CD286D /* Pods_Core_Example_iOS.framework in Frameworks */,
+ BBFDB50D4B4632DF9A32B305 /* Pods_Core_Example_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1368,7 +1699,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- ABA730C3E77B260C564C288A /* Pods_Core_Tests_iOS.framework in Frameworks */,
+ 66F5D2993433940E43128EFF /* Pods_Core_Tests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1439,67 +1770,6 @@
path = third_party;
sourceTree = "<group>";
};
- 2A06FEEED3D48AAD710413A7 /* Pods */ = {
- isa = PBXGroup;
- children = (
- 09F55B0265DCD315B2DD3C2E /* Pods-Auth_ApiTests.debug.xcconfig */,
- E8A8A21551A3D8557757AD0D /* Pods-Auth_ApiTests.release.xcconfig */,
- 94C0FA103316CB56F37E20EA /* Pods-Auth_EarlGreyTests.debug.xcconfig */,
- 0DB176DCABEFDF6C19B302B0 /* Pods-Auth_EarlGreyTests.release.xcconfig */,
- 6029CD8D7E65D491083D5944 /* Pods-Auth_Example_iOS.debug.xcconfig */,
- 0C69403B9730C701BF2E0446 /* Pods-Auth_Example_iOS.release.xcconfig */,
- B4F2CCE27C567E675C27953C /* Pods-Auth_Example_macOS.debug.xcconfig */,
- 4BF8EA84DF6AF0AB6E9BB6A0 /* Pods-Auth_Example_macOS.release.xcconfig */,
- 48317719F315960780114559 /* Pods-Auth_Sample.debug.xcconfig */,
- 8602A8FB9AF04A0C9A8FE380 /* Pods-Auth_Sample.release.xcconfig */,
- 0CA98384DDFFEECB1D473552 /* Pods-Auth_SwiftSample.debug.xcconfig */,
- 28B01131418E340D322829AC /* Pods-Auth_SwiftSample.release.xcconfig */,
- 1735157165B298F2A1EC36E3 /* Pods-Auth_Tests_iOS.debug.xcconfig */,
- D6A450A39BCA3DB4138333D8 /* Pods-Auth_Tests_iOS.release.xcconfig */,
- BA1AAFF4508A97F7B32533FC /* Pods-Auth_Tests_macOS.debug.xcconfig */,
- FDBC4B909E617B02D7E741F6 /* Pods-Auth_Tests_macOS.release.xcconfig */,
- 870F50EE08ED74C38B5CAF79 /* Pods-Core_Example_iOS.debug.xcconfig */,
- 1E6C076D38C1763E00A3DACA /* Pods-Core_Example_iOS.release.xcconfig */,
- 6FD4B6DC35E3304CBECFEC61 /* Pods-Core_Example_macOS.debug.xcconfig */,
- F7649E1B594D8101939746EA /* Pods-Core_Example_macOS.release.xcconfig */,
- 0D66D613C54F5BFF80D9AB63 /* Pods-Core_Tests_iOS.debug.xcconfig */,
- DDF4A6C7CFF20DCCF96071EC /* Pods-Core_Tests_iOS.release.xcconfig */,
- 2B3C652966760042D996247E /* Pods-Core_Tests_macOS.debug.xcconfig */,
- 287D8FC7F3129B28D8A29FBE /* Pods-Core_Tests_macOS.release.xcconfig */,
- E5978C421A9123C9D34CBA43 /* Pods-Database_Example_iOS.debug.xcconfig */,
- 5DA6361D6B54362D073F3BA5 /* Pods-Database_Example_iOS.release.xcconfig */,
- 1068E64D36A3C656184168DE /* Pods-Database_Example_macOS.debug.xcconfig */,
- 4CC7C8B9E821151509BB3B64 /* Pods-Database_Example_macOS.release.xcconfig */,
- 20928A4E610E48E3EA4D9F4A /* Pods-Database_IntegrationTests_iOS.debug.xcconfig */,
- EDA33867CB04D0AADD09321A /* Pods-Database_IntegrationTests_iOS.release.xcconfig */,
- 1CCC00FFFC534F0E9B41CF29 /* Pods-Database_IntegrationTests_macOS.debug.xcconfig */,
- 00BD45B2141C68C3F9809A4D /* Pods-Database_IntegrationTests_macOS.release.xcconfig */,
- 000DAC7D0D180A9FBB395BB6 /* Pods-Database_Tests_iOS.debug.xcconfig */,
- 2B1B85CD0C7778447F3BFCD5 /* Pods-Database_Tests_iOS.release.xcconfig */,
- 86B8E0400070C72C0FE0C2F8 /* Pods-Database_Tests_macOS.debug.xcconfig */,
- 7879DCC8860E7CED0311D4E8 /* Pods-Database_Tests_macOS.release.xcconfig */,
- 4D61AACC06F8E078EF051E4C /* Pods-Messaging_Example_iOS.debug.xcconfig */,
- 6098677E3698C58151DC2E85 /* Pods-Messaging_Example_iOS.release.xcconfig */,
- 46052D607615BD81295B65C6 /* Pods-Messaging_Tests_iOS.debug.xcconfig */,
- 3A304052F4122D3468145F6C /* Pods-Messaging_Tests_iOS.release.xcconfig */,
- 3E26CB853AB2CAF1960A0F71 /* Pods-Storage_Example_iOS.debug.xcconfig */,
- 97790B1C788991008685954F /* Pods-Storage_Example_iOS.release.xcconfig */,
- 24B879B03BD82C7DE771CA61 /* Pods-Storage_Example_macOS.debug.xcconfig */,
- FD3AEF097DFCF2ADAC345D2A /* Pods-Storage_Example_macOS.release.xcconfig */,
- 4ECAA105379B7E664C7FF223 /* Pods-Storage_IntegrationTests_iOS.debug.xcconfig */,
- 5CA5A85B5A80F118F3247910 /* Pods-Storage_IntegrationTests_iOS.release.xcconfig */,
- C1520E81B1BFD24ED1882137 /* Pods-Storage_IntegrationTests_macOS.debug.xcconfig */,
- B0895BC929D50B20A69CEEEF /* Pods-Storage_IntegrationTests_macOS.release.xcconfig */,
- 466C3694B6C68F69BA4DA448 /* Pods-Storage_Tests_iOS.debug.xcconfig */,
- B1EFE04FF3C9650984C5E3C3 /* Pods-Storage_Tests_iOS.release.xcconfig */,
- 4B490EFB675400675CA98196 /* Pods-Storage_Tests_macOS.debug.xcconfig */,
- E0EF5EDDB1FD839F03FC02AA /* Pods-Storage_Tests_macOS.release.xcconfig */,
- 77FA2AB612D17244983008F7 /* Pods-Analytics_Tests_iOS.debug.xcconfig */,
- 456CD9478A63272C4397975E /* Pods-Analytics_Tests_iOS.release.xcconfig */,
- );
- name = Pods;
- sourceTree = "<group>";
- };
6003F581195388D10070C39A = {
isa = PBXGroup;
children = (
@@ -1513,7 +1783,7 @@
DEDFEFED1FD1B8C100F7D466 /* Analytics_Tests_iOS */,
6003F58C195388D20070C39A /* Frameworks */,
6003F58B195388D20070C39A /* Products */,
- 2A06FEEED3D48AAD710413A7 /* Pods */,
+ 96BADAA81FD7CF6BED52C215 /* Pods */,
);
sourceTree = "<group>";
};
@@ -1546,6 +1816,14 @@
DE26D25D1F7049F1004AE1D3 /* Auth_ApiTests.xctest */,
DE26D26D1F705C35004AE1D3 /* Auth_EarlGreyTests.xctest */,
DE26D27D1F705EC7004AE1D3 /* SwiftSample.app */,
+ DEAAD3811FBA11270053BF48 /* Core_Example_tvOS.app */,
+ DEAAD3951FBA11270053BF48 /* Core_Tests_tvOS.xctest */,
+ DEAAD3E11FBA46AA0053BF48 /* Storage_Example_tvOS.app */,
+ DEAAD3F51FBA46AB0053BF48 /* Storage_Tests_tvOS.xctest */,
+ DE1CD5971FBA55AF00FC031E /* Database_Example_tvOS.app */,
+ DE1EC27F1FBA5E63007D18D8 /* Database_Tests_tvOS.xctest */,
+ DE53893E1FBB62E100199FC2 /* Auth_Tests_tvOS.xctest */,
+ DE1FAE901FBCF5E100897AAA /* Auth_Example_tvOS.app */,
DEDFEFEC1FD1B8C100F7D466 /* Analytics_Tests_iOS.xctest */,
);
name = Products;
@@ -1554,38 +1832,47 @@
6003F58C195388D20070C39A /* Frameworks */ = {
isa = PBXGroup;
children = (
+ D09005301EDB32D600154410 /* OCMock-iOS/OCMock.framework */,
DE45C6641E7DA8CB009E6ACD /* XCTest.framework */,
DEB61E781E7C542600C04B96 /* libsqlite3.tbd */,
6003F58D195388D20070C39A /* Foundation.framework */,
6003F58F195388D20070C39A /* CoreGraphics.framework */,
6003F591195388D20070C39A /* UIKit.framework */,
- 93491C87A390AB737849677E /* Pods_Auth_ApiTests.framework */,
- BDE126A5F0AFCA9956A4C5D9 /* Pods_Auth_EarlGreyTests.framework */,
- 4373FD322206E44A7CADC2A8 /* Pods_Auth_Example_iOS.framework */,
- F7A35264721D3C8D9F96F91C /* Pods_Auth_Example_macOS.framework */,
- D837E35351C0B844EA64B959 /* Pods_Auth_Sample.framework */,
- B0C52364C5FCE5D3FBAEAF83 /* Pods_Auth_SwiftSample.framework */,
- 0ABC4448E5917769098A4EEF /* Pods_Auth_Tests_iOS.framework */,
- 1015568683E2DFCC2719C754 /* Pods_Auth_Tests_macOS.framework */,
- 68657030253DE5895E124F45 /* Pods_Core_Example_iOS.framework */,
- 84C51650773603D9F827CB3F /* Pods_Core_Example_macOS.framework */,
- 3B9B568851BEE22B7FCB61FB /* Pods_Core_Tests_iOS.framework */,
- 86062A14985F49A3B99614A7 /* Pods_Core_Tests_macOS.framework */,
- 66544F771D53687DD73F8BE8 /* Pods_Database_Example_iOS.framework */,
- 7CF25C495716B3441849720B /* Pods_Database_Example_macOS.framework */,
- DFC35EAB61A983056BE25D28 /* Pods_Database_IntegrationTests_iOS.framework */,
- 81C1ABDD7BB039B4BF06A29E /* Pods_Database_IntegrationTests_macOS.framework */,
- 4852BF989C85671F5D7EBD2A /* Pods_Database_Tests_iOS.framework */,
- DE9C3D75207E5D1DC70BB364 /* Pods_Database_Tests_macOS.framework */,
- B0C1478ED7269FF2107F5B6F /* Pods_Messaging_Example_iOS.framework */,
- 6CCB3CEB7BF2E4994FBDB2E7 /* Pods_Messaging_Tests_iOS.framework */,
- 3742438A60FCFAAF24CDE751 /* Pods_Storage_Example_iOS.framework */,
- 8F27F07800D6FD739BD094D3 /* Pods_Storage_Example_macOS.framework */,
- 979DF124E3D1146A81188F78 /* Pods_Storage_IntegrationTests_iOS.framework */,
- 6A28B39B3D707677EF59C110 /* Pods_Storage_IntegrationTests_macOS.framework */,
- A8E6527440C118AC7C21D504 /* Pods_Storage_Tests_iOS.framework */,
- 910D7A5DE7D5AF153328D243 /* Pods_Storage_Tests_macOS.framework */,
- 29606A0F0B0782779D4E73A1 /* Pods_Analytics_Tests_iOS.framework */,
+ 48EC844B9B5B226AB409C04D /* Pods_Analytics_Tests_iOS.framework */,
+ 33C0463B7313FC8E23E5DAAD /* Pods_Auth_ApiTests.framework */,
+ 1FAA82401DA4259800B142EA /* Pods_Auth_EarlGreyTests.framework */,
+ A1F43E00CECD3298E770515E /* Pods_Auth_Example_iOS.framework */,
+ 9878B57CF73D2F865992E6EA /* Pods_Auth_Example_macOS.framework */,
+ 4384273DF1B662E4CE522BAF /* Pods_Auth_Example_tvOS.framework */,
+ 1ACEE1E8A4E9B9D4455A09AB /* Pods_Auth_Sample.framework */,
+ E0B3F6C29D6072C4CD9665AD /* Pods_Auth_SwiftSample.framework */,
+ 4ECF3BF97E614E5E627B8AFF /* Pods_Auth_Tests_iOS.framework */,
+ 0B687E5985EC23880B5FB9C0 /* Pods_Auth_Tests_macOS.framework */,
+ 20AE8AA8E8EB8E0BEF84F161 /* Pods_Auth_Tests_tvOS.framework */,
+ 94427D25FE9C3A26EF1A8ABE /* Pods_Core_Example_iOS.framework */,
+ DA298A99D536B60732EBCB7D /* Pods_Core_Example_macOS.framework */,
+ E9BD713FA8E0DDA1C631EFA7 /* Pods_Core_Example_tvOS.framework */,
+ E6CD25911724B592A3988A50 /* Pods_Core_Tests_iOS.framework */,
+ 48B19F642ED7795BE8C61702 /* Pods_Core_Tests_macOS.framework */,
+ 092A0E9B0100EB5D1592AD68 /* Pods_Core_Tests_tvOS.framework */,
+ 1F2C1255ABA57AFDFD587103 /* Pods_Database_Example_iOS.framework */,
+ 84EC7975F05977AE75E90A12 /* Pods_Database_Example_macOS.framework */,
+ 483A1D5066DE4B7EF0B8BF52 /* Pods_Database_Example_tvOS.framework */,
+ 1113F1AFA1EFE58780FE9294 /* Pods_Database_IntegrationTests_iOS.framework */,
+ B2FFB14744FBF59F4E89FE0F /* Pods_Database_IntegrationTests_macOS.framework */,
+ 2CCF6BD7264693FD98E10850 /* Pods_Database_Tests_iOS.framework */,
+ 61377AC9FE132A8D7BF71881 /* Pods_Database_Tests_macOS.framework */,
+ 5318F3AE32EEBCC9FF608813 /* Pods_Database_Tests_tvOS.framework */,
+ 984080F16FA41AF3AA9AD8C2 /* Pods_Messaging_Example_iOS.framework */,
+ 1D1C7CFB87F3066712EF881B /* Pods_Messaging_Tests_iOS.framework */,
+ DFCD819598D37C1AD6F7D601 /* Pods_Storage_Example_iOS.framework */,
+ 5656210C04D3CE12EDEC3A00 /* Pods_Storage_Example_macOS.framework */,
+ EBC238B93690B48A560707ED /* Pods_Storage_Example_tvOS.framework */,
+ D89F11E328D414F78B66B2F2 /* Pods_Storage_IntegrationTests_iOS.framework */,
+ 249A92EF1ADB4E2186F9F788 /* Pods_Storage_IntegrationTests_macOS.framework */,
+ 6F9D3351687EF7767B507F0E /* Pods_Storage_Tests_iOS.framework */,
+ A635330E6EB5E285D878626B /* Pods_Storage_Tests_macOS.framework */,
+ 9B4F4F14C797493D606A23A8 /* Pods_Storage_Tests_tvOS.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -1599,6 +1886,83 @@
name = "Podspec Metadata";
sourceTree = "<group>";
};
+ 96BADAA81FD7CF6BED52C215 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 920F3E71E6698FEADDA9D37A /* Pods-Analytics_Tests_iOS.debug.xcconfig */,
+ 2DE182937C7CA58E63112FD2 /* Pods-Analytics_Tests_iOS.release.xcconfig */,
+ A91C660FB541A4CD17BD6559 /* Pods-Auth_ApiTests.debug.xcconfig */,
+ A94313324676D16235A36D32 /* Pods-Auth_ApiTests.release.xcconfig */,
+ 16182094A8A3749CA6D24429 /* Pods-Auth_EarlGreyTests.debug.xcconfig */,
+ 8AB8C5932B72C705E2EBCF1B /* Pods-Auth_EarlGreyTests.release.xcconfig */,
+ 39D965DC207D9E9C841AB1AF /* Pods-Auth_Example_iOS.debug.xcconfig */,
+ FF3BDAACC6424BF110DC26F2 /* Pods-Auth_Example_iOS.release.xcconfig */,
+ 0E086A7E5D54786963FBFC7D /* Pods-Auth_Example_macOS.debug.xcconfig */,
+ FFFFFD100F6720BBBA4176CC /* Pods-Auth_Example_macOS.release.xcconfig */,
+ 1E5ECEF4C67573595335207D /* Pods-Auth_Example_tvOS.debug.xcconfig */,
+ 9B2AAD4EC2BD3FBC053CBD2A /* Pods-Auth_Example_tvOS.release.xcconfig */,
+ 0D4A8F333DE1D31AE14011D4 /* Pods-Auth_Sample.debug.xcconfig */,
+ 3B69D19E3FAF168C8EF37C81 /* Pods-Auth_Sample.release.xcconfig */,
+ 01936C31BDE676F86CF8DA39 /* Pods-Auth_SwiftSample.debug.xcconfig */,
+ 91D2A751787B7FDD624919EB /* Pods-Auth_SwiftSample.release.xcconfig */,
+ 9E042E6047B5B5D409AD083F /* Pods-Auth_Tests_iOS.debug.xcconfig */,
+ 122B6EBA56EAB083239B83DE /* Pods-Auth_Tests_iOS.release.xcconfig */,
+ 46EB9F652984D82936716B89 /* Pods-Auth_Tests_macOS.debug.xcconfig */,
+ B183A98C3EA6EA2E11FA31E4 /* Pods-Auth_Tests_macOS.release.xcconfig */,
+ 70B04F7AEEC14B4E1E8C23D8 /* Pods-Auth_Tests_tvOS.debug.xcconfig */,
+ 042AFA12FC20D0683FB59B9E /* Pods-Auth_Tests_tvOS.release.xcconfig */,
+ EE6603729203B76D9914EE06 /* Pods-Core_Example_iOS.debug.xcconfig */,
+ 3A2BAC7CAFE05F790B1E34A1 /* Pods-Core_Example_iOS.release.xcconfig */,
+ B55C9A02AA68737098994C79 /* Pods-Core_Example_macOS.debug.xcconfig */,
+ 7981511F571E13DECA09B4B1 /* Pods-Core_Example_macOS.release.xcconfig */,
+ 86E271316861BA45BD9370FC /* Pods-Core_Example_tvOS.debug.xcconfig */,
+ F55411158F1D5AD6FC20B9B9 /* Pods-Core_Example_tvOS.release.xcconfig */,
+ ECDA16775B57C6E80011DD9B /* Pods-Core_Tests_iOS.debug.xcconfig */,
+ 0921DBEEC62AE8DCF318657D /* Pods-Core_Tests_iOS.release.xcconfig */,
+ CDEE84B9D494E05B9F9D46FF /* Pods-Core_Tests_macOS.debug.xcconfig */,
+ 0118423DA26C4B44AEE1B9C1 /* Pods-Core_Tests_macOS.release.xcconfig */,
+ E18F9020BB494E59BB0DDA2E /* Pods-Core_Tests_tvOS.debug.xcconfig */,
+ B6BC99F9590CB7AAE33544C3 /* Pods-Core_Tests_tvOS.release.xcconfig */,
+ 3CF8F39CB220DE230DDAEC15 /* Pods-Database_Example_iOS.debug.xcconfig */,
+ 381D76A090B5EF6699CA3673 /* Pods-Database_Example_iOS.release.xcconfig */,
+ 639B98AAF5AC93281CDF9DAF /* Pods-Database_Example_macOS.debug.xcconfig */,
+ B7C4D4083183945C8A9CE722 /* Pods-Database_Example_macOS.release.xcconfig */,
+ B44CC7B623B174C922C241EF /* Pods-Database_Example_tvOS.debug.xcconfig */,
+ 7ED0DF69C095C21EFC81F672 /* Pods-Database_Example_tvOS.release.xcconfig */,
+ 885461BA75A5FE1BF1CBC992 /* Pods-Database_IntegrationTests_iOS.debug.xcconfig */,
+ 33C6BA3B4F6EEB1532A645E3 /* Pods-Database_IntegrationTests_iOS.release.xcconfig */,
+ D2ACCDA6F5D95F900ADBC704 /* Pods-Database_IntegrationTests_macOS.debug.xcconfig */,
+ F2A878FAEAB3ACF41E7D630C /* Pods-Database_IntegrationTests_macOS.release.xcconfig */,
+ 5E0F451FE2DF377FEEE0C9CE /* Pods-Database_Tests_iOS.debug.xcconfig */,
+ BC23B1A7390BEA04DE724F7C /* Pods-Database_Tests_iOS.release.xcconfig */,
+ EAB8C42B67530BE1F6913791 /* Pods-Database_Tests_macOS.debug.xcconfig */,
+ 4CCB05296C6932B64AFBFB1A /* Pods-Database_Tests_macOS.release.xcconfig */,
+ D63A20E34B2316DBCDD87E6C /* Pods-Database_Tests_tvOS.debug.xcconfig */,
+ 37A2B647AFCDC9187D37529B /* Pods-Database_Tests_tvOS.release.xcconfig */,
+ 99BF1D5FC3F0CC27D845BCDE /* Pods-Messaging_Example_iOS.debug.xcconfig */,
+ 4A7EFB64559F46B8A5FA288D /* Pods-Messaging_Example_iOS.release.xcconfig */,
+ 011545D4307696ABBF9658F2 /* Pods-Messaging_Tests_iOS.debug.xcconfig */,
+ C2C9D2EB11B351A0EEB3B93D /* Pods-Messaging_Tests_iOS.release.xcconfig */,
+ 06F3D16439F061DE9973902D /* Pods-Storage_Example_iOS.debug.xcconfig */,
+ D440FB786B320FCF836B508F /* Pods-Storage_Example_iOS.release.xcconfig */,
+ 66A4B7148EBB02E1A68EB8B0 /* Pods-Storage_Example_macOS.debug.xcconfig */,
+ 72CFADA95DFD90718FDCFE19 /* Pods-Storage_Example_macOS.release.xcconfig */,
+ 4F088699064170B6010B477A /* Pods-Storage_Example_tvOS.debug.xcconfig */,
+ 692B433E797D83866B178F94 /* Pods-Storage_Example_tvOS.release.xcconfig */,
+ E262D06D71EE92227622D747 /* Pods-Storage_IntegrationTests_iOS.debug.xcconfig */,
+ A2339EEA1F050084D3214753 /* Pods-Storage_IntegrationTests_iOS.release.xcconfig */,
+ 57876896413B7C97B317CCFD /* Pods-Storage_IntegrationTests_macOS.debug.xcconfig */,
+ 5FAFDE80DEFDE1EF5415939B /* Pods-Storage_IntegrationTests_macOS.release.xcconfig */,
+ 218DAA68383543E59864D4FA /* Pods-Storage_Tests_iOS.debug.xcconfig */,
+ 10C5FF4777A334F9F55ED95A /* Pods-Storage_Tests_iOS.release.xcconfig */,
+ D84F03BB958CAC55AF091002 /* Pods-Storage_Tests_macOS.debug.xcconfig */,
+ BA1FFE4321DBF890ADDCAAEE /* Pods-Storage_Tests_macOS.release.xcconfig */,
+ 3BDE00663D69912D5F2A7101 /* Pods-Storage_Tests_tvOS.debug.xcconfig */,
+ 63687A1F0EF54DDCBD13E4D4 /* Pods-Storage_Tests_tvOS.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
AFC8BAA01EC24B1600B8EEAE /* Shared */ = {
isa = PBXGroup;
children = (
@@ -1751,6 +2115,21 @@
name = macOS;
sourceTree = "<group>";
};
+ DE1EC2891FBA5EB5007D18D8 /* tvOS */ = {
+ isa = PBXGroup;
+ children = (
+ DE1EC28A1FBA5EB5007D18D8 /* AppDelegate.h */,
+ DE1EC28B1FBA5EB5007D18D8 /* AppDelegate.m */,
+ DE1EC28C1FBA5EB5007D18D8 /* Assets.xcassets */,
+ DE1EC28D1FBA5EB5007D18D8 /* Info.plist */,
+ DE1EC28E1FBA5EB5007D18D8 /* main.m */,
+ DE1EC28F1FBA5EB5007D18D8 /* Main.storyboard */,
+ DE1EC2901FBA5EB5007D18D8 /* ViewController.h */,
+ DE1EC2911FBA5EB5007D18D8 /* ViewController.m */,
+ );
+ path = tvOS;
+ sourceTree = "<group>";
+ };
DE26D1C61F70330A004AE1D3 /* ApiTests */ = {
isa = PBXGroup;
children = (
@@ -1835,6 +2214,21 @@
path = SwiftSample;
sourceTree = "<group>";
};
+ DE53894B1FBB635400199FC2 /* tvOS */ = {
+ isa = PBXGroup;
+ children = (
+ DE53894C1FBB635400199FC2 /* AppDelegate.h */,
+ DE5389521FBB635400199FC2 /* ViewController.h */,
+ DE53894D1FBB635400199FC2 /* AppDelegate.m */,
+ DE5389501FBB635400199FC2 /* main.m */,
+ DE5389531FBB635400199FC2 /* ViewController.m */,
+ DE53894F1FBB635400199FC2 /* Info.plist */,
+ DE5389511FBB635400199FC2 /* Main.storyboard */,
+ DE53894E1FBB635400199FC2 /* Assets.xcassets */,
+ );
+ path = tvOS;
+ sourceTree = "<group>";
+ };
DE7B8D2A1E8EF202009EB6DF /* Database */ = {
isa = PBXGroup;
children = (
@@ -1848,6 +2242,7 @@
isa = PBXGroup;
children = (
0672F2F11EBBA7D900818E87 /* GoogleService-Info.plist */,
+ DE1EC2891FBA5EB5007D18D8 /* tvOS */,
D0FE8A141ED9C5B2003F6722 /* iOS */,
D0FE8A151ED9C5B8003F6722 /* macOS */,
);
@@ -1871,16 +2266,18 @@
DE7B8D391E8EF202009EB6DF /* Unit */ = {
isa = PBXGroup;
children = (
+ 063CB47A1EBA7AEF00038A59 /* FIRDataSnapshotTests.h */,
+ 063CB4491EBA7AE200038A59 /* FIRMutableDataTests.h */,
+ 063CB44D1EBA7AE200038A59 /* FPathTests.h */,
+ 063CB4551EBA7AE200038A59 /* FSparseSnapshotTests.h */,
+ 063CB4571EBA7AE200038A59 /* FSyncPointTests.h */,
063CB4471EBA7AE200038A59 /* FArraySortedDictionaryTest.m */,
063CB4481EBA7AE200038A59 /* FCompoundHashTest.m */,
063CB46E1EBA7AEF00038A59 /* FCompoundWriteTest.m */,
- 063CB47A1EBA7AEF00038A59 /* FIRDataSnapshotTests.h */,
063CB47B1EBA7AEF00038A59 /* FIRDataSnapshotTests.m */,
- 063CB4491EBA7AE200038A59 /* FIRMutableDataTests.h */,
063CB44A1EBA7AE200038A59 /* FIRMutableDataTests.m */,
063CB44B1EBA7AE200038A59 /* FLevelDBStorageEngineTests.m */,
063CB44C1EBA7AE200038A59 /* FNodeTests.m */,
- 063CB44D1EBA7AE200038A59 /* FPathTests.h */,
063CB44E1EBA7AE200038A59 /* FPathTests.m */,
063CB44F1EBA7AE200038A59 /* FPersistenceManagerTest.m */,
063CB4501EBA7AE200038A59 /* FPruneForestTest.m */,
@@ -1888,9 +2285,7 @@
063CB4521EBA7AE200038A59 /* FQueryParamsTest.m */,
063CB4531EBA7AE200038A59 /* FRangeMergeTest.m */,
063CB4541EBA7AE200038A59 /* FRepoInfoTest.m */,
- 063CB4551EBA7AE200038A59 /* FSparseSnapshotTests.h */,
063CB4561EBA7AE200038A59 /* FSparseSnapshotTests.m */,
- 063CB4571EBA7AE200038A59 /* FSyncPointTests.h */,
063CB4581EBA7AE200038A59 /* FSyncPointTests.m */,
063CB45B1EBA7AE200038A59 /* FTrackedQueryManagerTest.m */,
063CB4901EBA7AEF00038A59 /* FTreeSortedDictionaryTests.m */,
@@ -1903,31 +2298,31 @@
isa = PBXGroup;
children = (
DE7B8D781E8EF202009EB6DF /* FDevice.h */,
- DE7B8D791E8EF202009EB6DF /* FDevice.m */,
DE7B8D7A1E8EF202009EB6DF /* FEventTester.h */,
- DE7B8D7B1E8EF202009EB6DF /* FEventTester.m */,
063CB47D1EBA7AEF00038A59 /* FIRFakeApp.h */,
- 063CB47E1EBA7AEF00038A59 /* FIRFakeApp.m */,
DE7B8D7C1E8EF202009EB6DF /* FIRTestAuthTokenProvider.h */,
- DE7B8D7D1E8EF202009EB6DF /* FIRTestAuthTokenProvider.m */,
DE7B8D7E1E8EF202009EB6DF /* FMockStorageEngine.h */,
- DE7B8D7F1E8EF202009EB6DF /* FMockStorageEngine.m */,
DE7B8D801E8EF202009EB6DF /* FTestAuthTokenGenerator.h */,
- DE7B8D811E8EF202009EB6DF /* FTestAuthTokenGenerator.m */,
063CB4591EBA7AE200038A59 /* FTestBase.h */,
- 063CB45A1EBA7AE200038A59 /* FTestBase.m */,
DE7B8D821E8EF202009EB6DF /* FTestCachePolicy.h */,
- DE7B8D831E8EF202009EB6DF /* FTestCachePolicy.m */,
DE7B8D841E8EF202009EB6DF /* FTestClock.h */,
- DE7B8D851E8EF202009EB6DF /* FTestClock.m */,
063CB48D1EBA7AEF00038A59 /* FTestContants.h */,
DE7B8D861E8EF202009EB6DF /* FTestExpectations.h */,
- DE7B8D871E8EF202009EB6DF /* FTestExpectations.m */,
DE7B8D881E8EF202009EB6DF /* FTestHelpers.h */,
- DE7B8D891E8EF202009EB6DF /* FTestHelpers.m */,
DE7B8D8A1E8EF203009EB6DF /* FTupleEventTypeString.h */,
- DE7B8D8B1E8EF203009EB6DF /* FTupleEventTypeString.m */,
DE7B8D8C1E8EF203009EB6DF /* SenTest+FWaiter.h */,
+ DE7B8D791E8EF202009EB6DF /* FDevice.m */,
+ DE7B8D7B1E8EF202009EB6DF /* FEventTester.m */,
+ 063CB47E1EBA7AEF00038A59 /* FIRFakeApp.m */,
+ DE7B8D7D1E8EF202009EB6DF /* FIRTestAuthTokenProvider.m */,
+ DE7B8D7F1E8EF202009EB6DF /* FMockStorageEngine.m */,
+ DE7B8D811E8EF202009EB6DF /* FTestAuthTokenGenerator.m */,
+ 063CB45A1EBA7AE200038A59 /* FTestBase.m */,
+ DE7B8D831E8EF202009EB6DF /* FTestCachePolicy.m */,
+ DE7B8D851E8EF202009EB6DF /* FTestClock.m */,
+ DE7B8D871E8EF202009EB6DF /* FTestExpectations.m */,
+ DE7B8D891E8EF202009EB6DF /* FTestHelpers.m */,
+ DE7B8D8B1E8EF203009EB6DF /* FTupleEventTypeString.m */,
DE7B8D8D1E8EF203009EB6DF /* SenTest+FWaiter.m */,
);
path = Helpers;
@@ -1949,6 +2344,7 @@
DE9314EC1E86C6FF0083EDBF /* App */ = {
isa = PBXGroup;
children = (
+ DE53894B1FBB635400199FC2 /* tvOS */,
DE9314F61E86C6FF0083EDBF /* GoogleService-Info.plist */,
D01853461EDACC10003A645C /* iOS */,
D01853471EDACC10003A645C /* macOS */,
@@ -1959,28 +2355,25 @@
DE9314F91E86C6FF0083EDBF /* Tests */ = {
isa = PBXGroup;
children = (
- 7E94853F1F578A9D005A3939 /* FIRAuthURLPresenterTests.m */,
- DE750DB51EB3DD4000A75E47 /* FIRAuthAPNSTokenManagerTests.m */,
- DE750DB61EB3DD4000A75E47 /* FIRAuthAPNSTokenTests.m */,
- DE750DB71EB3DD4000A75E47 /* FIRAuthAppCredentialManagerTests.m */,
- DE750DB81EB3DD4000A75E47 /* FIRAuthNotificationManagerTests.m */,
- DE0E5BB91EA7D92E00FAA825 /* FIRVerifyClientRequestTest.m */,
- DE0E5BBA1EA7D92E00FAA825 /* FIRVerifyClientResponseTests.m */,
- DE0E5BB51EA7D91C00FAA825 /* FIRAuthAppCredentialTests.m */,
- DE0E5BB61EA7D91C00FAA825 /* FIRAuthAppDelegateProxyTests.m */,
- DECE03991E9ECFF500164CA4 /* FIRPhoneAuthProviderTests.m */,
DE9314FB1E86C6FF0083EDBF /* FIRApp+FIRAuthUnitTests.h */,
DE9315091E86C6FF0083EDBF /* FIRFakeBackendRPCIssuer.h */,
DE9315231E86C6FF0083EDBF /* OCMStubRecorder+FIRAuthUnitTests.h */,
DE9314FA1E86C6FF0083EDBF /* FIRAdditionalUserInfoTests.m */,
DE9314FC1E86C6FF0083EDBF /* FIRApp+FIRAuthUnitTests.m */,
+ DE750DB51EB3DD4000A75E47 /* FIRAuthAPNSTokenManagerTests.m */,
+ DE750DB61EB3DD4000A75E47 /* FIRAuthAPNSTokenTests.m */,
+ DE750DB71EB3DD4000A75E47 /* FIRAuthAppCredentialManagerTests.m */,
+ DE0E5BB51EA7D91C00FAA825 /* FIRAuthAppCredentialTests.m */,
+ DE0E5BB61EA7D91C00FAA825 /* FIRAuthAppDelegateProxyTests.m */,
DE9314FD1E86C6FF0083EDBF /* FIRAuthBackendCreateAuthURITests.m */,
DE9314FE1E86C6FF0083EDBF /* FIRAuthBackendRPCImplementationTests.m */,
DE9314FF1E86C6FF0083EDBF /* FIRAuthDispatcherTests.m */,
DE9315001E86C6FF0083EDBF /* FIRAuthGlobalWorkQueueTests.m */,
DE9315011E86C6FF0083EDBF /* FIRAuthKeychainTests.m */,
+ DE750DB81EB3DD4000A75E47 /* FIRAuthNotificationManagerTests.m */,
DE9315021E86C6FF0083EDBF /* FIRAuthSerialTaskQueueTests.m */,
DE9315031E86C6FF0083EDBF /* FIRAuthTests.m */,
+ 7E94853F1F578A9D005A3939 /* FIRAuthURLPresenterTests.m */,
DE9315041E86C6FF0083EDBF /* FIRAuthUserDefaultsStorageTests.m */,
DE9315051E86C6FF0083EDBF /* FIRCreateAuthURIRequestTests.m */,
DE9315061E86C6FF0083EDBF /* FIRCreateAuthURIResponseTests.m */,
@@ -1994,6 +2387,7 @@
D92C82C61F578DF000D5EAFF /* FIRGetProjectConfigRequestTests.m */,
D92C82C51F578DF000D5EAFF /* FIRGetProjectConfigResponseTests.m */,
DE93150F1E86C6FF0083EDBF /* FIRGitHubAuthProviderTests.m */,
+ DECE03991E9ECFF500164CA4 /* FIRPhoneAuthProviderTests.m */,
DE9315111E86C6FF0083EDBF /* FIRResetPasswordRequestTests.m */,
DE9315121E86C6FF0083EDBF /* FIRResetPasswordResponseTests.m */,
DE9315131E86C6FF0083EDBF /* FIRSendVerificationCodeRequestTests.m */,
@@ -2003,9 +2397,12 @@
DE9315171E86C6FF0083EDBF /* FIRSignUpNewUserRequestTests.m */,
DE9315181E86C6FF0083EDBF /* FIRSignUpNewUserResponseTests.m */,
DE9315191E86C6FF0083EDBF /* FIRTwitterAuthProviderTests.m */,
+ 7EFA2E031F71C93300DD354F /* FIRUserMetadataTests.m */,
DE93151A1E86C6FF0083EDBF /* FIRUserTests.m */,
DE93151B1E86C6FF0083EDBF /* FIRVerifyAssertionRequestTests.m */,
DE93151C1E86C6FF0083EDBF /* FIRVerifyAssertionResponseTests.m */,
+ DE0E5BB91EA7D92E00FAA825 /* FIRVerifyClientRequestTest.m */,
+ DE0E5BBA1EA7D92E00FAA825 /* FIRVerifyClientResponseTests.m */,
DE93151D1E86C6FF0083EDBF /* FIRVerifyCustomTokenRequestTests.m */,
DE93151E1E86C6FF0083EDBF /* FIRVerifyCustomTokenResponseTests.m */,
DE93151F1E86C6FF0083EDBF /* FIRVerifyPasswordRequestTest.m */,
@@ -2014,7 +2411,6 @@
DE9315221E86C6FF0083EDBF /* FIRVerifyPhoneNumberResponseTests.m */,
DE9315241E86C6FF0083EDBF /* OCMStubRecorder+FIRAuthUnitTests.m */,
DE9315251E86C6FF0083EDBF /* Tests-Info.plist */,
- 7EFA2E031F71C93300DD354F /* FIRUserMetadataTests.m */,
);
path = Tests;
sourceTree = "<group>";
@@ -2058,6 +2454,36 @@
path = Tests;
sourceTree = "<group>";
};
+ DEAAD3B31FBA1CD80053BF48 /* tvOS */ = {
+ isa = PBXGroup;
+ children = (
+ DEAAD3D21FBA1F850053BF48 /* Main.storyboard */,
+ DEAAD3C61FBA1EF90053BF48 /* AppDelegate.h */,
+ DEAAD3C81FBA1EFA0053BF48 /* AppDelegate.m */,
+ DEAAD3C51FBA1EF90053BF48 /* Assets.xcassets */,
+ DEAAD3C41FBA1EF90053BF48 /* Info.plist */,
+ DEAAD3C71FBA1EF90053BF48 /* ViewController.h */,
+ DEAAD3C91FBA1EFA0053BF48 /* ViewController.m */,
+ DEAAD3BD1FBA1CD80053BF48 /* main.m */,
+ );
+ path = tvOS;
+ sourceTree = "<group>";
+ };
+ DEAAD4111FBA470A0053BF48 /* tvOS */ = {
+ isa = PBXGroup;
+ children = (
+ DEAAD4121FBA470A0053BF48 /* AppDelegate.h */,
+ DEAAD4131FBA470A0053BF48 /* AppDelegate.m */,
+ DEAAD4141FBA470A0053BF48 /* Assets.xcassets */,
+ DEAAD4151FBA470A0053BF48 /* Info.plist */,
+ DEAAD4161FBA470A0053BF48 /* main.m */,
+ DEAAD4171FBA470A0053BF48 /* Main.storyboard */,
+ DEAAD4181FBA470A0053BF48 /* ViewController.h */,
+ DEAAD4191FBA470A0053BF48 /* ViewController.m */,
+ );
+ path = tvOS;
+ sourceTree = "<group>";
+ };
DEB139B31E734D9D00AC236D /* Storage */ = {
isa = PBXGroup;
children = (
@@ -2080,6 +2506,7 @@
DEB61EB81E7C5DBB00C04B96 /* App */ = {
isa = PBXGroup;
children = (
+ DEAAD4111FBA470A0053BF48 /* tvOS */,
069428801EC3B35A00F7BC69 /* 1mb.dat */,
DEB61EC11E7C5DBB00C04B96 /* GoogleService-Info.plist */,
D0EDB2BA1EDA041900B6C31B /* iOS */,
@@ -2110,6 +2537,7 @@
DEE14D671E844677006FA992 /* App */ = {
isa = PBXGroup;
children = (
+ DEAAD3B31FBA1CD80053BF48 /* tvOS */,
DEE14D711E844677006FA992 /* GoogleService-Info.plist */,
D0D857F71ED9ADAE002342D2 /* macOS */,
D0D857F61ED9ADA8002342D2 /* iOS */,
@@ -2140,13 +2568,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 06121EC51EC399C50008D70E /* Build configuration list for PBXNativeTarget "Storage_IntegrationTests_iOS" */;
buildPhases = (
- C6DD8EA209B18D8651337E5A /* [CP] Check Pods Manifest.lock */,
+ F9006262CA0804846FE05F99 /* [CP] Check Pods Manifest.lock */,
06121EB81EC399C50008D70E /* Sources */,
06121EB91EC399C50008D70E /* Frameworks */,
06121EBA1EC399C50008D70E /* Resources */,
D090053C1EDB334800154410 /* CopyFiles */,
- D57035FA9DBD9B5C6F7E44BB /* [CP] Embed Pods Frameworks */,
- E4CD99103647D7D03D05576E /* [CP] Copy Pods Resources */,
+ E6E7FCA58951222D1403093F /* [CP] Embed Pods Frameworks */,
+ BCFDF9E24063519540D27F43 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2162,13 +2590,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 0624F3E81EC0ECFA00E5940D /* Build configuration list for PBXNativeTarget "Database_IntegrationTests_iOS" */;
buildPhases = (
- 964A6DD602ABD81ABDE945E1 /* [CP] Check Pods Manifest.lock */,
+ FC761FD2D605CBA0F9693A16 /* [CP] Check Pods Manifest.lock */,
0624F3DD1EC0ECFA00E5940D /* Sources */,
0624F3DE1EC0ECFA00E5940D /* Frameworks */,
0624F3DF1EC0ECFA00E5940D /* Resources */,
D09005361EDB331700154410 /* CopyFiles */,
- 2429BCE77F52A3CA917EBAD3 /* [CP] Embed Pods Frameworks */,
- BC5C8E9DA5ECC9095376EEFC /* [CP] Copy Pods Resources */,
+ 396062F8EC21600F2A1A832A /* [CP] Embed Pods Frameworks */,
+ DF698E6810C50B85FC20ABCC /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2184,12 +2612,12 @@
isa = PBXNativeTarget;
buildConfigurationList = AFD562F41EB13C6D00EA2233 /* Build configuration list for PBXNativeTarget "Messaging_Example_iOS" */;
buildPhases = (
- 4F7410B194A68B6D9F9D1C23 /* [CP] Check Pods Manifest.lock */,
+ 6692936359478B80897B1771 /* [CP] Check Pods Manifest.lock */,
AFD562E11EB13C6D00EA2233 /* Sources */,
AFD562E21EB13C6D00EA2233 /* Frameworks */,
AFD562E31EB13C6D00EA2233 /* Resources */,
- E14B732B18AC2D43E964F013 /* [CP] Embed Pods Frameworks */,
- CB265192F117EE5B7B6A90F3 /* [CP] Copy Pods Resources */,
+ CD18801A135756D44CE31E8C /* [CP] Embed Pods Frameworks */,
+ DA5D35B2E947885B7B9A8FCA /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2204,12 +2632,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D01853761EDAD084003A645C /* Build configuration list for PBXNativeTarget "Auth_Example_macOS" */;
buildPhases = (
- BD09C44595A6ECBB8FA2350D /* [CP] Check Pods Manifest.lock */,
+ 88B701F1A289EED5913CB89F /* [CP] Check Pods Manifest.lock */,
D01853691EDAD084003A645C /* Sources */,
D018536D1EDAD084003A645C /* Frameworks */,
D018536F1EDAD084003A645C /* Resources */,
- 61ED313363F4BDC7657BD2EE /* [CP] Embed Pods Frameworks */,
- 547E7E1564F7C15525BE1E84 /* [CP] Copy Pods Resources */,
+ 7AED28FFDB4538097571CAB0 /* [CP] Embed Pods Frameworks */,
+ A690931685428A81DB3D7318 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2224,12 +2652,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D01853C31EDAD364003A645C /* Build configuration list for PBXNativeTarget "Auth_Tests_macOS" */;
buildPhases = (
- 38CF5DFC135922889EC15A84 /* [CP] Check Pods Manifest.lock */,
+ 61833A6B418B3CF211027415 /* [CP] Check Pods Manifest.lock */,
D018538C1EDAD364003A645C /* Sources */,
D01853BD1EDAD364003A645C /* Frameworks */,
D01853C01EDAD364003A645C /* Resources */,
- 2144CF65BA13A617A6510316 /* [CP] Embed Pods Frameworks */,
- 68EBBBF8D47F1A4548F5F8A1 /* [CP] Copy Pods Resources */,
+ AD0431F92777A7C0529C761E /* [CP] Embed Pods Frameworks */,
+ D61AD5162C75965358E153F2 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2245,12 +2673,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D064E6A71ED9B1BF001956DF /* Build configuration list for PBXNativeTarget "Core_Example_macOS" */;
buildPhases = (
- 1BC0F30C28D9EDC8E02C0412 /* [CP] Check Pods Manifest.lock */,
+ 0B68B6F63D8D76A56DFE38F3 /* [CP] Check Pods Manifest.lock */,
D064E6921ED9B1BF001956DF /* Sources */,
D064E6931ED9B1BF001956DF /* Frameworks */,
D064E6941ED9B1BF001956DF /* Resources */,
- 062EEAC29DE0575BF611178E /* [CP] Embed Pods Frameworks */,
- 952D8E3BC2A768AF99B029D4 /* [CP] Copy Pods Resources */,
+ CCADF8C25FBA174357AEA0CE /* [CP] Embed Pods Frameworks */,
+ EB4045893AE0E69BB38780B1 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2265,12 +2693,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D064E6BC1ED9B31C001956DF /* Build configuration list for PBXNativeTarget "Core_Tests_macOS" */;
buildPhases = (
- 24BCD9BFDB0623B2BA73098C /* [CP] Check Pods Manifest.lock */,
+ EDDC22912C046AB4349E45D5 /* [CP] Check Pods Manifest.lock */,
D064E6AE1ED9B31C001956DF /* Sources */,
D064E6B61ED9B31C001956DF /* Frameworks */,
D064E6B91ED9B31C001956DF /* Resources */,
- 7ADF89772D7C70DB74EF0384 /* [CP] Embed Pods Frameworks */,
- FFAC5DC18B783B814EF2DAB5 /* [CP] Copy Pods Resources */,
+ A4A70B0E20C6A874C668B261 /* [CP] Embed Pods Frameworks */,
+ AE504E2BAD5B3581FC1898CA /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2286,12 +2714,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D0EDB2CA1EDA04F800B6C31B /* Build configuration list for PBXNativeTarget "Storage_Example_macOS" */;
buildPhases = (
- 00DF54E18B7F0C37010CF5C6 /* [CP] Check Pods Manifest.lock */,
+ C56FA5154BF616EA6F457108 /* [CP] Check Pods Manifest.lock */,
D0EDB2BE1EDA04F800B6C31B /* Sources */,
D0EDB2C21EDA04F800B6C31B /* Frameworks */,
D0EDB2C41EDA04F800B6C31B /* Resources */,
- E1EF4640668E42876CD0680B /* [CP] Embed Pods Frameworks */,
- DE3BC872B0631D9222625218 /* [CP] Copy Pods Resources */,
+ FE4106FE85FE9310554CF15A /* [CP] Embed Pods Frameworks */,
+ 5D1C5017F0B7B68B15BDD714 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2306,12 +2734,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D0EDB2F31EDA06CB00B6C31B /* Build configuration list for PBXNativeTarget "Storage_Tests_macOS" */;
buildPhases = (
- 9F9A46A840E3517985F97BF7 /* [CP] Check Pods Manifest.lock */,
+ 8A0408EE425E76C47C98D3D3 /* [CP] Check Pods Manifest.lock */,
D0EDB2E21EDA06CB00B6C31B /* Sources */,
D0EDB2ED1EDA06CB00B6C31B /* Frameworks */,
D0EDB2F01EDA06CB00B6C31B /* Resources */,
- 13C0A425999DC1AFAAFA85A2 /* [CP] Embed Pods Frameworks */,
- DC8467211F158C333D6E1851 /* [CP] Copy Pods Resources */,
+ 00C23492EFA7628C002D2287 /* [CP] Embed Pods Frameworks */,
+ F106DC91C54784AD9F5963D5 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2327,12 +2755,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D0EDB3041EDA06D500B6C31B /* Build configuration list for PBXNativeTarget "Storage_IntegrationTests_macOS" */;
buildPhases = (
- 80A283F697210020814F3349 /* [CP] Check Pods Manifest.lock */,
+ 36ECFC3EE140707B7C96FAFC /* [CP] Check Pods Manifest.lock */,
D0EDB2FC1EDA06D500B6C31B /* Sources */,
D0EDB2FE1EDA06D500B6C31B /* Frameworks */,
D0EDB3011EDA06D500B6C31B /* Resources */,
- 7EF78DCE613E776ECD9373C2 /* [CP] Embed Pods Frameworks */,
- 8263B27A42441EB177C87183 /* [CP] Copy Pods Resources */,
+ C826D2B941653E5EEEBE569D /* [CP] Embed Pods Frameworks */,
+ 9F60468168975372B533A4DF /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2348,12 +2776,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D0FE8A2C1ED9C804003F6722 /* Build configuration list for PBXNativeTarget "Database_Example_macOS" */;
buildPhases = (
- 08057DD8B44996A54EB74007 /* [CP] Check Pods Manifest.lock */,
+ FCAE72CAEA7047E5BC17A115 /* [CP] Check Pods Manifest.lock */,
D0FE8A201ED9C804003F6722 /* Sources */,
D0FE8A241ED9C804003F6722 /* Frameworks */,
D0FE8A261ED9C804003F6722 /* Resources */,
- EBD8971C0B3B5BCDA5F5EA9F /* [CP] Embed Pods Frameworks */,
- 89FC9C3CF79117EF07001272 /* [CP] Copy Pods Resources */,
+ 43F27469966E52E9FB44955E /* [CP] Embed Pods Frameworks */,
+ AFD8FCED83B8C2B69BC89591 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2368,12 +2796,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D0FE8A5F1ED9C86F003F6722 /* Build configuration list for PBXNativeTarget "Database_Tests_macOS" */;
buildPhases = (
- 83EC34B122E68BACA199C8BD /* [CP] Check Pods Manifest.lock */,
+ F58DF2B67102DFA67481CE7C /* [CP] Check Pods Manifest.lock */,
D0FE8A351ED9C86F003F6722 /* Sources */,
D0FE8A561ED9C86F003F6722 /* Frameworks */,
D0FE8A591ED9C86F003F6722 /* Resources */,
- B5D70414394DD066BE115ED8 /* [CP] Embed Pods Frameworks */,
- 8AC1F8EDC83D64A46940EA1F /* [CP] Copy Pods Resources */,
+ BAB96787C60CED3387854011 /* [CP] Embed Pods Frameworks */,
+ ED383603B7B5D4C03055E2A7 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2389,12 +2817,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D0FE8A891ED9C87B003F6722 /* Build configuration list for PBXNativeTarget "Database_IntegrationTests_macOS" */;
buildPhases = (
- 1D62AD16C337F524407C8EBF /* [CP] Check Pods Manifest.lock */,
+ A276E28C6BE15473C08F46C7 /* [CP] Check Pods Manifest.lock */,
D0FE8A681ED9C87B003F6722 /* Sources */,
D0FE8A831ED9C87B003F6722 /* Frameworks */,
D0FE8A861ED9C87B003F6722 /* Resources */,
- 3261343A30C97057EDCB6749 /* [CP] Embed Pods Frameworks */,
- 2D6499C61F0A16EE67985F35 /* [CP] Copy Pods Resources */,
+ 338DBAF509A5E9D092818DA2 /* [CP] Embed Pods Frameworks */,
+ 637BF15D486ACD0789DBBC68 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2406,16 +2834,77 @@
productReference = D0FE8A8C1ED9C87B003F6722 /* Database_IntegrationTests_macOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
+ DE1CD5961FBA55AF00FC031E /* Database_Example_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DE1CD5B61FBA55B000FC031E /* Build configuration list for PBXNativeTarget "Database_Example_tvOS" */;
+ buildPhases = (
+ 86C0D3C6E5D05FBBCA3CE8BF /* [CP] Check Pods Manifest.lock */,
+ DE1CD5931FBA55AF00FC031E /* Sources */,
+ DE1CD5941FBA55AF00FC031E /* Frameworks */,
+ DE1CD5951FBA55AF00FC031E /* Resources */,
+ D424AD0375A67F11DDF83CBB /* [CP] Embed Pods Frameworks */,
+ B133AB611E38B0B6695DF763 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Database_Example_tvOS;
+ productName = Database_Example_tvOS;
+ productReference = DE1CD5971FBA55AF00FC031E /* Database_Example_tvOS.app */;
+ productType = "com.apple.product-type.application";
+ };
+ DE1EC27E1FBA5E63007D18D8 /* Database_Tests_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DE1EC2861FBA5E63007D18D8 /* Build configuration list for PBXNativeTarget "Database_Tests_tvOS" */;
+ buildPhases = (
+ 7719F31E8BEEE94528B0B560 /* [CP] Check Pods Manifest.lock */,
+ DE1EC27B1FBA5E63007D18D8 /* Sources */,
+ DE1EC27C1FBA5E63007D18D8 /* Frameworks */,
+ DE1EC27D1FBA5E63007D18D8 /* Resources */,
+ 4AF5573D7DF12FD1D0C88A1A /* [CP] Embed Pods Frameworks */,
+ AFD2E6B7DB258E48009217D8 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ DE1EC2851FBA5E63007D18D8 /* PBXTargetDependency */,
+ );
+ name = Database_Tests_tvOS;
+ productName = Database_Tests_tvOS;
+ productReference = DE1EC27F1FBA5E63007D18D8 /* Database_Tests_tvOS.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ DE1FAE8F1FBCF5E100897AAA /* Auth_Example_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DE1FAEAB1FBCF5E200897AAA /* Build configuration list for PBXNativeTarget "Auth_Example_tvOS" */;
+ buildPhases = (
+ 2B2A8711B6CC7353ECA108F0 /* [CP] Check Pods Manifest.lock */,
+ DE1FAE8C1FBCF5E100897AAA /* Sources */,
+ DE1FAE8D1FBCF5E100897AAA /* Frameworks */,
+ DE1FAE8E1FBCF5E100897AAA /* Resources */,
+ F047DE7DFD8E3EFA65677278 /* [CP] Embed Pods Frameworks */,
+ 9CE7A87FC2C9C68B0C58E63B /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Auth_Example_tvOS;
+ productName = Auth_Example_tvOS;
+ productReference = DE1FAE901FBCF5E100897AAA /* Auth_Example_tvOS.app */;
+ productType = "com.apple.product-type.application";
+ };
DE26D22D1F70398A004AE1D3 /* Auth_Sample */ = {
isa = PBXNativeTarget;
buildConfigurationList = DE26D2411F70398A004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_Sample" */;
buildPhases = (
- 2F058EA64448194D0606AF43 /* [CP] Check Pods Manifest.lock */,
+ C24F5282192B81B6A39BAEB8 /* [CP] Check Pods Manifest.lock */,
DE26D22A1F70398A004AE1D3 /* Sources */,
DE26D22B1F70398A004AE1D3 /* Frameworks */,
DE26D22C1F70398A004AE1D3 /* Resources */,
- C4CB228F9FBF834637FDD550 /* [CP] Embed Pods Frameworks */,
- 7C60623F83982B8C98AD8A03 /* [CP] Copy Pods Resources */,
+ 08957B7A79C276AF1C031ED1 /* [CP] Embed Pods Frameworks */,
+ 6A17F5D59D7B838BFBBFAE93 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2430,12 +2919,12 @@
isa = PBXNativeTarget;
buildConfigurationList = DE26D2641F7049F1004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_ApiTests" */;
buildPhases = (
- 94DE13FC01F4BCC0A3AA92B8 /* [CP] Check Pods Manifest.lock */,
+ 9CAEF4F03D2C87AED96E87B8 /* [CP] Check Pods Manifest.lock */,
DE26D2591F7049F1004AE1D3 /* Sources */,
DE26D25A1F7049F1004AE1D3 /* Frameworks */,
DE26D25B1F7049F1004AE1D3 /* Resources */,
- 3EC098CF0777B0916DAB8AE7 /* [CP] Embed Pods Frameworks */,
- 418D23667D638E23FC6765B0 /* [CP] Copy Pods Resources */,
+ DF29C4F0F86D60F7FEE583F8 /* [CP] Embed Pods Frameworks */,
+ 118E42BDF843B8E5AFF716A0 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2451,12 +2940,12 @@
isa = PBXNativeTarget;
buildConfigurationList = DE26D2741F705C35004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_EarlGreyTests" */;
buildPhases = (
- B6C7305ECEA2DA69869E3199 /* [CP] Check Pods Manifest.lock */,
+ B6EF8098F3C4BB08D7BED9D8 /* [CP] Check Pods Manifest.lock */,
DE26D2691F705C35004AE1D3 /* Sources */,
DE26D26A1F705C35004AE1D3 /* Frameworks */,
DE26D26B1F705C35004AE1D3 /* Resources */,
- F5B5EF87DFA0131455579138 /* [CP] Embed Pods Frameworks */,
- EB62267583A8460DAF576DF9 /* [CP] Copy Pods Resources */,
+ 1611FB715EC5341B0397BD41 /* [CP] Embed Pods Frameworks */,
+ 08648163FCEA26546E5E8E35 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2472,12 +2961,12 @@
isa = PBXNativeTarget;
buildConfigurationList = DE26D28C1F705EC7004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_SwiftSample" */;
buildPhases = (
- 2A3CED73D6CF971623B65B11 /* [CP] Check Pods Manifest.lock */,
+ C85C84FF7518F64284384825 /* [CP] Check Pods Manifest.lock */,
DE26D2791F705EC7004AE1D3 /* Sources */,
DE26D27A1F705EC7004AE1D3 /* Frameworks */,
DE26D27B1F705EC7004AE1D3 /* Resources */,
- A397E143BFA2B54BBA78DB27 /* [CP] Embed Pods Frameworks */,
- DC71E8C018300A993E541683 /* [CP] Copy Pods Resources */,
+ 8B622E883C1CC4C26C0BB9A9 /* [CP] Embed Pods Frameworks */,
+ 2F08B0B91519AEB1E81960AB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2488,16 +2977,37 @@
productReference = DE26D27D1F705EC7004AE1D3 /* SwiftSample.app */;
productType = "com.apple.product-type.application";
};
+ DE53893D1FBB62E100199FC2 /* Auth_Tests_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DE5389491FBB62E100199FC2 /* Build configuration list for PBXNativeTarget "Auth_Tests_tvOS" */;
+ buildPhases = (
+ 6A332C7CB67CF7FF26296EF9 /* [CP] Check Pods Manifest.lock */,
+ DE53893A1FBB62E100199FC2 /* Sources */,
+ DE53893B1FBB62E100199FC2 /* Frameworks */,
+ DE53893C1FBB62E100199FC2 /* Resources */,
+ 94E5426439D34EF38E3A1C61 /* [CP] Embed Pods Frameworks */,
+ 2B9C5A21D0CCD50D254D6CFE /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ DE1E3B311FEB1E7600EAEBB0 /* PBXTargetDependency */,
+ );
+ name = Auth_Tests_tvOS;
+ productName = Auth_Example_tvOSTests;
+ productReference = DE53893E1FBB62E100199FC2 /* Auth_Tests_tvOS.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
DE7B8D041E8EF077009EB6DF /* Database_Example_iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = DE7B8D281E8EF078009EB6DF /* Build configuration list for PBXNativeTarget "Database_Example_iOS" */;
buildPhases = (
- 4B926E79AD9E0016DDA7FBF8 /* [CP] Check Pods Manifest.lock */,
+ EF45D0D217BDEA5CEB66E5C2 /* [CP] Check Pods Manifest.lock */,
DE7B8D011E8EF077009EB6DF /* Sources */,
DE7B8D021E8EF077009EB6DF /* Frameworks */,
DE7B8D031E8EF077009EB6DF /* Resources */,
- 7F7E65CEFB1C184D69448404 /* [CP] Embed Pods Frameworks */,
- B5724E5E5CB63BD5B738C4F6 /* [CP] Copy Pods Resources */,
+ 120796D59D14DFEBCB083458 /* [CP] Embed Pods Frameworks */,
+ BFCC067E4DA198D538DC3FDF /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2512,13 +3022,13 @@
isa = PBXNativeTarget;
buildConfigurationList = DE7B8D291E8EF078009EB6DF /* Build configuration list for PBXNativeTarget "Database_Tests_iOS" */;
buildPhases = (
- FF06F317B2790040C6157248 /* [CP] Check Pods Manifest.lock */,
+ 28757E7372E5CA218910628A /* [CP] Check Pods Manifest.lock */,
DE7B8D191E8EF078009EB6DF /* Sources */,
DE7B8D1A1E8EF078009EB6DF /* Frameworks */,
DE7B8D1B1E8EF078009EB6DF /* Resources */,
D09005341EDB330800154410 /* CopyFiles */,
- 2F2E08FC97C14E7EDDB8D804 /* [CP] Embed Pods Frameworks */,
- 91ED54292706C89DEAF738F0 /* [CP] Copy Pods Resources */,
+ ADB10E4C6A62992C15EE9BB4 /* [CP] Embed Pods Frameworks */,
+ 348348A57D424FA907702088 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2534,12 +3044,12 @@
isa = PBXNativeTarget;
buildConfigurationList = DE9314E91E86C6BE0083EDBF /* Build configuration list for PBXNativeTarget "Auth_Example_iOS" */;
buildPhases = (
- 2BE22FBF4B4647B6AF2A58D2 /* [CP] Check Pods Manifest.lock */,
+ 65E833A6A4000F0B79837D3D /* [CP] Check Pods Manifest.lock */,
DE9314C21E86C6BD0083EDBF /* Sources */,
DE9314C31E86C6BD0083EDBF /* Frameworks */,
DE9314C41E86C6BD0083EDBF /* Resources */,
- C0BB541B4E2E4188148B74BF /* [CP] Embed Pods Frameworks */,
- 3F2AF12006B4163F0BCBD5E2 /* [CP] Copy Pods Resources */,
+ 17495ED3CB98F3496DADEE40 /* [CP] Embed Pods Frameworks */,
+ 55A9CDE9471333A1DEEC2DC6 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2554,13 +3064,13 @@
isa = PBXNativeTarget;
buildConfigurationList = DE9314EA1E86C6BE0083EDBF /* Build configuration list for PBXNativeTarget "Auth_Tests_iOS" */;
buildPhases = (
- C981CB657374F18444683DDE /* [CP] Check Pods Manifest.lock */,
+ 17A106649075278BE816501D /* [CP] Check Pods Manifest.lock */,
DE9314DA1E86C6BE0083EDBF /* Sources */,
DE9314DB1E86C6BE0083EDBF /* Frameworks */,
DE9314DC1E86C6BE0083EDBF /* Resources */,
D090052F1EDB32B700154410 /* CopyFiles */,
- 8489BA940D280D954CF784DF /* [CP] Embed Pods Frameworks */,
- 194262A69E6C961D8D1888EB /* [CP] Copy Pods Resources */,
+ C70080AEF1AD5B5BB73542BF /* [CP] Embed Pods Frameworks */,
+ 3E73D0EE3702B20C522EB737 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2576,13 +3086,13 @@
isa = PBXNativeTarget;
buildConfigurationList = DE9315B31E8738460083EDBF /* Build configuration list for PBXNativeTarget "Messaging_Tests_iOS" */;
buildPhases = (
- 310F0C6DEC04131DD5D31B3C /* [CP] Check Pods Manifest.lock */,
+ 273510C286ECD5E359B6159E /* [CP] Check Pods Manifest.lock */,
DE9315A31E8738460083EDBF /* Sources */,
DE9315A41E8738460083EDBF /* Frameworks */,
DE9315A51E8738460083EDBF /* Resources */,
D09005381EDB333700154410 /* CopyFiles */,
- D736CA94F00AB417403CEC0D /* [CP] Embed Pods Frameworks */,
- 55298685299C7889EDDFF818 /* [CP] Copy Pods Resources */,
+ 997D0D4345B2BFC675DD3992 /* [CP] Embed Pods Frameworks */,
+ 96AC317066A0285BEC8B0E20 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2594,16 +3104,98 @@
productReference = DE9315A71E8738460083EDBF /* Messaging_Tests_iOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
+ DEAAD3801FBA11270053BF48 /* Core_Example_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DEAAD3A01FBA11280053BF48 /* Build configuration list for PBXNativeTarget "Core_Example_tvOS" */;
+ buildPhases = (
+ CFD020C48DD8D50E846F5F60 /* [CP] Check Pods Manifest.lock */,
+ DEAAD37D1FBA11270053BF48 /* Sources */,
+ DEAAD37E1FBA11270053BF48 /* Frameworks */,
+ DEAAD37F1FBA11270053BF48 /* Resources */,
+ 500A4C39D7949908D7E96FE6 /* [CP] Embed Pods Frameworks */,
+ C543D8A8F6950A4301C0D644 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Core_Example_tvOS;
+ productName = Core_Example_tvOS;
+ productReference = DEAAD3811FBA11270053BF48 /* Core_Example_tvOS.app */;
+ productType = "com.apple.product-type.application";
+ };
+ DEAAD3941FBA11270053BF48 /* Core_Tests_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DEAAD3A11FBA11280053BF48 /* Build configuration list for PBXNativeTarget "Core_Tests_tvOS" */;
+ buildPhases = (
+ 955CEE0E05C6781D75206EE4 /* [CP] Check Pods Manifest.lock */,
+ DEAAD3911FBA11270053BF48 /* Sources */,
+ DEAAD3921FBA11270053BF48 /* Frameworks */,
+ DEAAD3931FBA11270053BF48 /* Resources */,
+ 45C79B78C5B731142D5E1AC1 /* [CP] Embed Pods Frameworks */,
+ 6EC13D506E425EB20A7843D8 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ DEAAD3971FBA11280053BF48 /* PBXTargetDependency */,
+ );
+ name = Core_Tests_tvOS;
+ productName = Core_Example_tvOSTests;
+ productReference = DEAAD3951FBA11270053BF48 /* Core_Tests_tvOS.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ DEAAD3E01FBA46AA0053BF48 /* Storage_Example_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DEAAD4001FBA46AB0053BF48 /* Build configuration list for PBXNativeTarget "Storage_Example_tvOS" */;
+ buildPhases = (
+ 8E51FDDF5CDC6B3B42AE8735 /* [CP] Check Pods Manifest.lock */,
+ DEAAD3DD1FBA46AA0053BF48 /* Sources */,
+ DEAAD3DE1FBA46AA0053BF48 /* Frameworks */,
+ DEAAD3DF1FBA46AA0053BF48 /* Resources */,
+ 35E3827DC5E63EE2D7302B65 /* [CP] Embed Pods Frameworks */,
+ A6DC1E378B43295245C5C1DA /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Storage_Example_tvOS;
+ productName = Storage_Example_tvOS;
+ productReference = DEAAD3E11FBA46AA0053BF48 /* Storage_Example_tvOS.app */;
+ productType = "com.apple.product-type.application";
+ };
+ DEAAD3F41FBA46AB0053BF48 /* Storage_Tests_tvOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DEAAD4011FBA46AB0053BF48 /* Build configuration list for PBXNativeTarget "Storage_Tests_tvOS" */;
+ buildPhases = (
+ 40E50B2EBCE9B3E3B5E68B93 /* [CP] Check Pods Manifest.lock */,
+ DEAAD3F11FBA46AB0053BF48 /* Sources */,
+ DEAAD3F21FBA46AB0053BF48 /* Frameworks */,
+ DEAAD3F31FBA46AB0053BF48 /* Resources */,
+ 222F97AB71B243C0E8C1680C /* [CP] Embed Pods Frameworks */,
+ 76D01041B075D88EC92B58BC /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ DEAAD3F71FBA46AB0053BF48 /* PBXTargetDependency */,
+ );
+ name = Storage_Tests_tvOS;
+ productName = Storage_Example_tvOSTests;
+ productReference = DEAAD3F51FBA46AB0053BF48 /* Storage_Tests_tvOS.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
DEB139E01E73506A00AC236D /* Storage_Example_iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = DEB13A051E73506A00AC236D /* Build configuration list for PBXNativeTarget "Storage_Example_iOS" */;
buildPhases = (
- 0045465B164896D3C570A79A /* [CP] Check Pods Manifest.lock */,
+ 6412AADCC147925DABCBB905 /* [CP] Check Pods Manifest.lock */,
DEB139E21E73506A00AC236D /* Sources */,
DEB139F31E73506A00AC236D /* Frameworks */,
DEB139F91E73506A00AC236D /* Resources */,
- 9DDF848892C1B2DCE343D139 /* [CP] Embed Pods Frameworks */,
- 776FB063FB216F38E91EC8A1 /* [CP] Copy Pods Resources */,
+ E24428AEED98846FAEE3A892 /* [CP] Embed Pods Frameworks */,
+ 93AB0EF8AA5A4C48546D60A7 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2618,13 +3210,13 @@
isa = PBXNativeTarget;
buildConfigurationList = DEB13A201E73507E00AC236D /* Build configuration list for PBXNativeTarget "Storage_Tests_iOS" */;
buildPhases = (
- C0894681AFF0FF07CE891310 /* [CP] Check Pods Manifest.lock */,
+ 22CEBCEDBAD96E384B598C36 /* [CP] Check Pods Manifest.lock */,
DEB13A0E1E73507E00AC236D /* Sources */,
DEB13A161E73507E00AC236D /* Frameworks */,
DEB13A1D1E73507E00AC236D /* Resources */,
D090053A1EDB334000154410 /* CopyFiles */,
- 5355975898496CD7FF7DD106 /* [CP] Embed Pods Frameworks */,
- B57C4BF2A720187D5DF4C848 /* [CP] Copy Pods Resources */,
+ 436A2DE8B1C36C53FCED6019 /* [CP] Embed Pods Frameworks */,
+ 267B6FB90F537E2C78FA1629 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2640,12 +3232,12 @@
isa = PBXNativeTarget;
buildConfigurationList = DEDFEFF51FD1B8C100F7D466 /* Build configuration list for PBXNativeTarget "Analytics_Tests_iOS" */;
buildPhases = (
- E3A92F1E7F7F65ACF2BCEC78 /* [CP] Check Pods Manifest.lock */,
+ 9C3034A423FA21B0E3500BF9 /* [CP] Check Pods Manifest.lock */,
DEDFEFE81FD1B8C100F7D466 /* Sources */,
DEDFEFE91FD1B8C100F7D466 /* Frameworks */,
DEDFEFEA1FD1B8C100F7D466 /* Resources */,
- DC31836CBCE7DE03EC932511 /* [CP] Embed Pods Frameworks */,
- D293C865CA6C9CFE510F2030 /* [CP] Copy Pods Resources */,
+ 257DF49B2BF041A67ECC0C49 /* [CP] Embed Pods Frameworks */,
+ A127C8A6500F782E73C0851A /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2661,12 +3253,12 @@
isa = PBXNativeTarget;
buildConfigurationList = DEE14D641E84464D006FA992 /* Build configuration list for PBXNativeTarget "Core_Example_iOS" */;
buildPhases = (
- 6F3682326BA63694ECB240A3 /* [CP] Check Pods Manifest.lock */,
+ 5DCF8D9FF3A9EFDF5BC1783E /* [CP] Check Pods Manifest.lock */,
DEE14D3D1E84464D006FA992 /* Sources */,
DEE14D3E1E84464D006FA992 /* Frameworks */,
DEE14D3F1E84464D006FA992 /* Resources */,
- 4AA54CBB8303130FC18C1A27 /* [CP] Embed Pods Frameworks */,
- BD7302A2861F068F5540CCA6 /* [CP] Copy Pods Resources */,
+ D0A888D2C36723C55F2BDC0C /* [CP] Embed Pods Frameworks */,
+ 066FF207F29FD1E125CDCA9B /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2681,13 +3273,13 @@
isa = PBXNativeTarget;
buildConfigurationList = DEE14D651E84464D006FA992 /* Build configuration list for PBXNativeTarget "Core_Tests_iOS" */;
buildPhases = (
- E4708A6EB45D6F7D30070DCF /* [CP] Check Pods Manifest.lock */,
+ 8DB662ACD739CD47CFC7C093 /* [CP] Check Pods Manifest.lock */,
DEE14D551E84464D006FA992 /* Sources */,
DEE14D561E84464D006FA992 /* Frameworks */,
DEE14D571E84464D006FA992 /* Resources */,
D09005321EDB32EA00154410 /* CopyFiles */,
- DBE97573DB393D723CD8CDA2 /* [CP] Embed Pods Frameworks */,
- FFBE661125B41DE1A5B115C3 /* [CP] Copy Pods Resources */,
+ C97E0BBB635D9C80C5C62D74 /* [CP] Embed Pods Frameworks */,
+ 489E82E20508C1E1BF91E7B4 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -2773,6 +3365,22 @@
D0FE8A641ED9C87B003F6722 = {
TestTargetID = D0FE8A1E1ED9C804003F6722;
};
+ DE1CD5961FBA55AF00FC031E = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ };
+ DE1EC27E1FBA5E63007D18D8 = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ TestTargetID = DE1CD5961FBA55AF00FC031E;
+ };
+ DE1FAE8F1FBCF5E100897AAA = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ };
DE26D22D1F70398A004AE1D3 = {
CreatedOnToolsVersion = 9.0;
DevelopmentTeam = EQHXZ8M8AV;
@@ -2810,6 +3418,17 @@
DevelopmentTeam = EQHXZ8M8AV;
ProvisioningStyle = Automatic;
};
+ DE53893D1FBB62E100199FC2 = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ TestTargetID = DE5389291FBB62E100199FC2;
+ };
+ DE545C7F1FBCA3F000C637AE = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ };
DE7B8D041E8EF077009EB6DF = {
CreatedOnToolsVersion = 8.3;
ProvisioningStyle = Automatic;
@@ -2834,14 +3453,34 @@
ProvisioningStyle = Automatic;
TestTargetID = AFD562E41EB13C6D00EA2233;
};
+ DEAAD3801FBA11270053BF48 = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ };
+ DEAAD3941FBA11270053BF48 = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ TestTargetID = DEAAD3801FBA11270053BF48;
+ };
+ DEAAD3E01FBA46AA0053BF48 = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ };
+ DEAAD3F41FBA46AB0053BF48 = {
+ CreatedOnToolsVersion = 9.1;
+ DevelopmentTeam = EQHXZ8M8AV;
+ ProvisioningStyle = Automatic;
+ TestTargetID = DEAAD3E01FBA46AA0053BF48;
+ };
DEB13A0A1E73507E00AC236D = {
TestTargetID = DEB139E01E73506A00AC236D;
};
DEDFEFEB1FD1B8C100F7D466 = {
- CreatedOnToolsVersion = 9.1;
DevelopmentTeam = EQHXZ8M8AV;
ProvisioningStyle = Automatic;
- TestTargetID = DEE14D401E84464D006FA992;
};
DEE14D401E84464D006FA992 = {
CreatedOnToolsVersion = 8.2.1;
@@ -2875,20 +3514,27 @@
DE9314DD1E86C6BE0083EDBF /* Auth_Tests_iOS */,
D01853671EDAD084003A645C /* Auth_Example_macOS */,
D01853881EDAD364003A645C /* Auth_Tests_macOS */,
+ DE1FAE8F1FBCF5E100897AAA /* Auth_Example_tvOS */,
+ DE53893D1FBB62E100199FC2 /* Auth_Tests_tvOS */,
DE26D22D1F70398A004AE1D3 /* Auth_Sample */,
DE26D27C1F705EC7004AE1D3 /* Auth_SwiftSample */,
DE26D25C1F7049F1004AE1D3 /* Auth_ApiTests */,
DE26D26C1F705C35004AE1D3 /* Auth_EarlGreyTests */,
+ DE26D2971F70668F004AE1D3 /* Auth_AllTests */,
DEE14D401E84464D006FA992 /* Core_Example_iOS */,
DEE14D581E84464D006FA992 /* Core_Tests_iOS */,
D064E6951ED9B1BF001956DF /* Core_Example_macOS */,
D064E6AA1ED9B31C001956DF /* Core_Tests_macOS */,
+ DEAAD3801FBA11270053BF48 /* Core_Example_tvOS */,
+ DEAAD3941FBA11270053BF48 /* Core_Tests_tvOS */,
DE7B8D041E8EF077009EB6DF /* Database_Example_iOS */,
DE7B8D1C1E8EF078009EB6DF /* Database_Tests_iOS */,
0624F3E01EC0ECFA00E5940D /* Database_IntegrationTests_iOS */,
D0FE8A1E1ED9C804003F6722 /* Database_Example_macOS */,
D0FE8A311ED9C86F003F6722 /* Database_Tests_macOS */,
D0FE8A641ED9C87B003F6722 /* Database_IntegrationTests_macOS */,
+ DE1CD5961FBA55AF00FC031E /* Database_Example_tvOS */,
+ DE1EC27E1FBA5E63007D18D8 /* Database_Tests_tvOS */,
AFD562E41EB13C6D00EA2233 /* Messaging_Example_iOS */,
DE9315A61E8738460083EDBF /* Messaging_Tests_iOS */,
DEB139E01E73506A00AC236D /* Storage_Example_iOS */,
@@ -2898,9 +3544,11 @@
D0EDB2DE1EDA06CB00B6C31B /* Storage_Tests_macOS */,
D0EDB2F81EDA06D500B6C31B /* Storage_IntegrationTests_macOS */,
DEDFEFEB1FD1B8C100F7D466 /* Analytics_Tests_iOS */,
+ DEAAD3E01FBA46AA0053BF48 /* Storage_Example_tvOS */,
+ DEAAD3F41FBA46AB0053BF48 /* Storage_Tests_tvOS */,
DE3373891E73773400881891 /* AllUnitTests_iOS */,
D0FE8A041ED9C32C003F6722 /* AllUnitTests_macOS */,
- DE26D2971F70668F004AE1D3 /* Auth_AllTests */,
+ DE545C7F1FBCA3F000C637AE /* AllUnitTests_tvOS */,
);
};
/* End PBXProject section */
@@ -3017,6 +3665,35 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ DE1CD5951FBA55AF00FC031E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DE1EC2961FBA5EB5007D18D8 /* Main.storyboard in Resources */,
+ DE9037291FBA5F2400E239D3 /* GoogleService-Info.plist in Resources */,
+ DE1EC2931FBA5EB5007D18D8 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1EC27D1FBA5E63007D18D8 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DE90374D1FBA70E400E239D3 /* syncPointSpec.json in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1FAE8E1FBCF5E100897AAA /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DE1FAEB41FBCF60D00897AAA /* Info.plist in Resources */,
+ DE1FAEB71FBCF6CA00897AAA /* GoogleService-Info.plist in Resources */,
+ DE1FAEB51FBCF60D00897AAA /* Main.storyboard in Resources */,
+ DE1FAEB61FBCF60D00897AAA /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
DE26D22C1F70398A004AE1D3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3057,6 +3734,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ DE53893C1FBB62E100199FC2 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
DE7B8D031E8EF077009EB6DF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3105,6 +3789,41 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ DEAAD37F1FBA11270053BF48 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEAAD3CE1FBA1EFA0053BF48 /* Assets.xcassets in Resources */,
+ DEAAD3DC1FBA36210053BF48 /* GoogleService-Info.plist in Resources */,
+ DEAAD3D41FBA20480053BF48 /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3931FBA11270053BF48 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3DF1FBA46AA0053BF48 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEAAD4201FBA47110053BF48 /* 1mb.dat in Resources */,
+ DEAAD4211FBA49D10053BF48 /* GoogleService-Info.plist in Resources */,
+ DEAAD41E1FBA470B0053BF48 /* Main.storyboard in Resources */,
+ DEAAD41B1FBA470B0053BF48 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3F31FBA46AB0053BF48 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
DEB139F91E73506A00AC236D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3152,61 +3871,85 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 0045465B164896D3C570A79A /* [CP] Check Pods Manifest.lock */ = {
+ 00C23492EFA7628C002D2287 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Storage_Example_iOS-checkManifestLockResult.txt",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 00DF54E18B7F0C37010CF5C6 /* [CP] Check Pods Manifest.lock */ = {
+ 066FF207F29FD1E125CDCA9B /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Storage_Example_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 062EEAC29DE0575BF611178E /* [CP] Embed Pods Frameworks */ = {
+ 08648163FCEA26546E5E8E35 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-macOS/GoogleToolboxForMac.framework",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 08957B7A79C276AF1C031ED1 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-be8a5251/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher.default-Core/GTMSessionFetcher.framework",
+ "${BUILT_PRODUCTS_DIR}/Bolts/Bolts.framework",
+ "${BUILT_PRODUCTS_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework",
+ "${BUILT_PRODUCTS_DIR}/FBSDKLoginKit/FBSDKLoginKit.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMOAuth2/GTMOAuth2.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Bolts.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKLoginKit.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMOAuth2.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 08057DD8B44996A54EB74007 /* [CP] Check Pods Manifest.lock */ = {
+ 0B68B6F63D8D76A56DFE38F3 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3217,47 +3960,91 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Database_Example_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Core_Example_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 13C0A425999DC1AFAAFA85A2 /* [CP] Embed Pods Frameworks */ = {
+ 118E42BDF843B8E5AFF716A0 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 120796D59D14DFEBCB083458 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library-iOS/leveldb.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 194262A69E6C961D8D1888EB /* [CP] Copy Pods Resources */ = {
+ 1611FB715EC5341B0397BD41 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests-frameworks.sh",
+ "${PODS_ROOT}/EarlGrey/EarlGrey/EarlGrey.framework",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EarlGrey.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 17495ED3CB98F3496DADEE40 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-be8a5251/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-iOS/GTMSessionFetcher.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 1BC0F30C28D9EDC8E02C0412 /* [CP] Check Pods Manifest.lock */ = {
+ 17A106649075278BE816501D /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3268,14 +4055,32 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Core_Example_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Tests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 1D62AD16C337F524407C8EBF /* [CP] Check Pods Manifest.lock */ = {
+ 222F97AB71B243C0E8C1680C /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_tvOS/Pods-Storage_Tests_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-tvOS/OCMock.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_tvOS/Pods-Storage_Tests_tvOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 22CEBCEDBAD96E384B598C36 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3286,50 +4091,49 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Database_IntegrationTests_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Storage_Tests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 2144CF65BA13A617A6510316 /* [CP] Embed Pods Frameworks */ = {
+ 257DF49B2BF041A67ECC0C49 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 2429BCE77F52A3CA917EBAD3 /* [CP] Embed Pods Frameworks */ = {
+ 267B6FB90F537E2C78FA1629 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 24BCD9BFDB0623B2BA73098C /* [CP] Check Pods Manifest.lock */ = {
+ 273510C286ECD5E359B6159E /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3340,14 +4144,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Core_Tests_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Messaging_Tests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 2A3CED73D6CF971623B65B11 /* [CP] Check Pods Manifest.lock */ = {
+ 28757E7372E5CA218910628A /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3358,14 +4162,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_SwiftSample-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Database_Tests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 2BE22FBF4B4647B6AF2A58D2 /* [CP] Check Pods Manifest.lock */ = {
+ 2B2A8711B6CC7353ECA108F0 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3376,14 +4180,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_Example_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Example_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 2D6499C61F0A16EE67985F35 /* [CP] Copy Pods Resources */ = {
+ 2B9C5A21D0CCD50D254D6CFE /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3395,10 +4199,81 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_tvOS/Pods-Auth_Tests_tvOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 2F08B0B91519AEB1E81960AB /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-resources.sh",
+ "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 338DBAF509A5E9D092818DA2 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 348348A57D424FA907702088 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 2F058EA64448194D0606AF43 /* [CP] Check Pods Manifest.lock */ = {
+ 35E3827DC5E63EE2D7302B65 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_tvOS/Pods-Storage_Example_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-tvOS/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-tvOS/GTMSessionFetcher.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_tvOS/Pods-Storage_Example_tvOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 36ECFC3EE140707B7C96FAFC /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3409,20 +4284,20 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_Sample-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Storage_IntegrationTests_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 2F2E08FC97C14E7EDDB8D804 /* [CP] Embed Pods Frameworks */ = {
+ 396062F8EC21600F2A1A832A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS-frameworks.sh",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
@@ -3431,10 +4306,25 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 310F0C6DEC04131DD5D31B3C /* [CP] Check Pods Manifest.lock */ = {
+ 3E73D0EE3702B20C522EB737 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 40E50B2EBCE9B3E3B5E68B93 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3445,21 +4335,21 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Messaging_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Storage_Tests_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 3261343A30C97057EDCB6749 /* [CP] Embed Pods Frameworks */ = {
+ 436A2DE8B1C36C53FCED6019 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
@@ -3467,43 +4357,48 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 38CF5DFC135922889EC15A84 /* [CP] Check Pods Manifest.lock */ = {
+ 43F27469966E52E9FB44955E /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-macOS/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library-macOS/leveldb.framework",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_Tests_macOS-checkManifestLockResult.txt",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 3EC098CF0777B0916DAB8AE7 /* [CP] Embed Pods Frameworks */ = {
+ 45C79B78C5B731142D5E1AC1 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_tvOS/Pods-Core_Tests_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-tvOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_tvOS/Pods-Core_Tests_tvOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 3F2AF12006B4163F0BCBD5E2 /* [CP] Copy Pods Resources */ = {
+ 489E82E20508C1E1BF91E7B4 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3515,45 +4410,76 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 418D23667D638E23FC6765B0 /* [CP] Copy Pods Resources */ = {
+ 4AF5573D7DF12FD1D0C88A1A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_tvOS/Pods-Database_Tests_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-tvOS/OCMock.framework",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_tvOS/Pods-Database_Tests_tvOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 4AA54CBB8303130FC18C1A27 /* [CP] Embed Pods Frameworks */ = {
+ 500A4C39D7949908D7E96FE6 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_tvOS/Pods-Core_Example_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-tvOS/GoogleToolboxForMac.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_tvOS/Pods-Core_Example_tvOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 4B926E79AD9E0016DDA7FBF8 /* [CP] Check Pods Manifest.lock */ = {
+ 55A9CDE9471333A1DEEC2DC6 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 5D1C5017F0B7B68B15BDD714 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 5DCF8D9FF3A9EFDF5BC1783E /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3564,14 +4490,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Database_Example_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Core_Example_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 4F7410B194A68B6D9F9D1C23 /* [CP] Check Pods Manifest.lock */ = {
+ 61833A6B418B3CF211027415 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3582,97 +4508,101 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Messaging_Example_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Tests_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 5355975898496CD7FF7DD106 /* [CP] Embed Pods Frameworks */ = {
+ 637BF15D486ACD0789DBBC68 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_macOS/Pods-Database_IntegrationTests_macOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 547E7E1564F7C15525BE1E84 /* [CP] Copy Pods Resources */ = {
+ 6412AADCC147925DABCBB905 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Storage_Example_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 55298685299C7889EDDFF818 /* [CP] Copy Pods Resources */ = {
+ 65E833A6A4000F0B79837D3D /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Example_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 61ED313363F4BDC7657BD2EE /* [CP] Embed Pods Frameworks */ = {
+ 6692936359478B80897B1771 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-465fce74/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-macOS/GTMSessionFetcher.framework",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "$(DERIVED_FILE_DIR)/Pods-Messaging_Example_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS-frameworks.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 68EBBBF8D47F1A4548F5F8A1 /* [CP] Copy Pods Resources */ = {
+ 6A17F5D59D7B838BFBBFAE93 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-resources.sh",
+ "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 6F3682326BA63694ECB240A3 /* [CP] Check Pods Manifest.lock */ = {
+ 6A332C7CB67CF7FF26296EF9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3683,14 +4613,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Core_Example_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Tests_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 776FB063FB216F38E91EC8A1 /* [CP] Copy Pods Resources */ = {
+ 6EC13D506E425EB20A7843D8 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3702,86 +4632,81 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_tvOS/Pods-Core_Tests_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 7ADF89772D7C70DB74EF0384 /* [CP] Embed Pods Frameworks */ = {
+ 76D01041B075D88EC92B58BC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_tvOS/Pods-Storage_Tests_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 7C60623F83982B8C98AD8A03 /* [CP] Copy Pods Resources */ = {
+ 7719F31E8BEEE94528B0B560 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-resources.sh",
- "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
+ "$(DERIVED_FILE_DIR)/Pods-Database_Tests_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 7EF78DCE613E776ECD9373C2 /* [CP] Embed Pods Frameworks */ = {
+ 7AED28FFDB4538097571CAB0 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-465fce74/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-macOS/GTMSessionFetcher.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 7F7E65CEFB1C184D69448404 /* [CP] Embed Pods Frameworks */ = {
+ 86C0D3C6E5D05FBBCA3CE8BF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/leveldb-library-iOS/leveldb.framework",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ "$(DERIVED_FILE_DIR)/Pods-Database_Example_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS-frameworks.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 80A283F697210020814F3349 /* [CP] Check Pods Manifest.lock */ = {
+ 88B701F1A289EED5913CB89F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3792,29 +4717,74 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Storage_IntegrationTests_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Example_macOS-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 8A0408EE425E76C47C98D3D3 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Storage_Tests_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 8263B27A42441EB177C87183 /* [CP] Copy Pods Resources */ = {
+ 8B622E883C1CC4C26C0BB9A9 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-be8a5251/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher.default-Core/GTMSessionFetcher.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMOAuth2/GTMOAuth2.framework",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMOAuth2.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 8DB662ACD739CD47CFC7C093 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Core_Tests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 83EC34B122E68BACA199C8BD /* [CP] Check Pods Manifest.lock */ = {
+ 8E51FDDF5CDC6B3B42AE8735 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3825,21 +4795,36 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Database_Tests_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Storage_Example_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 8489BA940D280D954CF784DF /* [CP] Embed Pods Frameworks */ = {
+ 93AB0EF8AA5A4C48546D60A7 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 94E5426439D34EF38E3A1C61 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_tvOS/Pods-Auth_Tests_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-tvOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
@@ -3847,25 +4832,28 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_tvOS/Pods-Auth_Tests_tvOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 89FC9C3CF79117EF07001272 /* [CP] Copy Pods Resources */ = {
+ 955CEE0E05C6781D75206EE4 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Core_Tests_tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 8AC1F8EDC83D64A46940EA1F /* [CP] Copy Pods Resources */ = {
+ 96AC317066A0285BEC8B0E20 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3877,25 +4865,46 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 91ED54292706C89DEAF738F0 /* [CP] Copy Pods Resources */ = {
+ 997D0D4345B2BFC675DD3992 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 9C3034A423FA21B0E3500BF9 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Analytics_Tests_iOS-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 94DE13FC01F4BCC0A3AA92B8 /* [CP] Check Pods Manifest.lock */ = {
+ 9CAEF4F03D2C87AED96E87B8 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3913,7 +4922,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 952D8E3BC2A768AF99B029D4 /* [CP] Copy Pods Resources */ = {
+ 9CE7A87FC2C9C68B0C58E63B /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3925,50 +4934,40 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_tvOS/Pods-Auth_Example_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 964A6DD602ABD81ABDE945E1 /* [CP] Check Pods Manifest.lock */ = {
+ 9F60468168975372B533A4DF /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Database_IntegrationTests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 9DDF848892C1B2DCE343D139 /* [CP] Embed Pods Frameworks */ = {
+ A127C8A6500F782E73C0851A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-iOS/GTMSessionFetcher.framework",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 9F9A46A840E3517985F97BF7 /* [CP] Check Pods Manifest.lock */ = {
+ A276E28C6BE15473C08F46C7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -3979,38 +4978,32 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Storage_Tests_macOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Database_IntegrationTests_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- A397E143BFA2B54BBA78DB27 /* [CP] Embed Pods Frameworks */ = {
+ A4A70B0E20C6A874C668B261 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-be8a5251/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher.default-Core/GTMSessionFetcher.framework",
- "${BUILT_PRODUCTS_DIR}/GTMOAuth2/GTMOAuth2.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMOAuth2.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- B5724E5E5CB63BD5B738C4F6 /* [CP] Copy Pods Resources */ = {
+ A690931685428A81DB3D7318 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4022,10 +5015,10 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_macOS/Pods-Auth_Example_macOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- B57C4BF2A720187D5DF4C848 /* [CP] Copy Pods Resources */ = {
+ A6DC1E378B43295245C5C1DA /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4037,16 +5030,16 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_iOS/Pods-Storage_Tests_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_tvOS/Pods-Storage_Example_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- B5D70414394DD066BE115ED8 /* [CP] Embed Pods Frameworks */ = {
+ AD0431F92777A7C0529C761E /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS-frameworks.sh",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
@@ -4055,28 +5048,28 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- B6C7305ECEA2DA69869E3199 /* [CP] Check Pods Manifest.lock */ = {
+ ADB10E4C6A62992C15EE9BB4 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_EarlGreyTests-checkManifestLockResult.txt",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_iOS/Pods-Database_Tests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- BC5C8E9DA5ECC9095376EEFC /* [CP] Copy Pods Resources */ = {
+ AE504E2BAD5B3581FC1898CA /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4088,28 +5081,25 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- BD09C44595A6ECBB8FA2350D /* [CP] Check Pods Manifest.lock */ = {
+ AFD2E6B7DB258E48009217D8 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_Example_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_tvOS/Pods-Database_Tests_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- BD7302A2861F068F5540CCA6 /* [CP] Copy Pods Resources */ = {
+ AFD8FCED83B8C2B69BC89591 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4121,10 +5111,25 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ B133AB611E38B0B6695DF763 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_tvOS/Pods-Database_Example_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- C0894681AFF0FF07CE891310 /* [CP] Check Pods Manifest.lock */ = {
+ B6EF8098F3C4BB08D7BED9D8 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4135,84 +5140,62 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Storage_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_EarlGreyTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- C0BB541B4E2E4188148B74BF /* [CP] Embed Pods Frameworks */ = {
+ BAB96787C60CED3387854011 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-be8a5251/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-iOS/GTMSessionFetcher.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_iOS/Pods-Auth_Example_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- C4CB228F9FBF834637FDD550 /* [CP] Embed Pods Frameworks */ = {
+ BCFDF9E24063519540D27F43 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-be8a5251/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher.default-Core/GTMSessionFetcher.framework",
- "${BUILT_PRODUCTS_DIR}/Bolts/Bolts.framework",
- "${BUILT_PRODUCTS_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework",
- "${BUILT_PRODUCTS_DIR}/FBSDKLoginKit/FBSDKLoginKit.framework",
- "${BUILT_PRODUCTS_DIR}/GTMOAuth2/GTMOAuth2.framework",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Bolts.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKLoginKit.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMOAuth2.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Sample/Pods-Auth_Sample-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- C6DD8EA209B18D8651337E5A /* [CP] Check Pods Manifest.lock */ = {
+ BFCC067E4DA198D538DC3FDF /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Storage_IntegrationTests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_iOS/Pods-Database_Example_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- C981CB657374F18444683DDE /* [CP] Check Pods Manifest.lock */ = {
+ C24F5282192B81B6A39BAEB8 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4223,14 +5206,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Auth_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Auth_Sample-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- CB265192F117EE5B7B6A90F3 /* [CP] Copy Pods Resources */ = {
+ C543D8A8F6950A4301C0D644 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4242,31 +5225,34 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_tvOS/Pods-Core_Example_tvOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- D293C865CA6C9CFE510F2030 /* [CP] Copy Pods Resources */ = {
+ C56FA5154BF616EA6F457108 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Storage_Example_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- D57035FA9DBD9B5C6F7E44BB /* [CP] Embed Pods Frameworks */ = {
+ C70080AEF1AD5B5BB73542BF /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS-frameworks.sh",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
@@ -4275,17 +5261,17 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_iOS/Pods-Auth_Tests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- D736CA94F00AB417403CEC0D /* [CP] Embed Pods Frameworks */ = {
+ C826D2B941653E5EEEBE569D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-macOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
@@ -4293,10 +5279,28 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Tests_iOS/Pods-Messaging_Tests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_macOS/Pods-Storage_IntegrationTests_macOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ C85C84FF7518F64284384825 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Auth_SwiftSample-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- DBE97573DB393D723CD8CDA2 /* [CP] Embed Pods Frameworks */ = {
+ C97E0BBB635D9C80C5C62D74 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4314,13 +5318,71 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- DC31836CBCE7DE03EC932511 /* [CP] Embed Pods Frameworks */ = {
+ CCADF8C25FBA174357AEA0CE /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS-frameworks.sh",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-macOS/GoogleToolboxForMac.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ CD18801A135756D44CE31E8C /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-Logger-NSData+zlib/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ CFD020C48DD8D50E846F5F60 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Core_Example_tvOS-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ D0A888D2C36723C55F2BDC0C /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
);
@@ -4331,28 +5393,45 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Analytics_Tests_iOS/Pods-Analytics_Tests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_iOS/Pods-Core_Example_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- DC71E8C018300A993E541683 /* [CP] Copy Pods Resources */ = {
+ D424AD0375A67F11DDF83CBB /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_tvOS/Pods-Database_Example_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-tvOS/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library-tvOS/leveldb.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_tvOS/Pods-Database_Example_tvOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ D61AD5162C75965358E153F2 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-resources.sh",
- "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
- "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_SwiftSample/Pods-Auth_SwiftSample-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Tests_macOS/Pods-Auth_Tests_macOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- DC8467211F158C333D6E1851 /* [CP] Copy Pods Resources */ = {
+ DA5D35B2E947885B7B9A8FCA /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4364,10 +5443,25 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- DE3BC872B0631D9222625218 /* [CP] Copy Pods Resources */ = {
+ DF29C4F0F86D60F7FEE583F8 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_ApiTests/Pods-Auth_ApiTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ DF698E6810C50B85FC20ABCC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4379,52 +5473,80 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_IntegrationTests_iOS/Pods-Database_IntegrationTests_iOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- E14B732B18AC2D43E964F013 /* [CP] Embed Pods Frameworks */ = {
+ E24428AEED98846FAEE3A892 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-Logger-NSData+zlib/GoogleToolboxForMac.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-iOS/GoogleToolboxForMac.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-iOS/GTMSessionFetcher.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Messaging_Example_iOS/Pods-Messaging_Example_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_iOS/Pods-Storage_Example_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- E1EF4640668E42876CD0680B /* [CP] Embed Pods Frameworks */ = {
+ E6E7FCA58951222D1403093F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-macOS/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-macOS/GTMSessionFetcher.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- E3A92F1E7F7F65ACF2BCEC78 /* [CP] Check Pods Manifest.lock */ = {
+ EB4045893AE0E69BB38780B1 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Example_macOS/Pods-Core_Example_macOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ ED383603B7B5D4C03055E2A7 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Tests_macOS/Pods-Database_Tests_macOS-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ EDDC22912C046AB4349E45D5 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4435,14 +5557,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Analytics_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Core_Tests_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- E4708A6EB45D6F7D30070DCF /* [CP] Check Pods Manifest.lock */ = {
+ EF45D0D217BDEA5CEB66E5C2 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4453,29 +5575,34 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Core_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Database_Example_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- E4CD99103647D7D03D05576E /* [CP] Copy Pods Resources */ = {
+ F047DE7DFD8E3EFA65677278 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_tvOS/Pods-Auth_Example_tvOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-f29d6b98/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-tvOS/GTMSessionFetcher.framework",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_IntegrationTests_iOS/Pods-Storage_IntegrationTests_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_Example_tvOS/Pods-Auth_Example_tvOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- EB62267583A8460DAF576DF9 /* [CP] Copy Pods Resources */ = {
+ F106DC91C54784AD9F5963D5 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4487,48 +5614,46 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Tests_macOS/Pods-Storage_Tests_macOS-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- EBD8971C0B3B5BCDA5F5EA9F /* [CP] Embed Pods Frameworks */ = {
+ F58DF2B67102DFA67481CE7C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-macOS/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/leveldb-library-macOS/leveldb.framework",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ "$(DERIVED_FILE_DIR)/Pods-Database_Tests_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database_Example_macOS/Pods-Database_Example_macOS-frameworks.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- F5B5EF87DFA0131455579138 /* [CP] Embed Pods Frameworks */ = {
+ F9006262CA0804846FE05F99 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests-frameworks.sh",
- "${PODS_ROOT}/EarlGrey/EarlGrey/EarlGrey.framework",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EarlGrey.framework",
+ "$(DERIVED_FILE_DIR)/Pods-Storage_IntegrationTests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth_EarlGreyTests/Pods-Auth_EarlGreyTests-frameworks.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- FF06F317B2790040C6157248 /* [CP] Check Pods Manifest.lock */ = {
+ FC761FD2D605CBA0F9693A16 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -4539,41 +5664,49 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Database_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Database_IntegrationTests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- FFAC5DC18B783B814EF2DAB5 /* [CP] Copy Pods Resources */ = {
+ FCAE72CAEA7047E5BC17A115 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Database_Example_macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_macOS/Pods-Core_Tests_macOS-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- FFBE661125B41DE1A5B115C3 /* [CP] Copy Pods Resources */ = {
+ FE4106FE85FE9310554CF15A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib-macOS/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher-Core-macOS/GTMSessionFetcher.framework",
);
- name = "[CP] Copy Pods Resources";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Core_Tests_iOS/Pods-Core_Tests_iOS-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Storage_Example_macOS/Pods-Storage_Example_macOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -4829,6 +5962,65 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ DE1CD5931FBA55AF00FC031E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DE1EC2971FBA5EB5007D18D8 /* ViewController.m in Sources */,
+ DE1EC2951FBA5EB5007D18D8 /* main.m in Sources */,
+ DE1EC2921FBA5EB5007D18D8 /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1EC27B1FBA5E63007D18D8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DE90372F1FBA5F8F00E239D3 /* FLevelDBStorageEngineTests.m in Sources */,
+ DE9037361FBA5F8F00E239D3 /* FRangeMergeTest.m in Sources */,
+ DE90373F1FBA675D00E239D3 /* FDevice.m in Sources */,
+ DE9037311FBA5F8F00E239D3 /* FPathTests.m in Sources */,
+ DE9037441FBA675D00E239D3 /* FTestAuthTokenGenerator.m in Sources */,
+ DE9037391FBA5F8F00E239D3 /* FSyncPointTests.m in Sources */,
+ DE9037371FBA5F8F00E239D3 /* FRepoInfoTest.m in Sources */,
+ DE9037451FBA675D00E239D3 /* FTestBase.m in Sources */,
+ DE90372D1FBA5F8F00E239D3 /* FIRDataSnapshotTests.m in Sources */,
+ DE90372B1FBA5F8F00E239D3 /* FCompoundHashTest.m in Sources */,
+ DE90374B1FBA675D00E239D3 /* SenTest+FWaiter.m in Sources */,
+ DE9037321FBA5F8F00E239D3 /* FPersistenceManagerTest.m in Sources */,
+ DE9037461FBA675D00E239D3 /* FTestCachePolicy.m in Sources */,
+ DE90373A1FBA5F8F00E239D3 /* FTrackedQueryManagerTest.m in Sources */,
+ DE90373C1FBA5F8F00E239D3 /* FUtilitiesTest.m in Sources */,
+ DE90372C1FBA5F8F00E239D3 /* FCompoundWriteTest.m in Sources */,
+ DE9037431FBA675D00E239D3 /* FMockStorageEngine.m in Sources */,
+ DE9037381FBA5F8F00E239D3 /* FSparseSnapshotTests.m in Sources */,
+ DE9037341FBA5F8F00E239D3 /* FPruningTest.m in Sources */,
+ DE9037471FBA675D00E239D3 /* FTestClock.m in Sources */,
+ DE90373B1FBA5F8F00E239D3 /* FTreeSortedDictionaryTests.m in Sources */,
+ DE9037491FBA675D00E239D3 /* FTestHelpers.m in Sources */,
+ DE9037401FBA675D00E239D3 /* FEventTester.m in Sources */,
+ DE9037351FBA5F8F00E239D3 /* FQueryParamsTest.m in Sources */,
+ DE90372E1FBA5F8F00E239D3 /* FIRMutableDataTests.m in Sources */,
+ DE9037301FBA5F8F00E239D3 /* FNodeTests.m in Sources */,
+ DE9037421FBA675D00E239D3 /* FIRTestAuthTokenProvider.m in Sources */,
+ DE9037411FBA675D00E239D3 /* FIRFakeApp.m in Sources */,
+ DE9037331FBA5F8F00E239D3 /* FPruneForestTest.m in Sources */,
+ DE90374A1FBA675D00E239D3 /* FTupleEventTypeString.m in Sources */,
+ DE90372A1FBA5F8F00E239D3 /* FArraySortedDictionaryTest.m in Sources */,
+ DE9037481FBA675D00E239D3 /* FTestExpectations.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DE1FAE8C1FBCF5E100897AAA /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DE1FAEB31FBCF60D00897AAA /* ViewController.m in Sources */,
+ DE1FAEB21FBCF60D00897AAA /* main.m in Sources */,
+ DE1FAEB11FBCF60D00897AAA /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
DE26D22A1F70398A004AE1D3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4876,6 +6068,55 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ DE53893A1FBB62E100199FC2 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEF6C3171FBCE775005D0740 /* FIRAuthBackendRPCImplementationTests.m in Sources */,
+ DEF6C30D1FBCE72F005D0740 /* FIRAuthDispatcherTests.m in Sources */,
+ DEF6C3121FBCE775005D0740 /* FIRAuthAPNSTokenTests.m in Sources */,
+ DEF6C3131FBCE775005D0740 /* FIRAuthAppCredentialManagerTests.m in Sources */,
+ DEF6C3301FBCE775005D0740 /* FIRSetAccountInfoRequestTests.m in Sources */,
+ DEF6C3341FBCE775005D0740 /* FIRTwitterAuthProviderTests.m in Sources */,
+ DEF6C3271FBCE775005D0740 /* FIRGetOOBConfirmationCodeResponseTests.m in Sources */,
+ DEF6C3241FBCE775005D0740 /* FIRGetAccountInfoRequestTests.m in Sources */,
+ DEF6C33E1FBCE775005D0740 /* FIRVerifyPasswordResponseTests.m in Sources */,
+ DEF6C3141FBCE775005D0740 /* FIRAuthAppCredentialTests.m in Sources */,
+ DEF6C31C1FBCE775005D0740 /* FIRAuthTests.m in Sources */,
+ DEF6C33D1FBCE775005D0740 /* FIRVerifyPasswordRequestTest.m in Sources */,
+ DEF6C3181FBCE775005D0740 /* FIRAuthGlobalWorkQueueTests.m in Sources */,
+ DEF6C3191FBCE775005D0740 /* FIRAuthKeychainTests.m in Sources */,
+ DEF6C32A1FBCE775005D0740 /* FIRGitHubAuthProviderTests.m in Sources */,
+ DEF6C3321FBCE775005D0740 /* FIRSignUpNewUserRequestTests.m in Sources */,
+ DEF6C30F1FBCE775005D0740 /* FIRAdditionalUserInfoTests.m in Sources */,
+ DEF6C31B1FBCE775005D0740 /* FIRAuthSerialTaskQueueTests.m in Sources */,
+ DEF6C3251FBCE775005D0740 /* FIRGetAccountInfoResponseTests.m in Sources */,
+ DEF6C3281FBCE775005D0740 /* FIRGetProjectConfigRequestTests.m in Sources */,
+ DEF6C3291FBCE775005D0740 /* FIRGetProjectConfigResponseTests.m in Sources */,
+ DEF6C32D1FBCE775005D0740 /* FIRResetPasswordResponseTests.m in Sources */,
+ DEF6C33C1FBCE775005D0740 /* FIRVerifyCustomTokenResponseTests.m in Sources */,
+ DEF6C3161FBCE775005D0740 /* FIRAuthBackendCreateAuthURITests.m in Sources */,
+ DEF6C32C1FBCE775005D0740 /* FIRResetPasswordRequestTests.m in Sources */,
+ DEF6C31F1FBCE775005D0740 /* FIRCreateAuthURIRequestTests.m in Sources */,
+ DEF6C3201FBCE775005D0740 /* FIRCreateAuthURIResponseTests.m in Sources */,
+ DEF6C31A1FBCE775005D0740 /* FIRAuthNotificationManagerTests.m in Sources */,
+ DEF6C33B1FBCE775005D0740 /* FIRVerifyCustomTokenRequestTests.m in Sources */,
+ DEF6C3221FBCE775005D0740 /* FIRDeleteAccountResponseTests.m in Sources */,
+ DEF6C3381FBCE775005D0740 /* FIRVerifyAssertionResponseTests.m in Sources */,
+ DEF6C3101FBCE775005D0740 /* FIRApp+FIRAuthUnitTests.m in Sources */,
+ DEF6C3411FBCE775005D0740 /* OCMStubRecorder+FIRAuthUnitTests.m in Sources */,
+ DEF6C3211FBCE775005D0740 /* FIRDeleteAccountRequestTests.m in Sources */,
+ DEF6C3331FBCE775005D0740 /* FIRSignUpNewUserResponseTests.m in Sources */,
+ DEF6C3371FBCE775005D0740 /* FIRVerifyAssertionRequestTests.m in Sources */,
+ DEF6C3231FBCE775005D0740 /* FIRFakeBackendRPCIssuer.m in Sources */,
+ DEF6C31E1FBCE775005D0740 /* FIRAuthUserDefaultsStorageTests.m in Sources */,
+ DEF6C3351FBCE775005D0740 /* FIRUserMetadataTests.m in Sources */,
+ DEF6C3311FBCE775005D0740 /* FIRSetAccountInfoResponseTests.m in Sources */,
+ DEF6C3361FBCE775005D0740 /* FIRUserTests.m in Sources */,
+ DEF6C3261FBCE775005D0740 /* FIRGetOOBConfirmationCodeRequestTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
DE7B8D011E8EF077009EB6DF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -5019,6 +6260,57 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ DEAAD37D1FBA11270053BF48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEAAD3D01FBA1EFA0053BF48 /* ViewController.m in Sources */,
+ DEAAD3CF1FBA1EFA0053BF48 /* AppDelegate.m in Sources */,
+ DEAAD3C31FBA1CD90053BF48 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3911FBA11270053BF48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEAAD3DA1FBA34250053BF48 /* FIROptionsTest.m in Sources */,
+ DEAAD3D51FBA34250053BF48 /* FIRAppAssociationRegistrationUnitTests.m in Sources */,
+ DEAAD3D91FBA34250053BF48 /* FIRLoggerTest.m in Sources */,
+ DEAAD3D61FBA34250053BF48 /* FIRAppTest.m in Sources */,
+ DEAAD3D81FBA34250053BF48 /* FIRConfigurationTest.m in Sources */,
+ DEAAD3DB1FBA34250053BF48 /* FIRTestCase.m in Sources */,
+ DEAAD3D71FBA34250053BF48 /* FIRBundleUtilTest.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3DD1FBA46AA0053BF48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEAAD41F1FBA470B0053BF48 /* ViewController.m in Sources */,
+ DEAAD41D1FBA470B0053BF48 /* main.m in Sources */,
+ DEAAD41A1FBA470B0053BF48 /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DEAAD3F11FBA46AB0053BF48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DEAAD4251FBA49ED0053BF48 /* FIRStoragePathTests.m in Sources */,
+ DEAAD42A1FBA49ED0053BF48 /* FIRStorageUpdateMetadataTests.m in Sources */,
+ DEAAD4221FBA49ED0053BF48 /* FIRStorageDeleteTests.m in Sources */,
+ DEAAD4291FBA49ED0053BF48 /* FIRStorageTokenAuthorizerTests.m in Sources */,
+ DEAAD4231FBA49ED0053BF48 /* FIRStorageGetMetadataTests.m in Sources */,
+ DEAAD42B1FBA49ED0053BF48 /* FIRStorageUtilsTests.m in Sources */,
+ DEAAD4261FBA49ED0053BF48 /* FIRStorageReferenceTests.m in Sources */,
+ DEAAD4271FBA49ED0053BF48 /* FIRStorageTestHelpers.m in Sources */,
+ DEAAD4281FBA49ED0053BF48 /* FIRStorageTests.m in Sources */,
+ DEAAD4241FBA49ED0053BF48 /* FIRStorageMetadataTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
DEB139E21E73506A00AC236D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -5147,6 +6439,16 @@
target = D0FE8A1E1ED9C804003F6722 /* Database_Example_macOS */;
targetProxy = D0FE8A901ED9C9CD003F6722 /* PBXContainerItemProxy */;
};
+ DE1E3B311FEB1E7600EAEBB0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DE1FAE8F1FBCF5E100897AAA /* Auth_Example_tvOS */;
+ targetProxy = DE1E3B301FEB1E7600EAEBB0 /* PBXContainerItemProxy */;
+ };
+ DE1EC2851FBA5E63007D18D8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DE1CD5961FBA55AF00FC031E /* Database_Example_tvOS */;
+ targetProxy = DE1EC2841FBA5E63007D18D8 /* PBXContainerItemProxy */;
+ };
DE26D2631F7049F1004AE1D3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DE26D22D1F70398A004AE1D3 /* Auth_Sample */;
@@ -5177,6 +6479,21 @@
target = DEB13A0A1E73507E00AC236D /* Storage_Tests_iOS */;
targetProxy = DE3373971E73776F00881891 /* PBXContainerItemProxy */;
};
+ DE545C841FBCA41C00C637AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DEAAD3941FBA11270053BF48 /* Core_Tests_tvOS */;
+ targetProxy = DE545C831FBCA41C00C637AE /* PBXContainerItemProxy */;
+ };
+ DE545C861FBCA42C00C637AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DEAAD3F41FBA46AB0053BF48 /* Storage_Tests_tvOS */;
+ targetProxy = DE545C851FBCA42C00C637AE /* PBXContainerItemProxy */;
+ };
+ DE545C881FBCA43200C637AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DE1EC27E1FBA5E63007D18D8 /* Database_Tests_tvOS */;
+ targetProxy = DE545C871FBCA43200C637AE /* PBXContainerItemProxy */;
+ };
DE6F01BA1E957157004AEE01 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DE9315A61E8738460083EDBF /* Messaging_Tests_iOS */;
@@ -5197,6 +6514,16 @@
target = DE9314DD1E86C6BE0083EDBF /* Auth_Tests_iOS */;
targetProxy = DE9315861E86E9990083EDBF /* PBXContainerItemProxy */;
};
+ DEAAD3971FBA11280053BF48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DEAAD3801FBA11270053BF48 /* Core_Example_tvOS */;
+ targetProxy = DEAAD3961FBA11280053BF48 /* PBXContainerItemProxy */;
+ };
+ DEAAD3F71FBA46AB0053BF48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DEAAD3E01FBA46AA0053BF48 /* Storage_Example_tvOS */;
+ targetProxy = DEAAD3F61FBA46AB0053BF48 /* PBXContainerItemProxy */;
+ };
DEB13A261E73512500AC236D /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DEB139E01E73506A00AC236D /* Storage_Example_iOS */;
@@ -5362,7 +6689,7 @@
/* Begin XCBuildConfiguration section */
06121EC31EC399C50008D70E /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 4ECAA105379B7E664C7FF223 /* Pods-Storage_IntegrationTests_iOS.debug.xcconfig */;
+ baseConfigurationReference = E262D06D71EE92227622D747 /* Pods-Storage_IntegrationTests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5384,7 +6711,7 @@
};
06121EC41EC399C50008D70E /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 5CA5A85B5A80F118F3247910 /* Pods-Storage_IntegrationTests_iOS.release.xcconfig */;
+ baseConfigurationReference = A2339EEA1F050084D3214753 /* Pods-Storage_IntegrationTests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5407,7 +6734,7 @@
};
0624F3E91EC0ECFA00E5940D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 20928A4E610E48E3EA4D9F4A /* Pods-Database_IntegrationTests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 885461BA75A5FE1BF1CBC992 /* Pods-Database_IntegrationTests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5444,7 +6771,7 @@
};
0624F3EA1EC0ECFA00E5940D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = EDA33867CB04D0AADD09321A /* Pods-Database_IntegrationTests_iOS.release.xcconfig */;
+ baseConfigurationReference = 33C6BA3B4F6EEB1532A645E3 /* Pods-Database_IntegrationTests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5565,7 +6892,7 @@
};
AFD562F51EB13C6D00EA2233 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 4D61AACC06F8E078EF051E4C /* Pods-Messaging_Example_iOS.debug.xcconfig */;
+ baseConfigurationReference = 99BF1D5FC3F0CC27D845BCDE /* Pods-Messaging_Example_iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5590,7 +6917,7 @@
};
AFD562F61EB13C6D00EA2233 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 6098677E3698C58151DC2E85 /* Pods-Messaging_Example_iOS.release.xcconfig */;
+ baseConfigurationReference = 4A7EFB64559F46B8A5FA288D /* Pods-Messaging_Example_iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5615,7 +6942,7 @@
};
D01853771EDAD084003A645C /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = B4F2CCE27C567E675C27953C /* Pods-Auth_Example_macOS.debug.xcconfig */;
+ baseConfigurationReference = 0E086A7E5D54786963FBFC7D /* Pods-Auth_Example_macOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5636,7 +6963,7 @@
};
D01853781EDAD084003A645C /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 4BF8EA84DF6AF0AB6E9BB6A0 /* Pods-Auth_Example_macOS.release.xcconfig */;
+ baseConfigurationReference = FFFFFD100F6720BBBA4176CC /* Pods-Auth_Example_macOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5658,7 +6985,7 @@
};
D01853C41EDAD364003A645C /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = BA1AAFF4508A97F7B32533FC /* Pods-Auth_Tests_macOS.debug.xcconfig */;
+ baseConfigurationReference = 46EB9F652984D82936716B89 /* Pods-Auth_Tests_macOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5683,7 +7010,7 @@
};
D01853C51EDAD364003A645C /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FDBC4B909E617B02D7E741F6 /* Pods-Auth_Tests_macOS.release.xcconfig */;
+ baseConfigurationReference = B183A98C3EA6EA2E11FA31E4 /* Pods-Auth_Tests_macOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5709,7 +7036,7 @@
};
D064E6A81ED9B1BF001956DF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 6FD4B6DC35E3304CBECFEC61 /* Pods-Core_Example_macOS.debug.xcconfig */;
+ baseConfigurationReference = B55C9A02AA68737098994C79 /* Pods-Core_Example_macOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5730,7 +7057,7 @@
};
D064E6A91ED9B1BF001956DF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = F7649E1B594D8101939746EA /* Pods-Core_Example_macOS.release.xcconfig */;
+ baseConfigurationReference = 7981511F571E13DECA09B4B1 /* Pods-Core_Example_macOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5752,7 +7079,7 @@
};
D064E6BD1ED9B31C001956DF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 2B3C652966760042D996247E /* Pods-Core_Tests_macOS.debug.xcconfig */;
+ baseConfigurationReference = CDEE84B9D494E05B9F9D46FF /* Pods-Core_Tests_macOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5772,7 +7099,7 @@
};
D064E6BE1ED9B31C001956DF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 287D8FC7F3129B28D8A29FBE /* Pods-Core_Tests_macOS.release.xcconfig */;
+ baseConfigurationReference = 0118423DA26C4B44AEE1B9C1 /* Pods-Core_Tests_macOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5793,7 +7120,7 @@
};
D0EDB2CB1EDA04F800B6C31B /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 24B879B03BD82C7DE771CA61 /* Pods-Storage_Example_macOS.debug.xcconfig */;
+ baseConfigurationReference = 66A4B7148EBB02E1A68EB8B0 /* Pods-Storage_Example_macOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5814,7 +7141,7 @@
};
D0EDB2CC1EDA04F800B6C31B /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FD3AEF097DFCF2ADAC345D2A /* Pods-Storage_Example_macOS.release.xcconfig */;
+ baseConfigurationReference = 72CFADA95DFD90718FDCFE19 /* Pods-Storage_Example_macOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5836,7 +7163,7 @@
};
D0EDB2F41EDA06CB00B6C31B /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 4B490EFB675400675CA98196 /* Pods-Storage_Tests_macOS.debug.xcconfig */;
+ baseConfigurationReference = D84F03BB958CAC55AF091002 /* Pods-Storage_Tests_macOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = "";
@@ -5861,7 +7188,7 @@
};
D0EDB2F51EDA06CB00B6C31B /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = E0EF5EDDB1FD839F03FC02AA /* Pods-Storage_Tests_macOS.release.xcconfig */;
+ baseConfigurationReference = BA1FFE4321DBF890ADDCAAEE /* Pods-Storage_Tests_macOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = "";
@@ -5882,7 +7209,7 @@
};
D0EDB3051EDA06D500B6C31B /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = C1520E81B1BFD24ED1882137 /* Pods-Storage_IntegrationTests_macOS.debug.xcconfig */;
+ baseConfigurationReference = 57876896413B7C97B317CCFD /* Pods-Storage_IntegrationTests_macOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5904,7 +7231,7 @@
};
D0EDB3061EDA06D500B6C31B /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = B0895BC929D50B20A69CEEEF /* Pods-Storage_IntegrationTests_macOS.release.xcconfig */;
+ baseConfigurationReference = 5FAFDE80DEFDE1EF5415939B /* Pods-Storage_IntegrationTests_macOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -5945,7 +7272,7 @@
};
D0FE8A2D1ED9C804003F6722 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 1068E64D36A3C656184168DE /* Pods-Database_Example_macOS.debug.xcconfig */;
+ baseConfigurationReference = 639B98AAF5AC93281CDF9DAF /* Pods-Database_Example_macOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5966,7 +7293,7 @@
};
D0FE8A2E1ED9C804003F6722 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 4CC7C8B9E821151509BB3B64 /* Pods-Database_Example_macOS.release.xcconfig */;
+ baseConfigurationReference = B7C4D4083183945C8A9CE722 /* Pods-Database_Example_macOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -5988,7 +7315,7 @@
};
D0FE8A601ED9C86F003F6722 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 86B8E0400070C72C0FE0C2F8 /* Pods-Database_Tests_macOS.debug.xcconfig */;
+ baseConfigurationReference = EAB8C42B67530BE1F6913791 /* Pods-Database_Tests_macOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6027,7 +7354,7 @@
};
D0FE8A611ED9C86F003F6722 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7879DCC8860E7CED0311D4E8 /* Pods-Database_Tests_macOS.release.xcconfig */;
+ baseConfigurationReference = 4CCB05296C6932B64AFBFB1A /* Pods-Database_Tests_macOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6066,7 +7393,7 @@
};
D0FE8A8A1ED9C87B003F6722 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 1CCC00FFFC534F0E9B41CF29 /* Pods-Database_IntegrationTests_macOS.debug.xcconfig */;
+ baseConfigurationReference = D2ACCDA6F5D95F900ADBC704 /* Pods-Database_IntegrationTests_macOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6104,7 +7431,7 @@
};
D0FE8A8B1ED9C87B003F6722 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 00BD45B2141C68C3F9809A4D /* Pods-Database_IntegrationTests_macOS.release.xcconfig */;
+ baseConfigurationReference = F2A878FAEAB3ACF41E7D630C /* Pods-Database_IntegrationTests_macOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6141,9 +7468,242 @@
};
name = Release;
};
+ DE1CD5B21FBA55B000FC031E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = B44CC7B623B174C922C241EF /* Pods-Database_Example_tvOS.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Database/App/tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Database-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DE1CD5B31FBA55B000FC031E /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7ED0DF69C095C21EFC81F672 /* Pods-Database_Example_tvOS.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Database/App/tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Database-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
+ DE1EC2871FBA5E63007D18D8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = D63A20E34B2316DBCDD87E6C /* Pods-Database_Tests_tvOS.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"${PODS_ROOT}/../../Firebase/Database/Utilities/Tuples\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Core\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Realtime\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/third_party/SocketRocket\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Utilities\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Libraries\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Core/Utilities\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Api/Private\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Api\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Snapshot\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Login\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Constants\"",
+ "\"${PODS_ROOT}/../../Firebase/Database\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Persistence\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Core/View\"",
+ );
+ INFOPLIST_FILE = "Database/Tests/FirebaseTests-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Database-Tests-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Database_Example_tvOS.app/Database_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DE1EC2881FBA5E63007D18D8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 37A2B647AFCDC9187D37529B /* Pods-Database_Tests_tvOS.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"${PODS_ROOT}/../../Firebase/Database/Utilities/Tuples\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Core\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Realtime\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/third_party/SocketRocket\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Utilities\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Libraries\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Core/Utilities\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Api/Private\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Api\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Snapshot\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Login\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Constants\"",
+ "\"${PODS_ROOT}/../../Firebase/Database\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Persistence\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary\"",
+ "\"${PODS_ROOT}/../../Firebase/Database/Core/View\"",
+ );
+ INFOPLIST_FILE = "Database/Tests/FirebaseTests-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Database-Tests-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Database_Example_tvOS.app/Database_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
+ DE1FAEAC1FBCF5E200897AAA /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 1E5ECEF4C67573595335207D /* Pods-Auth_Example_tvOS.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Auth/App/iOS/Auth-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DE1FAEAD1FBCF5E200897AAA /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9B2AAD4EC2BD3FBC053CBD2A /* Pods-Auth_Example_tvOS.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Auth/App/iOS/Auth-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
DE26D2421F70398A004AE1D3 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 48317719F315960780114559 /* Pods-Auth_Sample.debug.xcconfig */;
+ baseConfigurationReference = 0D4A8F333DE1D31AE14011D4 /* Pods-Auth_Sample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6182,7 +7742,7 @@
};
DE26D2431F70398A004AE1D3 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 8602A8FB9AF04A0C9A8FE380 /* Pods-Auth_Sample.release.xcconfig */;
+ baseConfigurationReference = 3B69D19E3FAF168C8EF37C81 /* Pods-Auth_Sample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6222,7 +7782,7 @@
};
DE26D2651F7049F1004AE1D3 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 09F55B0265DCD315B2DD3C2E /* Pods-Auth_ApiTests.debug.xcconfig */;
+ baseConfigurationReference = A91C660FB541A4CD17BD6559 /* Pods-Auth_ApiTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6254,7 +7814,7 @@
};
DE26D2661F7049F1004AE1D3 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = E8A8A21551A3D8557757AD0D /* Pods-Auth_ApiTests.release.xcconfig */;
+ baseConfigurationReference = A94313324676D16235A36D32 /* Pods-Auth_ApiTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6287,7 +7847,7 @@
};
DE26D2751F705C35004AE1D3 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 94C0FA103316CB56F37E20EA /* Pods-Auth_EarlGreyTests.debug.xcconfig */;
+ baseConfigurationReference = 16182094A8A3749CA6D24429 /* Pods-Auth_EarlGreyTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6319,7 +7879,7 @@
};
DE26D2761F705C35004AE1D3 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0DB176DCABEFDF6C19B302B0 /* Pods-Auth_EarlGreyTests.release.xcconfig */;
+ baseConfigurationReference = 8AB8C5932B72C705E2EBCF1B /* Pods-Auth_EarlGreyTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6352,7 +7912,7 @@
};
DE26D28D1F705EC7004AE1D3 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0CA98384DDFFEECB1D473552 /* Pods-Auth_SwiftSample.debug.xcconfig */;
+ baseConfigurationReference = 01936C31BDE676F86CF8DA39 /* Pods-Auth_SwiftSample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6386,7 +7946,7 @@
};
DE26D28E1F705EC7004AE1D3 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 28B01131418E340D322829AC /* Pods-Auth_SwiftSample.release.xcconfig */;
+ baseConfigurationReference = 91D2A751787B7FDD624919EB /* Pods-Auth_SwiftSample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6452,9 +8012,100 @@
};
name = Release;
};
+ DE5389451FBB62E100199FC2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 70B04F7AEEC14B4E1E8C23D8 /* Pods-Auth_Tests_tvOS.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"${PODS_ROOT}/../../Firebase/Auth/Source/RPCs\"",
+ "\"${PODS_ROOT}/../../Firebase/Auth/Source\"",
+ "\"${PODS_ROOT}/../../Firebase/Auth/Source/AuthProviders\"",
+ );
+ INFOPLIST_FILE = "$(SRCROOT)/Auth/App/iOS/Auth-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ OTHER_LDFLAGS = "$(inherited)";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Auth_Example_tvOS.app/Auth_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DE5389461FBB62E100199FC2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 042AFA12FC20D0683FB59B9E /* Pods-Auth_Tests_tvOS.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"${PODS_ROOT}/../../Firebase/Auth/Source/RPCs\"",
+ "\"${PODS_ROOT}/../../Firebase/Auth/Source\"",
+ "\"${PODS_ROOT}/../../Firebase/Auth/Source/AuthProviders\"",
+ );
+ INFOPLIST_FILE = "$(SRCROOT)/Auth/App/iOS/Auth-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = "$(inherited)";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Auth-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Auth_Example_tvOS.app/Auth_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
+ DE545C811FBCA3F000C637AE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ };
+ name = Release;
+ };
DE7B8D241E8EF078009EB6DF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = E5978C421A9123C9D34CBA43 /* Pods-Database_Example_iOS.debug.xcconfig */;
+ baseConfigurationReference = 3CF8F39CB220DE230DDAEC15 /* Pods-Database_Example_iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6472,7 +8123,7 @@
};
DE7B8D251E8EF078009EB6DF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 5DA6361D6B54362D073F3BA5 /* Pods-Database_Example_iOS.release.xcconfig */;
+ baseConfigurationReference = 381D76A090B5EF6699CA3673 /* Pods-Database_Example_iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6491,7 +8142,7 @@
};
DE7B8D261E8EF078009EB6DF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 000DAC7D0D180A9FBB395BB6 /* Pods-Database_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 5E0F451FE2DF377FEEE0C9CE /* Pods-Database_Tests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6531,7 +8182,7 @@
};
DE7B8D271E8EF078009EB6DF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 2B1B85CD0C7778447F3BFCD5 /* Pods-Database_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = BC23B1A7390BEA04DE724F7C /* Pods-Database_Tests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6572,7 +8223,7 @@
};
DE9314E51E86C6BE0083EDBF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 6029CD8D7E65D491083D5944 /* Pods-Auth_Example_iOS.debug.xcconfig */;
+ baseConfigurationReference = 39D965DC207D9E9C841AB1AF /* Pods-Auth_Example_iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6594,7 +8245,7 @@
};
DE9314E61E86C6BE0083EDBF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0C69403B9730C701BF2E0446 /* Pods-Auth_Example_iOS.release.xcconfig */;
+ baseConfigurationReference = FF3BDAACC6424BF110DC26F2 /* Pods-Auth_Example_iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6616,7 +8267,7 @@
};
DE9314E71E86C6BE0083EDBF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 1735157165B298F2A1EC36E3 /* Pods-Auth_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 9E042E6047B5B5D409AD083F /* Pods-Auth_Tests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6641,7 +8292,7 @@
};
DE9314E81E86C6BE0083EDBF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = D6A450A39BCA3DB4138333D8 /* Pods-Auth_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = 122B6EBA56EAB083239B83DE /* Pods-Auth_Tests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6667,7 +8318,7 @@
};
DE9315B01E8738460083EDBF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 46052D607615BD81295B65C6 /* Pods-Messaging_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 011545D4307696ABBF9658F2 /* Pods-Messaging_Tests_iOS.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
@@ -6697,7 +8348,7 @@
};
DE9315B11E8738460083EDBF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3A304052F4122D3468145F6C /* Pods-Messaging_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = C2C9D2EB11B351A0EEB3B93D /* Pods-Messaging_Tests_iOS.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
@@ -6726,9 +8377,277 @@
};
name = Release;
};
+ DEAAD39C1FBA11280053BF48 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 86E271316861BA45BD9370FC /* Pods-Core_Example_tvOS.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Core/App/tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Core-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DEAAD39D1FBA11280053BF48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = F55411158F1D5AD6FC20B9B9 /* Pods-Core_Example_tvOS.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Core/App/tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Core-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
+ DEAAD39E1FBA11280053BF48 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E18F9020BB494E59BB0DDA2E /* Pods-Core_Tests_tvOS.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "Core/Tests/Tests-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Core-Example-tvOSTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Core_Example_tvOS.app/Core_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DEAAD39F1FBA11280053BF48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = B6BC99F9590CB7AAE33544C3 /* Pods-Core_Tests_tvOS.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "Core/Tests/Tests-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Core-Example-tvOSTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Core_Example_tvOS.app/Core_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
+ DEAAD3FC1FBA46AB0053BF48 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 4F088699064170B6010B477A /* Pods-Storage_Example_tvOS.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Storage/App/tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Storage-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DEAAD3FD1FBA46AB0053BF48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 692B433E797D83866B178F94 /* Pods-Storage_Example_tvOS.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = "$(SRCROOT)/Storage/App/tvOS/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Storage-Example-tvOS";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
+ DEAAD3FE1FBA46AB0053BF48 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3BDE00663D69912D5F2A7101 /* Pods-Storage_Tests_tvOS.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"${PODS_ROOT}/../../Firebase/Storage/Private\"",
+ );
+ INFOPLIST_FILE = "Storage/Tests/Tests-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Storage-Example-tvOSTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Storage_Example_tvOS.app/Storage_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ DEAAD3FF1FBA46AB0053BF48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 63687A1F0EF54DDCBD13E4D4 /* Pods-Storage_Tests_tvOS.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = EQHXZ8M8AV;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"${PODS_ROOT}/../../Firebase/Storage/Private\"",
+ );
+ INFOPLIST_FILE = "Storage/Tests/Tests-Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.google.Storage-Example-tvOSTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = appletvos;
+ TARGETED_DEVICE_FAMILY = 3;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Storage_Example_tvOS.app/Storage_Example_tvOS";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Release;
+ };
DEB13A061E73506A00AC236D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3E26CB853AB2CAF1960A0F71 /* Pods-Storage_Example_iOS.debug.xcconfig */;
+ baseConfigurationReference = 06F3D16439F061DE9973902D /* Pods-Storage_Example_iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
@@ -6749,7 +8668,7 @@
};
DEB13A071E73506A00AC236D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 97790B1C788991008685954F /* Pods-Storage_Example_iOS.release.xcconfig */;
+ baseConfigurationReference = D440FB786B320FCF836B508F /* Pods-Storage_Example_iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
@@ -6770,7 +8689,7 @@
};
DEB13A211E73507E00AC236D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 466C3694B6C68F69BA4DA448 /* Pods-Storage_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 218DAA68383543E59864D4FA /* Pods-Storage_Tests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = "";
@@ -6794,7 +8713,7 @@
};
DEB13A221E73507E00AC236D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = B1EFE04FF3C9650984C5E3C3 /* Pods-Storage_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = 10C5FF4777A334F9F55ED95A /* Pods-Storage_Tests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = "";
@@ -6814,7 +8733,7 @@
};
DEDFEFF31FD1B8C100F7D466 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 77FA2AB612D17244983008F7 /* Pods-Analytics_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 920F3E71E6698FEADDA9D37A /* Pods-Analytics_Tests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6846,7 +8765,7 @@
};
DEDFEFF41FD1B8C100F7D466 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 456CD9478A63272C4397975E /* Pods-Analytics_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = 2DE182937C7CA58E63112FD2 /* Pods-Analytics_Tests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6879,7 +8798,7 @@
};
DEE14D601E84464D006FA992 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 870F50EE08ED74C38B5CAF79 /* Pods-Core_Example_iOS.debug.xcconfig */;
+ baseConfigurationReference = EE6603729203B76D9914EE06 /* Pods-Core_Example_iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6896,7 +8815,7 @@
};
DEE14D611E84464D006FA992 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 1E6C076D38C1763E00A3DACA /* Pods-Core_Example_iOS.release.xcconfig */;
+ baseConfigurationReference = 3A2BAC7CAFE05F790B1E34A1 /* Pods-Core_Example_iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -6914,7 +8833,7 @@
};
DEE14D621E84464D006FA992 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0D66D613C54F5BFF80D9AB63 /* Pods-Core_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = ECDA16775B57C6E80011DD9B /* Pods-Core_Tests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6934,7 +8853,7 @@
};
DEE14D631E84464D006FA992 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = DDF4A6C7CFF20DCCF96071EC /* Pods-Core_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = 0921DBEEC62AE8DCF318657D /* Pods-Core_Tests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -6953,6 +8872,16 @@
};
name = Release;
};
+ DEF6C30C1FBCE70C005D0740 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = AllUnitTests_tvOS;
+ };
+ name = Debug;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -7091,6 +9020,33 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ DE1CD5B61FBA55B000FC031E /* Build configuration list for PBXNativeTarget "Database_Example_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DE1CD5B21FBA55B000FC031E /* Debug */,
+ DE1CD5B31FBA55B000FC031E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DE1EC2861FBA5E63007D18D8 /* Build configuration list for PBXNativeTarget "Database_Tests_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DE1EC2871FBA5E63007D18D8 /* Debug */,
+ DE1EC2881FBA5E63007D18D8 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DE1FAEAB1FBCF5E200897AAA /* Build configuration list for PBXNativeTarget "Auth_Example_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DE1FAEAC1FBCF5E200897AAA /* Debug */,
+ DE1FAEAD1FBCF5E200897AAA /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
DE26D2411F70398A004AE1D3 /* Build configuration list for PBXNativeTarget "Auth_Sample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -7145,6 +9101,24 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ DE5389491FBB62E100199FC2 /* Build configuration list for PBXNativeTarget "Auth_Tests_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DE5389451FBB62E100199FC2 /* Debug */,
+ DE5389461FBB62E100199FC2 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DE545C821FBCA3F000C637AE /* Build configuration list for PBXAggregateTarget "AllUnitTests_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DE545C811FBCA3F000C637AE /* Release */,
+ DEF6C30C1FBCE70C005D0740 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
DE7B8D281E8EF078009EB6DF /* Build configuration list for PBXNativeTarget "Database_Example_iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -7190,6 +9164,42 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ DEAAD3A01FBA11280053BF48 /* Build configuration list for PBXNativeTarget "Core_Example_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DEAAD39C1FBA11280053BF48 /* Debug */,
+ DEAAD39D1FBA11280053BF48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DEAAD3A11FBA11280053BF48 /* Build configuration list for PBXNativeTarget "Core_Tests_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DEAAD39E1FBA11280053BF48 /* Debug */,
+ DEAAD39F1FBA11280053BF48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DEAAD4001FBA46AB0053BF48 /* Build configuration list for PBXNativeTarget "Storage_Example_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DEAAD3FC1FBA46AB0053BF48 /* Debug */,
+ DEAAD3FD1FBA46AB0053BF48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DEAAD4011FBA46AB0053BF48 /* Build configuration list for PBXNativeTarget "Storage_Tests_tvOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DEAAD3FE1FBA46AB0053BF48 /* Debug */,
+ DEAAD3FF1FBA46AB0053BF48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
DEB13A051E73506A00AC236D /* Build configuration list for PBXNativeTarget "Storage_Example_iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/AllUnitTests_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/AllUnitTests_tvOS.xcscheme
new file mode 100644
index 0000000..24d7ae9
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/AllUnitTests_tvOS.xcscheme
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE545C7F1FBCA3F000C637AE"
+ BuildableName = "AllUnitTests_tvOS"
+ BlueprintName = "AllUnitTests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3941FBA11270053BF48"
+ BuildableName = "Core_Tests_tvOS.xctest"
+ BlueprintName = "Core_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1EC27E1FBA5E63007D18D8"
+ BuildableName = "Database_Tests_tvOS.xctest"
+ BlueprintName = "Database_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3F41FBA46AB0053BF48"
+ BuildableName = "Storage_Tests_tvOS.xctest"
+ BlueprintName = "Storage_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE53893D1FBB62E100199FC2"
+ BuildableName = "Auth_Tests_tvOS.xctest"
+ BlueprintName = "Auth_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE545C7F1FBCA3F000C637AE"
+ BuildableName = "AllUnitTests_tvOS"
+ BlueprintName = "AllUnitTests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE545C7F1FBCA3F000C637AE"
+ BuildableName = "AllUnitTests_tvOS"
+ BlueprintName = "AllUnitTests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE545C7F1FBCA3F000C637AE"
+ BuildableName = "AllUnitTests_tvOS"
+ BlueprintName = "AllUnitTests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Example_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Example_tvOS.xcscheme
new file mode 100644
index 0000000..92ef985
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Example_tvOS.xcscheme
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1FAE8F1FBCF5E100897AAA"
+ BuildableName = "Auth_Example_tvOS.app"
+ BlueprintName = "Auth_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE53893D1FBB62E100199FC2"
+ BuildableName = "Auth_Tests_tvOS.xctest"
+ BlueprintName = "Auth_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1FAE8F1FBCF5E100897AAA"
+ BuildableName = "Auth_Example_tvOS.app"
+ BlueprintName = "Auth_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1FAE8F1FBCF5E100897AAA"
+ BuildableName = "Auth_Example_tvOS.app"
+ BlueprintName = "Auth_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1FAE8F1FBCF5E100897AAA"
+ BuildableName = "Auth_Example_tvOS.app"
+ BlueprintName = "Auth_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Tests_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Tests_tvOS.xcscheme
new file mode 100644
index 0000000..10f6028
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Auth_Tests_tvOS.xcscheme
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE53893D1FBB62E100199FC2"
+ BuildableName = "Auth_Tests_tvOS.xctest"
+ BlueprintName = "Auth_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1FAEA31FBCF5E200897AAA"
+ BuildableName = "Auth_Example_tvOSTests.xctest"
+ BlueprintName = "Auth_Example_tvOSTests"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Example_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Example_tvOS.xcscheme
new file mode 100644
index 0000000..a499aca
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Example_tvOS.xcscheme
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3801FBA11270053BF48"
+ BuildableName = "Core_Example_tvOS.app"
+ BlueprintName = "Core_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3941FBA11270053BF48"
+ BuildableName = "Core_Tests_tvOS.xctest"
+ BlueprintName = "Core_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3801FBA11270053BF48"
+ BuildableName = "Core_Example_tvOS.app"
+ BlueprintName = "Core_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3801FBA11270053BF48"
+ BuildableName = "Core_Example_tvOS.app"
+ BlueprintName = "Core_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3801FBA11270053BF48"
+ BuildableName = "Core_Example_tvOS.app"
+ BlueprintName = "Core_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Tests_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Tests_tvOS.xcscheme
new file mode 100644
index 0000000..29e1d7e
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Core_Tests_tvOS.xcscheme
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3941FBA11270053BF48"
+ BuildableName = "Core_Tests_tvOS.xctest"
+ BlueprintName = "Core_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Example_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Example_tvOS.xcscheme
new file mode 100644
index 0000000..8f1f744
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Example_tvOS.xcscheme
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1CD5961FBA55AF00FC031E"
+ BuildableName = "Database_Example_tvOS.app"
+ BlueprintName = "Database_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1EC27E1FBA5E63007D18D8"
+ BuildableName = "Database_Tests_tvOS.xctest"
+ BlueprintName = "Database_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1CD5961FBA55AF00FC031E"
+ BuildableName = "Database_Example_tvOS.app"
+ BlueprintName = "Database_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1CD5961FBA55AF00FC031E"
+ BuildableName = "Database_Example_tvOS.app"
+ BlueprintName = "Database_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1CD5961FBA55AF00FC031E"
+ BuildableName = "Database_Example_tvOS.app"
+ BlueprintName = "Database_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Tests_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Tests_tvOS.xcscheme
new file mode 100644
index 0000000..1174631
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Database_Tests_tvOS.xcscheme
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DE1EC27E1FBA5E63007D18D8"
+ BuildableName = "Database_Tests_tvOS.xctest"
+ BlueprintName = "Database_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Example_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Example_tvOS.xcscheme
new file mode 100644
index 0000000..7cd609f
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Example_tvOS.xcscheme
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3E01FBA46AA0053BF48"
+ BuildableName = "Storage_Example_tvOS.app"
+ BlueprintName = "Storage_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3F41FBA46AB0053BF48"
+ BuildableName = "Storage_Tests_tvOS.xctest"
+ BlueprintName = "Storage_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3E01FBA46AA0053BF48"
+ BuildableName = "Storage_Example_tvOS.app"
+ BlueprintName = "Storage_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3E01FBA46AA0053BF48"
+ BuildableName = "Storage_Example_tvOS.app"
+ BlueprintName = "Storage_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3E01FBA46AA0053BF48"
+ BuildableName = "Storage_Example_tvOS.app"
+ BlueprintName = "Storage_Example_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Tests_tvOS.xcscheme b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Tests_tvOS.xcscheme
new file mode 100644
index 0000000..abc482e
--- /dev/null
+++ b/Example/Firebase.xcodeproj/xcshareddata/xcschemes/Storage_Tests_tvOS.xcscheme
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0910"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DEAAD3F41FBA46AB0053BF48"
+ BuildableName = "Storage_Tests_tvOS.xctest"
+ BlueprintName = "Storage_Tests_tvOS"
+ ReferencedContainer = "container:Firebase.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/Example/Messaging/App/GoogleService-Info.plist b/Example/Messaging/App/GoogleService-Info.plist
index 89afffe..3f7547f 100644
--- a/Example/Messaging/App/GoogleService-Info.plist
+++ b/Example/Messaging/App/GoogleService-Info.plist
@@ -10,8 +10,6 @@
<string>correct_client_id</string>
<key>REVERSED_CLIENT_ID</key>
<string>correct_reversed_client_id</string>
- <key>ANDROID_CLIENT_ID</key>
- <string>correct_android_client_id</string>
<key>GOOGLE_APP_ID</key>
<string>1:123:ios:123abc</string>
<key>GCM_SENDER_ID</key>
diff --git a/Example/Messaging/App/iOS/Messaging-Info.plist b/Example/Messaging/App/iOS/Messaging-Info.plist
index e42f39d..b43105e 100644
--- a/Example/Messaging/App/iOS/Messaging-Info.plist
+++ b/Example/Messaging/App/iOS/Messaging-Info.plist
@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>FirebaseMessagingAutoInitEnabled</key>
+ <false/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
diff --git a/Example/Messaging/Tests/FIRMessagingServiceTest.m b/Example/Messaging/Tests/FIRMessagingServiceTest.m
index c2b0853..c8d61c2 100644
--- a/Example/Messaging/Tests/FIRMessagingServiceTest.m
+++ b/Example/Messaging/Tests/FIRMessagingServiceTest.m
@@ -198,7 +198,8 @@
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
messaging.pubsub = mockPubSub;
messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub subscribeToTopic:[OCMArg isEqual:topicNameWithPrefix]]);
+ OCMExpect([messaging.pubsub subscribeToTopic:[OCMArg isEqual:topicNameWithPrefix]
+ handler:[OCMArg any]]);
[messaging subscribeToTopic:topicName];
OCMVerifyAll(mockPubSub);
// Need to swap back since it's a singleton and hence will live beyond the scope of this test.
@@ -213,7 +214,7 @@
NSString *topicName = @"/topics/topicWithoutPrefix";
messaging.pubsub = mockPubSub;
messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub subscribeToTopic:[OCMArg isEqual:topicName]]);
+ OCMExpect([messaging.pubsub subscribeToTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
[messaging subscribeToTopic:topicName];
OCMVerifyAll(mockPubSub);
// Need to swap back since it's a singleton and hence will live beyond the scope of this test.
@@ -229,7 +230,8 @@
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
messaging.pubsub = mockPubSub;
messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub unsubscribeFromTopic:[OCMArg isEqual:topicNameWithPrefix]]);
+ OCMExpect([messaging.pubsub unsubscribeFromTopic:[OCMArg isEqual:topicNameWithPrefix]
+ handler:[OCMArg any]]);
[messaging unsubscribeFromTopic:topicName];
OCMVerifyAll(mockPubSub);
// Need to swap back since it's a singleton and hence will live beyond the scope of this test.
@@ -244,7 +246,8 @@
NSString *topicName = @"/topics/topicWithPrefix";
messaging.pubsub = mockPubSub;
messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub unsubscribeFromTopic:[OCMArg isEqual:topicName]]);
+ OCMExpect([messaging.pubsub unsubscribeFromTopic:[OCMArg isEqual:topicName]
+ handler:[OCMArg any]]);
[messaging unsubscribeFromTopic:topicName];
OCMVerifyAll(mockPubSub);
// Need to swap back since it's a singleton and hence will live beyond the scope of this test.
diff --git a/Example/Messaging/Tests/FIRMessagingTest.m b/Example/Messaging/Tests/FIRMessagingTest.m
index 09cdffc..86ed647 100644
--- a/Example/Messaging/Tests/FIRMessagingTest.m
+++ b/Example/Messaging/Tests/FIRMessagingTest.m
@@ -20,6 +20,7 @@
#import "FIRMessaging.h"
#import "FIRMessagingInstanceIDProxy.h"
+#import "FIRMessaging_Private.h"
extern NSString *const kFIRMessagingFCMTokenFetchAPNSOption;
@@ -28,6 +29,7 @@ extern NSString *const kFIRMessagingFCMTokenFetchAPNSOption;
@property(nonatomic, readwrite, strong) NSString *defaultFcmToken;
@property(nonatomic, readwrite, strong) NSData *apnsTokenData;
@property(nonatomic, readwrite, strong) FIRMessagingInstanceIDProxy *instanceIDProxy;
+@property(nonatomic, readwrite, strong) NSUserDefaults *messagingUserDefaults;
- (instancetype)initPrivately;
// Direct Channel Methods
@@ -52,6 +54,9 @@ extern NSString *const kFIRMessagingFCMTokenFetchAPNSOption;
_mockMessaging = OCMPartialMock(self.messaging);
_mockInstanceIDProxy = OCMPartialMock(self.messaging.instanceIDProxy);
self.messaging.instanceIDProxy = _mockInstanceIDProxy;
+ [self.messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingSuiteName];
+ self.messaging.messagingUserDefaults =
+ [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingSuiteName];
}
- (void)tearDown {
@@ -60,6 +65,15 @@ extern NSString *const kFIRMessagingFCMTokenFetchAPNSOption;
[super tearDown];
}
+- (void)testAutoInitEnableFlag {
+ // Should read from Info.plist
+ XCTAssertFalse(_messaging.isAutoInitEnabled);
+
+ // Now set the flag should overwrite Info.plist value.
+ _messaging.autoInitEnabled = YES;
+ XCTAssertTrue(_messaging.isAutoInitEnabled);
+}
+
#pragma mark - Direct Channel Establishment Testing
// Should connect with valid token and application in foreground
diff --git a/Example/Messaging/Tests/Info.plist b/Example/Messaging/Tests/Info.plist
index ba72822..4df9372 100644
--- a/Example/Messaging/Tests/Info.plist
+++ b/Example/Messaging/Tests/Info.plist
@@ -20,5 +20,7 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
+ <key>FirebaseMessagingAutoInitEnabled</key>
+ <false/>
</dict>
</plist>
diff --git a/Example/Podfile b/Example/Podfile
index 164ca72..576d8d0 100644
--- a/Example/Podfile
+++ b/Example/Podfile
@@ -8,7 +8,7 @@ target 'Core_Example_iOS' do
# The next line is the forcing function for the Firebase pod. The Firebase
# version's subspecs should depend on the component versions in their
# corresponding podspec's.
- pod 'Firebase/Core', '4.7.0'
+ pod 'Firebase/Core', '4.8.2'
target 'Core_Tests_iOS' do
inherit! :search_paths
@@ -157,6 +157,60 @@ target 'Storage_Example_macOS' do
end
end
+target 'Core_Example_tvOS' do
+ platform :tvos, '10.0'
+
+ target 'Core_Tests_tvOS' do
+ inherit! :search_paths
+ pod 'OCMock'
+ end
+end
+
+target 'Auth_Example_tvOS' do
+ platform :tvos, '10.0'
+
+ pod 'FirebaseAuth', :path => '../'
+
+ target 'Auth_Tests_tvOS' do
+ inherit! :search_paths
+ pod 'OCMock'
+ end
+end
+
+target 'Database_Example_tvOS' do
+ platform :tvos, '10.0'
+
+ pod 'FirebaseDatabase', :path => '../'
+
+ target 'Database_Tests_tvOS' do
+ inherit! :search_paths
+ pod 'OCMock'
+ end
+
+# TODO
+# target 'Database_IntegrationTests_tvOS' do
+# inherit! :search_paths
+# pod 'OCMock'
+# end
+end
+
+target 'Storage_Example_tvOS' do
+ platform :tvos, '10.0'
+
+ pod 'FirebaseStorage', :path => '../'
+
+ target 'Storage_Tests_tvOS' do
+ inherit! :search_paths
+ pod 'OCMock'
+ end
+
+#TODO Storage_IntegrationTests_tvOS
+# target 'Storage_IntegrationTests_tvOS' do
+# inherit! :search_paths
+# pod 'OCMock'
+# end
+end
+
# This post_install workaround should be removed when FirebaseAnalytics
# removes its module includes to FirebaseCore.
diff --git a/Example/Storage/App/GoogleService-Info.plist b/Example/Storage/App/GoogleService-Info.plist
index 89afffe..3f7547f 100644
--- a/Example/Storage/App/GoogleService-Info.plist
+++ b/Example/Storage/App/GoogleService-Info.plist
@@ -10,8 +10,6 @@
<string>correct_client_id</string>
<key>REVERSED_CLIENT_ID</key>
<string>correct_reversed_client_id</string>
- <key>ANDROID_CLIENT_ID</key>
- <string>correct_android_client_id</string>
<key>GOOGLE_APP_ID</key>
<string>1:123:ios:123abc</string>
<key>GCM_SENDER_ID</key>
diff --git a/Example/Storage/App/tvOS/AppDelegate.h b/Example/Storage/App/tvOS/AppDelegate.h
new file mode 100644
index 0000000..013891c
--- /dev/null
+++ b/Example/Storage/App/tvOS/AppDelegate.h
@@ -0,0 +1,21 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/Example/Storage/App/tvOS/AppDelegate.m b/Example/Storage/App/tvOS/AppDelegate.m
new file mode 100644
index 0000000..fb6dbcf
--- /dev/null
+++ b/Example/Storage/App/tvOS/AppDelegate.m
@@ -0,0 +1,63 @@
+// Copyright 2017 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 FirebaseCore;
+@import FirebaseStorage;
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ [FIRApp configure];
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+ // Sent when the application is about to move from active to inactive state. This can occur for
+ // certain types of temporary interruptions (such as an incoming phone call or SMS message) or
+ // when the user quits the application and it begins the transition to the background state. Use
+ // this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates.
+ // Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ // Use this method to release shared resources, save user data, invalidate timers, and store
+ // enough application state information to restore your application to its current state in case
+ // it is terminated later. If your application supports background execution, this method is
+ // called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ // Called as part of the transition from the background to the active state; here you can undo
+ // many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If
+ // the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+ // Called when the application is about to terminate. Save data if appropriate. See also
+ // applicationDidEnterBackground:.
+}
+
+@end
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
new file mode 100644
index 0000000..b03ded1
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
@@ -0,0 +1,32 @@
+{
+ "assets" : [
+ {
+ "size" : "1280x768",
+ "idiom" : "tv",
+ "filename" : "App Icon - App Store.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "400x240",
+ "idiom" : "tv",
+ "filename" : "App Icon.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "2320x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image Wide.imageset",
+ "role" : "top-shelf-image-wide"
+ },
+ {
+ "size" : "1920x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image.imageset",
+ "role" : "top-shelf-image"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json b/Example/Storage/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..d746a60
--- /dev/null
+++ b/Example/Storage/App/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "11.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "9.0",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/Storage/App/tvOS/Info.plist b/Example/Storage/App/tvOS/Info.plist
new file mode 100644
index 0000000..02942a3
--- /dev/null
+++ b/Example/Storage/App/tvOS/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>arm64</string>
+ </array>
+ <key>UIUserInterfaceStyle</key>
+ <string>Automatic</string>
+</dict>
+</plist>
diff --git a/Example/Storage/App/tvOS/Main.storyboard b/Example/Storage/App/tvOS/Main.storyboard
new file mode 100644
index 0000000..72d5e22
--- /dev/null
+++ b/Example/Storage/App/tvOS/Main.storyboard
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" systemVersion="17A278a" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+ <viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/Example/Storage/App/tvOS/ViewController.h b/Example/Storage/App/tvOS/ViewController.h
new file mode 100644
index 0000000..b6115b8
--- /dev/null
+++ b/Example/Storage/App/tvOS/ViewController.h
@@ -0,0 +1,19 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+@end
diff --git a/Example/Storage/App/tvOS/ViewController.m b/Example/Storage/App/tvOS/ViewController.m
new file mode 100644
index 0000000..6d4676b
--- /dev/null
+++ b/Example/Storage/App/tvOS/ViewController.m
@@ -0,0 +1,33 @@
+// Copyright 2017 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 "ViewController.h"
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/Example/Storage/App/tvOS/main.m b/Example/Storage/App/tvOS/main.m
new file mode 100644
index 0000000..d9e6654
--- /dev/null
+++ b/Example/Storage/App/tvOS/main.m
@@ -0,0 +1,22 @@
+// Copyright 2017 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 <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/Example/Storage/Tests/Unit/FIRStorageTests.m b/Example/Storage/Tests/Unit/FIRStorageTests.m
index 503ac94..4086f62 100644
--- a/Example/Storage/Tests/Unit/FIRStorageTests.m
+++ b/Example/Storage/Tests/Unit/FIRStorageTests.m
@@ -79,7 +79,7 @@
}
- (void)testInitWithNilURL {
- XCTAssertThrows([FIRStorage storageForApp:self.app URL:nil]);
+ XCTAssertThrows([FIRStorage storageForApp:self.app URL:(id _Nonnull)nil]);
}
- (void)testInitWithPath {
diff --git a/Example/tvOSSample/Podfile b/Example/tvOSSample/Podfile
new file mode 100644
index 0000000..1e79a07
--- /dev/null
+++ b/Example/tvOSSample/Podfile
@@ -0,0 +1,14 @@
+# Uncomment the next line to define a global platform for your project
+# platform :ios, '9.0'
+
+target 'tvOSSample' do
+ # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
+ use_frameworks!
+
+ # Pods for tvOSSample
+ pod 'FirebaseCore', :path => '../../'
+ pod 'FirebaseAuth', :path => '../../'
+ pod 'FirebaseDatabase', :path => '../../'
+ pod 'FirebaseStorage', :path => '../../'
+
+end
diff --git a/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj b/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..60d2d25
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample.xcodeproj/project.pbxproj
@@ -0,0 +1,424 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 48;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ B7F83BACE8E8330E2A5C0861 /* Pods_tvOSSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCE8CD052953D89D96C9CDC /* Pods_tvOSSample.framework */; };
+ DE397DCB1FC8AD39007CBF0E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = ED4D5FEB1FBA055300501573 /* GoogleService-Info.plist */; };
+ ED4D5FDD1FBA008200501573 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4D5FDC1FBA008200501573 /* AppDelegate.swift */; };
+ ED4D5FE21FBA008200501573 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ED4D5FE01FBA008200501573 /* Main.storyboard */; };
+ ED4D5FE41FBA008200501573 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ED4D5FE31FBA008200501573 /* Assets.xcassets */; };
+ ED822C851FBA212600B00A2F /* StorageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED822C841FBA212600B00A2F /* StorageViewController.swift */; };
+ EDFBCF4C1FBB3ACC0041A9FD /* DatabaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDFBCF4B1FBB3ACC0041A9FD /* DatabaseViewController.swift */; };
+ EDFBCF511FBC88D20041A9FD /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDFBCF501FBC88D20041A9FD /* AuthViewController.swift */; };
+ EDFBCF531FBC89B70041A9FD /* AuthLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDFBCF521FBC89B70041A9FD /* AuthLoginViewController.swift */; };
+ EDFBCF551FBC95DD0041A9FD /* EmailLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDFBCF541FBC95DD0041A9FD /* EmailLoginViewController.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 3F2496EBDAD58301BC9119C5 /* Pods-tvOSSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tvOSSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-tvOSSample/Pods-tvOSSample.debug.xcconfig"; sourceTree = "<group>"; };
+ 5CCE8CD052953D89D96C9CDC /* Pods_tvOSSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_tvOSSample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ E0A4F4B42E46BAA2DF7A366E /* Pods-tvOSSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-tvOSSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-tvOSSample/Pods-tvOSSample.release.xcconfig"; sourceTree = "<group>"; };
+ ED4D5FD91FBA008200501573 /* tvOSSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tvOSSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ ED4D5FDC1FBA008200501573 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+ ED4D5FE11FBA008200501573 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ ED4D5FE31FBA008200501573 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ ED4D5FE51FBA008300501573 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ ED4D5FEB1FBA055300501573 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
+ ED822C841FBA212600B00A2F /* StorageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageViewController.swift; sourceTree = "<group>"; };
+ EDFBCF4B1FBB3ACC0041A9FD /* DatabaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseViewController.swift; sourceTree = "<group>"; };
+ EDFBCF501FBC88D20041A9FD /* AuthViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewController.swift; sourceTree = "<group>"; };
+ EDFBCF521FBC89B70041A9FD /* AuthLoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthLoginViewController.swift; sourceTree = "<group>"; };
+ EDFBCF541FBC95DD0041A9FD /* EmailLoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailLoginViewController.swift; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ ED4D5FD61FBA008200501573 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7F83BACE8E8330E2A5C0861 /* Pods_tvOSSample.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ A45A5C3CB0C23372780D9FA9 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 3F2496EBDAD58301BC9119C5 /* Pods-tvOSSample.debug.xcconfig */,
+ E0A4F4B42E46BAA2DF7A366E /* Pods-tvOSSample.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ BA0B7BD0C775F3B6FDDCCEB5 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 5CCE8CD052953D89D96C9CDC /* Pods_tvOSSample.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ ED4D5FD01FBA008200501573 = {
+ isa = PBXGroup;
+ children = (
+ ED4D5FDB1FBA008200501573 /* tvOSSample */,
+ ED4D5FDA1FBA008200501573 /* Products */,
+ A45A5C3CB0C23372780D9FA9 /* Pods */,
+ BA0B7BD0C775F3B6FDDCCEB5 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ ED4D5FDA1FBA008200501573 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ ED4D5FD91FBA008200501573 /* tvOSSample.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ ED4D5FDB1FBA008200501573 /* tvOSSample */ = {
+ isa = PBXGroup;
+ children = (
+ ED4D5FEB1FBA055300501573 /* GoogleService-Info.plist */,
+ ED4D5FDC1FBA008200501573 /* AppDelegate.swift */,
+ ED4D5FE01FBA008200501573 /* Main.storyboard */,
+ ED4D5FE31FBA008200501573 /* Assets.xcassets */,
+ ED4D5FE51FBA008300501573 /* Info.plist */,
+ ED822C841FBA212600B00A2F /* StorageViewController.swift */,
+ EDFBCF501FBC88D20041A9FD /* AuthViewController.swift */,
+ EDFBCF521FBC89B70041A9FD /* AuthLoginViewController.swift */,
+ EDFBCF541FBC95DD0041A9FD /* EmailLoginViewController.swift */,
+ EDFBCF4B1FBB3ACC0041A9FD /* DatabaseViewController.swift */,
+ );
+ path = tvOSSample;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ ED4D5FD81FBA008200501573 /* tvOSSample */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = ED4D5FE81FBA008300501573 /* Build configuration list for PBXNativeTarget "tvOSSample" */;
+ buildPhases = (
+ D5025FECAC3B7FED5FF1A46A /* [CP] Check Pods Manifest.lock */,
+ ED4D5FD51FBA008200501573 /* Sources */,
+ ED4D5FD61FBA008200501573 /* Frameworks */,
+ ED4D5FD71FBA008200501573 /* Resources */,
+ 1D04A7E6AB24B35668030EB4 /* [CP] Embed Pods Frameworks */,
+ 3A8B26C16219186ABE0EDF0F /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tvOSSample;
+ productName = tvOSSample;
+ productReference = ED4D5FD91FBA008200501573 /* tvOSSample.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ ED4D5FD11FBA008200501573 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0910;
+ LastUpgradeCheck = 0910;
+ ORGANIZATIONNAME = Firebase;
+ TargetAttributes = {
+ ED4D5FD81FBA008200501573 = {
+ CreatedOnToolsVersion = 9.1;
+ ProvisioningStyle = Manual;
+ };
+ };
+ };
+ buildConfigurationList = ED4D5FD41FBA008200501573 /* Build configuration list for PBXProject "tvOSSample" */;
+ compatibilityVersion = "Xcode 8.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = ED4D5FD01FBA008200501573;
+ productRefGroup = ED4D5FDA1FBA008200501573 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ ED4D5FD81FBA008200501573 /* tvOSSample */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ ED4D5FD71FBA008200501573 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ED4D5FE41FBA008200501573 /* Assets.xcassets in Resources */,
+ ED4D5FE21FBA008200501573 /* Main.storyboard in Resources */,
+ DE397DCB1FC8AD39007CBF0E /* GoogleService-Info.plist in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 1D04A7E6AB24B35668030EB4 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-tvOSSample/Pods-tvOSSample-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-tvOSSample/Pods-tvOSSample-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 3A8B26C16219186ABE0EDF0F /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-tvOSSample/Pods-tvOSSample-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ D5025FECAC3B7FED5FF1A46A /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-tvOSSample-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ ED4D5FD51FBA008200501573 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ EDFBCF551FBC95DD0041A9FD /* EmailLoginViewController.swift in Sources */,
+ EDFBCF4C1FBB3ACC0041A9FD /* DatabaseViewController.swift in Sources */,
+ ED4D5FDD1FBA008200501573 /* AppDelegate.swift in Sources */,
+ EDFBCF511FBC88D20041A9FD /* AuthViewController.swift in Sources */,
+ EDFBCF531FBC89B70041A9FD /* AuthLoginViewController.swift in Sources */,
+ ED822C851FBA212600B00A2F /* StorageViewController.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ ED4D5FE01FBA008200501573 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ ED4D5FE11FBA008200501573 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ ED4D5FE61FBA008300501573 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = appletvos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ };
+ name = Debug;
+ };
+ ED4D5FE71FBA008300501573 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = appletvos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ TVOS_DEPLOYMENT_TARGET = 11.1;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ ED4D5FE91FBA008300501573 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3F2496EBDAD58301BC9119C5 /* Pods-tvOSSample.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = tvOSSample/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.firebase.tvOSSample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_VERSION = 4.0;
+ TARGETED_DEVICE_FAMILY = 3;
+ };
+ name = Debug;
+ };
+ ED4D5FEA1FBA008300501573 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E0A4F4B42E46BAA2DF7A366E /* Pods-tvOSSample.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = tvOSSample/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.firebase.tvOSSample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_VERSION = 4.0;
+ TARGETED_DEVICE_FAMILY = 3;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ ED4D5FD41FBA008200501573 /* Build configuration list for PBXProject "tvOSSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ED4D5FE61FBA008300501573 /* Debug */,
+ ED4D5FE71FBA008300501573 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ ED4D5FE81FBA008300501573 /* Build configuration list for PBXNativeTarget "tvOSSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ED4D5FE91FBA008300501573 /* Debug */,
+ ED4D5FEA1FBA008300501573 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = ED4D5FD11FBA008200501573 /* Project object */;
+}
diff --git a/Example/tvOSSample/tvOSSample/AppDelegate.swift b/Example/tvOSSample/tvOSSample/AppDelegate.swift
new file mode 100644
index 0000000..9a0d052
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/AppDelegate.swift
@@ -0,0 +1,29 @@
+// Copyright 2017 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 UIKit
+import FirebaseCore
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+ // Override point for customization after application launch.
+ FirebaseApp.configure()
+ return true
+ }
+}
+
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..7f06667
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
new file mode 100644
index 0000000..d29f024
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json
@@ -0,0 +1,17 @@
+{
+ "layers" : [
+ {
+ "filename" : "Front.imagestacklayer"
+ },
+ {
+ "filename" : "Middle.imagestacklayer"
+ },
+ {
+ "filename" : "Back.imagestacklayer"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
new file mode 100644
index 0000000..b03ded1
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json
@@ -0,0 +1,32 @@
+{
+ "assets" : [
+ {
+ "size" : "1280x768",
+ "idiom" : "tv",
+ "filename" : "App Icon - App Store.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "400x240",
+ "idiom" : "tv",
+ "filename" : "App Icon.imagestack",
+ "role" : "primary-app-icon"
+ },
+ {
+ "size" : "2320x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image Wide.imageset",
+ "role" : "top-shelf-image-wide"
+ },
+ {
+ "size" : "1920x720",
+ "idiom" : "tv",
+ "filename" : "Top Shelf Image.imageset",
+ "role" : "top-shelf-image"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
new file mode 100644
index 0000000..16a370d
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "idiom" : "tv",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "tv",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/Assets.xcassets/LaunchImage.launchimage/Contents.json b/Example/tvOSSample/tvOSSample/Assets.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..d746a60
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Assets.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "11.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "tv",
+ "extent" : "full-screen",
+ "minimum-system-version" : "9.0",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/Example/tvOSSample/tvOSSample/AuthLoginViewController.swift b/Example/tvOSSample/tvOSSample/AuthLoginViewController.swift
new file mode 100644
index 0000000..dcf72d4
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/AuthLoginViewController.swift
@@ -0,0 +1,40 @@
+// Copyright 2017 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 UIKit
+import FirebaseAuth
+
+class AuthLoginViewController: UIViewController {
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ // Do any additional setup after loading the view.
+ }
+
+ override func didReceiveMemoryWarning() {
+ super.didReceiveMemoryWarning()
+ // Dispose of any resources that can be recreated.
+ }
+
+ /*
+ // MARK: - Navigation
+
+ // In a storyboard-based application, you will often want to do a little preparation before navigation
+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+ // Get the new view controller using segue.destinationViewController.
+ // Pass the selected object to the new view controller.
+ }
+ */
+}
diff --git a/Example/tvOSSample/tvOSSample/AuthViewController.swift b/Example/tvOSSample/tvOSSample/AuthViewController.swift
new file mode 100644
index 0000000..72351d3
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/AuthViewController.swift
@@ -0,0 +1,86 @@
+// Copyright 2017 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 UIKit
+import FirebaseAuth
+
+class AuthViewController: UIViewController {
+
+ // MARK: - User Interface
+
+ /// A stackview containing all of the buttons to providers (Email, OAuth, etc).
+ @IBOutlet weak var providers: UIStackView!
+
+ /// A stackview containing a signed in label and sign out button.
+ @IBOutlet weak var signedIn: UIStackView!
+
+ /// A label to display the status for the signed in user.
+ @IBOutlet weak var signInStatus: UILabel!
+
+ // MARK: - User Actions
+
+ @IBAction func signOutButtonHit(_ sender: UIButton) {
+ // Sign out via Auth and update the UI.
+ try? Auth.auth().signOut()
+
+ setUserSignedIn(nil)
+ }
+
+ // MARK: - View Controller Lifecycle
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ // Update the UI based on the current user (if there is one).
+ setUserSignedIn(Auth.auth().currentUser)
+ }
+
+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+ let destination = segue.destination
+ if let emailVC = destination as? EmailLoginViewController {
+ emailVC.delegate = self
+ }
+ }
+
+ // MARK: - Internal Helpers
+
+ private func setUserSignedIn(_ user: User?) {
+ if let user = user {
+ providers.isHidden = true
+ signedIn.isHidden = false
+
+ signInStatus.text = "User is signed in via \(user.providerID) and the UID \(user.uid)"
+ } else {
+ // User is signed out, hide the signed in state and show the providers.
+ providers.isHidden = false
+ signedIn.isHidden = true
+ }
+ }
+}
+
+// MARK: - EmailLoginDelegate conformance.
+
+extension AuthViewController: EmailLoginDelegate {
+ func emailLogin(_ controller: EmailLoginViewController, signedInAs user: User) {
+ setUserSignedIn(user)
+ dismiss(animated: true)
+ }
+
+ func emailLogin(_ controller: EmailLoginViewController, failedWithError error: Error) {
+ print("Fail..... \(error)")
+ DispatchQueue.main.async {
+ controller.presentError(with: "There was an issue logging in. Please try again.")
+ }
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/Base.lproj/Main.storyboard b/Example/tvOSSample/tvOSSample/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..a2539b3
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Base.lproj/Main.storyboard
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13529" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="7zF-dN-6Yw">
+ <device id="appleTV" orientation="landscape">
+ <adaptation id="light"/>
+ </device>
+ <dependencies>
+ <deployment identifier="tvOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
+ <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <customFonts key="customFonts">
+ <array key="HelveticaNeue.ttc">
+ <string>HelveticaNeue</string>
+ </array>
+ </customFonts>
+ <scenes>
+ <!--Storage-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController title="Storage" id="BYZ-38-t0r" customClass="StorageViewController" customModule="tvOSSample" customModuleProvider="target" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="G46-SV-2zY">
+ <rect key="frame" x="90" y="60" width="1740" height="960"/>
+ <subviews>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" text="Hello, Firebase!" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g3G-9d-w9c">
+ <rect key="frame" x="628" y="0.0" width="484" height="91"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="1Ht-Xf-hyX">
+ <rect key="frame" x="0.0" y="111" width="1740" height="677"/>
+ </imageView>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" text="State: Pending download" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4sv-2l-7R6">
+ <rect key="frame" x="657" y="808" width="427" height="46"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <stackView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="253" verticalCompressionResistancePriority="749" distribution="fillEqually" spacing="60" translatesAutoresizingMaskIntoConstraints="NO" id="Pcd-oU-DKI" userLabel="Button Stack View">
+ <rect key="frame" x="589" y="874" width="562" height="86"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ERN-SX-QsK">
+ <rect key="frame" x="0.0" y="0.0" width="251" height="86"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="Download"/>
+ <connections>
+ <action selector="downloadButtonHit:" destination="BYZ-38-t0r" eventType="primaryActionTriggered" id="wUX-Vk-IME"/>
+ </connections>
+ </button>
+ <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tx1-wP-N8v">
+ <rect key="frame" x="311" y="0.0" width="251" height="86"/>
+ <color key="backgroundColor" red="1" green="0.40000000600000002" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="Clear"/>
+ <connections>
+ <action selector="clearButtonHit:" destination="BYZ-38-t0r" eventType="primaryActionTriggered" id="s8P-pU-T19"/>
+ </connections>
+ </button>
+ </subviews>
+ </stackView>
+ </subviews>
+ </stackView>
+ </subviews>
+ <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstItem="G46-SV-2zY" firstAttribute="leading" secondItem="wu6-TO-1qx" secondAttribute="leading" id="HA1-L9-mG6"/>
+ <constraint firstItem="wu6-TO-1qx" firstAttribute="trailing" secondItem="G46-SV-2zY" secondAttribute="trailing" id="f82-FP-nqR"/>
+ <constraint firstItem="G46-SV-2zY" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="gcN-NC-PDe"/>
+ <constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="G46-SV-2zY" secondAttribute="bottom" id="hb7-C3-J4p"/>
+ </constraints>
+ <viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
+ </view>
+ <extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
+ <tabBarItem key="tabBarItem" title="Storage" id="4mO-Ls-vgJ"/>
+ <connections>
+ <outlet property="clearButton" destination="tx1-wP-N8v" id="lQA-AQ-sT6"/>
+ <outlet property="downloadButton" destination="ERN-SX-QsK" id="2Kf-3u-AxO"/>
+ <outlet property="imageView" destination="1Ht-Xf-hyX" id="MeV-di-b99"/>
+ <outlet property="stateLabel" destination="4sv-2l-7R6" id="DKm-L2-aiR"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="-3032" y="1936"/>
+ </scene>
+ <!--Database-->
+ <scene sceneID="i8D-25-rvO">
+ <objects>
+ <viewController id="gup-Ft-HnK" customClass="DatabaseViewController" customModule="tvOSSample" customModuleProvider="target" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="i5o-My-7RI"/>
+ <viewControllerLayoutGuide type="bottom" id="R20-Wh-bn4"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="1lM-LN-Cey">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="Bah-Ek-V99">
+ <rect key="frame" x="90" y="60" width="1740" height="960"/>
+ <subviews>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="253" verticalCompressionResistancePriority="1000" text="Magic Syncing Counter" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Pjh-c5-D2o">
+ <rect key="frame" x="0.0" y="0.0" width="1740" height="91"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalCompressionResistancePriority="900" text="?" textAlignment="center" lineBreakMode="tailTruncation" minimumScaleFactor="0.20000000000000001" translatesAutoresizingMaskIntoConstraints="NO" id="gcg-TC-hY4">
+ <rect key="frame" x="0.0" y="111" width="1740" height="743"/>
+ <fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="700"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <stackView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="253" verticalCompressionResistancePriority="749" distribution="fillEqually" spacing="60" translatesAutoresizingMaskIntoConstraints="NO" id="1hw-2E-6dg" userLabel="Button Stack View">
+ <rect key="frame" x="0.0" y="874" width="1740" height="86"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yc7-OR-WVJ">
+ <rect key="frame" x="0.0" y="0.0" width="840" height="86"/>
+ <color key="backgroundColor" red="0.25098040700000002" green="0.50196081400000003" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="+1"/>
+ <connections>
+ <action selector="incrementButtonHit:" destination="gup-Ft-HnK" eventType="primaryActionTriggered" id="zR6-AT-sGq"/>
+ </connections>
+ </button>
+ <button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ams-4H-2D4">
+ <rect key="frame" x="900" y="0.0" width="840" height="86"/>
+ <color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="-1"/>
+ <connections>
+ <action selector="decrementButton:" destination="gup-Ft-HnK" eventType="primaryActionTriggered" id="KTe-Dn-DgZ"/>
+ </connections>
+ </button>
+ </subviews>
+ </stackView>
+ </subviews>
+ </stackView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="R20-Wh-bn4" firstAttribute="top" secondItem="Bah-Ek-V99" secondAttribute="bottom" id="ECo-G5-TMU"/>
+ <constraint firstItem="V8l-aL-U1D" firstAttribute="trailing" secondItem="Bah-Ek-V99" secondAttribute="trailing" id="Ikr-TA-Ejk"/>
+ <constraint firstItem="Bah-Ek-V99" firstAttribute="leading" secondItem="V8l-aL-U1D" secondAttribute="leading" id="L8R-dY-jge"/>
+ <constraint firstItem="Bah-Ek-V99" firstAttribute="top" secondItem="i5o-My-7RI" secondAttribute="bottom" id="nvx-MN-rDc"/>
+ </constraints>
+ <viewLayoutGuide key="safeArea" id="V8l-aL-U1D"/>
+ </view>
+ <extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
+ <tabBarItem key="tabBarItem" title="Database" id="4ry-Ig-tAU"/>
+ <connections>
+ <outlet property="currentValue" destination="gcg-TC-hY4" id="1Cs-5w-yPF"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="FDt-0K-Tad" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="-812" y="1936"/>
+ </scene>
+ <!--Firebase Demo-->
+ <scene sceneID="Cbs-Et-MXF">
+ <objects>
+ <tabBarController title="Firebase Demo" automaticallyAdjustsScrollViewInsets="NO" id="7zF-dN-6Yw" sceneMemberID="viewController">
+ <toolbarItems/>
+ <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="yhw-Ot-Uul">
+ <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+ </tabBar>
+ <connections>
+ <segue destination="BYZ-38-t0r" kind="relationship" relationship="viewControllers" id="he8-oR-peB"/>
+ <segue destination="XYg-pc-Kbc" kind="relationship" relationship="viewControllers" id="x6X-oT-xPX"/>
+ <segue destination="gup-Ft-HnK" kind="relationship" relationship="viewControllers" id="CM1-Uf-Vcz"/>
+ </connections>
+ </tabBarController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="2Mm-5J-pE9" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="-814" y="-224"/>
+ </scene>
+ <!--Auth-->
+ <scene sceneID="KOh-Uh-VKO">
+ <objects>
+ <viewController id="XYg-pc-Kbc" customClass="AuthViewController" customModule="tvOSSample" customModuleProvider="target" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="q8D-PQ-udq"/>
+ <viewControllerLayoutGuide type="bottom" id="w5r-DR-UCF"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8lE-2P-i4i">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="500" verticalCompressionResistancePriority="1000" text="Auth" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GfO-0W-QKE">
+ <rect key="frame" x="885" y="60" width="151" height="91"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="60" translatesAutoresizingMaskIntoConstraints="NO" id="jeZ-ht-4RO" userLabel="Outer Stack">
+ <rect key="frame" x="769" y="497" width="383" height="86"/>
+ <subviews>
+ <stackView hidden="YES" opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="60" translatesAutoresizingMaskIntoConstraints="NO" id="ljv-p2-x1f" userLabel="Signed In Stack">
+ <rect key="frame" x="0.0" y="-497" width="383" height="60"/>
+ <subviews>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Signed in: (UID)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j4e-N4-2IJ">
+ <rect key="frame" x="57" y="0.0" width="269" height="0.0"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <button opaque="NO" contentMode="scaleToFill" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="m3A-YK-ass">
+ <rect key="frame" x="78" y="60" width="228" height="0.0"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="Sign Out"/>
+ <connections>
+ <action selector="signOutButtonHit:" destination="XYg-pc-Kbc" eventType="primaryActionTriggered" id="Hiq-Jx-oNo"/>
+ </connections>
+ </button>
+ </subviews>
+ </stackView>
+ <stackView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="500" verticalCompressionResistancePriority="749" axis="vertical" distribution="fillEqually" alignment="center" spacing="40" translatesAutoresizingMaskIntoConstraints="NO" id="0bY-NY-sEX" userLabel="Other Providers Stack">
+ <rect key="frame" x="0.0" y="0.0" width="383" height="86"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FRK-uH-meZ">
+ <rect key="frame" x="0.0" y="0.0" width="383" height="86"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="Email &amp; Password"/>
+ <connections>
+ <segue destination="64h-nN-haS" kind="show" id="OBj-mt-jsE"/>
+ </connections>
+ </button>
+ </subviews>
+ </stackView>
+ </subviews>
+ </stackView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="jeZ-ht-4RO" firstAttribute="top" relation="greaterThanOrEqual" secondItem="GfO-0W-QKE" secondAttribute="bottom" id="HyJ-ip-Q1e"/>
+ <constraint firstItem="GfO-0W-QKE" firstAttribute="top" secondItem="q8D-PQ-udq" secondAttribute="bottom" id="Icd-az-gH7"/>
+ <constraint firstItem="GfO-0W-QKE" firstAttribute="centerX" secondItem="8lE-2P-i4i" secondAttribute="centerX" id="q5o-7T-CbO"/>
+ <constraint firstItem="jeZ-ht-4RO" firstAttribute="centerY" secondItem="8lE-2P-i4i" secondAttribute="centerY" id="tii-97-jog"/>
+ <constraint firstItem="jeZ-ht-4RO" firstAttribute="centerX" secondItem="8lE-2P-i4i" secondAttribute="centerX" id="u5t-zJ-nRH"/>
+ </constraints>
+ <viewLayoutGuide key="safeArea" id="Kvt-PZ-Nk9"/>
+ </view>
+ <extendedEdge key="edgesForExtendedLayout"/>
+ <tabBarItem key="tabBarItem" title="Auth" id="IQh-1s-utZ"/>
+ <connections>
+ <outlet property="providers" destination="0bY-NY-sEX" id="8oq-4v-UHT"/>
+ <outlet property="signInStatus" destination="j4e-N4-2IJ" id="7wt-c1-8N9"/>
+ <outlet property="signedIn" destination="ljv-p2-x1f" id="4IZ-Bm-XNW"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="7sk-w5-jZ7" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="1350" y="1936"/>
+ </scene>
+ <!--Email Login View Controller-->
+ <scene sceneID="QMw-Qt-hDM">
+ <objects>
+ <viewController id="64h-nN-haS" customClass="EmailLoginViewController" customModule="tvOSSample" customModuleProvider="target" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="4fg-KG-aTM"/>
+ <viewControllerLayoutGuide type="bottom" id="RkR-wX-Tdq"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="yhK-2X-Z3p">
+ <rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" text="Email Login" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="46l-Z7-4KI">
+ <rect key="frame" x="778" y="20" width="365" height="91"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="40" translatesAutoresizingMaskIntoConstraints="NO" id="A1D-vt-Yfv">
+ <rect key="frame" x="716" y="409" width="490" height="262"/>
+ <subviews>
+ <stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="8Ag-kk-FiI" userLabel="Email Inputs">
+ <rect key="frame" x="0.0" y="0.0" width="490" height="136"/>
+ <subviews>
+ <stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="100" axis="vertical" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="OMj-ve-Czq" userLabel="Email Fields Stack">
+ <rect key="frame" x="0.0" y="0.0" width="490" height="136"/>
+ <subviews>
+ <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="100" horizontalCompressionResistancePriority="800" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Email Address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Jwa-bJ-Tt6">
+ <rect key="frame" x="0.0" y="0.0" width="490" height="58"/>
+ <nil key="textColor"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleTitle3"/>
+ <textInputTraits key="textInputTraits" textContentType="email"/>
+ </textField>
+ <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="100" horizontalCompressionResistancePriority="800" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Password" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="GP0-E2-Zjx">
+ <rect key="frame" x="0.0" y="78" width="490" height="58"/>
+ <nil key="textColor"/>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleTitle3"/>
+ <textInputTraits key="textInputTraits" secureTextEntry="YES" textContentType="password"/>
+ </textField>
+ </subviews>
+ </stackView>
+ </subviews>
+ </stackView>
+ <stackView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="256" verticalCompressionResistancePriority="1000" distribution="fillEqually" alignment="center" spacing="60" translatesAutoresizingMaskIntoConstraints="NO" id="6pe-KG-Tt8" userLabel="Email Buttons Stack">
+ <rect key="frame" x="0.0" y="176" width="490" height="86"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JUJ-6s-duw">
+ <rect key="frame" x="0.0" y="0.0" width="215" height="86"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="Log In"/>
+ <connections>
+ <action selector="logInButtonHit:" destination="64h-nN-haS" eventType="primaryActionTriggered" id="Ea2-dP-bgD"/>
+ </connections>
+ </button>
+ <button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Dt9-2d-WJM">
+ <rect key="frame" x="275" y="0.0" width="215" height="86"/>
+ <inset key="contentEdgeInsets" minX="40" minY="20" maxX="40" maxY="20"/>
+ <state key="normal" title="Sign Up"/>
+ <connections>
+ <action selector="signUpButtonHit:" destination="64h-nN-haS" eventType="primaryActionTriggered" id="KUW-Xi-zeI"/>
+ </connections>
+ </button>
+ </subviews>
+ </stackView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="6pe-KG-Tt8" firstAttribute="width" secondItem="8Ag-kk-FiI" secondAttribute="width" id="si6-Rj-cKU"/>
+ </constraints>
+ </stackView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="A1D-vt-Yfv" firstAttribute="centerY" secondItem="yhK-2X-Z3p" secondAttribute="centerY" id="AsP-r2-CmU"/>
+ <constraint firstItem="46l-Z7-4KI" firstAttribute="centerX" secondItem="yhK-2X-Z3p" secondAttribute="centerX" id="FSK-gW-wzc"/>
+ <constraint firstItem="A1D-vt-Yfv" firstAttribute="centerX" secondItem="46l-Z7-4KI" secondAttribute="centerX" id="SRe-fq-sjl"/>
+ <constraint firstItem="46l-Z7-4KI" firstAttribute="top" secondItem="yhK-2X-Z3p" secondAttribute="top" constant="20" id="WYg-tl-PPG"/>
+ <constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="A1D-vt-Yfv" secondAttribute="bottom" id="b2e-xU-0xq"/>
+ <constraint firstItem="A1D-vt-Yfv" firstAttribute="top" relation="greaterThanOrEqual" secondItem="46l-Z7-4KI" secondAttribute="bottom" id="bj1-cy-X9f"/>
+ </constraints>
+ <viewLayoutGuide key="safeArea" id="mS6-Be-asr"/>
+ </view>
+ <value key="contentSizeForViewInPopover" type="size" width="840" height="385"/>
+ <connections>
+ <outlet property="emailAddress" destination="Jwa-bJ-Tt6" id="HOE-at-pka"/>
+ <outlet property="password" destination="GP0-E2-Zjx" id="X8f-Ew-moe"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="guA-tW-goc" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="447" y="4052"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/Example/tvOSSample/tvOSSample/DatabaseViewController.swift b/Example/tvOSSample/tvOSSample/DatabaseViewController.swift
new file mode 100644
index 0000000..712c48f
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/DatabaseViewController.swift
@@ -0,0 +1,83 @@
+// Copyright 2017 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 UIKit
+import FirebaseDatabase
+
+/// A class to demonstrate the Firebase Realtime Database API. This will show a number read
+/// from the Database and increase or decrease it based on the buttons pressed.
+class DatabaseViewController: UIViewController {
+ private enum Counter: Int {
+ case increment = 1
+ case decrement = -1
+
+ var intValue: Int {
+ return rawValue
+ }
+ }
+
+ // MARK: - Interface
+
+ /// Label to display the current value.
+ @IBOutlet weak var currentValue: UILabel!
+
+ // MARK: - User Actions
+
+ /// The increment button was hit.
+ @IBAction func incrementButtonHit(_ sender: UIButton) { changeServerValue(with: .increment) }
+
+ /// the decrement button was hit.
+ @IBAction func decrementButton(_ sender: UIButton) { changeServerValue(with: .decrement) }
+
+ // MARK: - Internal Helpers
+
+ /// Update the number on the server by a particular value. Note: the number passed in should only
+ /// be one above or below the current number.
+ private func changeServerValue(with type: Counter) {
+ let ref = Database.database().reference(withPath: Constants.databasePath)
+ // Update the current value of the number.
+ ref.runTransactionBlock { (currentData) -> TransactionResult in
+ guard let value = currentData.value as? Int else {
+ return TransactionResult.abort()
+ }
+
+ currentData.value = value + type.intValue
+ return TransactionResult.success(withValue: currentData)
+ }
+ }
+
+ // MARK: - View Controller Lifecycle
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ // Observe the current value, and update the UI every time it changes.
+ let ref = Database.database().reference(withPath: Constants.databasePath)
+
+ ref.observe(.value) { [weak self] (snapshot) in
+ guard let value = snapshot.value as? Int else {
+ print("Error grabbing value from Snapshot!")
+ return
+ }
+
+ self?.currentValue.text = "\(value)"
+ }
+ }
+
+ // MARK: - Constants
+
+ private struct Constants {
+ static let databasePath = "magicSyncingCounter"
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/EmailLoginViewController.swift b/Example/tvOSSample/tvOSSample/EmailLoginViewController.swift
new file mode 100644
index 0000000..60dfc43
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/EmailLoginViewController.swift
@@ -0,0 +1,93 @@
+// Copyright 2017 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 UIKit
+import FirebaseAuth
+
+protocol EmailLoginDelegate {
+ func emailLogin(_ controller: EmailLoginViewController, signedInAs user: User)
+ func emailLogin(_ controller: EmailLoginViewController, failedWithError error: Error)
+}
+class EmailLoginViewController: UIViewController {
+
+ // MARK: - Public Properties
+
+ var delegate: EmailLoginDelegate?
+
+ // MARK: - User Interface
+
+ @IBOutlet private weak var emailAddress: UITextField!
+ @IBOutlet private weak var password: UITextField!
+
+ // MARK: - User Actions
+
+ @IBAction func logInButtonHit(_ sender: UIButton) {
+ guard let (email, password) = validatedInputs() else { return }
+
+ Auth.auth().signIn(withEmail: email, password: password) { [unowned self] (user, error) in
+ guard let user = user else {
+ print("Error signing in: \(error!)")
+ self.delegate?.emailLogin(self, failedWithError: error!)
+ return
+ }
+
+ print("Signed in as user: \(user.uid)!")
+ self.delegate?.emailLogin(self, signedInAs: user)
+ }
+ }
+
+ @IBAction func signUpButtonHit(_ sender: UIButton) {
+ guard let (email, password) = validatedInputs() else { return }
+
+ Auth.auth().createUser(withEmail: email, password: password) { [unowned self] (user, error) in
+ guard let user = user else {
+ print("Error signing up: \(error!)")
+ self.delegate?.emailLogin(self, failedWithError: error!)
+ return
+ }
+
+ print("Created new user: \(user.uid)!")
+ self.delegate?.emailLogin(self, signedInAs: user)
+ }
+ }
+
+ // MARK: - View Controller Lifecycle
+
+ override func viewDidLoad() {
+ }
+
+ // MARK: - Helper Methods
+
+ /// Validate the inputs for user email and password, returning the username and password if valid,
+ /// otherwise nil.
+ private func validatedInputs() -> (email: String, password: String)? {
+ guard let userEmail = emailAddress.text, userEmail.count >= 6 else {
+ presentError(with: "Email address isn't long enough.")
+ return nil
+ }
+
+ guard let userPassword = password.text, userPassword.count >= 6 else {
+ presentError(with: "Password is not long enough!")
+ return nil
+ }
+
+ return (userEmail, userPassword)
+ }
+
+ func presentError(with text: String) {
+ let alert = UIAlertController(title: "Error", message: text, preferredStyle: .alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: .default))
+ present(alert, animated: true)
+ }
+}
diff --git a/Example/tvOSSample/tvOSSample/Info.plist b/Example/tvOSSample/tvOSSample/Info.plist
new file mode 100644
index 0000000..02942a3
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>arm64</string>
+ </array>
+ <key>UIUserInterfaceStyle</key>
+ <string>Automatic</string>
+</dict>
+</plist>
diff --git a/Example/tvOSSample/tvOSSample/StorageViewController.swift b/Example/tvOSSample/tvOSSample/StorageViewController.swift
new file mode 100644
index 0000000..4416649
--- /dev/null
+++ b/Example/tvOSSample/tvOSSample/StorageViewController.swift
@@ -0,0 +1,148 @@
+// Copyright 2017 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 UIKit
+import FirebaseStorage
+
+class StorageViewController: UIViewController {
+ /// An enum describing the different states of the view controller.
+ private enum UIState: Equatable {
+ /// No image is being shown, waiting on user action.
+ case cleared
+
+ /// Currently downloading from Firebase.
+ case downloading(StorageTask)
+
+ /// The image has downloaded and should be displayed.
+ case downloaded(UIImage)
+
+ /// Show an error message and stop downloading.
+ case failed(String)
+
+ /// Equatable support for UIState.
+ static func ==(lhs: StorageViewController.UIState, rhs: StorageViewController.UIState) -> Bool {
+ switch (lhs, rhs) {
+ case (.cleared, .cleared): return true
+ case (.downloading, .downloading): return true
+ case (.downloaded, .downloaded): return true
+ case (.failed, .failed): return true
+ default: return false
+ }
+ }
+ }
+
+ /// MARK: - Properties
+
+ /// The current internal state of the view controller.
+ private var state: UIState = .cleared {
+ didSet { changeState(from: oldValue, to: state) }
+ }
+
+ // MARK: Interface
+
+ /// Image view to display the downloaded image.
+ @IBOutlet weak var imageView: UIImageView!
+
+ /// The download button.
+ @IBOutlet weak var downloadButton: UIButton!
+
+ /// The clear button.
+ @IBOutlet weak var clearButton: UIButton!
+
+ /// A visual representation of the state.
+ @IBOutlet weak var stateLabel: UILabel!
+
+ // MARK: - User Actions
+
+ @IBAction func downloadButtonHit(_ sender: UIButton) {
+ guard case .cleared = state else { return }
+
+ // Start the download.
+ let storage = Storage.storage()
+ let ref = storage.reference(withPath: Constants.downloadPath)
+ // TODO: Show progress bar here using proper API.
+ let task = ref.getData(maxSize: Constants.maxSize) { [unowned self] (data, error) in
+ guard let data = data else {
+ self.state = .failed("Error downloading: \(error!.localizedDescription)")
+ return
+ }
+
+ // Create a UIImage from the PNG data.
+ guard let image = UIImage(data: data) else {
+ self.state = .failed("Unable to initialize image with data downloaded.")
+ return
+ }
+
+ self.state = .downloaded(image)
+ }
+
+ // The completion block above could be run before this line in some situations. If that's the
+ // case, we don't need to do anything else and can return.
+ if case .downloaded = state { return }
+
+ // Set the state to downloading!
+ state = .downloading(task)
+ }
+
+ @IBAction func clearButtonHit(_ sender: UIButton) {
+ guard case .downloaded = state else { return }
+
+ state = .cleared
+ }
+
+ // MARK: - State Management
+
+ /// Changing from old state to new state.
+ private func changeState(from oldState: UIState, to newState: UIState) {
+ if oldState == newState { return }
+
+ switch (oldState, newState) {
+ // Regular state, start downloading the image.
+ case (.cleared, .downloading(_)):
+ // TODO: Update the UI with a spinner? Progress update?
+ stateLabel.text = "State: Downloading..."
+
+ // Download complete, ensure the download button is still off and enable the clear button.
+ case (_, .downloaded(let image)):
+ imageView.image = image
+ stateLabel.text = "State: Image downloaded!"
+
+ // Clear everything and reset to the original state.
+ case (_, .cleared):
+ imageView.image = nil
+ stateLabel.text = "State: Pending download"
+
+ // An error occurred.
+ case (_, .failed(let error)):
+ stateLabel.text = "State: \(error)"
+
+ // For now, as the default, throw a fatal error because it's an unexpected state. This will
+ // allow us to catch it immediately and add the required action or fix the bug.
+ default:
+ fatalError("Programmer error! Tried to go from \(oldState) to \(newState)")
+ }
+ }
+
+ // MARK: - Constants
+
+ /// Internal constants for this class.
+ private struct Constants {
+ /// The image name to download. Can comment this out and replace it with the other below it as
+ /// part of the demo. Ensure that Storage has an image uploaded to this path for this to
+ /// function properly.
+ static let downloadPath = "YOUR_IMAGE_NAME.jpg"
+
+ static let maxSize: Int64 = 1024 * 1024 * 10 // ~10MB
+ }
+}
diff --git a/Firebase/Auth/CHANGELOG.md b/Firebase/Auth/CHANGELOG.md
index d464cd6..176ae3b 100644
--- a/Firebase/Auth/CHANGELOG.md
+++ b/Firebase/Auth/CHANGELOG.md
@@ -1,3 +1,8 @@
+# v4.4.1
+- Fixes bug where the FIRAuthResult object returned following a Phone Number authentication
+ always contained a nil FIRAdditionalUserInfo object. Now the FIRAdditionalUserInfo object is
+ never nil and its newUser field is populated correctly.
+
# v4.4.0
- Adds new APIs which return an AuthDataResult object after successfully creating an
Email/Password user, signing in anonymously, signing in with Email/Password and signing
diff --git a/Firebase/Auth/FirebaseAuth.podspec b/Firebase/Auth/FirebaseAuth.podspec
index 8823238..8211bb0 100644
--- a/Firebase/Auth/FirebaseAuth.podspec
+++ b/Firebase/Auth/FirebaseAuth.podspec
@@ -45,6 +45,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel
'$(inherited) ' + 'FIRAuth_VERSION=' + s.version.to_s +
' FIRAuth_MINOR_VERSION=' + s.version.to_s.split(".")[0] + "." + s.version.to_s.split(".")[1]
}
+ s.framework = 'CoreGraphics'
s.framework = 'SafariServices'
s.framework = 'Security'
# s.dependency 'FirebaseCommunity/Core'
diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m
index ad363e0..ebca6c8 100644
--- a/Firebase/Auth/Source/FIRAuth.m
+++ b/Firebase/Auth/Source/FIRAuth.m
@@ -657,12 +657,29 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
isReauthentication ? FIRAuthOperationTypeReauth : FIRAuthOperationTypeSignUpOrSignIn;
[self signInWithPhoneCredential:phoneCredential
operation:operation
- callback:^(FIRUser *_Nullable user,
+ callback:^(FIRVerifyPhoneNumberResponse *_Nullable response,
NSError *_Nullable error) {
if (callback) {
- FIRAuthDataResult *result = user ?
- [[FIRAuthDataResult alloc] initWithUser:user additionalUserInfo:nil] : nil;
- callback(result, error);
+ if (error) {
+ callback(nil, error);
+ return;
+ }
+
+ [self completeSignInWithAccessToken:response.IDToken
+ accessTokenExpirationDate:response.approximateExpirationDate
+ refreshToken:response.refreshToken
+ anonymous:NO
+ callback:^(FIRUser *_Nullable user, NSError *_Nullable error) {
+ FIRAdditionalUserInfo *additionalUserInfo =
+ [[FIRAdditionalUserInfo alloc] initWithProviderID:FIRPhoneAuthProviderID
+ profile:nil
+ username:nil
+ isNewUser:response.isNewUser];
+ FIRAuthDataResult *result = user ?
+ [[FIRAuthDataResult alloc] initWithUser:user
+ additionalUserInfo:additionalUserInfo] : nil;
+ callback(result, error);
+ }];
}
}];
return;
@@ -1143,14 +1160,14 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
*/
- (void)signInWithPhoneCredential:(FIRPhoneAuthCredential *)credential
operation:(FIRAuthOperationType)operation
- callback:(FIRAuthResultCallback)callback {
+ callback:(FIRVerifyPhoneNumberResponseCallback)callback {
if (credential.temporaryProof.length && credential.phoneNumber.length) {
FIRVerifyPhoneNumberRequest *request =
[[FIRVerifyPhoneNumberRequest alloc] initWithTemporaryProof:credential.temporaryProof
phoneNumber:credential.phoneNumber
operation:operation
requestConfiguration:_requestConfiguration];
- [self phoneNumberSignInWithRequest:request callback:callback];
+ [FIRAuthBackend verifyPhoneNumber:request callback:callback];
return;
}
@@ -1167,32 +1184,9 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
verificationCode:credential.verificationCode
operation:operation
requestConfiguration:_requestConfiguration];
- [self phoneNumberSignInWithRequest:request callback:callback];
+ [FIRAuthBackend verifyPhoneNumber:request callback:callback];
}
-
-/** @fn phoneNumberSignInWithVerificationID:pasverificationCodesword:callback:
- @brief Signs in using a FIRVerifyPhoneNumberRequest object.
- @param request THe FIRVerifyPhoneNumberRequest request object.
- @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked
- asynchronously on the global auth work queue in the future.
- */
-- (void)phoneNumberSignInWithRequest:(FIRVerifyPhoneNumberRequest *)request
- callback:(FIRAuthResultCallback)callback {
- [FIRAuthBackend verifyPhoneNumber:request
- callback:^(FIRVerifyPhoneNumberResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- callback(nil, error);
- return;
- }
- [self completeSignInWithAccessToken:response.IDToken
- accessTokenExpirationDate:response.approximateExpirationDate
- refreshToken:response.refreshToken
- anonymous:NO
- callback:callback];
- }];
-}
#endif
/** @fn internalSignInAndRetrieveDataWithCustomToken:completion:
diff --git a/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m b/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m
index 7775305..215a391 100644
--- a/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m
+++ b/Firebase/Auth/Source/FIRAuthAPNSTokenManager.m
@@ -73,7 +73,9 @@ static const NSTimeInterval kLegacyRegistrationTimeout = 30;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#if TARGET_OS_IOS
[_application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert];
+#endif // TARGET_OS_IOS
#pragma clang diagnostic pop
}
});
diff --git a/Firebase/Auth/Source/Public/FIREmailAuthProvider.h b/Firebase/Auth/Source/Public/FIREmailAuthProvider.h
index 0108d40..99cd018 100644
--- a/Firebase/Auth/Source/Public/FIREmailAuthProvider.h
+++ b/Firebase/Auth/Source/Public/FIREmailAuthProvider.h
@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
extern NSString *const FIREmailAuthProviderID NS_SWIFT_NAME(EmailAuthProviderID);
/**
- @brief please use `FIREmailAuthProviderID` instead.
+ @brief Please use `FIREmailAuthProviderID` for Objective-C or `EmailAuthProviderID` for Swift instead.
*/
extern NSString *const FIREmailPasswordAuthProviderID __attribute__((deprecated));
diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m
index c6b9d03..12ef97c 100644
--- a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m
@@ -16,8 +16,6 @@
#import "FIRCreateAuthURIResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRCreateAuthURIResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m b/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m
index 671a41f..ae98175 100644
--- a/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRDeleteAccountResponse.m
@@ -16,8 +16,6 @@
#import "FIRDeleteAccountResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRDeleteAccountResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m
index bd028f1..0b6c416 100644
--- a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeResponse.m
@@ -16,8 +16,6 @@
#import "FIRGetOOBConfirmationCodeResponse.h"
-#import "FIRAuthErrorUtils.h"
-
NS_ASSUME_NONNULL_BEGIN
/** @var kOOBCodeKey
diff --git a/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m b/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m
index 9a1556b..6092cfe 100644
--- a/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRResetPasswordResponse.m
@@ -16,8 +16,6 @@
#import "FIRResetPasswordResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRResetPasswordResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m
index 6e228eb..ff9c7a6 100644
--- a/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRSetAccountInfoResponse.m
@@ -16,8 +16,6 @@
#import "FIRSetAccountInfoResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRSetAccountInfoResponseProviderUserInfo
- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
diff --git a/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m
index 7e58c5d..2071e07 100644
--- a/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRSignUpNewUserResponse.m
@@ -16,8 +16,6 @@
#import "FIRSignUpNewUserResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRSignUpNewUserResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m
index 8c970c8..5ee39fa 100644
--- a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionResponse.m
@@ -16,8 +16,6 @@
#import "FIRVerifyAssertionResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRVerifyAssertionResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m
index 8a87141..b6c3818 100644
--- a/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyCustomTokenResponse.m
@@ -16,8 +16,6 @@
#import "FIRVerifyCustomTokenResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRVerifyCustomTokenResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m
index d2c4a7c..71b4edd 100644
--- a/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyPasswordResponse.m
@@ -16,8 +16,6 @@
#import "FIRVerifyPasswordResponse.h"
-#import "FIRAuthErrorUtils.h"
-
@implementation FIRVerifyPasswordResponse
- (BOOL)setWithDictionary:(NSDictionary *)dictionary
diff --git a/Firebase/Core/CHANGELOG.md b/Firebase/Core/CHANGELOG.md
new file mode 100644
index 0000000..44b0f62
--- /dev/null
+++ b/Firebase/Core/CHANGELOG.md
@@ -0,0 +1,30 @@
+# Unreleased
+
+# 2018-01-18 -- v4.0.14 -- M21.1
+- [changed] Removed AppKit dependency for community macOS build.
+
+# 2017-11-30 -- v4.0.12 -- M20.2
+- [fixed] Removed `FIR_SWIFT_NAME` macro, replaced with proper `NS_SWIFT_NAME`.
+
+# 2017-11-14 -- v4.0.11 -- M20.1
+- [feature] Added `-FIRLoggerForceSTDERR` launch argument flag to force STDERR
+ output for all Firebase logging
+
+# 2017-08-25 -- v4.0.6 -- M18.1
+- [changed] Removed unused method
+
+# 2017-08-09 -- v4.0.5 -- M18.0
+- [changed] Log an error for an incorrectly configured bundle ID instead of an info
+ message.
+
+# 2017-07-12 -- v4.0.4 -- M17.4
+- [changed] Switched to using the https://cocoapods.org/pods/nanopb pod instead of
+ linking nanopb in (preventing linker conflicts).
+
+# 2017-06-06 -- v4.0.1 -- M17.1
+- [fixed] Improved diagnostic messages for Swift
+
+# 2017-05-17 -- v4.0.0 -- M17
+- [changed] Update FIROptions to have a simpler constructor and mutable properties
+- [feature] Swift naming update, FIR prefix dropped
+- [changed] Internal cleanup for open source release
diff --git a/Firebase/Core/FIRApp.m b/Firebase/Core/FIRApp.m
index 242fd79..22c9369 100644
--- a/Firebase/Core/FIRApp.m
+++ b/Firebase/Core/FIRApp.m
@@ -142,7 +142,8 @@ static FIRApp *sDefaultApp;
NSString *minVersion = info[@"MinimumOSVersion"];
if ([minVersion hasPrefix:@"7."]) {
- FIRLogNotice(kFIRLoggerCore, @"I-COR000026", @"Support for iOS 7 is deprecated and will "
+ FIRLogNotice(kFIRLoggerCore, @"I-COR000026",
+ @"Support for iOS 7 is deprecated and will "
@"stop working in the future. Please upgrade your app to target iOS 8 or "
@"above.");
}
@@ -367,7 +368,9 @@ static FIRApp *sDefaultApp;
NSLocalizedRecoverySuggestionErrorKey :
@"Check formatting and location of GoogleService-Info.plist."
};
- return FIRCreateError(kFirebaseCoreErrorDomain, FIRErrorCodeInvalidPlistFile, errorDict);
+ return [NSError errorWithDomain:kFirebaseCoreErrorDomain
+ code:FIRErrorCodeInvalidPlistFile
+ userInfo:errorDict];
}
+ (NSError *)errorForSubspecConfigurationFailureWithDomain:(NSString *)domain
@@ -378,7 +381,7 @@ static FIRApp *sDefaultApp;
[NSString stringWithFormat:@"Configuration failed for service %@.", service];
NSDictionary *errorDict =
@{NSLocalizedDescriptionKey : description, NSLocalizedFailureReasonErrorKey : reason};
- return FIRCreateError(domain, code, errorDict);
+ return [NSError errorWithDomain:domain code:code userInfo:errorDict];
}
+ (NSError *)errorForInvalidAppID {
@@ -388,7 +391,9 @@ static FIRApp *sDefaultApp;
@"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the "
@"customized options."
};
- return FIRCreateError(kFirebaseCoreErrorDomain, FIRErrorCodeInvalidAppID, errorDict);
+ return [NSError errorWithDomain:kFirebaseCoreErrorDomain
+ code:FIRErrorCodeInvalidAppID
+ userInfo:errorDict];
}
+ (BOOL)isDefaultAppConfigured {
diff --git a/Firebase/Core/FIRErrors.m b/Firebase/Core/FIRErrors.m
index 3c7e39a..6d6d52d 100644
--- a/Firebase/Core/FIRErrors.m
+++ b/Firebase/Core/FIRErrors.m
@@ -27,7 +27,3 @@ NSString *const kFirebaseDurableDeepLinkErrorDomain = @"com.firebase.durabledeep
NSString *const kFirebaseInstanceIDErrorDomain = @"com.firebase.instanceid";
NSString *const kFirebasePerfErrorDomain = @"com.firebase.perf";
NSString *const kFirebaseStorageErrorDomain = @"com.firebase.storage";
-
-NSError *FIRCreateError(NSString *domain, enum FIRErrorCode code, NSDictionary *userInfo) {
- return [NSError errorWithDomain:domain code:code userInfo:userInfo];
-}
diff --git a/Firebase/Core/FIRLogger.m b/Firebase/Core/FIRLogger.m
index ba22bde..01231a7 100644
--- a/Firebase/Core/FIRLogger.m
+++ b/Firebase/Core/FIRLogger.m
@@ -15,6 +15,7 @@
#import "Private/FIRLogger.h"
#import "FIRLoggerLevel.h"
+#import "Private/FIRVersion.h"
#import "third_party/FIRAppEnvironmentUtil.h"
#include <asl.h>
@@ -164,13 +165,13 @@ void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) {
return;
}
FIRLoggerInitializeASL();
- dispatch_async(sFIRClientQueue, ^{
- // We should not raise the logger level if we are running from App Store.
- if (loggerLevel >= FIRLoggerLevelNotice && [FIRAppEnvironmentUtil isFromAppStore]) {
- return;
- }
+ // We should not raise the logger level if we are running from App Store.
+ if (loggerLevel >= FIRLoggerLevelNotice && [FIRAppEnvironmentUtil isFromAppStore]) {
+ return;
+ }
- sFIRLoggerMaximumLevel = loggerLevel;
+ sFIRLoggerMaximumLevel = loggerLevel;
+ dispatch_async(sFIRClientQueue, ^{
asl_set_filter(sFIRLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel));
});
}
@@ -229,7 +230,8 @@ void FIRLogBasic(FIRLoggerLevel level,
NSCAssert(numberOfMatches == 1, @"Incorrect message code format.");
#endif
NSString *logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr];
- logMsg = [NSString stringWithFormat:@"%@[%@] %@", service, messageCode, logMsg];
+ logMsg = [NSString
+ stringWithFormat:@"%s - %@[%@] %@", FirebaseVersionString, service, messageCode, logMsg];
dispatch_async(sFIRClientQueue, ^{
asl_log(sFIRLoggerClient, NULL, level, "%s", logMsg.UTF8String);
});
diff --git a/Firebase/Core/FIRNetworkURLSession.m b/Firebase/Core/FIRNetworkURLSession.m
index d9c6f3a..c3da674 100644
--- a/Firebase/Core/FIRNetworkURLSession.m
+++ b/Firebase/Core/FIRNetworkURLSession.m
@@ -428,6 +428,7 @@
- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID {
#if (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) || \
+ TARGET_OS_TV || \
(TARGET_OS_IOS && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
// iOS 8/10.10 builds require the new backgroundSessionConfiguration method name.
diff --git a/Firebase/Core/FIROptions.m b/Firebase/Core/FIROptions.m
index 841c70b..fc92a55 100644
--- a/Firebase/Core/FIROptions.m
+++ b/Firebase/Core/FIROptions.m
@@ -42,7 +42,7 @@ NSString *const kFIRIsSignInEnabled = @"IS_SIGNIN_ENABLED";
NSString *const kFIRLibraryVersionID =
@"4" // Major version (one or more digits)
@"00" // Minor version (exactly 2 digits)
- @"12" // Build number (exactly 2 digits)
+ @"14" // Build number (exactly 2 digits)
@"000"; // Fixed "000"
// Plist file name.
NSString *const kServiceInfoFileName = @"GoogleService-Info";
@@ -62,12 +62,19 @@ NSString *const kFIRExceptionBadModification =
@property(nonatomic, readwrite) NSMutableDictionary *optionsDictionary;
/**
- * Combination of analytics options from both the main plist and the GoogleService-Info.plist.
+ * Calls `analyticsOptionsDictionaryWithInfoDictionary:` using [NSBundle mainBundle].infoDictionary.
+ * It combines analytics options from both the infoDictionary and the GoogleService-Info.plist.
* Values which are present in the main plist override values from the GoogleService-Info.plist.
*/
@property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary;
/**
+ * Combination of analytics options from both the infoDictionary and the GoogleService-Info.plist.
+ * Values which are present in the infoDictionary override values from the GoogleService-Info.plist.
+ */
+- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary;
+
+/**
* Throw exception if editing is locked when attempting to modify an option.
*/
- (void)checkEditingLocked;
@@ -346,16 +353,15 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
#pragma mark - Internal instance methods
-- (NSDictionary *)analyticsOptionsDictionary {
+- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary {
dispatch_once(&_createAnalyticsOptionsDictionaryOnce, ^{
NSMutableDictionary *tempAnalyticsOptions = [[NSMutableDictionary alloc] init];
- NSDictionary *mainInfoDictionary = [NSBundle mainBundle].infoDictionary;
NSArray *measurementKeys = @[
kFIRIsMeasurementEnabled, kFIRIsAnalyticsCollectionEnabled,
kFIRIsAnalyticsCollectionDeactivated
];
for (NSString *key in measurementKeys) {
- id value = mainInfoDictionary[key] ?: self.optionsDictionary[key] ?: nil;
+ id value = infoDictionary[key] ?: self.optionsDictionary[key] ?: nil;
if (!value) {
continue;
}
@@ -366,6 +372,10 @@ static NSDictionary *sDefaultOptionsDictionary = nil;
return _analyticsOptionsDictionary;
}
+- (NSDictionary *)analyticsOptionsDictionary {
+ return [self analyticsOptionsDictionaryWithInfoDictionary:[NSBundle mainBundle].infoDictionary];
+}
+
/**
* Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in
* GoogleService-Info.plist. This uses the old plist flag IS_MEASUREMENT_ENABLED, which should still
diff --git a/Firebase/Core/FIRReachabilityChecker.m b/Firebase/Core/FIRReachabilityChecker.m
index 733dffe..cac87ff 100644
--- a/Firebase/Core/FIRReachabilityChecker.m
+++ b/Firebase/Core/FIRReachabilityChecker.m
@@ -177,7 +177,7 @@ static NSString *const kFIRReachabilityDisconnectedStatus = @"Disconnected";
// Reachable flag is set. Check further flags.
if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
// Connection required flag is not set, so we have connectivity.
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kFIRReachabilityViaCellular
: kFIRReachabilityViaWifi;
#elif TARGET_OS_OSX
@@ -188,7 +188,7 @@ static NSString *const kFIRReachabilityDisconnectedStatus = @"Disconnected";
!(flags & kSCNetworkReachabilityFlagsInterventionRequired)) {
// If the connection on demand or connection on traffic flag is set, and user intervention
// is not required, we have connectivity.
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kFIRReachabilityViaCellular
: kFIRReachabilityViaWifi;
#elif TARGET_OS_OSX
diff --git a/Firebase/Core/FIRVersion.m b/Firebase/Core/FIRVersion.m
new file mode 100644
index 0000000..00a6741
--- /dev/null
+++ b/Firebase/Core/FIRVersion.m
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef Firebase_VERSION
+#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation"
+#endif
+
+#ifndef FIRCore_VERSION
+#error "FIRCore_VERSION is not defined: add -DFIRCore_VERSION=... to the build invocation"
+#endif
+
+// The following two macros supply the incantation so that the C
+// preprocessor does not try to parse the version as a floating
+// point number. See
+// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/
+#define STR(x) STR_EXPAND(x)
+#define STR_EXPAND(x) #x
+
+const unsigned char *const FirebaseVersionString =
+ (const unsigned char *const)STR(Firebase_VERSION);
+
+const unsigned char *const FirebaseCoreVersionString =
+ (const unsigned char *const)STR(FIRCore_VERSION);
diff --git a/Firebase/Core/Private/FIRErrors.h b/Firebase/Core/Private/FIRErrors.h
index 9a03575..cf69252 100644
--- a/Firebase/Core/Private/FIRErrors.h
+++ b/Firebase/Core/Private/FIRErrors.h
@@ -31,13 +31,3 @@ extern NSString *const kFirebaseDurableDeepLinkErrorDomain;
extern NSString *const kFirebaseInstanceIDErrorDomain;
extern NSString *const kFirebasePerfErrorDomain;
extern NSString *const kFirebaseStorageErrorDomain;
-
-/**
- * Factory for a NSError in the Firebase error domain.
- *
- * @param domain Domain of Firebase error.
- * @param code Error code that NSError should have.
- * @param userInfo User info that NSError should have.
- * @return An NSError in the Firebase domain.
- */
-extern NSError *FIRCreateError(NSString *domain, FIRErrorCode code, NSDictionary *userInfo);
diff --git a/Firestore/core/src/firebase/firestore/base/port.h b/Firebase/Core/Private/FIRVersion.h
index 37d1041..f18f61f 100644
--- a/Firestore/core/src/firebase/firestore/base/port.h
+++ b/Firebase/Core/Private/FIRVersion.h
@@ -14,20 +14,10 @@
* limitations under the License.
*/
-#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_BASE_PORT_H_
-#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_BASE_PORT_H_
+#import <Foundation/Foundation.h>
-#if defined(__APPLE__)
-// On Apple platforms we support building via Cocoapods without CMake. When
-// building this way we can't test the presence of features so predefine all
-// the platform-support feature macros to their expected values.
+/** The version of the Firebase SDK. */
+FOUNDATION_EXPORT const unsigned char *const FirebaseVersionString;
-// All supported Apple platforms have arc4random(3).
-#define HAVE_ARC4RANDOM 1
-
-#else
-
-#error "Unknown platform."
-#endif // defined(__APPLE__)
-
-#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_BASE_PORT_H_
+/** The version of the FirebaseCore Component. */
+FOUNDATION_EXPORT const unsigned char *const FirebaseCoreVersionString;
diff --git a/Firebase/Core/third_party/FIRAppEnvironmentUtil.h b/Firebase/Core/third_party/FIRAppEnvironmentUtil.h
index 7ae9827..09ee504 100644
--- a/Firebase/Core/third_party/FIRAppEnvironmentUtil.h
+++ b/Firebase/Core/third_party/FIRAppEnvironmentUtil.h
@@ -16,12 +16,6 @@
#import <Foundation/Foundation.h>
-#if TARGET_OS_IOS
-#import <UIKit/UIKit.h>
-#elif TARGET_OS_OSX
-#import <AppKit/AppKit.h>
-#endif
-
@interface FIRAppEnvironmentUtil : NSObject
/// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator,
@@ -46,12 +40,4 @@
/// Indicates whether it is running inside an extension or an app.
+ (BOOL)isAppExtension;
-#if TARGET_OS_IOS
-/// Returns the [UIApplication sharedApplication] if it is running on an app, not an extension.
-+ (UIApplication *)sharedApplication;
-#elif TARGET_OS_OSX
-/// Returns the [NSApplication sharedApplication].
-+ (NSApplication *)sharedApplication;
-#endif
-
@end
diff --git a/Firebase/Core/third_party/FIRAppEnvironmentUtil.m b/Firebase/Core/third_party/FIRAppEnvironmentUtil.m
index 3a08cfa..90e66f0 100644
--- a/Firebase/Core/third_party/FIRAppEnvironmentUtil.m
+++ b/Firebase/Core/third_party/FIRAppEnvironmentUtil.m
@@ -13,6 +13,9 @@
// limitations under the License.
#import <Foundation/Foundation.h>
+#if TARGET_OS_IOS || TARGET_OS_TV
+#import <UIKit/UIKit.h>
+#endif
#import "FIRAppEnvironmentUtil.h"
@@ -36,6 +39,12 @@ struct encryption_info_command {
@implementation FIRAppEnvironmentUtil
+/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox.
+/// This will affect your data integrity when using Firebase Analytics, as it will disable some
+/// necessary checks.
+static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey =
+ @"FirebaseAppStoreReceiptURLCheckEnabled";
+
/// The file name of the sandbox receipt. This is available on iOS >= 8.0
static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt";
@@ -152,13 +161,23 @@ static BOOL isAppEncrypted() {
}
+ (BOOL)isAppStoreReceiptSandbox {
+ // Since checking the App Store's receipt URL can be memory intensive, check the option in the
+ // Info.plist if developers opted out of this check.
+ id enableSandboxCheck =
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey];
+ if (enableSandboxCheck &&
+ [enableSandboxCheck isKindOfClass:[NSNumber class]] &&
+ ![enableSandboxCheck boolValue]) {
+ return NO;
+ }
+
NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL;
NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent;
return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName];
}
+ (BOOL)hasEmbeddedMobileProvision {
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0;
#elif TARGET_OS_OSX
return NO;
@@ -166,7 +185,7 @@ static BOOL isAppEncrypted() {
}
+ (BOOL)isSimulator {
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
NSString *platform = [FIRAppEnvironmentUtil deviceModel];
return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"];
#elif TARGET_OS_OSX
@@ -188,7 +207,7 @@ static BOOL isAppEncrypted() {
}
+ (NSString *)systemVersion {
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
return [UIDevice currentDevice].systemVersion;
#elif TARGET_OS_OSX
return [NSProcessInfo processInfo].operatingSystemVersionString;
@@ -196,7 +215,7 @@ static BOOL isAppEncrypted() {
}
+ (BOOL)isAppExtension {
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
// Documented by <a href="https://goo.gl/RRB2Up">Apple</a>
BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
return appExtension;
@@ -205,29 +224,10 @@ static BOOL isAppEncrypted() {
#endif
}
-#if TARGET_OS_IOS
-+ (UIApplication *)sharedApplication {
- if ([FIRAppEnvironmentUtil isAppExtension]) {
- return nil;
- }
- id sharedApplication = nil;
- Class uiApplicationClass = NSClassFromString(@"UIApplication");
- if (uiApplicationClass &&
- [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) {
- sharedApplication = [uiApplicationClass sharedApplication];
- }
- return sharedApplication;
-}
-#elif TARGET_OS_OSX
-+ (NSApplication *)sharedApplication {
- return [NSApplication sharedApplication];
-}
-#endif
-
#pragma mark - Helper methods
+ (BOOL)hasSCInfoFolder {
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
NSString *bundlePath = [NSBundle mainBundle].bundlePath;
NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"];
return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath];
diff --git a/Firebase/Database/CHANGELOG.md b/Firebase/Database/CHANGELOG.md
index 867def1..6867cce 100644
--- a/Firebase/Database/CHANGELOG.md
+++ b/Firebase/Database/CHANGELOG.md
@@ -1,3 +1,9 @@
+# v4.1.4
+- [added] Firebase Database is now community-supported on tvOS.
+
+# v4.1.3
+- [changed] Internal cleanup in the firebase-ios-sdk repository. Functionality of the RTDB SDK is not affected.
+
# v4.1.2
- [fixed] Addresses race condition that can occur during the initialization of empty snapshots.
diff --git a/Firebase/Database/Core/FPersistentConnection.m b/Firebase/Database/Core/FPersistentConnection.m
index 6f71d8b..870727c 100644
--- a/Firebase/Database/Core/FPersistentConnection.m
+++ b/Firebase/Database/Core/FPersistentConnection.m
@@ -925,7 +925,7 @@ static void reachabilityCallback(SCNetworkReachabilityRef ref, SCNetworkReachabi
- (void) sendConnectStats {
NSMutableDictionary *stats = [NSMutableDictionary dictionary];
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
if (self.config.persistenceEnabled) {
stats[@"persistence.ios.enabled"] = @1;
}
diff --git a/Firebase/Database/Core/FRepo.m b/Firebase/Database/Core/FRepo.m
index 0935b44..1c4b956 100644
--- a/Firebase/Database/Core/FRepo.m
+++ b/Firebase/Database/Core/FRepo.m
@@ -53,7 +53,7 @@
#import "FValueEventRegistration.h"
#import "FEmptyNode.h"
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
#endif
@@ -546,7 +546,7 @@
return;
// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual release build.
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
// The idea is to wait until any outstanding sets get written to disk. Since the sets might still be in our
// dispatch queue, we wait for the dispatch queue to catch up and for persistence to catch up.
// This may be undesirable though. The dispatch queue might just be processing a bunch of incoming data or
diff --git a/Firebase/Database/Persistence/FLevelDBStorageEngine.m b/Firebase/Database/Persistence/FLevelDBStorageEngine.m
index 490fb6c..7de9ebf 100644
--- a/Firebase/Database/Persistence/FLevelDBStorageEngine.m
+++ b/Firebase/Database/Persistence/FLevelDBStorageEngine.m
@@ -211,7 +211,7 @@ static NSString* trackedQueryKeysKey(NSUInteger trackedQueryId, NSString *key) {
}
+ (NSString *) firebaseDir {
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [dirPaths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:@"firebase"];
diff --git a/Firebase/Database/Realtime/FWebSocketConnection.m b/Firebase/Database/Realtime/FWebSocketConnection.m
index 0fd07e5..49d6bd8 100644
--- a/Firebase/Database/Realtime/FWebSocketConnection.m
+++ b/Firebase/Database/Realtime/FWebSocketConnection.m
@@ -25,7 +25,7 @@
#import "FStringUtilities.h"
#import "FIRDatabase_Private.h"
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
#endif
@@ -85,7 +85,7 @@
BOOL hasUiDeviceClass = NO;
// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual release build.
- #if TARGET_OS_IOS
+ #if TARGET_OS_IOS || TARGET_OS_TV
Class uiDeviceClass = NSClassFromString(@"UIDevice");
if (uiDeviceClass) {
systemVersion = [uiDeviceClass currentDevice].systemVersion;
diff --git a/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m b/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m
index a2c857b..c80dbb0 100644
--- a/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m
+++ b/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m
@@ -18,7 +18,7 @@
#import "FSRWebSocket.h"
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
#define HAS_ICU
#endif
@@ -28,7 +28,7 @@
#import <unicode/utf8.h>
#endif
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
#import <Endian.h>
#elif TARGET_OS_OSX
#import <CoreServices/CoreServices.h>
diff --git a/Firebase/Messaging/FIRMessaging.m b/Firebase/Messaging/FIRMessaging.m
index 782b779..3132831 100644
--- a/Firebase/Messaging/FIRMessaging.m
+++ b/Firebase/Messaging/FIRMessaging.m
@@ -70,6 +70,14 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
@"com.firebase.messaging.notif.fcm-token-refreshed";
#endif // defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
+NSString *const kFIRMessagingUserDefaultsKeyAutoInitEnabled =
+ @"com.firebase.messaging.auto-init.enabled"; // Auto Init Enabled key stored in NSUserDefaults
+NSString *const kFIRMessagingSuiteName =
+ @"com.firebase.messaging.user_defaults"; // Suite name for NSUserDefaults
+
+static NSString *const kFIRMessagingPlistAutoInitEnabled =
+ @"FirebaseMessagingAutoInitEnabled"; // Auto Init Enabled key stored in Info.plist
+
// Copied from Apple's header in case it is missing in some cases (e.g. pre-Xcode 8 builds).
#ifndef NSFoundationVersionNumber_iOS_8_x_Max
#define NSFoundationVersionNumber_iOS_8_x_Max 1199
@@ -120,8 +128,8 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
@end
-@interface FIRMessaging ()
- <FIRMessagingClientDelegate, FIRMessagingReceiverDelegate, FIRReachabilityDelegate>
+@interface FIRMessaging ()<FIRMessagingClientDelegate, FIRMessagingReceiverDelegate,
+ FIRReachabilityDelegate>
// FIRApp properties
@property(nonatomic, readwrite, copy) NSString *fcmSenderID;
@@ -141,6 +149,7 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
@property(nonatomic, readwrite, strong) FIRMessagingRmqManager *rmq2Manager;
@property(nonatomic, readwrite, strong) FIRMessagingReceiver *receiver;
@property(nonatomic, readwrite, strong) FIRMessagingSyncMessageManager *syncMessageManager;
+@property(nonatomic, readwrite, strong) NSUserDefaults *messagingUserDefaults;
/// Message ID's logged for analytics. This prevents us from logging the same message twice
/// which can happen if the user inadvertently calls `appDidReceiveMessage` along with us
@@ -166,6 +175,7 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
if (self) {
_loggedMessageIDs = [NSMutableSet set];
_instanceIDProxy = [[FIRMessagingInstanceIDProxy alloc] init];
+ _messagingUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingSuiteName];
}
return self;
}
@@ -404,7 +414,10 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
}];
} else if ([appDelegate respondsToSelector:openURLWithOptionsSelector]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
[appDelegate application:application openURL:url options:@{}];
+#pragma clang diagnostic pop
// Similarly, |application:openURL:sourceApplication:annotation:| will also always be called, due
// to the default swizzling done by FIRAAppDelegateProxy in Firebase Analytics
@@ -448,6 +461,33 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
#pragma mark - FCM
+- (BOOL)isAutoInitEnabled {
+ // Check storage
+ id isAutoInitEnabledObject =
+ [_messagingUserDefaults objectForKey:kFIRMessagingUserDefaultsKeyAutoInitEnabled];
+ if (isAutoInitEnabledObject) {
+ return [isAutoInitEnabledObject boolValue];
+ }
+
+ // Check Info.plist
+ isAutoInitEnabledObject =
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRMessagingPlistAutoInitEnabled];
+ if (isAutoInitEnabledObject) {
+ return [isAutoInitEnabledObject boolValue];
+ }
+ // If none of above exists, we default assume FCM auto init is enabled.
+ return YES;
+}
+
+- (void)setAutoInitEnabled:(BOOL)autoInitEnabled {
+ BOOL isFCMAutoInitEnabled = [self isAutoInitEnabled];
+ [_messagingUserDefaults setBool:autoInitEnabled
+ forKey:kFIRMessagingUserDefaultsKeyAutoInitEnabled];
+ if (!isFCMAutoInitEnabled && autoInitEnabled) {
+ self.defaultFcmToken = [self.instanceIDProxy token];
+ }
+}
+
- (NSString *)FCMToken {
NSString *token = self.defaultFcmToken;
if (!token) {
@@ -643,10 +683,15 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
}
- (void)subscribeToTopic:(NSString *)topic {
+ [self subscribeToTopic:topic completion:nil];
+}
+
+- (void)subscribeToTopic:(NSString *)topic
+ completion:(nullable FIRMessagingTopicOperationCompletion)completion {
if (self.defaultFcmToken.length && topic.length) {
NSString *normalizeTopic = [[self class ] normalizeTopic:topic];
if (normalizeTopic.length) {
- [self.pubsub subscribeToTopic:normalizeTopic];
+ [self.pubsub subscribeToTopic:normalizeTopic handler:completion];
} else {
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
@"Cannot parse topic name %@. Will not subscribe.", topic);
@@ -659,10 +704,15 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
}
- (void)unsubscribeFromTopic:(NSString *)topic {
+ [self unsubscribeFromTopic:topic completion:nil];
+}
+
+- (void)unsubscribeFromTopic:(NSString *)topic
+ completion:(nullable FIRMessagingTopicOperationCompletion)completion {
if (self.defaultFcmToken.length && topic.length) {
NSString *normalizeTopic = [[self class] normalizeTopic:topic];
if (normalizeTopic.length) {
- [self.pubsub unsubscribeFromTopic:normalizeTopic];
+ [self.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
} else {
FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
@"Cannot parse topic name %@. Will not unsubscribe.", topic);
@@ -728,7 +778,10 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
- (void)receiver:(FIRMessagingReceiver *)receiver
receivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
if ([self.delegate respondsToSelector:@selector(messaging:didReceiveMessage:)]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
[self.delegate messaging:self didReceiveMessage:remoteMessage];
+#pragma pop
} else if ([self.delegate respondsToSelector:@selector(applicationReceivedRemoteMessage:)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -781,7 +834,7 @@ NSString * const FIRMessagingRegistrationTokenRefreshedNotification =
#pragma mark - Notifications
- (void)didReceiveDefaultInstanceIDToken:(NSNotification *)notification {
- if (![notification.object isKindOfClass:[NSString class]]) {
+ if (notification.object && ![notification.object isKindOfClass:[NSString class]]) {
FIRMessagingLoggerDebug(kFIRMessagingMessageCodeMessaging015,
@"Invalid default FCM token type %@",
NSStringFromClass([notification.object class]));
diff --git a/Firebase/Messaging/FIRMessagingContextManagerService.m b/Firebase/Messaging/FIRMessagingContextManagerService.m
index 1c9f653..65f64ad 100644
--- a/Firebase/Messaging/FIRMessagingContextManagerService.m
+++ b/Firebase/Messaging/FIRMessagingContextManagerService.m
@@ -143,8 +143,11 @@ typedef NS_ENUM(NSUInteger, FIRMessagingContextManagerMessageType) {
}
if ([apsDictionary[kFIRMessagingContextManagerTitleKey] length]) {
// |alertTitle| is iOS 8.2+, so check if we can set it
- if ([notification respondsToSelector:@selector(setAlertTitle:)]) {
+ if ([notification respondsToSelector:@selector(setAlertTitle:)]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
notification.alertTitle = apsDictionary[kFIRMessagingContextManagerTitleKey];
+#pragma pop
}
}
diff --git a/Firebase/Messaging/FIRMessagingPubSub.h b/Firebase/Messaging/FIRMessagingPubSub.h
index 3a03494..2ce8ed4 100644
--- a/Firebase/Messaging/FIRMessagingPubSub.h
+++ b/Firebase/Messaging/FIRMessagingPubSub.h
@@ -59,6 +59,7 @@
* library for a given `authorizedEntity` and "gcm" scope.
* @param topic The topic to subscribe to. Should be of the form
* `"/topics/<topic-name>"`.
+ * @param options Unused parameter, please pass nil or empty dictionary.
* @param handler The callback handler invoked when the subscribe call
* ends. In case of success, a nil error is returned. Otherwise,
* an appropriate error object is returned.
@@ -70,7 +71,6 @@
options:(NSDictionary *)options
handler:(FIRMessagingTopicOperationCompletion)handler;
-
/**
* Unsubscribes an app instance from a topic, stopping it from receiving
* any further messages sent to that topic.
@@ -81,6 +81,7 @@
* @param token The token used to subscribe to this topic.
* @param topic The topic to unsubscribe from. Should be of the form
* `"/topics/<topic-name>"`.
+ * @param options Unused parameter, please pass nil or empty dictionary.
* @param handler The handler that is invoked once the unsubscribe call ends.
* In case of success, nil error is returned. Otherwise, an
* appropriate error object is returned.
@@ -98,8 +99,12 @@
* as compared to the `subscribe` method above which tries once.
*
* @param topic The topic name to subscribe to. Should be of the form `"/topics/<topic-name>"`.
+ * @param handler The handler that is invoked once the unsubscribe call ends.
+ * In case of success, nil error is returned. Otherwise, an
+ * appropriate error object is returned.
*/
-- (void)subscribeToTopic:(NSString *)topic;
+- (void)subscribeToTopic:(NSString *)topic
+ handler:(nullable FIRMessagingTopicOperationCompletion)handler;
/**
* Asynchronously unsubscribe from the topic. Adds to the pending list of topic operations.
@@ -107,8 +112,12 @@
* as compared to the `unsubscribe` method above which tries once.
*
* @param topic The topic name to unsubscribe from. Should be of the form `"/topics/<topic-name>"`.
+ * @param handler The handler that is invoked once the unsubscribe call ends.
+ * In case of success, nil error is returned. Otherwise, an
+ * appropriate error object is returned.
*/
-- (void)unsubscribeFromTopic:(NSString *)topic;
+- (void)unsubscribeFromTopic:(NSString *)topic
+ handler:(nullable FIRMessagingTopicOperationCompletion)handler;
/**
* Schedule subscriptions sync.
diff --git a/Firebase/Messaging/FIRMessagingPubSub.m b/Firebase/Messaging/FIRMessagingPubSub.m
index c8293e0..74a5292 100644
--- a/Firebase/Messaging/FIRMessagingPubSub.m
+++ b/Firebase/Messaging/FIRMessagingPubSub.m
@@ -146,16 +146,18 @@ static NSString *const kPendingSubscriptionsListKey =
}];
}
-- (void)subscribeToTopic:(NSString *)topic {
+- (void)subscribeToTopic:(NSString *)topic
+ handler:(nullable FIRMessagingTopicOperationCompletion)handler {
[self.pendingTopicUpdates addOperationForTopic:topic
withAction:FIRMessagingTopicActionSubscribe
- completion:nil];
+ completion:handler];
}
-- (void)unsubscribeFromTopic:(NSString *)topic {
+- (void)unsubscribeFromTopic:(NSString *)topic
+ handler:(nullable FIRMessagingTopicOperationCompletion)handler {
[self.pendingTopicUpdates addOperationForTopic:topic
withAction:FIRMessagingTopicActionUnsubscribe
- completion:nil];
+ completion:handler];
}
- (void)scheduleSync:(BOOL)immediately {
diff --git a/Firebase/Messaging/FIRMessagingRmq2PersistentStore.m b/Firebase/Messaging/FIRMessagingRmq2PersistentStore.m
index a85298c..f58bd52 100644
--- a/Firebase/Messaging/FIRMessagingRmq2PersistentStore.m
+++ b/Firebase/Messaging/FIRMessagingRmq2PersistentStore.m
@@ -104,8 +104,11 @@ typedef void(^FCMOutgoingRmqMessagesTableHandler)(int64_t rmqId, int8_t tag, NSD
// Utility to create an NSString from a sqlite3 result code
NSString * _Nonnull FIRMessagingStringFromSQLiteResult(int result) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
const char *errorStr = sqlite3_errstr(result);
- NSString *errorString = [NSString stringWithFormat:@"%d - %s", result, errorStr];
+#pragma pop
+ NSString *errorString = [NSString stringWithFormat:@"%d - %s", result, errorStr];
return errorString;
}
diff --git a/Firebase/Messaging/FIRMessagingTopicOperation.m b/Firebase/Messaging/FIRMessagingTopicOperation.m
index 90760eb..3120240 100644
--- a/Firebase/Messaging/FIRMessagingTopicOperation.m
+++ b/Firebase/Messaging/FIRMessagingTopicOperation.m
@@ -82,6 +82,7 @@ NSString *FIRMessagingSubscriptionsServer() {
_topic = topic;
_action = action;
_token = token;
+ _options = options;
_checkinService = checkinService;
_completion = completion;
diff --git a/Firebase/Messaging/FIRMessaging_Private.h b/Firebase/Messaging/FIRMessaging_Private.h
index 0c35179..135f091 100644
--- a/Firebase/Messaging/FIRMessaging_Private.h
+++ b/Firebase/Messaging/FIRMessaging_Private.h
@@ -25,6 +25,9 @@ typedef NS_ENUM(int8_t, FIRMessagingNetworkStatus) {
kFIRMessagingReachabilityReachableViaWWAN,
};
+FOUNDATION_EXPORT NSString *const kFIRMessagingUserDefaultsKeyAutoInitEnabled;
+FOUNDATION_EXPORT NSString *const kFIRMessagingSuiteName;
+
@interface FIRMessagingRemoteMessage ()
@property(nonatomic, strong) NSDictionary *appData;
diff --git a/Firebase/Messaging/Protos/GtalkCore.pbobjc.h b/Firebase/Messaging/Protos/GtalkCore.pbobjc.h
index d4c8c8c..46d2d9c 100644
--- a/Firebase/Messaging/Protos/GtalkCore.pbobjc.h
+++ b/Firebase/Messaging/Protos/GtalkCore.pbobjc.h
@@ -197,6 +197,9 @@ typedef GPB_ENUM(GtalkClientEvent_Type) {
GtalkClientEvent_Type_DiscardedEvents = 1,
GtalkClientEvent_Type_FailedConnection = 2,
GtalkClientEvent_Type_SuccessfulConnection = 3,
+ GtalkClientEvent_Type_McsReconnectRequest = 4,
+ GtalkClientEvent_Type_FailedSocketCreationMcsReconnect = 5,
+ GtalkClientEvent_Type_McsReconnectLimited = 6,
};
GPBEnumDescriptor *GtalkClientEvent_Type_EnumDescriptor(void);
@@ -207,6 +210,22 @@ GPBEnumDescriptor *GtalkClientEvent_Type_EnumDescriptor(void);
**/
BOOL GtalkClientEvent_Type_IsValidValue(int32_t value);
+#pragma mark - Enum GtalkClientEvent_McsReconnectAction
+
+typedef GPB_ENUM(GtalkClientEvent_McsReconnectAction) {
+ GtalkClientEvent_McsReconnectAction_None = 0,
+ GtalkClientEvent_McsReconnectAction_NotConnected = 1,
+ GtalkClientEvent_McsReconnectAction_TooSoon = 2,
+};
+
+GPBEnumDescriptor *GtalkClientEvent_McsReconnectAction_EnumDescriptor(void);
+
+/**
+ * Checks to see if the given value is defined by the enum or was not known at
+ * the time this source was generated.
+ **/
+BOOL GtalkClientEvent_McsReconnectAction_IsValidValue(int32_t value);
+
#pragma mark - GtalkGtalkCoreRoot
/**
@@ -247,9 +266,9 @@ typedef GPB_ENUM(GtalkHeartbeatPing_FieldNumber) {
@property(nonatomic, readwrite) BOOL hasStatus;
-@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower;
+@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower DEPRECATED_ATTRIBUTE;
/** Test to see if @c cellTower has been set. */
-@property(nonatomic, readwrite) BOOL hasCellTower;
+@property(nonatomic, readwrite) BOOL hasCellTower DEPRECATED_ATTRIBUTE;
@property(nonatomic, readwrite) int32_t intervalMs;
@@ -282,9 +301,9 @@ typedef GPB_ENUM(GtalkHeartbeatAck_FieldNumber) {
@property(nonatomic, readwrite) BOOL hasStatus;
-@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower;
+@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower DEPRECATED_ATTRIBUTE;
/** Test to see if @c cellTower has been set. */
-@property(nonatomic, readwrite) BOOL hasCellTower;
+@property(nonatomic, readwrite) BOOL hasCellTower DEPRECATED_ATTRIBUTE;
@property(nonatomic, readwrite) int32_t intervalMs;
@@ -406,7 +425,6 @@ typedef GPB_ENUM(GtalkLoginRequest_FieldNumber) {
GtalkLoginRequest_FieldNumber_DeviceId = 6,
GtalkLoginRequest_FieldNumber_LastRmqId = 7,
GtalkLoginRequest_FieldNumber_SettingArray = 8,
- GtalkLoginRequest_FieldNumber_Compress = 9,
GtalkLoginRequest_FieldNumber_ReceivedPersistentIdArray = 10,
GtalkLoginRequest_FieldNumber_IncludeStreamIds = 11,
GtalkLoginRequest_FieldNumber_HeartbeatStat = 13,
@@ -420,6 +438,8 @@ typedef GPB_ENUM(GtalkLoginRequest_FieldNumber) {
GtalkLoginRequest_FieldNumber_GcmStartTimeMs = 21,
GtalkLoginRequest_FieldNumber_ClientEventArray = 22,
GtalkLoginRequest_FieldNumber_OnFallback = 23,
+ GtalkLoginRequest_FieldNumber_NoPendingUpstream = 24,
+ GtalkLoginRequest_FieldNumber_ReconnectRequestId = 25,
};
@interface GtalkLoginRequest : GPBMessage
@@ -464,10 +484,6 @@ typedef GPB_ENUM(GtalkLoginRequest_FieldNumber) {
@property(nonatomic, readonly) NSUInteger settingArray_Count;
-@property(nonatomic, readwrite) int32_t compress;
-
-@property(nonatomic, readwrite) BOOL hasCompress;
-
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *receivedPersistentIdArray;
/** The number of items in @c receivedPersistentIdArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger receivedPersistentIdArray_Count;
@@ -507,9 +523,9 @@ typedef GPB_ENUM(GtalkLoginRequest_FieldNumber) {
@property(nonatomic, readwrite) BOOL hasTokenVersionInfo;
-@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower;
+@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower DEPRECATED_ATTRIBUTE;
/** Test to see if @c cellTower has been set. */
-@property(nonatomic, readwrite) BOOL hasCellTower;
+@property(nonatomic, readwrite) BOOL hasCellTower DEPRECATED_ATTRIBUTE;
@property(nonatomic, readwrite) uint64_t gcmStartTimeMs;
@@ -524,6 +540,14 @@ typedef GPB_ENUM(GtalkLoginRequest_FieldNumber) {
@property(nonatomic, readwrite) BOOL onFallback;
@property(nonatomic, readwrite) BOOL hasOnFallback;
+
+@property(nonatomic, readwrite) BOOL noPendingUpstream;
+
+@property(nonatomic, readwrite) BOOL hasNoPendingUpstream;
+
+@property(nonatomic, readwrite) int32_t reconnectRequestId;
+
+@property(nonatomic, readwrite) BOOL hasReconnectRequestId;
@end
#pragma mark - GtalkLoginResponse
@@ -1242,9 +1266,9 @@ typedef GPB_ENUM(GtalkDataMessageStanza_FieldNumber) {
@property(nonatomic, readwrite) BOOL hasFlags;
-@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower;
+@property(nonatomic, readwrite, strong, null_resettable) GtalkCellTower *cellTower DEPRECATED_ATTRIBUTE;
/** Test to see if @c cellTower has been set. */
-@property(nonatomic, readwrite) BOOL hasCellTower;
+@property(nonatomic, readwrite) BOOL hasCellTower DEPRECATED_ATTRIBUTE;
@property(nonatomic, readwrite) int32_t priority;
@@ -1273,6 +1297,7 @@ typedef GPB_ENUM(GtalkCellTower_FieldNumber) {
GtalkCellTower_FieldNumber_KnownCongestionStatus = 2,
};
+DEPRECATED_ATTRIBUTE
@interface GtalkCellTower : GPBMessage
@@ -1297,6 +1322,7 @@ typedef GPB_ENUM(GtalkClientEvent_FieldNumber) {
GtalkClientEvent_FieldNumber_TimeConnectionEndedMs = 203,
GtalkClientEvent_FieldNumber_ErrorCode = 204,
GtalkClientEvent_FieldNumber_TimeConnectionEstablishedMs = 300,
+ GtalkClientEvent_FieldNumber_McsReconnectAction = 400,
};
@interface GtalkClientEvent : GPBMessage
@@ -1333,6 +1359,10 @@ typedef GPB_ENUM(GtalkClientEvent_FieldNumber) {
@property(nonatomic, readwrite) uint64_t timeConnectionEstablishedMs;
@property(nonatomic, readwrite) BOOL hasTimeConnectionEstablishedMs;
+
+@property(nonatomic, readwrite) GtalkClientEvent_McsReconnectAction mcsReconnectAction;
+
+@property(nonatomic, readwrite) BOOL hasMcsReconnectAction;
@end
NS_ASSUME_NONNULL_END
diff --git a/Firebase/Messaging/Protos/GtalkCore.pbobjc.m b/Firebase/Messaging/Protos/GtalkCore.pbobjc.m
index f4efe22..06c9134 100644
--- a/Firebase/Messaging/Protos/GtalkCore.pbobjc.m
+++ b/Firebase/Messaging/Protos/GtalkCore.pbobjc.m
@@ -503,7 +503,6 @@ typedef struct GtalkHeartbeatConfig__storage_ {
@dynamic hasDeviceId, deviceId;
@dynamic hasLastRmqId, lastRmqId;
@dynamic settingArray, settingArray_Count;
-@dynamic hasCompress, compress;
@dynamic receivedPersistentIdArray, receivedPersistentIdArray_Count;
@dynamic hasIncludeStreamIds, includeStreamIds;
@dynamic hasHeartbeatStat, heartbeatStat;
@@ -517,12 +516,14 @@ typedef struct GtalkHeartbeatConfig__storage_ {
@dynamic hasGcmStartTimeMs, gcmStartTimeMs;
@dynamic clientEventArray, clientEventArray_Count;
@dynamic hasOnFallback, onFallback;
+@dynamic hasNoPendingUpstream, noPendingUpstream;
+@dynamic hasReconnectRequestId, reconnectRequestId;
typedef struct GtalkLoginRequest__storage_ {
uint32_t _has_storage_[1];
- int32_t compress;
GtalkLoginRequest_AuthService authService;
int32_t networkType;
+ int32_t reconnectRequestId;
NSString *id_p;
NSString *domain;
NSString *user;
@@ -620,15 +621,6 @@ typedef struct GtalkLoginRequest__storage_ {
.dataType = GPBDataTypeMessage,
},
{
- .name = "compress",
- .dataTypeSpecific.className = NULL,
- .number = GtalkLoginRequest_FieldNumber_Compress,
- .hasIndex = 7,
- .offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, compress),
- .flags = GPBFieldOptional,
- .dataType = GPBDataTypeInt32,
- },
- {
.name = "receivedPersistentIdArray",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_ReceivedPersistentIdArray,
@@ -641,8 +633,8 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "includeStreamIds",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_IncludeStreamIds,
- .hasIndex = 8,
- .offset = 9, // Stored in _has_storage_ to save space.
+ .hasIndex = 7,
+ .offset = 8, // Stored in _has_storage_ to save space.
.flags = GPBFieldOptional,
.dataType = GPBDataTypeBool,
},
@@ -650,7 +642,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "heartbeatStat",
.dataTypeSpecific.className = GPBStringifySymbol(GtalkHeartbeatStat),
.number = GtalkLoginRequest_FieldNumber_HeartbeatStat,
- .hasIndex = 10,
+ .hasIndex = 9,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, heartbeatStat),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeMessage,
@@ -659,8 +651,8 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "useRmq2",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_UseRmq2,
- .hasIndex = 11,
- .offset = 12, // Stored in _has_storage_ to save space.
+ .hasIndex = 10,
+ .offset = 11, // Stored in _has_storage_ to save space.
.flags = GPBFieldOptional,
.dataType = GPBDataTypeBool,
},
@@ -668,7 +660,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "accountId",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_AccountId,
- .hasIndex = 13,
+ .hasIndex = 12,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, accountId),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt64,
@@ -677,7 +669,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "authService",
.dataTypeSpecific.enumDescFunc = GtalkLoginRequest_AuthService_EnumDescriptor,
.number = GtalkLoginRequest_FieldNumber_AuthService,
- .hasIndex = 14,
+ .hasIndex = 13,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, authService),
.flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
.dataType = GPBDataTypeEnum,
@@ -686,7 +678,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "networkType",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_NetworkType,
- .hasIndex = 15,
+ .hasIndex = 14,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, networkType),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt32,
@@ -695,7 +687,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "status",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_Status,
- .hasIndex = 16,
+ .hasIndex = 15,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, status),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt64,
@@ -704,7 +696,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "tokenVersionInfo",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_TokenVersionInfo,
- .hasIndex = 17,
+ .hasIndex = 16,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, tokenVersionInfo),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
@@ -713,7 +705,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "cellTower",
.dataTypeSpecific.className = GPBStringifySymbol(GtalkCellTower),
.number = GtalkLoginRequest_FieldNumber_CellTower,
- .hasIndex = 18,
+ .hasIndex = 17,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, cellTower),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeMessage,
@@ -722,7 +714,7 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "gcmStartTimeMs",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_GcmStartTimeMs,
- .hasIndex = 19,
+ .hasIndex = 18,
.offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, gcmStartTimeMs),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeUInt64,
@@ -740,11 +732,29 @@ typedef struct GtalkLoginRequest__storage_ {
.name = "onFallback",
.dataTypeSpecific.className = NULL,
.number = GtalkLoginRequest_FieldNumber_OnFallback,
- .hasIndex = 20,
- .offset = 21, // Stored in _has_storage_ to save space.
+ .hasIndex = 19,
+ .offset = 20, // Stored in _has_storage_ to save space.
.flags = GPBFieldOptional,
.dataType = GPBDataTypeBool,
},
+ {
+ .name = "noPendingUpstream",
+ .dataTypeSpecific.className = NULL,
+ .number = GtalkLoginRequest_FieldNumber_NoPendingUpstream,
+ .hasIndex = 21,
+ .offset = 22, // Stored in _has_storage_ to save space.
+ .flags = GPBFieldOptional,
+ .dataType = GPBDataTypeBool,
+ },
+ {
+ .name = "reconnectRequestId",
+ .dataTypeSpecific.className = NULL,
+ .number = GtalkLoginRequest_FieldNumber_ReconnectRequestId,
+ .hasIndex = 23,
+ .offset = (uint32_t)offsetof(GtalkLoginRequest__storage_, reconnectRequestId),
+ .flags = GPBFieldOptional,
+ .dataType = GPBDataTypeInt32,
+ },
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:[GtalkLoginRequest class]
@@ -2730,6 +2740,9 @@ typedef struct GtalkTalkMetadata__storage_ {
#pragma mark - GtalkCellTower
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-implementations"
+
@implementation GtalkCellTower
@dynamic hasId_p, id_p;
@@ -2782,6 +2795,8 @@ typedef struct GtalkCellTower__storage_ {
@end
+#pragma clang diagnostic pop
+
#pragma mark - GtalkClientEvent
@implementation GtalkClientEvent
@@ -2794,6 +2809,7 @@ typedef struct GtalkCellTower__storage_ {
@dynamic hasTimeConnectionEndedMs, timeConnectionEndedMs;
@dynamic hasErrorCode, errorCode;
@dynamic hasTimeConnectionEstablishedMs, timeConnectionEstablishedMs;
+@dynamic hasMcsReconnectAction, mcsReconnectAction;
typedef struct GtalkClientEvent__storage_ {
uint32_t _has_storage_[1];
@@ -2802,6 +2818,7 @@ typedef struct GtalkClientEvent__storage_ {
int32_t networkType;
int32_t networkPort;
int32_t errorCode;
+ GtalkClientEvent_McsReconnectAction mcsReconnectAction;
uint64_t timeConnectionStartedMs;
uint64_t timeConnectionEndedMs;
uint64_t timeConnectionEstablishedMs;
@@ -2885,6 +2902,15 @@ typedef struct GtalkClientEvent__storage_ {
.flags = GPBFieldOptional,
.dataType = GPBDataTypeUInt64,
},
+ {
+ .name = "mcsReconnectAction",
+ .dataTypeSpecific.enumDescFunc = GtalkClientEvent_McsReconnectAction_EnumDescriptor,
+ .number = GtalkClientEvent_FieldNumber_McsReconnectAction,
+ .hasIndex = 8,
+ .offset = (uint32_t)offsetof(GtalkClientEvent__storage_, mcsReconnectAction),
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
+ .dataType = GPBDataTypeEnum,
+ },
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:[GtalkClientEvent class]
@@ -2909,12 +2935,17 @@ GPBEnumDescriptor *GtalkClientEvent_Type_EnumDescriptor(void) {
if (!descriptor) {
static const char *valueNames =
"Unknown\000DiscardedEvents\000FailedConnection"
- "\000SuccessfulConnection\000";
+ "\000SuccessfulConnection\000McsReconnectReques"
+ "t\000FailedSocketCreationMcsReconnect\000McsRe"
+ "connectLimited\000";
static const int32_t values[] = {
GtalkClientEvent_Type_Unknown,
GtalkClientEvent_Type_DiscardedEvents,
GtalkClientEvent_Type_FailedConnection,
GtalkClientEvent_Type_SuccessfulConnection,
+ GtalkClientEvent_Type_McsReconnectRequest,
+ GtalkClientEvent_Type_FailedSocketCreationMcsReconnect,
+ GtalkClientEvent_Type_McsReconnectLimited,
};
GPBEnumDescriptor *worker =
[GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GtalkClientEvent_Type)
@@ -2935,6 +2966,45 @@ BOOL GtalkClientEvent_Type_IsValidValue(int32_t value__) {
case GtalkClientEvent_Type_DiscardedEvents:
case GtalkClientEvent_Type_FailedConnection:
case GtalkClientEvent_Type_SuccessfulConnection:
+ case GtalkClientEvent_Type_McsReconnectRequest:
+ case GtalkClientEvent_Type_FailedSocketCreationMcsReconnect:
+ case GtalkClientEvent_Type_McsReconnectLimited:
+ return YES;
+ default:
+ return NO;
+ }
+}
+
+#pragma mark - Enum GtalkClientEvent_McsReconnectAction
+
+GPBEnumDescriptor *GtalkClientEvent_McsReconnectAction_EnumDescriptor(void) {
+ static GPBEnumDescriptor *descriptor = NULL;
+ if (!descriptor) {
+ static const char *valueNames =
+ "None\000NotConnected\000TooSoon\000";
+ static const int32_t values[] = {
+ GtalkClientEvent_McsReconnectAction_None,
+ GtalkClientEvent_McsReconnectAction_NotConnected,
+ GtalkClientEvent_McsReconnectAction_TooSoon,
+ };
+ GPBEnumDescriptor *worker =
+ [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GtalkClientEvent_McsReconnectAction)
+ valueNames:valueNames
+ values:values
+ count:(uint32_t)(sizeof(values) / sizeof(int32_t))
+ enumVerifier:GtalkClientEvent_McsReconnectAction_IsValidValue];
+ if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {
+ [worker release];
+ }
+ }
+ return descriptor;
+}
+
+BOOL GtalkClientEvent_McsReconnectAction_IsValidValue(int32_t value__) {
+ switch (value__) {
+ case GtalkClientEvent_McsReconnectAction_None:
+ case GtalkClientEvent_McsReconnectAction_NotConnected:
+ case GtalkClientEvent_McsReconnectAction_TooSoon:
return YES;
default:
return NO;
diff --git a/Firebase/Messaging/Public/FIRMessaging.h b/Firebase/Messaging/Public/FIRMessaging.h
index 7cd7b19..33dd596 100644
--- a/Firebase/Messaging/Public/FIRMessaging.h
+++ b/Firebase/Messaging/Public/FIRMessaging.h
@@ -289,7 +289,6 @@ NS_SWIFT_NAME(Messaging)
*/
@property(nonatomic, weak, nullable) id<FIRMessagingDelegate> delegate;
-
/**
* Delegate to handle remote data messages received via FCM for devices running iOS 10 or above.
*/
@@ -354,6 +353,20 @@ NS_SWIFT_NAME(Messaging)
#pragma mark - FCM Tokens
/**
+ * Is Firebase Messaging token auto generation enabled? If this flag is disabled,
+ * Firebase Messaging will not generate token automatically for message delivery.
+ *
+ * This setting is persisted, and is applied on future
+ * invocations of your application. Once explicitly set, it overrides any
+ * settings in your Info.plist.
+ *
+ * By default, FCM automatic initialization is enabled. If you need to change the
+ * default (for example, because you want to prompt the user before getting token)
+ * set FirebaseMessagingAutoInitEnabled to false in your application's Info.plist.
+ */
+@property(nonatomic, assign, getter=isAutoInitEnabled) BOOL autoInitEnabled;
+
+/**
* The FCM token is used to identify this device so that FCM can send notifications to it.
* It is associated with your APNS token when the APNS token is supplied, so that sending
* messages to the FCM token will be delivered over APNS.
diff --git a/Firebase/Storage/CHANGELOG.md b/Firebase/Storage/CHANGELOG.md
index 00fc3b7..1077b9f 100644
--- a/Firebase/Storage/CHANGELOG.md
+++ b/Firebase/Storage/CHANGELOG.md
@@ -1,3 +1,9 @@
+# v2.1.2
+- [added] Firebase Storage is now community-supported on tvOS.
+
+# v2.1.1
+- [changed] Internal cleanup in the firebase-ios-sdk repository. Functionality of the Storage SDK is not affected.
+
# v2.1.0
- [added] Added 'md5Hash' to FIRStorageMetadata.
diff --git a/Firebase/Storage/FIRStorageErrors.m b/Firebase/Storage/FIRStorageErrors.m
index 92c0536..ecfae02 100644
--- a/Firebase/Storage/FIRStorageErrors.m
+++ b/Firebase/Storage/FIRStorageErrors.m
@@ -63,7 +63,7 @@
NSString *totalString = total ? @(total).stringValue : @"unknown";
NSString *sizeString = total ? @(size).stringValue : @"unknown";
NSString *const kSizeExceededErrorFormat =
- @"Attempeted to download object with size of %@ bytes, "
+ @"Attempted to download object with size of %@ bytes, "
@"which exceeds the maximum size of %@ bytes. "
@"Consider raising the maximum download size, or using "
@"[FIRStorageReference writeToFile:]";
@@ -104,7 +104,7 @@
break;
case FIRStorageErrorCodeUnknown:
- /* Fall through to default case for unknown errors */
+ /* Fall through to default case for unknown errors */
default:
errorMessage = @"An unknown error occurred, please check the server response.";
diff --git a/Firebase/Storage/FIRStorageObservableTask.m b/Firebase/Storage/FIRStorageObservableTask.m
index 58455f6..7d7c61f 100644
--- a/Firebase/Storage/FIRStorageObservableTask.m
+++ b/Firebase/Storage/FIRStorageObservableTask.m
@@ -102,7 +102,7 @@
break;
case FIRStorageTaskStatusUnknown:
- // Fall through to exception case if an unknown status is passed
+ // Fall through to exception case if an unknown status is passed
default:
[NSException raise:NSInternalInconsistencyException
diff --git a/Firebase/Storage/FIRStorageUtils.m b/Firebase/Storage/FIRStorageUtils.m
index 216b4b6..bc517ff 100644
--- a/Firebase/Storage/FIRStorageUtils.m
+++ b/Firebase/Storage/FIRStorageUtils.m
@@ -14,7 +14,7 @@
#import <Foundation/Foundation.h>
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS || TARGET_OS_TV
#import <MobileCoreServices/MobileCoreServices.h>
#elif TARGET_OS_OSX
#import <CoreServices/CoreServices.h>
diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec
index 3ee4832..9589a40 100644
--- a/FirebaseAuth.podspec
+++ b/FirebaseAuth.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseAuth'
- s.version = '4.4.0'
+ s.version = '4.4.2'
s.summary = 'The official iOS client for Firebase Authentication'
s.description = <<-DESC
@@ -19,6 +19,7 @@ supports email and password accounts, as well as several 3rd party authenticatio
s.social_media_url = 'https://twitter.com/Firebase'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.10'
+ s.tvos.deployment_target = '10.0'
s.cocoapods_version = '>= 1.4.0.beta.2'
s.static_framework = true
@@ -41,6 +42,13 @@ supports email and password accounts, as well as several 3rd party authenticatio
source + '**/FIRPhoneAuthCredential.[mh]',
source + '**/FIRPhoneAuthProvider.[mh]'
]
+ s.tvos.exclude_files = [
+ source + '**/FIRAuthURLPresenter.[mh]',
+ source + '**/FIRAuthWebView.[mh]',
+ source + '**/FIRAuthWebViewController.[mh]',
+ source + '**/FIRPhoneAuthCredential.[mh]',
+ source + '**/FIRPhoneAuthProvider.[mh]'
+ ]
s.public_header_files = source + 'Public/*.h'
s.preserve_paths = [
'Firebase/Auth/README.md',
diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec
index 453518f..3c583cf 100644
--- a/FirebaseCore.podspec
+++ b/FirebaseCore.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseCore'
- s.version = '4.0.12'
+ s.version = '4.0.14'
s.summary = 'Firebase Core for iOS'
s.description = <<-DESC
@@ -18,6 +18,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration
s.social_media_url = 'https://twitter.com/Firebase'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.10'
+ s.tvos.deployment_target = '10.0'
s.cocoapods_version = '>= 1.4.0.beta.2'
s.static_framework = true
@@ -26,6 +27,13 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration
s.source_files = 'Firebase/Core/**/*.[mh]'
s.public_header_files = 'Firebase/Core/Public/*.h', 'Firebase/Core/Private/*.h'
s.private_header_files = 'Firebase/Core/Private/*.h'
- s.framework = 'SystemConfiguration'
+ s.frameworks = [
+ 'Foundation',
+ 'SystemConfiguration'
+ ]
s.dependency 'GoogleToolboxForMac/NSData+zlib', '~> 2.1'
+ s.pod_target_xcconfig = {
+ 'OTHER_CFLAGS' => '-fno-autolink ' +
+ '-DFIRCore_VERSION=' + s.version.to_s + ' -DFirebase_VERSION=4.8.0'
+ }
end
diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec
index 338a2f6..4497254 100644
--- a/FirebaseDatabase.podspec
+++ b/FirebaseDatabase.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseDatabase'
- s.version = '4.1.2'
+ s.version = '4.1.4'
s.summary = 'Firebase Open Source Libraries for iOS.'
s.description = <<-DESC
@@ -18,6 +18,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel
s.social_media_url = 'https://twitter.com/Firebase'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.10'
+ s.tvos.deployment_target = '10.0'
s.cocoapods_version = '>= 1.4.0.beta.2'
s.static_framework = true
diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec
index ed7346c..b3db410 100644
--- a/FirebaseFirestore.podspec
+++ b/FirebaseFirestore.podspec
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'FirebaseFirestore'
- s.version = '0.9.3'
+ s.version = '0.10.0'
s.summary = 'Google Cloud Firestore for iOS'
s.description = <<-DESC
@@ -32,16 +32,25 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
'Firestore/Source/**/*',
'Firestore/Port/**/*',
'Firestore/Protos/objc/**/*.[hm]',
- 'Firestore/core/src/**/*.{h,cc}',
- 'Firestore/third_party/Immutable/*.[mh]'
+ 'Firestore/core/include/**/*.{h,cc,mm}',
+ 'Firestore/core/src/**/*.{h,cc,mm}',
+ 'Firestore/third_party/Immutable/*.[mh]',
+ 'Firestore/third_party/abseil-cpp/**/*.{h,cc}'
]
s.requires_arc = [
'Firestore/Source/**/*',
+ 'Firestore/core/src/**/*.mm',
'Firestore/third_party/Immutable/*.[mh]'
]
s.exclude_files = [
'Firestore/Port/*test.cc',
- 'Firestore/third_party/Immutable/Tests/**'
+ 'Firestore/third_party/Immutable/Tests/**',
+ 'Firestore/third_party/abseil-cpp/**/*_test.{h,cc}',
+
+ # Exclude alternate implementations for other platforms
+ 'Firestore/core/src/firebase/firestore/util/assert_stdio.cc',
+ 'Firestore/core/src/firebase/firestore/util/log_stdio.cc',
+ 'Firestore/core/src/firebase/firestore/util/secure_random_openssl.cc'
]
s.public_header_files = 'Firestore/Source/Public/*.h'
@@ -54,9 +63,18 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
s.frameworks = 'MobileCoreServices'
s.library = 'c++'
s.pod_target_xcconfig = {
- 'GCC_PREPROCESSOR_DEFINITIONS' =>
- 'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 ',
- 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"',
- 'OTHER_CFLAGS' => '-DFIRFirestore_VERSION=' + s.version.to_s
+ 'GCC_PREPROCESSOR_DEFINITIONS' => 'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 ',
+ 'HEADER_SEARCH_PATHS' =>
+ '"${PODS_TARGET_SRCROOT}" ' +
+ '"${PODS_TARGET_SRCROOT}/Firestore/third_party/abseil-cpp"',
+ 'OTHER_CFLAGS' => '-DFIRFirestore_VERSION=' + s.version.to_s
}
+
+ s.prepare_command = <<-CMD
+ # Generate a version of the config.h header suitable for building with
+ # CocoaPods.
+ sed '/^#cmakedefine/ d' \
+ Firestore/core/src/firebase/firestore/util/config.h.in > \
+ Firestore/core/src/firebase/firestore/util/config.h
+ CMD
end
diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec
index a26b0b9..b1fdb68 100644
--- a/FirebaseMessaging.podspec
+++ b/FirebaseMessaging.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseMessaging'
- s.version = '2.0.7'
+ s.version = '2.0.8'
s.summary = 'Firebase Messaging for iOS'
s.description = <<-DESC
diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec
index af81620..a466210 100644
--- a/FirebaseStorage.podspec
+++ b/FirebaseStorage.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseStorage'
- s.version = '2.1.0'
+ s.version = '2.1.2'
s.summary = 'Firebase Storage for iOS'
s.description = <<-DESC
@@ -18,6 +18,7 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas
s.social_media_url = 'https://twitter.com/Firebase'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.10'
+ s.tvos.deployment_target = '10.0'
s.cocoapods_version = '>= 1.4.0.beta.2'
s.static_framework = true
diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md
index 0c5bcdc..13b147d 100644
--- a/Firestore/CHANGELOG.md
+++ b/Firestore/CHANGELOG.md
@@ -1,8 +1,34 @@
# Unreleased
+- [fixed] Fixed a regression in Firebase iOS release 4.8.1 that could in certain
+ cases result in an "OnlineState should not affect limbo documents." assertion
+ crash when the client loses its network connection.
+
+# v0.10.0
+- [changed] Removed the includeMetadataChanges property in FIRDocumentListenOptions
+ to avoid confusion with the factory method of the same name.
+- [changed] Added a commit method that takes no completion handler to FIRWriteBatch.
+- [feature] Queries can now be created from an NSPredicate.
+- [feature] Added SnapshotOptions API to control how DocumentSnapshots return unresolved
+ server timestamps.
+- [feature] Added `disableNetwork()` and `enableNetwork()` methods to
+ `Firestore` class, allowing for explicit network management.
+- [changed] For non-existing documents, DocumentSnapshot.data() now returns `nil`
+ instead of throwing an exception. A non-nullable QueryDocumentSnapshot is
+ introduced for Queries to reduce the number of nil-checks in your code.
+- [changed] Snapshot listeners (with the `includeMetadataChanges` option
+ enabled) now receive an event with `snapshot.metadata.isFromCache` set to
+ `true` if the SDK loses its connection to the backend. A new event with
+ `snapshot.metadata.isFromCache` set to false will be raised once the
+ connection is restored and the query is in sync with the backend again.
+- [fixed] Multiple offline mutations now properly reflected in retrieved
+ documents. Previously, only the last mutation would be visible. (#643)
+- [fixed] Fixed a crash in `closeWithFinaleState:` that could be triggered by
+ signing out when the app didn't have a network connection.
+
+# v0.9.4
- [changed] Firestore no longer has a direct dependency on FirebaseAuth.
- [fixed] Fixed a crash when using path names with international characters
with persistence enabled.
-
- [fixed] Addressed race condition during the teardown of idle streams (#490).
# v0.9.3
diff --git a/Firestore/CMakeLists.txt b/Firestore/CMakeLists.txt
index 6c2a32e..b8c95c6 100644
--- a/Firestore/CMakeLists.txt
+++ b/Firestore/CMakeLists.txt
@@ -13,20 +13,54 @@
# limitations under the License.
cmake_minimum_required(VERSION 2.8.11)
-project(firestore)
+project(firestore C CXX)
-set(FIREBASE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/..")
-include("${FIREBASE_SOURCE_DIR}/cmake/utils.cmake")
+set(FIREBASE_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
-find_package(GTest REQUIRED)
+# CMAKE_INSTALL_PREFIX should be passed in to this build so that it can find
+# outputs of the superbuild. This is handled automatically if run via the
+# superbuild (i.e. by invoking cmake on the directory above this).
+#
+# If you want to use this project directly in e.g. CLion, make sure you
+# configure this.
+set(FIREBASE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
-# We use C++11
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
+list(INSERT CMAKE_MODULE_PATH 0 ${FIREBASE_SOURCE_DIR}/cmake)
+include(utils)
-# Fully qualified imports, project wide
-include_directories("${FIREBASE_SOURCE_DIR}")
+# Include GoogleTest directly in the build.
+set(gtest_dir ${FIREBASE_INSTALL_DIR}/external/googletest)
+add_subdirectory(
+ ${gtest_dir}/src/googletest
+ ${gtest_dir}/src/googletest-build
+ EXCLUDE_FROM_ALL
+)
+
+# Set up aliases with the same names as available via FindGTest.
+add_library(
+ GTest::GTest ALIAS gtest
+)
+
+add_library(
+ GTest::Main ALIAS gtest_main
+)
+
+find_package(LevelDB REQUIRED)
+find_package(GRPC REQUIRED)
+
+if(APPLE)
+ find_package(FirebaseCore REQUIRED)
+endif()
enable_testing()
+add_subdirectory(third_party/abseil-cpp)
+
+include(CompilerSetup)
+
+# Generated sources will be relative to the binary directory.
+include_directories(${FIREBASE_INSTALL_DIR})
+
+# Fully qualified imports, project wide
+include_directories(${FIREBASE_SOURCE_DIR})
+
add_subdirectory(core)
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index 437b661..4a8f4fb 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -24,12 +24,92 @@
/* Begin PBXBuildFile section */
3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; };
+ 5436F32420008FAD006E51E3 /* string_printf_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5436F32320008FAD006E51E3 /* string_printf_test.cc */; };
54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A531FC913E500713A1A /* secure_random_test.cc */; };
54740A581FC914F000713A1A /* autoid_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A521FC913E500713A1A /* autoid_test.cc */; };
- 54764FAB1FAA0C320085E60A /* string_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54764FAA1FAA0C320085E60A /* string_util_test.cc */; };
54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */; };
+ 548DB927200D590300E00ABC /* assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 548DB926200D590300E00ABC /* assert_test.cc */; };
+ 548DB929200D59F600E00ABC /* comparison_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 548DB928200D59F600E00ABC /* comparison_test.cc */; };
5491BC721FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */; };
5491BC731FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */; };
+ 5492E03120213FFC00B64F25 /* FSTLevelDBSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */; };
+ 5492E03220213FFC00B64F25 /* FSTMockDatastore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02D20213FFC00B64F25 /* FSTMockDatastore.mm */; };
+ 5492E03320213FFC00B64F25 /* FSTSyncEngineTestDriver.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02E20213FFC00B64F25 /* FSTSyncEngineTestDriver.mm */; };
+ 5492E03420213FFC00B64F25 /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; };
+ 5492E03520213FFC00B64F25 /* FSTSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */; };
+ 5492E03B2021401F00B64F25 /* FSTTestDispatchQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0362021401E00B64F25 /* FSTTestDispatchQueue.mm */; };
+ 5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0372021401E00B64F25 /* XCTestCase+Await.mm */; };
+ 5492E03D2021401F00B64F25 /* FSTAssertTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0382021401E00B64F25 /* FSTAssertTests.mm */; };
+ 5492E03E2021401F00B64F25 /* FSTEventAccumulator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */; };
+ 5492E03F2021401F00B64F25 /* FSTHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03A2021401F00B64F25 /* FSTHelpers.mm */; };
+ 5492E041202143E700B64F25 /* FSTEventAccumulator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */; };
+ 5492E0422021440500B64F25 /* FSTHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03A2021401F00B64F25 /* FSTHelpers.mm */; };
+ 5492E0432021441E00B64F25 /* FSTTestDispatchQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0362021401E00B64F25 /* FSTTestDispatchQueue.mm */; };
+ 5492E0442021457E00B64F25 /* XCTestCase+Await.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0372021401E00B64F25 /* XCTestCase+Await.mm */; };
+ 5492E050202154AA00B64F25 /* FIRCollectionReferenceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E045202154AA00B64F25 /* FIRCollectionReferenceTests.mm */; };
+ 5492E051202154AA00B64F25 /* FIRQueryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E046202154AA00B64F25 /* FIRQueryTests.mm */; };
+ 5492E052202154AB00B64F25 /* FIRGeoPointTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E048202154AA00B64F25 /* FIRGeoPointTests.mm */; };
+ 5492E053202154AB00B64F25 /* FIRDocumentReferenceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E049202154AA00B64F25 /* FIRDocumentReferenceTests.mm */; };
+ 5492E054202154AB00B64F25 /* FIRFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04A202154AA00B64F25 /* FIRFieldValueTests.mm */; };
+ 5492E055202154AB00B64F25 /* FIRDocumentSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04B202154AA00B64F25 /* FIRDocumentSnapshotTests.mm */; };
+ 5492E056202154AB00B64F25 /* FIRFieldPathTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04C202154AA00B64F25 /* FIRFieldPathTests.mm */; };
+ 5492E057202154AB00B64F25 /* FIRSnapshotMetadataTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */; };
+ 5492E058202154AB00B64F25 /* FSTAPIHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04E202154AA00B64F25 /* FSTAPIHelpers.mm */; };
+ 5492E059202154AB00B64F25 /* FIRQuerySnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04F202154AA00B64F25 /* FIRQuerySnapshotTests.mm */; };
+ 5492E062202154B900B64F25 /* FSTTimestampTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E05B202154B800B64F25 /* FSTTimestampTests.mm */; };
+ 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E05C202154B800B64F25 /* FSTViewSnapshotTest.mm */; };
+ 5492E064202154B900B64F25 /* FSTQueryListenerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E05D202154B900B64F25 /* FSTQueryListenerTests.mm */; };
+ 5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E05E202154B900B64F25 /* FSTViewTests.mm */; };
+ 5492E066202154B900B64F25 /* FSTDatabaseInfoTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E05F202154B900B64F25 /* FSTDatabaseInfoTests.mm */; };
+ 5492E067202154B900B64F25 /* FSTEventManagerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E060202154B900B64F25 /* FSTEventManagerTests.mm */; };
+ 5492E068202154B900B64F25 /* FSTQueryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E061202154B900B64F25 /* FSTQueryTests.mm */; };
+ 5492E072202154D600B64F25 /* FIRQueryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E069202154D500B64F25 /* FIRQueryTests.mm */; };
+ 5492E073202154D600B64F25 /* FIRFieldsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */; };
+ 5492E074202154D600B64F25 /* FIRListenerRegistrationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */; };
+ 5492E075202154D600B64F25 /* FIRDatabaseTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */; };
+ 5492E076202154D600B64F25 /* FIRValidationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06D202154D600B64F25 /* FIRValidationTests.mm */; };
+ 5492E077202154D600B64F25 /* FIRServerTimestampTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06E202154D600B64F25 /* FIRServerTimestampTests.mm */; };
+ 5492E078202154D600B64F25 /* FIRWriteBatchTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06F202154D600B64F25 /* FIRWriteBatchTests.mm */; };
+ 5492E079202154D600B64F25 /* FIRCursorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E070202154D600B64F25 /* FIRCursorTests.mm */; };
+ 5492E07A202154D600B64F25 /* FIRTypeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E071202154D600B64F25 /* FIRTypeTests.mm */; };
+ 5492E07F202154EC00B64F25 /* FSTTransactionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07B202154EB00B64F25 /* FSTTransactionTests.mm */; };
+ 5492E080202154EC00B64F25 /* FSTSmokeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07C202154EB00B64F25 /* FSTSmokeTests.mm */; };
+ 5492E081202154EC00B64F25 /* FSTStreamTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07D202154EB00B64F25 /* FSTStreamTests.mm */; };
+ 5492E082202154EC00B64F25 /* FSTDatastoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07E202154EC00B64F25 /* FSTDatastoreTests.mm */; };
+ 5492E09D2021552D00B64F25 /* FSTLocalStoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0832021552A00B64F25 /* FSTLocalStoreTests.mm */; };
+ 5492E09E2021552D00B64F25 /* FSTEagerGarbageCollectorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0842021552A00B64F25 /* FSTEagerGarbageCollectorTests.mm */; };
+ 5492E09F2021552D00B64F25 /* FSTLevelDBMigrationsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0862021552A00B64F25 /* FSTLevelDBMigrationsTests.mm */; };
+ 5492E0A02021552D00B64F25 /* FSTLevelDBMutationQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0872021552A00B64F25 /* FSTLevelDBMutationQueueTests.mm */; };
+ 5492E0A12021552D00B64F25 /* FSTMemoryLocalStoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0882021552A00B64F25 /* FSTMemoryLocalStoreTests.mm */; };
+ 5492E0A22021552D00B64F25 /* FSTQueryCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0892021552A00B64F25 /* FSTQueryCacheTests.mm */; };
+ 5492E0A32021552D00B64F25 /* FSTLocalSerializerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E08A2021552A00B64F25 /* FSTLocalSerializerTests.mm */; };
+ 5492E0A42021552D00B64F25 /* FSTMemoryQueryCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E08B2021552B00B64F25 /* FSTMemoryQueryCacheTests.mm */; };
+ 5492E0A52021552D00B64F25 /* FSTMemoryRemoteDocumentCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E08C2021552B00B64F25 /* FSTMemoryRemoteDocumentCacheTests.mm */; };
+ 5492E0A62021552D00B64F25 /* FSTPersistenceTestHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E08D2021552B00B64F25 /* FSTPersistenceTestHelpers.mm */; };
+ 5492E0A72021552D00B64F25 /* FSTLevelDBKeyTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E08E2021552B00B64F25 /* FSTLevelDBKeyTests.mm */; };
+ 5492E0A82021552D00B64F25 /* FSTLevelDBLocalStoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E08F2021552B00B64F25 /* FSTLevelDBLocalStoreTests.mm */; };
+ 5492E0A92021552D00B64F25 /* FSTRemoteDocumentChangeBufferTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0902021552B00B64F25 /* FSTRemoteDocumentChangeBufferTests.mm */; };
+ 5492E0AA2021552D00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0922021552B00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm */; };
+ 5492E0AB2021552D00B64F25 /* StringViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0932021552B00B64F25 /* StringViewTests.mm */; };
+ 5492E0AC2021552D00B64F25 /* FSTMutationQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0962021552C00B64F25 /* FSTMutationQueueTests.mm */; };
+ 5492E0AD2021552D00B64F25 /* FSTMemoryMutationQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0972021552C00B64F25 /* FSTMemoryMutationQueueTests.mm */; };
+ 5492E0AE2021552D00B64F25 /* FSTLevelDBQueryCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0982021552C00B64F25 /* FSTLevelDBQueryCacheTests.mm */; };
+ 5492E0AF2021552D00B64F25 /* FSTReferenceSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09A2021552C00B64F25 /* FSTReferenceSetTests.mm */; };
+ 5492E0B02021552D00B64F25 /* FSTWriteGroupTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09B2021552C00B64F25 /* FSTWriteGroupTests.mm */; };
+ 5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */; };
+ 5492E0B92021555100B64F25 /* FSTDocumentKeyTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */; };
+ 5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */; };
+ 5492E0BB2021555100B64F25 /* FSTDatabaseIDTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B42021555100B64F25 /* FSTDatabaseIDTests.mm */; };
+ 5492E0BC2021555100B64F25 /* FSTPathTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B52021555100B64F25 /* FSTPathTests.mm */; };
+ 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */; };
+ 5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B72021555100B64F25 /* FSTMutationTests.mm */; };
+ 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */; };
+ 5492E0C62021557E00B64F25 /* FSTWatchChange+Testing.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C02021557E00B64F25 /* FSTWatchChange+Testing.mm */; };
+ 5492E0C72021557E00B64F25 /* FSTSerializerBetaTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */; };
+ 5492E0C82021557E00B64F25 /* FSTDatastoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C22021557E00B64F25 /* FSTDatastoreTests.mm */; };
+ 5492E0C92021557E00B64F25 /* FSTRemoteEventTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */; };
+ 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */; };
+ 54C2294F1FECABAE007D065B /* log_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54C2294E1FECABAE007D065B /* log_test.cc */; };
54DA12A61F315EE100DD57A1 /* collection_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129C1F315EE100DD57A1 /* collection_spec_test.json */; };
54DA12A71F315EE100DD57A1 /* existence_filter_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */; };
54DA12A81F315EE100DD57A1 /* limbo_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */; };
@@ -40,11 +120,7 @@
54DA12AD1F315EE100DD57A1 /* persistence_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A31F315EE100DD57A1 /* persistence_spec_test.json */; };
54DA12AE1F315EE100DD57A1 /* resume_token_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A41F315EE100DD57A1 /* resume_token_spec_test.json */; };
54DA12AF1F315EE100DD57A1 /* write_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A51F315EE100DD57A1 /* write_spec_test.json */; };
- 54DA12B11F315F3800DD57A1 /* FIRValidationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 54DA12B01F315F3800DD57A1 /* FIRValidationTests.m */; };
- 54E928241F33953300C1953E /* FSTEventAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E9281D1F33950B00C1953E /* FSTEventAccumulator.m */; };
- 54E928251F33953400C1953E /* FSTEventAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E9281D1F33950B00C1953E /* FSTEventAccumulator.m */; };
- 54E9282C1F339CAD00C1953E /* XCTestCase+Await.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E9282B1F339CAD00C1953E /* XCTestCase+Await.m */; };
- 54E9282D1F339CAD00C1953E /* XCTestCase+Await.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E9282B1F339CAD00C1953E /* XCTestCase+Await.m */; };
+ 54EB764D202277B30088B8F3 /* array_sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
@@ -57,86 +133,30 @@
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
- 61E1D8B11FCF6C5700753285 /* StringViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 61E1D8AF1FCF6AF500753285 /* StringViewTests.mm */; };
6ED54761B845349D43DB6B78 /* Pods_Firestore_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */; };
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
+ AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB356EF6200EA5EB0089B766 /* field_value_test.cc */; };
+ AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CF82019382300D97691 /* target_id_generator_test.cc */; };
+ AB380CFE201A2F4500D97691 /* string_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CFC201A2EE200D97691 /* string_util_test.cc */; };
+ AB380D02201BC69F00D97691 /* bits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380D01201BC69F00D97691 /* bits_test.cc */; };
+ AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380D03201BC6E400D97691 /* ordered_code_test.cc */; };
+ AB7BAB342012B519001E0872 /* geo_point_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB7BAB332012B519001E0872 /* geo_point_test.cc */; };
+ ABE6637A201FA81900ED349A /* database_id_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB71064B201FA60300344F18 /* database_id_test.cc */; };
+ ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABF6506B201131F8005F2C74 /* timestamp_test.cc */; };
AFE6114F0D4DAECBA7B7C089 /* Pods_Firestore_IntegrationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */; };
C4E749275AD0FBDF9F4716A8 /* Pods_SwiftBuildTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32AD40BF6B0E849B07FFD05E /* Pods_SwiftBuildTest.framework */; };
- D5B2532E4676014F57A7EAB9 /* FSTStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */; };
- D5B25474286C9800CE42B8C2 /* FSTTestDispatchQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */; };
- D5B259FDEE8094E8D710C5BF /* FSTTestDispatchQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */; };
- DE03B2C91F2149D600A30B9C /* FSTTransactionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C61F0D48AC0013853F /* FSTTransactionTests.m */; };
DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
DE03B2D61F2149D600A30B9C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
DE03B2D71F2149D600A30B9C /* Pods_Firestore_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */; };
DE03B2DD1F2149D600A30B9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
- DE03B2EC1F214BA200A30B9C /* FSTDatastoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C41F0D48AC0013853F /* FSTDatastoreTests.m */; };
- DE03B2ED1F214BA200A30B9C /* FSTSmokeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C51F0D48AC0013853F /* FSTSmokeTests.m */; };
- DE03B2EE1F214BAA00A30B9C /* FIRWriteBatchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE0F471F1F960A0071599A /* FIRWriteBatchTests.m */; };
- DE03B2EF1F214BAA00A30B9C /* FIRCursorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1BD1F0D48AC0013853F /* FIRCursorTests.m */; };
- DE03B2F01F214BAA00A30B9C /* FIRDatabaseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1BE1F0D48AC0013853F /* FIRDatabaseTests.m */; };
- DE03B2F11F214BAA00A30B9C /* FIRFieldsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1BF1F0D48AC0013853F /* FIRFieldsTests.m */; };
- DE03B2F21F214BAA00A30B9C /* FIRListenerRegistrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C01F0D48AC0013853F /* FIRListenerRegistrationTests.m */; };
- DE03B2F31F214BAA00A30B9C /* FIRQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C11F0D48AC0013853F /* FIRQueryTests.m */; };
- DE03B2F41F214BAA00A30B9C /* FIRServerTimestampTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C21F0D48AC0013853F /* FIRServerTimestampTests.m */; };
- DE03B2F51F214BAA00A30B9C /* FIRTypeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C31F0D48AC0013853F /* FIRTypeTests.m */; };
- DE03B35E1F21586C00A30B9C /* FSTHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1891F0D48AC0013853F /* FSTHelpers.m */; };
DE03B3631F215E1A00A30B9C /* CAcert.pem in Resources */ = {isa = PBXBuildFile; fileRef = DE03B3621F215E1600A30B9C /* CAcert.pem */; };
DE0761F81F2FE68D003233AF /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0761F61F2FE68D003233AF /* main.swift */; };
DE2EF0851F3D0B6E003D0CDC /* FSTArraySortedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF07E1F3D0B6E003D0CDC /* FSTArraySortedDictionaryTests.m */; };
DE2EF0861F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF0801F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m */; };
DE2EF0871F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF0821F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m */; };
DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF0841F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m */; };
- DE51B1CC1F0D48C00013853F /* FIRGeoPointTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1841F0D48AC0013853F /* FIRGeoPointTests.m */; };
- DE51B1CD1F0D48CD0013853F /* FSTDatabaseInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1A91F0D48AC0013853F /* FSTDatabaseInfoTests.m */; };
- DE51B1CE1F0D48CD0013853F /* FSTEventManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1AA1F0D48AC0013853F /* FSTEventManagerTests.m */; };
- DE51B1CF1F0D48CD0013853F /* FSTQueryListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1AB1F0D48AC0013853F /* FSTQueryListenerTests.m */; };
- DE51B1D01F0D48CD0013853F /* FSTQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1AC1F0D48AC0013853F /* FSTQueryTests.m */; };
- DE51B1D11F0D48CD0013853F /* FSTTargetIDGeneratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1AE1F0D48AC0013853F /* FSTTargetIDGeneratorTests.m */; };
- DE51B1D21F0D48CD0013853F /* FSTTimestampTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1AF1F0D48AC0013853F /* FSTTimestampTests.m */; };
- DE51B1D31F0D48CD0013853F /* FSTViewSnapshotTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B01F0D48AC0013853F /* FSTViewSnapshotTest.m */; };
- DE51B1D41F0D48CD0013853F /* FSTViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B11F0D48AC0013853F /* FSTViewTests.m */; };
- DE51B1D91F0D490D0013853F /* FSTEagerGarbageCollectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1631F0D48AC0013853F /* FSTEagerGarbageCollectorTests.m */; };
- DE51B1DA1F0D490D0013853F /* FSTLevelDBLocalStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1651F0D48AC0013853F /* FSTLevelDBLocalStoreTests.m */; };
- DE51B1DB1F0D490D0013853F /* FSTLevelDBQueryCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1671F0D48AC0013853F /* FSTLevelDBQueryCacheTests.m */; };
- DE51B1DC1F0D490D0013853F /* FSTLocalSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1691F0D48AC0013853F /* FSTLocalSerializerTests.m */; };
- DE51B1DD1F0D490D0013853F /* FSTLocalStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B16B1F0D48AC0013853F /* FSTLocalStoreTests.m */; };
- DE51B1DE1F0D490D0013853F /* FSTMemoryLocalStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B16C1F0D48AC0013853F /* FSTMemoryLocalStoreTests.m */; };
- DE51B1DF1F0D490D0013853F /* FSTMemoryMutationQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B16D1F0D48AC0013853F /* FSTMemoryMutationQueueTests.m */; };
- DE51B1E01F0D490D0013853F /* FSTMemoryQueryCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B16E1F0D48AC0013853F /* FSTMemoryQueryCacheTests.m */; };
- DE51B1E11F0D490D0013853F /* FSTMemoryRemoteDocumentCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B16F1F0D48AC0013853F /* FSTMemoryRemoteDocumentCacheTests.m */; };
- DE51B1E21F0D490D0013853F /* FSTMutationQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1711F0D48AC0013853F /* FSTMutationQueueTests.m */; };
- DE51B1E31F0D490D0013853F /* FSTPersistenceTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1731F0D48AC0013853F /* FSTPersistenceTestHelpers.m */; };
- DE51B1E41F0D490D0013853F /* FSTQueryCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1751F0D48AC0013853F /* FSTQueryCacheTests.m */; };
- DE51B1E51F0D490D0013853F /* FSTReferenceSetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1761F0D48AC0013853F /* FSTReferenceSetTests.m */; };
- DE51B1E61F0D490D0013853F /* FSTRemoteDocumentCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1781F0D48AC0013853F /* FSTRemoteDocumentCacheTests.m */; };
- DE51B1E71F0D490D0013853F /* FSTRemoteDocumentChangeBufferTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1791F0D48AC0013853F /* FSTRemoteDocumentChangeBufferTests.m */; };
- DE51B1E81F0D490D0013853F /* FSTLevelDBKeyTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1641F0D48AC0013853F /* FSTLevelDBKeyTests.mm */; };
- DE51B1E91F0D490D0013853F /* FSTLevelDBMutationQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1661F0D48AC0013853F /* FSTLevelDBMutationQueueTests.mm */; };
- DE51B1EA1F0D490D0013853F /* FSTLevelDBRemoteDocumentCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1681F0D48AC0013853F /* FSTLevelDBRemoteDocumentCacheTests.mm */; };
- DE51B1EB1F0D490D0013853F /* FSTWriteGroupTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DE51B17A1F0D48AC0013853F /* FSTWriteGroupTests.mm */; };
- DE51B1EC1F0D49140013853F /* FSTDatabaseIDTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B17C1F0D48AC0013853F /* FSTDatabaseIDTests.m */; };
- DE51B1ED1F0D49140013853F /* FSTDocumentKeyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B17D1F0D48AC0013853F /* FSTDocumentKeyTests.m */; };
- DE51B1EE1F0D49140013853F /* FSTDocumentSetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B17E1F0D48AC0013853F /* FSTDocumentSetTests.m */; };
- DE51B1EF1F0D49140013853F /* FSTDocumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B17F1F0D48AC0013853F /* FSTDocumentTests.m */; };
- DE51B1F01F0D49140013853F /* FSTFieldValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1801F0D48AC0013853F /* FSTFieldValueTests.m */; };
- DE51B1F11F0D49140013853F /* FSTMutationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1811F0D48AC0013853F /* FSTMutationTests.m */; };
- DE51B1F21F0D49140013853F /* FSTPathTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1821F0D48AC0013853F /* FSTPathTests.m */; };
- DE51B1F31F0D491B0013853F /* FSTDatastoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B31F0D48AC0013853F /* FSTDatastoreTests.m */; };
- DE51B1F41F0D491B0013853F /* FSTRemoteEventTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B41F0D48AC0013853F /* FSTRemoteEventTests.m */; };
- DE51B1F61F0D491B0013853F /* FSTSerializerBetaTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B61F0D48AC0013853F /* FSTSerializerBetaTests.m */; };
- DE51B1F81F0D491F0013853F /* FSTWatchChange+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B91F0D48AC0013853F /* FSTWatchChange+Testing.m */; };
- DE51B1F91F0D491F0013853F /* FSTWatchChangeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1BA1F0D48AC0013853F /* FSTWatchChangeTests.m */; };
- DE51B1FA1F0D492C0013853F /* FSTLevelDBSpecTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1941F0D48AC0013853F /* FSTLevelDBSpecTests.m */; };
- DE51B1FB1F0D492C0013853F /* FSTMemorySpecTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1951F0D48AC0013853F /* FSTMemorySpecTests.m */; };
- DE51B1FC1F0D492C0013853F /* FSTMockDatastore.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1971F0D48AC0013853F /* FSTMockDatastore.m */; };
- DE51B1FD1F0D492C0013853F /* FSTSpecTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1991F0D48AC0013853F /* FSTSpecTests.m */; };
- DE51B1FE1F0D492C0013853F /* FSTSyncEngineTestDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B19B1F0D48AC0013853F /* FSTSyncEngineTestDriver.m */; };
- DE51B1FF1F0D493A0013853F /* FSTAssertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1861F0D48AC0013853F /* FSTAssertTests.m */; };
- DE51B2001F0D493A0013853F /* FSTComparisonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1871F0D48AC0013853F /* FSTComparisonTests.m */; };
- DE51B2011F0D493E0013853F /* FSTHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1891F0D48AC0013853F /* FSTHelpers.m */; };
F104BBD69BC3F0796E3A77C1 /* Pods_Firestore_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */; };
/* End PBXBuildFile section */
@@ -185,11 +205,95 @@
3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = "<group>"; };
42491D7DC8C8CD245CC22B93 /* Pods-SwiftBuildTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftBuildTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest.debug.xcconfig"; sourceTree = "<group>"; };
4EBC5F5ABE1FD097EFE5E224 /* Pods-Firestore_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.release.xcconfig"; sourceTree = "<group>"; };
+ 5436F32320008FAD006E51E3 /* string_printf_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_printf_test.cc; path = ../../core/test/firebase/firestore/util/string_printf_test.cc; sourceTree = "<group>"; };
54740A521FC913E500713A1A /* autoid_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = autoid_test.cc; path = ../../core/test/firebase/firestore/util/autoid_test.cc; sourceTree = "<group>"; };
54740A531FC913E500713A1A /* secure_random_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = secure_random_test.cc; path = ../../core/test/firebase/firestore/util/secure_random_test.cc; sourceTree = "<group>"; };
- 54764FAA1FAA0C320085E60A /* string_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_util_test.cc; path = ../../Port/string_util_test.cc; sourceTree = "<group>"; };
54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = FSTGoogleTestTests.mm; path = GoogleTest/FSTGoogleTestTests.mm; sourceTree = "<group>"; };
+ 548DB926200D590300E00ABC /* assert_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = assert_test.cc; path = ../../core/test/firebase/firestore/util/assert_test.cc; sourceTree = "<group>"; };
+ 548DB928200D59F600E00ABC /* comparison_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = comparison_test.cc; path = ../../core/test/firebase/firestore/util/comparison_test.cc; sourceTree = "<group>"; };
5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTIntegrationTestCase.mm; sourceTree = "<group>"; };
+ 5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBSpecTests.mm; sourceTree = "<group>"; };
+ 5492E02D20213FFC00B64F25 /* FSTMockDatastore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMockDatastore.mm; sourceTree = "<group>"; };
+ 5492E02E20213FFC00B64F25 /* FSTSyncEngineTestDriver.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTSyncEngineTestDriver.mm; sourceTree = "<group>"; };
+ 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMemorySpecTests.mm; sourceTree = "<group>"; };
+ 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTSpecTests.mm; sourceTree = "<group>"; };
+ 5492E0362021401E00B64F25 /* FSTTestDispatchQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTTestDispatchQueue.mm; sourceTree = "<group>"; };
+ 5492E0372021401E00B64F25 /* XCTestCase+Await.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "XCTestCase+Await.mm"; sourceTree = "<group>"; };
+ 5492E0382021401E00B64F25 /* FSTAssertTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTAssertTests.mm; sourceTree = "<group>"; };
+ 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTEventAccumulator.mm; sourceTree = "<group>"; };
+ 5492E03A2021401F00B64F25 /* FSTHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTHelpers.mm; sourceTree = "<group>"; };
+ 5492E045202154AA00B64F25 /* FIRCollectionReferenceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRCollectionReferenceTests.mm; sourceTree = "<group>"; };
+ 5492E046202154AA00B64F25 /* FIRQueryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRQueryTests.mm; sourceTree = "<group>"; };
+ 5492E047202154AA00B64F25 /* FSTAPIHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTAPIHelpers.h; sourceTree = "<group>"; };
+ 5492E048202154AA00B64F25 /* FIRGeoPointTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRGeoPointTests.mm; sourceTree = "<group>"; };
+ 5492E049202154AA00B64F25 /* FIRDocumentReferenceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRDocumentReferenceTests.mm; sourceTree = "<group>"; };
+ 5492E04A202154AA00B64F25 /* FIRFieldValueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRFieldValueTests.mm; sourceTree = "<group>"; };
+ 5492E04B202154AA00B64F25 /* FIRDocumentSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRDocumentSnapshotTests.mm; sourceTree = "<group>"; };
+ 5492E04C202154AA00B64F25 /* FIRFieldPathTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRFieldPathTests.mm; sourceTree = "<group>"; };
+ 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRSnapshotMetadataTests.mm; sourceTree = "<group>"; };
+ 5492E04E202154AA00B64F25 /* FSTAPIHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTAPIHelpers.mm; sourceTree = "<group>"; };
+ 5492E04F202154AA00B64F25 /* FIRQuerySnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRQuerySnapshotTests.mm; sourceTree = "<group>"; };
+ 5492E05A202154B800B64F25 /* FSTSyncEngine+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FSTSyncEngine+Testing.h"; sourceTree = "<group>"; };
+ 5492E05B202154B800B64F25 /* FSTTimestampTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTTimestampTests.mm; sourceTree = "<group>"; };
+ 5492E05C202154B800B64F25 /* FSTViewSnapshotTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTViewSnapshotTest.mm; sourceTree = "<group>"; };
+ 5492E05D202154B900B64F25 /* FSTQueryListenerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTQueryListenerTests.mm; sourceTree = "<group>"; };
+ 5492E05E202154B900B64F25 /* FSTViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTViewTests.mm; sourceTree = "<group>"; };
+ 5492E05F202154B900B64F25 /* FSTDatabaseInfoTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDatabaseInfoTests.mm; sourceTree = "<group>"; };
+ 5492E060202154B900B64F25 /* FSTEventManagerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTEventManagerTests.mm; sourceTree = "<group>"; };
+ 5492E061202154B900B64F25 /* FSTQueryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTQueryTests.mm; sourceTree = "<group>"; };
+ 5492E069202154D500B64F25 /* FIRQueryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRQueryTests.mm; sourceTree = "<group>"; };
+ 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRFieldsTests.mm; sourceTree = "<group>"; };
+ 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRListenerRegistrationTests.mm; sourceTree = "<group>"; };
+ 5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRDatabaseTests.mm; sourceTree = "<group>"; };
+ 5492E06D202154D600B64F25 /* FIRValidationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRValidationTests.mm; sourceTree = "<group>"; };
+ 5492E06E202154D600B64F25 /* FIRServerTimestampTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRServerTimestampTests.mm; sourceTree = "<group>"; };
+ 5492E06F202154D600B64F25 /* FIRWriteBatchTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRWriteBatchTests.mm; sourceTree = "<group>"; };
+ 5492E070202154D600B64F25 /* FIRCursorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRCursorTests.mm; sourceTree = "<group>"; };
+ 5492E071202154D600B64F25 /* FIRTypeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRTypeTests.mm; sourceTree = "<group>"; };
+ 5492E07B202154EB00B64F25 /* FSTTransactionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTTransactionTests.mm; sourceTree = "<group>"; };
+ 5492E07C202154EB00B64F25 /* FSTSmokeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTSmokeTests.mm; sourceTree = "<group>"; };
+ 5492E07D202154EB00B64F25 /* FSTStreamTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTStreamTests.mm; sourceTree = "<group>"; };
+ 5492E07E202154EC00B64F25 /* FSTDatastoreTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDatastoreTests.mm; sourceTree = "<group>"; };
+ 5492E0832021552A00B64F25 /* FSTLocalStoreTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLocalStoreTests.mm; sourceTree = "<group>"; };
+ 5492E0842021552A00B64F25 /* FSTEagerGarbageCollectorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTEagerGarbageCollectorTests.mm; sourceTree = "<group>"; };
+ 5492E0852021552A00B64F25 /* FSTRemoteDocumentCacheTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTRemoteDocumentCacheTests.h; sourceTree = "<group>"; };
+ 5492E0862021552A00B64F25 /* FSTLevelDBMigrationsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBMigrationsTests.mm; sourceTree = "<group>"; };
+ 5492E0872021552A00B64F25 /* FSTLevelDBMutationQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBMutationQueueTests.mm; sourceTree = "<group>"; };
+ 5492E0882021552A00B64F25 /* FSTMemoryLocalStoreTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMemoryLocalStoreTests.mm; sourceTree = "<group>"; };
+ 5492E0892021552A00B64F25 /* FSTQueryCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTQueryCacheTests.mm; sourceTree = "<group>"; };
+ 5492E08A2021552A00B64F25 /* FSTLocalSerializerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLocalSerializerTests.mm; sourceTree = "<group>"; };
+ 5492E08B2021552B00B64F25 /* FSTMemoryQueryCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMemoryQueryCacheTests.mm; sourceTree = "<group>"; };
+ 5492E08C2021552B00B64F25 /* FSTMemoryRemoteDocumentCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMemoryRemoteDocumentCacheTests.mm; sourceTree = "<group>"; };
+ 5492E08D2021552B00B64F25 /* FSTPersistenceTestHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTPersistenceTestHelpers.mm; sourceTree = "<group>"; };
+ 5492E08E2021552B00B64F25 /* FSTLevelDBKeyTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBKeyTests.mm; sourceTree = "<group>"; };
+ 5492E08F2021552B00B64F25 /* FSTLevelDBLocalStoreTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBLocalStoreTests.mm; sourceTree = "<group>"; };
+ 5492E0902021552B00B64F25 /* FSTRemoteDocumentChangeBufferTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteDocumentChangeBufferTests.mm; sourceTree = "<group>"; };
+ 5492E0912021552B00B64F25 /* FSTLocalStoreTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTLocalStoreTests.h; sourceTree = "<group>"; };
+ 5492E0922021552B00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBRemoteDocumentCacheTests.mm; sourceTree = "<group>"; };
+ 5492E0932021552B00B64F25 /* StringViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringViewTests.mm; sourceTree = "<group>"; };
+ 5492E0942021552C00B64F25 /* FSTMutationQueueTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTMutationQueueTests.h; sourceTree = "<group>"; };
+ 5492E0952021552C00B64F25 /* FSTQueryCacheTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTQueryCacheTests.h; sourceTree = "<group>"; };
+ 5492E0962021552C00B64F25 /* FSTMutationQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMutationQueueTests.mm; sourceTree = "<group>"; };
+ 5492E0972021552C00B64F25 /* FSTMemoryMutationQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMemoryMutationQueueTests.mm; sourceTree = "<group>"; };
+ 5492E0982021552C00B64F25 /* FSTLevelDBQueryCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBQueryCacheTests.mm; sourceTree = "<group>"; };
+ 5492E0992021552C00B64F25 /* FSTPersistenceTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTPersistenceTestHelpers.h; sourceTree = "<group>"; };
+ 5492E09A2021552C00B64F25 /* FSTReferenceSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTReferenceSetTests.mm; sourceTree = "<group>"; };
+ 5492E09B2021552C00B64F25 /* FSTWriteGroupTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWriteGroupTests.mm; sourceTree = "<group>"; };
+ 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteDocumentCacheTests.mm; sourceTree = "<group>"; };
+ 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentKeyTests.mm; sourceTree = "<group>"; };
+ 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentSetTests.mm; sourceTree = "<group>"; };
+ 5492E0B42021555100B64F25 /* FSTDatabaseIDTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDatabaseIDTests.mm; sourceTree = "<group>"; };
+ 5492E0B52021555100B64F25 /* FSTPathTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTPathTests.mm; sourceTree = "<group>"; };
+ 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentTests.mm; sourceTree = "<group>"; };
+ 5492E0B72021555100B64F25 /* FSTMutationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMutationTests.mm; sourceTree = "<group>"; };
+ 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTFieldValueTests.mm; sourceTree = "<group>"; };
+ 5492E0C02021557E00B64F25 /* FSTWatchChange+Testing.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "FSTWatchChange+Testing.mm"; sourceTree = "<group>"; };
+ 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTSerializerBetaTests.mm; sourceTree = "<group>"; };
+ 5492E0C22021557E00B64F25 /* FSTDatastoreTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDatastoreTests.mm; sourceTree = "<group>"; };
+ 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteEventTests.mm; sourceTree = "<group>"; };
+ 5492E0C42021557E00B64F25 /* FSTWatchChange+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FSTWatchChange+Testing.h"; sourceTree = "<group>"; };
+ 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWatchChangeTests.mm; sourceTree = "<group>"; };
+ 54C2294E1FECABAE007D065B /* log_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = log_test.cc; path = ../../core/test/firebase/firestore/util/log_test.cc; sourceTree = "<group>"; };
54DA129C1F315EE100DD57A1 /* collection_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = collection_spec_test.json; sourceTree = "<group>"; };
54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = existence_filter_spec_test.json; sourceTree = "<group>"; };
54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = limbo_spec_test.json; sourceTree = "<group>"; };
@@ -200,12 +304,10 @@
54DA12A31F315EE100DD57A1 /* persistence_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = persistence_spec_test.json; sourceTree = "<group>"; };
54DA12A41F315EE100DD57A1 /* resume_token_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = resume_token_spec_test.json; sourceTree = "<group>"; };
54DA12A51F315EE100DD57A1 /* write_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = write_spec_test.json; sourceTree = "<group>"; };
- 54DA12B01F315F3800DD57A1 /* FIRValidationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRValidationTests.m; sourceTree = "<group>"; };
54E9281C1F33950B00C1953E /* FSTEventAccumulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTEventAccumulator.h; sourceTree = "<group>"; };
- 54E9281D1F33950B00C1953E /* FSTEventAccumulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTEventAccumulator.m; sourceTree = "<group>"; };
54E9281E1F33950B00C1953E /* FSTIntegrationTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTIntegrationTestCase.h; sourceTree = "<group>"; };
54E9282A1F339CAD00C1953E /* XCTestCase+Await.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "XCTestCase+Await.h"; sourceTree = "<group>"; };
- 54E9282B1F339CAD00C1953E /* XCTestCase+Await.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "XCTestCase+Await.m"; sourceTree = "<group>"; };
+ 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = array_sorted_map_test.cc; path = ../../immutable/array_sorted_map_test.cc; sourceTree = "<group>"; };
6003F58A195388D20070C39A /* Firestore_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Firestore_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -222,7 +324,6 @@
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
- 61E1D8AF1FCF6AF500753285 /* StringViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringViewTests.mm; sourceTree = "<group>"; };
69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -230,12 +331,18 @@
8E002F4AD5D9B6197C940847 /* Firestore.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Firestore.podspec; path = ../Firestore.podspec; sourceTree = "<group>"; };
9D52E67EE96AA7E5D6F69748 /* Pods-Firestore_IntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests/Pods-Firestore_IntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
9EF477AD4B2B643FD320867A /* Pods-Firestore_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.debug.xcconfig"; sourceTree = "<group>"; };
+ AB356EF6200EA5EB0089B766 /* field_value_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = field_value_test.cc; sourceTree = "<group>"; };
+ AB380CF82019382300D97691 /* target_id_generator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = target_id_generator_test.cc; sourceTree = "<group>"; };
+ AB380CFC201A2EE200D97691 /* string_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_util_test.cc; path = ../../core/test/firebase/firestore/util/string_util_test.cc; sourceTree = "<group>"; };
+ AB380D01201BC69F00D97691 /* bits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bits_test.cc; path = ../../core/test/firebase/firestore/util/bits_test.cc; sourceTree = "<group>"; };
+ AB380D03201BC6E400D97691 /* ordered_code_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ordered_code_test.cc; path = ../../core/test/firebase/firestore/util/ordered_code_test.cc; sourceTree = "<group>"; };
+ AB71064B201FA60300344F18 /* database_id_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = database_id_test.cc; sourceTree = "<group>"; };
+ AB7BAB332012B519001E0872 /* geo_point_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = geo_point_test.cc; path = ../../core/test/firebase/firestore/geo_point_test.cc; sourceTree = "<group>"; };
+ ABF6506B201131F8005F2C74 /* timestamp_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = timestamp_test.cc; sourceTree = "<group>"; };
B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CE00BABB5A3AAB44A4C209E2 /* Pods-Firestore_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests/Pods-Firestore_Tests.debug.xcconfig"; sourceTree = "<group>"; };
D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
- D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTTestDispatchQueue.m; sourceTree = "<group>"; };
D5B259DAA9149B80D6245B57 /* FSTTestDispatchQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTTestDispatchQueue.h; sourceTree = "<group>"; };
- D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTStreamTests.m; sourceTree = "<group>"; };
DB17FEDFB80770611A935A60 /* Pods-Firestore_IntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests/Pods-Firestore_IntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
DE03B2E91F2149D600A30B9C /* Firestore_IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DE03B3621F215E1600A30B9C /* CAcert.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = CAcert.pem; sourceTree = "<group>"; };
@@ -248,77 +355,11 @@
DE2EF0821F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "FSTImmutableSortedSet+Testing.m"; path = "../../third_party/Immutable/Tests/FSTImmutableSortedSet+Testing.m"; sourceTree = "<group>"; };
DE2EF0831F3D0B6E003D0CDC /* FSTLLRBValueNode+Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "FSTLLRBValueNode+Test.h"; path = "../../third_party/Immutable/Tests/FSTLLRBValueNode+Test.h"; sourceTree = "<group>"; };
DE2EF0841F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FSTTreeSortedDictionaryTests.m; path = ../../third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m; sourceTree = "<group>"; };
- DE51B1631F0D48AC0013853F /* FSTEagerGarbageCollectorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTEagerGarbageCollectorTests.m; sourceTree = "<group>"; };
- DE51B1641F0D48AC0013853F /* FSTLevelDBKeyTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBKeyTests.mm; sourceTree = "<group>"; };
- DE51B1651F0D48AC0013853F /* FSTLevelDBLocalStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTLevelDBLocalStoreTests.m; sourceTree = "<group>"; };
- DE51B1661F0D48AC0013853F /* FSTLevelDBMutationQueueTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBMutationQueueTests.mm; sourceTree = "<group>"; };
- DE51B1671F0D48AC0013853F /* FSTLevelDBQueryCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTLevelDBQueryCacheTests.m; sourceTree = "<group>"; };
- DE51B1681F0D48AC0013853F /* FSTLevelDBRemoteDocumentCacheTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBRemoteDocumentCacheTests.mm; sourceTree = "<group>"; };
- DE51B1691F0D48AC0013853F /* FSTLocalSerializerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTLocalSerializerTests.m; sourceTree = "<group>"; };
- DE51B16A1F0D48AC0013853F /* FSTLocalStoreTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTLocalStoreTests.h; sourceTree = "<group>"; };
- DE51B16B1F0D48AC0013853F /* FSTLocalStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTLocalStoreTests.m; sourceTree = "<group>"; };
- DE51B16C1F0D48AC0013853F /* FSTMemoryLocalStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMemoryLocalStoreTests.m; sourceTree = "<group>"; };
- DE51B16D1F0D48AC0013853F /* FSTMemoryMutationQueueTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMemoryMutationQueueTests.m; sourceTree = "<group>"; };
- DE51B16E1F0D48AC0013853F /* FSTMemoryQueryCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMemoryQueryCacheTests.m; sourceTree = "<group>"; };
- DE51B16F1F0D48AC0013853F /* FSTMemoryRemoteDocumentCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMemoryRemoteDocumentCacheTests.m; sourceTree = "<group>"; };
- DE51B1701F0D48AC0013853F /* FSTMutationQueueTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTMutationQueueTests.h; sourceTree = "<group>"; };
- DE51B1711F0D48AC0013853F /* FSTMutationQueueTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMutationQueueTests.m; sourceTree = "<group>"; };
- DE51B1721F0D48AC0013853F /* FSTPersistenceTestHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTPersistenceTestHelpers.h; sourceTree = "<group>"; };
- DE51B1731F0D48AC0013853F /* FSTPersistenceTestHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTPersistenceTestHelpers.m; sourceTree = "<group>"; };
- DE51B1741F0D48AC0013853F /* FSTQueryCacheTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTQueryCacheTests.h; sourceTree = "<group>"; };
- DE51B1751F0D48AC0013853F /* FSTQueryCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTQueryCacheTests.m; sourceTree = "<group>"; };
- DE51B1761F0D48AC0013853F /* FSTReferenceSetTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTReferenceSetTests.m; sourceTree = "<group>"; };
- DE51B1771F0D48AC0013853F /* FSTRemoteDocumentCacheTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTRemoteDocumentCacheTests.h; sourceTree = "<group>"; };
- DE51B1781F0D48AC0013853F /* FSTRemoteDocumentCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTRemoteDocumentCacheTests.m; sourceTree = "<group>"; };
- DE51B1791F0D48AC0013853F /* FSTRemoteDocumentChangeBufferTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTRemoteDocumentChangeBufferTests.m; sourceTree = "<group>"; };
- DE51B17A1F0D48AC0013853F /* FSTWriteGroupTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWriteGroupTests.mm; sourceTree = "<group>"; };
- DE51B17C1F0D48AC0013853F /* FSTDatabaseIDTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDatabaseIDTests.m; sourceTree = "<group>"; };
- DE51B17D1F0D48AC0013853F /* FSTDocumentKeyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDocumentKeyTests.m; sourceTree = "<group>"; };
- DE51B17E1F0D48AC0013853F /* FSTDocumentSetTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDocumentSetTests.m; sourceTree = "<group>"; };
- DE51B17F1F0D48AC0013853F /* FSTDocumentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDocumentTests.m; sourceTree = "<group>"; };
- DE51B1801F0D48AC0013853F /* FSTFieldValueTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTFieldValueTests.m; sourceTree = "<group>"; };
- DE51B1811F0D48AC0013853F /* FSTMutationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMutationTests.m; sourceTree = "<group>"; };
- DE51B1821F0D48AC0013853F /* FSTPathTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTPathTests.m; sourceTree = "<group>"; };
- DE51B1841F0D48AC0013853F /* FIRGeoPointTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRGeoPointTests.m; sourceTree = "<group>"; };
- DE51B1861F0D48AC0013853F /* FSTAssertTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTAssertTests.m; sourceTree = "<group>"; };
- DE51B1871F0D48AC0013853F /* FSTComparisonTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTComparisonTests.m; sourceTree = "<group>"; };
DE51B1881F0D48AC0013853F /* FSTHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTHelpers.h; sourceTree = "<group>"; };
- DE51B1891F0D48AC0013853F /* FSTHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTHelpers.m; sourceTree = "<group>"; };
- DE51B1941F0D48AC0013853F /* FSTLevelDBSpecTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTLevelDBSpecTests.m; sourceTree = "<group>"; };
- DE51B1951F0D48AC0013853F /* FSTMemorySpecTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMemorySpecTests.m; sourceTree = "<group>"; };
DE51B1961F0D48AC0013853F /* FSTMockDatastore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTMockDatastore.h; sourceTree = "<group>"; };
- DE51B1971F0D48AC0013853F /* FSTMockDatastore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTMockDatastore.m; sourceTree = "<group>"; };
DE51B1981F0D48AC0013853F /* FSTSpecTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTSpecTests.h; sourceTree = "<group>"; };
- DE51B1991F0D48AC0013853F /* FSTSpecTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTSpecTests.m; sourceTree = "<group>"; };
DE51B19A1F0D48AC0013853F /* FSTSyncEngineTestDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTSyncEngineTestDriver.h; sourceTree = "<group>"; };
- DE51B19B1F0D48AC0013853F /* FSTSyncEngineTestDriver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTSyncEngineTestDriver.m; sourceTree = "<group>"; };
DE51B1A71F0D48AC0013853F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
- DE51B1A91F0D48AC0013853F /* FSTDatabaseInfoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDatabaseInfoTests.m; sourceTree = "<group>"; };
- DE51B1AA1F0D48AC0013853F /* FSTEventManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTEventManagerTests.m; sourceTree = "<group>"; };
- DE51B1AB1F0D48AC0013853F /* FSTQueryListenerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTQueryListenerTests.m; sourceTree = "<group>"; };
- DE51B1AC1F0D48AC0013853F /* FSTQueryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTQueryTests.m; sourceTree = "<group>"; };
- DE51B1AD1F0D48AC0013853F /* FSTSyncEngine+Testing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FSTSyncEngine+Testing.h"; sourceTree = "<group>"; };
- DE51B1AE1F0D48AC0013853F /* FSTTargetIDGeneratorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTTargetIDGeneratorTests.m; sourceTree = "<group>"; };
- DE51B1AF1F0D48AC0013853F /* FSTTimestampTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTTimestampTests.m; sourceTree = "<group>"; };
- DE51B1B01F0D48AC0013853F /* FSTViewSnapshotTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTViewSnapshotTest.m; sourceTree = "<group>"; };
- DE51B1B11F0D48AC0013853F /* FSTViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTViewTests.m; sourceTree = "<group>"; };
- DE51B1B31F0D48AC0013853F /* FSTDatastoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDatastoreTests.m; sourceTree = "<group>"; };
- DE51B1B41F0D48AC0013853F /* FSTRemoteEventTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTRemoteEventTests.m; sourceTree = "<group>"; };
- DE51B1B61F0D48AC0013853F /* FSTSerializerBetaTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTSerializerBetaTests.m; sourceTree = "<group>"; };
- DE51B1B81F0D48AC0013853F /* FSTWatchChange+Testing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FSTWatchChange+Testing.h"; sourceTree = "<group>"; };
- DE51B1B91F0D48AC0013853F /* FSTWatchChange+Testing.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "FSTWatchChange+Testing.m"; sourceTree = "<group>"; };
- DE51B1BA1F0D48AC0013853F /* FSTWatchChangeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTWatchChangeTests.m; sourceTree = "<group>"; };
- DE51B1BD1F0D48AC0013853F /* FIRCursorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRCursorTests.m; sourceTree = "<group>"; };
- DE51B1BE1F0D48AC0013853F /* FIRDatabaseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRDatabaseTests.m; sourceTree = "<group>"; };
- DE51B1BF1F0D48AC0013853F /* FIRFieldsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRFieldsTests.m; sourceTree = "<group>"; };
- DE51B1C01F0D48AC0013853F /* FIRListenerRegistrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRListenerRegistrationTests.m; sourceTree = "<group>"; };
- DE51B1C11F0D48AC0013853F /* FIRQueryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRQueryTests.m; sourceTree = "<group>"; };
- DE51B1C21F0D48AC0013853F /* FIRServerTimestampTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRServerTimestampTests.m; sourceTree = "<group>"; };
- DE51B1C31F0D48AC0013853F /* FIRTypeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRTypeTests.m; sourceTree = "<group>"; };
- DE51B1C41F0D48AC0013853F /* FSTDatastoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDatastoreTests.m; sourceTree = "<group>"; };
- DE51B1C51F0D48AC0013853F /* FSTSmokeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTSmokeTests.m; sourceTree = "<group>"; };
- DE51B1C61F0D48AC0013853F /* FSTTransactionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTTransactionTests.m; sourceTree = "<group>"; };
- DEFE0F471F1F960A0071599A /* FIRWriteBatchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRWriteBatchTests.m; sourceTree = "<group>"; };
F23325524BEAF8D24F78AC88 /* Pods-SwiftBuildTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftBuildTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -371,8 +412,15 @@
54740A561FC913EB00713A1A /* util */ = {
isa = PBXGroup;
children = (
+ 548DB926200D590300E00ABC /* assert_test.cc */,
54740A521FC913E500713A1A /* autoid_test.cc */,
+ AB380D01201BC69F00D97691 /* bits_test.cc */,
+ 548DB928200D59F600E00ABC /* comparison_test.cc */,
+ 54C2294E1FECABAE007D065B /* log_test.cc */,
+ AB380D03201BC6E400D97691 /* ordered_code_test.cc */,
54740A531FC913E500713A1A /* secure_random_test.cc */,
+ 5436F32320008FAD006E51E3 /* string_printf_test.cc */,
+ AB380CFC201A2EE200D97691 /* string_util_test.cc */,
);
name = util;
sourceTree = "<group>";
@@ -380,19 +428,23 @@
54764FAC1FAA0C390085E60A /* GoogleTests */ = {
isa = PBXGroup;
children = (
- 54764FAD1FAA0C650085E60A /* Port */,
+ AB380CF7201937B800D97691 /* core */,
+ 54EB764B202277970088B8F3 /* immutable */,
+ AB356EF5200E9D1A0089B766 /* model */,
54740A561FC913EB00713A1A /* util */,
54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */,
+ AB7BAB332012B519001E0872 /* geo_point_test.cc */,
);
name = GoogleTests;
sourceTree = "<group>";
};
- 54764FAD1FAA0C650085E60A /* Port */ = {
+ 54EB764B202277970088B8F3 /* immutable */ = {
isa = PBXGroup;
children = (
- 54764FAA1FAA0C320085E60A /* string_util_test.cc */,
+ 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */,
);
- name = Port;
+ name = immutable;
+ path = ../../core/test/firebase/firestore/core/immutable;
sourceTree = "<group>";
};
6003F581195388D10070C39A = {
@@ -512,6 +564,26 @@
name = Pods;
sourceTree = "<group>";
};
+ AB356EF5200E9D1A0089B766 /* model */ = {
+ isa = PBXGroup;
+ children = (
+ AB71064B201FA60300344F18 /* database_id_test.cc */,
+ AB356EF6200EA5EB0089B766 /* field_value_test.cc */,
+ ABF6506B201131F8005F2C74 /* timestamp_test.cc */,
+ );
+ name = model;
+ path = ../../core/test/firebase/firestore/model;
+ sourceTree = "<group>";
+ };
+ AB380CF7201937B800D97691 /* core */ = {
+ isa = PBXGroup;
+ children = (
+ AB380CF82019382300D97691 /* target_id_generator_test.cc */,
+ );
+ name = core;
+ path = ../../core/test/firebase/firestore/core;
+ sourceTree = "<group>";
+ };
DE0761E51F2FE611003233AF /* SwiftBuildTest */ = {
isa = PBXGroup;
children = (
@@ -537,31 +609,32 @@
DE51B1621F0D48AC0013853F /* Local */ = {
isa = PBXGroup;
children = (
- 61E1D8AF1FCF6AF500753285 /* StringViewTests.mm */,
- DE51B16A1F0D48AC0013853F /* FSTLocalStoreTests.h */,
- DE51B1701F0D48AC0013853F /* FSTMutationQueueTests.h */,
- DE51B1721F0D48AC0013853F /* FSTPersistenceTestHelpers.h */,
- DE51B1741F0D48AC0013853F /* FSTQueryCacheTests.h */,
- DE51B1771F0D48AC0013853F /* FSTRemoteDocumentCacheTests.h */,
- DE51B1631F0D48AC0013853F /* FSTEagerGarbageCollectorTests.m */,
- DE51B1651F0D48AC0013853F /* FSTLevelDBLocalStoreTests.m */,
- DE51B1671F0D48AC0013853F /* FSTLevelDBQueryCacheTests.m */,
- DE51B1691F0D48AC0013853F /* FSTLocalSerializerTests.m */,
- DE51B16B1F0D48AC0013853F /* FSTLocalStoreTests.m */,
- DE51B16C1F0D48AC0013853F /* FSTMemoryLocalStoreTests.m */,
- DE51B16D1F0D48AC0013853F /* FSTMemoryMutationQueueTests.m */,
- DE51B16E1F0D48AC0013853F /* FSTMemoryQueryCacheTests.m */,
- DE51B16F1F0D48AC0013853F /* FSTMemoryRemoteDocumentCacheTests.m */,
- DE51B1711F0D48AC0013853F /* FSTMutationQueueTests.m */,
- DE51B1731F0D48AC0013853F /* FSTPersistenceTestHelpers.m */,
- DE51B1751F0D48AC0013853F /* FSTQueryCacheTests.m */,
- DE51B1761F0D48AC0013853F /* FSTReferenceSetTests.m */,
- DE51B1781F0D48AC0013853F /* FSTRemoteDocumentCacheTests.m */,
- DE51B1791F0D48AC0013853F /* FSTRemoteDocumentChangeBufferTests.m */,
- DE51B1641F0D48AC0013853F /* FSTLevelDBKeyTests.mm */,
- DE51B1661F0D48AC0013853F /* FSTLevelDBMutationQueueTests.mm */,
- DE51B1681F0D48AC0013853F /* FSTLevelDBRemoteDocumentCacheTests.mm */,
- DE51B17A1F0D48AC0013853F /* FSTWriteGroupTests.mm */,
+ 5492E0842021552A00B64F25 /* FSTEagerGarbageCollectorTests.mm */,
+ 5492E08E2021552B00B64F25 /* FSTLevelDBKeyTests.mm */,
+ 5492E08F2021552B00B64F25 /* FSTLevelDBLocalStoreTests.mm */,
+ 5492E0862021552A00B64F25 /* FSTLevelDBMigrationsTests.mm */,
+ 5492E0872021552A00B64F25 /* FSTLevelDBMutationQueueTests.mm */,
+ 5492E0982021552C00B64F25 /* FSTLevelDBQueryCacheTests.mm */,
+ 5492E0922021552B00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm */,
+ 5492E08A2021552A00B64F25 /* FSTLocalSerializerTests.mm */,
+ 5492E0912021552B00B64F25 /* FSTLocalStoreTests.h */,
+ 5492E0832021552A00B64F25 /* FSTLocalStoreTests.mm */,
+ 5492E0882021552A00B64F25 /* FSTMemoryLocalStoreTests.mm */,
+ 5492E0972021552C00B64F25 /* FSTMemoryMutationQueueTests.mm */,
+ 5492E08B2021552B00B64F25 /* FSTMemoryQueryCacheTests.mm */,
+ 5492E08C2021552B00B64F25 /* FSTMemoryRemoteDocumentCacheTests.mm */,
+ 5492E0942021552C00B64F25 /* FSTMutationQueueTests.h */,
+ 5492E0962021552C00B64F25 /* FSTMutationQueueTests.mm */,
+ 5492E0992021552C00B64F25 /* FSTPersistenceTestHelpers.h */,
+ 5492E08D2021552B00B64F25 /* FSTPersistenceTestHelpers.mm */,
+ 5492E0952021552C00B64F25 /* FSTQueryCacheTests.h */,
+ 5492E0892021552A00B64F25 /* FSTQueryCacheTests.mm */,
+ 5492E09A2021552C00B64F25 /* FSTReferenceSetTests.mm */,
+ 5492E0852021552A00B64F25 /* FSTRemoteDocumentCacheTests.h */,
+ 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */,
+ 5492E0902021552B00B64F25 /* FSTRemoteDocumentChangeBufferTests.mm */,
+ 5492E09B2021552C00B64F25 /* FSTWriteGroupTests.mm */,
+ 5492E0932021552B00B64F25 /* StringViewTests.mm */,
);
path = Local;
sourceTree = "<group>";
@@ -569,13 +642,13 @@
DE51B17B1F0D48AC0013853F /* Model */ = {
isa = PBXGroup;
children = (
- DE51B17C1F0D48AC0013853F /* FSTDatabaseIDTests.m */,
- DE51B17D1F0D48AC0013853F /* FSTDocumentKeyTests.m */,
- DE51B17E1F0D48AC0013853F /* FSTDocumentSetTests.m */,
- DE51B17F1F0D48AC0013853F /* FSTDocumentTests.m */,
- DE51B1801F0D48AC0013853F /* FSTFieldValueTests.m */,
- DE51B1811F0D48AC0013853F /* FSTMutationTests.m */,
- DE51B1821F0D48AC0013853F /* FSTPathTests.m */,
+ 5492E0B42021555100B64F25 /* FSTDatabaseIDTests.mm */,
+ 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */,
+ 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */,
+ 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */,
+ 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */,
+ 5492E0B72021555100B64F25 /* FSTMutationTests.mm */,
+ 5492E0B52021555100B64F25 /* FSTPathTests.mm */,
);
path = Model;
sourceTree = "<group>";
@@ -583,7 +656,17 @@
DE51B1831F0D48AC0013853F /* API */ = {
isa = PBXGroup;
children = (
- DE51B1841F0D48AC0013853F /* FIRGeoPointTests.m */,
+ 5492E045202154AA00B64F25 /* FIRCollectionReferenceTests.mm */,
+ 5492E049202154AA00B64F25 /* FIRDocumentReferenceTests.mm */,
+ 5492E04B202154AA00B64F25 /* FIRDocumentSnapshotTests.mm */,
+ 5492E04C202154AA00B64F25 /* FIRFieldPathTests.mm */,
+ 5492E04A202154AA00B64F25 /* FIRFieldValueTests.mm */,
+ 5492E048202154AA00B64F25 /* FIRGeoPointTests.mm */,
+ 5492E04F202154AA00B64F25 /* FIRQuerySnapshotTests.mm */,
+ 5492E046202154AA00B64F25 /* FIRQueryTests.mm */,
+ 5492E04D202154AA00B64F25 /* FIRSnapshotMetadataTests.mm */,
+ 5492E047202154AA00B64F25 /* FSTAPIHelpers.h */,
+ 5492E04E202154AA00B64F25 /* FSTAPIHelpers.mm */,
);
path = API;
sourceTree = "<group>";
@@ -591,18 +674,17 @@
DE51B1851F0D48AC0013853F /* Util */ = {
isa = PBXGroup;
children = (
+ 5492E0382021401E00B64F25 /* FSTAssertTests.mm */,
54E9281C1F33950B00C1953E /* FSTEventAccumulator.h */,
- 54E9281D1F33950B00C1953E /* FSTEventAccumulator.m */,
+ 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */,
+ DE51B1881F0D48AC0013853F /* FSTHelpers.h */,
+ 5492E03A2021401F00B64F25 /* FSTHelpers.mm */,
54E9281E1F33950B00C1953E /* FSTIntegrationTestCase.h */,
5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */,
- DE51B1861F0D48AC0013853F /* FSTAssertTests.m */,
- DE51B1871F0D48AC0013853F /* FSTComparisonTests.m */,
- DE51B1881F0D48AC0013853F /* FSTHelpers.h */,
- DE51B1891F0D48AC0013853F /* FSTHelpers.m */,
- 54E9282A1F339CAD00C1953E /* XCTestCase+Await.h */,
- 54E9282B1F339CAD00C1953E /* XCTestCase+Await.m */,
D5B259DAA9149B80D6245B57 /* FSTTestDispatchQueue.h */,
- D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */,
+ 5492E0362021401E00B64F25 /* FSTTestDispatchQueue.mm */,
+ 54E9282A1F339CAD00C1953E /* XCTestCase+Await.h */,
+ 5492E0372021401E00B64F25 /* XCTestCase+Await.mm */,
);
path = Util;
sourceTree = "<group>";
@@ -610,14 +692,14 @@
DE51B1931F0D48AC0013853F /* SpecTests */ = {
isa = PBXGroup;
children = (
+ 5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */,
+ 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */,
DE51B1961F0D48AC0013853F /* FSTMockDatastore.h */,
+ 5492E02D20213FFC00B64F25 /* FSTMockDatastore.mm */,
DE51B1981F0D48AC0013853F /* FSTSpecTests.h */,
+ 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */,
DE51B19A1F0D48AC0013853F /* FSTSyncEngineTestDriver.h */,
- DE51B1941F0D48AC0013853F /* FSTLevelDBSpecTests.m */,
- DE51B1951F0D48AC0013853F /* FSTMemorySpecTests.m */,
- DE51B1971F0D48AC0013853F /* FSTMockDatastore.m */,
- DE51B1991F0D48AC0013853F /* FSTSpecTests.m */,
- DE51B19B1F0D48AC0013853F /* FSTSyncEngineTestDriver.m */,
+ 5492E02E20213FFC00B64F25 /* FSTSyncEngineTestDriver.mm */,
DE51B19C1F0D48AC0013853F /* json */,
);
path = SpecTests;
@@ -645,15 +727,14 @@
DE51B1A81F0D48AC0013853F /* Core */ = {
isa = PBXGroup;
children = (
- DE51B1AD1F0D48AC0013853F /* FSTSyncEngine+Testing.h */,
- DE51B1A91F0D48AC0013853F /* FSTDatabaseInfoTests.m */,
- DE51B1AA1F0D48AC0013853F /* FSTEventManagerTests.m */,
- DE51B1AB1F0D48AC0013853F /* FSTQueryListenerTests.m */,
- DE51B1AC1F0D48AC0013853F /* FSTQueryTests.m */,
- DE51B1AE1F0D48AC0013853F /* FSTTargetIDGeneratorTests.m */,
- DE51B1AF1F0D48AC0013853F /* FSTTimestampTests.m */,
- DE51B1B01F0D48AC0013853F /* FSTViewSnapshotTest.m */,
- DE51B1B11F0D48AC0013853F /* FSTViewTests.m */,
+ 5492E05F202154B900B64F25 /* FSTDatabaseInfoTests.mm */,
+ 5492E060202154B900B64F25 /* FSTEventManagerTests.mm */,
+ 5492E05D202154B900B64F25 /* FSTQueryListenerTests.mm */,
+ 5492E061202154B900B64F25 /* FSTQueryTests.mm */,
+ 5492E05A202154B800B64F25 /* FSTSyncEngine+Testing.h */,
+ 5492E05B202154B800B64F25 /* FSTTimestampTests.mm */,
+ 5492E05C202154B800B64F25 /* FSTViewSnapshotTest.mm */,
+ 5492E05E202154B900B64F25 /* FSTViewTests.mm */,
);
path = Core;
sourceTree = "<group>";
@@ -661,12 +742,12 @@
DE51B1B21F0D48AC0013853F /* Remote */ = {
isa = PBXGroup;
children = (
- DE51B1B31F0D48AC0013853F /* FSTDatastoreTests.m */,
- DE51B1B41F0D48AC0013853F /* FSTRemoteEventTests.m */,
- DE51B1B61F0D48AC0013853F /* FSTSerializerBetaTests.m */,
- DE51B1B81F0D48AC0013853F /* FSTWatchChange+Testing.h */,
- DE51B1B91F0D48AC0013853F /* FSTWatchChange+Testing.m */,
- DE51B1BA1F0D48AC0013853F /* FSTWatchChangeTests.m */,
+ 5492E0C22021557E00B64F25 /* FSTDatastoreTests.mm */,
+ 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */,
+ 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */,
+ 5492E0C42021557E00B64F25 /* FSTWatchChange+Testing.h */,
+ 5492E0C02021557E00B64F25 /* FSTWatchChange+Testing.mm */,
+ 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */,
);
path = Remote;
sourceTree = "<group>";
@@ -674,13 +755,12 @@
DE51B1BB1F0D48AC0013853F /* Integration */ = {
isa = PBXGroup;
children = (
- DE03B3621F215E1600A30B9C /* CAcert.pem */,
DE51B1BC1F0D48AC0013853F /* API */,
- DE51B1C41F0D48AC0013853F /* FSTDatastoreTests.m */,
- DE51B1C51F0D48AC0013853F /* FSTSmokeTests.m */,
- DE51B1C61F0D48AC0013853F /* FSTTransactionTests.m */,
- DE51B1C71F0D48AC0013853F /* Util */,
- D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */,
+ DE03B3621F215E1600A30B9C /* CAcert.pem */,
+ 5492E07E202154EC00B64F25 /* FSTDatastoreTests.mm */,
+ 5492E07C202154EB00B64F25 /* FSTSmokeTests.mm */,
+ 5492E07D202154EB00B64F25 /* FSTStreamTests.mm */,
+ 5492E07B202154EB00B64F25 /* FSTTransactionTests.mm */,
);
path = Integration;
sourceTree = "<group>";
@@ -688,26 +768,19 @@
DE51B1BC1F0D48AC0013853F /* API */ = {
isa = PBXGroup;
children = (
- DE51B1BD1F0D48AC0013853F /* FIRCursorTests.m */,
- DE51B1BE1F0D48AC0013853F /* FIRDatabaseTests.m */,
- DE51B1BF1F0D48AC0013853F /* FIRFieldsTests.m */,
- DE51B1C01F0D48AC0013853F /* FIRListenerRegistrationTests.m */,
- DE51B1C11F0D48AC0013853F /* FIRQueryTests.m */,
- DE51B1C21F0D48AC0013853F /* FIRServerTimestampTests.m */,
- DE51B1C31F0D48AC0013853F /* FIRTypeTests.m */,
- 54DA12B01F315F3800DD57A1 /* FIRValidationTests.m */,
- DEFE0F471F1F960A0071599A /* FIRWriteBatchTests.m */,
+ 5492E070202154D600B64F25 /* FIRCursorTests.mm */,
+ 5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */,
+ 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */,
+ 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */,
+ 5492E069202154D500B64F25 /* FIRQueryTests.mm */,
+ 5492E06E202154D600B64F25 /* FIRServerTimestampTests.mm */,
+ 5492E071202154D600B64F25 /* FIRTypeTests.mm */,
+ 5492E06D202154D600B64F25 /* FIRValidationTests.mm */,
+ 5492E06F202154D600B64F25 /* FIRWriteBatchTests.mm */,
);
path = API;
sourceTree = "<group>";
};
- DE51B1C71F0D48AC0013853F /* Util */ = {
- isa = PBXGroup;
- children = (
- );
- path = Util;
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -917,8 +990,7 @@
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-f0850809/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac-Defines-NSData+zlib/GoogleToolboxForMac.framework",
"${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
"${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
"${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
@@ -930,7 +1002,6 @@
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
@@ -1160,66 +1231,86 @@
buildActionMask = 2147483647;
files = (
DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */,
- DE51B1FD1F0D492C0013853F /* FSTSpecTests.m in Sources */,
- DE51B2001F0D493A0013853F /* FSTComparisonTests.m in Sources */,
- DE51B1CC1F0D48C00013853F /* FIRGeoPointTests.m in Sources */,
- DE51B1E11F0D490D0013853F /* FSTMemoryRemoteDocumentCacheTests.m in Sources */,
- DE51B1FF1F0D493A0013853F /* FSTAssertTests.m in Sources */,
- DE51B1D31F0D48CD0013853F /* FSTViewSnapshotTest.m in Sources */,
- DE51B1F91F0D491F0013853F /* FSTWatchChangeTests.m in Sources */,
- DE51B1F81F0D491F0013853F /* FSTWatchChange+Testing.m in Sources */,
- DE51B1EB1F0D490D0013853F /* FSTWriteGroupTests.mm in Sources */,
- DE51B2011F0D493E0013853F /* FSTHelpers.m in Sources */,
- DE51B1F61F0D491B0013853F /* FSTSerializerBetaTests.m in Sources */,
- DE51B1F01F0D49140013853F /* FSTFieldValueTests.m in Sources */,
+ ABE6637A201FA81900ED349A /* database_id_test.cc in Sources */,
+ 5492E0AF2021552D00B64F25 /* FSTReferenceSetTests.mm in Sources */,
+ 5492E09E2021552D00B64F25 /* FSTEagerGarbageCollectorTests.mm in Sources */,
+ 5492E0C62021557E00B64F25 /* FSTWatchChange+Testing.mm in Sources */,
+ 5492E064202154B900B64F25 /* FSTQueryListenerTests.mm in Sources */,
+ 5492E03320213FFC00B64F25 /* FSTSyncEngineTestDriver.mm in Sources */,
+ AB380CFE201A2F4500D97691 /* string_util_test.cc in Sources */,
+ 5492E0A42021552D00B64F25 /* FSTMemoryQueryCacheTests.mm in Sources */,
+ 5492E0A92021552D00B64F25 /* FSTRemoteDocumentChangeBufferTests.mm in Sources */,
+ 54C2294F1FECABAE007D065B /* log_test.cc in Sources */,
+ 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */,
+ 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */,
+ 5492E0BC2021555100B64F25 /* FSTPathTests.mm in Sources */,
+ 5492E0B02021552D00B64F25 /* FSTWriteGroupTests.mm in Sources */,
+ 5492E058202154AB00B64F25 /* FSTAPIHelpers.mm in Sources */,
+ AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */,
+ 5492E0A82021552D00B64F25 /* FSTLevelDBLocalStoreTests.mm in Sources */,
5491BC721FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */,
DE2EF0861F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m in Sources */,
- DE51B1DE1F0D490D0013853F /* FSTMemoryLocalStoreTests.m in Sources */,
- DE51B1EC1F0D49140013853F /* FSTDatabaseIDTests.m in Sources */,
- DE51B1ED1F0D49140013853F /* FSTDocumentKeyTests.m in Sources */,
- DE51B1D41F0D48CD0013853F /* FSTViewTests.m in Sources */,
+ 5492E03120213FFC00B64F25 /* FSTLevelDBSpecTests.mm in Sources */,
+ 5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */,
+ 5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */,
54740A581FC914F000713A1A /* autoid_test.cc in Sources */,
- DE51B1F41F0D491B0013853F /* FSTRemoteEventTests.m in Sources */,
- 54E928241F33953300C1953E /* FSTEventAccumulator.m in Sources */,
- DE51B1D11F0D48CD0013853F /* FSTTargetIDGeneratorTests.m in Sources */,
- DE51B1EF1F0D49140013853F /* FSTDocumentTests.m in Sources */,
- DE51B1DC1F0D490D0013853F /* FSTLocalSerializerTests.m in Sources */,
- DE51B1E71F0D490D0013853F /* FSTRemoteDocumentChangeBufferTests.m in Sources */,
- DE51B1E51F0D490D0013853F /* FSTReferenceSetTests.m in Sources */,
- DE51B1EA1F0D490D0013853F /* FSTLevelDBRemoteDocumentCacheTests.mm in Sources */,
- DE51B1D21F0D48CD0013853F /* FSTTimestampTests.m in Sources */,
- DE51B1EE1F0D49140013853F /* FSTDocumentSetTests.m in Sources */,
+ 548DB927200D590300E00ABC /* assert_test.cc in Sources */,
+ 5492E0A62021552D00B64F25 /* FSTPersistenceTestHelpers.mm in Sources */,
+ 5492E066202154B900B64F25 /* FSTDatabaseInfoTests.mm in Sources */,
+ 5492E0A12021552D00B64F25 /* FSTMemoryLocalStoreTests.mm in Sources */,
+ 5436F32420008FAD006E51E3 /* string_printf_test.cc in Sources */,
+ 5492E067202154B900B64F25 /* FSTEventManagerTests.mm in Sources */,
+ 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */,
+ 5492E055202154AB00B64F25 /* FIRDocumentSnapshotTests.mm in Sources */,
+ 5492E03E2021401F00B64F25 /* FSTEventAccumulator.mm in Sources */,
DE2EF0851F3D0B6E003D0CDC /* FSTArraySortedDictionaryTests.m in Sources */,
- DE51B1F11F0D49140013853F /* FSTMutationTests.m in Sources */,
- DE51B1FB1F0D492C0013853F /* FSTMemorySpecTests.m in Sources */,
- DE51B1DB1F0D490D0013853F /* FSTLevelDBQueryCacheTests.m in Sources */,
- 54764FAB1FAA0C320085E60A /* string_util_test.cc in Sources */,
- 54E9282C1F339CAD00C1953E /* XCTestCase+Await.m in Sources */,
- DE51B1DF1F0D490D0013853F /* FSTMemoryMutationQueueTests.m in Sources */,
- DE51B1F31F0D491B0013853F /* FSTDatastoreTests.m in Sources */,
- DE51B1D01F0D48CD0013853F /* FSTQueryTests.m in Sources */,
+ 5492E0AA2021552D00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm in Sources */,
+ 5492E0AC2021552D00B64F25 /* FSTMutationQueueTests.mm in Sources */,
+ 5492E056202154AB00B64F25 /* FIRFieldPathTests.mm in Sources */,
+ 5492E03220213FFC00B64F25 /* FSTMockDatastore.mm in Sources */,
+ AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */,
+ AB7BAB342012B519001E0872 /* geo_point_test.cc in Sources */,
+ 5492E0AD2021552D00B64F25 /* FSTMemoryMutationQueueTests.mm in Sources */,
+ 5492E051202154AA00B64F25 /* FIRQueryTests.mm in Sources */,
+ 5492E054202154AB00B64F25 /* FIRFieldValueTests.mm in Sources */,
+ 5492E09F2021552D00B64F25 /* FSTLevelDBMigrationsTests.mm in Sources */,
+ 5492E053202154AB00B64F25 /* FIRDocumentReferenceTests.mm in Sources */,
+ 5492E09D2021552D00B64F25 /* FSTLocalStoreTests.mm in Sources */,
+ 5492E0A32021552D00B64F25 /* FSTLocalSerializerTests.mm in Sources */,
+ 5492E0A72021552D00B64F25 /* FSTLevelDBKeyTests.mm in Sources */,
+ 5492E0A22021552D00B64F25 /* FSTQueryCacheTests.mm in Sources */,
+ 5492E0A52021552D00B64F25 /* FSTMemoryRemoteDocumentCacheTests.mm in Sources */,
+ 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */,
+ 5492E0B92021555100B64F25 /* FSTDocumentKeyTests.mm in Sources */,
DE2EF0871F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m in Sources */,
- DE51B1E01F0D490D0013853F /* FSTMemoryQueryCacheTests.m in Sources */,
- DE51B1E91F0D490D0013853F /* FSTLevelDBMutationQueueTests.mm in Sources */,
+ 5492E0BB2021555100B64F25 /* FSTDatabaseIDTests.mm in Sources */,
+ 5492E0C82021557E00B64F25 /* FSTDatastoreTests.mm in Sources */,
+ 5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */,
+ 5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */,
54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */,
- DE51B1E61F0D490D0013853F /* FSTRemoteDocumentCacheTests.m in Sources */,
- 61E1D8B11FCF6C5700753285 /* StringViewTests.mm in Sources */,
- DE51B1D91F0D490D0013853F /* FSTEagerGarbageCollectorTests.m in Sources */,
- DE51B1E21F0D490D0013853F /* FSTMutationQueueTests.m in Sources */,
- DE51B1E81F0D490D0013853F /* FSTLevelDBKeyTests.mm in Sources */,
- DE51B1E31F0D490D0013853F /* FSTPersistenceTestHelpers.m in Sources */,
- DE51B1CF1F0D48CD0013853F /* FSTQueryListenerTests.m in Sources */,
- DE51B1DA1F0D490D0013853F /* FSTLevelDBLocalStoreTests.m in Sources */,
- DE51B1FA1F0D492C0013853F /* FSTLevelDBSpecTests.m in Sources */,
- DE51B1FE1F0D492C0013853F /* FSTSyncEngineTestDriver.m in Sources */,
- DE51B1FC1F0D492C0013853F /* FSTMockDatastore.m in Sources */,
- DE51B1CE1F0D48CD0013853F /* FSTEventManagerTests.m in Sources */,
- DE51B1E41F0D490D0013853F /* FSTQueryCacheTests.m in Sources */,
- DE51B1CD1F0D48CD0013853F /* FSTDatabaseInfoTests.m in Sources */,
- DE51B1F21F0D49140013853F /* FSTPathTests.m in Sources */,
+ AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */,
+ 5492E03F2021401F00B64F25 /* FSTHelpers.mm in Sources */,
+ 5492E068202154B900B64F25 /* FSTQueryTests.mm in Sources */,
+ 5492E0AB2021552D00B64F25 /* StringViewTests.mm in Sources */,
+ 5492E0C92021557E00B64F25 /* FSTRemoteEventTests.mm in Sources */,
+ ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */,
+ 5492E0AE2021552D00B64F25 /* FSTLevelDBQueryCacheTests.mm in Sources */,
+ 5492E059202154AB00B64F25 /* FIRQuerySnapshotTests.mm in Sources */,
+ 5492E050202154AA00B64F25 /* FIRCollectionReferenceTests.mm in Sources */,
+ 5492E0A02021552D00B64F25 /* FSTLevelDBMutationQueueTests.mm in Sources */,
+ 54EB764D202277B30088B8F3 /* array_sorted_map_test.cc in Sources */,
+ 5492E03420213FFC00B64F25 /* FSTMemorySpecTests.mm in Sources */,
+ AB380D02201BC69F00D97691 /* bits_test.cc in Sources */,
+ 548DB929200D59F600E00ABC /* comparison_test.cc in Sources */,
+ 5492E03D2021401F00B64F25 /* FSTAssertTests.mm in Sources */,
+ 5492E062202154B900B64F25 /* FSTTimestampTests.mm in Sources */,
+ 5492E052202154AB00B64F25 /* FIRGeoPointTests.mm in Sources */,
+ 5492E0C72021557E00B64F25 /* FSTSerializerBetaTests.mm in Sources */,
+ 5492E03520213FFC00B64F25 /* FSTSpecTests.mm in Sources */,
+ 5492E03B2021401F00B64F25 /* FSTTestDispatchQueue.mm in Sources */,
+ 5492E057202154AB00B64F25 /* FIRSnapshotMetadataTests.mm in Sources */,
54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */,
- DE51B1DD1F0D490D0013853F /* FSTLocalStoreTests.m in Sources */,
- D5B25474286C9800CE42B8C2 /* FSTTestDispatchQueue.m in Sources */,
+ 5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1227,24 +1318,24 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- DE03B2EE1F214BAA00A30B9C /* FIRWriteBatchTests.m in Sources */,
- DE03B2F01F214BAA00A30B9C /* FIRDatabaseTests.m in Sources */,
+ 5492E076202154D600B64F25 /* FIRValidationTests.mm in Sources */,
+ 5492E072202154D600B64F25 /* FIRQueryTests.mm in Sources */,
5491BC731FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */,
- DE03B2F41F214BAA00A30B9C /* FIRServerTimestampTests.m in Sources */,
- DE03B2F11F214BAA00A30B9C /* FIRFieldsTests.m in Sources */,
- 54E9282D1F339CAD00C1953E /* XCTestCase+Await.m in Sources */,
- DE03B2EC1F214BA200A30B9C /* FSTDatastoreTests.m in Sources */,
- 54E928251F33953400C1953E /* FSTEventAccumulator.m in Sources */,
- DE03B2ED1F214BA200A30B9C /* FSTSmokeTests.m in Sources */,
- DE03B2F31F214BAA00A30B9C /* FIRQueryTests.m in Sources */,
- DE03B35E1F21586C00A30B9C /* FSTHelpers.m in Sources */,
- DE03B2F51F214BAA00A30B9C /* FIRTypeTests.m in Sources */,
- DE03B2EF1F214BAA00A30B9C /* FIRCursorTests.m in Sources */,
- DE03B2F21F214BAA00A30B9C /* FIRListenerRegistrationTests.m in Sources */,
- DE03B2C91F2149D600A30B9C /* FSTTransactionTests.m in Sources */,
- 54DA12B11F315F3800DD57A1 /* FIRValidationTests.m in Sources */,
- D5B2532E4676014F57A7EAB9 /* FSTStreamTests.m in Sources */,
- D5B259FDEE8094E8D710C5BF /* FSTTestDispatchQueue.m in Sources */,
+ 5492E0442021457E00B64F25 /* XCTestCase+Await.mm in Sources */,
+ 5492E07A202154D600B64F25 /* FIRTypeTests.mm in Sources */,
+ 5492E0422021440500B64F25 /* FSTHelpers.mm in Sources */,
+ 5492E041202143E700B64F25 /* FSTEventAccumulator.mm in Sources */,
+ 5492E080202154EC00B64F25 /* FSTSmokeTests.mm in Sources */,
+ 5492E077202154D600B64F25 /* FIRServerTimestampTests.mm in Sources */,
+ 5492E081202154EC00B64F25 /* FSTStreamTests.mm in Sources */,
+ 5492E074202154D600B64F25 /* FIRListenerRegistrationTests.mm in Sources */,
+ 5492E082202154EC00B64F25 /* FSTDatastoreTests.mm in Sources */,
+ 5492E079202154D600B64F25 /* FIRCursorTests.mm in Sources */,
+ 5492E073202154D600B64F25 /* FIRFieldsTests.mm in Sources */,
+ 5492E07F202154EC00B64F25 /* FSTTransactionTests.mm in Sources */,
+ 5492E075202154D600B64F25 /* FIRDatabaseTests.mm in Sources */,
+ 5492E078202154D600B64F25 /* FIRWriteBatchTests.mm in Sources */,
+ 5492E0432021441E00B64F25 /* FSTTestDispatchQueue.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1450,7 +1541,9 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
+ "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/GoogleTest/googletest/include\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
@@ -1481,7 +1574,9 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
+ "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/GoogleTest/googletest/include\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
@@ -1512,6 +1607,9 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
+ "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
+ "\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/GoogleTest/googletest/include\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
OTHER_LDFLAGS = (
@@ -1550,6 +1648,9 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
+ "\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
+ "\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/GoogleTest/googletest/include\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
OTHER_LDFLAGS = (
diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile
index 89af74f..bd57e21 100644
--- a/Firestore/Example/Podfile
+++ b/Firestore/Example/Podfile
@@ -1,7 +1,7 @@
# The next line is the forcing function for the Firebase pod. The Firebase
# version's subspecs should depend on the component versions in their
# corresponding podspec's.
-pod 'Firebase/Core', '4.7.0'
+pod 'Firebase/Core', '4.8.2'
use_frameworks!
platform :ios, '8.0'
diff --git a/Firestore/Example/SwiftBuildTest/main.swift b/Firestore/Example/SwiftBuildTest/main.swift
index bea8b56..260735b 100644
--- a/Firestore/Example/SwiftBuildTest/main.swift
+++ b/Firestore/Example/SwiftBuildTest/main.swift
@@ -27,6 +27,8 @@ func main() {
writeDocument(at: documentRef);
+ writeDocuments(at: documentRef, database: db);
+
addDocument(to: collectionRef);
readDocument(at: documentRef);
@@ -37,6 +39,8 @@ func main() {
listenToDocuments(matching: query);
+ enableDisableNetwork(database: db);
+
types();
}
@@ -129,6 +133,47 @@ func writeDocument(at docRef: DocumentReference) {
}
}
+func enableDisableNetwork(database db: Firestore) {
+ // closure syntax
+ db.disableNetwork(completion: { (error) in
+ if let e = error {
+ print("Uh oh! \(e)")
+ return
+ }
+ })
+ // trailing block syntax
+ db.enableNetwork { (error) in
+ if let e = error {
+ print("Uh oh! \(e)")
+ return
+ }
+ }
+}
+
+func writeDocuments(at docRef: DocumentReference, database db: Firestore) {
+ var batch: WriteBatch;
+
+ batch = db.batch();
+ batch.setData(["a" : "b"], forDocument:docRef);
+ batch.setData(["c" : "d"], forDocument:docRef);
+ // commit without completion callback.
+ batch.commit();
+ print("Batch write without completion complete!");
+
+ batch = db.batch();
+ batch.setData(["a" : "b"], forDocument:docRef);
+ batch.setData(["c" : "d"], forDocument:docRef);
+ // commit with completion callback via trailing closure syntax.
+ batch.commit() { error in
+ if let error = error {
+ print("Uh oh! \(error)");
+ return;
+ }
+ print("Batch write callback complete!");
+ }
+ print("Batch write with completion complete!");
+}
+
func addDocument(to collectionRef: CollectionReference) {
collectionRef.addDocument(data: ["foo": 42]);
@@ -141,11 +186,20 @@ func readDocument(at docRef: DocumentReference) {
// Trailing closure syntax.
docRef.getDocument() { document, error in
if let document = document {
- // NOTE that document is nullable.
- let data = document.data();
+ // Note that both document and document.data() is nullable.
+ if let data = document.data() {
print("Read document: \(data)")
-
- // Fields are read via subscript notation.
+ }
+ if let data = document.data(with:SnapshotOptions.serverTimestampBehavior(.estimate)) {
+ print("Read document: \(data)")
+ }
+ if let foo = document.get("foo") {
+ print("Field: \(foo)")
+ }
+ if let foo = document.get("foo", options: SnapshotOptions.serverTimestampBehavior(.previous)) {
+ print("Field: \(foo)")
+ }
+ // Fields can also be read via subscript notation.
if let foo = document["foo"] {
print("Field: \(foo)")
}
@@ -181,24 +235,27 @@ func readDocuments(matching query: Query) {
func listenToDocument(at docRef: DocumentReference) {
- let listener = docRef.addSnapshotListener() { document, error in
- if let error = error {
- print("Uh oh! Listen canceled: \(error)")
- return
- }
+ let listener = docRef.addSnapshotListener() { document, error in
+ if let error = error {
+ print("Uh oh! Listen canceled: \(error)")
+ return
+ }
- if let document = document {
- print("Current document: \(document.data())");
- if (document.metadata.isFromCache) {
- print("From Cache")
- } else {
- print("From Server")
- }
- }
+ if let document = document {
+ // Note that document.data() is nullable.
+ if let data : [String:Any] = document.data() {
+ print("Current document: \(data)");
+ }
+ if document.metadata.isFromCache {
+ print("From Cache")
+ } else {
+ print("From Server")
+ }
}
+ }
- // Unsubscribe.
- listener.remove();
+ // Unsubscribe.
+ listener.remove();
}
func listenToDocuments(matching query: Query) {
@@ -215,7 +272,9 @@ func listenToDocuments(matching query: Query) {
// TODO(mikelehen): Figure out how to make "for..in" syntax work
// directly on documentSet.
for document in snap.documents {
- print("Doc: ", document.data())
+ // Note that document.data() is not nullable.
+ let data : [String:Any] = document.data()
+ print("Doc: ", data)
}
}
}
@@ -258,7 +317,7 @@ func transactions() {
let balanceA = try transaction.getDocument(accA)["balance"] as! Double
let balanceB = try transaction.getDocument(accB)["balance"] as! Double
- if (balanceA < amount) {
+ if balanceA < amount {
errorPointer?.pointee = NSError(domain: "Foo", code: 123, userInfo: nil)
return nil
}
diff --git a/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm b/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm
new file mode 100644
index 0000000..547078f
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRCollectionReference.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRCollectionReferenceTests : XCTestCase
+@end
+
+@implementation FIRCollectionReferenceTests
+
+- (void)testEquals {
+ FIRCollectionReference *referenceFoo = FSTTestCollectionRef(@"foo");
+ FIRCollectionReference *referenceFooDup = FSTTestCollectionRef(@"foo");
+ FIRCollectionReference *referenceBar = FSTTestCollectionRef(@"bar");
+ XCTAssertEqualObjects(referenceFoo, referenceFooDup);
+ XCTAssertNotEqualObjects(referenceFoo, referenceBar);
+
+ XCTAssertEqual([referenceFoo hash], [referenceFooDup hash]);
+ XCTAssertNotEqual([referenceFoo hash], [referenceBar hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm b/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm
new file mode 100644
index 0000000..cc2b431
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRDocumentReference.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRDocumentReferenceTests : XCTestCase
+@end
+
+@implementation FIRDocumentReferenceTests
+
+- (void)testEquals {
+ FIRDocumentReference *referenceFoo = FSTTestDocRef(@"rooms/foo");
+ FIRDocumentReference *referenceFooDup = FSTTestDocRef(@"rooms/foo");
+ FIRDocumentReference *referenceBar = FSTTestDocRef(@"rooms/bar");
+ XCTAssertEqualObjects(referenceFoo, referenceFooDup);
+ XCTAssertNotEqualObjects(referenceFoo, referenceBar);
+
+ XCTAssertEqual([referenceFoo hash], [referenceFooDup hash]);
+ XCTAssertNotEqual([referenceFoo hash], [referenceBar hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRDocumentSnapshotTests.mm b/Firestore/Example/Tests/API/FIRDocumentSnapshotTests.mm
new file mode 100644
index 0000000..677d385
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRDocumentSnapshotTests.mm
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRDocumentSnapshot.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRDocumentSnapshotTests : XCTestCase
+@end
+
+@implementation FIRDocumentSnapshotTests
+
+- (void)testEquals {
+ FIRDocumentSnapshot *base = FSTTestDocSnapshot(@"rooms/foo", 1, @{ @"a" : @1 }, NO, NO);
+ FIRDocumentSnapshot *baseDup = FSTTestDocSnapshot(@"rooms/foo", 1, @{ @"a" : @1 }, NO, NO);
+ FIRDocumentSnapshot *nilData = FSTTestDocSnapshot(@"rooms/foo", 1, nil, NO, NO);
+ FIRDocumentSnapshot *nilDataDup = FSTTestDocSnapshot(@"rooms/foo", 1, nil, NO, NO);
+ FIRDocumentSnapshot *differentPath = FSTTestDocSnapshot(@"rooms/bar", 1, @{ @"a" : @1 }, NO, NO);
+ FIRDocumentSnapshot *differentData = FSTTestDocSnapshot(@"rooms/bar", 1, @{ @"b" : @1 }, NO, NO);
+ FIRDocumentSnapshot *hasMutations = FSTTestDocSnapshot(@"rooms/bar", 1, @{ @"a" : @1 }, YES, NO);
+ FIRDocumentSnapshot *fromCache = FSTTestDocSnapshot(@"rooms/bar", 1, @{ @"a" : @1 }, NO, YES);
+ XCTAssertEqualObjects(base, baseDup);
+ XCTAssertEqualObjects(nilData, nilDataDup);
+ XCTAssertNotEqualObjects(base, nilData);
+ XCTAssertNotEqualObjects(nilData, base);
+ XCTAssertNotEqualObjects(base, differentPath);
+ XCTAssertNotEqualObjects(base, differentData);
+ XCTAssertNotEqualObjects(base, hasMutations);
+ XCTAssertNotEqualObjects(base, fromCache);
+
+ XCTAssertEqual([base hash], [baseDup hash]);
+ XCTAssertEqual([nilData hash], [nilDataDup hash]);
+ XCTAssertNotEqual([base hash], [nilData hash]);
+ XCTAssertNotEqual([base hash], [differentPath hash]);
+ XCTAssertNotEqual([base hash], [differentData hash]);
+ XCTAssertNotEqual([base hash], [hasMutations hash]);
+ XCTAssertNotEqual([base hash], [fromCache hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRFieldPathTests.mm b/Firestore/Example/Tests/API/FIRFieldPathTests.mm
new file mode 100644
index 0000000..679ea89
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRFieldPathTests.mm
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRFieldPath.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Source/API/FIRFieldPath+Internal.h"
+#import "Firestore/Source/Model/FSTPath.h"
+
+#import "Firestore/Example/Tests/Util/FSTHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRFieldPathTests : XCTestCase
+@end
+
+@implementation FIRFieldPathTests
+
+- (void)testEquals {
+ FIRFieldPath *foo = [[FIRFieldPath alloc] initPrivate:FSTTestFieldPath(@"foo.ooo.oooo")];
+ FIRFieldPath *fooDup = [[FIRFieldPath alloc] initPrivate:FSTTestFieldPath(@"foo.ooo.oooo")];
+ FIRFieldPath *bar = [[FIRFieldPath alloc] initPrivate:FSTTestFieldPath(@"baa.aaa.aaar")];
+ XCTAssertEqualObjects(foo, fooDup);
+ XCTAssertNotEqualObjects(foo, bar);
+
+ XCTAssertEqual([foo hash], [fooDup hash]);
+ XCTAssertNotEqual([foo hash], [bar hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRFieldValueTests.mm b/Firestore/Example/Tests/API/FIRFieldValueTests.mm
new file mode 100644
index 0000000..575dfee
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRFieldValueTests.mm
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRFieldValue.h>
+
+#import <XCTest/XCTest.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRFieldValueTests : XCTestCase
+@end
+
+@implementation FIRFieldValueTests
+
+- (void)testEquals {
+ FIRFieldValue *deleted = [FIRFieldValue fieldValueForDelete];
+ FIRFieldValue *deleteDup = [FIRFieldValue fieldValueForDelete];
+ FIRFieldValue *serverTimestamp = [FIRFieldValue fieldValueForServerTimestamp];
+ FIRFieldValue *serverTimestampDup = [FIRFieldValue fieldValueForServerTimestamp];
+ XCTAssertEqualObjects(deleted, deleteDup);
+ XCTAssertNotEqualObjects(deleted, nil);
+ XCTAssertEqualObjects(serverTimestamp, serverTimestampDup);
+ XCTAssertNotEqualObjects(serverTimestamp, nil);
+ XCTAssertNotEqualObjects(deleted, serverTimestamp);
+
+ XCTAssertEqual([deleted hash], [deleteDup hash]);
+ XCTAssertEqual([serverTimestamp hash], [serverTimestamp hash]);
+ XCTAssertNotEqual([deleted hash], [serverTimestamp hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRGeoPointTests.m b/Firestore/Example/Tests/API/FIRGeoPointTests.mm
index b505de0..4de80a8 100644
--- a/Firestore/Example/Tests/API/FIRGeoPointTests.m
+++ b/Firestore/Example/Tests/API/FIRGeoPointTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#import "FirebaseFirestore/FIRGeoPoint.h"
+#import <FirebaseFirestore/FIRGeoPoint.h>
#import <XCTest/XCTest.h>
@@ -28,16 +28,17 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FIRGeoPointTests
- (void)testEquals {
- XCTAssertEqualObjects([[FIRGeoPoint alloc] initWithLatitude:0 longitude:0],
- [[FIRGeoPoint alloc] initWithLatitude:0 longitude:0]);
- XCTAssertEqualObjects([[FIRGeoPoint alloc] initWithLatitude:1.23 longitude:4.56],
- [[FIRGeoPoint alloc] initWithLatitude:1.23 longitude:4.56]);
- XCTAssertNotEqualObjects([[FIRGeoPoint alloc] initWithLatitude:0 longitude:0],
- [[FIRGeoPoint alloc] initWithLatitude:1 longitude:0]);
- XCTAssertNotEqualObjects([[FIRGeoPoint alloc] initWithLatitude:0 longitude:0],
- [[FIRGeoPoint alloc] initWithLatitude:0 longitude:1]);
- XCTAssertNotEqualObjects([[FIRGeoPoint alloc] initWithLatitude:0 longitude:0],
- [[NSObject alloc] init]);
+ FIRGeoPoint *foo = FSTTestGeoPoint(1.23, 4.56);
+ FIRGeoPoint *fooDup = FSTTestGeoPoint(1.23, 4.56);
+ FIRGeoPoint *differentLatitude = FSTTestGeoPoint(1.23, 0);
+ FIRGeoPoint *differentLongitude = FSTTestGeoPoint(0, 4.56);
+ XCTAssertEqualObjects(foo, fooDup);
+ XCTAssertNotEqualObjects(foo, differentLatitude);
+ XCTAssertNotEqualObjects(foo, differentLongitude);
+
+ XCTAssertEqual([foo hash], [fooDup hash]);
+ XCTAssertNotEqual([foo hash], [differentLatitude hash]);
+ XCTAssertNotEqual([foo hash], [differentLongitude hash]);
}
- (void)testComparison {
diff --git a/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm b/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm
new file mode 100644
index 0000000..067425a
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRQuerySnapshot.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Source/Model/FSTPath.h"
+
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRQuerySnapshotTests : XCTestCase
+@end
+
+@implementation FIRQuerySnapshotTests
+
+- (void)testEquals {
+ FIRQuerySnapshot *foo = FSTTestQuerySnapshot(@"foo", @{}, @{ @"a" : @{@"a" : @1} }, YES, NO);
+ FIRQuerySnapshot *fooDup = FSTTestQuerySnapshot(@"foo", @{}, @{ @"a" : @{@"a" : @1} }, YES, NO);
+ FIRQuerySnapshot *differentPath = FSTTestQuerySnapshot(@"bar", @{},
+ @{ @"a" : @{@"a" : @1} }, YES, NO);
+ FIRQuerySnapshot *differentDoc = FSTTestQuerySnapshot(@"foo",
+ @{ @"a" : @{@"b" : @1} }, @{}, YES, NO);
+ FIRQuerySnapshot *noPendingWrites = FSTTestQuerySnapshot(@"foo", @{},
+ @{ @"a" : @{@"a" : @1} }, NO, NO);
+ FIRQuerySnapshot *fromCache = FSTTestQuerySnapshot(@"foo", @{},
+ @{ @"a" : @{@"a" : @1} }, YES, YES);
+ XCTAssertEqualObjects(foo, fooDup);
+ XCTAssertNotEqualObjects(foo, differentPath);
+ XCTAssertNotEqualObjects(foo, differentDoc);
+ XCTAssertNotEqualObjects(foo, noPendingWrites);
+ XCTAssertNotEqualObjects(foo, fromCache);
+
+ XCTAssertEqual([foo hash], [fooDup hash]);
+ XCTAssertNotEqual([foo hash], [differentPath hash]);
+ XCTAssertNotEqual([foo hash], [differentDoc hash]);
+ XCTAssertNotEqual([foo hash], [noPendingWrites hash]);
+ XCTAssertNotEqual([foo hash], [fromCache hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRQueryTests.mm b/Firestore/Example/Tests/API/FIRQueryTests.mm
new file mode 100644
index 0000000..83f90be
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRQueryTests.mm
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRQuery.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Source/API/FIRQuery+Internal.h"
+#import "Firestore/Source/Core/FSTQuery.h"
+#import "Firestore/Source/Model/FSTPath.h"
+
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRQueryTests : XCTestCase
+@end
+
+@implementation FIRQueryTests
+
+- (void)testEquals {
+ FIRFirestore *firestore = FSTTestFirestore();
+ FIRQuery *queryFoo = [FIRQuery referenceWithQuery:FSTTestQuery(@"foo") firestore:firestore];
+ FIRQuery *queryFooDup = [FIRQuery referenceWithQuery:FSTTestQuery(@"foo") firestore:firestore];
+ FIRQuery *queryBar = [FIRQuery referenceWithQuery:FSTTestQuery(@"bar") firestore:firestore];
+ XCTAssertEqualObjects(queryFoo, queryFooDup);
+ XCTAssertNotEqualObjects(queryFoo, queryBar);
+ XCTAssertEqualObjects([queryFoo queryWhereField:@"f" isEqualTo:@1],
+ [queryFoo queryWhereField:@"f" isEqualTo:@1]);
+ XCTAssertNotEqualObjects([queryFoo queryWhereField:@"f" isEqualTo:@1],
+ [queryFoo queryWhereField:@"f" isEqualTo:@2]);
+
+ XCTAssertEqual([queryFoo hash], [queryFooDup hash]);
+ XCTAssertNotEqual([queryFoo hash], [queryBar hash]);
+ XCTAssertEqual([[queryFoo queryWhereField:@"f" isEqualTo:@1] hash],
+ [[queryFoo queryWhereField:@"f" isEqualTo:@1] hash]);
+ XCTAssertNotEqual([[queryFoo queryWhereField:@"f" isEqualTo:@1] hash],
+ [[queryFoo queryWhereField:@"f" isEqualTo:@2] hash]);
+}
+
+- (void)testFilteringWithPredicate {
+ FIRFirestore *firestore = FSTTestFirestore();
+ FIRQuery *query = [FIRQuery referenceWithQuery:FSTTestQuery(@"foo") firestore:firestore];
+ FIRQuery *query1 = [query queryWhereField:@"f" isLessThanOrEqualTo:@1];
+ FIRQuery *query2 = [query queryFilteredUsingPredicate:[NSPredicate predicateWithFormat:@"f<=1"]];
+ FIRQuery *query3 =
+ [[query queryWhereField:@"f1" isLessThan:@2] queryWhereField:@"f2" isEqualTo:@3];
+ FIRQuery *query4 =
+ [query queryFilteredUsingPredicate:[NSPredicate predicateWithFormat:@"f1<2 && f2==3"]];
+ FIRQuery *query5 =
+ [[[[[query queryWhereField:@"f1" isLessThan:@2] queryWhereField:@"f2" isEqualTo:@3]
+ queryWhereField:@"f1"
+ isLessThanOrEqualTo:@"four"] queryWhereField:@"f1"
+ isGreaterThanOrEqualTo:@"five"] queryWhereField:@"f1"
+ isGreaterThan:@6];
+ FIRQuery *query6 = [query
+ queryFilteredUsingPredicate:
+ [NSPredicate predicateWithFormat:@"f1<2 && f2==3 && f1<='four' && f1>='five' && f1>6"]];
+ FIRQuery *query7 = [query
+ queryFilteredUsingPredicate:
+ [NSPredicate predicateWithFormat:@"2>f1 && 3==f2 && 'four'>=f1 && 'five'<=f1 && 6<f1"]];
+ XCTAssertEqualObjects(query1, query2);
+ XCTAssertNotEqualObjects(query2, query3);
+ XCTAssertEqualObjects(query3, query4);
+ XCTAssertNotEqualObjects(query4, query5);
+ XCTAssertEqualObjects(query5, query6);
+ XCTAssertEqualObjects(query6, query7);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FIRSnapshotMetadataTests.mm b/Firestore/Example/Tests/API/FIRSnapshotMetadataTests.mm
new file mode 100644
index 0000000..a4d321b
--- /dev/null
+++ b/Firestore/Example/Tests/API/FIRSnapshotMetadataTests.mm
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FIRSnapshotMetadata.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSnapshotMetadataTests : XCTestCase
+@end
+
+@implementation FIRSnapshotMetadataTests
+
+- (void)testEquals {
+ FIRSnapshotMetadata *foo =
+ [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:YES fromCache:YES];
+ FIRSnapshotMetadata *fooDup =
+ [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:YES fromCache:YES];
+ FIRSnapshotMetadata *bar =
+ [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:YES fromCache:NO];
+ FIRSnapshotMetadata *baz =
+ [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:NO fromCache:YES];
+ XCTAssertEqualObjects(foo, fooDup);
+ XCTAssertNotEqualObjects(foo, bar);
+ XCTAssertNotEqualObjects(foo, baz);
+ XCTAssertNotEqualObjects(bar, baz);
+
+ XCTAssertEqual([foo hash], [fooDup hash]);
+ XCTAssertNotEqual([foo hash], [bar hash]);
+ XCTAssertNotEqual([foo hash], [baz hash]);
+ XCTAssertNotEqual([bar hash], [baz hash]);
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FSTAPIHelpers.h b/Firestore/Example/Tests/API/FSTAPIHelpers.h
new file mode 100644
index 0000000..0729af0
--- /dev/null
+++ b/Firestore/Example/Tests/API/FSTAPIHelpers.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 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 <Foundation/Foundation.h>
+
+#import "Firestore/Example/Tests/Util/FSTHelpers.h"
+
+@class FIRCollectionReference;
+@class FIRDocumentReference;
+@class FIRDocumentSnapshot;
+@class FIRFirestore;
+@class FIRQuerySnapshot;
+
+NS_ASSUME_NONNULL_BEGIN
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/** A convenience method for creating dummy singleton FIRFirestore for tests. */
+FIRFirestore *FSTTestFirestore();
+
+/** A convenience method for creating a doc snapshot for tests. */
+FIRDocumentSnapshot *FSTTestDocSnapshot(NSString *path,
+ FSTTestSnapshotVersion version,
+ NSDictionary<NSString *, id> *_Nullable data,
+ BOOL hasMutations,
+ BOOL fromCache);
+
+/** A convenience method for creating a collection reference from a path string. */
+FIRCollectionReference *FSTTestCollectionRef(NSString *path);
+
+/** A convenience method for creating a document reference from a path string. */
+FIRDocumentReference *FSTTestDocRef(NSString *path);
+
+/**
+ * A convenience method for creating a particular query snapshot for tests.
+ *
+ * @param path To be used in constructing the query.
+ * @param oldDocs Provides the prior set of documents in the QuerySnapshot. Each dictionary entry
+ * maps to a document, with the key being the document id, and the value being the document
+ * contents.
+ * @param docsToAdd Specifies data to be added into the query snapshot as of now. Each dictionary
+ * entry maps to a document, with the key being the document id, and the value being the document
+ * contents.
+ * @param hasPendingWrites Whether the query snapshot has pending writes to the server.
+ * @param fromCache Whether the query snapshot is cache result.
+ * @returns A query snapshot that consists of both sets of documents.
+ */
+FIRQuerySnapshot *FSTTestQuerySnapshot(
+ NSString *path,
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *oldDocs,
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *docsToAdd,
+ BOOL hasPendingWrites,
+ BOOL fromCache);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/API/FSTAPIHelpers.mm b/Firestore/Example/Tests/API/FSTAPIHelpers.mm
new file mode 100644
index 0000000..da899b7
--- /dev/null
+++ b/Firestore/Example/Tests/API/FSTAPIHelpers.mm
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017 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 "Firestore/Example/Tests/API/FSTAPIHelpers.h"
+
+#import <FirebaseFirestore/FIRDocumentChange.h>
+#import <FirebaseFirestore/FIRDocumentReference.h>
+#import <FirebaseFirestore/FIRSnapshotMetadata.h>
+
+#import "Firestore/Source/API/FIRCollectionReference+Internal.h"
+#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
+#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h"
+#import "Firestore/Source/API/FIRFirestore+Internal.h"
+#import "Firestore/Source/API/FIRQuerySnapshot+Internal.h"
+#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
+#import "Firestore/Source/Core/FSTQuery.h"
+#import "Firestore/Source/Core/FSTViewSnapshot.h"
+#import "Firestore/Source/Model/FSTDocument.h"
+#import "Firestore/Source/Model/FSTDocumentKey.h"
+#import "Firestore/Source/Model/FSTDocumentSet.h"
+#import "Firestore/Source/Model/FSTPath.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+FIRFirestore *FSTTestFirestore() {
+ static FIRFirestore *sharedInstance = nil;
+ static dispatch_once_t onceToken;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+ dispatch_once(&onceToken, ^{
+ sharedInstance = [[FIRFirestore alloc] initWithProjectID:@"abc"
+ database:@"abc"
+ persistenceKey:@"db123"
+ credentialsProvider:nil
+ workerDispatchQueue:nil
+ firebaseApp:nil];
+ });
+#pragma clang diagnostic pop
+ return sharedInstance;
+}
+
+FIRDocumentSnapshot *FSTTestDocSnapshot(NSString *path,
+ FSTTestSnapshotVersion version,
+ NSDictionary<NSString *, id> *_Nullable data,
+ BOOL hasMutations,
+ BOOL fromCache) {
+ FSTDocument *doc = data ? FSTTestDoc(path, version, data, hasMutations) : nil;
+ return [FIRDocumentSnapshot snapshotWithFirestore:FSTTestFirestore()
+ documentKey:FSTTestDocKey(path)
+ document:doc
+ fromCache:fromCache];
+}
+
+FIRCollectionReference *FSTTestCollectionRef(NSString *path) {
+ return [FIRCollectionReference referenceWithPath:FSTTestPath(path) firestore:FSTTestFirestore()];
+}
+
+FIRDocumentReference *FSTTestDocRef(NSString *path) {
+ return [FIRDocumentReference referenceWithPath:FSTTestPath(path) firestore:FSTTestFirestore()];
+}
+
+/** A convenience method for creating a query snapshots for tests. */
+FIRQuerySnapshot *FSTTestQuerySnapshot(
+ NSString *path,
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *oldDocs,
+ NSDictionary<NSString *, NSDictionary<NSString *, id> *> *docsToAdd,
+ BOOL hasPendingWrites,
+ BOOL fromCache) {
+ FIRSnapshotMetadata *metadata =
+ [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:hasPendingWrites fromCache:fromCache];
+ FSTDocumentSet *oldDocuments = FSTTestDocSet(FSTDocumentComparatorByKey, @[]);
+ for (NSString *key in oldDocs) {
+ oldDocuments = [oldDocuments
+ documentSetByAddingDocument:FSTTestDoc([NSString stringWithFormat:@"%@/%@", path, key], 1,
+ oldDocs[key], hasPendingWrites)];
+ }
+ FSTDocumentSet *newDocuments = oldDocuments;
+ NSArray<FSTDocumentViewChange *> *documentChanges = [NSArray array];
+ for (NSString *key in docsToAdd) {
+ FSTDocument *docToAdd = FSTTestDoc([NSString stringWithFormat:@"%@/%@", path, key], 1,
+ docsToAdd[key], hasPendingWrites);
+ newDocuments = [newDocuments documentSetByAddingDocument:docToAdd];
+ documentChanges = [documentChanges
+ arrayByAddingObject:[FSTDocumentViewChange
+ changeWithDocument:docToAdd
+ type:FSTDocumentViewChangeTypeAdded]];
+ }
+ FSTViewSnapshot *viewSnapshot = [[FSTViewSnapshot alloc] initWithQuery:FSTTestQuery(path)
+ documents:newDocuments
+ oldDocuments:oldDocuments
+ documentChanges:documentChanges
+ fromCache:fromCache
+ hasPendingWrites:hasPendingWrites
+ syncStateChanged:YES];
+ return [FIRQuerySnapshot snapshotWithFirestore:FSTTestFirestore()
+ originalQuery:FSTTestQuery(path)
+ snapshot:viewSnapshot
+ metadata:metadata];
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/Core/FSTDatabaseInfoTests.m b/Firestore/Example/Tests/Core/FSTDatabaseInfoTests.mm
index c7cf22a..c7cf22a 100644
--- a/Firestore/Example/Tests/Core/FSTDatabaseInfoTests.m
+++ b/Firestore/Example/Tests/Core/FSTDatabaseInfoTests.mm
diff --git a/Firestore/Example/Tests/Core/FSTEventManagerTests.m b/Firestore/Example/Tests/Core/FSTEventManagerTests.mm
index 99021ce..fcde17d 100644
--- a/Firestore/Example/Tests/Core/FSTEventManagerTests.m
+++ b/Firestore/Example/Tests/Core/FSTEventManagerTests.mm
@@ -52,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testHandlesManyListenersPerQuery {
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"foo/bar")];
+ FSTQuery *query = FSTTestQuery(@"foo/bar");
FSTQueryListener *listener1 = [self noopListenerForQuery:query];
FSTQueryListener *listener2 = [self noopListenerForQuery:query];
@@ -73,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testHandlesUnlistenOnUnknownListenerGracefully {
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"foo/bar")];
+ FSTQuery *query = FSTTestQuery(@"foo/bar");
FSTQueryListener *listener = [self noopListenerForQuery:query];
FSTSyncEngine *syncEngineMock = OCMStrictClassMock([FSTSyncEngine class]);
@@ -95,8 +95,8 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testNotifiesListenersInTheRightOrder {
- FSTQuery *query1 = [FSTQuery queryWithPath:FSTTestPath(@"foo/bar")];
- FSTQuery *query2 = [FSTQuery queryWithPath:FSTTestPath(@"bar/baz")];
+ FSTQuery *query1 = FSTTestQuery(@"foo/bar");
+ FSTQuery *query2 = FSTTestQuery(@"bar/baz");
NSMutableArray *eventOrder = [NSMutableArray array];
FSTQueryListener *listener1 = [self makeMockListenerForQuery:query1
@@ -135,15 +135,15 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testWillForwardOnlineStateChanges {
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"foo/bar")];
+ FSTQuery *query = FSTTestQuery(@"foo/bar");
FSTQueryListener *fakeListener = OCMClassMock([FSTQueryListener class]);
NSMutableArray *events = [NSMutableArray array];
OCMStub([fakeListener query]).andReturn(query);
- OCMStub([fakeListener clientDidChangeOnlineState:FSTOnlineStateUnknown])
+ OCMStub([fakeListener applyChangedOnlineState:FSTOnlineStateUnknown])
.andDo(^(NSInvocation *invocation) {
[events addObject:@(FSTOnlineStateUnknown)];
});
- OCMStub([fakeListener clientDidChangeOnlineState:FSTOnlineStateHealthy])
+ OCMStub([fakeListener applyChangedOnlineState:FSTOnlineStateHealthy])
.andDo(^(NSInvocation *invocation) {
[events addObject:@(FSTOnlineStateHealthy)];
});
@@ -154,7 +154,7 @@ NS_ASSUME_NONNULL_BEGIN
[eventManager addListener:fakeListener];
XCTAssertEqualObjects(events, @[ @(FSTOnlineStateUnknown) ]);
- [eventManager watchStreamDidChangeOnlineState:FSTOnlineStateHealthy];
+ [eventManager applyChangedOnlineState:FSTOnlineStateHealthy];
XCTAssertEqualObjects(events, (@[ @(FSTOnlineStateUnknown), @(FSTOnlineStateHealthy) ]));
}
diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.m b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm
index 1bb7a47..4856b5f 100644
--- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.m
+++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm
@@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray<FSTViewSnapshot *> *accum = [NSMutableArray array];
NSMutableArray<FSTViewSnapshot *> *otherAccum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO);
FSTDocument *doc2prime =
@@ -88,7 +88,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRaisesErrorEvent {
NSMutableArray<NSError *> *accum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms/Eros")];
+ FSTQuery *query = FSTTestQuery(@"rooms/Eros");
FSTQueryListener *listener = [self listenToQuery:query
handler:^(FSTViewSnapshot *snapshot, NSError *error) {
@@ -104,7 +104,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRaisesEventForEmptyCollectionAfterSync {
NSMutableArray<FSTViewSnapshot *> *accum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTQueryListener *listener = [self listenToQuery:query accumulatingSnapshots:accum];
@@ -126,7 +126,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testMutingAsyncListenerPreventsAllSubsequentEvents {
NSMutableArray<FSTViewSnapshot *> *accum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms/Eros")];
+ FSTQuery *query = FSTTestQuery(@"rooms/Eros");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 3, @{@"name" : @"Eros"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Eros", 4, @{@"name" : @"Eros2"}, NO);
@@ -166,7 +166,7 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray<FSTViewSnapshot *> *filteredAccum = [NSMutableArray array];
NSMutableArray<FSTViewSnapshot *> *fullAccum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO);
@@ -204,7 +204,7 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray<FSTViewSnapshot *> *filteredAccum = [NSMutableArray array];
NSMutableArray<FSTViewSnapshot *> *fullAccum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, YES);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO);
FSTDocument *doc1Prime = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
@@ -253,7 +253,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRaisesQueryMetadataEventsOnlyWhenHasPendingWritesOnTheQueryChanges {
NSMutableArray<FSTViewSnapshot *> *fullAccum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, YES);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, YES);
FSTDocument *doc1Prime = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
@@ -290,7 +290,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testMetadataOnlyDocumentChangesAreFilteredOutWhenIncludeDocumentMetadataChangesIsFalse {
NSMutableArray<FSTViewSnapshot *> *filteredAccum = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, YES);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO);
FSTDocument *doc1Prime = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
@@ -322,7 +322,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testWillWaitForSyncIfOnline {
NSMutableArray<FSTViewSnapshot *> *events = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO);
FSTQueryListener *listener =
@@ -340,10 +340,10 @@ NS_ASSUME_NONNULL_BEGIN
[FSTTargetChange changeWithDocuments:@[ doc1, doc2 ]
currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent]);
- [listener clientDidChangeOnlineState:FSTOnlineStateHealthy]; // no event
+ [listener applyChangedOnlineState:FSTOnlineStateHealthy]; // no event
[listener queryDidChangeViewSnapshot:snap1];
- [listener clientDidChangeOnlineState:FSTOnlineStateUnknown];
- [listener clientDidChangeOnlineState:FSTOnlineStateHealthy];
+ [listener applyChangedOnlineState:FSTOnlineStateUnknown];
+ [listener applyChangedOnlineState:FSTOnlineStateHealthy];
[listener queryDidChangeViewSnapshot:snap2];
[listener queryDidChangeViewSnapshot:snap3];
@@ -365,7 +365,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testWillRaiseInitialEventWhenGoingOffline {
NSMutableArray<FSTViewSnapshot *> *events = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO);
FSTQueryListener *listener =
@@ -379,12 +379,12 @@ NS_ASSUME_NONNULL_BEGIN
FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], nil);
FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2 ], nil);
- [listener clientDidChangeOnlineState:FSTOnlineStateHealthy]; // no event
- [listener queryDidChangeViewSnapshot:snap1]; // no event
- [listener clientDidChangeOnlineState:FSTOnlineStateFailed]; // event
- [listener clientDidChangeOnlineState:FSTOnlineStateUnknown]; // no event
- [listener clientDidChangeOnlineState:FSTOnlineStateFailed]; // no event
- [listener queryDidChangeViewSnapshot:snap2]; // another event
+ [listener applyChangedOnlineState:FSTOnlineStateHealthy]; // no event
+ [listener queryDidChangeViewSnapshot:snap1]; // no event
+ [listener applyChangedOnlineState:FSTOnlineStateFailed]; // event
+ [listener applyChangedOnlineState:FSTOnlineStateUnknown]; // no event
+ [listener applyChangedOnlineState:FSTOnlineStateFailed]; // no event
+ [listener queryDidChangeViewSnapshot:snap2]; // another event
FSTDocumentViewChange *change1 =
[FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded];
@@ -411,7 +411,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testWillRaiseInitialEventWhenGoingOfflineAndThereAreNoDocs {
NSMutableArray<FSTViewSnapshot *> *events = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTQueryListener *listener = [self listenToQuery:query
options:[FSTListenOptions defaultOptions]
accumulatingSnapshots:events];
@@ -419,9 +419,9 @@ NS_ASSUME_NONNULL_BEGIN
FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], nil);
- [listener clientDidChangeOnlineState:FSTOnlineStateHealthy]; // no event
- [listener queryDidChangeViewSnapshot:snap1]; // no event
- [listener clientDidChangeOnlineState:FSTOnlineStateFailed]; // event
+ [listener applyChangedOnlineState:FSTOnlineStateHealthy]; // no event
+ [listener queryDidChangeViewSnapshot:snap1]; // no event
+ [listener applyChangedOnlineState:FSTOnlineStateFailed]; // event
FSTViewSnapshot *expectedSnap = [[FSTViewSnapshot alloc]
initWithQuery:query
@@ -437,7 +437,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testWillRaiseInitialEventWhenStartingOfflineAndThereAreNoDocs {
NSMutableArray<FSTViewSnapshot *> *events = [NSMutableArray array];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"rooms")];
+ FSTQuery *query = FSTTestQuery(@"rooms");
FSTQueryListener *listener = [self listenToQuery:query
options:[FSTListenOptions defaultOptions]
accumulatingSnapshots:events];
@@ -445,8 +445,8 @@ NS_ASSUME_NONNULL_BEGIN
FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], nil);
- [listener clientDidChangeOnlineState:FSTOnlineStateFailed]; // no event
- [listener queryDidChangeViewSnapshot:snap1]; // event
+ [listener applyChangedOnlineState:FSTOnlineStateFailed]; // no event
+ [listener queryDidChangeViewSnapshot:snap1]; // event
FSTViewSnapshot *expectedSnap = [[FSTViewSnapshot alloc]
initWithQuery:query
diff --git a/Firestore/Example/Tests/Core/FSTQueryTests.m b/Firestore/Example/Tests/Core/FSTQueryTests.mm
index 1fd0e8b..3d2bd82 100644
--- a/Firestore/Example/Tests/Core/FSTQueryTests.m
+++ b/Firestore/Example/Tests/Core/FSTQueryTests.mm
@@ -61,9 +61,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testOrderBy {
- FSTResourcePath *path =
- [FSTResourcePath pathWithSegments:@[ @"rooms", @"Firestore", @"messages" ]];
- FSTQuery *query = [FSTQuery queryWithPath:path];
+ FSTQuery *query = FSTTestQuery(@"rooms/Firestore/messages");
query =
[query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"length")
ascending:NO]];
@@ -80,29 +78,25 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testMatchesBasedOnDocumentKey {
- FSTResourcePath *queryKey =
- [FSTResourcePath pathWithSegments:@[ @"rooms", @"eros", @"messages", @"1" ]];
FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, NO);
FSTDocument *doc3 = FSTTestDoc(@"rooms/other/messages/1", 0, @{@"text" : @"msg3"}, NO);
// document query
- FSTQuery *query = [FSTQuery queryWithPath:queryKey];
+ FSTQuery *query = FSTTestQuery(@"rooms/eros/messages/1");
XCTAssertTrue([query matchesDocument:doc1]);
XCTAssertFalse([query matchesDocument:doc2]);
XCTAssertFalse([query matchesDocument:doc3]);
}
- (void)testMatchesCorrectlyForShallowAncestorQuery {
- FSTResourcePath *queryPath =
- [FSTResourcePath pathWithSegments:@[ @"rooms", @"eros", @"messages" ]];
FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
FSTDocument *doc1Meta = FSTTestDoc(@"rooms/eros/messages/1/meta/1", 0, @{@"meta" : @"mv"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, NO);
FSTDocument *doc3 = FSTTestDoc(@"rooms/other/messages/1", 0, @{@"text" : @"msg3"}, NO);
// shallow ancestor query
- FSTQuery *query = [FSTQuery queryWithPath:queryPath];
+ FSTQuery *query = FSTTestQuery(@"rooms/eros/messages");
XCTAssertTrue([query matchesDocument:doc1]);
XCTAssertFalse([query matchesDocument:doc1Meta]);
XCTAssertTrue([query matchesDocument:doc2]);
@@ -110,21 +104,20 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEmptyFieldsAreAllowedForQueries {
- FSTResourcePath *queryPath = [FSTResourcePath pathWithString:@"rooms/eros/messages"];
FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{}, NO);
- FSTQuery *query = [[FSTQuery queryWithPath:queryPath]
+ FSTQuery *query = [FSTTestQuery(@"rooms/eros/messages")
queryByAddingFilter:FSTTestFilter(@"text", @"==", @"msg1")];
XCTAssertTrue([query matchesDocument:doc1]);
XCTAssertFalse([query matchesDocument:doc2]);
}
- (void)testMatchesPrimitiveValuesForFilters {
- FSTQuery *query1 = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
- queryByAddingFilter:FSTTestFilter(@"sort", @">=", @(2))];
- FSTQuery *query2 = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
- queryByAddingFilter:FSTTestFilter(@"sort", @"<=", @(2))];
+ FSTQuery *query1 =
+ [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @">=", @(2))];
+ FSTQuery *query2 =
+ [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @"<=", @(2))];
FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @1 }, NO);
FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @2 }, NO);
@@ -149,7 +142,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testNullFilter {
- FSTQuery *query = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
+ FSTQuery *query = [FSTTestQuery(@"collection")
queryByAddingFilter:FSTTestFilter(@"sort", @"==", [NSNull null])];
FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{@"sort" : [NSNull null]}, NO);
FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @2 }, NO);
@@ -165,8 +158,8 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testNanFilter {
- FSTQuery *query = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
- queryByAddingFilter:FSTTestFilter(@"sort", @"==", @(NAN))];
+ FSTQuery *query =
+ [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @"==", @(NAN))];
FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @(NAN) }, NO);
FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @2 }, NO);
FSTDocument *doc3 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @3.1 }, NO);
@@ -181,10 +174,10 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testDoesNotMatchComplexObjectsForFilters {
- FSTQuery *query1 = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
- queryByAddingFilter:FSTTestFilter(@"sort", @"<=", @(2))];
- FSTQuery *query2 = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
- queryByAddingFilter:FSTTestFilter(@"sort", @">=", @(2))];
+ FSTQuery *query1 =
+ [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @"<=", @(2))];
+ FSTQuery *query2 =
+ [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @">=", @(2))];
FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @2 }, NO);
FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @[] }, NO);
@@ -212,7 +205,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testDoesntRemoveComplexObjectsWithOrderBy {
- FSTQuery *query1 = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]]
+ FSTQuery *query1 = [FSTTestQuery(@"collection")
queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort")
ascending:YES]];
@@ -232,9 +225,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testFiltersBasedOnArrayValue {
- FSTQuery *baseQuery =
- [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]];
-
+ FSTQuery *baseQuery = FSTTestQuery(@"collection");
FSTDocument *doc1 = FSTTestDoc(@"collection/doc", 0, @{ @"tags" : @[ @"foo", @1, @YES ] }, NO);
NSArray<id<FSTFilter>> *matchingFilters =
@@ -256,9 +247,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testFiltersBasedOnObjectValue {
- FSTQuery *baseQuery =
- [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]];
-
+ FSTQuery *baseQuery = FSTTestQuery(@"collection");
FSTDocument *doc1 =
FSTTestDoc(@"collection/doc", 0,
@{ @"tags" : @{@"foo" : @"foo", @"a" : @0, @"b" : @YES, @"c" : @(NAN)} }, NO);
@@ -310,7 +299,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testSortsDocumentsInTheCorrectOrder {
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]];
+ FSTQuery *query = FSTTestQuery(@"collection");
query =
[query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort")
ascending:YES]];
@@ -339,7 +328,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testSortsDocumentsUsingMultipleFields {
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]];
+ FSTQuery *query = FSTTestQuery(@"collection");
query =
[query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort1")
ascending:YES]];
@@ -366,7 +355,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testSortsDocumentsWithDescendingToo {
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"collection" ]]];
+ FSTQuery *query = FSTTestQuery(@"collection");
query =
[query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort1")
ascending:NO]];
@@ -393,40 +382,40 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEquality {
- FSTQuery *q11 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q11 = FSTTestQuery(@"foo");
q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))];
q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))];
- FSTQuery *q12 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q12 = FSTTestQuery(@"foo");
q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))];
q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))];
- FSTQuery *q21 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
- FSTQuery *q22 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q21 = FSTTestQuery(@"foo");
+ FSTQuery *q22 = FSTTestQuery(@"foo");
- FSTQuery *q31 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo", @"bar" ]]];
- FSTQuery *q32 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo", @"bar" ]]];
+ FSTQuery *q31 = FSTTestQuery(@"foo/bar");
+ FSTQuery *q32 = FSTTestQuery(@"foo/bar");
- FSTQuery *q41 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q41 = FSTTestQuery(@"foo");
q41 = [q41 queryByAddingSortBy:@"foo" ascending:YES];
q41 = [q41 queryByAddingSortBy:@"bar" ascending:YES];
- FSTQuery *q42 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q42 = FSTTestQuery(@"foo");
q42 = [q42 queryByAddingSortBy:@"foo" ascending:YES];
q42 = [q42 queryByAddingSortBy:@"bar" ascending:YES];
- FSTQuery *q43Diff = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q43Diff = FSTTestQuery(@"foo");
q43Diff = [q43Diff queryByAddingSortBy:@"bar" ascending:YES];
q43Diff = [q43Diff queryByAddingSortBy:@"foo" ascending:YES];
- FSTQuery *q51 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q51 = FSTTestQuery(@"foo");
q51 = [q51 queryByAddingSortBy:@"foo" ascending:YES];
q51 = [q51 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))];
- FSTQuery *q52 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q52 = FSTTestQuery(@"foo");
q52 = [q52 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))];
q52 = [q52 queryByAddingSortBy:@"foo" ascending:YES];
- FSTQuery *q53Diff = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q53Diff = FSTTestQuery(@"foo");
q53Diff = [q53Diff queryByAddingFilter:FSTTestFilter(@"bar", @">", @(2))];
q53Diff = [q53Diff queryByAddingSortBy:@"bar" ascending:YES];
- FSTQuery *q61 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q61 = FSTTestQuery(@"foo");
q61 = [q61 queryBySettingLimit:10];
// XCTAssertEqualObjects(q11, q12); // TODO(klimt): not canonical yet
@@ -458,40 +447,40 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testUniqueIds {
- FSTQuery *q11 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q11 = FSTTestQuery(@"foo");
q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))];
q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))];
- FSTQuery *q12 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q12 = FSTTestQuery(@"foo");
q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))];
q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))];
- FSTQuery *q21 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
- FSTQuery *q22 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q21 = FSTTestQuery(@"foo");
+ FSTQuery *q22 = FSTTestQuery(@"foo");
- FSTQuery *q31 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo", @"bar" ]]];
- FSTQuery *q32 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo", @"bar" ]]];
+ FSTQuery *q31 = FSTTestQuery(@"foo/bar");
+ FSTQuery *q32 = FSTTestQuery(@"foo/bar");
- FSTQuery *q41 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q41 = FSTTestQuery(@"foo");
q41 = [q41 queryByAddingSortBy:@"foo" ascending:YES];
q41 = [q41 queryByAddingSortBy:@"bar" ascending:YES];
- FSTQuery *q42 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q42 = FSTTestQuery(@"foo");
q42 = [q42 queryByAddingSortBy:@"foo" ascending:YES];
q42 = [q42 queryByAddingSortBy:@"bar" ascending:YES];
- FSTQuery *q43Diff = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q43Diff = FSTTestQuery(@"foo");
q43Diff = [q43Diff queryByAddingSortBy:@"bar" ascending:YES];
q43Diff = [q43Diff queryByAddingSortBy:@"foo" ascending:YES];
- FSTQuery *q51 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q51 = FSTTestQuery(@"foo");
q51 = [q51 queryByAddingSortBy:@"foo" ascending:YES];
q51 = [q51 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))];
- FSTQuery *q52 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q52 = FSTTestQuery(@"foo");
q52 = [q52 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))];
q52 = [q52 queryByAddingSortBy:@"foo" ascending:YES];
- FSTQuery *q53Diff = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q53Diff = FSTTestQuery(@"foo");
q53Diff = [q53Diff queryByAddingFilter:FSTTestFilter(@"bar", @">", @(2))];
q53Diff = [q53Diff queryByAddingSortBy:@"bar" ascending:YES];
- FSTQuery *q61 = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *q61 = FSTTestQuery(@"foo");
q61 = [q61 queryBySettingLimit:10];
// XCTAssertEqual(q11.hash, q12.hash); // TODO(klimt): not canonical yet
diff --git a/Firestore/Example/Tests/Core/FSTTargetIDGeneratorTests.m b/Firestore/Example/Tests/Core/FSTTargetIDGeneratorTests.m
deleted file mode 100644
index 6f54fd1..0000000
--- a/Firestore/Example/Tests/Core/FSTTargetIDGeneratorTests.m
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2017 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 "Firestore/Source/Core/FSTTargetIDGenerator.h"
-
-#import <XCTest/XCTest.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface FSTTargetIDGenerator ()
-- (instancetype)initWithGeneratorID:(NSInteger)generatorID startingAfterID:(FSTTargetID)after;
-@end
-
-@interface FSTTargetIDGeneratorTests : XCTestCase
-@end
-
-@implementation FSTTargetIDGeneratorTests
-
-- (void)testConstructor {
- XCTAssertEqual([[[FSTTargetIDGenerator alloc] initWithGeneratorID:0 startingAfterID:0] nextID],
- 2);
- XCTAssertEqual([[[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:0] nextID],
- 1);
-
- XCTAssertEqual([[FSTTargetIDGenerator generatorForLocalStoreStartingAfterID:0] nextID], 2);
- XCTAssertEqual([[FSTTargetIDGenerator generatorForSyncEngineStartingAfterID:0] nextID], 1);
-}
-
-- (void)testSkipPast {
- FSTTargetIDGenerator *gen =
- [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:-1];
- XCTAssertEqual([gen nextID], 1);
-
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:2];
- XCTAssertEqual([gen nextID], 3);
-
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:4];
- XCTAssertEqual([gen nextID], 5);
-
- for (int i = 4; i < 12; ++i) {
- FSTTargetIDGenerator *gen0 =
- [[FSTTargetIDGenerator alloc] initWithGeneratorID:0 startingAfterID:i];
- FSTTargetIDGenerator *gen1 =
- [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:i];
- XCTAssertEqual([gen0 nextID], i + 2 & ~1, @"Skip failed for index %d", i);
- XCTAssertEqual([gen1 nextID], i + 1 | 1, @"Skip failed for index %d", i);
- }
-
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:12];
- XCTAssertEqual([gen nextID], 13);
-
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:0 startingAfterID:22];
- XCTAssertEqual([gen nextID], 24);
-}
-
-- (void)testIncrement {
- FSTTargetIDGenerator *gen =
- [[FSTTargetIDGenerator alloc] initWithGeneratorID:0 startingAfterID:0];
- XCTAssertEqual([gen nextID], 2);
- XCTAssertEqual([gen nextID], 4);
- XCTAssertEqual([gen nextID], 6);
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:0 startingAfterID:46];
- XCTAssertEqual([gen nextID], 48);
- XCTAssertEqual([gen nextID], 50);
- XCTAssertEqual([gen nextID], 52);
- XCTAssertEqual([gen nextID], 54);
-
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:0];
- XCTAssertEqual([gen nextID], 1);
- XCTAssertEqual([gen nextID], 3);
- XCTAssertEqual([gen nextID], 5);
- gen = [[FSTTargetIDGenerator alloc] initWithGeneratorID:1 startingAfterID:46];
- XCTAssertEqual([gen nextID], 47);
- XCTAssertEqual([gen nextID], 49);
- XCTAssertEqual([gen nextID], 51);
- XCTAssertEqual([gen nextID], 53);
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/Core/FSTTimestampTests.m b/Firestore/Example/Tests/Core/FSTTimestampTests.mm
index a3765fe..a3765fe 100644
--- a/Firestore/Example/Tests/Core/FSTTimestampTests.m
+++ b/Firestore/Example/Tests/Core/FSTTimestampTests.mm
diff --git a/Firestore/Example/Tests/Core/FSTViewSnapshotTest.m b/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm
index 5d3787a..fe3e42d 100644
--- a/Firestore/Example/Tests/Core/FSTViewSnapshotTest.m
+++ b/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm
@@ -107,7 +107,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testViewSnapshotConstructor {
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"a" ]]];
+ FSTQuery *query = FSTTestQuery(@"a");
FSTDocumentSet *documents = [FSTDocumentSet documentSetWithComparator:FSTDocumentComparatorByKey];
FSTDocumentSet *oldDocuments = documents;
documents = [documents documentSetByAddingDocument:FSTTestDoc(@"c/a", 1, @{}, NO)];
diff --git a/Firestore/Example/Tests/Core/FSTViewTests.m b/Firestore/Example/Tests/Core/FSTViewTests.mm
index e6c4510..e6c4510 100644
--- a/Firestore/Example/Tests/Core/FSTViewTests.m
+++ b/Firestore/Example/Tests/Core/FSTViewTests.mm
diff --git a/Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm b/Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm
index 4fc77ed..18dfaf3 100644
--- a/Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm
+++ b/Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm
@@ -17,8 +17,9 @@
#import <XCTest/XCTest.h>
#import <objc/runtime.h>
+#include <gtest/gtest.h>
+
#include "Firestore/Source/Util/FSTAssert.h"
-#include "gtest/gtest.h"
/**
* An XCTest test case that finds C++ test cases written in the GoogleTest framework, runs them, and
diff --git a/Firestore/Example/Tests/Integration/API/FIRCursorTests.m b/Firestore/Example/Tests/Integration/API/FIRCursorTests.mm
index dc9da83..3b5c38f 100644
--- a/Firestore/Example/Tests/Integration/API/FIRCursorTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRCursorTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
diff --git a/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.m b/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm
index 087eb01..3b6a67e 100644
--- a/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
@@ -83,6 +83,13 @@
XCTAssertFalse(result.exists);
}
+- (void)testCanRetrieveDocumentThatDoesNotExist {
+ FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
+ FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
+ XCTAssertNil(result.data);
+ XCTAssertNil(result[@"foo"]);
+}
+
- (void)testCannotUpdateNonexistentDocument {
FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
@@ -603,6 +610,7 @@
} else if (callbacks == 2) {
XCTAssertEqual(docSet.count, 1);
+ XCTAssertTrue([docSet.documents[0] isKindOfClass:[FIRQueryDocumentSnapshot class]]);
XCTAssertEqualObjects(docSet.documents[0].data, newData);
XCTAssertEqual(docSet.documents[0].metadata.hasPendingWrites, YES);
[changeCompletion fulfill];
@@ -844,7 +852,7 @@
FIRFirestore *firestore = doc.firestore;
NSDictionary<NSString *, id> *data = @{@"a" : @"b"};
- [firestore.client disableNetworkWithCompletion:^(NSError *error) {
+ [firestore disableNetworkWithCompletion:^(NSError *error) {
XCTAssertNil(error);
[doc setData:data
@@ -853,7 +861,7 @@
[writeEpectation fulfill];
}];
- [firestore.client enableNetworkWithCompletion:^(NSError *error) {
+ [firestore enableNetworkWithCompletion:^(NSError *error) {
XCTAssertNil(error);
[networkExpectation fulfill];
}];
@@ -883,7 +891,7 @@
__weak FIRDocumentReference *weakDoc = doc;
- [firestore.client disableNetworkWithCompletion:^(NSError *error) {
+ [firestore disableNetworkWithCompletion:^(NSError *error) {
XCTAssertNil(error);
[doc setData:data
completion:^(NSError *_Nullable error) {
@@ -904,7 +912,7 @@
// Verify that we are reading from cache.
XCTAssertTrue(snapshot.metadata.fromCache);
XCTAssertEqualObjects(snapshot.data, data);
- [firestore.client enableNetworkWithCompletion:^(NSError *error) {
+ [firestore enableNetworkWithCompletion:^(NSError *error) {
[networkExpectation fulfill];
}];
}];
@@ -931,4 +939,25 @@
[self readSnapshotForRef:[self documentRef] requireOnline:YES];
}
+- (void)testCanDisableNetwork {
+ FIRDocumentReference *doc = [self documentRef];
+ FIRFirestore *firestore = doc.firestore;
+
+ [firestore enableNetworkWithCompletion:[self completionForExpectationWithName:@"Enable network"]];
+ [self awaitExpectations];
+ [firestore
+ enableNetworkWithCompletion:[self completionForExpectationWithName:@"Enable network again"]];
+ [self awaitExpectations];
+ [firestore
+ disableNetworkWithCompletion:[self completionForExpectationWithName:@"Disable network"]];
+ [self awaitExpectations];
+ [firestore
+ disableNetworkWithCompletion:[self
+ completionForExpectationWithName:@"Disable network again"]];
+ [self awaitExpectations];
+ [firestore
+ enableNetworkWithCompletion:[self completionForExpectationWithName:@"Final enable network"]];
+ [self awaitExpectations];
+}
+
@end
diff --git a/Firestore/Example/Tests/Integration/API/FIRFieldsTests.m b/Firestore/Example/Tests/Integration/API/FIRFieldsTests.mm
index b647f52..34bd87e 100644
--- a/Firestore/Example/Tests/Integration/API/FIRFieldsTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRFieldsTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
diff --git a/Firestore/Example/Tests/Integration/API/FIRListenerRegistrationTests.m b/Firestore/Example/Tests/Integration/API/FIRListenerRegistrationTests.mm
index 9751844..036ab32 100644
--- a/Firestore/Example/Tests/Integration/API/FIRListenerRegistrationTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRListenerRegistrationTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
@@ -128,35 +128,4 @@
[two remove];
}
-- (void)testWatchSurvivesNetworkDisconnect {
- XCTestExpectation *testExpectiation =
- [self expectationWithDescription:@"testWatchSurvivesNetworkDisconnect"];
-
- FIRCollectionReference *collectionRef = [self collectionRef];
- FIRDocumentReference *docRef = [collectionRef documentWithAutoID];
-
- FIRFirestore *firestore = collectionRef.firestore;
-
- FIRQueryListenOptions *options = [[[FIRQueryListenOptions options]
- includeDocumentMetadataChanges:YES] includeQueryMetadataChanges:YES];
-
- [collectionRef addSnapshotListenerWithOptions:options
- listener:^(FIRQuerySnapshot *snapshot, NSError *error) {
- XCTAssertNil(error);
- if (!snapshot.empty && !snapshot.metadata.fromCache) {
- [testExpectiation fulfill];
- }
- }];
-
- [firestore.client disableNetworkWithCompletion:^(NSError *error) {
- XCTAssertNil(error);
- [docRef setData:@{@"foo" : @"bar"}];
- [firestore.client enableNetworkWithCompletion:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }];
-
- [self awaitExpectations];
-}
-
@end
diff --git a/Firestore/Example/Tests/Integration/API/FIRQueryTests.m b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm
index 180b423..32d746e 100644
--- a/Firestore/Example/Tests/Integration/API/FIRQueryTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
-#import "Firestore/Source/Core/FSTFirestoreClient.h"
-
+#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
+#import "Firestore/Source/API/FIRFirestore+Internal.h"
+#import "Firestore/Source/Core/FSTFirestoreClient.h"
@interface FIRQueryTests : FSTIntegrationTestCase
@end
@@ -111,6 +112,23 @@
XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(snapshot), (@[ @"b", @"a" ]));
}
+- (void)testQueryWithPredicate {
+ FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
+ @"a" : @{@"a" : @1},
+ @"b" : @{@"a" : @2},
+ @"c" : @{@"a" : @3}
+ }];
+
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a < 3"];
+ FIRQuery *query = [collRef queryFilteredUsingPredicate:predicate];
+ query = [query queryOrderedByFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"a" ]]
+ descending:YES];
+
+ FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:query];
+
+ XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(snapshot), (@[ @"b", @"a" ]));
+}
+
- (void)testFilterOnInfinity {
FIRCollectionReference *collRef = [self collectionRefWithDocuments:@{
@"a" : @{@"inf" : @(INFINITY)},
@@ -194,4 +212,90 @@
XCTAssertEqualObjects(FIRQuerySnapshotGetData(docs), (@[ testDocs[@"ab"], testDocs[@"ba"] ]));
}
+- (void)testWatchSurvivesNetworkDisconnect {
+ XCTestExpectation *testExpectiation =
+ [self expectationWithDescription:@"testWatchSurvivesNetworkDisconnect"];
+
+ FIRCollectionReference *collectionRef = [self collectionRef];
+ FIRDocumentReference *docRef = [collectionRef documentWithAutoID];
+
+ FIRFirestore *firestore = collectionRef.firestore;
+
+ FIRQueryListenOptions *options = [[[FIRQueryListenOptions options]
+ includeDocumentMetadataChanges:YES] includeQueryMetadataChanges:YES];
+
+ [collectionRef addSnapshotListenerWithOptions:options
+ listener:^(FIRQuerySnapshot *snapshot, NSError *error) {
+ XCTAssertNil(error);
+ if (!snapshot.empty && !snapshot.metadata.fromCache) {
+ [testExpectiation fulfill];
+ }
+ }];
+
+ [firestore disableNetworkWithCompletion:^(NSError *error) {
+ XCTAssertNil(error);
+ [docRef setData:@{@"foo" : @"bar"}];
+ [firestore enableNetworkWithCompletion:^(NSError *error) {
+ XCTAssertNil(error);
+ }];
+ }];
+
+ [self awaitExpectations];
+}
+
+- (void)testQueriesFireFromCacheWhenOffline {
+ NSDictionary *testDocs = @{
+ @"a" : @{@"foo" : @1},
+ };
+ FIRCollectionReference *collection = [self collectionRefWithDocuments:testDocs];
+
+ FIRQueryListenOptions *options = [[[FIRQueryListenOptions options]
+ includeDocumentMetadataChanges:YES] includeQueryMetadataChanges:YES];
+ id<FIRListenerRegistration> registration =
+ [collection addSnapshotListenerWithOptions:options
+ listener:self.eventAccumulator.valueEventHandler];
+
+ FIRQuerySnapshot *querySnap = [self.eventAccumulator awaitEventWithName:@"initial event"];
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnap), @[ @{ @"foo" : @1 } ]);
+ XCTAssertEqual(querySnap.metadata.isFromCache, NO);
+
+ [self disableNetwork];
+ querySnap = [self.eventAccumulator awaitEventWithName:@"offline event with isFromCache=YES"];
+ XCTAssertEqual(querySnap.metadata.isFromCache, YES);
+
+ // TODO(b/70631617): There's currently a backend bug that prevents us from using a resume token
+ // right away (against hexa at least). So we sleep. :-( :-( Anything over ~10ms seems to be
+ // sufficient.
+ [NSThread sleepForTimeInterval:0.2f];
+
+ [self enableNetwork];
+ querySnap = [self.eventAccumulator awaitEventWithName:@"back online event with isFromCache=NO"];
+ XCTAssertEqual(querySnap.metadata.isFromCache, NO);
+
+ [registration remove];
+}
+
+- (void)testCanHaveMultipleMutationsWhileOffline {
+ FIRCollectionReference *col = [self collectionRef];
+
+ // set a few docs to known values
+ NSDictionary *initialDocs =
+ @{ @"doc1" : @{@"key1" : @"value1"},
+ @"doc2" : @{@"key2" : @"value2"} };
+ [self writeAllDocuments:initialDocs toCollection:col];
+
+ // go offline for the rest of this test
+ [self disableNetwork];
+
+ // apply *multiple* mutations while offline
+ [[col documentWithPath:@"doc1"] setData:@{@"key1b" : @"value1b"}];
+ [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"}];
+
+ FIRQuerySnapshot *result = [self readDocumentSetForRef:col];
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[
+ @{@"key1b" : @"value1b"},
+ @{@"key2b" : @"value2b"},
+ ]));
+}
+
@end
diff --git a/Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.m b/Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.m
deleted file mode 100644
index 2ee3966..0000000
--- a/Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.m
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2017 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 FirebaseFirestore;
-
-#import <XCTest/XCTest.h>
-
-#import "Firestore/Source/Core/FSTFirestoreClient.h"
-
-#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
-#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
-
-@interface FIRServerTimestampTests : FSTIntegrationTestCase
-@end
-
-@implementation FIRServerTimestampTests {
- // Data written in tests via set.
- NSDictionary *_setData;
-
- // Base and update data used for update tests.
- NSDictionary *_initialData;
- NSDictionary *_updateData;
-
- // A document reference to read and write to.
- FIRDocumentReference *_docRef;
-
- // Accumulator used to capture events during the test.
- FSTEventAccumulator *_accumulator;
-
- // Listener registration for a listener maintained during the course of the test.
- id<FIRListenerRegistration> _listenerRegistration;
-}
-
-- (void)setUp {
- [super setUp];
-
- // Data written in tests via set.
- _setData = @{
- @"a" : @42,
- @"when" : [FIRFieldValue fieldValueForServerTimestamp],
- @"deep" : @{@"when" : [FIRFieldValue fieldValueForServerTimestamp]}
- };
-
- // Base and update data used for update tests.
- _initialData = @{ @"a" : @42 };
- _updateData = @{
- @"when" : [FIRFieldValue fieldValueForServerTimestamp],
- @"deep" : @{@"when" : [FIRFieldValue fieldValueForServerTimestamp]}
- };
-
- _docRef = [self documentRef];
- _accumulator = [FSTEventAccumulator accumulatorForTest:self];
- _listenerRegistration = [_docRef addSnapshotListener:_accumulator.handler];
-
- // Wait for initial nil snapshot to avoid potential races.
- FIRDocumentSnapshot *initialSnapshot = [_accumulator awaitEventWithName:@"initial event"];
- XCTAssertFalse(initialSnapshot.exists);
-}
-
-- (void)tearDown {
- [_listenerRegistration remove];
-
- [super tearDown];
-}
-
-// Returns the expected data, with an arbitrary timestamp substituted in.
-- (NSDictionary *)expectedDataWithTimestamp:(id _Nullable)timestamp {
- return @{ @"a" : @42, @"when" : timestamp, @"deep" : @{@"when" : timestamp} };
-}
-
-/** Writes _initialData and waits for the corresponding snapshot. */
-- (void)writeInitialData {
- [self writeDocumentRef:_docRef data:_initialData];
- FIRDocumentSnapshot *initialDataSnap = [_accumulator awaitEventWithName:@"Initial data event."];
- XCTAssertEqualObjects(initialDataSnap.data, _initialData);
-}
-
-/** Waits for a snapshot containing _setData but with NSNull for the timestamps. */
-- (void)waitForLocalEvent {
- FIRDocumentSnapshot *localSnap = [_accumulator awaitEventWithName:@"Local event."];
- XCTAssertEqualObjects(localSnap.data, [self expectedDataWithTimestamp:[NSNull null]]);
-}
-
-/** Waits for a snapshot containing _setData but with resolved server timestamps. */
-- (void)waitForRemoteEvent {
- // server event should have a resolved timestamp; verify it.
- FIRDocumentSnapshot *remoteSnap = [_accumulator awaitEventWithName:@"Remote event"];
- XCTAssertTrue(remoteSnap.exists);
- NSDate *when = remoteSnap[@"when"];
- XCTAssertTrue([when isKindOfClass:[NSDate class]]);
- // Tolerate up to 10 seconds of clock skew between client and server.
- XCTAssertEqualWithAccuracy(when.timeIntervalSinceNow, 0, 10);
-
- // Validate the rest of the document.
- XCTAssertEqualObjects(remoteSnap.data, [self expectedDataWithTimestamp:when]);
-}
-
-- (void)runTransactionBlock:(void (^)(FIRTransaction *transaction))transactionBlock {
- XCTestExpectation *expectation = [self expectationWithDescription:@"transaction complete"];
- [_docRef.firestore runTransactionWithBlock:^id(FIRTransaction *transaction, NSError **pError) {
- transactionBlock(transaction);
- return nil;
- }
- completion:^(id result, NSError *error) {
- XCTAssertNil(error);
- [expectation fulfill];
- }];
- [self awaitExpectations];
-}
-
-- (void)testServerTimestampsWorkViaSet {
- [self writeDocumentRef:_docRef data:_setData];
- [self waitForLocalEvent];
- [self waitForRemoteEvent];
-}
-
-- (void)testServerTimestampsWorkViaUpdate {
- [self writeInitialData];
- [self updateDocumentRef:_docRef data:_updateData];
- [self waitForLocalEvent];
- [self waitForRemoteEvent];
-}
-
-- (void)testServerTimestampsWorkViaTransactionSet {
- [self runTransactionBlock:^(FIRTransaction *transaction) {
- [transaction setData:_setData forDocument:_docRef];
- }];
-
- [self waitForRemoteEvent];
-}
-
-- (void)testServerTimestampsWorkViaTransactionUpdate {
- [self writeInitialData];
- [self runTransactionBlock:^(FIRTransaction *transaction) {
- [transaction updateData:_updateData forDocument:_docRef];
- }];
- [self waitForRemoteEvent];
-}
-
-- (void)testServerTimestampsFailViaUpdateOnNonexistentDocument {
- XCTestExpectation *expectation = [self expectationWithDescription:@"update complete"];
- [_docRef updateData:_updateData
- completion:^(NSError *error) {
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
- XCTAssertEqual(error.code, FIRFirestoreErrorCodeNotFound);
- [expectation fulfill];
- }];
- [self awaitExpectations];
-}
-
-- (void)testServerTimestampsFailViaTransactionUpdateOnNonexistentDocument {
- XCTestExpectation *expectation = [self expectationWithDescription:@"transaction complete"];
- [_docRef.firestore runTransactionWithBlock:^id(FIRTransaction *transaction, NSError **pError) {
- [transaction updateData:_updateData forDocument:_docRef];
- return nil;
- }
- completion:^(id result, NSError *error) {
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
- // TODO(b/35201829): This should be NotFound, but right now we retry transactions on any
- // error and so this turns into Aborted instead.
- // TODO(mikelehen): Actually it's FailedPrecondition, unlike Android. What do we want???
- XCTAssertEqual(error.code, FIRFirestoreErrorCodeFailedPrecondition);
- [expectation fulfill];
- }];
- [self awaitExpectations];
-}
-
-@end
diff --git a/Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.mm b/Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.mm
new file mode 100644
index 0000000..916ce7e
--- /dev/null
+++ b/Firestore/Example/Tests/Integration/API/FIRServerTimestampTests.mm
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2017 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 <FirebaseFirestore/FirebaseFirestore.h>
+
+#import <XCTest/XCTest.h>
+
+#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
+#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
+#import "Firestore/Source/API/FIRFirestore+Internal.h"
+#import "Firestore/Source/Core/FSTFirestoreClient.h"
+
+@interface FIRServerTimestampTests : FSTIntegrationTestCase
+@end
+
+@implementation FIRServerTimestampTests {
+ // Data written in tests via set.
+ NSDictionary *_setData;
+
+ // Base and update data used for update tests.
+ NSDictionary *_initialData;
+ NSDictionary *_updateData;
+
+ // A document reference to read and write to.
+ FIRDocumentReference *_docRef;
+
+ // Accumulator used to capture events during the test.
+ FSTEventAccumulator *_accumulator;
+
+ // Listener registration for a listener maintained during the course of the test.
+ id<FIRListenerRegistration> _listenerRegistration;
+
+ // Snapshot options that return the previous value for pending server timestamps.
+ FIRSnapshotOptions *_returnPreviousValue;
+ FIRSnapshotOptions *_returnEstimatedValue;
+}
+
+- (void)setUp {
+ [super setUp];
+
+ _returnPreviousValue =
+ [FIRSnapshotOptions serverTimestampBehavior:FIRServerTimestampBehaviorPrevious];
+ _returnEstimatedValue =
+ [FIRSnapshotOptions serverTimestampBehavior:FIRServerTimestampBehaviorEstimate];
+
+ // Data written in tests via set.
+ _setData = @{
+ @"a" : @42,
+ @"when" : [FIRFieldValue fieldValueForServerTimestamp],
+ @"deep" : @{@"when" : [FIRFieldValue fieldValueForServerTimestamp]}
+ };
+
+ // Base and update data used for update tests.
+ _initialData = @{ @"a" : @42 };
+ _updateData = @{
+ @"when" : [FIRFieldValue fieldValueForServerTimestamp],
+ @"deep" : @{@"when" : [FIRFieldValue fieldValueForServerTimestamp]}
+ };
+
+ _docRef = [self documentRef];
+ _accumulator = [FSTEventAccumulator accumulatorForTest:self];
+ _listenerRegistration = [_docRef addSnapshotListener:_accumulator.valueEventHandler];
+
+ // Wait for initial nil snapshot to avoid potential races.
+ FIRDocumentSnapshot *initialSnapshot = [_accumulator awaitEventWithName:@"initial event"];
+ XCTAssertFalse(initialSnapshot.exists);
+}
+
+- (void)tearDown {
+ [_listenerRegistration remove];
+
+ [super tearDown];
+}
+
+#pragma mark - Test Helpers
+
+/** Returns the expected data, with the specified timestamp substituted in. */
+- (NSDictionary *)expectedDataWithTimestamp:(nullable id)timestamp {
+ return @{ @"a" : @42, @"when" : timestamp, @"deep" : @{@"when" : timestamp} };
+}
+
+/** Writes _initialData and waits for the corresponding snapshot. */
+- (void)writeInitialData {
+ [self writeDocumentRef:_docRef data:_initialData];
+ FIRDocumentSnapshot *initialDataSnap = [_accumulator awaitEventWithName:@"Initial data event."];
+ XCTAssertEqualObjects(initialDataSnap.data, _initialData);
+}
+
+/** Waits for a snapshot with local writes. */
+- (FIRDocumentSnapshot *)waitForLocalEvent {
+ FIRDocumentSnapshot *snapshot;
+ do {
+ snapshot = [_accumulator awaitEventWithName:@"Local event."];
+ } while (!snapshot.metadata.hasPendingWrites);
+ return snapshot;
+}
+
+/** Waits for a snapshot that has no pending writes */
+- (FIRDocumentSnapshot *)waitForRemoteEvent {
+ FIRDocumentSnapshot *snapshot;
+ do {
+ snapshot = [_accumulator awaitEventWithName:@"Remote event."];
+ } while (snapshot.metadata.hasPendingWrites);
+ return snapshot;
+}
+
+/** Verifies a snapshot containing _setData but with NSNull for the timestamps. */
+- (void)verifyTimestampsAreNullInSnapshot:(FIRDocumentSnapshot *)snapshot {
+ XCTAssertEqualObjects(snapshot.data, [self expectedDataWithTimestamp:[NSNull null]]);
+}
+
+/** Verifies a snapshot containing _setData but with a local estimate for the timestamps. */
+- (void)verifyTimestampsAreEstimatedInSnapshot:(FIRDocumentSnapshot *)snapshot {
+ id timestamp = [snapshot valueForField:@"when" options:_returnEstimatedValue];
+ XCTAssertTrue([timestamp isKindOfClass:[NSDate class]]);
+ XCTAssertEqualObjects([snapshot dataWithOptions:_returnEstimatedValue],
+ [self expectedDataWithTimestamp:timestamp]);
+}
+
+/**
+ * Verifies a snapshot containing _setData but using the previous field value for server
+ * timestamps.
+ */
+- (void)verifyTimestampsInSnapshot:(FIRDocumentSnapshot *)snapshot
+ fromPreviousSnapshot:(nullable FIRDocumentSnapshot *)previousSnapshot {
+ if (previousSnapshot == nil) {
+ XCTAssertEqualObjects([snapshot dataWithOptions:_returnPreviousValue],
+ [self expectedDataWithTimestamp:[NSNull null]]);
+ } else {
+ XCTAssertEqualObjects([snapshot dataWithOptions:_returnPreviousValue],
+ [self expectedDataWithTimestamp:previousSnapshot[@"when"]]);
+ }
+}
+
+/** Verifies a snapshot containing _setData but with resolved server timestamps. */
+- (void)verifySnapshotWithResolvedTimestamps:(FIRDocumentSnapshot *)snapshot {
+ XCTAssertTrue(snapshot.exists);
+ NSDate *when = snapshot[@"when"];
+ XCTAssertTrue([when isKindOfClass:[NSDate class]]);
+ // Tolerate up to 10 seconds of clock skew between client and server.
+ XCTAssertEqualWithAccuracy(when.timeIntervalSinceNow, 0, 10);
+
+ // Validate the rest of the document.
+ XCTAssertEqualObjects(snapshot.data, [self expectedDataWithTimestamp:when]);
+}
+
+/** Runs a transaction block. */
+- (void)runTransactionBlock:(void (^)(FIRTransaction *transaction))transactionBlock {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"transaction complete"];
+ [_docRef.firestore runTransactionWithBlock:^id(FIRTransaction *transaction, NSError **pError) {
+ transactionBlock(transaction);
+ return nil;
+ }
+ completion:^(id result, NSError *error) {
+ XCTAssertNil(error);
+ [expectation fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+#pragma mark - Test Cases
+
+- (void)testServerTimestampsWorkViaSet {
+ [self writeDocumentRef:_docRef data:_setData];
+ [self verifyTimestampsAreNullInSnapshot:[self waitForLocalEvent]];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+}
+
+- (void)testServerTimestampsWorkViaUpdate {
+ [self writeInitialData];
+ [self updateDocumentRef:_docRef data:_updateData];
+ [self verifyTimestampsAreNullInSnapshot:[self waitForLocalEvent]];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+}
+
+- (void)testServerTimestampsWithEstimatedValue {
+ [self writeDocumentRef:_docRef data:_setData];
+ [self verifyTimestampsAreEstimatedInSnapshot:[self waitForLocalEvent]];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+}
+
+- (void)testServerTimestampsWithPreviousValue {
+ [self writeDocumentRef:_docRef data:_setData];
+ [self verifyTimestampsInSnapshot:[self waitForLocalEvent] fromPreviousSnapshot:nil];
+ FIRDocumentSnapshot *remoteSnapshot = [self waitForRemoteEvent];
+
+ [_docRef updateData:_updateData];
+ [self verifyTimestampsInSnapshot:[self waitForLocalEvent] fromPreviousSnapshot:remoteSnapshot];
+
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+}
+
+- (void)testServerTimestampsWithPreviousValueOfDifferentType {
+ [self writeDocumentRef:_docRef data:_setData];
+ [self verifyTimestampsInSnapshot:[self waitForLocalEvent] fromPreviousSnapshot:nil];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+
+ [_docRef updateData:@{@"a" : [FIRFieldValue fieldValueForServerTimestamp]}];
+ FIRDocumentSnapshot *localSnapshot = [self waitForLocalEvent];
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a"], [NSNull null]);
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a" options:_returnPreviousValue], @42);
+ XCTAssertTrue([[localSnapshot valueForField:@"a" options:_returnEstimatedValue]
+ isKindOfClass:[NSDate class]]);
+
+ FIRDocumentSnapshot *remoteSnapshot = [self waitForRemoteEvent];
+ XCTAssertTrue([[remoteSnapshot valueForField:@"a"] isKindOfClass:[NSDate class]]);
+ XCTAssertTrue([[remoteSnapshot valueForField:@"a" options:_returnPreviousValue]
+ isKindOfClass:[NSDate class]]);
+ XCTAssertTrue([[remoteSnapshot valueForField:@"a" options:_returnEstimatedValue]
+ isKindOfClass:[NSDate class]]);
+}
+
+- (void)testServerTimestampsWithConsecutiveUpdates {
+ [self writeDocumentRef:_docRef data:_setData];
+ [self verifyTimestampsInSnapshot:[self waitForLocalEvent] fromPreviousSnapshot:nil];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+
+ [self disableNetwork];
+
+ [_docRef updateData:@{@"a" : [FIRFieldValue fieldValueForServerTimestamp]}];
+ FIRDocumentSnapshot *localSnapshot = [self waitForLocalEvent];
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a" options:_returnPreviousValue], @42);
+
+ [_docRef updateData:@{@"a" : [FIRFieldValue fieldValueForServerTimestamp]}];
+ localSnapshot = [self waitForLocalEvent];
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a" options:_returnPreviousValue], @42);
+
+ [self enableNetwork];
+
+ FIRDocumentSnapshot *remoteSnapshot = [self waitForRemoteEvent];
+ XCTAssertTrue([[remoteSnapshot valueForField:@"a"] isKindOfClass:[NSDate class]]);
+}
+
+- (void)testServerTimestampsPreviousValueFromLocalMutation {
+ [self writeDocumentRef:_docRef data:_setData];
+ [self verifyTimestampsInSnapshot:[self waitForLocalEvent] fromPreviousSnapshot:nil];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+
+ [self disableNetwork];
+
+ [_docRef updateData:@{@"a" : [FIRFieldValue fieldValueForServerTimestamp]}];
+ FIRDocumentSnapshot *localSnapshot = [self waitForLocalEvent];
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a" options:_returnPreviousValue], @42);
+
+ [_docRef updateData:@{ @"a" : @1337 }];
+ localSnapshot = [self waitForLocalEvent];
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a"], @1337);
+
+ [_docRef updateData:@{@"a" : [FIRFieldValue fieldValueForServerTimestamp]}];
+ localSnapshot = [self waitForLocalEvent];
+ XCTAssertEqualObjects([localSnapshot valueForField:@"a" options:_returnPreviousValue], @1337);
+
+ [self enableNetwork];
+
+ FIRDocumentSnapshot *remoteSnapshot = [self waitForRemoteEvent];
+ XCTAssertTrue([[remoteSnapshot valueForField:@"a"] isKindOfClass:[NSDate class]]);
+}
+
+- (void)testServerTimestampsWorkViaTransactionSet {
+ [self runTransactionBlock:^(FIRTransaction *transaction) {
+ [transaction setData:_setData forDocument:_docRef];
+ }];
+
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+}
+
+- (void)testServerTimestampsWorkViaTransactionUpdate {
+ [self writeInitialData];
+ [self runTransactionBlock:^(FIRTransaction *transaction) {
+ [transaction updateData:_updateData forDocument:_docRef];
+ }];
+ [self verifySnapshotWithResolvedTimestamps:[self waitForRemoteEvent]];
+}
+
+- (void)testServerTimestampsFailViaUpdateOnNonexistentDocument {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"update complete"];
+ [_docRef updateData:_updateData
+ completion:^(NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeNotFound);
+ [expectation fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+- (void)testServerTimestampsFailViaTransactionUpdateOnNonexistentDocument {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"transaction complete"];
+ [_docRef.firestore runTransactionWithBlock:^id(FIRTransaction *transaction, NSError **pError) {
+ [transaction updateData:_updateData forDocument:_docRef];
+ return nil;
+ }
+ completion:^(id result, NSError *error) {
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
+ // TODO(b/35201829): This should be NotFound, but right now we retry transactions on any
+ // error and so this turns into Aborted instead.
+ // TODO(mikelehen): Actually it's FailedPrecondition, unlike Android. What do we want???
+ XCTAssertEqual(error.code, FIRFirestoreErrorCodeFailedPrecondition);
+ [expectation fulfill];
+ }];
+ [self awaitExpectations];
+}
+
+@end
diff --git a/Firestore/Example/Tests/Integration/API/FIRTypeTests.m b/Firestore/Example/Tests/Integration/API/FIRTypeTests.mm
index 638835f..5140b90 100644
--- a/Firestore/Example/Tests/Integration/API/FIRTypeTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRTypeTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
@@ -40,7 +40,8 @@
- (void)testCanReadAndWriteArrayFields {
[self assertSuccessfulRoundtrip:@{
- @"array" : @[ @1, @"foo", @{@"deep" : @YES}, [NSNull null] ]
+ @"array" : @[ @1, @"foo",
+ @{ @"deep" : @YES }, [NSNull null] ]
}];
}
diff --git a/Firestore/Example/Tests/Integration/API/FIRValidationTests.m b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
index a318c47..49e572a 100644
--- a/Firestore/Example/Tests/Integration/API/FIRValidationTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
@@ -169,7 +169,7 @@
}
- (void)testWritesWithIndirectlyNestedArraysSucceed {
- NSDictionary<NSString *, id> *data = @{ @"nested-array" : @[ @1, @{@"foo" : @[ @2 ]} ] };
+ NSDictionary<NSString *, id> *data = @{ @"nested-array" : @[ @1, @{ @"foo" : @[ @2 ] } ] };
FIRDocumentReference *ref = [self documentRef];
FIRDocumentReference *ref2 = [self documentRef];
diff --git a/Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.m b/Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.mm
index 562c29f..9a2fef1 100644
--- a/Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.m
+++ b/Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
@@ -35,6 +35,29 @@
[self awaitExpectations];
}
+- (void)testCommitWithoutCompletionHandler {
+ FIRDocumentReference *doc = [self documentRef];
+ FIRWriteBatch *batch1 = [doc.firestore batch];
+ [batch1 setData:@{@"aa" : @"bb"} forDocument:doc];
+ [batch1 commitWithCompletion:nil];
+ FIRDocumentSnapshot *snapshot1 = [self readDocumentForRef:doc];
+ XCTAssertTrue(snapshot1.exists);
+ XCTAssertEqualObjects(snapshot1.data, @{@"aa" : @"bb"});
+
+ FIRWriteBatch *batch2 = [doc.firestore batch];
+ [batch2 setData:@{@"cc" : @"dd"} forDocument:doc];
+ [batch2 commit];
+
+ // TODO(b/70631617): There's currently a backend bug that prevents us from using a resume token
+ // right away (against hexa at least). So we sleep. :-( :-( Anything over ~10ms seems to be
+ // sufficient.
+ [NSThread sleepForTimeInterval:0.2f];
+
+ FIRDocumentSnapshot *snapshot2 = [self readDocumentForRef:doc];
+ XCTAssertTrue(snapshot2.exists);
+ XCTAssertEqualObjects(snapshot2.data, @{@"cc" : @"dd"});
+}
+
- (void)testSetDocuments {
FIRDocumentReference *doc = [self documentRef];
XCTestExpectation *batchExpectation = [self expectationWithDescription:@"batch written"];
@@ -131,7 +154,7 @@
FSTEventAccumulator *accumulator = [FSTEventAccumulator accumulatorForTest:self];
[collection addSnapshotListenerWithOptions:[[FIRQueryListenOptions options]
includeQueryMetadataChanges:YES]
- listener:accumulator.handler];
+ listener:accumulator.valueEventHandler];
FIRQuerySnapshot *initialSnap = [accumulator awaitEventWithName:@"initial event"];
XCTAssertEqual(initialSnap.count, 0);
@@ -161,7 +184,7 @@
FSTEventAccumulator *accumulator = [FSTEventAccumulator accumulatorForTest:self];
[collection addSnapshotListenerWithOptions:[[FIRQueryListenOptions options]
includeQueryMetadataChanges:YES]
- listener:accumulator.handler];
+ listener:accumulator.valueEventHandler];
FIRQuerySnapshot *initialSnap = [accumulator awaitEventWithName:@"initial event"];
XCTAssertEqual(initialSnap.count, 0);
@@ -195,7 +218,7 @@
FSTEventAccumulator *accumulator = [FSTEventAccumulator accumulatorForTest:self];
[collection addSnapshotListenerWithOptions:[[FIRQueryListenOptions options]
includeQueryMetadataChanges:YES]
- listener:accumulator.handler];
+ listener:accumulator.valueEventHandler];
FIRQuerySnapshot *initialSnap = [accumulator awaitEventWithName:@"initial event"];
XCTAssertEqual(initialSnap.count, 0);
@@ -227,7 +250,7 @@
FSTEventAccumulator *accumulator = [FSTEventAccumulator accumulatorForTest:self];
[doc
addSnapshotListenerWithOptions:[[FIRDocumentListenOptions options] includeMetadataChanges:YES]
- listener:accumulator.handler];
+ listener:accumulator.valueEventHandler];
FIRDocumentSnapshot *initialSnap = [accumulator awaitEventWithName:@"initial event"];
XCTAssertFalse(initialSnap.exists);
diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.m b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm
index 047f059..bf56367 100644
--- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.m
+++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <GRPCClient/GRPCCall+ChannelCredentials.h>
#import <GRPCClient/GRPCCall+Tests.h>
diff --git a/Firestore/Example/Tests/Integration/FSTSmokeTests.m b/Firestore/Example/Tests/Integration/FSTSmokeTests.mm
index 847474a..cb726b8 100644
--- a/Firestore/Example/Tests/Integration/FSTSmokeTests.m
+++ b/Firestore/Example/Tests/Integration/FSTSmokeTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
@@ -48,7 +48,7 @@
[self writeDocumentRef:writerRef data:data];
id<FIRListenerRegistration> listenerRegistration =
- [readerRef addSnapshotListener:self.eventAccumulator.handler];
+ [readerRef addSnapshotListener:self.eventAccumulator.valueEventHandler];
FIRDocumentSnapshot *doc = [self.eventAccumulator awaitEventWithName:@"snapshot"];
XCTAssertEqual([doc class], [FIRDocumentSnapshot class]);
@@ -62,7 +62,7 @@
[self readerAndWriterOnDocumentRef:^(NSString *path, FIRDocumentReference *readerRef,
FIRDocumentReference *writerRef) {
id<FIRListenerRegistration> listenerRegistration =
- [readerRef addSnapshotListener:self.eventAccumulator.handler];
+ [readerRef addSnapshotListener:self.eventAccumulator.valueEventHandler];
FIRDocumentSnapshot *doc1 = [self.eventAccumulator awaitEventWithName:@"null snapshot"];
XCTAssertFalse(doc1.exists);
@@ -82,7 +82,7 @@
- (void)testWillFireValueEventsForEmptyCollections {
FIRCollectionReference *collection = [self.db collectionWithPath:@"empty-collection"];
id<FIRListenerRegistration> listenerRegistration =
- [collection addSnapshotListener:self.eventAccumulator.handler];
+ [collection addSnapshotListener:self.eventAccumulator.valueEventHandler];
FIRQuerySnapshot *snap = [self.eventAccumulator awaitEventWithName:@"empty query snapshot"];
XCTAssertEqual([snap class], [FIRQuerySnapshot class]);
diff --git a/Firestore/Example/Tests/Integration/FSTStreamTests.m b/Firestore/Example/Tests/Integration/FSTStreamTests.mm
index bbdf372..bbdf372 100644
--- a/Firestore/Example/Tests/Integration/FSTStreamTests.m
+++ b/Firestore/Example/Tests/Integration/FSTStreamTests.mm
diff --git a/Firestore/Example/Tests/Integration/FSTTransactionTests.m b/Firestore/Example/Tests/Integration/FSTTransactionTests.mm
index 2e828c9..21803ea 100644
--- a/Firestore/Example/Tests/Integration/FSTTransactionTests.m
+++ b/Firestore/Example/Tests/Integration/FSTTransactionTests.mm
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@import FirebaseFirestore;
+#import <FirebaseFirestore/FirebaseFirestore.h>
#import <XCTest/XCTest.h>
#include <libkern/OSAtomic.h>
diff --git a/Firestore/Example/Tests/Local/FSTEagerGarbageCollectorTests.m b/Firestore/Example/Tests/Local/FSTEagerGarbageCollectorTests.mm
index 1dd6d62..53f0202 100644
--- a/Firestore/Example/Tests/Local/FSTEagerGarbageCollectorTests.m
+++ b/Firestore/Example/Tests/Local/FSTEagerGarbageCollectorTests.mm
@@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
FSTReferenceSet *referenceSet = [[FSTReferenceSet alloc] init];
[gc addGarbageSource:referenceSet];
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:@"foo/bar"];
+ FSTDocumentKey *key = FSTTestDocKey(@"foo/bar");
[referenceSet addReferenceToKey:key forID:1];
FSTAssertEqualSets([gc collectGarbage], @[]);
XCTAssertFalse([referenceSet isEmpty]);
@@ -50,9 +50,9 @@ NS_ASSUME_NONNULL_BEGIN
FSTReferenceSet *referenceSet = [[FSTReferenceSet alloc] init];
[gc addGarbageSource:referenceSet];
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"foo/bar"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"foo/baz"];
- FSTDocumentKey *key3 = [FSTDocumentKey keyWithPathString:@"foo/blah"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"foo/bar");
+ FSTDocumentKey *key2 = FSTTestDocKey(@"foo/baz");
+ FSTDocumentKey *key3 = FSTTestDocKey(@"foo/blah");
[referenceSet addReferenceToKey:key1 forID:1];
[referenceSet addReferenceToKey:key2 forID:1];
[referenceSet addReferenceToKey:key3 forID:2];
@@ -77,12 +77,12 @@ NS_ASSUME_NONNULL_BEGIN
[gc addGarbageSource:localViews];
[gc addGarbageSource:mutations];
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"foo/bar"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"foo/bar");
[remoteTargets addReferenceToKey:key1 forID:1];
[localViews addReferenceToKey:key1 forID:1];
[mutations addReferenceToKey:key1 forID:10];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"foo/baz"];
+ FSTDocumentKey *key2 = FSTTestDocKey(@"foo/baz");
[mutations addReferenceToKey:key2 forID:10];
XCTAssertFalse([remoteTargets isEmpty]);
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBLocalStoreTests.m b/Firestore/Example/Tests/Local/FSTLevelDBLocalStoreTests.mm
index f71f5c9..f71f5c9 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBLocalStoreTests.m
+++ b/Firestore/Example/Tests/Local/FSTLevelDBLocalStoreTests.mm
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
new file mode 100644
index 0000000..8ef0e94
--- /dev/null
+++ b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 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 <XCTest/XCTest.h>
+#include <leveldb/db.h>
+
+#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
+#import "Firestore/Source/Local/FSTLevelDBMigrations.h"
+#import "Firestore/Source/Local/FSTLevelDBQueryCache.h"
+
+#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+using leveldb::DB;
+using leveldb::Options;
+using leveldb::Status;
+
+@interface FSTLevelDBMigrationsTests : XCTestCase
+@end
+
+@implementation FSTLevelDBMigrationsTests {
+ std::shared_ptr<DB> _db;
+}
+
+- (void)setUp {
+ Options options;
+ options.error_if_exists = true;
+ options.create_if_missing = true;
+
+ NSString *dir = [FSTPersistenceTestHelpers levelDBDir];
+ DB *db;
+ Status status = DB::Open(options, [dir UTF8String], &db);
+ XCTAssert(status.ok(), @"Failed to create db: %s", status.ToString().c_str());
+ _db.reset(db);
+}
+
+- (void)tearDown {
+ _db.reset();
+}
+
+- (void)testAddsTargetGlobal {
+ FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
+ XCTAssertNil(metadata, @"Not expecting metadata yet, we should have an empty db");
+ [FSTLevelDBMigrations runMigrationsOnDB:_db];
+ metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
+ XCTAssertNotNil(metadata, @"Migrations should have added the metadata");
+}
+
+- (void)testSetsVersionNumber {
+ FSTLevelDBSchemaVersion initial = [FSTLevelDBMigrations schemaVersionForDB:_db];
+ XCTAssertEqual(0, initial, "No version should be equivalent to 0");
+
+ // Pick an arbitrary high migration number and migrate to it.
+ [FSTLevelDBMigrations runMigrationsOnDB:_db];
+ FSTLevelDBSchemaVersion actual = [FSTLevelDBMigrations schemaVersionForDB:_db];
+ XCTAssertGreaterThan(actual, 0, @"Expected to migrate to a schema version > 0");
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
index 6c26fd9..fe79598 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
@@ -19,7 +19,6 @@
#import <XCTest/XCTest.h>
#include <leveldb/db.h>
-#include "Firestore/Port/ordered_code.h"
#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
#import "Firestore/Source/Auth/FSTUser.h"
#import "Firestore/Source/Local/FSTLevelDB.h"
@@ -29,6 +28,8 @@
#import "Firestore/Example/Tests/Local/FSTMutationQueueTests.h"
#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
+#include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
+
NS_ASSUME_NONNULL_BEGIN
using leveldb::DB;
@@ -36,7 +37,7 @@ using leveldb::Slice;
using leveldb::Status;
using leveldb::WriteOptions;
using Firestore::StringView;
-using Firestore::OrderedCode;
+using firebase::firestore::util::OrderedCode;
// A dummy mutation value, useful for testing code that's known to examine only mutation keys.
static const char *kDummy = "1";
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBQueryCacheTests.m b/Firestore/Example/Tests/Local/FSTLevelDBQueryCacheTests.mm
index 929ab9e..929ab9e 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBQueryCacheTests.m
+++ b/Firestore/Example/Tests/Local/FSTLevelDBQueryCacheTests.mm
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBRemoteDocumentCacheTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBRemoteDocumentCacheTests.mm
index 1f84aa6..638ab2f 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBRemoteDocumentCacheTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBRemoteDocumentCacheTests.mm
@@ -18,16 +18,17 @@
#include <leveldb/db.h>
-#include "Firestore/Port/ordered_code.h"
#import "Firestore/Source/Local/FSTLevelDB.h"
#import "Firestore/Source/Local/FSTLevelDBKey.h"
#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
+#include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
+
NS_ASSUME_NONNULL_BEGIN
using leveldb::WriteOptions;
-using Firestore::OrderedCode;
+using firebase::firestore::util::OrderedCode;
// A dummy document value, useful for testing code that's known to examine only document keys.
static const char *kDummy = "1";
diff --git a/Firestore/Example/Tests/Local/FSTLocalSerializerTests.m b/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm
index 90f9ca3..95b9b11 100644
--- a/Firestore/Example/Tests/Local/FSTLocalSerializerTests.m
+++ b/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm
@@ -70,7 +70,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testEncodesMutationBatch {
FSTMutation *set = FSTTestSetMutation(@"foo/bar", @{ @"a" : @"b", @"num" : @1 });
FSTMutation *patch = [[FSTPatchMutation alloc]
- initWithKey:[FSTDocumentKey keyWithPathString:@"bar/baz"]
+ initWithKey:FSTTestDocKey(@"bar/baz")
fieldMask:[[FSTFieldMask alloc] initWithFields:@[ FSTTestFieldPath(@"a") ]]
value:FSTTestObjectValue(
@{ @"a" : @"b",
@@ -157,6 +157,7 @@ NS_ASSUME_NONNULL_BEGIN
FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query
targetID:targetID
+ listenSequenceNumber:10
purpose:FSTQueryPurposeListen
snapshotVersion:version
resumeToken:resumeToken];
@@ -166,6 +167,7 @@ NS_ASSUME_NONNULL_BEGIN
FSTPBTarget *expected = [FSTPBTarget message];
expected.targetId = targetID;
+ expected.lastListenSequenceNumber = 10;
expected.snapshotVersion.nanos = 1039000;
expected.resumeToken = [resumeToken copy];
expected.query.parent = queryTarget.parent;
diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.m b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm
index 245e1c4..45d1815 100644
--- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.m
+++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm
@@ -196,8 +196,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
NSEnumerator<NSString *> *keyPathEnumerator = keyPaths.objectEnumerator; \
[actual enumerateKeysAndObjectsUsingBlock:^(FSTDocumentKey * actualKey, \
FSTMaybeDocument * value, BOOL * stop) { \
- FSTDocumentKey *expectedKey = \
- [FSTDocumentKey keyWithPathString:[keyPathEnumerator nextObject]]; \
+ FSTDocumentKey *expectedKey = FSTTestDocKey([keyPathEnumerator nextObject]); \
XCTAssertEqualObjects(actualKey, expectedKey); \
XCTAssertTrue([value isKindOfClass:[FSTDeletedDocument class]]); \
}]; \
@@ -213,11 +212,11 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
} while (0)
/** Asserts that the given local store does not contain the given document. */
-#define FSTAssertNotContains(keyPathString) \
- do { \
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:keyPathString]; \
- FSTMaybeDocument *actual = [self.localStore readDocument:key]; \
- XCTAssertNil(actual); \
+#define FSTAssertNotContains(keyPathString) \
+ do { \
+ FSTDocumentKey *key = FSTTestDocKey(keyPathString); \
+ FSTMaybeDocument *actual = [self.localStore readDocument:key]; \
+ XCTAssertNil(actual); \
} while (0)
- (void)testMutationBatchKeys {
@@ -261,7 +260,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
if ([self isTestBaseClass]) return;
// Start a query that requires acks to be held.
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo");
[self allocateQuery:query];
[self writeMutation:FSTTestSetMutation(@"foo/bar", @{@"foo" : @"bar"})];
@@ -554,7 +553,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
- (void)testCollectsGarbageAfterChangeBatch {
if ([self isTestBaseClass]) return;
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo");
[self allocateQuery:query];
FSTAssertTargetID(2);
@@ -637,7 +636,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
- (void)testPinsDocumentsInTheLocalView {
if ([self isTestBaseClass]) return;
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo");
[self allocateQuery:query];
FSTAssertTargetID(2);
@@ -685,7 +684,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
FSTTestSetMutation(@"foo/baz", @{@"foo" : @"baz"}),
FSTTestSetMutation(@"foo/bar/Foo/Bar", @{@"Foo" : @"Bar"})
]];
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo", @"bar" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo/bar");
FSTDocumentDictionary *docs = [self.localStore executeQuery:query];
XCTAssertEqualObjects([docs values], @[ FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES) ]);
}
@@ -700,7 +699,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
FSTTestSetMutation(@"foo/bar/Foo/Bar", @{@"Foo" : @"Bar"}),
FSTTestSetMutation(@"fooo/blah", @{@"fooo" : @"blah"})
]];
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo");
FSTDocumentDictionary *docs = [self.localStore executeQuery:query];
XCTAssertEqualObjects([docs values], (@[
FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES),
@@ -711,7 +710,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
- (void)testCanExecuteMixedCollectionQueries {
if ([self isTestBaseClass]) return;
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo");
[self allocateQuery:query];
FSTAssertTargetID(2);
@@ -736,7 +735,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
// This test only works in the absence of the FSTEagerGarbageCollector.
[self restartWithNoopGarbageCollector];
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo", @"bar" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo/bar");
FSTQueryData *queryData = [self.localStore allocateQuery:query];
FSTBoxedTargetID *targetID = @(queryData.targetID);
NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000);
@@ -770,7 +769,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation,
if ([self isTestBaseClass]) return;
[self restartWithNoopGarbageCollector];
- FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"foo" ]]];
+ FSTQuery *query = FSTTestQuery(@"foo");
[self allocateQuery:query];
FSTAssertTargetID(2);
diff --git a/Firestore/Example/Tests/Local/FSTMemoryLocalStoreTests.m b/Firestore/Example/Tests/Local/FSTMemoryLocalStoreTests.mm
index b78239e..b78239e 100644
--- a/Firestore/Example/Tests/Local/FSTMemoryLocalStoreTests.m
+++ b/Firestore/Example/Tests/Local/FSTMemoryLocalStoreTests.mm
diff --git a/Firestore/Example/Tests/Local/FSTMemoryMutationQueueTests.m b/Firestore/Example/Tests/Local/FSTMemoryMutationQueueTests.mm
index ab7afee..ab7afee 100644
--- a/Firestore/Example/Tests/Local/FSTMemoryMutationQueueTests.m
+++ b/Firestore/Example/Tests/Local/FSTMemoryMutationQueueTests.mm
diff --git a/Firestore/Example/Tests/Local/FSTMemoryQueryCacheTests.m b/Firestore/Example/Tests/Local/FSTMemoryQueryCacheTests.mm
index fb7df6b..fb7df6b 100644
--- a/Firestore/Example/Tests/Local/FSTMemoryQueryCacheTests.m
+++ b/Firestore/Example/Tests/Local/FSTMemoryQueryCacheTests.mm
diff --git a/Firestore/Example/Tests/Local/FSTMemoryRemoteDocumentCacheTests.m b/Firestore/Example/Tests/Local/FSTMemoryRemoteDocumentCacheTests.mm
index 162eef0..162eef0 100644
--- a/Firestore/Example/Tests/Local/FSTMemoryRemoteDocumentCacheTests.m
+++ b/Firestore/Example/Tests/Local/FSTMemoryRemoteDocumentCacheTests.mm
diff --git a/Firestore/Example/Tests/Local/FSTMutationQueueTests.m b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm
index f168ac9..020a0a7 100644
--- a/Firestore/Example/Tests/Local/FSTMutationQueueTests.m
+++ b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm
@@ -301,7 +301,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.persistence commitGroup:group];
NSArray<FSTMutationBatch *> *expected = @[ batches[1], batches[2], batches[4] ];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"foo")];
+ FSTQuery *query = FSTTestQuery(@"foo");
NSArray<FSTMutationBatch *> *matches =
[self.mutationQueue allMutationBatchesAffectingQuery:query];
diff --git a/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h b/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h
index 936bacf..5859d4b 100644
--- a/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h
+++ b/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h
@@ -24,6 +24,12 @@ NS_ASSUME_NONNULL_BEGIN
@interface FSTPersistenceTestHelpers : NSObject
/**
+ * @return The directory where a leveldb instance can store data files. Any files that existed
+ * there will be deleted first.
+ */
++ (NSString *)levelDBDir;
+
+/**
* Creates and starts a new FSTLevelDB instance for testing, destroying any previous contents
* if they existed.
*
diff --git a/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.m b/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.mm
index c773b12..e9e129d 100644
--- a/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.m
+++ b/Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.mm
@@ -26,10 +26,9 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FSTPersistenceTestHelpers
-+ (FSTLevelDB *)levelDBPersistence {
++ (NSString *)levelDBDir {
NSError *error;
NSFileManager *files = [NSFileManager defaultManager];
-
NSString *dir =
[NSTemporaryDirectory() stringByAppendingPathComponent:@"FSTPersistenceTestHelpers"];
if ([files fileExistsAtPath:dir]) {
@@ -40,12 +39,18 @@ NS_ASSUME_NONNULL_BEGIN
format:@"Failed to clean up leveldb path %@: %@", dir, error];
}
}
+ return dir;
+}
+
++ (FSTLevelDB *)levelDBPersistence {
+ NSString *dir = [self levelDBDir];
FSTDatabaseID *databaseID = [FSTDatabaseID databaseIDWithProject:@"p" database:@"d"];
FSTSerializerBeta *remoteSerializer = [[FSTSerializerBeta alloc] initWithDatabaseID:databaseID];
FSTLocalSerializer *serializer =
[[FSTLocalSerializer alloc] initWithRemoteSerializer:remoteSerializer];
FSTLevelDB *db = [[FSTLevelDB alloc] initWithDirectory:dir serializer:serializer];
+ NSError *error;
BOOL success = [db start:&error];
if (!success) {
[NSException raise:NSInternalInconsistencyException
diff --git a/Firestore/Example/Tests/Local/FSTQueryCacheTests.m b/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm
index 1fed440..0c6a2a4 100644
--- a/Firestore/Example/Tests/Local/FSTQueryCacheTests.m
+++ b/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm
@@ -31,12 +31,18 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FSTQueryCacheTests {
FSTQuery *_queryRooms;
+ FSTListenSequenceNumber _previousSequenceNumber;
+ FSTTargetID _previousTargetID;
+ FSTTestSnapshotVersion _previousSnapshotVersion;
}
- (void)setUp {
[super setUp];
_queryRooms = FSTTestQuery(@"rooms");
+ _previousSequenceNumber = 1000;
+ _previousTargetID = 500;
+ _previousSnapshotVersion = 100;
}
/**
@@ -56,7 +62,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testSetAndReadAQuery {
if ([self isTestBaseClass]) return;
- FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms targetID:1 version:1];
+ FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms];
[self addQueryData:queryData];
FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
@@ -70,20 +76,18 @@ NS_ASSUME_NONNULL_BEGIN
// Type information is currently lost in our canonicalID implementations so this currently an
// easy way to force colliding canonicalIDs
- FSTQuery *q1 = [[FSTQuery queryWithPath:FSTTestPath(@"a")]
- queryByAddingFilter:FSTTestFilter(@"foo", @"==", @(1))];
- FSTQuery *q2 = [[FSTQuery queryWithPath:FSTTestPath(@"a")]
- queryByAddingFilter:FSTTestFilter(@"foo", @"==", @"1")];
+ FSTQuery *q1 = [FSTTestQuery(@"a") queryByAddingFilter:FSTTestFilter(@"foo", @"==", @(1))];
+ FSTQuery *q2 = [FSTTestQuery(@"a") queryByAddingFilter:FSTTestFilter(@"foo", @"==", @"1")];
XCTAssertEqualObjects(q1.canonicalID, q2.canonicalID);
- FSTQueryData *data1 = [self queryDataWithQuery:q1 targetID:1 version:1];
+ FSTQueryData *data1 = [self queryDataWithQuery:q1];
[self addQueryData:data1];
// Using the other query should not return the query cache entry despite equal canonicalIDs.
XCTAssertNil([self.queryCache queryDataForQuery:q2]);
XCTAssertEqualObjects([self.queryCache queryDataForQuery:q1], data1);
- FSTQueryData *data2 = [self queryDataWithQuery:q2 targetID:2 version:1];
+ FSTQueryData *data2 = [self queryDataWithQuery:q2];
[self addQueryData:data2];
XCTAssertEqualObjects([self.queryCache queryDataForQuery:q1], data1);
@@ -101,10 +105,12 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testSetQueryToNewValue {
if ([self isTestBaseClass]) return;
- FSTQueryData *queryData1 = [self queryDataWithQuery:_queryRooms targetID:1 version:1];
+ FSTQueryData *queryData1 =
+ [self queryDataWithQuery:_queryRooms targetID:1 listenSequenceNumber:10 version:1];
[self addQueryData:queryData1];
- FSTQueryData *queryData2 = [self queryDataWithQuery:_queryRooms targetID:1 version:2];
+ FSTQueryData *queryData2 =
+ [self queryDataWithQuery:_queryRooms targetID:1 listenSequenceNumber:10 version:2];
[self addQueryData:queryData2];
FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
@@ -117,7 +123,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRemoveQuery {
if ([self isTestBaseClass]) return;
- FSTQueryData *queryData1 = [self queryDataWithQuery:_queryRooms targetID:1 version:1];
+ FSTQueryData *queryData1 = [self queryDataWithQuery:_queryRooms];
[self addQueryData:queryData1];
[self removeQueryData:queryData1];
@@ -129,7 +135,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRemoveNonExistentQuery {
if ([self isTestBaseClass]) return;
- FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms targetID:1 version:1];
+ FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms];
// no-op, but make sure it doesn't throw.
XCTAssertNoThrow([self removeQueryData:queryData]);
@@ -138,11 +144,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRemoveQueryRemovesMatchingKeysToo {
if ([self isTestBaseClass]) return;
- FSTQueryData *rooms = [self queryDataWithQuery:_queryRooms targetID:1 version:1];
+ FSTQueryData *rooms = [self queryDataWithQuery:_queryRooms];
[self addQueryData:rooms];
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"rooms/foo"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"rooms/bar"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"rooms/foo");
+ FSTDocumentKey *key2 = FSTTestDocKey(@"rooms/bar");
[self addMatchingKey:key1 forTargetID:rooms.targetID];
[self addMatchingKey:key2 forTargetID:rooms.targetID];
@@ -157,7 +163,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testAddOrRemoveMatchingKeys {
if ([self isTestBaseClass]) return;
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:@"foo/bar"];
+ FSTDocumentKey *key = FSTTestDocKey(@"foo/bar");
XCTAssertFalse([self.queryCache containsKey:key]);
@@ -177,9 +183,9 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testRemoveMatchingKeysForTargetID {
if ([self isTestBaseClass]) return;
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"foo/bar"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"foo/baz"];
- FSTDocumentKey *key3 = [FSTDocumentKey keyWithPathString:@"foo/blah"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"foo/bar");
+ FSTDocumentKey *key2 = FSTTestDocKey(@"foo/baz");
+ FSTDocumentKey *key3 = FSTTestDocKey(@"foo/blah");
[self addMatchingKey:key1 forTargetID:1];
[self addMatchingKey:key2 forTargetID:1];
@@ -206,16 +212,16 @@ NS_ASSUME_NONNULL_BEGIN
[garbageCollector addGarbageSource:self.queryCache];
FSTAssertEqualSets([garbageCollector collectGarbage], @[]);
- FSTQueryData *rooms = [self queryDataWithQuery:FSTTestQuery(@"rooms") targetID:1 version:1];
- FSTDocumentKey *room1 = [FSTDocumentKey keyWithPathString:@"rooms/bar"];
- FSTDocumentKey *room2 = [FSTDocumentKey keyWithPathString:@"rooms/foo"];
+ FSTQueryData *rooms = [self queryDataWithQuery:FSTTestQuery(@"rooms")];
+ FSTDocumentKey *room1 = FSTTestDocKey(@"rooms/bar");
+ FSTDocumentKey *room2 = FSTTestDocKey(@"rooms/foo");
[self addQueryData:rooms];
[self addMatchingKey:room1 forTargetID:rooms.targetID];
[self addMatchingKey:room2 forTargetID:rooms.targetID];
- FSTQueryData *halls = [self queryDataWithQuery:FSTTestQuery(@"halls") targetID:2 version:1];
- FSTDocumentKey *hall1 = [FSTDocumentKey keyWithPathString:@"halls/bar"];
- FSTDocumentKey *hall2 = [FSTDocumentKey keyWithPathString:@"halls/foo"];
+ FSTQueryData *halls = [self queryDataWithQuery:FSTTestQuery(@"halls")];
+ FSTDocumentKey *hall1 = FSTTestDocKey(@"halls/bar");
+ FSTDocumentKey *hall2 = FSTTestDocKey(@"halls/foo");
[self addQueryData:halls];
[self addMatchingKey:hall1 forTargetID:halls.targetID];
[self addMatchingKey:hall2 forTargetID:halls.targetID];
@@ -235,9 +241,9 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testMatchingKeysForTargetID {
if ([self isTestBaseClass]) return;
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"foo/bar"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"foo/baz"];
- FSTDocumentKey *key3 = [FSTDocumentKey keyWithPathString:@"foo/blah"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"foo/bar");
+ FSTDocumentKey *key2 = FSTTestDocKey(@"foo/baz");
+ FSTDocumentKey *key3 = FSTTestDocKey(@"foo/blah");
[self addMatchingKey:key1 forTargetID:1];
[self addMatchingKey:key2 forTargetID:1];
@@ -251,6 +257,46 @@ NS_ASSUME_NONNULL_BEGIN
FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:2], (@[ key1, key3 ]));
}
+- (void)testHighestListenSequenceNumber {
+ if ([self isTestBaseClass]) return;
+
+ FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"rooms")
+ targetID:1
+ listenSequenceNumber:10
+ purpose:FSTQueryPurposeListen];
+ [self addQueryData:query1];
+ FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"halls")
+ targetID:2
+ listenSequenceNumber:20
+ purpose:FSTQueryPurposeListen];
+ [self addQueryData:query2];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20);
+
+ // TargetIDs never come down.
+ [self removeQueryData:query2];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20);
+
+ // A query with an empty result set still counts.
+ FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"garages")
+ targetID:42
+ listenSequenceNumber:100
+ purpose:FSTQueryPurposeListen];
+ [self addQueryData:query3];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+
+ [self removeQueryData:query1];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+
+ [self removeQueryData:query3];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+
+ // Verify that the highestTargetID even survives restarts.
+ [self.queryCache shutdown];
+ self.queryCache = [self.persistence queryCache];
+ [self.queryCache start];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+}
+
- (void)testHighestTargetID {
if ([self isTestBaseClass]) return;
@@ -258,17 +304,19 @@ NS_ASSUME_NONNULL_BEGIN
FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"rooms")
targetID:1
+ listenSequenceNumber:10
purpose:FSTQueryPurposeListen];
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"rooms/bar"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"rooms/foo"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"rooms/bar");
+ FSTDocumentKey *key2 = FSTTestDocKey(@"rooms/foo");
[self addQueryData:query1];
[self addMatchingKey:key1 forTargetID:1];
[self addMatchingKey:key2 forTargetID:1];
FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"halls")
targetID:2
+ listenSequenceNumber:20
purpose:FSTQueryPurposeListen];
- FSTDocumentKey *key3 = [FSTDocumentKey keyWithPathString:@"halls/foo"];
+ FSTDocumentKey *key3 = FSTTestDocKey(@"halls/foo");
[self addQueryData:query2];
[self addMatchingKey:key3 forTargetID:2];
XCTAssertEqual([self.queryCache highestTargetID], 2);
@@ -280,6 +328,7 @@ NS_ASSUME_NONNULL_BEGIN
// A query with an empty result set still counts.
FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"garages")
targetID:42
+ listenSequenceNumber:100
purpose:FSTQueryPurposeListen];
[self addQueryData:query3];
XCTAssertEqual([self.queryCache highestTargetID], 42);
@@ -321,12 +370,21 @@ NS_ASSUME_NONNULL_BEGIN
* Creates a new FSTQueryData object from the given parameters, synthesizing a resume token from
* the snapshot version.
*/
+- (FSTQueryData *)queryDataWithQuery:(FSTQuery *)query {
+ return [self queryDataWithQuery:query
+ targetID:++_previousTargetID
+ listenSequenceNumber:++_previousSequenceNumber
+ version:++_previousSnapshotVersion];
+}
+
- (FSTQueryData *)queryDataWithQuery:(FSTQuery *)query
targetID:(FSTTargetID)targetID
+ listenSequenceNumber:(FSTListenSequenceNumber)sequenceNumber
version:(FSTTestSnapshotVersion)version {
NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(version);
return [[FSTQueryData alloc] initWithQuery:query
targetID:targetID
+ listenSequenceNumber:sequenceNumber
purpose:FSTQueryPurposeListen
snapshotVersion:FSTTestVersion(version)
resumeToken:resumeToken];
diff --git a/Firestore/Example/Tests/Local/FSTReferenceSetTests.m b/Firestore/Example/Tests/Local/FSTReferenceSetTests.mm
index 0b852a2..802117a 100644
--- a/Firestore/Example/Tests/Local/FSTReferenceSetTests.m
+++ b/Firestore/Example/Tests/Local/FSTReferenceSetTests.mm
@@ -18,6 +18,7 @@
#import <XCTest/XCTest.h>
+#import "Firestore/Example/Tests/Util/FSTHelpers.h"
#import "Firestore/Source/Model/FSTDocumentKey.h"
NS_ASSUME_NONNULL_BEGIN
@@ -28,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FSTReferenceSetTests
- (void)testAddOrRemoveReferences {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:@"foo/bar"];
+ FSTDocumentKey *key = FSTTestDocKey(@"foo/bar");
FSTReferenceSet *referenceSet = [[FSTReferenceSet alloc] init];
XCTAssertTrue([referenceSet isEmpty]);
@@ -53,9 +54,9 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testRemoveAllReferencesForTargetID {
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"foo/bar"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"foo/baz"];
- FSTDocumentKey *key3 = [FSTDocumentKey keyWithPathString:@"foo/blah"];
+ FSTDocumentKey *key1 = FSTTestDocKey(@"foo/bar");
+ FSTDocumentKey *key2 = FSTTestDocKey(@"foo/baz");
+ FSTDocumentKey *key3 = FSTTestDocKey(@"foo/blah");
FSTReferenceSet *referenceSet = [[FSTReferenceSet alloc] init];
[referenceSet addReferenceToKey:key1 forID:1];
diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.m b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm
index 16fe3bf..d240604 100644
--- a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.m
+++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm
@@ -112,7 +112,7 @@ static const int kVersion = 42;
[self setTestDocumentAtPath:@"b/2"];
[self setTestDocumentAtPath:@"c/1"];
- FSTQuery *query = [FSTQuery queryWithPath:FSTTestPath(@"b")];
+ FSTQuery *query = FSTTestQuery(@"b");
FSTDocumentDictionary *results = [self.remoteDocumentCache documentsMatchingQuery:query];
NSArray *expected =
@[ FSTTestDoc(@"b/1", kVersion, _kDocData, NO), FSTTestDoc(@"b/2", kVersion, _kDocData, NO) ];
diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.m b/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm
index 1970779..1970779 100644
--- a/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.m
+++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm
diff --git a/Firestore/Example/Tests/Model/FSTDatabaseIDTests.m b/Firestore/Example/Tests/Model/FSTDatabaseIDTests.mm
index cb1b19d..cb1b19d 100644
--- a/Firestore/Example/Tests/Model/FSTDatabaseIDTests.m
+++ b/Firestore/Example/Tests/Model/FSTDatabaseIDTests.mm
diff --git a/Firestore/Example/Tests/Model/FSTDocumentKeyTests.m b/Firestore/Example/Tests/Model/FSTDocumentKeyTests.mm
index d66ee73..d66ee73 100644
--- a/Firestore/Example/Tests/Model/FSTDocumentKeyTests.m
+++ b/Firestore/Example/Tests/Model/FSTDocumentKeyTests.mm
diff --git a/Firestore/Example/Tests/Model/FSTDocumentSetTests.m b/Firestore/Example/Tests/Model/FSTDocumentSetTests.mm
index bf6cd21..fbaa5d6 100644
--- a/Firestore/Example/Tests/Model/FSTDocumentSetTests.m
+++ b/Firestore/Example/Tests/Model/FSTDocumentSetTests.mm
@@ -79,14 +79,6 @@ NS_ASSUME_NONNULL_BEGIN
XCTAssertEqualObjects([[set documentEnumerator] allObjects], (@[ _doc3, _doc1, _doc2 ]));
}
-- (void)testPredecessorDocumentForKey {
- FSTDocumentSet *set = FSTTestDocSet(_comp, @[ _doc1, _doc2, _doc3 ]);
-
- XCTAssertNil([set predecessorDocumentForKey:_doc3.key]);
- XCTAssertEqualObjects([set predecessorDocumentForKey:_doc1.key], _doc3);
- XCTAssertEqualObjects([set predecessorDocumentForKey:_doc2.key], _doc1);
-}
-
- (void)testDeletes {
FSTDocumentSet *set = FSTTestDocSet(_comp, @[ _doc1, _doc2, _doc3 ]);
diff --git a/Firestore/Example/Tests/Model/FSTDocumentTests.m b/Firestore/Example/Tests/Model/FSTDocumentTests.mm
index e56ab34..59f526d 100644
--- a/Firestore/Example/Tests/Model/FSTDocumentTests.m
+++ b/Firestore/Example/Tests/Model/FSTDocumentTests.mm
@@ -33,20 +33,20 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FSTDocumentTests
- (void)testConstructor {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:@"messages/first"];
+ FSTDocumentKey *key = FSTTestDocKey(@"messages/first");
FSTSnapshotVersion *version = FSTTestVersion(1);
FSTObjectValue *data = FSTTestObjectValue(@{ @"a" : @1 });
FSTDocument *doc =
[FSTDocument documentWithData:data key:key version:version hasLocalMutations:NO];
- XCTAssertEqualObjects(doc.key, [FSTDocumentKey keyWithPathString:@"messages/first"]);
+ XCTAssertEqualObjects(doc.key, FSTTestDocKey(@"messages/first"));
XCTAssertEqualObjects(doc.version, version);
XCTAssertEqualObjects(doc.data, data);
XCTAssertEqual(doc.hasLocalMutations, NO);
}
- (void)testExtractsFields {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:@"rooms/eros"];
+ FSTDocumentKey *key = FSTTestDocKey(@"rooms/eros");
FSTSnapshotVersion *version = FSTTestVersion(1);
FSTObjectValue *data = FSTTestObjectValue(@{
@"desc" : @"Discuss all the project related stuff",
@@ -62,38 +62,31 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testIsEqual {
- FSTDocumentKey *key1 = [FSTDocumentKey keyWithPathString:@"messages/first"];
- FSTDocumentKey *key2 = [FSTDocumentKey keyWithPathString:@"messages/second"];
- FSTObjectValue *data1 = FSTTestObjectValue(@{ @"a" : @1 });
- FSTObjectValue *data2 = FSTTestObjectValue(@{ @"b" : @1 });
- FSTSnapshotVersion *version1 = FSTTestVersion(1);
-
- FSTDocument *doc1 =
- [FSTDocument documentWithData:data1 key:key1 version:version1 hasLocalMutations:NO];
- FSTDocument *doc2 =
- [FSTDocument documentWithData:data1 key:key1 version:version1 hasLocalMutations:NO];
-
- XCTAssertEqualObjects(doc1, doc2);
- XCTAssertEqualObjects(
- doc1, [FSTDocument documentWithData:FSTTestObjectValue(
- @{ @"a" : @1 })
- key:[FSTDocumentKey keyWithPathString:@"messages/first"]
- version:version1
- hasLocalMutations:NO]);
-
- FSTSnapshotVersion *version2 = FSTTestVersion(2);
- XCTAssertNotEqualObjects(
- doc1, [FSTDocument documentWithData:data2 key:key1 version:version1 hasLocalMutations:NO]);
- XCTAssertNotEqualObjects(
- doc1, [FSTDocument documentWithData:data1 key:key2 version:version1 hasLocalMutations:NO]);
- XCTAssertNotEqualObjects(
- doc1, [FSTDocument documentWithData:data1 key:key1 version:version2 hasLocalMutations:NO]);
- XCTAssertNotEqualObjects(
- doc1, [FSTDocument documentWithData:data1 key:key1 version:version1 hasLocalMutations:YES]);
-
- XCTAssertEqualObjects(
- [FSTDocument documentWithData:data1 key:key1 version:version1 hasLocalMutations:YES],
- [FSTDocument documentWithData:data1 key:key1 version:version1 hasLocalMutations:5]);
+ XCTAssertEqualObjects(FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, NO),
+ FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, NO));
+ XCTAssertNotEqualObjects(FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, NO),
+ FSTTestDoc(@"messages/first", 1,
+ @{ @"b" : @1 }, NO));
+ XCTAssertNotEqualObjects(FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, NO),
+ FSTTestDoc(@"messages/second", 1,
+ @{ @"b" : @1 }, NO));
+ XCTAssertNotEqualObjects(FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, NO),
+ FSTTestDoc(@"messages/first", 2,
+ @{ @"a" : @1 }, NO));
+ XCTAssertNotEqualObjects(FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, NO),
+ FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, YES));
+
+ XCTAssertEqualObjects(FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, YES),
+ FSTTestDoc(@"messages/first", 1,
+ @{ @"a" : @1 }, 5));
}
@end
diff --git a/Firestore/Example/Tests/Model/FSTFieldValueTests.m b/Firestore/Example/Tests/Model/FSTFieldValueTests.mm
index acf95f0..56b885f 100644
--- a/Firestore/Example/Tests/Model/FSTFieldValueTests.m
+++ b/Firestore/Example/Tests/Model/FSTFieldValueTests.mm
@@ -16,9 +16,9 @@
#import "Firestore/Source/Model/FSTFieldValue.h"
+#import <FirebaseFirestore/FIRGeoPoint.h>
#import <XCTest/XCTest.h>
-#import "FirebaseFirestore/FIRGeoPoint.h"
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#import "Firestore/Source/API/FSTUserDataConverter.h"
#import "Firestore/Source/Core/FSTTimestamp.h"
@@ -26,6 +26,7 @@
#import "Firestore/Source/Model/FSTFieldValue.h"
#import "Firestore/Source/Model/FSTPath.h"
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
/** Helper to wrap the values in a set of equality groups using FSTTestFieldValue(). */
@@ -39,10 +40,12 @@ NSArray *FSTWrapGroups(NSArray *groups) {
// strings that can be used instead.
if ([value isEqual:@"server-timestamp-1"]) {
wrappedValue = [FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:FSTTestTimestamp(2016, 5, 20, 10, 20, 0)];
+ serverTimestampValueWithLocalWriteTime:FSTTestTimestamp(2016, 5, 20, 10, 20, 0)
+ previousValue:nil];
} else if ([value isEqual:@"server-timestamp-2"]) {
wrappedValue = [FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:FSTTestTimestamp(2016, 10, 21, 15, 32, 0)];
+ serverTimestampValueWithLocalWriteTime:FSTTestTimestamp(2016, 10, 21, 15, 32, 0)
+ previousValue:nil];
} else if ([value isKindOfClass:[FSTDocumentKeyReference class]]) {
// We directly convert these here so that the databaseIDs can be different.
FSTDocumentKeyReference *reference = (FSTDocumentKeyReference *)value;
@@ -441,12 +444,15 @@ union DoubleBits {
@[
// NOTE: ServerTimestampValues can't be parsed via FSTTestFieldValue().
[FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:[FSTTimestamp timestampWithDate:date1]],
+ serverTimestampValueWithLocalWriteTime:[FSTTimestamp timestampWithDate:date1]
+ previousValue:nil],
[FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:[FSTTimestamp timestampWithDate:date1]]
+ serverTimestampValueWithLocalWriteTime:[FSTTimestamp timestampWithDate:date1]
+ previousValue:nil]
],
@[ [FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:[FSTTimestamp timestampWithDate:date2]] ],
+ serverTimestampValueWithLocalWriteTime:[FSTTimestamp timestampWithDate:date2]
+ previousValue:nil] ],
@[
FSTTestFieldValue(FSTTestGeoPoint(0, 1)),
[FSTGeoPointValue geoPointValue:FSTTestGeoPoint(0, 1)]
diff --git a/Firestore/Example/Tests/Model/FSTMutationTests.m b/Firestore/Example/Tests/Model/FSTMutationTests.mm
index 678755e..47fa9b3 100644
--- a/Firestore/Example/Tests/Model/FSTMutationTests.m
+++ b/Firestore/Example/Tests/Model/FSTMutationTests.mm
@@ -42,7 +42,7 @@
FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"bar" : @"bar-value"});
- FSTMaybeDocument *setDoc = [set applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *setDoc = [set applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
NSDictionary *expectedData = @{@"bar" : @"bar-value"};
XCTAssertEqualObjects(setDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
@@ -54,7 +54,8 @@
FSTMutation *patch =
FSTTestPatchMutation(@"collection/key", @{@"foo.bar" : @"new-bar-value"}, nil);
- FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *patchedDoc =
+ [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
NSDictionary *expectedData = @{ @"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value" };
XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
@@ -64,13 +65,14 @@
NSDictionary *docData = @{ @"foo" : @{@"bar" : @"bar-value", @"baz" : @"baz-value"} };
FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:@"collection/key"];
+ FSTDocumentKey *key = FSTTestDocKey(@"collection/key");
FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:@[ FSTTestFieldPath(@"foo.bar") ]];
FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:key
fieldMask:mask
value:[FSTObjectValue objectValue]
precondition:[FSTPrecondition none]];
- FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *patchedDoc =
+ [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
NSDictionary *expectedData = @{ @"foo" : @{@"baz" : @"baz-value"} };
XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
@@ -82,7 +84,8 @@
FSTMutation *patch =
FSTTestPatchMutation(@"collection/key", @{@"foo.bar" : @"new-bar-value"}, nil);
- FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *patchedDoc =
+ [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
NSDictionary *expectedData = @{ @"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value" };
XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
@@ -91,7 +94,8 @@
- (void)testPatchingDeletedDocumentsDoesNothing {
FSTMaybeDocument *baseDoc = FSTTestDeletedDoc(@"collection/key", 0);
FSTMutation *patch = FSTTestPatchMutation(@"collection/key", @{@"foo" : @"bar"}, nil);
- FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *patchedDoc =
+ [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
XCTAssertEqualObjects(patchedDoc, baseDoc);
}
@@ -100,7 +104,8 @@
FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
FSTMutation *transform = FSTTestTransformMutation(@"collection/key", @[ @"foo.bar" ]);
- FSTMaybeDocument *transformedDoc = [transform applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *transformedDoc =
+ [transform applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
// Server timestamps aren't parsed, so we manually insert it.
FSTObjectValue *expectedData = FSTTestObjectValue(
@@ -108,7 +113,8 @@
@"baz" : @"baz-value" });
expectedData =
[expectedData objectBySettingValue:[FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:_timestamp]
+ serverTimestampValueWithLocalWriteTime:_timestamp
+ previousValue:nil]
forPath:FSTTestFieldPath(@"foo.bar")];
FSTDocument *expectedDoc = [FSTDocument documentWithData:expectedData
@@ -129,8 +135,10 @@
initWithVersion:FSTTestVersion(1)
transformResults:@[ [FSTTimestampValue timestampValue:_timestamp] ]];
- FSTMaybeDocument *transformedDoc =
- [transform applyTo:baseDoc localWriteTime:_timestamp mutationResult:mutationResult];
+ FSTMaybeDocument *transformedDoc = [transform applyTo:baseDoc
+ baseDocument:baseDoc
+ localWriteTime:_timestamp
+ mutationResult:mutationResult];
NSDictionary *expectedData =
@{ @"foo" : @{@"bar" : _timestamp.approximateDateValue},
@@ -143,7 +151,8 @@
FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
FSTMutation *mutation = FSTTestDeleteMutation(@"collection/key");
- FSTMaybeDocument *result = [mutation applyTo:baseDoc localWriteTime:_timestamp];
+ FSTMaybeDocument *result =
+ [mutation applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
XCTAssertEqualObjects(result, FSTTestDeletedDoc(@"collection/key", 0));
}
@@ -154,8 +163,10 @@
FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"foo" : @"new-bar"});
FSTMutationResult *mutationResult =
[[FSTMutationResult alloc] initWithVersion:FSTTestVersion(4) transformResults:nil];
- FSTMaybeDocument *setDoc =
- [set applyTo:baseDoc localWriteTime:_timestamp mutationResult:mutationResult];
+ FSTMaybeDocument *setDoc = [set applyTo:baseDoc
+ baseDocument:baseDoc
+ localWriteTime:_timestamp
+ mutationResult:mutationResult];
NSDictionary *expectedData = @{@"foo" : @"new-bar"};
XCTAssertEqualObjects(setDoc, FSTTestDoc(@"collection/key", 0, expectedData, NO));
@@ -168,8 +179,10 @@
FSTMutation *patch = FSTTestPatchMutation(@"collection/key", @{@"foo" : @"new-bar"}, nil);
FSTMutationResult *mutationResult =
[[FSTMutationResult alloc] initWithVersion:FSTTestVersion(4) transformResults:nil];
- FSTMaybeDocument *patchedDoc =
- [patch applyTo:baseDoc localWriteTime:_timestamp mutationResult:mutationResult];
+ FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc
+ baseDocument:baseDoc
+ localWriteTime:_timestamp
+ mutationResult:mutationResult];
NSDictionary *expectedData = @{@"foo" : @"new-bar"};
XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, NO));
@@ -179,8 +192,10 @@
do { \
FSTMutationResult *mutationResult = \
[[FSTMutationResult alloc] initWithVersion:FSTTestVersion(0) transformResults:nil]; \
- FSTMaybeDocument *actual = \
- [mutation applyTo:base localWriteTime:_timestamp mutationResult:mutationResult]; \
+ FSTMaybeDocument *actual = [mutation applyTo:base \
+ baseDocument:base \
+ localWriteTime:_timestamp \
+ mutationResult:mutationResult]; \
XCTAssertEqualObjects(actual, expected); \
} while (0);
diff --git a/Firestore/Example/Tests/Model/FSTPathTests.m b/Firestore/Example/Tests/Model/FSTPathTests.mm
index b8529e5..b8529e5 100644
--- a/Firestore/Example/Tests/Model/FSTPathTests.m
+++ b/Firestore/Example/Tests/Model/FSTPathTests.mm
diff --git a/Firestore/Example/Tests/Remote/FSTDatastoreTests.m b/Firestore/Example/Tests/Remote/FSTDatastoreTests.mm
index f3cc56f..6d6e912 100644
--- a/Firestore/Example/Tests/Remote/FSTDatastoreTests.m
+++ b/Firestore/Example/Tests/Remote/FSTDatastoreTests.mm
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#import "FirebaseFirestore/FIRFirestoreErrors.h"
#import "Firestore/Source/Remote/FSTDatastore.h"
+#import <FirebaseFirestore/FIRFirestoreErrors.h>
#import <GRPCClient/GRPCCall.h>
#import <XCTest/XCTest.h>
diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.m b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm
index a947eb4..a947eb4 100644
--- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.m
+++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm
diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.m b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
index 528076f..de4a07a 100644
--- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.m
+++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
@@ -16,12 +16,12 @@
#import "Firestore/Source/Remote/FSTSerializerBeta.h"
+#import <FirebaseFirestore/FIRFieldPath.h>
+#import <FirebaseFirestore/FIRFirestoreErrors.h>
+#import <FirebaseFirestore/FIRGeoPoint.h>
#import <GRPCClient/GRPCCall.h>
#import <XCTest/XCTest.h>
-#import "FirebaseFirestore/FIRFieldPath.h"
-#import "FirebaseFirestore/FIRFirestoreErrors.h"
-#import "FirebaseFirestore/FIRGeoPoint.h"
#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h"
#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
#import "Firestore/Protos/objc/google/firestore/v1beta1/Common.pbobjc.h"
@@ -44,6 +44,7 @@
#import "Firestore/Source/Model/FSTPath.h"
#import "Firestore/Source/Remote/FSTWatchChange.h"
+#import "Firestore/Example/Tests/API/FSTAPIHelpers.h"
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
NS_ASSUME_NONNULL_BEGIN
@@ -266,7 +267,8 @@ NS_ASSUME_NONNULL_BEGIN
@"i" : @1,
@"n" : [NSNull null],
@"s" : @"foo",
- @"a" : @[ @2, @"bar", @{@"b" : @NO} ],
+ @"a" : @[ @2, @"bar",
+ @{ @"b" : @NO } ],
@"o" : @{
@"d" : @100,
@"nested" : @{@"e" : @(LLONG_MIN)},
@@ -394,20 +396,25 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testEncodesListenRequestLabels {
FSTQuery *query = FSTTestQuery(@"collection/key");
- FSTQueryData *queryData =
- [[FSTQueryData alloc] initWithQuery:query targetID:2 purpose:FSTQueryPurposeListen];
+ FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query
+ targetID:2
+ listenSequenceNumber:3
+ purpose:FSTQueryPurposeListen];
NSDictionary<NSString *, NSString *> *result =
[self.serializer encodedListenRequestLabelsForQueryData:queryData];
XCTAssertNil(result);
- queryData =
- [[FSTQueryData alloc] initWithQuery:query targetID:2 purpose:FSTQueryPurposeLimboResolution];
+ queryData = [[FSTQueryData alloc] initWithQuery:query
+ targetID:2
+ listenSequenceNumber:3
+ purpose:FSTQueryPurposeLimboResolution];
result = [self.serializer encodedListenRequestLabelsForQueryData:queryData];
XCTAssertEqualObjects(result, @{@"goog-listen-tags" : @"limbo-document"});
queryData = [[FSTQueryData alloc] initWithQuery:query
targetID:2
+ listenSequenceNumber:3
purpose:FSTQueryPurposeExistenceFilterMismatch];
result = [self.serializer encodedListenRequestLabelsForQueryData:queryData];
XCTAssertEqualObjects(result, @{@"goog-listen-tags" : @"existence-filter-mismatch"});
@@ -428,7 +435,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - encodedQuery
- (void)testEncodesFirstLevelKeyQueries {
- FSTQuery *q = [FSTQuery queryWithPath:FSTTestPath(@"docs/1")];
+ FSTQuery *q = FSTTestQuery(@"docs/1");
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -439,7 +446,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesFirstLevelAncestorQueries {
- FSTQuery *q = [FSTQuery queryWithPath:FSTTestPath(@"messages")];
+ FSTQuery *q = FSTTestQuery(@"messages");
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -455,7 +462,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesNestedAncestorQueries {
- FSTQuery *q = [FSTQuery queryWithPath:FSTTestPath(@"rooms/1/messages/10/attachments")];
+ FSTQuery *q = FSTTestQuery(@"rooms/1/messages/10/attachments");
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -471,8 +478,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesSingleFiltersAtFirstLevelCollections {
- FSTQuery *q = [[FSTQuery queryWithPath:FSTTestPath(@"docs")]
- queryByAddingFilter:FSTTestFilter(@"prop", @"<", @(42))];
+ FSTQuery *q = [FSTTestQuery(@"docs") queryByAddingFilter:FSTTestFilter(@"prop", @"<", @(42))];
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -495,7 +501,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesMultipleFiltersOnDeeperCollections {
- FSTQuery *q = [[[FSTQuery queryWithPath:FSTTestPath(@"rooms/1/messages/10/attachments")]
+ FSTQuery *q = [[FSTTestQuery(@"rooms/1/messages/10/attachments")
queryByAddingFilter:FSTTestFilter(@"prop", @">=", @(42))]
queryByAddingFilter:FSTTestFilter(@"author", @"==", @"dimond")];
FSTQueryData *model = [self queryDataForQuery:q];
@@ -544,10 +550,8 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)unaryFilterTestWithValue:(id)value
- expectedUnaryOperator:(GCFSStructuredQuery_UnaryFilter_Operator)
- operator{
- FSTQuery *q = [[FSTQuery queryWithPath:FSTTestPath(@"docs")]
- queryByAddingFilter:FSTTestFilter(@"prop", @"==", value)];
+ expectedUnaryOperator:(GCFSStructuredQuery_UnaryFilter_Operator)op {
+ FSTQuery *q = [FSTTestQuery(@"docs") queryByAddingFilter:FSTTestFilter(@"prop", @"==", value)];
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -560,14 +564,14 @@ NS_ASSUME_NONNULL_BEGIN
GCFSStructuredQuery_UnaryFilter *filter = expected.query.structuredQuery.where.unaryFilter;
filter.field.fieldPath = @"prop";
- filter.op = operator;
+ filter.op = op;
expected.targetId = 1;
[self assertRoundTripForQueryData:model proto:expected];
}
- (void)testEncodesSortOrders {
- FSTQuery *q = [[FSTQuery queryWithPath:FSTTestPath(@"docs")]
+ FSTQuery *q = [FSTTestQuery(@"docs")
queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"prop")
ascending:YES]];
FSTQueryData *model = [self queryDataForQuery:q];
@@ -587,7 +591,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesSortOrdersDescending {
- FSTQuery *q = [[FSTQuery queryWithPath:FSTTestPath(@"rooms/1/messages/10/attachments")]
+ FSTQuery *q = [FSTTestQuery(@"rooms/1/messages/10/attachments")
queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"prop")
ascending:NO]];
FSTQueryData *model = [self queryDataForQuery:q];
@@ -607,7 +611,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesLimits {
- FSTQuery *q = [[FSTQuery queryWithPath:FSTTestPath(@"docs")] queryBySettingLimit:26];
+ FSTQuery *q = [FSTTestQuery(@"docs") queryBySettingLimit:26];
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -624,9 +628,10 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesResumeTokens {
- FSTQuery *q = [FSTQuery queryWithPath:FSTTestPath(@"docs")];
+ FSTQuery *q = FSTTestQuery(@"docs");
FSTQueryData *model = [[FSTQueryData alloc] initWithQuery:q
targetID:1
+ listenSequenceNumber:0
purpose:FSTQueryPurposeListen
snapshotVersion:[FSTSnapshotVersion noVersion]
resumeToken:FSTTestData(1, 2, 3, -1)];
@@ -647,6 +652,7 @@ NS_ASSUME_NONNULL_BEGIN
- (FSTQueryData *)queryDataForQuery:(FSTQuery *)query {
return [[FSTQueryData alloc] initWithQuery:query
targetID:1
+ listenSequenceNumber:0
purpose:FSTQueryPurposeListen
snapshotVersion:[FSTSnapshotVersion noVersion]
resumeToken:[NSData data]];
diff --git a/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.m b/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm
index 6bb314d..6bb314d 100644
--- a/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.m
+++ b/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm
diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.m b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm
index df2496b..df2496b 100644
--- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.m
+++ b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm
diff --git a/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.m b/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm
index a67f667..a67f667 100644
--- a/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.m
+++ b/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm
diff --git a/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.m b/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm
index 3030ab5..3030ab5 100644
--- a/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.m
+++ b/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm
diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.m b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm
index 9a1d719..9a1d719 100644
--- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.m
+++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm
diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.m b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm
index 2c1b8db..3335990 100644
--- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.m
+++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm
@@ -16,9 +16,9 @@
#import "Firestore/Example/Tests/SpecTests/FSTSpecTests.h"
+#import <FirebaseFirestore/FIRFirestoreErrors.h>
#import <GRPCClient/GRPCCall.h>
-#import "FirebaseFirestore/FIRFirestoreErrors.h"
#import "Firestore/Source/Auth/FSTUser.h"
#import "Firestore/Source/Core/FSTEventManager.h"
#import "Firestore/Source/Core/FSTQuery.h"
@@ -103,11 +103,11 @@ static NSString *const kNoIOSTag = @"no-ios";
- (nullable FSTQuery *)parseQuery:(id)querySpec {
if ([querySpec isKindOfClass:[NSString class]]) {
- return [FSTQuery queryWithPath:[FSTResourcePath pathWithString:querySpec]];
+ return FSTTestQuery(querySpec);
} else if ([querySpec isKindOfClass:[NSDictionary class]]) {
NSDictionary *queryDict = (NSDictionary *)querySpec;
NSString *path = queryDict[@"path"];
- __block FSTQuery *query = [FSTQuery queryWithPath:[FSTResourcePath pathWithString:path]];
+ __block FSTQuery *query = FSTTestQuery(path);
if (queryDict[@"limit"]) {
NSNumber *limit = queryDict[@"limit"];
query = [query queryBySettingLimit:limit.integerValue];
@@ -156,7 +156,7 @@ static NSString *const kNoIOSTag = @"no-ios";
FSTTargetID actualID = [self.driver addUserListenerWithQuery:query];
FSTTargetID expectedID = [listenSpec[0] intValue];
- XCTAssertEqual(actualID, expectedID);
+ XCTAssertEqual(actualID, expectedID, @"targetID assigned to listen");
}
- (void)doUnlisten:(NSArray *)unlistenSpec {
@@ -237,7 +237,7 @@ static NSString *const kNoIOSTag = @"no-ios";
}
} else if (watchEntity[@"doc"]) {
NSArray *docSpec = watchEntity[@"doc"];
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:docSpec[0]];
+ FSTDocumentKey *key = FSTTestDocKey(docSpec[0]);
FSTObjectValue *value = FSTTestObjectValue(docSpec[2]);
FSTSnapshotVersion *version = [self parseVersion:docSpec[1]];
FSTMaybeDocument *doc =
@@ -249,7 +249,7 @@ static NSString *const kNoIOSTag = @"no-ios";
document:doc];
[self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]];
} else if (watchEntity[@"key"]) {
- FSTDocumentKey *docKey = [FSTDocumentKey keyWithPathString:watchEntity[@"key"]];
+ FSTDocumentKey *docKey = FSTTestDocKey(watchEntity[@"key"]);
FSTWatchChange *change =
[[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[]
removedTargetIDs:watchEntity[@"removedTargets"]
@@ -503,6 +503,7 @@ static NSString *const kNoIOSTag = @"no-ios";
expectedActiveTargets[@(targetID)] =
[[FSTQueryData alloc] initWithQuery:query
targetID:targetID
+ listenSequenceNumber:0
purpose:FSTQueryPurposeListen
snapshotVersion:[FSTSnapshotVersion noVersion]
resumeToken:resumeToken];
diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h
index 3d031bd..46601d7 100644
--- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h
+++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h
@@ -17,6 +17,7 @@
#import <Foundation/Foundation.h>
#import "Firestore/Source/Core/FSTTypes.h"
+#import "Firestore/Source/Remote/FSTRemoteStore.h"
@class FSTDocumentKey;
@class FSTMutation;
@@ -76,7 +77,7 @@ typedef NSDictionary<FSTUser *, NSArray<FSTOutstandingWrite *> *> FSTOutstanding
*
* Each method on the driver injects a different event into the system.
*/
-@interface FSTSyncEngineTestDriver : NSObject
+@interface FSTSyncEngineTestDriver : NSObject <FSTOnlineStateDelegate>
/**
* Initializes the underlying FSTSyncEngine with the given local persistence implementation and
diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm
index 896a292..a4de615 100644
--- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m
+++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm
@@ -16,9 +16,9 @@
#import "Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h"
+#import <FirebaseFirestore/FIRFirestoreErrors.h>
#import <GRPCClient/GRPCCall.h>
-#import "FirebaseFirestore/FIRFirestoreErrors.h"
#import "Firestore/Source/Auth/FSTUser.h"
#import "Firestore/Source/Core/FSTEventManager.h"
#import "Firestore/Source/Core/FSTQuery.h"
@@ -119,7 +119,7 @@ NS_ASSUME_NONNULL_BEGIN
_remoteStore.syncEngine = _syncEngine;
_eventManager = [FSTEventManager eventManagerWithSyncEngine:_syncEngine];
- _remoteStore.onlineStateDelegate = _eventManager;
+ _remoteStore.onlineStateDelegate = self;
// Set up internal event tracking for the spec tests.
NSMutableArray<FSTQueryEvent *> *events = [NSMutableArray array];
@@ -139,6 +139,16 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+- (NSDictionary<FSTUser *, NSMutableArray<FSTOutstandingWrite *> *> *)outstandingWrites {
+ return static_cast<NSDictionary<FSTUser *, NSMutableArray<FSTOutstandingWrite *> *> *>(
+ _outstandingWrites);
+}
+
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState {
+ [self.syncEngine applyChangedOnlineState:onlineState];
+ [self.eventManager applyChangedOnlineState:onlineState];
+}
+
- (void)start {
[self.localStore start];
[self.remoteStore start];
diff --git a/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json b/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json
index e607710..7bfe557 100644
--- a/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json
+++ b/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json
@@ -1608,7 +1608,19 @@
"stateExpect": {
"activeTargets": {},
"limboDocs": []
- }
+ },
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false
+ }
+ ]
},
{
"enableNetwork": true,
diff --git a/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json b/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json
index f542a6e..6cbbc80 100644
--- a/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json
+++ b/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json
@@ -294,5 +294,424 @@
]
}
]
+ },
+ "Queries revert to fromCache=true when offline.": {
+ "describeName": "Offline:",
+ "itName": "Queries revert to fromCache=true when offline.",
+ "tags": [],
+ "config": {
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": [
+ 2,
+ {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ }
+ ],
+ "stateExpect": {
+ "activeTargets": {
+ "2": {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ [
+ "collection/a",
+ 1000,
+ {
+ "key": "a"
+ }
+ ]
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ],
+ "watchSnapshot": 1000,
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "added": [
+ [
+ "collection/a",
+ 1000,
+ {
+ "key": "a"
+ }
+ ]
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false
+ }
+ ]
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ }
+ },
+ "stateExpect": {
+ "activeTargets": {
+ "2": {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": "resume-token-1000"
+ }
+ }
+ }
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ }
+ }
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ }
+ },
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false
+ }
+ ]
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ],
+ "watchSnapshot": 1000,
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false
+ }
+ ]
+ }
+ ]
+ },
+ "Queries with limbo documents handle going offline.": {
+ "describeName": "Offline:",
+ "itName": "Queries with limbo documents handle going offline.",
+ "tags": [],
+ "config": {
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": [
+ 2,
+ {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ }
+ ],
+ "stateExpect": {
+ "activeTargets": {
+ "2": {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ [
+ "collection/a",
+ 1000,
+ {
+ "key": "a"
+ }
+ ]
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ],
+ "watchSnapshot": 1000,
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "added": [
+ [
+ "collection/a",
+ 1000,
+ {
+ "key": "a"
+ }
+ ]
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false
+ }
+ ]
+ },
+ {
+ "watchReset": [
+ 2
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1001"
+ ],
+ "watchSnapshot": 1001,
+ "stateExpect": {
+ "limboDocs": [
+ "collection/a"
+ ],
+ "activeTargets": {
+ "1": {
+ "query": {
+ "path": "collection/a",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": ""
+ },
+ "2": {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": ""
+ }
+ }
+ },
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false
+ }
+ ]
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ }
+ },
+ "stateExpect": {
+ "activeTargets": {
+ "1": {
+ "query": {
+ "path": "collection/a",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": ""
+ },
+ "2": {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": "resume-token-1001"
+ }
+ }
+ }
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ }
+ }
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1001"
+ ],
+ "watchSnapshot": 1001
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [],
+ "targets": [
+ 1
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
+ ],
+ "resume-token-1001"
+ ],
+ "watchSnapshot": 1001,
+ "expect": [
+ {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "removed": [
+ [
+ "collection/a",
+ 1000,
+ {
+ "key": "a"
+ }
+ ]
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false
+ }
+ ],
+ "stateExpect": {
+ "limboDocs": [],
+ "activeTargets": {
+ "2": {
+ "query": {
+ "path": "collection",
+ "filters": [],
+ "orderBys": []
+ },
+ "resumeToken": "resume-token-1001"
+ }
+ }
+ }
+ }
+ ]
}
}
diff --git a/Firestore/Example/Tests/Util/FSTAssertTests.m b/Firestore/Example/Tests/Util/FSTAssertTests.mm
index 0cba03f..0cba03f 100644
--- a/Firestore/Example/Tests/Util/FSTAssertTests.m
+++ b/Firestore/Example/Tests/Util/FSTAssertTests.mm
diff --git a/Firestore/Example/Tests/Util/FSTComparisonTests.m b/Firestore/Example/Tests/Util/FSTComparisonTests.m
deleted file mode 100644
index 5632e64..0000000
--- a/Firestore/Example/Tests/Util/FSTComparisonTests.m
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2017 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 "Firestore/Source/Util/FSTComparison.h"
-
-#import <XCTest/XCTest.h>
-
-union DoubleBits {
- double d;
- uint64_t bits;
-};
-
-#define ASSERT_BIT_EQUALS(expected, actual) \
- do { \
- union DoubleBits expectedBits = {.d = expected}; \
- union DoubleBits actualBits = {.d = expected}; \
- if (expectedBits.bits != actualBits.bits) { \
- XCTFail(@"Expected <%f> to compare equal to <%f> with bits <%llX> equal to <%llX>", actual, \
- expected, actualBits.bits, expectedBits.bits); \
- } \
- } while (0);
-
-#define ASSERT_ORDERED_SAME(doubleValue, longValue) \
- do { \
- NSComparisonResult result = FSTCompareMixed(doubleValue, longValue); \
- if (result != NSOrderedSame) { \
- XCTFail(@"Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
- } \
- } while (0);
-
-#define ASSERT_ORDERED_DESCENDING(doubleValue, longValue) \
- do { \
- NSComparisonResult result = FSTCompareMixed(doubleValue, longValue); \
- if (result != NSOrderedDescending) { \
- XCTFail(@"Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
- } \
- } while (0);
-
-#define ASSERT_ORDERED_ASCENDING(doubleValue, longValue) \
- do { \
- NSComparisonResult result = FSTCompareMixed(doubleValue, longValue); \
- if (result != NSOrderedAscending) { \
- XCTFail(@"Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
- } \
- } while (0);
-
-@interface FSTComparisonTests : XCTestCase
-@end
-
-@implementation FSTComparisonTests
-
-- (void)testMixedComparison {
- // Infinities
- ASSERT_ORDERED_ASCENDING(-INFINITY, LLONG_MIN);
- ASSERT_ORDERED_ASCENDING(-INFINITY, LLONG_MAX);
- ASSERT_ORDERED_ASCENDING(-INFINITY, 0LL);
-
- ASSERT_ORDERED_DESCENDING(INFINITY, LLONG_MIN);
- ASSERT_ORDERED_DESCENDING(INFINITY, LLONG_MAX);
- ASSERT_ORDERED_DESCENDING(INFINITY, 0LL);
-
- // NaN
- ASSERT_ORDERED_ASCENDING(NAN, LLONG_MIN);
- ASSERT_ORDERED_ASCENDING(NAN, LLONG_MAX);
- ASSERT_ORDERED_ASCENDING(NAN, 0LL);
-
- // Large values (note DBL_MIN is positive and near zero).
- ASSERT_ORDERED_ASCENDING(-DBL_MAX, LLONG_MIN);
-
- // Tests around LLONG_MIN
- ASSERT_BIT_EQUALS((double)LLONG_MIN, -0x1.0p63);
- ASSERT_ORDERED_SAME(-0x1.0p63, LLONG_MIN);
- ASSERT_ORDERED_ASCENDING(-0x1.0p63, LLONG_MIN + 1);
-
- XCTAssertLessThan(-0x1.0000000000001p63, -0x1.0p63);
- ASSERT_ORDERED_ASCENDING(-0x1.0000000000001p63, LLONG_MIN);
- ASSERT_ORDERED_DESCENDING(-0x1.FFFFFFFFFFFFFp62, LLONG_MIN);
-
- // Tests around LLONG_MAX
- // Note LLONG_MAX cannot be exactly represented by a double, so the system rounds it to the
- // nearest double, which is 2^63. This number, in turn is larger than the maximum representable
- // as a long.
- ASSERT_BIT_EQUALS(0x1.0p63, (double)LLONG_MAX);
- ASSERT_ORDERED_DESCENDING(0x1.0p63, LLONG_MAX);
-
- // The largest value with an exactly long representation
- XCTAssertEqual((long)0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC00LL);
- ASSERT_ORDERED_SAME(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC00LL);
-
- ASSERT_ORDERED_DESCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFB00LL);
- ASSERT_ORDERED_DESCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFBFFLL);
- ASSERT_ORDERED_ASCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC01LL);
- ASSERT_ORDERED_ASCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFD00LL);
-
- ASSERT_ORDERED_ASCENDING(0x1.FFFFFFFFFFFFEp62, 0x7FFFFFFFFFFFFC00LL);
-
- // Tests around MAX_SAFE_INTEGER
- ASSERT_ORDERED_SAME(0x1.FFFFFFFFFFFFFp52, 0x1FFFFFFFFFFFFFLL);
- ASSERT_ORDERED_DESCENDING(0x1.FFFFFFFFFFFFFp52, 0x1FFFFFFFFFFFFELL);
- ASSERT_ORDERED_ASCENDING(0x1.FFFFFFFFFFFFEp52, 0x1FFFFFFFFFFFFFLL);
- ASSERT_ORDERED_ASCENDING(0x1.FFFFFFFFFFFFFp52, 0x20000000000000LL);
-
- // Tests around MIN_SAFE_INTEGER
- ASSERT_ORDERED_SAME(-0x1.FFFFFFFFFFFFFp52, -0x1FFFFFFFFFFFFFLL);
- ASSERT_ORDERED_ASCENDING(-0x1.FFFFFFFFFFFFFp52, -0x1FFFFFFFFFFFFELL);
- ASSERT_ORDERED_DESCENDING(-0x1.FFFFFFFFFFFFEp52, -0x1FFFFFFFFFFFFFLL);
- ASSERT_ORDERED_DESCENDING(-0x1.FFFFFFFFFFFFFp52, -0x20000000000000LL);
-
- // Tests around zero.
- ASSERT_ORDERED_SAME(-0.0, 0LL);
- ASSERT_ORDERED_SAME(0.0, 0LL);
-
- // The smallest representable positive value should be greater than zero
- ASSERT_ORDERED_DESCENDING(DBL_MIN, 0LL);
- ASSERT_ORDERED_ASCENDING(-DBL_MIN, 0LL);
-
- // Note that 0x1.0p-1074 is a hex floating point literal representing the minimum subnormal
- // number: <https://en.wikipedia.org/wiki/Denormal_number>.
- double minSubNormal = 0x1.0p-1074;
- ASSERT_ORDERED_DESCENDING(minSubNormal, 0LL);
- ASSERT_ORDERED_ASCENDING(-minSubNormal, 0LL);
-
- // Other sanity checks
- ASSERT_ORDERED_ASCENDING(0.5, 1LL);
- ASSERT_ORDERED_DESCENDING(0.5, 0LL);
- ASSERT_ORDERED_ASCENDING(1.5, 2LL);
- ASSERT_ORDERED_DESCENDING(1.5, 1LL);
-}
-
-@end
diff --git a/Firestore/Example/Tests/Util/FSTEventAccumulator.h b/Firestore/Example/Tests/Util/FSTEventAccumulator.h
index ae5392c..baa501b 100644
--- a/Firestore/Example/Tests/Util/FSTEventAccumulator.h
+++ b/Firestore/Example/Tests/Util/FSTEventAccumulator.h
@@ -23,7 +23,7 @@
NS_ASSUME_NONNULL_BEGIN
-typedef void (^FSTGenericEventHandler)(id _Nullable, NSError *error);
+typedef void (^FSTValueEventHandler)(id _Nullable, NSError *_Nullable error);
@interface FSTEventAccumulator : NSObject
@@ -35,7 +35,8 @@ typedef void (^FSTGenericEventHandler)(id _Nullable, NSError *error);
- (NSArray<id> *)awaitEvents:(NSUInteger)events name:(NSString *)name;
-@property(nonatomic, strong, readonly) FSTGenericEventHandler handler;
+@property(nonatomic, strong, readonly) FSTValueEventHandler valueEventHandler;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/Util/FSTEventAccumulator.m b/Firestore/Example/Tests/Util/FSTEventAccumulator.mm
index b44ec67..c4c1602 100644
--- a/Firestore/Example/Tests/Util/FSTEventAccumulator.m
+++ b/Firestore/Example/Tests/Util/FSTEventAccumulator.mm
@@ -68,9 +68,8 @@ NS_ASSUME_NONNULL_BEGIN
return events[0];
}
-// Overrides the handler property
-- (void (^)(id _Nullable, NSError *))handler {
- return ^void(id _Nullable value, NSError *error) {
+- (void (^)(id _Nullable, NSError *_Nullable))valueEventHandler {
+ return ^void(id _Nullable value, NSError *_Nullable error) {
// We can't store nil in the _events array, but these are still interesting to tests so store
// NSNull instead.
id event = value ? value : [NSNull null];
diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h
index 91ccbcf..4dbf910 100644
--- a/Firestore/Example/Tests/Util/FSTHelpers.h
+++ b/Firestore/Example/Tests/Util/FSTHelpers.h
@@ -16,7 +16,6 @@
#import <Foundation/Foundation.h>
-#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
#import "Firestore/Source/Core/FSTTypes.h"
#import "Firestore/Source/Model/FSTDocumentDictionary.h"
#import "Firestore/Source/Model/FSTDocumentKeySet.h"
@@ -33,7 +32,6 @@
@class FSTPatchMutation;
@class FSTQuery;
@class FSTRemoteEvent;
-@class FSTResourceName;
@class FSTResourcePath;
@class FSTSetMutation;
@class FSTSnapshotVersion;
@@ -145,6 +143,8 @@ NSDate *FSTTestDate(int year, int month, int day, int hour, int minute, int seco
*/
NSData *FSTTestData(int bytes, ...);
+// Note that FIRGeoPoint is a model class in addition to an API class, so we put this helper here
+// instead of FSTAPIHelpers.h
/** Creates a new GeoPoint from the latitude and longitude values */
FIRGeoPoint *FSTTestGeoPoint(double latitude, double longitude);
diff --git a/Firestore/Example/Tests/Util/FSTHelpers.m b/Firestore/Example/Tests/Util/FSTHelpers.mm
index f01bddb..64fe213 100644
--- a/Firestore/Example/Tests/Util/FSTHelpers.m
+++ b/Firestore/Example/Tests/Util/FSTHelpers.mm
@@ -16,14 +16,18 @@
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
-#import "FirebaseFirestore/FIRFieldPath.h"
-#import "FirebaseFirestore/FIRGeoPoint.h"
+#include <inttypes.h>
+
+#import <FirebaseFirestore/FIRFieldPath.h>
+#import <FirebaseFirestore/FIRGeoPoint.h>
+
#import "Firestore/Source/API/FIRFieldPath+Internal.h"
#import "Firestore/Source/API/FSTUserDataConverter.h"
#import "Firestore/Source/Core/FSTQuery.h"
#import "Firestore/Source/Core/FSTSnapshotVersion.h"
#import "Firestore/Source/Core/FSTTimestamp.h"
#import "Firestore/Source/Core/FSTView.h"
+#import "Firestore/Source/Core/FSTViewSnapshot.h"
#import "Firestore/Source/Local/FSTLocalViewChanges.h"
#import "Firestore/Source/Local/FSTQueryData.h"
#import "Firestore/Source/Model/FSTDatabaseID.h"
@@ -138,7 +142,7 @@ FSTDocument *FSTTestDoc(NSString *path,
FSTTestSnapshotVersion version,
NSDictionary<NSString *, id> *data,
BOOL hasMutations) {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:path];
+ FSTDocumentKey *key = FSTTestDocKey(path);
return [FSTDocument documentWithData:FSTTestObjectValue(data)
key:key
version:FSTTestVersion(version)
@@ -146,7 +150,7 @@ FSTDocument *FSTTestDoc(NSString *path,
}
FSTDeletedDocument *FSTTestDeletedDoc(NSString *path, FSTTestSnapshotVersion version) {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:path];
+ FSTDocumentKey *key = FSTTestDocKey(path);
return [FSTDeletedDocument documentWithKey:key version:FSTTestVersion(version)];
}
@@ -214,7 +218,7 @@ FSTSortOrder *FSTTestOrderBy(NSString *field, NSString *direction) {
}
NSComparator FSTTestDocComparator(NSString *fieldPath) {
- FSTQuery *query = [[FSTQuery queryWithPath:[FSTResourcePath pathWithSegments:@[ @"docs" ]]]
+ FSTQuery *query = [FSTTestQuery(@"docs")
queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(fieldPath)
ascending:YES]];
return [query comparator];
@@ -229,7 +233,7 @@ FSTDocumentSet *FSTTestDocSet(NSComparator comp, NSArray<FSTDocument *> *docs) {
}
FSTSetMutation *FSTTestSetMutation(NSString *path, NSDictionary<NSString *, id> *values) {
- return [[FSTSetMutation alloc] initWithKey:[FSTDocumentKey keyWithPathString:path]
+ return [[FSTSetMutation alloc] initWithKey:FSTTestDocKey(path)
value:FSTTestObjectValue(values)
precondition:[FSTPrecondition none]];
}
@@ -274,7 +278,7 @@ FSTTransformMutation *FSTTestTransformMutation(NSString *path,
}
FSTDeleteMutation *FSTTestDeleteMutation(NSString *path) {
- return [[FSTDeleteMutation alloc] initWithKey:[FSTDocumentKey keyWithPathString:path]
+ return [[FSTDeleteMutation alloc] initWithKey:FSTTestDocKey(path)
precondition:[FSTPrecondition none]];
}
@@ -334,12 +338,12 @@ FSTLocalViewChanges *FSTTestViewChanges(FSTQuery *query,
NSArray<NSString *> *removedKeys) {
FSTDocumentKeySet *added = [FSTDocumentKeySet keySet];
for (NSString *keyPath in addedKeys) {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:keyPath];
+ FSTDocumentKey *key = FSTTestDocKey(keyPath);
added = [added setByAddingObject:key];
}
FSTDocumentKeySet *removed = [FSTDocumentKeySet keySet];
for (NSString *keyPath in removedKeys) {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPathString:keyPath];
+ FSTDocumentKey *key = FSTTestDocKey(keyPath);
removed = [removed setByAddingObject:key];
}
return [FSTLocalViewChanges changesForQuery:query addedKeys:added removedKeys:removed];
diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h
index 88f9346..e1820e2 100644
--- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h
+++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h
@@ -18,6 +18,7 @@
#import <XCTest/XCTest.h>
#import "Firestore/Example/Tests/Util/XCTestCase+Await.h"
+#import "Firestore/Source/Core/FSTTypes.h"
@class FIRCollectionReference;
@class FIRDocumentSnapshot;
@@ -82,6 +83,10 @@ extern "C" {
- (void)deleteDocumentRef:(FIRDocumentReference *)ref;
+- (void)disableNetwork;
+
+- (void)enableNetwork;
+
/**
* "Blocks" the current thread/run loop until the block returns YES.
* Should only be called on the main thread.
diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
index 3d30a77..ef15056 100644
--- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
+++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
@@ -25,6 +25,7 @@
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#import "Firestore/Source/Auth/FSTEmptyCredentialsProvider.h"
+#import "Firestore/Source/Core/FSTFirestoreClient.h"
#import "Firestore/Source/Local/FSTLevelDB.h"
#import "Firestore/Source/Model/FSTDatabaseID.h"
#import "Firestore/Source/Util/FSTDispatchQueue.h"
@@ -158,11 +159,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)shutdownFirestore:(FIRFirestore *)firestore {
- XCTestExpectation *shutdownCompletion = [self expectationWithDescription:@"shutdown"];
- [firestore shutdownWithCompletion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- [shutdownCompletion fulfill];
- }];
+ [firestore shutdownWithCompletion:[self completionForExpectationWithName:@"shutdown"]];
[self awaitExpectations];
}
@@ -261,31 +258,29 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)writeDocumentRef:(FIRDocumentReference *)ref data:(NSDictionary<NSString *, id> *)data {
- XCTestExpectation *expectation = [self expectationWithDescription:@"setData"];
- [ref setData:data
- completion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- [expectation fulfill];
- }];
+ [ref setData:data completion:[self completionForExpectationWithName:@"setData"]];
[self awaitExpectations];
}
- (void)updateDocumentRef:(FIRDocumentReference *)ref data:(NSDictionary<id, id> *)data {
- XCTestExpectation *expectation = [self expectationWithDescription:@"updateData"];
- [ref updateData:data
- completion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- [expectation fulfill];
- }];
+ [ref updateData:data completion:[self completionForExpectationWithName:@"updateData"]];
[self awaitExpectations];
}
- (void)deleteDocumentRef:(FIRDocumentReference *)ref {
- XCTestExpectation *expectation = [self expectationWithDescription:@"deleteDocument"];
- [ref deleteDocumentWithCompletion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- [expectation fulfill];
- }];
+ [ref deleteDocumentWithCompletion:[self completionForExpectationWithName:@"deleteDocument"]];
+ [self awaitExpectations];
+}
+
+- (void)disableNetwork {
+ [self.db.client
+ disableNetworkWithCompletion:[self completionForExpectationWithName:@"Disable Network."]];
+ [self awaitExpectations];
+}
+
+- (void)enableNetwork {
+ [self.db.client
+ enableNetworkWithCompletion:[self completionForExpectationWithName:@"Enable Network."]];
[self awaitExpectations];
}
diff --git a/Firestore/Example/Tests/Util/FSTTestDispatchQueue.m b/Firestore/Example/Tests/Util/FSTTestDispatchQueue.mm
index 8124cf2..8124cf2 100644
--- a/Firestore/Example/Tests/Util/FSTTestDispatchQueue.m
+++ b/Firestore/Example/Tests/Util/FSTTestDispatchQueue.mm
diff --git a/Firestore/Example/Tests/Util/XCTestCase+Await.h b/Firestore/Example/Tests/Util/XCTestCase+Await.h
index 9d575f9..1afe8c0 100644
--- a/Firestore/Example/Tests/Util/XCTestCase+Await.h
+++ b/Firestore/Example/Tests/Util/XCTestCase+Await.h
@@ -16,6 +16,8 @@
#import <XCTest/XCTest.h>
+#import "Firestore/Source/Core/FSTTypes.h"
+
@interface XCTestCase (Await)
/**
@@ -29,4 +31,10 @@
*/
- (double)defaultExpectationWaitSeconds;
+/**
+ * Returns a completion block that fulfills a newly-created expectation with the specified
+ * name.
+ */
+- (FSTVoidErrorBlock)completionForExpectationWithName:(NSString *)expectationName;
+
@end
diff --git a/Firestore/Example/Tests/Util/XCTestCase+Await.m b/Firestore/Example/Tests/Util/XCTestCase+Await.mm
index 15c67ca..a5fefc9 100644
--- a/Firestore/Example/Tests/Util/XCTestCase+Await.m
+++ b/Firestore/Example/Tests/Util/XCTestCase+Await.mm
@@ -18,7 +18,9 @@
#import <Foundation/Foundation.h>
-static const double kExpectationWaitSeconds = 10.0;
+// TODO(b/72864027): Reduce this to 10 seconds again once we've resolved issues with Query
+// Conformance Tests flakiness or gotten answers from GRPC about reconnect delays.
+static const double kExpectationWaitSeconds = 25.0;
@implementation XCTestCase (Await)
@@ -35,4 +37,12 @@ static const double kExpectationWaitSeconds = 10.0;
return kExpectationWaitSeconds;
}
+- (FSTVoidErrorBlock)completionForExpectationWithName:(NSString *)expectationName {
+ XCTestExpectation *expectation = [self expectationWithDescription:expectationName];
+ return ^(NSError *error) {
+ XCTAssertNil(error);
+ [expectation fulfill];
+ };
+}
+
@end
diff --git a/Firestore/Port/absl/absl_attributes.h b/Firestore/Port/absl/absl_attributes.h
deleted file mode 100644
index d43930c..0000000
--- a/Firestore/Port/absl/absl_attributes.h
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-// Various macros for C++ attributes
-// Most macros here are exposing GCC or Clang features, and are stubbed out for
-// other compilers.
-// GCC attributes documentation:
-// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
-// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
-// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
-//
-// Most attributes in this file are already supported by GCC 4.7.
-// However, some of them are not supported in older version of Clang.
-// Thus, we check __has_attribute() first. If the check fails, we check if we
-// are on GCC and assume the attribute exists on GCC (which is verified on GCC
-// 4.7).
-//
-// For sanitizer-related attributes, define the following macros
-// using -D along with the given value for -fsanitize:
-// - ADDRESS_SANITIZER with -fsanitize=address (GCC 4.8+, Clang)
-// - MEMORY_SANITIZER with -fsanitize=memory (Clang)
-// - THREAD_SANITIZER with -fsanitize=thread (GCC 4.8+, Clang)
-// - UNDEFINED_BEHAVIOR_SANITIZER with -fsanitize=undefined (GCC 4.9+, Clang)
-// - CONTROL_FLOW_INTEGRITY with -fsanitize=cfi (Clang)
-// Since these are only supported by GCC and Clang now, we only check for
-// __GNUC__ (GCC or Clang) and the above macros.
-#ifndef THIRD_PARTY_ABSL_BASE_ATTRIBUTES_H_
-#define THIRD_PARTY_ABSL_BASE_ATTRIBUTES_H_
-
-// ABSL_HAVE_ATTRIBUTE is a function-like feature checking macro.
-// It's a wrapper around __has_attribute, which is defined by GCC 5+ and Clang.
-// It evaluates to a nonzero constant integer if the attribute is supported
-// or 0 if not.
-// It evaluates to zero if __has_attribute is not defined by the compiler.
-// GCC: https://gcc.gnu.org/gcc-5/changes.html
-// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
-#ifdef __has_attribute
-#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
-#else
-#define ABSL_HAVE_ATTRIBUTE(x) 0
-#endif
-
-// ABSL_HAVE_CPP_ATTRIBUTE is a function-like feature checking macro that
-// accepts C++11 style attributes. It's a wrapper around __has_cpp_attribute,
-// defined by ISO C++ SD-6
-// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
-// find __has_cpp_attribute, will evaluate to 0.
-#if defined(__cplusplus) && defined(__has_cpp_attribute)
-// NOTE: requiring __cplusplus above should not be necessary, but
-// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
-#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
-#else
-#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
-#endif
-
-// -----------------------------------------------------------------------------
-// Function Attributes
-// -----------------------------------------------------------------------------
-// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
-// Clang: https://clang.llvm.org/docs/AttributeReference.html
-
-// PRINTF_ATTRIBUTE, SCANF_ATTRIBUTE
-// Tell the compiler to do printf format std::string checking if the
-// compiler supports it; see the 'format' attribute in
-// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
-//
-// N.B.: As the GCC manual states, "[s]ince non-static C++ methods
-// have an implicit 'this' argument, the arguments of such methods
-// should be counted from two, not one."
-#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
- __attribute__((__format__(__printf__, string_index, first_to_check)))
-#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
- __attribute__((__format__(__scanf__, string_index, first_to_check)))
-#else
-#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
-#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
-#define PRINTF_ATTRIBUTE(string_index, first_to_check) \
- __attribute__((__format__(__printf__, string_index, first_to_check)))
-#define SCANF_ATTRIBUTE(string_index, first_to_check) \
- __attribute__((__format__(__scanf__, string_index, first_to_check)))
-#else
-#define PRINTF_ATTRIBUTE(string_index, first_to_check)
-#define SCANF_ATTRIBUTE(string_index, first_to_check)
-#endif
-
-// ATTRIBUTE_ALWAYS_INLINE, ATTRIBUTE_NOINLINE
-// For functions we want to force inline or not inline.
-// Introduced in gcc 3.1.
-#if ABSL_HAVE_ATTRIBUTE(always_inline) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
-#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
-#else
-#define ABSL_ATTRIBUTE_ALWAYS_INLINE
-#endif
-
-#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
-#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
-#else
-#define ABSL_ATTRIBUTE_NOINLINE
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(always_inline) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
-#define HAVE_ATTRIBUTE_ALWAYS_INLINE 1
-#else
-#define ATTRIBUTE_ALWAYS_INLINE
-#endif
-
-#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_NOINLINE __attribute__((noinline))
-#define HAVE_ATTRIBUTE_NOINLINE 1
-#else
-#define ATTRIBUTE_NOINLINE
-#endif
-
-// ATTRIBUTE_NO_TAIL_CALL
-// Prevent the compiler from optimizing away stack frames for functions which
-// end in a call to another function.
-#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
-#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
-#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
-#elif defined(__GNUC__) && !defined(__clang__)
-#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
-#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((optimize("no-optimize-sibling-calls")))
-#else
-#define ABSL_ATTRIBUTE_NO_TAIL_CALL
-#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
-#define HAVE_ATTRIBUTE_NO_TAIL_CALL 1
-#define ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
-#elif defined(__GNUC__) && !defined(__clang__)
-#define HAVE_ATTRIBUTE_NO_TAIL_CALL 1
-#define ATTRIBUTE_NO_TAIL_CALL __attribute__((optimize("no-optimize-sibling-calls")))
-#else
-#define ATTRIBUTE_NO_TAIL_CALL
-#define HAVE_ATTRIBUTE_NO_TAIL_CALL 0
-#endif
-
-// ATTRIBUTE_WEAK
-// For weak functions
-#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))
-#undef ABSL_ATTRIBUTE_WEAK
-#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
-#define ABSL_HAVE_ATTRIBUTE_WEAK 1
-#else
-#define ABSL_ATTRIBUTE_WEAK
-#define ABSL_HAVE_ATTRIBUTE_WEAK 0
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))
-#undef ATTRIBUTE_WEAK
-#define ATTRIBUTE_WEAK __attribute__((weak))
-#define HAVE_ATTRIBUTE_WEAK 1
-#else
-#define ATTRIBUTE_WEAK
-#define HAVE_ATTRIBUTE_WEAK 0
-#endif
-
-// ATTRIBUTE_NONNULL
-// Tell the compiler either that a particular function parameter
-// should be a non-null pointer, or that all pointer arguments should
-// be non-null.
-//
-// Note: As the GCC manual states, "[s]ince non-static C++ methods
-// have an implicit 'this' argument, the arguments of such methods
-// should be counted from two, not one."
-//
-// Args are indexed starting at 1.
-// For non-static class member functions, the implicit "this" argument
-// is arg 1, and the first explicit argument is arg 2.
-// For static class member functions, there is no implicit "this", and
-// the first explicit argument is arg 1.
-//
-// /* arg_a cannot be null, but arg_b can */
-// void Function(void* arg_a, void* arg_b) ATTRIBUTE_NONNULL(1);
-//
-// class C {
-// /* arg_a cannot be null, but arg_b can */
-// void Method(void* arg_a, void* arg_b) ATTRIBUTE_NONNULL(2);
-//
-// /* arg_a cannot be null, but arg_b can */
-// static void StaticMethod(void* arg_a, void* arg_b) ATTRIBUTE_NONNULL(1);
-// };
-//
-// If no arguments are provided, then all pointer arguments should be non-null.
-//
-// /* No pointer arguments may be null. */
-// void Function(void* arg_a, void* arg_b, int arg_c) ATTRIBUTE_NONNULL();
-//
-// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
-// ATTRIBUTE_NONNULL does not.
-#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
-#else
-#define ABSL_ATTRIBUTE_NONNULL(...)
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
-#else
-#define ATTRIBUTE_NONNULL(...)
-#endif
-
-// ATTRIBUTE_NORETURN
-// Tell the compiler that a given function never returns
-#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
-#elif defined(_MSC_VER)
-#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
-#else
-#define ABSL_ATTRIBUTE_NORETURN
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_NORETURN __attribute__((noreturn))
-#elif defined(_MSC_VER)
-#define ATTRIBUTE_NORETURN __declspec(noreturn)
-#else
-#define ATTRIBUTE_NORETURN
-#endif
-
-// ATTRIBUTE_NO_SANITIZE_ADDRESS
-// Tell AddressSanitizer (or other memory testing tools) to ignore a given
-// function. Useful for cases when a function reads random locations on stack,
-// calls _exit from a cloned subprocess, deliberately accesses buffer
-// out of bounds or does other scary things with memory.
-// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
-// https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
-#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
-#else
-#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
-#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
-#else
-#define ATTRIBUTE_NO_SANITIZE_ADDRESS
-#endif
-
-// ATTRIBUTE_NO_SANITIZE_MEMORY
-// Tell MemorySanitizer to relax the handling of a given function. All "Use of
-// uninitialized value" warnings from such functions will be suppressed, and all
-// values loaded from memory will be considered fully initialized.
-// This is similar to the ADDRESS_SANITIZER attribute above, but deals with
-// initializedness rather than addressability issues.
-// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
-#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
-#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
-#else
-#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
-#define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
-#else
-#define ATTRIBUTE_NO_SANITIZE_MEMORY
-#endif
-
-// ATTRIBUTE_NO_SANITIZE_THREAD
-// Tell ThreadSanitizer to not instrument a given function.
-// If you are adding this attribute, please cc dynamic-tools@ on the cl.
-// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
-// https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__) && defined(THREAD_SANITIZER)
-#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
-#else
-#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if defined(__GNUC__) && defined(THREAD_SANITIZER)
-#define ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
-#else
-#define ATTRIBUTE_NO_SANITIZE_THREAD
-#endif
-
-// ATTRIBUTE_NO_SANITIZE_UNDEFINED
-// Tell UndefinedSanitizer to ignore a given function. Useful for cases
-// where certain behavior (eg. devision by zero) is being used intentionally.
-// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
-// https://gcc.gnu.org/gcc-4.9/changes.html
-#if defined(__GNUC__) && defined(UNDEFINED_BEHAVIOR_SANITIZER)
-#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
-#else
-#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if defined(__GNUC__) && defined(UNDEFINED_BEHAVIOR_SANITIZER)
-#define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
-#else
-#define ATTRIBUTE_NO_SANITIZE_UNDEFINED
-#endif
-
-// ATTRIBUTE_NO_SANITIZE_CFI
-// Tell ControlFlowIntegrity sanitizer to not instrument a given function.
-#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
-#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
-#else
-#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
-#define ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
-#else
-#define ATTRIBUTE_NO_SANITIZE_CFI
-#endif
-
-// ATTRIBUTE_SECTION
-// Labeled sections are not supported on Darwin/iOS.
-#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
-#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
-#elif (ABSL_HAVE_ATTRIBUTE(section) || (defined(__GNUC__) && !defined(__clang__))) && \
- !(defined(__APPLE__) && defined(__MACH__))
-#define ABSL_HAVE_ATTRIBUTE_SECTION 1
-//
-// Tell the compiler/linker to put a given function into a section and define
-// "__start_ ## name" and "__stop_ ## name" symbols to bracket the section.
-// This functionality is supported by GNU linker.
-// Any function with ATTRIBUTE_SECTION must not be inlined, or it will
-// be placed into whatever section its caller is placed into.
-//
-#ifndef ABSL_ATTRIBUTE_SECTION
-#define ABSL_ATTRIBUTE_SECTION(name) __attribute__((section(#name))) __attribute__((noinline))
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#ifndef ATTRIBUTE_SECTION
-#define ATTRIBUTE_SECTION(name) __attribute__((section(#name))) __attribute__((noinline))
-#endif
-
-// Tell the compiler/linker to put a given variable into a section and define
-// "__start_ ## name" and "__stop_ ## name" symbols to bracket the section.
-// This functionality is supported by GNU linker.
-#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
-#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#ifndef ATTRIBUTE_SECTION_VARIABLE
-#define ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
-#endif
-
-//
-// Weak section declaration to be used as a global declaration
-// for ATTRIBUTE_SECTION_START|STOP(name) to compile and link
-// even without functions with ATTRIBUTE_SECTION(name).
-// DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
-// a no-op on ELF but not on Mach-O.
-//
-#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
-#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
- extern char __start_##name[] ATTRIBUTE_WEAK; \
- extern char __stop_##name[] ATTRIBUTE_WEAK
-#endif
-#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
-#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
-#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#ifndef DECLARE_ATTRIBUTE_SECTION_VARS
-#define DECLARE_ATTRIBUTE_SECTION_VARS(name) \
- extern char __start_##name[] ATTRIBUTE_WEAK; \
- extern char __stop_##name[] ATTRIBUTE_WEAK
-#endif
-#ifndef DEFINE_ATTRIBUTE_SECTION_VARS
-#define INIT_ATTRIBUTE_SECTION_VARS(name)
-#define DEFINE_ATTRIBUTE_SECTION_VARS(name)
-#endif
-
-//
-// Return void* pointers to start/end of a section of code with
-// functions having ATTRIBUTE_SECTION(name).
-// Returns 0 if no such functions exits.
-// One must DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and link.
-//
-#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(__start_##name))
-#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(__stop_##name))
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(__start_##name))
-#define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(__stop_##name))
-
-#else // !ABSL_HAVE_ATTRIBUTE_SECTION
-
-#define ABSL_HAVE_ATTRIBUTE_SECTION 0
-
-// provide dummy definitions
-#define ABSL_ATTRIBUTE_SECTION(name)
-#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
-#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
-#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
-#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
-#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
-#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#define ATTRIBUTE_SECTION(name)
-#define ATTRIBUTE_SECTION_VARIABLE(name)
-#define INIT_ATTRIBUTE_SECTION_VARS(name)
-#define DEFINE_ATTRIBUTE_SECTION_VARS(name)
-#define DECLARE_ATTRIBUTE_SECTION_VARS(name)
-#define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
-#define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
-
-#endif // ATTRIBUTE_SECTION
-
-// ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-// Support for aligning the stack on 32-bit x86.
-#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || (defined(__GNUC__) && !defined(__clang__))
-#if defined(__i386__)
-#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC __attribute__((force_align_arg_pointer))
-#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
-#elif defined(__x86_64__)
-#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
-#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-#else // !__i386__ && !__x86_64
-#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
-#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-#endif // __i386__
-#else
-#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || (defined(__GNUC__) && !defined(__clang__))
-#if defined(__i386__)
-#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC __attribute__((force_align_arg_pointer))
-#define REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
-#elif defined(__x86_64__)
-#define REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
-#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-#else // !__i386__ && !__x86_64
-#define REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
-#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-#endif // __i386__
-#else
-#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
-#define REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
-#endif
-
-// MUST_USE_RESULT
-// Tell the compiler to warn about unused return values for functions declared
-// with this macro. The macro must appear as the very first part of a function
-// declaration or definition:
-//
-// MUST_USE_RESULT Sprocket* AllocateSprocket();
-//
-// This placement has the broadest compatibility with GCC, Clang, and MSVC, with
-// both defs and decls, and with GCC-style attributes, MSVC declspec, and C++11
-// attributes. Note: past advice was to place the macro after the argument list.
-#if ABSL_HAVE_ATTRIBUTE(warn_unused_result) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
-#else
-#define ABSL_MUST_USE_RESULT
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(warn_unused_result) || (defined(__GNUC__) && !defined(__clang__))
-#define MUST_USE_RESULT __attribute__((warn_unused_result))
-#else
-#define MUST_USE_RESULT
-#endif
-
-// ATTRIBUTE_HOT, ATTRIBUTE_COLD
-// Tell GCC that a function is hot or cold. GCC can use this information to
-// improve static analysis, i.e. a conditional branch to a cold function
-// is likely to be not-taken.
-// This annotation is used for function declarations, e.g.:
-// int foo() ATTRIBUTE_HOT;
-#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
-#else
-#define ABSL_ATTRIBUTE_HOT
-#endif
-
-#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
-#else
-#define ABSL_ATTRIBUTE_COLD
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_HOT __attribute__((hot))
-#else
-#define ATTRIBUTE_HOT
-#endif
-
-#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_COLD __attribute__((cold))
-#else
-#define ATTRIBUTE_COLD
-#endif
-
-// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
-//
-// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
-// macro used as an attribute to mark functions that must always or never be
-// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
-//
-// For reference on the LLVM XRay instrumentation, see
-// http://llvm.org/docs/XRay.html.
-//
-// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
-// will always get the XRay instrumentation sleds. These sleds may introduce
-// some binary size and runtime overhead and must be used sparingly.
-//
-// These attributes only take effect when the following conditions are met:
-//
-// - The file/target is built in at least C++11 mode, with a Clang compiler
-// that supports XRay attributes.
-// - The file/target is built with the -fxray-instrument flag set for the
-// Clang/LLVM compiler.
-// - The function is defined in the translation unit (the compiler honors the
-// attribute in either the definition or the declaration, and must match).
-//
-// There are cases when, even when building with XRay instrumentation, users
-// might want to control specifically which functions are instrumented for a
-// particular build using special-case lists provided to the compiler. These
-// special case lists are provided to Clang via the
-// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
-// attributes in source take precedence over these special-case lists.
-//
-// To disable the XRay attributes at build-time, users may define
-// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
-// packages/targets, as this may lead to conflicting definitions of functions at
-// link-time.
-//
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && !defined(ABSL_NO_XRAY_ATTRIBUTES)
-#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
-#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
-#define ABSL_XRAY_LOG_ARGS(N) [[ clang::xray_always_instrument, clang::xray_log_args(N) ]]
-#else
-#define ABSL_XRAY_ALWAYS_INSTRUMENT
-#define ABSL_XRAY_NEVER_INSTRUMENT
-#define ABSL_XRAY_LOG_ARGS(N)
-#endif
-
-// -----------------------------------------------------------------------------
-// Variable Attributes
-// -----------------------------------------------------------------------------
-
-// ATTRIBUTE_UNUSED
-// Prevent the compiler from complaining about or optimizing away variables
-// that appear unused.
-#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
-#undef ABSL_ATTRIBUTE_UNUSED
-#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
-#else
-#define ABSL_ATTRIBUTE_UNUSED
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
-#undef ATTRIBUTE_UNUSED
-#define ATTRIBUTE_UNUSED __attribute__((__unused__))
-#else
-#define ATTRIBUTE_UNUSED
-#endif
-
-// ATTRIBUTE_INITIAL_EXEC
-// Tell the compiler to use "initial-exec" mode for a thread-local variable.
-// See http://people.redhat.com/drepper/tls.pdf for the gory details.
-#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
-#else
-#define ABSL_ATTRIBUTE_INITIAL_EXEC
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
-#else
-#define ATTRIBUTE_INITIAL_EXEC
-#endif
-
-// ATTRIBUTE_PACKED
-// Prevent the compiler from padding a structure to natural alignment
-#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
-#else
-#define ABSL_ATTRIBUTE_PACKED
-#endif
-
-// To be deleted macros. All macros are going te be renamed with ABSL_ prefix.
-#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
-#define ATTRIBUTE_PACKED __attribute__((__packed__))
-#else
-#define ATTRIBUTE_PACKED
-#endif
-
-// ABSL_CONST_INIT
-// A variable declaration annotated with the ABSL_CONST_INIT attribute will
-// not compile (on supported platforms) unless the variable has a constant
-// initializer. This is useful for variables with static and thread storage
-// duration, because it guarantees that they will not suffer from the so-called
-// "static init order fiasco".
-//
-// Sample usage:
-//
-// ABSL_CONST_INIT static MyType my_var = MakeMyType(...);
-//
-// Note that this attribute is redundant if the variable is declared constexpr.
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
-// NOLINTNEXTLINE(whitespace/braces) (b/36288871)
-#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
-#else
-#define ABSL_CONST_INIT
-#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
-
-#endif // THIRD_PARTY_ABSL_BASE_ATTRIBUTES_H_
diff --git a/Firestore/Port/absl/absl_config.h b/Firestore/Port/absl/absl_config.h
deleted file mode 100644
index 70f4d86..0000000
--- a/Firestore/Port/absl/absl_config.h
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-// Defines preprocessor macros describing the presence of "features" available.
-// This facilitates writing portable code by parameterizing the compilation
-// based on the presence or lack of a feature.
-//
-// We define a feature as some interface we wish to program to: for example,
-// some library function or system call.
-//
-// For example, suppose a programmer wants to write a program that uses the
-// 'mmap' system call. Then one might write:
-//
-// #include "absl/base/config.h"
-//
-// #ifdef ABSL_HAVE_MMAP
-// #include "sys/mman.h"
-// #endif //ABSL_HAVE_MMAP
-//
-// ...
-// #ifdef ABSL_HAVE_MMAP
-// void *ptr = mmap(...);
-// ...
-// #endif // ABSL_HAVE_MMAP
-//
-// As a special note, using feature macros from config.h to determine whether
-// to include a particular header requires violating the style guide's required
-// ordering for headers: this is permitted.
-
-#ifndef THIRD_PARTY_ABSL_BASE_CONFIG_H_
-#define THIRD_PARTY_ABSL_BASE_CONFIG_H_
-
-// Included for the __GLIBC__ macro (or similar macros on other systems).
-#include <limits.h>
-
-#ifdef __cplusplus
-// Included for __GLIBCXX__, _LIBCPP_VERSION
-#include <cstddef>
-#endif // __cplusplus
-
-// If we're using glibc, make sure we meet a minimum version requirement
-// before we proceed much further.
-//
-// We have chosen glibc 2.12 as the minimum as it was tagged for release
-// in May, 2010 and includes some functionality used in Google software
-// (for instance pthread_setname_np):
-// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
-#ifdef __GLIBC_PREREQ
-#if !__GLIBC_PREREQ(2, 12)
-#error "Minimum required version of glibc is 2.12."
-#endif
-#endif
-
-// ABSL_HAVE_BUILTIN is a function-like feature checking macro.
-// It's a wrapper around __has_builtin, which is defined by only clang now.
-// It evaluates to 1 if the builtin is supported or 0 if not.
-// Define it to avoid an extra level of #ifdef __has_builtin check.
-// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
-#ifdef __has_builtin
-#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
-#else
-#define ABSL_HAVE_BUILTIN(x) 0
-#endif
-
-// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE is defined when
-// std::is_trivially_destructible<T> is supported.
-//
-// All supported compilers using libc++ have it, as does gcc >= 4.8
-// using libstdc++, as does Visual Studio.
-// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/libstdc++/manual/manual/status.html#status.iso.2011
-// is the first version where std::is_trivially_destructible no longer
-// appeared as missing in the Type properties row.
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
-#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
-#elif defined(_LIBCPP_VERSION) || \
- (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
- (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
- defined(_MSC_VER)
-#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
-#endif
-
-// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE is defined when
-// std::is_trivially_default_constructible<T> and
-// std::is_trivially_copy_constructible<T> are supported.
-//
-// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE is defined when
-// std::is_trivially_copy_assignable<T> is supported.
-//
-// Clang with libc++ supports it, as does gcc >= 5.1 with either
-// libc++ or libstdc++, as does Visual Studio.
-// https://gcc.gnu.org/gcc-5/changes.html lists as new
-// "std::is_trivially_constructible, std::is_trivially_assignable
-// etc."
-#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
-#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
-#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
-#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
-#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
- (!defined(__clang__) && defined(__GNUC__) && \
- (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
- (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
- defined(_MSC_VER)
-#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
-#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
-#endif
-
-// ABSL_HAVE_THREAD_LOCAL is defined when C++11's thread_local is available.
-// Clang implements thread_local keyword but Xcode did not support the
-// implementation until Xcode 8.
-#ifdef ABSL_HAVE_THREAD_LOCAL
-#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
-#elif !defined(__apple_build_version__) || __apple_build_version__ >= 8000042
-#define ABSL_HAVE_THREAD_LOCAL 1
-#endif
-
-// ABSL_HAVE_INTRINSIC_INT128 is defined when the implementation provides the
-// 128 bit integral type: __int128.
-//
-// __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is supported.
-// Clang on ppc64 and aarch64 are exceptions where __int128 exists but has a
-// sporadic compiler crashing bug. Nvidia's nvcc also defines __GNUC__ and
-// __SIZEOF_INT128__ but not all versions that do this support __int128. Support
-// has been tested for versions >= 7.
-#ifdef ABSL_HAVE_INTRINSIC_INT128
-#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
-#elif (defined(__clang__) && defined(__SIZEOF_INT128__) && !defined(__ppc64__) && \
- !defined(__aarch64__)) || \
- (defined(__CUDACC__) && defined(__SIZEOF_INT128__) && __CUDACC_VER__ >= 70000) || \
- (!defined(__clang__) && !defined(__CUDACC__) && defined(__GNUC__) && \
- defined(__SIZEOF_INT128__))
-#define ABSL_HAVE_INTRINSIC_INT128 1
-#endif
-
-// Operating system-specific features.
-//
-// Currently supported operating systems and associated preprocessor
-// symbols:
-//
-// Linux and Linux-derived __linux__
-// Android __ANDROID__ (implies __linux__)
-// Linux (non-Android) __linux__ && !__ANDROID__
-// Darwin (Mac OS X and iOS) __APPLE__ && __MACH__
-// Akaros (http://akaros.org) __ros__
-// Windows _WIN32
-// NaCL __native_client__
-// AsmJS __asmjs__
-// Fuschia __Fuchsia__
-//
-// Note that since Android defines both __ANDROID__ and __linux__, one
-// may probe for either Linux or Android by simply testing for __linux__.
-//
-
-// ABSL_HAVE_MMAP is defined when the system has an mmap(2) implementation
-// as defined in POSIX.1-2001.
-#ifdef ABSL_HAVE_MMAP
-#error ABSL_HAVE_MMAP cannot be directly set
-#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__ros__) || \
- defined(__native_client__) || defined(__asmjs__) || defined(__Fuchsia__)
-#define ABSL_HAVE_MMAP 1
-#endif
-
-// ABSL_HAS_PTHREAD_GETSCHEDPARAM is defined when the system implements the
-// pthread_(get|set)schedparam(3) functions as defined in POSIX.1-2001.
-#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
-#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
-#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__ros__)
-#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
-#endif
-
-// ABSL_HAVE_SCHED_YIELD is defined when the system implements
-// sched_yield(2) as defined in POSIX.1-2001.
-#ifdef ABSL_HAVE_SCHED_YIELD
-#error ABSL_HAVE_SCHED_YIELD cannot be directly set
-#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
-#define ABSL_HAVE_SCHED_YIELD 1
-#endif
-
-// ABSL_HAVE_SEMAPHORE_H is defined when the system supports the <semaphore.h>
-// header and sem_open(3) family of functions as standardized in POSIX.1-2001.
-//
-// Note: While Apple does have <semaphore.h> for both iOS and macOS, it is
-// explicity deprecated and will cause build failures if enabled for those
-// systems. We side-step the issue by not defining it here for Apple platforms.
-#ifdef ABSL_HAVE_SEMAPHORE_H
-#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
-#elif defined(__linux__) || defined(__ros__)
-#define ABSL_HAVE_SEMAPHORE_H 1
-#endif
-
-// Library-specific features.
-#ifdef ABSL_HAVE_ALARM
-#error ABSL_HAVE_ALARM cannot be directly set
-#elif defined(__GOOGLE_GRTE_VERSION__)
-// feature tests for Google's GRTE
-#define ABSL_HAVE_ALARM 1
-#elif defined(__GLIBC__)
-// feature test for glibc
-#define ABSL_HAVE_ALARM 1
-#elif defined(_MSC_VER)
-// feature tests for Microsoft's library
-#elif defined(__native_client__)
-#else
-// other standard libraries
-#define ABSL_HAVE_ALARM 1
-#endif
-
-#if defined(_STLPORT_VERSION)
-#error "STLPort is not supported."
-#endif
-
-// -----------------------------------------------------------------------------
-// Endianness
-// -----------------------------------------------------------------------------
-// Define ABSL_IS_LITTLE_ENDIAN, ABSL_IS_BIG_ENDIAN.
-// Some compilers or system headers provide macros to specify endianness.
-// Unfortunately, there is no standard for the names of the macros or even of
-// the header files.
-// Reference: https://sourceforge.net/p/predef/wiki/Endianness/
-#if defined(ABSL_IS_BIG_ENDIAN) || defined(ABSL_IS_LITTLE_ENDIAN)
-#error "ABSL_IS_(BIG|LITTLE)_ENDIAN cannot be directly set."
-
-#elif defined(__GLIBC__) || defined(__linux__)
-// Operating systems that use the GNU C library generally provide <endian.h>
-// containing __BYTE_ORDER, __LITTLE_ENDIAN, __BIG_ENDIAN.
-#include <endian.h>
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define ABSL_IS_LITTLE_ENDIAN 1
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define ABSL_IS_BIG_ENDIAN 1
-#else // __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN
-#error "Unknown endianness"
-#endif // __BYTE_ORDER
-
-#elif defined(__APPLE__) && defined(__MACH__)
-// Apple has <machine/endian.h> containing BYTE_ORDER, BIG_ENDIAN,
-// LITTLE_ENDIAN.
-#include <machine/endian.h> // NOLINT(build/include)
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define ABSL_IS_LITTLE_ENDIAN 1
-#elif BYTE_ORDER == BIG_ENDIAN
-#define ABSL_IS_BIG_ENDIAN 1
-#else // BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN
-#error "Unknown endianness"
-#endif // BYTE_ORDER
-
-#elif defined(_WIN32)
-// Assume Windows is little-endian.
-#define ABSL_IS_LITTLE_ENDIAN 1
-
-#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || \
- defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
-#define ABSL_IS_LITTLE_ENDIAN 1
-
-#elif defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || \
- defined(__AARCH64EB__) || defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
-#define ABSL_IS_BIG_ENDIAN 1
-
-#else
-#error "absl endian detection needs to be set up on your platform."
-#endif
-
-// ABSL_HAVE_EXCEPTIONS is defined when exceptions are enabled. Many
-// compilers support a "no exceptions" mode that disables exceptions.
-//
-// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
-//
-// - Code using `throw` and `try` may not compile.
-// - The `noexcept` specifier will still compile and behave as normal.
-// - The `noexcept` operator may still return `false`.
-//
-// For further details, consult the compiler's documentation.
-#ifdef ABSL_HAVE_EXCEPTIONS
-#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
-
-#elif defined(__clang__)
-// TODO
-// Switch to using __cpp_exceptions when we no longer support versions < 3.6.
-// For details on this check, see:
-// https://goo.gl/PilDrJ
-#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
-#define ABSL_HAVE_EXCEPTIONS 1
-#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
-
-// Handle remaining special cases and default to exceptions being supported.
-#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
- !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
- !(defined(_MSC_VER) && !defined(_CPPUNWIND))
-#define ABSL_HAVE_EXCEPTIONS 1
-#endif
-
-#endif // THIRD_PARTY_ABSL_BASE_CONFIG_H_
diff --git a/Firestore/Port/absl/absl_endian.h b/Firestore/Port/absl/absl_endian.h
deleted file mode 100644
index 2c51a27..0000000
--- a/Firestore/Port/absl/absl_endian.h
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
-#define ABSL_BASE_INTERNAL_ENDIAN_H_
-
-// The following guarantees declaration of the byte swap functions
-#ifdef _MSC_VER
-#include <stdlib.h> // NOLINT(build/include)
-#elif defined(__APPLE__) && defined(__MACH__)
-// Mac OS X / Darwin features
-#include <libkern/OSByteOrder.h>
-#elif defined(__GLIBC__)
-#include <byteswap.h> // IWYU pragma: export
-#endif
-
-#include <cstdint>
-#include "Firestore/Port/absl/absl_port.h"
-
-namespace absl {
-
-// Use compiler byte-swapping intrinsics if they are available. 32-bit
-// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
-// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
-// For simplicity, we enable them all only for GCC 4.8.0 or later.
-#if defined(__clang__) || \
- (defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
-inline uint64_t gbswap_64(uint64_t host_int) {
- return __builtin_bswap64(host_int);
-}
-inline uint32_t gbswap_32(uint32_t host_int) {
- return __builtin_bswap32(host_int);
-}
-inline uint16 gbswap_16(uint16 host_int) {
- return __builtin_bswap16(host_int);
-}
-
-#elif defined(_MSC_VER)
-inline uint64_t gbswap_64(uint64_t host_int) {
- return _byteswap_uint64(host_int);
-}
-inline uint32_t gbswap_32(uint32_t host_int) {
- return _byteswap_ulong(host_int);
-}
-inline uint16 gbswap_16(uint16 host_int) {
- return _byteswap_ushort(host_int);
-}
-
-#elif defined(__APPLE__) && defined(__MACH__)
-inline uint64_t gbswap_64(uint64_t host_int) {
- return OSSwapInt16(host_int);
-}
-inline uint32_t gbswap_32(uint32_t host_int) {
- return OSSwapInt32(host_int);
-}
-inline uint16 gbswap_16(uint16 host_int) {
- return OSSwapInt64(host_int);
-}
-
-#else
-inline uint64_t gbswap_64(uint64_t host_int) {
-#if defined(__GNUC__) && defined(__x86_64__) && !(defined(__APPLE__) && defined(__MACH__))
- // Adapted from /usr/include/byteswap.h. Not available on Mac.
- if (__builtin_constant_p(host_int)) {
- return __bswap_constant_64(host_int);
- } else {
- register uint64_t result;
- __asm__("bswap %0" : "=r"(result) : "0"(host_int));
- return result;
- }
-#elif defined(__GLIBC__)
- return bswap_64(host_int);
-#else
- return (((x & GG_ULONGLONG(0xFF)) << 56) | ((x & GG_ULONGLONG(0xFF00)) << 40) |
- ((x & GG_ULONGLONG(0xFF0000)) << 24) | ((x & GG_ULONGLONG(0xFF000000)) << 8) |
- ((x & GG_ULONGLONG(0xFF00000000)) >> 8) | ((x & GG_ULONGLONG(0xFF0000000000)) >> 24) |
- ((x & GG_ULONGLONG(0xFF000000000000)) >> 40) |
- ((x & GG_ULONGLONG(0xFF00000000000000)) >> 56));
-#endif // bswap_64
-}
-
-inline uint32_t gbswap_32(uint32_t host_int) {
-#if defined(__GLIBC__)
- return bswap_32(host_int);
-#else
- return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) |
- ((x & 0xFF000000) >> 24));
-#endif
-}
-
-inline uint16 gbswap_16(uint16 host_int) {
-#if defined(__GLIBC__)
- return bswap_16(host_int);
-#else
- return (uint16)(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)); // NOLINT
-#endif
-}
-
-#endif // intrinics available
-
-#ifdef ABSL_IS_LITTLE_ENDIAN
-
-// Definitions for ntohl etc. that don't require us to include
-// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
-// than just #defining them because in debug mode, gcc doesn't
-// correctly handle the (rather involved) definitions of bswap_32.
-// gcc guarantees that inline functions are as fast as macros, so
-// this isn't a performance hit.
-inline uint16 ghtons(uint16 x) {
- return gbswap_16(x);
-}
-inline uint32_t ghtonl(uint32_t x) {
- return gbswap_32(x);
-}
-inline uint64_t ghtonll(uint64_t x) {
- return gbswap_64(x);
-}
-
-#elif defined ABSL_IS_BIG_ENDIAN
-
-// These definitions are simpler on big-endian machines
-// These are functions instead of macros to avoid self-assignment warnings
-// on calls such as "i = ghtnol(i);". This also provides type checking.
-inline uint16 ghtons(uint16 x) {
- return x;
-}
-inline uint32_t ghtonl(uint32_t x) {
- return x;
-}
-inline uint64_t ghtonll(uint64_t x) {
- return x;
-}
-
-#else
-#error \
- "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
- "ABSL_IS_LITTLE_ENDIAN must be defined"
-#endif // byte order
-
-inline uint16 gntohs(uint16 x) {
- return ghtons(x);
-}
-inline uint32_t gntohl(uint32_t x) {
- return ghtonl(x);
-}
-inline uint64_t gntohll(uint64_t x) {
- return ghtonll(x);
-}
-
-// Utilities to convert numbers between the current hosts's native byte
-// order and little-endian byte order
-//
-// Load/Store methods are alignment safe
-namespace little_endian {
-// Conversion functions.
-#ifdef ABSL_IS_LITTLE_ENDIAN
-
-inline uint16 FromHost16(uint16 x) {
- return x;
-}
-inline uint16 ToHost16(uint16 x) {
- return x;
-}
-
-inline uint32_t FromHost32(uint32_t x) {
- return x;
-}
-inline uint32_t ToHost32(uint32_t x) {
- return x;
-}
-
-inline uint64_t FromHost64(uint64_t x) {
- return x;
-}
-inline uint64_t ToHost64(uint64_t x) {
- return x;
-}
-
-inline constexpr bool IsLittleEndian() {
- return true;
-}
-
-#elif defined ABSL_IS_BIG_ENDIAN
-
-inline uint16 FromHost16(uint16 x) {
- return gbswap_16(x);
-}
-inline uint16 ToHost16(uint16 x) {
- return gbswap_16(x);
-}
-
-inline uint32_t FromHost32(uint32_t x) {
- return gbswap_32(x);
-}
-inline uint32_t ToHost32(uint32_t x) {
- return gbswap_32(x);
-}
-
-inline uint64_t FromHost64(uint64_t x) {
- return gbswap_64(x);
-}
-inline uint64_t ToHost64(uint64_t x) {
- return gbswap_64(x);
-}
-
-inline constexpr bool IsLittleEndian() {
- return false;
-}
-
-#endif /* ENDIAN */
-
-// Functions to do unaligned loads and stores in little-endian order.
-inline uint16 Load16(const void *p) {
- return ToHost16(UNALIGNED_LOAD16(p));
-}
-
-inline void Store16(void *p, uint16 v) {
- UNALIGNED_STORE16(p, FromHost16(v));
-}
-
-inline uint32_t Load32(const void *p) {
- return ToHost32(UNALIGNED_LOAD32(p));
-}
-
-inline void Store32(void *p, uint32_t v) {
- UNALIGNED_STORE32(p, FromHost32(v));
-}
-
-inline uint64_t Load64(const void *p) {
- return ToHost64(UNALIGNED_LOAD64(p));
-}
-
-inline void Store64(void *p, uint64_t v) {
- UNALIGNED_STORE64(p, FromHost64(v));
-}
-
-} // namespace little_endian
-
-// Utilities to convert numbers between the current hosts's native byte
-// order and big-endian byte order (same as network byte order)
-//
-// Load/Store methods are alignment safe
-namespace big_endian {
-#ifdef ABSL_IS_LITTLE_ENDIAN
-
-inline uint16 FromHost16(uint16 x) {
- return gbswap_16(x);
-}
-inline uint16 ToHost16(uint16 x) {
- return gbswap_16(x);
-}
-
-inline uint32_t FromHost32(uint32_t x) {
- return gbswap_32(x);
-}
-inline uint32_t ToHost32(uint32_t x) {
- return gbswap_32(x);
-}
-
-inline uint64_t FromHost64(uint64_t x) {
- return gbswap_64(x);
-}
-inline uint64_t ToHost64(uint64_t x) {
- return gbswap_64(x);
-}
-
-inline constexpr bool IsLittleEndian() {
- return true;
-}
-
-#elif defined ABSL_IS_BIG_ENDIAN
-
-inline uint16 FromHost16(uint16 x) {
- return x;
-}
-inline uint16 ToHost16(uint16 x) {
- return x;
-}
-
-inline uint32_t FromHost32(uint32_t x) {
- return x;
-}
-inline uint32_t ToHost32(uint32_t x) {
- return x;
-}
-
-inline uint64_t FromHost64(uint64_t x) {
- return x;
-}
-inline uint64_t ToHost64(uint64_t x) {
- return x;
-}
-
-inline constexpr bool IsLittleEndian() {
- return false;
-}
-
-#endif /* ENDIAN */
-
-// Functions to do unaligned loads and stores in big-endian order.
-inline uint16 Load16(const void *p) {
- return ToHost16(UNALIGNED_LOAD16(p));
-}
-
-inline void Store16(void *p, uint16 v) {
- UNALIGNED_STORE16(p, FromHost16(v));
-}
-
-inline uint32_t Load32(const void *p) {
- return ToHost32(UNALIGNED_LOAD32(p));
-}
-
-inline void Store32(void *p, uint32_t v) {
- UNALIGNED_STORE32(p, FromHost32(v));
-}
-
-inline uint64_t Load64(const void *p) {
- return ToHost64(UNALIGNED_LOAD64(p));
-}
-
-inline void Store64(void *p, uint64_t v) {
- UNALIGNED_STORE64(p, FromHost64(v));
-}
-
-} // namespace big_endian
-
-} // namespace absl
-
-#endif // ABSL_BASE_INTERNAL_ENDIAN_H_
diff --git a/Firestore/Port/absl/absl_integral_types.h b/Firestore/Port/absl/absl_integral_types.h
deleted file mode 100644
index 47da9c1..0000000
--- a/Firestore/Port/absl/absl_integral_types.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-// Basic integer type definitions for various platforms
-//
-// This code is compiled directly on many platforms, including client
-// platforms like Windows, Mac, and embedded systems. Before making
-// any changes here, make sure that you're not breaking any platforms.
-//
-
-#ifndef THIRD_PARTY_ABSL_BASE_INTEGRAL_TYPES_H_
-#define THIRD_PARTY_ABSL_BASE_INTEGRAL_TYPES_H_
-
-// These typedefs are also defined in base/swig/google.swig. In the
-// SWIG environment, we use those definitions and avoid duplicate
-// definitions here with an ifdef. The definitions should be the
-// same in both files, and ideally be only defined in this file.
-#ifndef SWIG
-// Standard typedefs
-// Signed integer types with width of exactly 8, 16, 32, or 64 bits
-// respectively, for use when exact sizes are required.
-typedef signed char schar;
-typedef signed char int8;
-typedef short int16;
-typedef int int32;
-#ifdef COMPILER_MSVC
-typedef __int64 int64;
-#else
-typedef long long int64;
-#endif /* COMPILER_MSVC */
-
-// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
-// places. Use the signed types unless your variable represents a bit
-// pattern (eg a hash value) or you really need the extra bit. Do NOT
-// use 'unsigned' to express "this value should always be positive";
-// use assertions for this.
-
-// Unsigned integer types with width of exactly 8, 16, 32, or 64 bits
-// respectively, for use when exact sizes are required.
-typedef unsigned char uint8;
-typedef unsigned short uint16;
-typedef unsigned int uint32;
-#ifdef COMPILER_MSVC
-typedef unsigned __int64 uint64;
-#else
-typedef unsigned long long uint64;
-#endif /* COMPILER_MSVC */
-
-// A type to represent a Unicode code-point value. As of Unicode 4.0,
-// such values require up to 21 bits.
-// (For type-checking on pointers, make this explicitly signed,
-// and it should always be the signed version of whatever int32 is.)
-typedef signed int char32;
-
-// A type to represent a natural machine word (for e.g. efficiently
-// scanning through memory for checksums or index searching). Don't use
-// this for storing normal integers. Ideally this would be just
-// unsigned int, but our 64-bit architectures use the LP64 model
-// (http://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models), hence
-// their ints are only 32 bits. We want to use the same fundamental
-// type on all archs if possible to preserve *printf() compatability.
-typedef unsigned long uword_t;
-
-#endif /* SWIG */
-
-// long long macros to be used because gcc and vc++ use different suffixes,
-// and different size specifiers in format strings
-#undef GG_LONGLONG
-#undef GG_ULONGLONG
-#undef GG_LL_FORMAT
-
-#ifdef COMPILER_MSVC /* if Visual C++ */
-
-// VC++ long long suffixes
-#define GG_LONGLONG(x) x##I64
-#define GG_ULONGLONG(x) x##UI64
-
-// Length modifier in printf format std::string for int64's (e.g. within %d)
-#define GG_LL_FORMAT "I64" // As in printf("%I64d", ...)
-#define GG_LL_FORMAT_W L"I64"
-
-#else /* not Visual C++ */
-
-#define GG_LONGLONG(x) x##LL
-#define GG_ULONGLONG(x) x##ULL
-#define GG_LL_FORMAT "ll" // As in "%lld". Note that "q" is poor form also.
-#define GG_LL_FORMAT_W L"ll"
-
-#endif // COMPILER_MSVC
-
-// There are still some requirements that we build these headers in
-// C-compatibility mode. Unfortunately, -Wall doesn't like c-style
-// casts, and C doesn't know how to read braced-initialization for
-// integers.
-#if defined(__cplusplus)
-const uint8 kuint8max{0xFF};
-const uint16 kuint16max{0xFFFF};
-const uint32 kuint32max{0xFFFFFFFF};
-const uint64 kuint64max{GG_ULONGLONG(0xFFFFFFFFFFFFFFFF)};
-const int8 kint8min{~0x7F};
-const int8 kint8max{0x7F};
-const int16 kint16min{~0x7FFF};
-const int16 kint16max{0x7FFF};
-const int32 kint32min{~0x7FFFFFFF};
-const int32 kint32max{0x7FFFFFFF};
-const int64 kint64min{GG_LONGLONG(~0x7FFFFFFFFFFFFFFF)};
-const int64 kint64max{GG_LONGLONG(0x7FFFFFFFFFFFFFFF)};
-#else // not __cplusplus, this branch exists only for C-compat
-static const uint8 kuint8max = ((uint8)0xFF);
-static const uint16 kuint16max = ((uint16)0xFFFF);
-static const uint32 kuint32max = ((uint32)0xFFFFFFFF);
-static const uint64 kuint64max = ((uint64)GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
-static const int8 kint8min = ((int8)~0x7F);
-static const int8 kint8max = ((int8)0x7F);
-static const int16 kint16min = ((int16)~0x7FFF);
-static const int16 kint16max = ((int16)0x7FFF);
-static const int32 kint32min = ((int32)~0x7FFFFFFF);
-static const int32 kint32max = ((int32)0x7FFFFFFF);
-static const int64 kint64min = ((int64)GG_LONGLONG(~0x7FFFFFFFFFFFFFFF));
-static const int64 kint64max = ((int64)GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
-#endif // __cplusplus
-
-// The following are not real constants, but we list them so CodeSearch and
-// other tools find them, in case people are looking for the above constants
-// under different names:
-// kMaxUint8, kMaxUint16, kMaxUint32, kMaxUint64
-// kMinInt8, kMaxInt8, kMinInt16, kMaxInt16, kMinInt32, kMaxInt32,
-// kMinInt64, kMaxInt64
-
-// No object has kIllegalFprint as its Fingerprint.
-typedef uint64 Fprint;
-static const Fprint kIllegalFprint = 0;
-static const Fprint kMaxFprint = GG_ULONGLONG(0xFFFFFFFFFFFFFFFF);
-
-#endif // THIRD_PARTY_ABSL_BASE_INTEGRAL_TYPES_H_
diff --git a/Firestore/Port/absl/absl_port.h b/Firestore/Port/absl/absl_port.h
deleted file mode 100644
index eee21fc..0000000
--- a/Firestore/Port/absl/absl_port.h
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-// Various portability macros, type definitions, and inline functions
-// This file is used for both C and C++!
-//
-// These are weird things we need to do to get this compiling on
-// random systems (and on SWIG).
-//
-// This files is structured into the following high-level categories:
-// - Platform checks (OS, Compiler, C++, Library)
-// - Feature macros
-// - Utility macros
-// - Utility functions
-// - Type alias
-// - Predefined system/language macros
-// - Predefined system/language functions
-// - Compiler attributes (__attribute__)
-// - Performance optimization (alignment, branch prediction)
-// - Obsolete
-//
-
-#ifndef THIRD_PARTY_ABSL_BASE_PORT_H_
-#define THIRD_PARTY_ABSL_BASE_PORT_H_
-
-#include <assert.h>
-#include <limits.h> // So we can set the bounds of our types
-#include <stdlib.h> // for free()
-#include <string.h> // for memcpy()
-
-#include "Firestore/Port/absl/absl_attributes.h"
-#include "Firestore/Port/absl/absl_config.h"
-#include "Firestore/Port/absl/absl_integral_types.h"
-
-#ifdef SWIG
-%include "attributes.h"
-#endif
-
-// -----------------------------------------------------------------------------
-// Operating System Check
-// -----------------------------------------------------------------------------
-
-#if defined(__CYGWIN__)
-#error "Cygwin is not supported."
-#endif
-
-// -----------------------------------------------------------------------------
-// Compiler Check
-// -----------------------------------------------------------------------------
-
-// We support MSVC++ 14.0 update 2 and later.
-#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918
-#error "This package requires Visual Studio 2015 Update 2 or higher"
-#endif
-
-// We support gcc 4.7 and later.
-#if defined(__GNUC__) && !defined(__clang__)
-#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
-#error "This package requires gcc 4.7 or higher"
-#endif
-#endif
-
-// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
-// This corresponds to Apple Xcode version 4.5.
-#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
-#error "This package requires __apple_build_version__ of 4211165 or higher"
-#endif
-
-// -----------------------------------------------------------------------------
-// C++ Version Check
-// -----------------------------------------------------------------------------
-
-// Enforce C++11 as the minimum. Note that Visual Studio has not
-// advanced __cplusplus despite being good enough for our purposes, so
-// so we exempt it from the check.
-#if defined(__cplusplus) && !defined(_MSC_VER) && !defined(SWIG)
-#if __cplusplus < 201103L
-#error "C++ versions less than C++11 are not supported."
-#endif
-#endif
-
-// -----------------------------------------------------------------------------
-// C++ Standard Library Check
-// -----------------------------------------------------------------------------
-
-#if defined(__cplusplus)
-#include <cstddef>
-#if defined(_STLPORT_VERSION)
-#error "STLPort is not supported."
-#endif
-#endif
-
-// -----------------------------------------------------------------------------
-// Feature Macros
-// -----------------------------------------------------------------------------
-
-// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
-// We assume __thread is supported on Linux when compiled with Clang or compiled
-// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
-#ifdef ABSL_HAVE_TLS
-#error ABSL_HAVE_TLS cannot be directly set
-#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
-#define ABSL_HAVE_TLS 1
-#endif
-
-// -----------------------------------------------------------------------------
-// Utility Macros
-// -----------------------------------------------------------------------------
-
-// ABSL_FUNC_PTR_TO_CHAR_PTR
-// On some platforms, a "function pointer" points to a function descriptor
-// rather than directly to the function itself.
-// Use ABSL_FUNC_PTR_TO_CHAR_PTR(func) to get a char-pointer to the first
-// instruction of the function func.
-#if defined(__cplusplus)
-#if (defined(__powerpc__) && !(_CALL_ELF > 1)) || defined(__ia64)
-// use opd section for function descriptors on these platforms, the function
-// address is the first word of the descriptor
-namespace absl {
-enum { kPlatformUsesOPDSections = 1 };
-} // namespace absl
-#define ABSL_FUNC_PTR_TO_CHAR_PTR(func) (reinterpret_cast<char **>(func)[0])
-#else // not PPC or IA64
-namespace absl {
-enum { kPlatformUsesOPDSections = 0 };
-} // namespace absl
-#define ABSL_FUNC_PTR_TO_CHAR_PTR(func) (reinterpret_cast<char *>(func))
-#endif // PPC or IA64
-#endif // __cplusplus
-
-// -----------------------------------------------------------------------------
-// Utility Functions
-// -----------------------------------------------------------------------------
-
-#if defined(__cplusplus)
-namespace absl {
-constexpr char PathSeparator() {
-#ifdef _WIN32
- return '\\';
-#else
- return '/';
-#endif
-}
-} // namespace absl
-#endif // __cplusplus
-
-// -----------------------------------------------------------------------------
-// Type Alias
-// -----------------------------------------------------------------------------
-
-#ifdef _MSC_VER
-// uid_t
-// MSVC doesn't have uid_t
-typedef int uid_t;
-
-// pid_t
-// Defined all over the place.
-typedef int pid_t;
-
-// ssize_t
-// VC++ doesn't understand "ssize_t". SSIZE_T is defined in <basetsd.h>.
-#include <basetsd.h>
-typedef SSIZE_T ssize_t;
-#endif // _MSC_VER
-
-// -----------------------------------------------------------------------------
-// Predefined System/Language Macros
-// -----------------------------------------------------------------------------
-
-// MAP_ANONYMOUS
-#if defined(__APPLE__) && defined(__MACH__)
-// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is
-// deprecated. In Darwin, MAP_ANON is all there is.
-#if !defined MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif // !MAP_ANONYMOUS
-#endif // __APPLE__ && __MACH__
-
-// PATH_MAX
-// You say tomato, I say atotom
-#ifdef _MSC_VER
-#define PATH_MAX MAX_PATH
-#endif
-
-// -----------------------------------------------------------------------------
-// Performance Optimization
-// -----------------------------------------------------------------------------
-
-// Alignment
-
-// CACHELINE_SIZE, CACHELINE_ALIGNED
-// Deprecated: Use ABSL_CACHELINE_SIZE, ABSL_CACHELINE_ALIGNED.
-// Note: When C++17 is available, consider using the following:
-// - std::hardware_constructive_interference_size
-// - std::hardware_destructive_interference_size
-// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
-#if defined(__GNUC__)
-#if defined(__i386__) || defined(__x86_64__)
-#define CACHELINE_SIZE 64
-#define ABSL_CACHELINE_SIZE 64
-#elif defined(__powerpc64__)
-#define CACHELINE_SIZE 128
-#define ABSL_CACHELINE_SIZE 128
-#elif defined(__aarch64__)
-// We would need to read special register ctr_el0 to find out L1 dcache size.
-// This value is a good estimate based on a real aarch64 machine.
-#define CACHELINE_SIZE 64
-#define ABSL_CACHELINE_SIZE 64
-#elif defined(__arm__)
-// Cache line sizes for ARM: These values are not strictly correct since
-// cache line sizes depend on implementations, not architectures. There
-// are even implementations with cache line sizes configurable at boot
-// time.
-#if defined(__ARM_ARCH_5T__)
-#define CACHELINE_SIZE 32
-#define ABSL_CACHELINE_SIZE 32
-#elif defined(__ARM_ARCH_7A__)
-#define CACHELINE_SIZE 64
-#define ABSL_CACHELINE_SIZE 64
-#endif
-#endif
-
-#ifndef CACHELINE_SIZE
-// A reasonable default guess. Note that overestimates tend to waste more
-// space, while underestimates tend to waste more time.
-#define CACHELINE_SIZE 64
-#define ABSL_CACHELINE_SIZE 64
-#endif
-
-// On some compilers, expands to __attribute__((aligned(CACHELINE_SIZE))).
-// For compilers where this is not known to work, expands to nothing.
-//
-// No further guarantees are made here. The result of applying the macro
-// to variables and types is always implementation defined.
-//
-// WARNING: It is easy to use this attribute incorrectly, even to the point
-// of causing bugs that are difficult to diagnose, crash, etc. It does not
-// guarantee that objects are aligned to a cache line.
-//
-// Recommendations:
-//
-// 1) Consult compiler documentation; this comment is not kept in sync as
-// toolchains evolve.
-// 2) Verify your use has the intended effect. This often requires inspecting
-// the generated machine code.
-// 3) Prefer applying this attribute to individual variables. Avoid
-// applying it to types. This tends to localize the effect.
-#define CACHELINE_ALIGNED __attribute__((aligned(CACHELINE_SIZE)))
-#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
-
-#else // not GCC
-#define CACHELINE_SIZE 64
-#define ABSL_CACHELINE_SIZE 64
-#define CACHELINE_ALIGNED
-#define ABSL_CACHELINE_ALIGNED
-#endif
-
-// unaligned APIs
-
-// Portable handling of unaligned loads, stores, and copies.
-// On some platforms, like ARM, the copy functions can be more efficient
-// then a load and a store.
-//
-// It is possible to implement all of these these using constant-length memcpy
-// calls, which is portable and will usually be inlined into simple loads and
-// stores if the architecture supports it. However, such inlining usually
-// happens in a pass that's quite late in compilation, which means the resulting
-// loads and stores cannot participate in many other optimizations, leading to
-// overall worse code.
-
-// The unaligned API is C++ only. The declarations use C++ features
-// (namespaces, inline) which are absent or incompatible in C.
-#if defined(__cplusplus)
-
-#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER)
-// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
-// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
-// will miss a bug if 08 is the first unaddressable byte.
-// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
-// miss a race between this access and some other accesses to 08.
-// MemorySanitizer will correctly propagate the shadow on unaligned stores
-// and correctly report bugs on unaligned loads, but it may not properly
-// update and report the origin of the uninitialized memory.
-// For all three tools, replacing an unaligned access with a tool-specific
-// callback solves the problem.
-
-// Make sure uint16_t/uint32_t/uint64_t are defined.
-#include <stdint.h>
-
-extern "C" {
-uint16_t __sanitizer_unaligned_load16(const void *p);
-uint32_t __sanitizer_unaligned_load32(const void *p);
-uint64_t __sanitizer_unaligned_load64(const void *p);
-void __sanitizer_unaligned_store16(void *p, uint16_t v);
-void __sanitizer_unaligned_store32(void *p, uint32_t v);
-void __sanitizer_unaligned_store64(void *p, uint64_t v);
-} // extern "C"
-
-inline uint16 UNALIGNED_LOAD16(const void *p) {
- return __sanitizer_unaligned_load16(p);
-}
-
-inline uint32 UNALIGNED_LOAD32(const void *p) {
- return __sanitizer_unaligned_load32(p);
-}
-
-inline uint64 UNALIGNED_LOAD64(const void *p) {
- return __sanitizer_unaligned_load64(p);
-}
-
-inline void UNALIGNED_STORE16(void *p, uint16 v) {
- __sanitizer_unaligned_store16(p, v);
-}
-
-inline void UNALIGNED_STORE32(void *p, uint32 v) {
- __sanitizer_unaligned_store32(p, v);
-}
-
-inline void UNALIGNED_STORE64(void *p, uint64 v) {
- __sanitizer_unaligned_store64(p, v);
-}
-
-#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) || \
- defined(__ppc__) || defined(__PPC__) || defined(__ppc64__) || defined(__PPC64__)
-
-// x86 and x86-64 can perform unaligned loads/stores directly;
-// modern PowerPC hardware can also do unaligned integer loads and stores;
-// but note: the FPU still sends unaligned loads and stores to a trap handler!
-
-#define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
-#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
-#define UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
-
-#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
-#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
-#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
-
-#elif defined(__arm__) && !defined(__ARM_ARCH_5__) && !defined(__ARM_ARCH_5T__) && \
- !defined(__ARM_ARCH_5TE__) && !defined(__ARM_ARCH_5TEJ__) && !defined(__ARM_ARCH_6__) && \
- !defined(__ARM_ARCH_6J__) && !defined(__ARM_ARCH_6K__) && !defined(__ARM_ARCH_6Z__) && \
- !defined(__ARM_ARCH_6ZK__) && !defined(__ARM_ARCH_6T2__)
-
-// ARMv7 and newer support native unaligned accesses, but only of 16-bit
-// and 32-bit values (not 64-bit); older versions either raise a fatal signal,
-// do an unaligned read and rotate the words around a bit, or do the reads very
-// slowly (trip through kernel mode). There's no simple #define that says just
-// “ARMv7 or higher”, so we have to filter away all ARMv5 and ARMv6
-// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define,
-// so in time, maybe we can move on to that.
-//
-// This is a mess, but there's not much we can do about it.
-//
-// To further complicate matters, only LDR instructions (single reads) are
-// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we
-// explicitly tell the compiler that these accesses can be unaligned, it can and
-// will combine accesses. On armcc, the way to signal this is done by accessing
-// through the type (uint32 __packed *), but GCC has no such attribute
-// (it ignores __attribute__((packed)) on individual variables). However,
-// we can tell it that a _struct_ is unaligned, which has the same effect,
-// so we do that.
-
-namespace base {
-namespace internal {
-
-struct Unaligned16Struct {
- uint16 value;
- uint8 dummy; // To make the size non-power-of-two.
-} ATTRIBUTE_PACKED;
-
-struct Unaligned32Struct {
- uint32 value;
- uint8 dummy; // To make the size non-power-of-two.
-} ATTRIBUTE_PACKED;
-
-} // namespace internal
-} // namespace base
-
-#define UNALIGNED_LOAD16(_p) \
- ((reinterpret_cast<const ::base::internal::Unaligned16Struct *>(_p))->value)
-#define UNALIGNED_LOAD32(_p) \
- ((reinterpret_cast<const ::base::internal::Unaligned32Struct *>(_p))->value)
-
-#define UNALIGNED_STORE16(_p, _val) \
- ((reinterpret_cast< ::base::internal::Unaligned16Struct *>(_p))->value = (_val))
-#define UNALIGNED_STORE32(_p, _val) \
- ((reinterpret_cast< ::base::internal::Unaligned32Struct *>(_p))->value = (_val))
-
-inline uint64 UNALIGNED_LOAD64(const void *p) {
- uint64 t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline void UNALIGNED_STORE64(void *p, uint64 v) {
- memcpy(p, &v, sizeof v);
-}
-
-#else
-
-#define NEED_ALIGNED_LOADS
-
-// These functions are provided for architectures that don't support
-// unaligned loads and stores.
-
-inline uint16 UNALIGNED_LOAD16(const void *p) {
- uint16 t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline uint32 UNALIGNED_LOAD32(const void *p) {
- uint32 t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline uint64 UNALIGNED_LOAD64(const void *p) {
- uint64 t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline void UNALIGNED_STORE16(void *p, uint16 v) {
- memcpy(p, &v, sizeof v);
-}
-
-inline void UNALIGNED_STORE32(void *p, uint32 v) {
- memcpy(p, &v, sizeof v);
-}
-
-inline void UNALIGNED_STORE64(void *p, uint64 v) {
- memcpy(p, &v, sizeof v);
-}
-
-#endif
-
-// The UNALIGNED_LOADW and UNALIGNED_STOREW macros load and store values
-// of type uword_t.
-#ifdef _LP64
-#define UNALIGNED_LOADW(_p) UNALIGNED_LOAD64(_p)
-#define UNALIGNED_STOREW(_p, _val) UNALIGNED_STORE64(_p, _val)
-#else
-#define UNALIGNED_LOADW(_p) UNALIGNED_LOAD32(_p)
-#define UNALIGNED_STOREW(_p, _val) UNALIGNED_STORE32(_p, _val)
-#endif
-
-inline void UnalignedCopy16(const void *src, void *dst) {
- UNALIGNED_STORE16(dst, UNALIGNED_LOAD16(src));
-}
-
-inline void UnalignedCopy32(const void *src, void *dst) {
- UNALIGNED_STORE32(dst, UNALIGNED_LOAD32(src));
-}
-
-inline void UnalignedCopy64(const void *src, void *dst) {
- if (sizeof(void *) == 8) {
- UNALIGNED_STORE64(dst, UNALIGNED_LOAD64(src));
- } else {
- const char *src_char = reinterpret_cast<const char *>(src);
- char *dst_char = reinterpret_cast<char *>(dst);
-
- UNALIGNED_STORE32(dst_char, UNALIGNED_LOAD32(src_char));
- UNALIGNED_STORE32(dst_char + 4, UNALIGNED_LOAD32(src_char + 4));
- }
-}
-
-#endif // defined(__cplusplus), end of unaligned API
-
-// PREDICT_TRUE, PREDICT_FALSE
-//
-// GCC can be told that a certain branch is not likely to be taken (for
-// instance, a CHECK failure), and use that information in static analysis.
-// Giving it this information can help it optimize for the common case in
-// the absence of better information (ie. -fprofile-arcs).
-#if ABSL_HAVE_BUILTIN(__builtin_expect) || (defined(__GNUC__) && !defined(__clang__))
-#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
-#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
-#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-#else
-#define PREDICT_FALSE(x) x
-#define PREDICT_TRUE(x) x
-#define ABSL_PREDICT_FALSE(x) x
-#define ABSL_PREDICT_TRUE(x) x
-#endif
-
-// ABSL_ASSERT
-//
-// In C++11, `assert` can't be used portably within constexpr functions.
-// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
-// functions. Example:
-//
-// constexpr double Divide(double a, double b) {
-// return ABSL_ASSERT(b != 0), a / b;
-// }
-//
-// This macro is inspired by
-// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
-#if defined(NDEBUG)
-#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
-#else
-#define ABSL_ASSERT(expr) \
- (PREDICT_TRUE((expr)) ? (void)0 : [] { assert(false && #expr); }()) // NOLINT
-#endif
-
-// -----------------------------------------------------------------------------
-// Obsolete (to be removed)
-// -----------------------------------------------------------------------------
-
-// HAS_GLOBAL_STRING
-// Some platforms have a std::string class that is different from ::std::string
-// (although the interface is the same, of course). On other platforms,
-// std::string is the same as ::std::string.
-#if defined(__cplusplus) && !defined(SWIG)
-#include <string>
-#ifndef HAS_GLOBAL_STRING
-using std::basic_string;
-using std::string;
-#endif // HAS_GLOBAL_STRING
-#endif // SWIG, __cplusplus
-
-#endif // THIRD_PARTY_ABSL_BASE_PORT_H_
diff --git a/Firestore/Port/string_util.h b/Firestore/Port/string_util.h
deleted file mode 100644
index 6e85ba9..0000000
--- a/Firestore/Port/string_util.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-// Useful string functions and so forth. This is a grab-bag file.
-//
-// These functions work fine for UTF-8 strings as long as you can
-// consider them to be just byte strings. For example, due to the
-// design of UTF-8 you do not need to worry about accidental matches,
-// as long as all your inputs are valid UTF-8 (use \uHHHH, not \xHH or \oOOO).
-
-#ifndef IPHONE_FIRESTORE_PORT_STRING_UTIL_H_
-#define IPHONE_FIRESTORE_PORT_STRING_UTIL_H_
-
-#include <string>
-
-namespace leveldb {
-class Slice;
-}
-
-namespace Firestore {
-
-// Returns the smallest lexicographically larger string of equal or smaller
-// length. Returns an empty string if there is no such successor (if the input
-// is empty or consists entirely of 0xff bytes).
-// Useful for calculating the smallest lexicographically larger string
-// that will not be prefixed by the input string.
-//
-// Examples:
-// "a" -> "b", "aaa" -> "aab", "aa\xff" -> "ab", "\xff" -> "", "" -> ""
-std::string PrefixSuccessor(leveldb::Slice prefix);
-
-// Returns the immediate lexicographically-following string. This is useful to
-// turn an inclusive range into something that can be used with Bigtable's
-// SetLimitRow():
-//
-// // Inclusive range [min_element, max_element].
-// string min_element = ...;
-// string max_element = ...;
-//
-// // Equivalent range [range_start, range_end).
-// string range_start = min_element;
-// string range_end = ImmediateSuccessor(max_element);
-//
-// WARNING: Returns the input string with a '\0' appended; if you call c_str()
-// on the result, it will compare equal to s.
-//
-// WARNING: Transforms "" -> "\0"; this doesn't account for Bigtable's special
-// treatment of "" as infinity.
-std::string ImmediateSuccessor(leveldb::Slice s);
-
-} // namespace Firestore
-
-#endif // IPHONE_FIRESTORE_PORT_STRING_UTIL_H_
diff --git a/Firestore/Source/API/FIRCollectionReference.mm b/Firestore/Source/API/FIRCollectionReference.mm
index 92cccc6..a8de29b 100644
--- a/Firestore/Source/API/FIRCollectionReference.mm
+++ b/Firestore/Source/API/FIRCollectionReference.mm
@@ -15,6 +15,7 @@
*/
#import "FIRCollectionReference.h"
+#import "FIRFirestore.h"
#include "Firestore/core/src/firebase/firestore/util/autoid.h"
@@ -65,6 +66,26 @@ NS_ASSUME_NONNULL_BEGIN
FSTFail(@"Use FIRCollectionReference initWithPath: initializer.");
}
+// NSObject Methods
+- (BOOL)isEqual:(nullable id)other {
+ if (other == self) return YES;
+ if (![[other class] isEqual:[self class]]) return NO;
+
+ return [self isEqualToReference:other];
+}
+
+- (BOOL)isEqualToReference:(nullable FIRCollectionReference *)reference {
+ if (self == reference) return YES;
+ if (reference == nil) return NO;
+ return [self.firestore isEqual:reference.firestore] && [self.query isEqual:reference.query];
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [self.firestore hash];
+ hash = hash * 31u + [self.query hash];
+ return hash;
+}
+
- (NSString *)collectionID {
return [self.query.path lastSegment];
}
diff --git a/Firestore/Source/API/FIRDocumentChange+Internal.h b/Firestore/Source/API/FIRDocumentChange+Internal.h
index 7e2e5c6..7c9723c 100644
--- a/Firestore/Source/API/FIRDocumentChange+Internal.h
+++ b/Firestore/Source/API/FIRDocumentChange+Internal.h
@@ -16,6 +16,7 @@
#import "FIRDocumentChange.h"
+@class FIRFirestore;
@class FSTViewSnapshot;
NS_ASSUME_NONNULL_BEGIN
diff --git a/Firestore/Source/API/FIRDocumentChange.m b/Firestore/Source/API/FIRDocumentChange.mm
index 970dc90..d1d9999 100644
--- a/Firestore/Source/API/FIRDocumentChange.m
+++ b/Firestore/Source/API/FIRDocumentChange.mm
@@ -57,11 +57,11 @@ NS_ASSUME_NONNULL_BEGIN
NSUInteger index = 0;
NSMutableArray<FIRDocumentChange *> *changes = [NSMutableArray array];
for (FSTDocumentViewChange *change in snapshot.documentChanges) {
- FIRDocumentSnapshot *document =
- [FIRDocumentSnapshot snapshotWithFirestore:firestore
- documentKey:change.document.key
- document:change.document
- fromCache:snapshot.isFromCache];
+ FIRQueryDocumentSnapshot *document =
+ [FIRQueryDocumentSnapshot snapshotWithFirestore:firestore
+ documentKey:change.document.key
+ document:change.document
+ fromCache:snapshot.isFromCache];
FSTAssert(change.type == FSTDocumentViewChangeTypeAdded,
@"Invalid event type for first snapshot");
FSTAssert(!lastDocument ||
@@ -79,11 +79,11 @@ NS_ASSUME_NONNULL_BEGIN
FSTDocumentSet *indexTracker = snapshot.oldDocuments;
NSMutableArray<FIRDocumentChange *> *changes = [NSMutableArray array];
for (FSTDocumentViewChange *change in snapshot.documentChanges) {
- FIRDocumentSnapshot *document =
- [FIRDocumentSnapshot snapshotWithFirestore:firestore
- documentKey:change.document.key
- document:change.document
- fromCache:snapshot.isFromCache];
+ FIRQueryDocumentSnapshot *document =
+ [FIRQueryDocumentSnapshot snapshotWithFirestore:firestore
+ documentKey:change.document.key
+ document:change.document
+ fromCache:snapshot.isFromCache];
NSUInteger oldIndex = NSNotFound;
NSUInteger newIndex = NSNotFound;
@@ -112,7 +112,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FIRDocumentChange
- (instancetype)initWithType:(FIRDocumentChangeType)type
- document:(FIRDocumentSnapshot *)document
+ document:(FIRQueryDocumentSnapshot *)document
oldIndex:(NSUInteger)oldIndex
newIndex:(NSUInteger)newIndex {
if (self = [super init]) {
diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.mm
index 1c80ea9..05253f7 100644
--- a/Firestore/Source/API/FIRDocumentReference.m
+++ b/Firestore/Source/API/FIRDocumentReference.mm
@@ -48,6 +48,8 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithIncludeMetadataChanges:(BOOL)includeMetadataChanges
NS_DESIGNATED_INITIALIZER;
+@property(nonatomic, assign, readonly) BOOL includeMetadataChanges;
+
@end
@implementation FIRDocumentListenOptions
@@ -114,7 +116,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqual:(nullable id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
return [self isEqualToReference:other];
}
@@ -122,10 +124,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqualToReference:(nullable FIRDocumentReference *)reference {
if (self == reference) return YES;
if (reference == nil) return NO;
- if (self.firestore != reference.firestore && ![self.firestore isEqual:reference.firestore])
- return NO;
- if (self.key != reference.key && ![self.key isEqualToKey:reference.key]) return NO;
- return YES;
+ return [self.firestore isEqual:reference.firestore] && [self.key isEqualToKey:reference.key];
}
- (NSUInteger)hash {
diff --git a/Firestore/Source/API/FIRDocumentSnapshot.m b/Firestore/Source/API/FIRDocumentSnapshot.mm
index b78472e..10709e8 100644
--- a/Firestore/Source/API/FIRDocumentSnapshot.m
+++ b/Firestore/Source/API/FIRDocumentSnapshot.mm
@@ -20,11 +20,13 @@
#import "Firestore/Source/API/FIRFieldPath+Internal.h"
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
+#import "Firestore/Source/API/FIRSnapshotOptions+Internal.h"
#import "Firestore/Source/Model/FSTDatabaseID.h"
#import "Firestore/Source/Model/FSTDocument.h"
#import "Firestore/Source/Model/FSTDocumentKey.h"
#import "Firestore/Source/Model/FSTFieldValue.h"
#import "Firestore/Source/Model/FSTPath.h"
+#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTUsageValidation.h"
NS_ASSUME_NONNULL_BEGIN
@@ -49,10 +51,10 @@ NS_ASSUME_NONNULL_BEGIN
documentKey:(FSTDocumentKey *)documentKey
document:(nullable FSTDocument *)document
fromCache:(BOOL)fromCache {
- return [[FIRDocumentSnapshot alloc] initWithFirestore:firestore
- documentKey:documentKey
- document:document
- fromCache:fromCache];
+ return [[[self class] alloc] initWithFirestore:firestore
+ documentKey:documentKey
+ document:document
+ fromCache:fromCache];
}
@end
@@ -76,6 +78,34 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+// NSObject Methods
+- (BOOL)isEqual:(nullable id)other {
+ if (other == self) return YES;
+ // self class could be FIRDocumentSnapshot or subtype. So we compare with base type explicitly.
+ if (![other isKindOfClass:[FIRDocumentSnapshot class]]) return NO;
+
+ return [self isEqualToSnapshot:other];
+}
+
+- (BOOL)isEqualToSnapshot:(nullable FIRDocumentSnapshot *)snapshot {
+ if (self == snapshot) return YES;
+ if (snapshot == nil) return NO;
+
+ return [self.firestore isEqual:snapshot.firestore] &&
+ [self.internalKey isEqual:snapshot.internalKey] &&
+ (self.internalDocument == snapshot.internalDocument ||
+ [self.internalDocument isEqual:snapshot.internalDocument]) &&
+ self.fromCache == snapshot.fromCache;
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [self.firestore hash];
+ hash = hash * 31u + [self.internalKey hash];
+ hash = hash * 31u + [self.internalDocument hash];
+ hash = hash * 31u + (self.fromCache ? 1 : 0);
+ return hash;
+}
+
@dynamic exists;
- (BOOL)exists {
@@ -99,40 +129,48 @@ NS_ASSUME_NONNULL_BEGIN
return _cachedMetadata;
}
-- (NSDictionary<NSString *, id> *)data {
- FSTDocument *document = self.internalDocument;
-
- if (!document) {
- FSTThrowInvalidUsage(
- @"NonExistentDocumentException",
- @"Document '%@' doesn't exist. "
- @"Check document.exists to make sure the document exists before calling document.data.",
- self.internalKey);
- }
+- (nullable NSDictionary<NSString *, id> *)data {
+ return [self dataWithOptions:[FIRSnapshotOptions defaultOptions]];
+}
- return [self convertedObject:[self.internalDocument data]];
+- (nullable NSDictionary<NSString *, id> *)dataWithOptions:(FIRSnapshotOptions *)options {
+ return self.internalDocument == nil
+ ? nil
+ : [self convertedObject:[self.internalDocument data]
+ options:[FSTFieldValueOptions optionsForSnapshotOptions:options]];
}
-- (nullable id)objectForKeyedSubscript:(id)key {
+- (nullable id)valueForField:(id)field {
+ return [self valueForField:field options:[FIRSnapshotOptions defaultOptions]];
+}
+
+- (nullable id)valueForField:(id)field options:(FIRSnapshotOptions *)options {
FIRFieldPath *fieldPath;
- if ([key isKindOfClass:[NSString class]]) {
- fieldPath = [FIRFieldPath pathWithDotSeparatedString:key];
- } else if ([key isKindOfClass:[FIRFieldPath class]]) {
- fieldPath = key;
+ if ([field isKindOfClass:[NSString class]]) {
+ fieldPath = [FIRFieldPath pathWithDotSeparatedString:field];
+ } else if ([field isKindOfClass:[FIRFieldPath class]]) {
+ fieldPath = field;
} else {
FSTThrowInvalidArgument(@"Subscript key must be an NSString or FIRFieldPath.");
}
FSTFieldValue *fieldValue = [[self.internalDocument data] valueForPath:fieldPath.internalValue];
- return [self convertedValue:fieldValue];
+ return fieldValue == nil
+ ? nil
+ : [self convertedValue:fieldValue
+ options:[FSTFieldValueOptions optionsForSnapshotOptions:options]];
}
-- (id)convertedValue:(FSTFieldValue *)value {
+- (nullable id)objectForKeyedSubscript:(id)key {
+ return [self valueForField:key];
+}
+
+- (id)convertedValue:(FSTFieldValue *)value options:(FSTFieldValueOptions *)options {
if ([value isKindOfClass:[FSTObjectValue class]]) {
- return [self convertedObject:(FSTObjectValue *)value];
+ return [self convertedObject:(FSTObjectValue *)value options:options];
} else if ([value isKindOfClass:[FSTArrayValue class]]) {
- return [self convertedArray:(FSTArrayValue *)value];
+ return [self convertedArray:(FSTArrayValue *)value options:options];
} else if ([value isKindOfClass:[FSTReferenceValue class]]) {
FSTReferenceValue *ref = (FSTReferenceValue *)value;
FSTDatabaseID *refDatabase = ref.databaseID;
@@ -146,30 +184,69 @@ NS_ASSUME_NONNULL_BEGIN
self.reference.path, refDatabase.projectID, refDatabase.databaseID, database.projectID,
database.databaseID);
}
- return [FIRDocumentReference referenceWithKey:ref.value firestore:self.firestore];
+ return [FIRDocumentReference referenceWithKey:[ref valueWithOptions:options]
+ firestore:self.firestore];
} else {
- return value.value;
+ return [value valueWithOptions:options];
}
}
-- (NSDictionary<NSString *, id> *)convertedObject:(FSTObjectValue *)objectValue {
+- (NSDictionary<NSString *, id> *)convertedObject:(FSTObjectValue *)objectValue
+ options:(FSTFieldValueOptions *)options {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
[objectValue.internalValue
enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *value, BOOL *stop) {
- result[key] = [self convertedValue:value];
+ result[key] = [self convertedValue:value options:options];
}];
return result;
}
-- (NSArray<id> *)convertedArray:(FSTArrayValue *)arrayValue {
+- (NSArray<id> *)convertedArray:(FSTArrayValue *)arrayValue
+ options:(FSTFieldValueOptions *)options {
NSArray<FSTFieldValue *> *internalValue = arrayValue.internalValue;
NSMutableArray *result = [NSMutableArray arrayWithCapacity:internalValue.count];
[internalValue enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) {
- [result addObject:[self convertedValue:value]];
+ [result addObject:[self convertedValue:value options:options]];
}];
return result;
}
@end
+@interface FIRQueryDocumentSnapshot ()
+
+- (instancetype)initWithFirestore:(FIRFirestore *)firestore
+ documentKey:(FSTDocumentKey *)documentKey
+ document:(FSTDocument *)document
+ fromCache:(BOOL)fromCache NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation FIRQueryDocumentSnapshot
+
+- (instancetype)initWithFirestore:(FIRFirestore *)firestore
+ documentKey:(FSTDocumentKey *)documentKey
+ document:(FSTDocument *)document
+ fromCache:(BOOL)fromCache {
+ self = [super initWithFirestore:firestore
+ documentKey:documentKey
+ document:document
+ fromCache:fromCache];
+ return self;
+}
+
+- (NSDictionary<NSString *, id> *)data {
+ NSDictionary<NSString *, id> *data = [super data];
+ FSTAssert(data, @"Document in a QueryDocumentSnapshot should exist");
+ return data;
+}
+
+- (NSDictionary<NSString *, id> *)dataWithOptions:(FIRSnapshotOptions *)options {
+ NSDictionary<NSString *, id> *data = [super dataWithOptions:options];
+ FSTAssert(data, @"Document in a QueryDocumentSnapshot should exist");
+ return data;
+}
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/API/FIRFieldPath.m b/Firestore/Source/API/FIRFieldPath.mm
index d0a70c0..f4e532f 100644
--- a/Firestore/Source/API/FIRFieldPath.m
+++ b/Firestore/Source/API/FIRFieldPath.mm
@@ -80,7 +80,7 @@ NS_ASSUME_NONNULL_BEGIN
return [[[self class] alloc] initPrivate:self.internalValue];
}
-- (BOOL)isEqual:(id)object {
+- (BOOL)isEqual:(nullable id)object {
if (self == object) {
return YES;
}
diff --git a/Firestore/Source/API/FIRFieldValue.m b/Firestore/Source/API/FIRFieldValue.mm
index 7ae4fb0..7ae4fb0 100644
--- a/Firestore/Source/API/FIRFieldValue.m
+++ b/Firestore/Source/API/FIRFieldValue.mm
diff --git a/Firestore/Source/API/FIRFirestore.m b/Firestore/Source/API/FIRFirestore.mm
index 7814ce1..10367bd 100644
--- a/Firestore/Source/API/FIRFirestore.m
+++ b/Firestore/Source/API/FIRFirestore.mm
@@ -41,7 +41,7 @@
NS_ASSUME_NONNULL_BEGIN
-NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
+extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
@interface FIRFirestore ()
@@ -50,13 +50,17 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
@property(nonatomic, strong) id<FSTCredentialsProvider> credentialsProvider;
@property(nonatomic, strong) FSTDispatchQueue *workerDispatchQueue;
-@property(nonatomic, strong) FSTFirestoreClient *client;
+// Note that `client` is updated after initialization, but marking this readwrite would generate an
+// incorrect setter (since we make the assignment to `client` inside an `@synchronized` block.
+@property(nonatomic, strong, readonly) FSTFirestoreClient *client;
@property(nonatomic, strong, readonly) FSTUserDataConverter *dataConverter;
@end
@implementation FIRFirestore {
+ // All guarded by @synchronized(self)
FIRFirestoreSettings *_settings;
+ FSTFirestoreClient *_client;
}
+ (NSMutableDictionary<NSString *, FIRFirestore *> *)instances {
@@ -154,64 +158,74 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
}
- (FIRFirestoreSettings *)settings {
- // Disallow mutation of our internal settings
- return [_settings copy];
+ @synchronized(self) {
+ // Disallow mutation of our internal settings
+ return [_settings copy];
+ }
}
- (void)setSettings:(FIRFirestoreSettings *)settings {
- // As a special exception, don't throw if the same settings are passed repeatedly. This should
- // make it more friendly to create a Firestore instance.
- if (_client && ![_settings isEqual:settings]) {
- FSTThrowInvalidUsage(@"FIRIllegalStateException",
- @"Firestore instance has already been started and its settings can no "
- "longer be changed. You can only set settings before calling any "
- "other methods on a Firestore instance.");
+ @synchronized(self) {
+ // As a special exception, don't throw if the same settings are passed repeatedly. This should
+ // make it more friendly to create a Firestore instance.
+ if (_client && ![_settings isEqual:settings]) {
+ FSTThrowInvalidUsage(@"FIRIllegalStateException",
+ @"Firestore instance has already been started and its settings can no "
+ "longer be changed. You can only set settings before calling any "
+ "other methods on a Firestore instance.");
+ }
+ _settings = [settings copy];
}
- _settings = [settings copy];
}
/**
- * Ensures that the FirestoreClient is configured.
- * @return self
+ * Ensures that the FirestoreClient is configured and returns it.
*/
-- (instancetype)firestoreWithConfiguredClient {
- if (!_client) {
- // These values are validated elsewhere; this is just double-checking:
- FSTAssert(_settings.host, @"FirestoreSettings.host cannot be nil.");
- FSTAssert(_settings.dispatchQueue, @"FirestoreSettings.dispatchQueue cannot be nil.");
-
- FSTDatabaseInfo *databaseInfo =
- [FSTDatabaseInfo databaseInfoWithDatabaseID:_databaseID
- persistenceKey:_persistenceKey
- host:_settings.host
- sslEnabled:_settings.sslEnabled];
-
- FSTDispatchQueue *userDispatchQueue = [FSTDispatchQueue queueWith:_settings.dispatchQueue];
-
- _client = [FSTFirestoreClient clientWithDatabaseInfo:databaseInfo
- usePersistence:_settings.persistenceEnabled
- credentialsProvider:_credentialsProvider
- userDispatchQueue:userDispatchQueue
- workerDispatchQueue:_workerDispatchQueue];
+- (FSTFirestoreClient *)client {
+ [self ensureClientConfigured];
+ return _client;
+}
+
+- (void)ensureClientConfigured {
+ @synchronized(self) {
+ if (!_client) {
+ // These values are validated elsewhere; this is just double-checking:
+ FSTAssert(_settings.host, @"FirestoreSettings.host cannot be nil.");
+ FSTAssert(_settings.dispatchQueue, @"FirestoreSettings.dispatchQueue cannot be nil.");
+
+ FSTDatabaseInfo *databaseInfo =
+ [FSTDatabaseInfo databaseInfoWithDatabaseID:_databaseID
+ persistenceKey:_persistenceKey
+ host:_settings.host
+ sslEnabled:_settings.sslEnabled];
+
+ FSTDispatchQueue *userDispatchQueue = [FSTDispatchQueue queueWith:_settings.dispatchQueue];
+
+ _client = [FSTFirestoreClient clientWithDatabaseInfo:databaseInfo
+ usePersistence:_settings.persistenceEnabled
+ credentialsProvider:_credentialsProvider
+ userDispatchQueue:userDispatchQueue
+ workerDispatchQueue:_workerDispatchQueue];
+ }
}
- return self;
}
- (FIRCollectionReference *)collectionWithPath:(NSString *)collectionPath {
if (!collectionPath) {
FSTThrowInvalidArgument(@"Collection path cannot be nil.");
}
+ [self ensureClientConfigured];
FSTResourcePath *path = [FSTResourcePath pathWithString:collectionPath];
- return
- [FIRCollectionReference referenceWithPath:path firestore:self.firestoreWithConfiguredClient];
+ return [FIRCollectionReference referenceWithPath:path firestore:self];
}
- (FIRDocumentReference *)documentWithPath:(NSString *)documentPath {
if (!documentPath) {
FSTThrowInvalidArgument(@"Document path cannot be nil.");
}
+ [self ensureClientConfigured];
FSTResourcePath *path = [FSTResourcePath pathWithString:documentPath];
- return [FIRDocumentReference referenceWithPath:path firestore:self.firestoreWithConfiguredClient];
+ return [FIRDocumentReference referenceWithPath:path firestore:self];
}
- (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **))updateBlock
@@ -241,12 +255,13 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
internalCompletion(result, error);
});
};
- [self firestoreWithConfiguredClient];
[self.client transactionWithRetries:5 updateBlock:wrappedUpdate completion:completion];
}
- (FIRWriteBatch *)batch {
- return [FIRWriteBatch writeBatchWithFirestore:[self firestoreWithConfiguredClient]];
+ [self ensureClientConfigured];
+
+ return [FIRWriteBatch writeBatchWithFirestore:self];
}
- (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **error))updateBlock
@@ -264,11 +279,19 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
}
- (void)shutdownWithCompletion:(nullable void (^)(NSError *_Nullable error))completion {
- if (!self.client) {
+ FSTFirestoreClient *client;
+ @synchronized(self) {
+ client = _client;
+ _client = nil;
+ }
+
+ if (!client) {
+ // We should be dispatching the callback on the user dispatch queue but if the client is nil
+ // here that queue was never created.
completion(nil);
- return;
+ } else {
+ [client shutdownWithCompletion:completion];
}
- return [self.client shutdownWithCompletion:completion];
}
+ (BOOL)isLoggingEnabled {
@@ -279,6 +302,16 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
FIRSetLoggerLevel(logging ? FIRLoggerLevelDebug : FIRLoggerLevelNotice);
}
+- (void)enableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable error))completion {
+ [self ensureClientConfigured];
+ [self.client enableNetworkWithCompletion:completion];
+}
+
+- (void)disableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable))completion {
+ [self ensureClientConfigured];
+ [self.client disableNetworkWithCompletion:completion];
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/API/FIRFirestoreSettings.m b/Firestore/Source/API/FIRFirestoreSettings.mm
index 9677ff6..9677ff6 100644
--- a/Firestore/Source/API/FIRFirestoreSettings.m
+++ b/Firestore/Source/API/FIRFirestoreSettings.mm
diff --git a/Firestore/Source/API/FIRFirestoreVersion.m b/Firestore/Source/API/FIRFirestoreVersion.mm
index 4f8bb28..b1fe480 100644
--- a/Firestore/Source/API/FIRFirestoreVersion.m
+++ b/Firestore/Source/API/FIRFirestoreVersion.mm
@@ -25,5 +25,5 @@
#define STR(x) STR_EXPAND(x)
#define STR_EXPAND(x) #x
-const unsigned char *const FirebaseFirestoreVersionString =
+extern "C" const unsigned char *const FirebaseFirestoreVersionString =
(const unsigned char *const)STR(FIRFirestore_VERSION);
diff --git a/Firestore/Source/API/FIRGeoPoint.m b/Firestore/Source/API/FIRGeoPoint.mm
index 72e9e7d..8d89633 100644
--- a/Firestore/Source/API/FIRGeoPoint.m
+++ b/Firestore/Source/API/FIRGeoPoint.mm
@@ -16,9 +16,14 @@
#import "Firestore/Source/API/FIRGeoPoint+Internal.h"
-#import "Firestore/Source/Util/FSTComparison.h"
+#import "Firestore/core/src/firebase/firestore/util/comparison.h"
+
#import "Firestore/Source/Util/FSTUsageValidation.h"
+using firebase::firestore::util::DoubleBitwiseEquals;
+using firebase::firestore::util::DoubleBitwiseHash;
+using firebase::firestore::util::WrapCompare;
+
NS_ASSUME_NONNULL_BEGIN
@implementation FIRGeoPoint
@@ -45,11 +50,11 @@ NS_ASSUME_NONNULL_BEGIN
}
- (NSComparisonResult)compare:(FIRGeoPoint *)other {
- NSComparisonResult result = FSTCompareDoubles(self.latitude, other.latitude);
+ NSComparisonResult result = WrapCompare<double>(self.latitude, other.latitude);
if (result != NSOrderedSame) {
return result;
} else {
- return FSTCompareDoubles(self.longitude, other.longitude);
+ return WrapCompare<double>(self.longitude, other.longitude);
}
}
@@ -67,12 +72,12 @@ NS_ASSUME_NONNULL_BEGIN
return NO;
}
FIRGeoPoint *otherGeoPoint = (FIRGeoPoint *)other;
- return FSTDoubleBitwiseEquals(self.latitude, otherGeoPoint.latitude) &&
- FSTDoubleBitwiseEquals(self.longitude, otherGeoPoint.longitude);
+ return DoubleBitwiseEquals(self.latitude, otherGeoPoint.latitude) &&
+ DoubleBitwiseEquals(self.longitude, otherGeoPoint.longitude);
}
- (NSUInteger)hash {
- return 31 * FSTDoubleBitwiseHash(self.latitude) + FSTDoubleBitwiseHash(self.longitude);
+ return 31 * DoubleBitwiseHash(self.latitude) + DoubleBitwiseHash(self.longitude);
}
/** Implements NSCopying without actually copying because geopoints are immutable. */
diff --git a/Firestore/Source/API/FIRListenerRegistration.m b/Firestore/Source/API/FIRListenerRegistration.mm
index 9f4ddd5..9f4ddd5 100644
--- a/Firestore/Source/API/FIRListenerRegistration.m
+++ b/Firestore/Source/API/FIRListenerRegistration.mm
diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.mm
index 12e79c5..1bbf91e 100644
--- a/Firestore/Source/API/FIRQuery.m
+++ b/Firestore/Source/API/FIRQuery.mm
@@ -107,7 +107,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqual:(nullable id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
return [self isEqualToQuery:other];
}
@@ -115,9 +115,8 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqualToQuery:(nullable FIRQuery *)query {
if (self == query) return YES;
if (query == nil) return NO;
- if (self.firestore != query.firestore && ![self.firestore isEqual:query.firestore]) return NO;
- if (self.query != query.query && ![self.query isEqual:query.query]) return NO;
- return YES;
+
+ return [self.firestore isEqual:query.firestore] && [self.query isEqual:query.query];
}
- (NSUInteger)hash {
@@ -256,6 +255,95 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
value:value];
}
+- (FIRQuery *)queryFilteredUsingComparisonPredicate:(NSPredicate *)predicate {
+ NSComparisonPredicate *comparison = (NSComparisonPredicate *)predicate;
+ if (comparison.comparisonPredicateModifier != NSDirectPredicateModifier) {
+ FSTThrowInvalidArgument(@"Invalid query. Predicate cannot have an aggregate modifier.");
+ }
+ NSString *path;
+ id value = nil;
+ if ([comparison.leftExpression expressionType] == NSKeyPathExpressionType &&
+ [comparison.rightExpression expressionType] == NSConstantValueExpressionType) {
+ path = comparison.leftExpression.keyPath;
+ value = comparison.rightExpression.constantValue;
+ switch (comparison.predicateOperatorType) {
+ case NSEqualToPredicateOperatorType:
+ return [self queryWhereField:path isEqualTo:value];
+ case NSLessThanPredicateOperatorType:
+ return [self queryWhereField:path isLessThan:value];
+ case NSLessThanOrEqualToPredicateOperatorType:
+ return [self queryWhereField:path isLessThanOrEqualTo:value];
+ case NSGreaterThanPredicateOperatorType:
+ return [self queryWhereField:path isGreaterThan:value];
+ case NSGreaterThanOrEqualToPredicateOperatorType:
+ return [self queryWhereField:path isGreaterThanOrEqualTo:value];
+ default:; // Fallback below to throw assertion.
+ }
+ } else if ([comparison.leftExpression expressionType] == NSConstantValueExpressionType &&
+ [comparison.rightExpression expressionType] == NSKeyPathExpressionType) {
+ path = comparison.rightExpression.keyPath;
+ value = comparison.leftExpression.constantValue;
+ switch (comparison.predicateOperatorType) {
+ case NSEqualToPredicateOperatorType:
+ return [self queryWhereField:path isEqualTo:value];
+ case NSLessThanPredicateOperatorType:
+ return [self queryWhereField:path isGreaterThan:value];
+ case NSLessThanOrEqualToPredicateOperatorType:
+ return [self queryWhereField:path isGreaterThanOrEqualTo:value];
+ case NSGreaterThanPredicateOperatorType:
+ return [self queryWhereField:path isLessThan:value];
+ case NSGreaterThanOrEqualToPredicateOperatorType:
+ return [self queryWhereField:path isLessThanOrEqualTo:value];
+ default:; // Fallback below to throw assertion.
+ }
+ } else {
+ FSTThrowInvalidArgument(
+ @"Invalid query. Predicate comparisons must include a key path and a constant.");
+ }
+ // Fallback cases of unsupported comparison operator.
+ switch (comparison.predicateOperatorType) {
+ case NSCustomSelectorPredicateOperatorType:
+ FSTThrowInvalidArgument(@"Invalid query. Custom predicate filters are not supported.");
+ break;
+ default:
+ FSTThrowInvalidArgument(@"Invalid query. Operator type %lu is not supported.",
+ (unsigned long)comparison.predicateOperatorType);
+ }
+}
+
+- (FIRQuery *)queryFilteredUsingCompoundPredicate:(NSPredicate *)predicate {
+ NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate;
+ if (compound.compoundPredicateType != NSAndPredicateType || compound.subpredicates.count == 0) {
+ FSTThrowInvalidArgument(@"Invalid query. Only compound queries using AND are supported.");
+ }
+ FIRQuery *query = self;
+ for (NSPredicate *pred in compound.subpredicates) {
+ query = [query queryFilteredUsingPredicate:pred];
+ }
+ return query;
+}
+
+- (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate {
+ if ([predicate isKindOfClass:[NSComparisonPredicate class]]) {
+ return [self queryFilteredUsingComparisonPredicate:predicate];
+ } else if ([predicate isKindOfClass:[NSCompoundPredicate class]]) {
+ return [self queryFilteredUsingCompoundPredicate:predicate];
+ } else if ([predicate isKindOfClass:[[NSPredicate
+ predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) {
+ return true;
+ }] class]]) {
+ FSTThrowInvalidArgument(
+ @"Invalid query. Block-based predicates are not "
+ "supported. Please use predicateWithFormat to "
+ "create predicates instead.");
+ } else {
+ FSTThrowInvalidArgument(
+ @"Invalid query. Expect comparison or compound of "
+ "comparison predicate. Please use "
+ "predicateWithFormat to create predicates.");
+ }
+}
+
- (FIRQuery *)queryOrderedByField:(NSString *)field {
return
[self queryOrderedByFieldPath:[FIRFieldPath pathWithDotSeparatedString:field] descending:NO];
diff --git a/Firestore/Source/API/FIRQuerySnapshot.m b/Firestore/Source/API/FIRQuerySnapshot.mm
index 6bc6761..abee84c 100644
--- a/Firestore/Source/API/FIRQuerySnapshot.m
+++ b/Firestore/Source/API/FIRQuerySnapshot.mm
@@ -16,6 +16,7 @@
#import "Firestore/Source/API/FIRQuerySnapshot+Internal.h"
+#import "FIRFirestore.h"
#import "FIRSnapshotMetadata.h"
#import "Firestore/Source/API/FIRDocumentChange+Internal.h"
#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h"
@@ -57,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FIRQuerySnapshot {
// Cached value of the documents property.
- NSArray<FIRDocumentSnapshot *> *_documents;
+ NSArray<FIRQueryDocumentSnapshot *> *_documents;
// Cached value of the documentChanges property.
NSArray<FIRDocumentChange *> *_documentChanges;
@@ -76,6 +77,31 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+// NSObject Methods
+- (BOOL)isEqual:(nullable id)other {
+ if (other == self) return YES;
+ if (![[other class] isEqual:[self class]]) return NO;
+
+ return [self isEqualToSnapshot:other];
+}
+
+- (BOOL)isEqualToSnapshot:(nullable FIRQuerySnapshot *)snapshot {
+ if (self == snapshot) return YES;
+ if (snapshot == nil) return NO;
+
+ return [self.firestore isEqual:snapshot.firestore] &&
+ [self.originalQuery isEqual:snapshot.originalQuery] &&
+ [self.snapshot isEqual:snapshot.snapshot] && [self.metadata isEqual:snapshot.metadata];
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = [self.firestore hash];
+ hash = hash * 31u + [self.originalQuery hash];
+ hash = hash * 31u + [self.snapshot hash];
+ hash = hash * 31u + [self.metadata hash];
+ return hash;
+}
+
@dynamic empty;
- (FIRQuery *)query {
@@ -93,18 +119,18 @@ NS_ASSUME_NONNULL_BEGIN
return self.snapshot.documents.count;
}
-- (NSArray<FIRDocumentSnapshot *> *)documents {
+- (NSArray<FIRQueryDocumentSnapshot *> *)documents {
if (!_documents) {
FSTDocumentSet *documentSet = self.snapshot.documents;
FIRFirestore *firestore = self.firestore;
BOOL fromCache = self.metadata.fromCache;
- NSMutableArray<FIRDocumentSnapshot *> *result = [NSMutableArray array];
+ NSMutableArray<FIRQueryDocumentSnapshot *> *result = [NSMutableArray array];
for (FSTDocument *document in documentSet.documentEnumerator) {
- [result addObject:[FIRDocumentSnapshot snapshotWithFirestore:firestore
- documentKey:document.key
- document:document
- fromCache:fromCache]];
+ [result addObject:[FIRQueryDocumentSnapshot snapshotWithFirestore:firestore
+ documentKey:document.key
+ document:document
+ fromCache:fromCache]];
}
_documents = result;
diff --git a/Firestore/Source/API/FIRSetOptions.m b/Firestore/Source/API/FIRSetOptions.mm
index 623deaa..b41086c 100644
--- a/Firestore/Source/API/FIRSetOptions.m
+++ b/Firestore/Source/API/FIRSetOptions.mm
@@ -15,7 +15,6 @@
*/
#import "Firestore/Source/API/FIRSetOptions+Internal.h"
-#import "Firestore/Source/Model/FSTMutation.h"
NS_ASSUME_NONNULL_BEGIN
@@ -40,8 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
}
FIRSetOptions *otherOptions = (FIRSetOptions *)other;
-
- return otherOptions.merge != self.merge;
+ return otherOptions.merge == self.merge;
}
- (NSUInteger)hash {
diff --git a/Firestore/Source/API/FIRSnapshotMetadata.m b/Firestore/Source/API/FIRSnapshotMetadata.mm
index 224015f..27747ce 100644
--- a/Firestore/Source/API/FIRSnapshotMetadata.m
+++ b/Firestore/Source/API/FIRSnapshotMetadata.mm
@@ -44,6 +44,27 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+// NSObject Methods
+- (BOOL)isEqual:(nullable id)other {
+ if (other == self) return YES;
+ if (![[other class] isEqual:[self class]]) return NO;
+
+ return [self isEqualToMetadata:other];
+}
+
+- (BOOL)isEqualToMetadata:(nullable FIRSnapshotMetadata *)metadata {
+ if (self == metadata) return YES;
+ if (metadata == nil) return NO;
+
+ return self.pendingWrites == metadata.pendingWrites && self.fromCache == metadata.fromCache;
+}
+
+- (NSUInteger)hash {
+ NSUInteger hash = self.pendingWrites ? 1 : 0;
+ hash = hash * 31u + (self.fromCache ? 1 : 0);
+ return hash;
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/API/FIRSnapshotOptions+Internal.h b/Firestore/Source/API/FIRSnapshotOptions+Internal.h
new file mode 100644
index 0000000..64e7dbc
--- /dev/null
+++ b/Firestore/Source/API/FIRSnapshotOptions+Internal.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 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 "FIRDocumentSnapshot.h"
+
+#import <Foundation/Foundation.h>
+
+#import "Firestore/Source/Model/FSTFieldValue.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSnapshotOptions (Internal)
+
+/** Returns a default instance of FIRSnapshotOptions that specifies no options. */
++ (instancetype)defaultOptions;
+
+/* Initializes a new instance with the specified server timestamp behavior. */
+- (instancetype)initWithServerTimestampBehavior:(FSTServerTimestampBehavior)serverTimestampBehavior;
+
+/* Returns the server timestamp behavior. Returns -1 if no behavior is specified. */
+- (FSTServerTimestampBehavior)serverTimestampBehavior;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/API/FIRSnapshotOptions.mm b/Firestore/Source/API/FIRSnapshotOptions.mm
new file mode 100644
index 0000000..72ea3cc
--- /dev/null
+++ b/Firestore/Source/API/FIRSnapshotOptions.mm
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 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 "FIRDocumentSnapshot.h"
+
+#import "Firestore/Source/API/FIRSnapshotOptions+Internal.h"
+#import "Firestore/Source/Util/FSTAssert.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FIRSnapshotOptions ()
+
+@property(nonatomic) FSTServerTimestampBehavior serverTimestampBehavior;
+
+@end
+
+@implementation FIRSnapshotOptions
+
+- (instancetype)initWithServerTimestampBehavior:
+ (FSTServerTimestampBehavior)serverTimestampBehavior {
+ self = [super init];
+
+ if (self) {
+ _serverTimestampBehavior = serverTimestampBehavior;
+ }
+
+ return self;
+}
+
++ (instancetype)defaultOptions {
+ static FIRSnapshotOptions *sharedInstance = nil;
+ static dispatch_once_t onceToken;
+
+ dispatch_once(&onceToken, ^{
+ sharedInstance =
+ [[FIRSnapshotOptions alloc] initWithServerTimestampBehavior:FSTServerTimestampBehaviorNone];
+ });
+
+ return sharedInstance;
+}
+
++ (instancetype)serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior {
+ switch (serverTimestampBehavior) {
+ case FIRServerTimestampBehaviorEstimate:
+ return [[FIRSnapshotOptions alloc]
+ initWithServerTimestampBehavior:FSTServerTimestampBehaviorEstimate];
+ case FIRServerTimestampBehaviorPrevious:
+ return [[FIRSnapshotOptions alloc]
+ initWithServerTimestampBehavior:FSTServerTimestampBehaviorPrevious];
+ case FIRServerTimestampBehaviorNone:
+ return [FIRSnapshotOptions defaultOptions];
+ default:
+ FSTFail(@"Encountered unknown server timestamp behavior: %d", (int)serverTimestampBehavior);
+ }
+}
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/Firestore/Source/API/FIRTransaction.m b/Firestore/Source/API/FIRTransaction.mm
index 5edff19..5edff19 100644
--- a/Firestore/Source/API/FIRTransaction.m
+++ b/Firestore/Source/API/FIRTransaction.mm
diff --git a/Firestore/Source/API/FIRWriteBatch.m b/Firestore/Source/API/FIRWriteBatch.mm
index b918a9a..b1cfa09 100644
--- a/Firestore/Source/API/FIRWriteBatch.m
+++ b/Firestore/Source/API/FIRWriteBatch.mm
@@ -93,7 +93,11 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (void)commitWithCompletion:(void (^)(NSError *_Nullable error))completion {
+- (void)commit {
+ [self commitWithCompletion:nil];
+}
+
+- (void)commitWithCompletion:(nullable void (^)(NSError *_Nullable error))completion {
[self verifyNotCommitted];
self.committed = TRUE;
[self.firestore.client writeMutations:self.mutations completion:completion];
diff --git a/Firestore/Source/API/FSTUserDataConverter.m b/Firestore/Source/API/FSTUserDataConverter.mm
index 414aadb..414aadb 100644
--- a/Firestore/Source/API/FSTUserDataConverter.m
+++ b/Firestore/Source/API/FSTUserDataConverter.mm
diff --git a/Firestore/Source/Auth/FSTCredentialsProvider.m b/Firestore/Source/Auth/FSTCredentialsProvider.mm
index 653d7ff..653d7ff 100644
--- a/Firestore/Source/Auth/FSTCredentialsProvider.m
+++ b/Firestore/Source/Auth/FSTCredentialsProvider.mm
diff --git a/Firestore/Source/Auth/FSTEmptyCredentialsProvider.m b/Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm
index e78452a..e78452a 100644
--- a/Firestore/Source/Auth/FSTEmptyCredentialsProvider.m
+++ b/Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm
diff --git a/Firestore/Source/Auth/FSTUser.m b/Firestore/Source/Auth/FSTUser.mm
index 605b4e6..605b4e6 100644
--- a/Firestore/Source/Auth/FSTUser.m
+++ b/Firestore/Source/Auth/FSTUser.mm
diff --git a/Firestore/Source/Core/FSTDatabaseInfo.m b/Firestore/Source/Core/FSTDatabaseInfo.mm
index 2dbe61a..2dbe61a 100644
--- a/Firestore/Source/Core/FSTDatabaseInfo.m
+++ b/Firestore/Source/Core/FSTDatabaseInfo.mm
diff --git a/Firestore/Source/Core/FSTEventManager.h b/Firestore/Source/Core/FSTEventManager.h
index edd2a96..8eafd4b 100644
--- a/Firestore/Source/Core/FSTEventManager.h
+++ b/Firestore/Source/Core/FSTEventManager.h
@@ -62,7 +62,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)queryDidChangeViewSnapshot:(FSTViewSnapshot *)snapshot;
- (void)queryDidError:(NSError *)error;
-- (void)clientDidChangeOnlineState:(FSTOnlineState)onlineState;
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState;
@property(nonatomic, strong, readonly) FSTQuery *query;
diff --git a/Firestore/Source/Core/FSTEventManager.m b/Firestore/Source/Core/FSTEventManager.mm
index 3e1b99b..bc204a0 100644
--- a/Firestore/Source/Core/FSTEventManager.m
+++ b/Firestore/Source/Core/FSTEventManager.mm
@@ -151,7 +151,7 @@ NS_ASSUME_NONNULL_BEGIN
self.viewSnapshotHandler(nil, error);
}
-- (void)clientDidChangeOnlineState:(FSTOnlineState)onlineState {
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState {
self.onlineState = onlineState;
if (self.snapshot && !self.raisedInitialEvent &&
[self shouldRaiseInitialEventForSnapshot:self.snapshot onlineState:onlineState]) {
@@ -268,7 +268,7 @@ NS_ASSUME_NONNULL_BEGIN
}
[queryInfo.listeners addObject:listener];
- [listener clientDidChangeOnlineState:self.onlineState];
+ [listener applyChangedOnlineState:self.onlineState];
if (queryInfo.viewSnapshot) {
[listener queryDidChangeViewSnapshot:queryInfo.viewSnapshot];
@@ -321,11 +321,11 @@ NS_ASSUME_NONNULL_BEGIN
[self.queries removeObjectForKey:query];
}
-- (void)watchStreamDidChangeOnlineState:(FSTOnlineState)onlineState {
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState {
self.onlineState = onlineState;
for (FSTQueryListenersInfo *info in self.queries.objectEnumerator) {
for (FSTQueryListener *listener in info.listeners) {
- [listener clientDidChangeOnlineState:onlineState];
+ [listener applyChangedOnlineState:onlineState];
}
}
}
diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h
index 6a1e11b..0ecf2f6 100644
--- a/Firestore/Source/Core/FSTFirestoreClient.h
+++ b/Firestore/Source/Core/FSTFirestoreClient.h
@@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
* SDK architecture. It is responsible for creating the worker queue that is shared by all of the
* other components in the system.
*/
-@interface FSTFirestoreClient : NSObject
+@interface FSTFirestoreClient : NSObject <FSTOnlineStateDelegate>
/**
* Creates and returns a FSTFirestoreClient with the given parameters.
diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.mm
index 2e0e407..5986b5b 100644
--- a/Firestore/Source/Core/FSTFirestoreClient.m
+++ b/Firestore/Source/Core/FSTFirestoreClient.mm
@@ -172,7 +172,7 @@ NS_ASSUME_NONNULL_BEGIN
// Setup wiring for remote store.
_remoteStore.syncEngine = _syncEngine;
- _remoteStore.onlineStateDelegate = _eventManager;
+ _remoteStore.onlineStateDelegate = self;
// NOTE: RemoteStore depends on LocalStore (for persisting stream tokens, refilling mutation
// queue, etc.) so must be started after LocalStore.
@@ -187,6 +187,11 @@ NS_ASSUME_NONNULL_BEGIN
[self.syncEngine userDidChange:user];
}
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState {
+ [self.syncEngine applyChangedOnlineState:onlineState];
+ [self.eventManager applyChangedOnlineState:onlineState];
+}
+
- (void)disableNetworkWithCompletion:(nullable FSTVoidErrorBlock)completion {
[self.workerDispatchQueue dispatchAsync:^{
[self.remoteStore disableNetwork];
@@ -248,9 +253,11 @@ NS_ASSUME_NONNULL_BEGIN
completion:(nullable FSTVoidErrorBlock)completion {
[self.workerDispatchQueue dispatchAsync:^{
if (mutations.count == 0) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(nil);
- }];
+ if (completion) {
+ [self.userDispatchQueue dispatchAsync:^{
+ completion(nil);
+ }];
+ }
} else {
[self.syncEngine writeMutations:mutations
completion:^(NSError *error) {
diff --git a/Firestore/Source/Core/FSTListenSequence.h b/Firestore/Source/Core/FSTListenSequence.h
new file mode 100644
index 0000000..56d0e78
--- /dev/null
+++ b/Firestore/Source/Core/FSTListenSequence.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 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 <Foundation/Foundation.h>
+
+#import "FSTTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * FSTListenSequence is a monotonic sequence. It is initialized with a minimum value to
+ * exceed. All subsequent calls to next will return increasing values.
+ */
+@interface FSTListenSequence : NSObject
+
+- (instancetype)initStartingAfter:(FSTListenSequenceNumber)after NS_DESIGNATED_INITIALIZER;
+
+- (id)init NS_UNAVAILABLE;
+
+- (FSTListenSequenceNumber)next;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/Firestore/Source/Core/FSTListenSequence.mm b/Firestore/Source/Core/FSTListenSequence.mm
new file mode 100644
index 0000000..6f50d35
--- /dev/null
+++ b/Firestore/Source/Core/FSTListenSequence.mm
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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 "FSTListenSequence.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - FSTListenSequence
+
+@interface FSTListenSequence () {
+ FSTListenSequenceNumber _previousSequenceNumber;
+}
+
+@end
+
+@implementation FSTListenSequence
+
+#pragma mark - Constructors
+
+- (instancetype)initStartingAfter:(FSTListenSequenceNumber)after {
+ self = [super init];
+ if (self) {
+ _previousSequenceNumber = after;
+ }
+ return self;
+}
+
+#pragma mark - Public methods
+
+- (FSTListenSequenceNumber)next {
+ _previousSequenceNumber++;
+ return _previousSequenceNumber;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/Firestore/Source/Core/FSTQuery.m b/Firestore/Source/Core/FSTQuery.mm
index 0bfd917..8c98687 100644
--- a/Firestore/Source/Core/FSTQuery.m
+++ b/Firestore/Source/Core/FSTQuery.mm
@@ -27,6 +27,13 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - FSTRelationFilterOperator functions
+/**
+ * Returns the reverse order (i.e. Ascending => Descending) etc.
+ */
+static constexpr NSComparisonResult ReverseOrder(NSComparisonResult result) {
+ return static_cast<NSComparisonResult>(-static_cast<NSInteger>(result));
+}
+
NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOperator) {
switch (filterOperator) {
case FSTRelationFilterOperatorLessThan:
@@ -205,7 +212,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
- (BOOL)isEqual:(id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
return [self.field isEqual:((FSTNullFilter *)other).field];
}
@@ -246,7 +253,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
- (BOOL)isEqual:(id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
return [self.field isEqual:((FSTNanFilter *)other).field];
}
@@ -287,16 +294,20 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Public methods
- (NSComparisonResult)compareDocument:(FSTDocument *)document1 toDocument:(FSTDocument *)document2 {
- int modifier = self.isAscending ? 1 : -1;
+ NSComparisonResult result;
if ([self.field isEqual:[FSTFieldPath keyFieldPath]]) {
- return (NSComparisonResult)(modifier * FSTDocumentKeyComparator(document1.key, document2.key));
+ result = FSTDocumentKeyComparator(document1.key, document2.key);
} else {
FSTFieldValue *value1 = [document1 fieldForPath:self.field];
FSTFieldValue *value2 = [document2 fieldForPath:self.field];
FSTAssert(value1 != nil && value2 != nil,
@"Trying to compare documents on fields that don't exist.");
- return modifier * [value1 compare:value2];
+ result = [value1 compare:value2];
+ }
+ if (!self.isAscending) {
+ result = ReverseOrder(result);
}
+ return result;
}
- (NSString *)canonicalID {
@@ -377,7 +388,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
if ([sortOrderComponent.field isEqual:[FSTFieldPath keyFieldPath]]) {
FSTAssert([fieldValue isKindOfClass:[FSTReferenceValue class]],
@"FSTBound has a non-key value where the key path is being used %@", fieldValue);
- comparison = [fieldValue.value compare:document.key];
+ FSTReferenceValue *refValue = (FSTReferenceValue *)fieldValue;
+ comparison = [refValue.value compare:document.key];
} else {
FSTFieldValue *docValue = [document fieldForPath:sortOrderComponent.field];
FSTAssert(docValue != nil, @"Field should exist since document matched the orderBy already.");
@@ -385,7 +397,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
}
if (!sortOrderComponent.isAscending) {
- comparison = comparison * -1;
+ comparison = ReverseOrder(comparison);
}
if (comparison != 0) {
diff --git a/Firestore/Source/Core/FSTSnapshotVersion.m b/Firestore/Source/Core/FSTSnapshotVersion.mm
index 980ae52..980ae52 100644
--- a/Firestore/Source/Core/FSTSnapshotVersion.m
+++ b/Firestore/Source/Core/FSTSnapshotVersion.mm
diff --git a/Firestore/Source/Core/FSTSyncEngine.h b/Firestore/Source/Core/FSTSyncEngine.h
index bb45196..7060155 100644
--- a/Firestore/Source/Core/FSTSyncEngine.h
+++ b/Firestore/Source/Core/FSTSyncEngine.h
@@ -100,6 +100,9 @@ NS_ASSUME_NONNULL_BEGIN
- (void)userDidChange:(FSTUser *)user;
+/** Applies an FSTOnlineState change to the sync engine and notifies any views of the change. */
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTSyncEngine.m b/Firestore/Source/Core/FSTSyncEngine.mm
index 98658e4..d82cc99 100644
--- a/Firestore/Source/Core/FSTSyncEngine.m
+++ b/Firestore/Source/Core/FSTSyncEngine.mm
@@ -22,7 +22,6 @@
#import "Firestore/Source/Auth/FSTUser.h"
#import "Firestore/Source/Core/FSTQuery.h"
#import "Firestore/Source/Core/FSTSnapshotVersion.h"
-#import "Firestore/Source/Core/FSTTargetIDGenerator.h"
#import "Firestore/Source/Core/FSTTransaction.h"
#import "Firestore/Source/Core/FSTView.h"
#import "Firestore/Source/Core/FSTViewSnapshot.h"
@@ -41,8 +40,14 @@
#import "Firestore/Source/Util/FSTDispatchQueue.h"
#import "Firestore/Source/Util/FSTLogger.h"
+#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h"
+
NS_ASSUME_NONNULL_BEGIN
+// Limbo documents don't use persistence, and are eagerly GC'd. So, listens for them don't need
+// real sequence numbers.
+static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
+
#pragma mark - FSTQueryView
/**
@@ -137,14 +142,14 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableDictionary<FSTUser *, NSMutableDictionary<NSNumber *, FSTVoidErrorBlock> *>
*mutationCompletionBlocks;
-/** Used for creating the FSTTargetIDs for the listens used to resolve limbo documents. */
-@property(nonatomic, strong, readonly) FSTTargetIDGenerator *targetIdGenerator;
-
@property(nonatomic, strong) FSTUser *currentUser;
@end
-@implementation FSTSyncEngine
+@implementation FSTSyncEngine {
+ /** Used for creating the FSTTargetIDs for the listens used to resolve limbo documents. */
+ firebase::firestore::core::TargetIdGenerator _targetIdGenerator;
+}
- (instancetype)initWithLocalStore:(FSTLocalStore *)localStore
remoteStore:(FSTRemoteStore *)remoteStore
@@ -163,7 +168,8 @@ NS_ASSUME_NONNULL_BEGIN
[_limboCollector addGarbageSource:_limboDocumentRefs];
_mutationCompletionBlocks = [NSMutableDictionary dictionary];
- _targetIdGenerator = [FSTTargetIDGenerator generatorForSyncEngineStartingAfterID:0];
+ _targetIdGenerator =
+ firebase::firestore::core::TargetIdGenerator::SyncEngineTargetIdGenerator(0);
_currentUser = initialUser;
}
return self;
@@ -318,6 +324,21 @@ NS_ASSUME_NONNULL_BEGIN
[self emitNewSnapshotsWithChanges:changes remoteEvent:remoteEvent];
}
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState {
+ NSMutableArray<FSTViewSnapshot *> *newViewSnapshots = [NSMutableArray array];
+ [self.queryViewsByQuery
+ enumerateKeysAndObjectsUsingBlock:^(FSTQuery *query, FSTQueryView *queryView, BOOL *stop) {
+ FSTViewChange *viewChange = [queryView.view applyChangedOnlineState:onlineState];
+ FSTAssert(viewChange.limboChanges.count == 0,
+ @"OnlineState should not affect limbo documents.");
+ if (viewChange.snapshot) {
+ [newViewSnapshots addObject:viewChange.snapshot];
+ }
+ }];
+
+ [self.delegate handleViewSnapshots:newViewSnapshots];
+}
+
- (void)rejectListenWithTargetID:(FSTBoxedTargetID *)targetID error:(NSError *)error {
[self assertDelegateExistsForSelector:_cmd];
@@ -471,10 +492,11 @@ NS_ASSUME_NONNULL_BEGIN
if (!self.limboTargetsByKey[key]) {
FSTLog(@"New document in limbo: %@", key);
- FSTTargetID limboTargetID = [self.targetIdGenerator nextID];
+ FSTTargetID limboTargetID = _targetIdGenerator.NextId();
FSTQuery *query = [FSTQuery queryWithPath:key.path];
FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query
targetID:limboTargetID
+ listenSequenceNumber:kIrrelevantSequenceNumber
purpose:FSTQueryPurposeLimboResolution];
self.limboKeysByTarget[@(limboTargetID)] = key;
[self.remoteStore listenToTargetWithQueryData:queryData];
diff --git a/Firestore/Source/Core/FSTTargetIDGenerator.h b/Firestore/Source/Core/FSTTargetIDGenerator.h
deleted file mode 100644
index 0b230ae..0000000
--- a/Firestore/Source/Core/FSTTargetIDGenerator.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2017 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 <Foundation/Foundation.h>
-
-#import "Firestore/Source/Core/FSTTypes.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- * FSTTargetIDGenerator generates monotonically increasing integer IDs. There are separate
- * generators for different scopes. While these generators will operate independently of each
- * other, they are scoped, such that no two generators will ever produce the same ID. This is
- * useful, because sometimes the backend may group IDs from separate parts of the client into the
- * same ID space.
- */
-@interface FSTTargetIDGenerator : NSObject
-
-/**
- * Creates and returns the FSTTargetIDGenerator for the local store.
- *
- * @param after An ID to start at. Every call to nextID will return an ID > @a after.
- * @return A shared instance of FSTTargetIDGenerator.
- */
-+ (instancetype)generatorForLocalStoreStartingAfterID:(FSTTargetID)after;
-
-/**
- * Creates and returns the FSTTargetIDGenerator for the sync engine.
- *
- * @param after An ID to start at. Every call to nextID will return an ID > @a after.
- * @return A shared instance of FSTTargetIDGenerator.
- */
-+ (instancetype)generatorForSyncEngineStartingAfterID:(FSTTargetID)after;
-
-- (id)init __attribute__((unavailable("Use a static constructor method.")));
-
-/** Returns the next ID in the sequence. */
-- (FSTTargetID)nextID;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTTargetIDGenerator.m b/Firestore/Source/Core/FSTTargetIDGenerator.m
deleted file mode 100644
index 58092ec..0000000
--- a/Firestore/Source/Core/FSTTargetIDGenerator.m
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2017 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 "Firestore/Source/Core/FSTTargetIDGenerator.h"
-
-#import <libkern/OSAtomic.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-#pragma mark - FSTTargetIDGenerator
-
-static const int kReservedBits = 1;
-
-/** FSTTargetIDGeneratorID is the set of all valid generators. */
-typedef NS_ENUM(NSInteger, FSTTargetIDGeneratorID) {
- FSTTargetIDGeneratorIDLocalStore = 0,
- FSTTargetIDGeneratorIDSyncEngine = 1
-};
-
-@interface FSTTargetIDGenerator () {
- // This is volatile so it can be used with OSAtomicAdd32.
- volatile FSTTargetID _previousID;
-}
-
-/**
- * Initializes the generator.
- *
- * @param generatorID A unique ID indicating which generator this is.
- * @param after Every call to nextID will return a number > @a after.
- */
-- (instancetype)initWithGeneratorID:(FSTTargetIDGeneratorID)generatorID
- startingAfterID:(FSTTargetID)after NS_DESIGNATED_INITIALIZER;
-
-// This is typed as FSTTargetID because we need to do bitwise operations with them together.
-@property(nonatomic, assign) FSTTargetID generatorID;
-@end
-
-@implementation FSTTargetIDGenerator
-
-#pragma mark - Constructors
-
-- (instancetype)initWithGeneratorID:(FSTTargetIDGeneratorID)generatorID
- startingAfterID:(FSTTargetID)after {
- self = [super init];
- if (self) {
- _generatorID = generatorID;
-
- // Replace the generator part of |after| with this generator's ID.
- FSTTargetID afterWithoutGenerator = (after >> kReservedBits) << kReservedBits;
- FSTTargetID afterGenerator = after - afterWithoutGenerator;
- if (afterGenerator >= _generatorID) {
- // For example, if:
- // self.generatorID = 0b0000
- // after = 0b1011
- // afterGenerator = 0b0001
- // Then:
- // previous = 0b1010
- // next = 0b1100
- _previousID = afterWithoutGenerator | self.generatorID;
- } else {
- // For example, if:
- // self.generatorID = 0b0001
- // after = 0b1010
- // afterGenerator = 0b0000
- // Then:
- // previous = 0b1001
- // next = 0b1011
- _previousID = (afterWithoutGenerator | self.generatorID) - (1 << kReservedBits);
- }
- }
- return self;
-}
-
-+ (instancetype)generatorForLocalStoreStartingAfterID:(FSTTargetID)after {
- return [[FSTTargetIDGenerator alloc] initWithGeneratorID:FSTTargetIDGeneratorIDLocalStore
- startingAfterID:after];
-}
-
-+ (instancetype)generatorForSyncEngineStartingAfterID:(FSTTargetID)after {
- return [[FSTTargetIDGenerator alloc] initWithGeneratorID:FSTTargetIDGeneratorIDSyncEngine
- startingAfterID:after];
-}
-
-#pragma mark - Public methods
-
-- (FSTTargetID)nextID {
- return OSAtomicAdd32(1 << kReservedBits, &_previousID);
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTTimestamp.m b/Firestore/Source/Core/FSTTimestamp.mm
index 6d9e314..d2b492a 100644
--- a/Firestore/Source/Core/FSTTimestamp.m
+++ b/Firestore/Source/Core/FSTTimestamp.mm
@@ -16,8 +16,11 @@
#import "Firestore/Source/Core/FSTTimestamp.h"
+#include "Firestore/core/src/firebase/firestore/util/comparison.h"
+
#import "Firestore/Source/Util/FSTAssert.h"
-#import "Firestore/Source/Util/FSTComparison.h"
+
+using firebase::firestore::util::WrapCompare;
NS_ASSUME_NONNULL_BEGIN
@@ -110,11 +113,11 @@ static const int kNanosPerSecond = 1000000000;
}
- (NSComparisonResult)compare:(FSTTimestamp *)other {
- NSComparisonResult result = FSTCompareInt64s(self.seconds, other.seconds);
+ NSComparisonResult result = WrapCompare<int64_t>(self.seconds, other.seconds);
if (result != NSOrderedSame) {
return result;
}
- return FSTCompareInt32s(self.nanos, other.nanos);
+ return WrapCompare<int32_t>(self.nanos, other.nanos);
}
@end
diff --git a/Firestore/Source/Core/FSTTransaction.m b/Firestore/Source/Core/FSTTransaction.mm
index c4c5f27..f97888a 100644
--- a/Firestore/Source/Core/FSTTransaction.m
+++ b/Firestore/Source/Core/FSTTransaction.mm
@@ -104,22 +104,22 @@ NS_ASSUME_NONNULL_BEGIN
FSTThrowInvalidUsage(@"FIRIllegalStateException",
@"All reads in a transaction must be done before any writes.");
}
- [self.datastore
- lookupDocuments:keys
- completion:^(NSArray<FSTDocument *> *_Nullable documents, NSError *_Nullable error) {
- if (error) {
- completion(nil, error);
- return;
- }
- for (FSTMaybeDocument *doc in documents) {
- NSError *recordError = nil;
- if (![self recordVersionForDocument:doc error:&recordError]) {
- completion(nil, recordError);
- return;
- }
- }
- completion(documents, nil);
- }];
+ [self.datastore lookupDocuments:keys
+ completion:^(NSArray<FSTMaybeDocument *> *_Nullable documents,
+ NSError *_Nullable error) {
+ if (error) {
+ completion(nil, error);
+ return;
+ }
+ for (FSTMaybeDocument *doc in documents) {
+ NSError *recordError = nil;
+ if (![self recordVersionForDocument:doc error:&recordError]) {
+ completion(nil, recordError);
+ return;
+ }
+ }
+ completion(documents, nil);
+ }];
}
/** Stores mutations to be written when commitWithCompletion is called. */
diff --git a/Firestore/Source/Core/FSTTypes.h b/Firestore/Source/Core/FSTTypes.h
index c10f1bf..877ec94 100644
--- a/Firestore/Source/Core/FSTTypes.h
+++ b/Firestore/Source/Core/FSTTypes.h
@@ -26,6 +26,8 @@ typedef int32_t FSTBatchID;
typedef int32_t FSTTargetID;
+typedef int64_t FSTListenSequenceNumber;
+
typedef NSNumber FSTBoxedTargetID;
/**
@@ -67,8 +69,8 @@ typedef void (^FSTTransactionBlock)(FSTTransaction *transaction,
typedef NS_ENUM(NSUInteger, FSTOnlineState) {
/**
* The Firestore client is in an unknown online state. This means the client is either not
- * actively trying to establish a connection or it was previously in an unknown state and is
- * trying to establish a connection.
+ * actively trying to establish a connection or it is currently trying to establish a connection,
+ * but it has not succeeded or failed yet.
*/
FSTOnlineStateUnknown,
@@ -80,9 +82,8 @@ typedef NS_ENUM(NSUInteger, FSTOnlineState) {
FSTOnlineStateHealthy,
/**
- * The client has tried to establish a connection but has failed.
- * This state is reached after either a connection attempt failed or a healthy stream was closed
- * for unexpected reasons.
+ * The client considers itself offline. It is either trying to establish a connection but
+ * failing, or it has been explicitly marked offline via a call to `disableNetwork`.
*/
FSTOnlineStateFailed
};
diff --git a/Firestore/Source/Core/FSTView.h b/Firestore/Source/Core/FSTView.h
index ed230a3..6ff77cd 100644
--- a/Firestore/Source/Core/FSTView.h
+++ b/Firestore/Source/Core/FSTView.h
@@ -16,6 +16,7 @@
#import <Foundation/Foundation.h>
+#import "Firestore/Source/Core/FSTTypes.h"
#import "Firestore/Source/Model/FSTDocumentDictionary.h"
#import "Firestore/Source/Model/FSTDocumentKeySet.h"
@@ -138,6 +139,12 @@ typedef NS_ENUM(NSInteger, FSTLimboDocumentChangeType) {
- (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges
targetChange:(nullable FSTTargetChange *)targetChange;
+/**
+ * Applies an FSTOnlineState change to the view, potentially generating an FSTViewChange if the
+ * view's syncState changes as a result.
+ */
+- (FSTViewChange *)applyChangedOnlineState:(FSTOnlineState)onlineState;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTView.m b/Firestore/Source/Core/FSTView.mm
index 9b44bf4..d6b4558 100644
--- a/Firestore/Source/Core/FSTView.m
+++ b/Firestore/Source/Core/FSTView.mm
@@ -94,6 +94,12 @@ NS_ASSUME_NONNULL_BEGIN
return self.type == otherChange.type && [self.key isEqual:otherChange.key];
}
+- (NSUInteger)hash {
+ NSUInteger hash = self.type;
+ hash = hash * 31u + [self.key hash];
+ return hash;
+}
+
@end
#pragma mark - FSTViewChange
@@ -306,8 +312,8 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang
}
return self.query.comparator(c1.document, c2.document);
}];
-
- NSArray<FSTLimboDocumentChange *> *limboChanges = [self applyTargetChange:targetChange];
+ [self applyTargetChange:targetChange];
+ NSArray<FSTLimboDocumentChange *> *limboChanges = [self updateLimboDocuments];
BOOL synced = self.limboDocuments.count == 0 && self.isCurrent;
FSTSyncState newSyncState = synced ? FSTSyncStateSynced : FSTSyncStateLocal;
BOOL syncStateChanged = newSyncState != self.syncState;
@@ -330,6 +336,24 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang
}
}
+- (FSTViewChange *)applyChangedOnlineState:(FSTOnlineState)onlineState {
+ if (self.isCurrent && onlineState == FSTOnlineStateFailed) {
+ // If we're offline, set `current` to NO and then call applyChanges to refresh our syncState
+ // and generate an FSTViewChange as appropriate. We are guaranteed to get a new FSTTargetChange
+ // that sets `current` back to YES once the client is back online.
+ self.current = NO;
+ return
+ [self applyChangesToDocuments:[[FSTViewDocumentChanges alloc]
+ initWithDocumentSet:self.documentSet
+ changeSet:[FSTDocumentViewChangeSet changeSet]
+ needsRefill:NO
+ mutatedKeys:self.mutatedKeys]];
+ } else {
+ // No effect, just return a no-op FSTViewChange.
+ return [[FSTViewChange alloc] initWithSnapshot:nil limboChanges:@[]];
+ }
+}
+
#pragma mark - Private methods
/** Returns whether the doc for the given key should be in limbo. */
@@ -354,10 +378,9 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang
}
/**
- * Updates syncedDocuments, isAcked, and limbo docs based on the given change.
- * @return the list of changes to which docs are in limbo.
+ * Updates syncedDocuments and current based on the given change.
*/
-- (NSArray<FSTLimboDocumentChange *> *)applyTargetChange:(nullable FSTTargetChange *)targetChange {
+- (void)applyTargetChange:(nullable FSTTargetChange *)targetChange {
if (targetChange) {
FSTTargetMapping *targetMapping = targetChange.mapping;
if ([targetMapping isKindOfClass:[FSTResetMapping class]]) {
@@ -384,16 +407,21 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang
break;
}
}
+}
+
+/** Updates limboDocuments and returns any changes as FSTLimboDocumentChanges. */
+- (NSArray<FSTLimboDocumentChange *> *)updateLimboDocuments {
+ // We can only determine limbo documents when we're in-sync with the server.
+ if (!self.isCurrent) {
+ return @[];
+ }
- // Recompute the set of limbo docs.
// TODO(klimt): Do this incrementally so that it's not quadratic when updating many documents.
FSTDocumentKeySet *oldLimboDocuments = self.limboDocuments;
self.limboDocuments = [FSTDocumentKeySet keySet];
- if (self.isCurrent) {
- for (FSTDocument *doc in self.documentSet.documentEnumerator) {
- if ([self shouldBeLimboDocumentKey:doc.key]) {
- self.limboDocuments = [self.limboDocuments setByAddingObject:doc.key];
- }
+ for (FSTDocument *doc in self.documentSet.documentEnumerator) {
+ if ([self shouldBeLimboDocumentKey:doc.key]) {
+ self.limboDocuments = [self.limboDocuments setByAddingObject:doc.key];
}
}
diff --git a/Firestore/Source/Core/FSTViewSnapshot.m b/Firestore/Source/Core/FSTViewSnapshot.mm
index e60b785..e60b785 100644
--- a/Firestore/Source/Core/FSTViewSnapshot.m
+++ b/Firestore/Source/Core/FSTViewSnapshot.mm
diff --git a/Firestore/Source/Local/FSTDocumentReference.h b/Firestore/Source/Local/FSTDocumentReference.h
index eff60e4..04b8416 100644
--- a/Firestore/Source/Local/FSTDocumentReference.h
+++ b/Firestore/Source/Local/FSTDocumentReference.h
@@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface FSTDocumentReference : NSObject <NSCopying>
/** Initializes the document reference with the given key and ID. */
-- (instancetype)initWithKey:(FSTDocumentKey *)key ID:(int)ID NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithKey:(FSTDocumentKey *)key ID:(int32_t)ID NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
* The targetID of a referring target or the batchID of a referring mutation batch. (Which this
* is depends upon which FSTReferenceSet this reference is a part of.)
*/
-@property(nonatomic, assign, readonly) int ID;
+@property(nonatomic, assign, readonly) int32_t ID;
@end
diff --git a/Firestore/Source/Local/FSTDocumentReference.m b/Firestore/Source/Local/FSTDocumentReference.mm
index 1631789..4310baa 100644
--- a/Firestore/Source/Local/FSTDocumentReference.m
+++ b/Firestore/Source/Local/FSTDocumentReference.mm
@@ -16,14 +16,17 @@
#import "Firestore/Source/Local/FSTDocumentReference.h"
+#include "Firestore/core/src/firebase/firestore/util/comparison.h"
+
#import "Firestore/Source/Model/FSTDocumentKey.h"
-#import "Firestore/Source/Util/FSTComparison.h"
+
+using firebase::firestore::util::WrapCompare;
NS_ASSUME_NONNULL_BEGIN
@implementation FSTDocumentReference
-- (instancetype)initWithKey:(FSTDocumentKey *)key ID:(int)ID {
+- (instancetype)initWithKey:(FSTDocumentKey *)key ID:(int32_t)ID {
self = [super init];
if (self) {
_key = key;
@@ -34,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqual:(id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
FSTDocumentReference *reference = (FSTDocumentReference *)other;
@@ -67,13 +70,13 @@ const NSComparator FSTDocumentReferenceComparatorByKey =
if (result != NSOrderedSame) {
return result;
}
- return FSTCompareInts(left.ID, right.ID);
+ return WrapCompare<int32_t>(left.ID, right.ID);
};
/** Sorts document references by ID then key. */
const NSComparator FSTDocumentReferenceComparatorByID =
^NSComparisonResult(FSTDocumentReference *left, FSTDocumentReference *right) {
- NSComparisonResult result = FSTCompareInts(left.ID, right.ID);
+ NSComparisonResult result = WrapCompare<int32_t>(left.ID, right.ID);
if (result != NSOrderedSame) {
return result;
}
diff --git a/Firestore/Source/Local/FSTEagerGarbageCollector.m b/Firestore/Source/Local/FSTEagerGarbageCollector.mm
index 77a577e..77a577e 100644
--- a/Firestore/Source/Local/FSTEagerGarbageCollector.m
+++ b/Firestore/Source/Local/FSTEagerGarbageCollector.mm
diff --git a/Firestore/Source/Local/FSTLevelDB.h b/Firestore/Source/Local/FSTLevelDB.h
index 762054b..520557a 100644
--- a/Firestore/Source/Local/FSTLevelDB.h
+++ b/Firestore/Source/Local/FSTLevelDB.h
@@ -16,16 +16,10 @@
#import <Foundation/Foundation.h>
-#import "Firestore/Source/Local/FSTPersistence.h"
-
-#ifdef __cplusplus
#include <memory>
-namespace leveldb {
-class DB;
-class Status;
-}
-#endif
+#import "Firestore/Source/Local/FSTPersistence.h"
+#include "leveldb/db.h"
@class FSTDatabaseInfo;
@class FSTLocalSerializer;
@@ -68,8 +62,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (BOOL)start:(NSError **)error;
-#ifdef __cplusplus
// What follows is the Objective-C++ extension to the API.
+/**
+ * @return A standard set of read options
+ */
++ (const leveldb::ReadOptions)standardReadOptions;
/**
* Creates an NSError based on the given status if the status is not ok.
@@ -98,8 +95,6 @@ NS_ASSUME_NONNULL_BEGIN
/** The native db pointer, allocated during start. */
@property(nonatomic, assign, readonly) std::shared_ptr<leveldb::DB> ptr;
-#endif
-
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTLevelDB.mm b/Firestore/Source/Local/FSTLevelDB.mm
index fb1c81a..d163ed5 100644
--- a/Firestore/Source/Local/FSTLevelDB.mm
+++ b/Firestore/Source/Local/FSTLevelDB.mm
@@ -20,6 +20,7 @@
#import "FIRFirestoreErrors.h"
#import "Firestore/Source/Core/FSTDatabaseInfo.h"
+#import "Firestore/Source/Local/FSTLevelDBMigrations.h"
#import "Firestore/Source/Local/FSTLevelDBMutationQueue.h"
#import "Firestore/Source/Local/FSTLevelDBQueryCache.h"
#import "Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h"
@@ -36,6 +37,7 @@ static NSString *const kReservedPathComponent = @"firestore";
using leveldb::DB;
using leveldb::Options;
+using leveldb::ReadOptions;
using leveldb::Status;
using leveldb::WriteOptions;
@@ -50,6 +52,15 @@ using leveldb::WriteOptions;
@implementation FSTLevelDB
+/**
+ * For now this is paranoid, but perhaps disable that in production builds.
+ */
++ (const ReadOptions)standardReadOptions {
+ ReadOptions options;
+ options.verify_checksums = true;
+ return options;
+}
+
- (instancetype)initWithDirectory:(NSString *)directory
serializer:(FSTLocalSerializer *)serializer {
if (self = [super init]) {
@@ -72,8 +83,8 @@ using leveldb::WriteOptions;
#else
#error "local storage on tvOS"
-// TODO(mcg): Writing to NSDocumentsDirectory on tvOS will fail; we need to write to Caches
-// https://developer.apple.com/library/content/documentation/General/Conceptual/AppleTV_PG/
+ // TODO(mcg): Writing to NSDocumentsDirectory on tvOS will fail; we need to write to Caches
+ // https://developer.apple.com/library/content/documentation/General/Conceptual/AppleTV_PG/
#endif
}
@@ -115,8 +126,8 @@ using leveldb::WriteOptions;
if (!database) {
return NO;
}
-
_ptr.reset(database);
+ [FSTLevelDBMigrations runMigrationsOnDB:_ptr];
return YES;
}
diff --git a/Firestore/Source/Local/FSTLevelDBKey.h b/Firestore/Source/Local/FSTLevelDBKey.h
index 2e9b9b2..f3f4bcf 100644
--- a/Firestore/Source/Local/FSTLevelDBKey.h
+++ b/Firestore/Source/Local/FSTLevelDBKey.h
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#ifndef __cplusplus
-#error "FSTLevelDBKey is Objective-C++ and can only be included from .mm files"
-#endif
-
#import <Foundation/Foundation.h>
#import "Firestore/Source/Core/FSTTypes.h"
@@ -82,6 +78,14 @@ NS_ASSUME_NONNULL_BEGIN
@end
+/** A key to a singleton row storing the version of the schema. */
+@interface FSTLevelDBVersionKey : NSObject
+
+/** Returns the key pointing to the singleton row storing the schema version. */
++ (std::string)key;
+
+@end
+
/** A key in the mutations table. */
@interface FSTLevelDBMutationKey : NSObject
diff --git a/Firestore/Source/Local/FSTLevelDBKey.mm b/Firestore/Source/Local/FSTLevelDBKey.mm
index c6f51b9..41aea39 100644
--- a/Firestore/Source/Local/FSTLevelDBKey.mm
+++ b/Firestore/Source/Local/FSTLevelDBKey.mm
@@ -18,18 +18,18 @@
#include <string>
-#include "Firestore/Port/ordered_code.h"
-#include "Firestore/Port/string_util.h"
#import "Firestore/Source/Model/FSTDocumentKey.h"
#import "Firestore/Source/Model/FSTPath.h"
+#include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
+
NS_ASSUME_NONNULL_BEGIN
-using Firestore::OrderedCode;
-using Firestore::PrefixSuccessor;
+using firebase::firestore::util::OrderedCode;
using Firestore::StringView;
using leveldb::Slice;
+static const char *kVersionGlobalTable = "version";
static const char *kMutationsTable = "mutation";
static const char *kDocumentMutationsTable = "document_mutation";
static const char *kMutationQueuesTable = "mutation_queue";
@@ -111,11 +111,11 @@ void WriteComponentLabel(std::string *dest, FSTComponentLabel label) {
*/
BOOL ReadComponentLabel(leveldb::Slice *contents, FSTComponentLabel *label) {
int64_t rawResult = 0;
- Slice tmp = *contents;
+ absl::string_view tmp(contents->data(), contents->size());
if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
if (rawResult >= FSTComponentLabelTerminator && rawResult <= FSTComponentLabelUnknown) {
*label = static_cast<FSTComponentLabel>(rawResult);
- *contents = tmp;
+ *contents = leveldb::Slice(tmp.data(), tmp.size());
return YES;
}
}
@@ -130,9 +130,9 @@ BOOL ReadComponentLabel(leveldb::Slice *contents, FSTComponentLabel *label) {
*
* If the read is successful, returns YES and contents will be updated to the next unread byte.
*/
-BOOL ReadComponentLabelMatching(Slice *contents, FSTComponentLabel expectedLabel) {
+BOOL ReadComponentLabelMatching(absl::string_view *contents, FSTComponentLabel expectedLabel) {
int64_t rawResult = 0;
- Slice tmp = *contents;
+ absl::string_view tmp = *contents;
if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
if (rawResult == expectedLabel) {
*contents = tmp;
@@ -154,10 +154,10 @@ BOOL ReadComponentLabelMatching(Slice *contents, FSTComponentLabel expectedLabel
*/
BOOL ReadInt32(Slice *contents, int32_t *result) {
int64_t rawResult = 0;
- Slice tmp = *contents;
+ absl::string_view tmp(contents->data(), contents->size());
if (OrderedCode::ReadSignedNumIncreasing(&tmp, &rawResult)) {
if (rawResult >= INT32_MIN && rawResult <= INT32_MAX) {
- *contents = tmp;
+ *contents = leveldb::Slice(tmp.data(), tmp.size());
*result = static_cast<int32_t>(rawResult);
return YES;
}
@@ -182,10 +182,11 @@ void WriteLabeledInt32(std::string *dest, FSTComponentLabel label, int32_t value
* value will be set to the decoded integer value.
*/
BOOL ReadLabeledInt32(Slice *contents, FSTComponentLabel expectedLabel, int32_t *value) {
- Slice tmp = *contents;
+ absl::string_view tmp(contents->data(), contents->size());
if (ReadComponentLabelMatching(&tmp, expectedLabel)) {
- if (ReadInt32(&tmp, value)) {
- *contents = tmp;
+ Slice tmpSlice = leveldb::Slice(tmp.data(), tmp.size());
+ if (ReadInt32(&tmpSlice, value)) {
+ *contents = tmpSlice;
return YES;
}
}
@@ -209,10 +210,10 @@ void WriteLabeledString(std::string *dest, FSTComponentLabel label, StringView v
* value will be set to the decoded string value.
*/
BOOL ReadLabeledString(Slice *contents, FSTComponentLabel expectedLabel, std::string *value) {
- Slice tmp = *contents;
+ absl::string_view tmp(contents->data(), contents->size());
if (ReadComponentLabelMatching(&tmp, expectedLabel)) {
if (OrderedCode::ReadString(&tmp, value)) {
- *contents = tmp;
+ *contents = leveldb::Slice(tmp.data(), tmp.size());
return YES;
}
}
@@ -274,7 +275,7 @@ BOOL ReadDocumentKey(Slice *contents, FSTDocumentKey *__strong *result) {
for (;;) {
// Advance a temporary slice to avoid advancing contents into the next key component which may
// not be a path segment.
- Slice readPosition = completeSegments;
+ absl::string_view readPosition(completeSegments.data(), completeSegments.size());
if (!ReadComponentLabelMatching(&readPosition, FSTComponentLabelPathSegment)) {
break;
}
@@ -286,7 +287,7 @@ BOOL ReadDocumentKey(Slice *contents, FSTDocumentKey *__strong *result) {
[pathSegments addObject:pathSegment];
segment.clear();
- completeSegments = readPosition;
+ completeSegments = leveldb::Slice(readPosition.data(), readPosition.size());
}
FSTResourcePath *path = [FSTResourcePath pathWithSegments:pathSegments];
@@ -306,7 +307,10 @@ inline void WriteTerminator(std::string *dest) {
}
inline BOOL ReadTerminator(Slice *contents) {
- return ReadComponentLabelMatching(contents, FSTComponentLabelTerminator);
+ absl::string_view tmp(contents->data(), contents->size());
+ BOOL result = ReadComponentLabelMatching(&tmp, FSTComponentLabelTerminator);
+ *contents = leveldb::Slice(tmp.data(), tmp.size());
+ return result;
}
inline void WriteTableName(std::string *dest, const char *tableName) {
@@ -445,6 +449,17 @@ NSString *InvalidKey(const Slice &key) {
@end
+@implementation FSTLevelDBVersionKey
+
++ (std::string)key {
+ std::string result;
+ WriteTableName(&result, kVersionGlobalTable);
+ WriteTerminator(&result);
+ return result;
+}
+
+@end
+
@implementation FSTLevelDBMutationKey {
std::string _userID;
}
diff --git a/Firestore/Source/Local/FSTLevelDBMigrations.h b/Firestore/Source/Local/FSTLevelDBMigrations.h
new file mode 100644
index 0000000..24fb5c8
--- /dev/null
+++ b/Firestore/Source/Local/FSTLevelDBMigrations.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 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 <Foundation/Foundation.h>
+
+#include <memory>
+
+#include "leveldb/db.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef int32_t FSTLevelDBSchemaVersion;
+
+@interface FSTLevelDBMigrations : NSObject
+
+/**
+ * Returns the current version of the schema for the given database
+ */
++ (FSTLevelDBSchemaVersion)schemaVersionForDB:(std::shared_ptr<leveldb::DB>)db;
+
+/**
+ * Runs any migrations needed to bring the given database up to the current schema version
+ */
++ (void)runMigrationsOnDB:(std::shared_ptr<leveldb::DB>)db;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTLevelDBMigrations.mm b/Firestore/Source/Local/FSTLevelDBMigrations.mm
new file mode 100644
index 0000000..49af893
--- /dev/null
+++ b/Firestore/Source/Local/FSTLevelDBMigrations.mm
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/Source/Local/FSTLevelDBMigrations.h"
+
+#include <leveldb/db.h>
+#include <leveldb/write_batch.h>
+
+#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
+#import "Firestore/Source/Local/FSTLevelDB.h"
+#import "Firestore/Source/Local/FSTLevelDBKey.h"
+#import "Firestore/Source/Local/FSTLevelDBQueryCache.h"
+#import "Firestore/Source/Local/FSTWriteGroup.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Current version of the schema defined in this file.
+static FSTLevelDBSchemaVersion kSchemaVersion = 1;
+
+using leveldb::DB;
+using leveldb::Status;
+using leveldb::Slice;
+using leveldb::WriteOptions;
+
+/**
+ * Ensures that the global singleton target metadata row exists in LevelDB.
+ * @param db The db in which to require the row.
+ */
+static void EnsureTargetGlobal(std::shared_ptr<DB> db, FSTWriteGroup *group) {
+ FSTPBTargetGlobal *targetGlobal = [FSTLevelDBQueryCache readTargetMetadataFromDB:db];
+ if (!targetGlobal) {
+ [group setMessage:[FSTPBTargetGlobal message] forKey:[FSTLevelDBTargetGlobalKey key]];
+ }
+}
+
+/**
+ * Save the given version number as the current version of the schema of the database.
+ * @param version The version to save
+ * @param group The transaction in which to save the new version number
+ */
+static void SaveVersion(FSTLevelDBSchemaVersion version, FSTWriteGroup *group) {
+ std::string key = [FSTLevelDBVersionKey key];
+ std::string version_string = std::to_string(version);
+ [group setData:version_string forKey:key];
+}
+
+@implementation FSTLevelDBMigrations
+
++ (FSTLevelDBSchemaVersion)schemaVersionForDB:(std::shared_ptr<DB>)db {
+ std::string key = [FSTLevelDBVersionKey key];
+ std::string version_string;
+ Status status = db->Get([FSTLevelDB standardReadOptions], key, &version_string);
+ if (status.IsNotFound()) {
+ return 0;
+ } else {
+ return stoi(version_string);
+ }
+}
+
++ (void)runMigrationsOnDB:(std::shared_ptr<DB>)db {
+ FSTWriteGroup *group = [FSTWriteGroup groupWithAction:@"Migrations"];
+ FSTLevelDBSchemaVersion currentVersion = [self schemaVersionForDB:db];
+ // Each case in this switch statement intentionally falls through. This lets us
+ // start at the current schema version and apply any migrations that have not yet
+ // been applied, to bring us up to current, as defined by the kSchemaVersion constant.
+ switch (currentVersion) {
+ case 0:
+ EnsureTargetGlobal(db, group);
+ // Fallthrough
+ default:
+ if (currentVersion < kSchemaVersion) {
+ SaveVersion(kSchemaVersion, group);
+ }
+ }
+ if (!group.isEmpty) {
+ [group writeToDB:db];
+ }
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.h b/Firestore/Source/Local/FSTLevelDBMutationQueue.h
index dd2ed4f..cc05db7 100644
--- a/Firestore/Source/Local/FSTLevelDBMutationQueue.h
+++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.h
@@ -16,15 +16,10 @@
#import <Foundation/Foundation.h>
-#import "Firestore/Source/Local/FSTMutationQueue.h"
-
-#ifdef __cplusplus
#include <memory>
-namespace leveldb {
-class DB;
-}
-#endif
+#import "Firestore/Source/Local/FSTMutationQueue.h"
+#include "leveldb/db.h"
@class FSTLevelDB;
@class FSTLocalSerializer;
@@ -41,7 +36,6 @@ NS_ASSUME_NONNULL_BEGIN
/** The garbage collector to notify about potential garbage keys. */
@property(nonatomic, weak, readwrite, nullable) id<FSTGarbageCollector> garbageCollector;
-#ifdef __cplusplus
/**
* Creates a new mutation queue for the given user, in the given LevelDB.
*
@@ -57,7 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
* returns 0. Note that batch IDs are global.
*/
+ (FSTBatchID)loadNextBatchIDFromDB:(std::shared_ptr<leveldb::DB>)db;
-#endif
@end
diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
index 56a22a1..dbe58e8 100644
--- a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
+++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
@@ -34,12 +34,10 @@
#import "Firestore/Source/Model/FSTPath.h"
#import "Firestore/Source/Util/FSTAssert.h"
-#include "Firestore/Port/ordered_code.h"
-#include "Firestore/Port/string_util.h"
+#include "Firestore/core/src/firebase/firestore/util/string_util.h"
NS_ASSUME_NONNULL_BEGIN
-using Firestore::OrderedCode;
using Firestore::StringView;
using leveldb::DB;
using leveldb::Iterator;
@@ -164,7 +162,7 @@ static ReadOptions StandardReadOptions() {
while (moreUserIDs) {
// Compute the first key after the last mutation for nextUserID.
auto userEnd = [FSTLevelDBMutationKey keyPrefixWithUserID:nextUserID];
- userEnd = Firestore::PrefixSuccessor(userEnd);
+ userEnd = firebase::firestore::util::PrefixSuccessor(userEnd);
// Seek to that key with the intent of finding the boundary between nextUserID's mutations
// and the one after that (if any).
diff --git a/Firestore/Source/Local/FSTLevelDBQueryCache.h b/Firestore/Source/Local/FSTLevelDBQueryCache.h
index 6d5cd60..1f6fbd4 100644
--- a/Firestore/Source/Local/FSTLevelDBQueryCache.h
+++ b/Firestore/Source/Local/FSTLevelDBQueryCache.h
@@ -16,17 +16,13 @@
#import <Foundation/Foundation.h>
-#import "Firestore/Source/Local/FSTQueryCache.h"
-
-#ifdef __cplusplus
#include <memory>
-namespace leveldb {
-class DB;
-}
-#endif
+#import "Firestore/Source/Local/FSTQueryCache.h"
+#include "leveldb/db.h"
@class FSTLocalSerializer;
+@class FSTPBTargetGlobal;
@protocol FSTGarbageCollector;
NS_ASSUME_NONNULL_BEGIN
@@ -34,12 +30,16 @@ NS_ASSUME_NONNULL_BEGIN
/** Cached Queries backed by LevelDB. */
@interface FSTLevelDBQueryCache : NSObject <FSTQueryCache>
+/**
+ * Retrieves the global singleton metadata row from the given database, if it exists.
+ */
++ (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(std::shared_ptr<leveldb::DB>)db;
+
- (instancetype)init NS_UNAVAILABLE;
/** The garbage collector to notify about potential garbage keys. */
@property(nonatomic, weak, readwrite, nullable) id<FSTGarbageCollector> garbageCollector;
-#ifdef __cplusplus
/**
* Creates a new query cache in the given LevelDB.
*
@@ -47,7 +47,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (instancetype)initWithDB:(std::shared_ptr<leveldb::DB>)db
serializer:(FSTLocalSerializer *)serializer NS_DESIGNATED_INITIALIZER;
-#endif
@end
diff --git a/Firestore/Source/Local/FSTLevelDBQueryCache.mm b/Firestore/Source/Local/FSTLevelDBQueryCache.mm
index 13d15ee..b3f4822 100644
--- a/Firestore/Source/Local/FSTLevelDBQueryCache.mm
+++ b/Firestore/Source/Local/FSTLevelDBQueryCache.mm
@@ -22,6 +22,7 @@
#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
#import "Firestore/Source/Core/FSTQuery.h"
+#import "Firestore/Source/Local/FSTLevelDB.h"
#import "Firestore/Source/Local/FSTLevelDBKey.h"
#import "Firestore/Source/Local/FSTLocalSerializer.h"
#import "Firestore/Source/Local/FSTQueryData.h"
@@ -29,12 +30,8 @@
#import "Firestore/Source/Model/FSTDocumentKey.h"
#import "Firestore/Source/Util/FSTAssert.h"
-#include "Firestore/Port/ordered_code.h"
-#include "Firestore/Port/string_util.h"
-
NS_ASSUME_NONNULL_BEGIN
-using Firestore::OrderedCode;
using Firestore::StringView;
using leveldb::DB;
using leveldb::Iterator;
@@ -43,17 +40,6 @@ using leveldb::Slice;
using leveldb::Status;
using leveldb::WriteOptions;
-/**
- * Returns a standard set of read options.
- *
- * For now this is paranoid, but perhaps disable that in production builds.
- */
-static ReadOptions GetStandardReadOptions() {
- ReadOptions options;
- options.verify_checksums = true;
- return options;
-}
-
@interface FSTLevelDBQueryCache ()
/** A write-through cached copy of the metadata for the query cache. */
@@ -74,6 +60,29 @@ static ReadOptions GetStandardReadOptions() {
FSTSnapshotVersion *_lastRemoteSnapshotVersion;
}
++ (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(std::shared_ptr<DB>)db {
+ std::string key = [FSTLevelDBTargetGlobalKey key];
+ std::string value;
+ Status status = db->Get([FSTLevelDB standardReadOptions], key, &value);
+ if (status.IsNotFound()) {
+ return nil;
+ } else if (!status.ok()) {
+ FSTFail(@"metadataForKey: failed loading key %s with status: %s", key.c_str(),
+ status.ToString().c_str());
+ }
+
+ NSData *data =
+ [[NSData alloc] initWithBytesNoCopy:(void *)value.data() length:value.size() freeWhenDone:NO];
+
+ NSError *error;
+ FSTPBTargetGlobal *proto = [FSTPBTargetGlobal parseFromData:data error:&error];
+ if (!proto) {
+ FSTFail(@"FSTPBTargetGlobal failed to parse: %@", error);
+ }
+
+ return proto;
+}
+
- (instancetype)initWithDB:(std::shared_ptr<DB>)db serializer:(FSTLocalSerializer *)serializer {
if (self = [super init]) {
FSTAssert(db, @"db must not be NULL");
@@ -84,11 +93,10 @@ static ReadOptions GetStandardReadOptions() {
}
- (void)start {
- std::string key = [FSTLevelDBTargetGlobalKey key];
- FSTPBTargetGlobal *metadata = [self metadataForKey:key];
- if (!metadata) {
- metadata = [FSTPBTargetGlobal message];
- }
+ FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
+ FSTAssert(
+ metadata != nil,
+ @"Found nil metadata, expected schema to be at version 0 which ensures metadata existence");
_lastRemoteSnapshotVersion = [self.serializer decodedVersion:metadata.lastRemoteSnapshotVersion];
self.metadata = metadata;
@@ -100,6 +108,10 @@ static ReadOptions GetStandardReadOptions() {
return self.metadata.highestTargetId;
}
+- (FSTListenSequenceNumber)highestListenSequenceNumber {
+ return self.metadata.highestListenSequenceNumber;
+}
+
- (FSTSnapshotVersion *)lastRemoteSnapshotVersion {
return _lastRemoteSnapshotVersion;
}
@@ -116,7 +128,6 @@ static ReadOptions GetStandardReadOptions() {
}
- (void)addQueryData:(FSTQueryData *)queryData group:(FSTWriteGroup *)group {
- // TODO(mcg): actually populate listen sequence number
FSTTargetID targetID = queryData.targetID;
std::string key = [FSTLevelDBTargetKey keyWithTargetID:targetID];
[group setMessage:[self.serializer encodedQueryData:queryData] forKey:key];
@@ -127,9 +138,19 @@ static ReadOptions GetStandardReadOptions() {
std::string emptyBuffer;
[group setData:emptyBuffer forKey:indexKey];
+ BOOL saveMetadata = NO;
FSTPBTargetGlobal *metadata = self.metadata;
if (targetID > metadata.highestTargetId) {
metadata.highestTargetId = targetID;
+ saveMetadata = YES;
+ }
+
+ if (queryData.sequenceNumber > metadata.highestListenSequenceNumber) {
+ metadata.highestListenSequenceNumber = queryData.sequenceNumber;
+ saveMetadata = YES;
+ }
+
+ if (saveMetadata) {
[group setMessage:metadata forKey:[FSTLevelDBTargetGlobalKey key]];
}
}
@@ -148,34 +169,6 @@ static ReadOptions GetStandardReadOptions() {
}
/**
- * Looks up the query global metadata associated with the given key.
- *
- * @return the parsed protocol buffer message or nil if the row referenced by the given key does
- * not exist.
- */
-- (nullable FSTPBTargetGlobal *)metadataForKey:(const std::string &)key {
- std::string value;
- Status status = _db->Get(GetStandardReadOptions(), key, &value);
- if (status.IsNotFound()) {
- return nil;
- } else if (!status.ok()) {
- FSTFail(@"metadataForKey: failed loading key %s with status: %s", key.c_str(),
- status.ToString().c_str());
- }
-
- NSData *data =
- [[NSData alloc] initWithBytesNoCopy:(void *)value.data() length:value.size() freeWhenDone:NO];
-
- NSError *error;
- FSTPBTargetGlobal *proto = [FSTPBTargetGlobal parseFromData:data error:&error];
- if (!proto) {
- FSTFail(@"FSTPBTargetGlobal failed to parse: %@", error);
- }
-
- return proto;
-}
-
-/**
* Parses the given bytes as an FSTPBTarget protocol buffer and then converts to the equivalent
* query data.
*/
@@ -197,7 +190,7 @@ static ReadOptions GetStandardReadOptions() {
// Note that this is a scan rather than a get because canonicalIDs are not required to be unique
// per target.
Slice canonicalID = StringView(query.canonicalID);
- std::unique_ptr<Iterator> indexItererator(_db->NewIterator(GetStandardReadOptions()));
+ std::unique_ptr<Iterator> indexItererator(_db->NewIterator([FSTLevelDB standardReadOptions]));
std::string indexPrefix = [FSTLevelDBQueryTargetKey keyPrefixWithCanonicalID:canonicalID];
indexItererator->Seek(indexPrefix);
@@ -205,7 +198,7 @@ static ReadOptions GetStandardReadOptions() {
// unique and ordered, so when scanning a table prefixed by exactly one canonicalID, all the
// targetIDs will be unique and in order.
std::string targetPrefix = [FSTLevelDBTargetKey keyPrefix];
- std::unique_ptr<Iterator> targetIterator(_db->NewIterator(GetStandardReadOptions()));
+ std::unique_ptr<Iterator> targetIterator(_db->NewIterator([FSTLevelDB standardReadOptions]));
FSTLevelDBQueryTargetKey *rowKey = [[FSTLevelDBQueryTargetKey alloc] init];
for (; indexItererator->Valid(); indexItererator->Next()) {
@@ -277,7 +270,7 @@ static ReadOptions GetStandardReadOptions() {
- (void)removeMatchingKeysForTargetID:(FSTTargetID)targetID group:(FSTWriteGroup *)group {
std::string indexPrefix = [FSTLevelDBTargetDocumentKey keyPrefixWithTargetID:targetID];
- std::unique_ptr<Iterator> indexIterator(_db->NewIterator(GetStandardReadOptions()));
+ std::unique_ptr<Iterator> indexIterator(_db->NewIterator([FSTLevelDB standardReadOptions]));
indexIterator->Seek(indexPrefix);
FSTLevelDBTargetDocumentKey *rowKey = [[FSTLevelDBTargetDocumentKey alloc] init];
@@ -300,7 +293,7 @@ static ReadOptions GetStandardReadOptions() {
- (FSTDocumentKeySet *)matchingKeysForTargetID:(FSTTargetID)targetID {
std::string indexPrefix = [FSTLevelDBTargetDocumentKey keyPrefixWithTargetID:targetID];
- std::unique_ptr<Iterator> indexIterator(_db->NewIterator(GetStandardReadOptions()));
+ std::unique_ptr<Iterator> indexIterator(_db->NewIterator([FSTLevelDB standardReadOptions]));
indexIterator->Seek(indexPrefix);
FSTDocumentKeySet *result = [FSTDocumentKeySet keySet];
@@ -323,7 +316,7 @@ static ReadOptions GetStandardReadOptions() {
- (BOOL)containsKey:(FSTDocumentKey *)key {
std::string indexPrefix = [FSTLevelDBDocumentTargetKey keyPrefixWithResourcePath:key.path];
- std::unique_ptr<Iterator> indexIterator(_db->NewIterator(GetStandardReadOptions()));
+ std::unique_ptr<Iterator> indexIterator(_db->NewIterator([FSTLevelDB standardReadOptions]));
indexIterator->Seek(indexPrefix);
if (indexIterator->Valid()) {
diff --git a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h
index 1da3cca..20942e2 100644
--- a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h
+++ b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h
@@ -16,15 +16,10 @@
#import <Foundation/Foundation.h>
-#import "Firestore/Source/Local/FSTRemoteDocumentCache.h"
-
-#ifdef __cplusplus
#include <memory>
-namespace leveldb {
-class DB;
-}
-#endif
+#import "Firestore/Source/Local/FSTRemoteDocumentCache.h"
+#include "leveldb/db.h"
@class FSTLocalSerializer;
@@ -35,7 +30,6 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init NS_UNAVAILABLE;
-#ifdef __cplusplus
/**
* Creates a new remote documents cache in the given leveldb.
*
@@ -43,7 +37,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (instancetype)initWithDB:(std::shared_ptr<leveldb::DB>)db
serializer:(FSTLocalSerializer *)serializer NS_DESIGNATED_INITIALIZER;
-#endif
@end
diff --git a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm
index 02f9f3e..b842cb5 100644
--- a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm
+++ b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm
@@ -32,12 +32,8 @@
#import "Firestore/Source/Model/FSTPath.h"
#import "Firestore/Source/Util/FSTAssert.h"
-#include "Firestore/Port/ordered_code.h"
-#include "Firestore/Port/string_util.h"
-
NS_ASSUME_NONNULL_BEGIN
-using Firestore::OrderedCode;
using leveldb::DB;
using leveldb::Iterator;
using leveldb::ReadOptions;
diff --git a/Firestore/Source/Local/FSTLocalDocumentsView.m b/Firestore/Source/Local/FSTLocalDocumentsView.mm
index a6734c4..0e88958 100644
--- a/Firestore/Source/Local/FSTLocalDocumentsView.m
+++ b/Firestore/Source/Local/FSTLocalDocumentsView.mm
@@ -167,9 +167,9 @@ NS_ASSUME_NONNULL_BEGIN
BOOL *stop) {
FSTMaybeDocument *mutatedDoc = [self localDocument:remoteDocument key:key];
if ([mutatedDoc isKindOfClass:[FSTDeletedDocument class]]) {
- result = [documents dictionaryByRemovingObjectForKey:key];
+ result = [result dictionaryByRemovingObjectForKey:key];
} else if ([mutatedDoc isKindOfClass:[FSTDocument class]]) {
- result = [documents dictionaryBySettingObject:(FSTDocument *)mutatedDoc forKey:key];
+ result = [result dictionaryBySettingObject:(FSTDocument *)mutatedDoc forKey:key];
} else {
FSTFail(@"Unknown document: %@", mutatedDoc);
}
diff --git a/Firestore/Source/Local/FSTLocalSerializer.m b/Firestore/Source/Local/FSTLocalSerializer.mm
index c71e9dd..c531c77 100644
--- a/Firestore/Source/Local/FSTLocalSerializer.m
+++ b/Firestore/Source/Local/FSTLocalSerializer.mm
@@ -16,6 +16,8 @@
#import "Firestore/Source/Local/FSTLocalSerializer.h"
+#include <inttypes.h>
+
#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h"
#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
@@ -156,6 +158,7 @@
FSTPBTarget *proto = [FSTPBTarget message];
proto.targetId = queryData.targetID;
+ proto.lastListenSequenceNumber = queryData.sequenceNumber;
proto.snapshotVersion = [remoteSerializer encodedVersion:queryData.snapshotVersion];
proto.resumeToken = queryData.resumeToken;
@@ -173,6 +176,7 @@
FSTSerializerBeta *remoteSerializer = self.remoteSerializer;
FSTTargetID targetID = target.targetId;
+ FSTListenSequenceNumber sequenceNumber = target.lastListenSequenceNumber;
FSTSnapshotVersion *version = [remoteSerializer decodedVersion:target.snapshotVersion];
NSData *resumeToken = target.resumeToken;
@@ -192,6 +196,7 @@
return [[FSTQueryData alloc] initWithQuery:query
targetID:targetID
+ listenSequenceNumber:sequenceNumber
purpose:FSTQueryPurposeListen
snapshotVersion:version
resumeToken:resumeToken];
diff --git a/Firestore/Source/Local/FSTLocalStore.m b/Firestore/Source/Local/FSTLocalStore.mm
index cde7104..fa77e37 100644
--- a/Firestore/Source/Local/FSTLocalStore.m
+++ b/Firestore/Source/Local/FSTLocalStore.mm
@@ -17,9 +17,9 @@
#import "Firestore/Source/Local/FSTLocalStore.h"
#import "Firestore/Source/Auth/FSTUser.h"
+#import "Firestore/Source/Core/FSTListenSequence.h"
#import "Firestore/Source/Core/FSTQuery.h"
#import "Firestore/Source/Core/FSTSnapshotVersion.h"
-#import "Firestore/Source/Core/FSTTargetIDGenerator.h"
#import "Firestore/Source/Core/FSTTimestamp.h"
#import "Firestore/Source/Local/FSTGarbageCollector.h"
#import "Firestore/Source/Local/FSTLocalDocumentsView.h"
@@ -41,6 +41,8 @@
#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTLogger.h"
+#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h"
+
NS_ASSUME_NONNULL_BEGIN
@interface FSTLocalStore ()
@@ -73,8 +75,7 @@ NS_ASSUME_NONNULL_BEGIN
/** Maps a targetID to data about its query. */
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, FSTQueryData *> *targetIDs;
-/** Used to generate targetIDs for queries tracked locally. */
-@property(nonatomic, strong) FSTTargetIDGenerator *targetIDGenerator;
+@property(nonatomic, strong) FSTListenSequence *listenSequence;
/**
* A heldBatchResult is a mutation batch result (from a write acknowledgement) that arrived before
@@ -89,7 +90,10 @@ NS_ASSUME_NONNULL_BEGIN
@end
-@implementation FSTLocalStore
+@implementation FSTLocalStore {
+ /** Used to generate targetIDs for queries tracked locally. */
+ firebase::firestore::core::TargetIdGenerator _targetIDGenerator;
+}
- (instancetype)initWithPersistence:(id<FSTPersistence>)persistence
garbageCollector:(id<FSTGarbageCollector>)garbageCollector
@@ -110,6 +114,9 @@ NS_ASSUME_NONNULL_BEGIN
_targetIDs = [NSMutableDictionary dictionary];
_heldBatchResults = [NSMutableArray array];
+
+ _targetIDGenerator =
+ firebase::firestore::core::TargetIdGenerator::LocalStoreTargetIdGenerator(0);
}
return self;
}
@@ -147,7 +154,10 @@ NS_ASSUME_NONNULL_BEGIN
[self.queryCache start];
FSTTargetID targetID = [self.queryCache highestTargetID];
- self.targetIDGenerator = [FSTTargetIDGenerator generatorForLocalStoreStartingAfterID:targetID];
+ _targetIDGenerator =
+ firebase::firestore::core::TargetIdGenerator::LocalStoreTargetIdGenerator(targetID);
+ FSTListenSequenceNumber sequenceNumber = [self.queryCache highestListenSequenceNumber];
+ self.listenSequence = [[FSTListenSequence alloc] initStartingAfter:sequenceNumber];
}
- (void)shutdown {
@@ -380,6 +390,7 @@ NS_ASSUME_NONNULL_BEGIN
- (FSTQueryData *)allocateQuery:(FSTQuery *)query {
FSTQueryData *cached = [self.queryCache queryDataForQuery:query];
FSTTargetID targetID;
+ FSTListenSequenceNumber sequenceNumber = [self.listenSequence next];
if (cached) {
// This query has been listened to previously, so reuse the previous targetID.
// TODO(mcg): freshen last accessed date?
@@ -387,9 +398,11 @@ NS_ASSUME_NONNULL_BEGIN
} else {
FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Allocate query"];
- targetID = [self.targetIDGenerator nextID];
- cached =
- [[FSTQueryData alloc] initWithQuery:query targetID:targetID purpose:FSTQueryPurposeListen];
+ targetID = _targetIDGenerator.NextId();
+ cached = [[FSTQueryData alloc] initWithQuery:query
+ targetID:targetID
+ listenSequenceNumber:sequenceNumber
+ purpose:FSTQueryPurposeListen];
[self.queryCache addQueryData:cached group:group];
[self.persistence commitGroup:group];
diff --git a/Firestore/Source/Local/FSTLocalViewChanges.m b/Firestore/Source/Local/FSTLocalViewChanges.mm
index 9a7f445..9a7f445 100644
--- a/Firestore/Source/Local/FSTLocalViewChanges.m
+++ b/Firestore/Source/Local/FSTLocalViewChanges.mm
diff --git a/Firestore/Source/Local/FSTLocalWriteResult.m b/Firestore/Source/Local/FSTLocalWriteResult.mm
index c1753fe..c1753fe 100644
--- a/Firestore/Source/Local/FSTLocalWriteResult.m
+++ b/Firestore/Source/Local/FSTLocalWriteResult.mm
diff --git a/Firestore/Source/Local/FSTMemoryMutationQueue.m b/Firestore/Source/Local/FSTMemoryMutationQueue.mm
index b155264..702f614 100644
--- a/Firestore/Source/Local/FSTMemoryMutationQueue.m
+++ b/Firestore/Source/Local/FSTMemoryMutationQueue.mm
@@ -23,10 +23,13 @@
#import "Firestore/Source/Model/FSTMutationBatch.h"
#import "Firestore/Source/Model/FSTPath.h"
#import "Firestore/Source/Util/FSTAssert.h"
-#import "Firestore/Source/Util/FSTComparison.h"
NS_ASSUME_NONNULL_BEGIN
+static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, NSNumber *right) {
+ return [left compare:right];
+};
+
@interface FSTMemoryMutationQueue ()
/**
@@ -260,7 +263,7 @@ NS_ASSUME_NONNULL_BEGIN
// Find unique batchIDs referenced by all documents potentially matching the query.
__block FSTImmutableSortedSet<NSNumber *> *uniqueBatchIDs =
- [FSTImmutableSortedSet setWithComparator:FSTNumberComparator];
+ [FSTImmutableSortedSet setWithComparator:NumberComparator];
FSTDocumentReferenceBlock block = ^(FSTDocumentReference *reference, BOOL *stop) {
FSTResourcePath *rowKeyPath = reference.key.path;
if (![prefix isPrefixOfPath:rowKeyPath]) {
diff --git a/Firestore/Source/Local/FSTMemoryPersistence.m b/Firestore/Source/Local/FSTMemoryPersistence.mm
index e301820..e301820 100644
--- a/Firestore/Source/Local/FSTMemoryPersistence.m
+++ b/Firestore/Source/Local/FSTMemoryPersistence.mm
diff --git a/Firestore/Source/Local/FSTMemoryQueryCache.m b/Firestore/Source/Local/FSTMemoryQueryCache.mm
index 8d37bcb..bcab174 100644
--- a/Firestore/Source/Local/FSTMemoryQueryCache.m
+++ b/Firestore/Source/Local/FSTMemoryQueryCache.mm
@@ -34,6 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
/** The highest numbered target ID encountered. */
@property(nonatomic, assign) FSTTargetID highestTargetID;
+@property(nonatomic, assign) FSTListenSequenceNumber highestListenSequenceNumber;
+
@end
@implementation FSTMemoryQueryCache {
@@ -65,6 +67,10 @@ NS_ASSUME_NONNULL_BEGIN
return _highestTargetID;
}
+- (FSTListenSequenceNumber)highestListenSequenceNumber {
+ return _highestListenSequenceNumber;
+}
+
- (FSTSnapshotVersion *)lastRemoteSnapshotVersion {
return _lastRemoteSnapshotVersion;
}
@@ -79,6 +85,9 @@ NS_ASSUME_NONNULL_BEGIN
if (queryData.targetID > self.highestTargetID) {
self.highestTargetID = queryData.targetID;
}
+ if (queryData.sequenceNumber > self.highestListenSequenceNumber) {
+ self.highestListenSequenceNumber = queryData.sequenceNumber;
+ }
}
- (void)removeQueryData:(FSTQueryData *)queryData group:(__unused FSTWriteGroup *)group {
diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.m b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm
index 9bbc047..9bbc047 100644
--- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.m
+++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm
diff --git a/Firestore/Source/Local/FSTNoOpGarbageCollector.m b/Firestore/Source/Local/FSTNoOpGarbageCollector.mm
index e03b599..e03b599 100644
--- a/Firestore/Source/Local/FSTNoOpGarbageCollector.m
+++ b/Firestore/Source/Local/FSTNoOpGarbageCollector.mm
diff --git a/Firestore/Source/Local/FSTQueryCache.h b/Firestore/Source/Local/FSTQueryCache.h
index e0cf4c8..88c9df9 100644
--- a/Firestore/Source/Local/FSTQueryCache.h
+++ b/Firestore/Source/Local/FSTQueryCache.h
@@ -53,6 +53,11 @@ NS_ASSUME_NONNULL_BEGIN
- (FSTTargetID)highestTargetID;
/**
+ * Returns the highest listen sequence number of any query seen by the cache.
+ */
+- (FSTListenSequenceNumber)highestListenSequenceNumber;
+
+/**
* A global snapshot version representing the last consistent snapshot we received from the
* backend. This is monotonically increasing and any snapshots received from the backend prior to
* this version (e.g. for targets resumed with a resume_token) should be suppressed (buffered)
diff --git a/Firestore/Source/Local/FSTQueryData.h b/Firestore/Source/Local/FSTQueryData.h
index 048bfad..5db2de6 100644
--- a/Firestore/Source/Local/FSTQueryData.h
+++ b/Firestore/Source/Local/FSTQueryData.h
@@ -40,6 +40,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) {
- (instancetype)initWithQuery:(FSTQuery *)query
targetID:(FSTTargetID)targetID
+ listenSequenceNumber:(FSTListenSequenceNumber)sequenceNumber
purpose:(FSTQueryPurpose)purpose
snapshotVersion:(FSTSnapshotVersion *)snapshotVersion
resumeToken:(NSData *)resumeToken NS_DESIGNATED_INITIALIZER;
@@ -47,6 +48,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) {
/** Convenience initializer for use when creating an FSTQueryData for the first time. */
- (instancetype)initWithQuery:(FSTQuery *)query
targetID:(FSTTargetID)targetID
+ listenSequenceNumber:(FSTListenSequenceNumber)sequenceNumber
purpose:(FSTQueryPurpose)purpose;
- (instancetype)init NS_UNAVAILABLE;
@@ -64,6 +66,8 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) {
*/
@property(nonatomic, assign, readonly) FSTTargetID targetID;
+@property(nonatomic, assign, readonly) FSTListenSequenceNumber sequenceNumber;
+
/** The purpose of the query. */
@property(nonatomic, assign, readonly) FSTQueryPurpose purpose;
diff --git a/Firestore/Source/Local/FSTQueryData.m b/Firestore/Source/Local/FSTQueryData.mm
index 080f136..6bb716a 100644
--- a/Firestore/Source/Local/FSTQueryData.m
+++ b/Firestore/Source/Local/FSTQueryData.mm
@@ -25,6 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithQuery:(FSTQuery *)query
targetID:(FSTTargetID)targetID
+ listenSequenceNumber:(FSTListenSequenceNumber)sequenceNumber
purpose:(FSTQueryPurpose)purpose
snapshotVersion:(FSTSnapshotVersion *)snapshotVersion
resumeToken:(NSData *)resumeToken {
@@ -32,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
if (self) {
_query = query;
_targetID = targetID;
+ _sequenceNumber = sequenceNumber;
_purpose = purpose;
_snapshotVersion = snapshotVersion;
_resumeToken = [resumeToken copy];
@@ -41,9 +43,11 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithQuery:(FSTQuery *)query
targetID:(FSTTargetID)targetID
+ listenSequenceNumber:(FSTListenSequenceNumber)sequenceNumber
purpose:(FSTQueryPurpose)purpose {
return [self initWithQuery:query
targetID:targetID
+ listenSequenceNumber:sequenceNumber
purpose:purpose
snapshotVersion:[FSTSnapshotVersion noVersion]
resumeToken:[NSData data]];
@@ -83,6 +87,7 @@ NS_ASSUME_NONNULL_BEGIN
resumeToken:(NSData *)resumeToken {
return [[FSTQueryData alloc] initWithQuery:self.query
targetID:self.targetID
+ listenSequenceNumber:self.sequenceNumber
purpose:self.purpose
snapshotVersion:snapshotVersion
resumeToken:resumeToken];
diff --git a/Firestore/Source/Local/FSTReferenceSet.m b/Firestore/Source/Local/FSTReferenceSet.mm
index 2acd64b..2acd64b 100644
--- a/Firestore/Source/Local/FSTReferenceSet.m
+++ b/Firestore/Source/Local/FSTReferenceSet.mm
diff --git a/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.m b/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm
index bca587a..bca587a 100644
--- a/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.m
+++ b/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm
diff --git a/Firestore/Source/Local/FSTWriteGroup.h b/Firestore/Source/Local/FSTWriteGroup.h
index 5ea0387..c21ff72 100644
--- a/Firestore/Source/Local/FSTWriteGroup.h
+++ b/Firestore/Source/Local/FSTWriteGroup.h
@@ -16,17 +16,10 @@
#import <Foundation/Foundation.h>
-#ifdef __cplusplus
#include <memory>
#include "Firestore/Source/Local/StringView.h"
-
-namespace leveldb {
-class DB;
-class Status;
-}
-
-#endif
+#include "leveldb/db.h"
NS_ASSUME_NONNULL_BEGIN
@@ -61,8 +54,6 @@ NS_ASSUME_NONNULL_BEGIN
/** Returns YES if the write group has no messages in it. */
- (BOOL)isEmpty;
-#ifdef __cplusplus
-
/**
* Marks the given key for deletion.
*
@@ -90,8 +81,6 @@ NS_ASSUME_NONNULL_BEGIN
/** Writes the contents to the given LevelDB. */
- (leveldb::Status)writeToDB:(std::shared_ptr<leveldb::DB>)db;
-#endif
-
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTWriteGroup.mm b/Firestore/Source/Local/FSTWriteGroup.mm
index 6859d53..80d09ca 100644
--- a/Firestore/Source/Local/FSTWriteGroup.mm
+++ b/Firestore/Source/Local/FSTWriteGroup.mm
@@ -23,9 +23,6 @@
#import "Firestore/Source/Local/FSTLevelDBKey.h"
#import "Firestore/Source/Util/FSTAssert.h"
-#include "Firestore/Port/ordered_code.h"
-
-using Firestore::OrderedCode;
using Firestore::StringView;
using leveldb::DB;
using leveldb::Slice;
diff --git a/Firestore/Source/Local/FSTWriteGroupTracker.m b/Firestore/Source/Local/FSTWriteGroupTracker.mm
index 7e3bf60..7e3bf60 100644
--- a/Firestore/Source/Local/FSTWriteGroupTracker.m
+++ b/Firestore/Source/Local/FSTWriteGroupTracker.mm
diff --git a/Firestore/Source/Local/StringView.h b/Firestore/Source/Local/StringView.h
index b81b7b5..4e36cff 100644
--- a/Firestore/Source/Local/StringView.h
+++ b/Firestore/Source/Local/StringView.h
@@ -17,14 +17,11 @@
#ifndef IPHONE_FIRESTORE_SOURCE_LOCAL_STRING_VIEW_H_
#define IPHONE_FIRESTORE_SOURCE_LOCAL_STRING_VIEW_H_
-#ifndef __cplusplus
-#error "StringView is Objective-C++ and can only be included from .mm files"
-#endif
-
#import <Foundation/Foundation.h>
#include <leveldb/slice.h>
#include <string>
+#include "absl/strings/string_view.h"
namespace Firestore {
@@ -64,6 +61,10 @@ class StringView {
StringView(leveldb::Slice slice) : data_(slice.data()), size_(slice.size()) {
}
+ // Creates a StringView from the absl::string_view.
+ StringView(absl::string_view s) : data_(s.data()), size_(s.size()) {
+ }
+
// Creates a StringView from the given std::string. The string must be an
// lvalue for the lifetime requirements to be satisfied.
StringView(const std::string &str) : data_(str.data()), size_(str.size()) {
@@ -76,6 +77,13 @@ class StringView {
return leveldb::Slice(data_, size_);
}
+ // Converts this StringView to a absl::string_view, which is an equivalent (and more
+ // functional) type. The returned string_view has the same lifetime as this
+ // StringView.
+ operator absl::string_view() {
+ return absl::string_view(data_, size_);
+ }
+
private:
const char *data_;
const size_t size_;
diff --git a/Firestore/Source/Model/FSTDatabaseID.m b/Firestore/Source/Model/FSTDatabaseID.mm
index 4d0448a..bff5855 100644
--- a/Firestore/Source/Model/FSTDatabaseID.m
+++ b/Firestore/Source/Model/FSTDatabaseID.mm
@@ -48,7 +48,7 @@ NSString *const kDefaultDatabaseID = @"(default)";
- (BOOL)isEqual:(id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
return [self isEqualToDatabaseId:other];
}
diff --git a/Firestore/Source/Model/FSTDocument.m b/Firestore/Source/Model/FSTDocument.mm
index bf416e7..bf416e7 100644
--- a/Firestore/Source/Model/FSTDocument.m
+++ b/Firestore/Source/Model/FSTDocument.mm
diff --git a/Firestore/Source/Model/FSTDocumentDictionary.m b/Firestore/Source/Model/FSTDocumentDictionary.mm
index 362af54..362af54 100644
--- a/Firestore/Source/Model/FSTDocumentDictionary.m
+++ b/Firestore/Source/Model/FSTDocumentDictionary.mm
diff --git a/Firestore/Source/Model/FSTDocumentKey.m b/Firestore/Source/Model/FSTDocumentKey.mm
index a382a55..a382a55 100644
--- a/Firestore/Source/Model/FSTDocumentKey.m
+++ b/Firestore/Source/Model/FSTDocumentKey.mm
diff --git a/Firestore/Source/Model/FSTDocumentKeySet.m b/Firestore/Source/Model/FSTDocumentKeySet.mm
index f07b785..f07b785 100644
--- a/Firestore/Source/Model/FSTDocumentKeySet.m
+++ b/Firestore/Source/Model/FSTDocumentKeySet.mm
diff --git a/Firestore/Source/Model/FSTDocumentSet.h b/Firestore/Source/Model/FSTDocumentSet.h
index a7f8c4a..022e900 100644
--- a/Firestore/Source/Model/FSTDocumentSet.h
+++ b/Firestore/Source/Model/FSTDocumentSet.h
@@ -59,16 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
- (FSTDocument *_Nullable)lastDocument;
/**
- * Returns the document previous to the document associated with the given key in the set according
- * to its built in ordering. Returns nil if the document associated with the given key is the
- * first document.
- *
- * @param key A key that must be present in the DocumentSet.
- * @throws NSInvalidArgumentException if key is not present.
- */
-- (FSTDocument *_Nullable)predecessorDocumentForKey:(FSTDocumentKey *)key;
-
-/**
* Returns the index of the document with the provided key in the document set. Returns NSNotFound
* if the key is not present.
*/
diff --git a/Firestore/Source/Model/FSTDocumentSet.m b/Firestore/Source/Model/FSTDocumentSet.mm
index c4c0f49..6f44799 100644
--- a/Firestore/Source/Model/FSTDocumentSet.m
+++ b/Firestore/Source/Model/FSTDocumentSet.mm
@@ -135,16 +135,6 @@ typedef FSTImmutableSortedSet<FSTDocument *> SetType;
return [self.sortedSet lastObject];
}
-- (FSTDocument *_Nullable)predecessorDocumentForKey:(FSTDocumentKey *)key {
- FSTDocument *doc = [self.index objectForKey:key];
- if (!doc) {
- @throw [NSException exceptionWithName:NSInvalidArgumentException
- reason:[NSString stringWithFormat:@"Key %@ does not exist", key]
- userInfo:nil];
- }
- return [self.sortedSet predecessorObject:doc];
-}
-
- (NSUInteger)indexOfKey:(FSTDocumentKey *)key {
FSTDocument *doc = [self.index objectForKey:key];
return doc ? [self.sortedSet indexOfObject:doc] : NSNotFound;
diff --git a/Firestore/Source/Model/FSTDocumentVersionDictionary.m b/Firestore/Source/Model/FSTDocumentVersionDictionary.mm
index 870e082..870e082 100644
--- a/Firestore/Source/Model/FSTDocumentVersionDictionary.m
+++ b/Firestore/Source/Model/FSTDocumentVersionDictionary.mm
diff --git a/Firestore/Source/Model/FSTFieldValue.h b/Firestore/Source/Model/FSTFieldValue.h
index 6de9793..93fd5c4 100644
--- a/Firestore/Source/Model/FSTFieldValue.h
+++ b/Firestore/Source/Model/FSTFieldValue.h
@@ -22,7 +22,9 @@
@class FSTDocumentKey;
@class FSTFieldPath;
@class FSTTimestamp;
+@class FSTFieldValueOptions;
@class FIRGeoPoint;
+@class FIRSnapshotOptions;
NS_ASSUME_NONNULL_BEGIN
@@ -40,6 +42,32 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
FSTTypeOrderObject,
};
+/** Defines the return value for pending server timestamps. */
+typedef NS_ENUM(NSInteger, FSTServerTimestampBehavior) {
+ FSTServerTimestampBehaviorNone,
+ FSTServerTimestampBehaviorEstimate,
+ FSTServerTimestampBehaviorPrevious
+};
+
+/** Holds properties that define field value deserialization options. */
+@interface FSTFieldValueOptions : NSObject
+
+@property(nonatomic, readonly, assign) FSTServerTimestampBehavior serverTimestampBehavior;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Creates an FSTFieldValueOptions instance that specifies deserialization behavior for pending
+ * server timestamps.
+ */
+- (instancetype)initWithServerTimestampBehavior:(FSTServerTimestampBehavior)serverTimestampBehavior
+ NS_DESIGNATED_INITIALIZER;
+
+/** Creates an FSTFieldValueOption instance from FIRSnapshotOptions. */
++ (instancetype)optionsForSnapshotOptions:(FIRSnapshotOptions *)value;
+
+@end
+
/**
* Abstract base class representing an immutable data value as stored in Firestore. FSTFieldValue
* represents all the different kinds of values that can be stored in fields in a document.
@@ -58,7 +86,7 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
* - Array
* - Object
*/
-@interface FSTFieldValue : NSObject
+@interface FSTFieldValue <__covariant T> : NSObject
/** Returns the FSTTypeOrder for this value. */
- (FSTTypeOrder)typeOrder;
@@ -69,7 +97,15 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
* TODO(mikelehen): This conversion should probably happen at the API level and right now `value` is
* used inappropriately in the serializer implementation, etc. We need to do some reworking.
*/
-- (id)value;
+- (T)value;
+
+/**
+ * Converts an FSTFieldValue into the value that users will see in document snapshots.
+ *
+ * Options can be provided to configure the deserialization of some field values (such as server
+ * timestamps).
+ */
+- (T)valueWithOptions:(FSTFieldValueOptions *)options;
/** Compares against another FSTFieldValue. */
- (NSComparisonResult)compare:(FSTFieldValue *)other;
@@ -79,26 +115,24 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
/**
* A null value stored in Firestore. The |value| of a FSTNullValue is [NSNull null].
*/
-@interface FSTNullValue : FSTFieldValue
+@interface FSTNullValue : FSTFieldValue <NSNull *>
+ (instancetype)nullValue;
-- (id)value;
@end
/**
* A boolean value stored in Firestore.
*/
-@interface FSTBooleanValue : FSTFieldValue
+@interface FSTBooleanValue : FSTFieldValue <NSNumber *>
+ (instancetype)trueValue;
+ (instancetype)falseValue;
+ (instancetype)booleanValue:(BOOL)value;
-- (NSNumber *)value;
@end
/**
* Base class inherited from by FSTIntegerValue and FSTDoubleValue. It implements proper number
* comparisons between the two types.
*/
-@interface FSTNumberValue : FSTFieldValue
+@interface FSTNumberValue : FSTFieldValue <NSNumber *>
@end
/**
@@ -106,7 +140,6 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
*/
@interface FSTIntegerValue : FSTNumberValue
+ (instancetype)integerValue:(int64_t)value;
-- (NSNumber *)value;
- (int64_t)internalValue;
@end
@@ -116,24 +149,21 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
@interface FSTDoubleValue : FSTNumberValue
+ (instancetype)doubleValue:(double)value;
+ (instancetype)nanValue;
-- (NSNumber *)value;
- (double)internalValue;
@end
/**
* A string stored in Firestore.
*/
-@interface FSTStringValue : FSTFieldValue
+@interface FSTStringValue : FSTFieldValue <NSString *>
+ (instancetype)stringValue:(NSString *)value;
-- (NSString *)value;
@end
/**
* A timestamp value stored in Firestore.
*/
-@interface FSTTimestampValue : FSTFieldValue
+@interface FSTTimestampValue : FSTFieldValue <NSDate *>
+ (instancetype)timestampValue:(FSTTimestamp *)value;
-- (NSDate *)value;
- (FSTTimestamp *)internalValue;
@end
@@ -144,46 +174,54 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
* - FSTServerTimestampValue instances are created as the result of applying an FSTTransformMutation
* (see [FSTTransformMutation applyTo]). They can only exist in the local view of a document.
* Therefore they do not need to be parsed or serialized.
- * - When evaluated locally (e.g. via FSTDocumentSnapshot data), they evaluate to NSNull (at least
- * for now, see b/62064202).
+ * - When evaluated locally (e.g. via FSTDocumentSnapshot data), they by default evaluate to NSNull.
+ * This behavior can be configured by passing custom FSTFieldValueOptions to `valueWithOptions:`.
* - They sort after all FSTTimestampValues. With respect to other FSTServerTimestampValues, they
* sort by their localWriteTime.
*/
-@interface FSTServerTimestampValue : FSTFieldValue
-+ (instancetype)serverTimestampValueWithLocalWriteTime:(FSTTimestamp *)localWriteTime;
-- (NSNull *)value;
+@interface FSTServerTimestampValue : FSTFieldValue <id>
++ (instancetype)serverTimestampValueWithLocalWriteTime:(FSTTimestamp *)localWriteTime
+ previousValue:(nullable FSTFieldValue *)previousValue;
+
@property(nonatomic, strong, readonly) FSTTimestamp *localWriteTime;
+@property(nonatomic, strong, readonly, nullable) FSTFieldValue *previousValue;
+
@end
/**
* A geo point value stored in Firestore.
*/
-@interface FSTGeoPointValue : FSTFieldValue
+@interface FSTGeoPointValue : FSTFieldValue <FIRGeoPoint *>
+ (instancetype)geoPointValue:(FIRGeoPoint *)value;
-- (FIRGeoPoint *)value;
+- (FIRGeoPoint *)valueWithOptions:(FSTFieldValueOptions *)options;
@end
/**
* A blob value stored in Firestore.
*/
-@interface FSTBlobValue : FSTFieldValue
+@interface FSTBlobValue : FSTFieldValue <NSData *>
+ (instancetype)blobValue:(NSData *)value;
-- (NSData *)value;
+- (NSData *)valueWithOptions:(FSTFieldValueOptions *)options;
@end
/**
* A reference value stored in Firestore.
*/
-@interface FSTReferenceValue : FSTFieldValue
+@interface FSTReferenceValue : FSTFieldValue <FSTDocumentKey *>
+ (instancetype)referenceValue:(FSTDocumentKey *)value databaseID:(FSTDatabaseID *)databaseID;
-- (FSTDocumentKey *)value;
+- (FSTDocumentKey *)valueWithOptions:(FSTFieldValueOptions *)options;
@property(nonatomic, strong, readonly) FSTDatabaseID *databaseID;
@end
/**
* A structured object value stored in Firestore.
*/
-@interface FSTObjectValue : FSTFieldValue
+// clang-format off
+@interface FSTObjectValue : FSTFieldValue < NSDictionary<NSString *, id> * >
+
+- (instancetype)init NS_UNAVAILABLE;
+// clang-format on
+
/** Returns an empty FSTObjectValue. */
+ (instancetype)objectValue;
@@ -198,9 +236,7 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
- (instancetype)initWithImmutableDictionary:
(FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *)value NS_DESIGNATED_INITIALIZER;
-- (instancetype)init NS_UNAVAILABLE;
-
-- (NSDictionary<NSString *, id> *)value;
+- (NSDictionary<NSString *, id> *)valueWithOptions:(FSTFieldValueOptions *)options;
- (FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *)internalValue;
/** Returns the value at the given path if it exists. Returns nil otherwise. */
@@ -222,19 +258,20 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
/**
* An array value stored in Firestore.
*/
-@interface FSTArrayValue : FSTFieldValue
+// clang-format off
+@interface FSTArrayValue : FSTFieldValue < NSArray <id> * >
+
+- (instancetype)init NS_UNAVAILABLE;
+// clang-format on
/**
* Initializes this instance with the given array of wrapped values.
*
* @param value An immutable array of FSTFieldValue objects. Caller is responsible for copying the
- * value or releasing all references.
+ * value or releasing all references.
*/
- (instancetype)initWithValueNoCopy:(NSArray<FSTFieldValue *> *)value NS_DESIGNATED_INITIALIZER;
-- (instancetype)init NS_UNAVAILABLE;
-
-- (NSArray<id> *)value;
- (NSArray<FSTFieldValue *> *)internalValue;
@end
diff --git a/Firestore/Source/Model/FSTFieldValue.m b/Firestore/Source/Model/FSTFieldValue.mm
index 95ad306..8ffc98e 100644
--- a/Firestore/Source/Model/FSTFieldValue.m
+++ b/Firestore/Source/Model/FSTFieldValue.mm
@@ -16,17 +16,60 @@
#import "Firestore/Source/Model/FSTFieldValue.h"
+#include "Firestore/core/src/firebase/firestore/util/comparison.h"
+#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
+
#import "Firestore/Source/API/FIRGeoPoint+Internal.h"
+#import "Firestore/Source/API/FIRSnapshotOptions+Internal.h"
#import "Firestore/Source/Core/FSTTimestamp.h"
#import "Firestore/Source/Model/FSTDatabaseID.h"
#import "Firestore/Source/Model/FSTDocumentKey.h"
#import "Firestore/Source/Model/FSTPath.h"
#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTClasses.h"
-#import "Firestore/Source/Util/FSTComparison.h"
+
+using firebase::firestore::util::Comparator;
+using firebase::firestore::util::CompareMixedNumber;
+using firebase::firestore::util::DoubleBitwiseEquals;
+using firebase::firestore::util::DoubleBitwiseHash;
+using firebase::firestore::util::MakeStringView;
+using firebase::firestore::util::ReverseOrder;
+using firebase::firestore::util::WrapCompare;
NS_ASSUME_NONNULL_BEGIN
+#pragma mark - FSTFieldValueOptions
+
+@implementation FSTFieldValueOptions
+
++ (instancetype)optionsForSnapshotOptions:(FIRSnapshotOptions *)options {
+ if (options.serverTimestampBehavior == FSTServerTimestampBehaviorNone) {
+ static FSTFieldValueOptions *defaultInstance = nil;
+ static dispatch_once_t onceToken;
+
+ dispatch_once(&onceToken, ^{
+ defaultInstance = [[FSTFieldValueOptions alloc]
+ initWithServerTimestampBehavior:FSTServerTimestampBehaviorNone];
+ });
+ return defaultInstance;
+ } else {
+ return [[FSTFieldValueOptions alloc]
+ initWithServerTimestampBehavior:options.serverTimestampBehavior];
+ }
+}
+
+- (instancetype)initWithServerTimestampBehavior:
+ (FSTServerTimestampBehavior)serverTimestampBehavior {
+ self = [super init];
+
+ if (self) {
+ _serverTimestampBehavior = serverTimestampBehavior;
+ }
+ return self;
+}
+
+@end
+
#pragma mark - FSTFieldValue
@interface FSTFieldValue ()
@@ -40,6 +83,11 @@ NS_ASSUME_NONNULL_BEGIN
}
- (id)value {
+ return [self valueWithOptions:[FSTFieldValueOptions
+ optionsForSnapshotOptions:[FIRSnapshotOptions defaultOptions]]];
+}
+
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
@throw FSTAbstractMethodException(); // NOLINT
}
@@ -89,7 +137,7 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderNull;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return [NSNull null];
}
@@ -155,7 +203,7 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderBoolean;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return self.internalValue ? @YES : @NO;
}
@@ -170,7 +218,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSComparisonResult)compare:(FSTFieldValue *)other {
if ([other isKindOfClass:[FSTBooleanValue class]]) {
- return FSTCompareBools(self.internalValue, ((FSTBooleanValue *)other).internalValue);
+ return WrapCompare<bool>(self.internalValue, ((FSTBooleanValue *)other).internalValue);
} else {
return [self defaultCompare:other];
}
@@ -193,19 +241,22 @@ NS_ASSUME_NONNULL_BEGIN
if ([self isKindOfClass:[FSTDoubleValue class]]) {
double thisDouble = ((FSTDoubleValue *)self).internalValue;
if ([other isKindOfClass:[FSTDoubleValue class]]) {
- return FSTCompareDoubles(thisDouble, ((FSTDoubleValue *)other).internalValue);
+ return WrapCompare(thisDouble, ((FSTDoubleValue *)other).internalValue);
} else {
FSTAssert([other isKindOfClass:[FSTIntegerValue class]], @"Unknown number value: %@",
other);
- return FSTCompareMixed(thisDouble, ((FSTIntegerValue *)other).internalValue);
+ auto result = CompareMixedNumber(thisDouble, ((FSTIntegerValue *)other).internalValue);
+ return static_cast<NSComparisonResult>(result);
}
} else {
int64_t thisInt = ((FSTIntegerValue *)self).internalValue;
if ([other isKindOfClass:[FSTIntegerValue class]]) {
- return FSTCompareInt64s(thisInt, ((FSTIntegerValue *)other).internalValue);
+ return WrapCompare(thisInt, ((FSTIntegerValue *)other).internalValue);
} else {
FSTAssert([other isKindOfClass:[FSTDoubleValue class]], @"Unknown number value: %@", other);
- return -1 * FSTCompareMixed(((FSTDoubleValue *)other).internalValue, thisInt);
+ double otherDouble = ((FSTDoubleValue *)other).internalValue;
+ auto result = ReverseOrder(CompareMixedNumber(otherDouble, thisInt));
+ return static_cast<NSComparisonResult>(result);
}
}
}
@@ -233,7 +284,7 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return @(self.internalValue);
}
@@ -285,7 +336,7 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return @(self.internalValue);
}
@@ -296,11 +347,11 @@ NS_ASSUME_NONNULL_BEGIN
// NOTE: isEqual: should compare NaN equal to itself and -0.0 not equal to 0.0.
return [other isKindOfClass:[FSTDoubleValue class]] &&
- FSTDoubleBitwiseEquals(self.internalValue, ((FSTDoubleValue *)other).internalValue);
+ DoubleBitwiseEquals(self.internalValue, ((FSTDoubleValue *)other).internalValue);
}
- (NSUInteger)hash {
- return FSTDoubleBitwiseHash(self.internalValue);
+ return DoubleBitwiseHash(self.internalValue);
}
// NOTE: compare: is implemented in NumberValue.
@@ -309,6 +360,17 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - FSTStringValue
+/**
+ * Specialization of Comparator for NSStrings.
+ */
+template <>
+struct Comparator<NSString *> {
+ bool operator()(NSString *left, NSString *right) const {
+ Comparator<absl::string_view> lessThan;
+ return lessThan(MakeStringView(left), MakeStringView(right));
+ }
+};
+
@interface FSTStringValue ()
@property(nonatomic, copy, readonly) NSString *internalValue;
@end
@@ -332,7 +394,7 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderString;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return self.internalValue;
}
@@ -347,7 +409,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSComparisonResult)compare:(FSTFieldValue *)other {
if ([other isKindOfClass:[FSTStringValue class]]) {
- return FSTCompareStrings(self.internalValue, ((FSTStringValue *)other).internalValue);
+ return WrapCompare(self.internalValue, ((FSTStringValue *)other).internalValue);
} else {
return [self defaultCompare:other];
}
@@ -379,7 +441,7 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderTimestamp;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
// For developers, we expose Timestamps as Dates.
return self.internalValue.approximateDateValue;
}
@@ -410,14 +472,18 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FSTServerTimestampValue
-+ (instancetype)serverTimestampValueWithLocalWriteTime:(FSTTimestamp *)localWriteTime {
- return [[FSTServerTimestampValue alloc] initWithLocalWriteTime:localWriteTime];
++ (instancetype)serverTimestampValueWithLocalWriteTime:(FSTTimestamp *)localWriteTime
+ previousValue:(nullable FSTFieldValue *)previousValue {
+ return [[FSTServerTimestampValue alloc] initWithLocalWriteTime:localWriteTime
+ previousValue:previousValue];
}
-- (id)initWithLocalWriteTime:(FSTTimestamp *)localWriteTime {
+- (id)initWithLocalWriteTime:(FSTTimestamp *)localWriteTime
+ previousValue:(nullable FSTFieldValue *)previousValue {
self = [super init];
if (self) {
_localWriteTime = localWriteTime;
+ _previousValue = previousValue;
}
return self;
}
@@ -426,9 +492,17 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderTimestamp;
}
-- (NSNull *)value {
- // For developers, server timestamps always evaluate to NSNull (for now, at least; b/62064202).
- return [NSNull null];
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
+ switch (options.serverTimestampBehavior) {
+ case FSTServerTimestampBehaviorNone:
+ return [NSNull null];
+ case FSTServerTimestampBehaviorEstimate:
+ return [self.localWriteTime approximateDateValue];
+ case FSTServerTimestampBehaviorPrevious:
+ return self.previousValue ? [self.previousValue valueWithOptions:options] : [NSNull null];
+ default:
+ FSTFail(@"Unexpected server timestamp option: %d", (int)options.serverTimestampBehavior);
+ }
}
- (BOOL)isEqual:(id)other {
@@ -481,7 +555,7 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderGeoPoint;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return self.internalValue;
}
@@ -506,6 +580,22 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - FSTBlobValue
+static NSComparisonResult CompareBytes(NSData *left, NSData *right) {
+ NSUInteger minLength = MIN(left.length, right.length);
+ int result = memcmp(left.bytes, right.bytes, minLength);
+ if (result < 0) {
+ return NSOrderedAscending;
+ } else if (result > 0) {
+ return NSOrderedDescending;
+ } else if (left.length < right.length) {
+ return NSOrderedAscending;
+ } else if (left.length > right.length) {
+ return NSOrderedDescending;
+ } else {
+ return NSOrderedSame;
+ }
+}
+
@interface FSTBlobValue ()
@property(nonatomic, copy, readonly) NSData *internalValue;
@end
@@ -529,7 +619,7 @@ NS_ASSUME_NONNULL_BEGIN
return FSTTypeOrderBlob;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return self.internalValue;
}
@@ -544,7 +634,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSComparisonResult)compare:(FSTFieldValue *)other {
if ([other isKindOfClass:[FSTBlobValue class]]) {
- return FSTCompareBytes(self.internalValue, ((FSTBlobValue *)other).internalValue);
+ return CompareBytes(self.internalValue, ((FSTBlobValue *)other).internalValue);
} else {
return [self defaultCompare:other];
}
@@ -573,7 +663,7 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
return self.key;
}
@@ -614,6 +704,10 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - FSTObjectValue
+static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, NSString *right) {
+ return WrapCompare(left, right);
+};
+
@interface FSTObjectValue ()
@property(nonatomic, strong, readonly)
FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *internalValue;
@@ -627,7 +721,7 @@ NS_ASSUME_NONNULL_BEGIN
dispatch_once(&onceToken, ^{
FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *empty =
- [FSTImmutableSortedDictionary dictionaryWithComparator:FSTStringComparator];
+ [FSTImmutableSortedDictionary dictionaryWithComparator:StringComparator];
sharedEmptyInstance = [[FSTObjectValue alloc] initWithImmutableDictionary:empty];
});
return sharedEmptyInstance;
@@ -644,15 +738,15 @@ NS_ASSUME_NONNULL_BEGIN
- (id)initWithDictionary:(NSDictionary<NSString *, FSTFieldValue *> *)value {
FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *dictionary =
- [FSTImmutableSortedDictionary dictionaryWithDictionary:value comparator:FSTStringComparator];
+ [FSTImmutableSortedDictionary dictionaryWithDictionary:value comparator:StringComparator];
return [self initWithImmutableDictionary:dictionary];
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
[self.internalValue
enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) {
- result[key] = [obj value];
+ result[key] = [obj valueWithOptions:options];
}];
return result;
}
@@ -698,7 +792,7 @@ NS_ASSUME_NONNULL_BEGIN
key2 = [enumerator2 nextObject];
}
// Only equal if both enumerators are exhausted.
- return FSTCompareBools(key1 != nil, key2 != nil);
+ return WrapCompare(key1 != nil, key2 != nil);
} else {
return [self defaultCompare:other];
}
@@ -803,7 +897,7 @@ NS_ASSUME_NONNULL_BEGIN
return [self.internalValue hash];
}
-- (id)value {
+- (id)valueWithOptions:(FSTFieldValueOptions *)options {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count];
[self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) {
[result addObject:[obj value]];
@@ -826,7 +920,7 @@ NS_ASSUME_NONNULL_BEGIN
return cmp;
}
}
- return FSTCompareUIntegers(selfArray.count, otherArray.count);
+ return WrapCompare<int64_t>(selfArray.count, otherArray.count);
} else {
return [self defaultCompare:other];
}
diff --git a/Firestore/Source/Model/FSTMutation.h b/Firestore/Source/Model/FSTMutation.h
index ef7f1c8..7c5f6de 100644
--- a/Firestore/Source/Model/FSTMutation.h
+++ b/Firestore/Source/Model/FSTMutation.h
@@ -158,8 +158,10 @@ typedef NS_ENUM(NSUInteger, FSTPreconditionExists) {
* Applies this mutation to the given FSTDocument, FSTDeletedDocument or nil, if we don't have
* information about this document. Both the input and returned documents can be nil.
*
- * @param maybeDoc The document to mutate. The input document should nil if it does not currently
- * exist.
+ * @param maybeDoc The current state of the document to mutate. The input document should be nil if
+ * it does not currently exist.
+ * @param baseDoc The state of the document prior to this mutation batch. The input document should
+ * be nil if it the document did not exist.
* @param localWriteTime A timestamp indicating the local write time of the batch this mutation is
* a part of.
* @param mutationResult Optional result info from the backend. If omitted, it's assumed that
@@ -196,16 +198,18 @@ typedef NS_ENUM(NSUInteger, FSTPreconditionExists) {
* apply the transform if the prior mutation resulted in an FSTDocument (always true for an
* FSTSetMutation, but not necessarily for an FSTPatchMutation).
*/
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
localWriteTime:(FSTTimestamp *)localWriteTime
- mutationResult:(FSTMutationResult *_Nullable)mutationResult;
+ mutationResult:(nullable FSTMutationResult *)mutationResult;
/**
* A helper version of applyTo for applying mutations locally (without a mutation result from the
* backend).
*/
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
- localWriteTime:(FSTTimestamp *)localWriteTime;
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
+ localWriteTime:(nullable FSTTimestamp *)localWriteTime;
@property(nonatomic, strong, readonly) FSTDocumentKey *key;
diff --git a/Firestore/Source/Model/FSTMutation.m b/Firestore/Source/Model/FSTMutation.mm
index 5b47280..c249138 100644
--- a/Firestore/Source/Model/FSTMutation.m
+++ b/Firestore/Source/Model/FSTMutation.mm
@@ -97,7 +97,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqual:(id)other {
if (other == self) return YES;
- if (!other || ![[other class] isEqual:[self class]]) return NO;
+ if (![[other class] isEqual:[self class]]) return NO;
FSTFieldTransform *otherFieldTransform = other;
return [self.path isEqual:otherFieldTransform.path] &&
[self.transform isEqual:otherFieldTransform.transform];
@@ -236,15 +236,18 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
localWriteTime:(FSTTimestamp *)localWriteTime
- mutationResult:(FSTMutationResult *_Nullable)mutationResult {
+ mutationResult:(nullable FSTMutationResult *)mutationResult {
@throw FSTAbstractMethodException(); // NOLINT
}
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
- localWriteTime:(FSTTimestamp *)localWriteTime {
- return [self applyTo:maybeDoc localWriteTime:localWriteTime mutationResult:nil];
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
+ localWriteTime:(nullable FSTTimestamp *)localWriteTime {
+ return
+ [self applyTo:maybeDoc baseDocument:baseDoc localWriteTime:localWriteTime mutationResult:nil];
}
@end
@@ -287,9 +290,10 @@ NS_ASSUME_NONNULL_BEGIN
return result;
}
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
localWriteTime:(FSTTimestamp *)localWriteTime
- mutationResult:(FSTMutationResult *_Nullable)mutationResult {
+ mutationResult:(nullable FSTMutationResult *)mutationResult {
if (mutationResult) {
FSTAssert(!mutationResult.transformResults, @"Transform results received by FSTSetMutation.");
}
@@ -362,9 +366,10 @@ NS_ASSUME_NONNULL_BEGIN
self.key, self.fieldMask, self.value, self.precondition];
}
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
localWriteTime:(FSTTimestamp *)localWriteTime
- mutationResult:(FSTMutationResult *_Nullable)mutationResult {
+ mutationResult:(nullable FSTMutationResult *)mutationResult {
if (mutationResult) {
FSTAssert(!mutationResult.transformResults, @"Transform results received by FSTPatchMutation.");
}
@@ -451,9 +456,10 @@ NS_ASSUME_NONNULL_BEGIN
self.key, self.fieldTransforms, self.precondition];
}
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
localWriteTime:(FSTTimestamp *)localWriteTime
- mutationResult:(FSTMutationResult *_Nullable)mutationResult {
+ mutationResult:(nullable FSTMutationResult *)mutationResult {
if (mutationResult) {
FSTAssert(mutationResult.transformResults,
@"Transform results missing for FSTTransformMutation.");
@@ -473,8 +479,9 @@ NS_ASSUME_NONNULL_BEGIN
BOOL hasLocalMutations = (mutationResult == nil);
NSArray<FSTFieldValue *> *transformResults =
- mutationResult ? mutationResult.transformResults
- : [self localTransformResultsWithWriteTime:localWriteTime];
+ mutationResult
+ ? mutationResult.transformResults
+ : [self localTransformResultsWithBaseDocument:baseDoc writeTime:localWriteTime];
FSTObjectValue *newData = [self transformObject:doc.data transformResults:transformResults];
return [FSTDocument documentWithData:newData
key:doc.key
@@ -486,16 +493,26 @@ NS_ASSUME_NONNULL_BEGIN
* Creates an array of "transform results" (a transform result is a field value representing the
* result of applying a transform) for use when applying an FSTTransformMutation locally.
*
+ * @param baseDocument The document prior to applying this mutation batch.
* @param localWriteTime The local time of the transform mutation (used to generate
* FSTServerTimestampValues).
* @return The transform results array.
*/
-- (NSArray<FSTFieldValue *> *)localTransformResultsWithWriteTime:(FSTTimestamp *)localWriteTime {
+- (NSArray<FSTFieldValue *> *)localTransformResultsWithBaseDocument:
+ (FSTMaybeDocument *_Nullable)baseDocument
+ writeTime:(FSTTimestamp *)localWriteTime {
NSMutableArray<FSTFieldValue *> *transformResults = [NSMutableArray array];
for (FSTFieldTransform *fieldTransform in self.fieldTransforms) {
if ([fieldTransform.transform isKindOfClass:[FSTServerTimestampTransform class]]) {
- [transformResults addObject:[FSTServerTimestampValue
- serverTimestampValueWithLocalWriteTime:localWriteTime]];
+ FSTFieldValue *previousValue = nil;
+
+ if ([baseDocument isMemberOfClass:[FSTDocument class]]) {
+ previousValue = [((FSTDocument *)baseDocument) fieldForPath:fieldTransform.path];
+ }
+
+ [transformResults
+ addObject:[FSTServerTimestampValue serverTimestampValueWithLocalWriteTime:localWriteTime
+ previousValue:previousValue]];
} else {
FSTFail(@"Encountered unknown transform: %@", fieldTransform);
}
@@ -551,9 +568,10 @@ NS_ASSUME_NONNULL_BEGIN
stringWithFormat:@"<FSTDeleteMutation key=%@ precondition=%@>", self.key, self.precondition];
}
-- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc
+- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc
+ baseDocument:(nullable FSTMaybeDocument *)baseDoc
localWriteTime:(FSTTimestamp *)localWriteTime
- mutationResult:(FSTMutationResult *_Nullable)mutationResult {
+ mutationResult:(nullable FSTMutationResult *)mutationResult {
if (mutationResult) {
FSTAssert(!mutationResult.transformResults,
@"Transform results received by FSTDeleteMutation.");
diff --git a/Firestore/Source/Model/FSTMutationBatch.m b/Firestore/Source/Model/FSTMutationBatch.mm
index 3677908..01adca7 100644
--- a/Firestore/Source/Model/FSTMutationBatch.m
+++ b/Firestore/Source/Model/FSTMutationBatch.mm
@@ -71,6 +71,7 @@ const FSTBatchID kFSTBatchIDUnknown = -1;
mutationBatchResult:(FSTMutationBatchResult *_Nullable)mutationBatchResult {
FSTAssert(!maybeDoc || [maybeDoc.key isEqualToKey:documentKey],
@"applyTo: key %@ doesn't match maybeDoc key %@", documentKey, maybeDoc.key);
+ FSTMaybeDocument *baseDoc = maybeDoc;
if (mutationBatchResult) {
FSTAssert(mutationBatchResult.mutationResults.count == self.mutations.count,
@"Mismatch between mutations length (%lu) and results length (%lu)",
@@ -83,6 +84,7 @@ const FSTBatchID kFSTBatchIDUnknown = -1;
FSTMutationResult *_Nullable mutationResult = mutationBatchResult.mutationResults[i];
if ([mutation.key isEqualToKey:documentKey]) {
maybeDoc = [mutation applyTo:maybeDoc
+ baseDocument:baseDoc
localWriteTime:self.localWriteTime
mutationResult:mutationResult];
}
diff --git a/Firestore/Source/Model/FSTPath.m b/Firestore/Source/Model/FSTPath.mm
index b236107..636c322 100644
--- a/Firestore/Source/Model/FSTPath.m
+++ b/Firestore/Source/Model/FSTPath.mm
@@ -240,7 +240,7 @@ NS_ASSUME_NONNULL_BEGIN
c = *source++;
// TODO(b/37244157): Make this a user-facing exception once we finalize field escaping.
FSTAssert(c != '\0', @"Trailing escape characters not allowed in %@", fieldPath);
- // Fall through
+ // Fall through
default:
// copy into the current segment
diff --git a/Firestore/Source/Public/FIRDocumentChange.h b/Firestore/Source/Public/FIRDocumentChange.h
index 022c81b..4717067 100644
--- a/Firestore/Source/Public/FIRDocumentChange.h
+++ b/Firestore/Source/Public/FIRDocumentChange.h
@@ -18,7 +18,7 @@
NS_ASSUME_NONNULL_BEGIN
-@class FIRDocumentSnapshot;
+@class FIRQueryDocumentSnapshot;
/** An enumeration of document change types. */
typedef NS_ENUM(NSInteger, FIRDocumentChangeType) {
@@ -47,7 +47,7 @@ NS_SWIFT_NAME(DocumentChange)
@property(nonatomic, readonly) FIRDocumentChangeType type;
/** The document affected by this change. */
-@property(nonatomic, strong, readonly) FIRDocumentSnapshot *document;
+@property(nonatomic, strong, readonly) FIRQueryDocumentSnapshot *document;
/**
* The index of the changed document in the result set immediately prior to this FIRDocumentChange
diff --git a/Firestore/Source/Public/FIRDocumentReference.h b/Firestore/Source/Public/FIRDocumentReference.h
index 439e727..7fcc7a8 100644
--- a/Firestore/Source/Public/FIRDocumentReference.h
+++ b/Firestore/Source/Public/FIRDocumentReference.h
@@ -36,8 +36,6 @@ NS_SWIFT_NAME(DocumentListenOptions)
- (instancetype)init;
-@property(nonatomic, assign, readonly) BOOL includeMetadataChanges;
-
/**
* Sets the includeMetadataChanges option which controls whether metadata-only changes (i.e. only
* `FIRDocumentSnapshot.metadata` changed) should trigger snapshot events. Default is NO.
diff --git a/Firestore/Source/Public/FIRDocumentSnapshot.h b/Firestore/Source/Public/FIRDocumentSnapshot.h
index 3e67c25..6e79a7f 100644
--- a/Firestore/Source/Public/FIRDocumentSnapshot.h
+++ b/Firestore/Source/Public/FIRDocumentSnapshot.h
@@ -22,9 +22,61 @@
NS_ASSUME_NONNULL_BEGIN
/**
+ * Controls the return value for server timestamps that have not yet been set to
+ * their final value.
+ */
+typedef NS_ENUM(NSInteger, FIRServerTimestampBehavior) {
+ /**
+ * Return `NSNull` for `FieldValue.serverTimestamp()` fields that have not yet
+ * been set to their final value.
+ */
+ FIRServerTimestampBehaviorNone,
+
+ /**
+ * Return a local estimates for `FieldValue.serverTimestamp()`
+ * fields that have not yet been set to their final value. This estimate will
+ * likely differ from the final value and may cause these pending values to
+ * change once the server result becomes available.
+ */
+ FIRServerTimestampBehaviorEstimate,
+
+ /**
+ * Return the previous value for `FieldValue.serverTimestamp()` fields that
+ * have not yet been set to their final value.
+ */
+ FIRServerTimestampBehaviorPrevious
+} NS_SWIFT_NAME(ServerTimestampBehavior);
+
+/**
+ * Options that configure how data is retrieved from a `DocumentSnapshot`
+ * (e.g. the desired behavior for server timestamps that have not yet been set
+ * to their final value).
+ */
+NS_SWIFT_NAME(SnapshotOptions)
+@interface FIRSnapshotOptions : NSObject
+
+/** */
+- (instancetype)init __attribute__((unavailable("FIRSnapshotOptions cannot be created directly.")));
+
+/**
+ * If set, controls the return value for `FieldValue.serverTimestamp()`
+ * fields that have not yet been set to their final value.
+ *
+ * If omitted, `NSNull` will be returned by default.
+ *
+ * @return The created `FIRSnapshotOptions` object.
+ */
++ (instancetype)serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior;
+
+@end
+
+/**
* A `FIRDocumentSnapshot` contains data read from a document in your Firestore database. The data
* can be extracted with the `data` property or by using subscript syntax to access a specific
* field.
+ *
+ * For a `FIRDocumentSnapshot` that points to a non-existing document, any data access will return
+ * `nil`. You can use the `exists` property to explicitly verify a documents existence.
*/
NS_SWIFT_NAME(DocumentSnapshot)
@interface FIRDocumentSnapshot : NSObject
@@ -46,21 +98,104 @@ NS_SWIFT_NAME(DocumentSnapshot)
@property(nonatomic, strong, readonly) FIRSnapshotMetadata *metadata;
/**
- * Retrieves all fields in the document as an `NSDictionary`.
+ * Retrieves all fields in the document as an `NSDictionary`. Returns `nil` if the document doesn't
+ * exist.
*
- * @return An `NSDictionary` containing all fields in the document.
+ * Server-provided timestamps that have not yet been set to their final value will be returned as
+ * `NSNull`. You can use `dataWithOptions()` to configure this behavior.
+ *
+ * @return An `NSDictionary` containing all fields in the document or `nil` if the document doesn't
+ * exist.
*/
-- (NSDictionary<NSString *, id> *)data;
+- (nullable NSDictionary<NSString *, id> *)data;
+
+/**
+ * Retrieves all fields in the document as a `Dictionary`. Returns `nil` if the document doesn't
+ * exist.
+ *
+ * @param options `SnapshotOptions` to configure how data is returned from the snapshot (e.g. the
+ * desired behavior for server timestamps that have not yet been set to their final value).
+ * @return A `Dictionary` containing all fields in the document or `nil` if the document doesn't
+ * exist.
+ */
+- (nullable NSDictionary<NSString *, id> *)dataWithOptions:(FIRSnapshotOptions *)options;
+
+/**
+ * Retrieves a specific field from the document. Returns `nil` if the document or the field doesn't
+ * exist.
+ *
+ * The timestamps that have not yet been set to their final value will be returned as `NSNull`. The
+ * can use `get(_:options:)` to configure this behavior.
+ *
+ * @param field The field to retrieve.
+ * @return The value contained in the field or `nil` if the document or field doesn't exist.
+ */
+- (nullable id)valueForField:(id)field NS_SWIFT_NAME(get(_:));
+
+/**
+ * Retrieves a specific field from the document. Returns `nil` if the document or the field doesn't
+ * exist.
+ *
+ * The timestamps that have not yet been set to their final value will be returned as `NSNull`. The
+ * can use `get(_:options:)` to configure this behavior.
+ *
+ * @param field The field to retrieve.
+ * @param options `SnapshotOptions` to configure how data is returned from the snapshot (e.g. the
+ * desired behavior for server timestamps that have not yet been set to their final value).
+ * @return The value contained in the field or `nil` if the document or field doesn't exist.
+ */
+// clang-format off
+- (nullable id)valueForField:(id)field
+ options:(FIRSnapshotOptions *)options
+ NS_SWIFT_NAME(get(_:options:));
+// clang-format on
/**
* Retrieves a specific field from the document.
*
* @param key The field to retrieve.
*
- * @return The value contained in the field or `nil` if the field doesn't exist.
+ * @return The value contained in the field or `nil` if the document or field doesn't exist.
*/
- (nullable id)objectForKeyedSubscript:(id)key;
@end
+/**
+ * A `FIRQueryDocumentSnapshot` contains data read from a document in your Firestore database as
+ * part of a query. The document is guaranteed to exist and its data can be extracted with the
+ * `data` property or by using subscript syntax to access a specific field.
+ *
+ * A `FIRQueryDocumentSnapshot` offers the same API surface as a `FIRDocumentSnapshot`. As
+ * deleted documents are not returned from queries, its `exists` property will always be true and
+ * `data:` will never return `nil`.
+ */
+NS_SWIFT_NAME(QueryDocumentSnapshot)
+@interface FIRQueryDocumentSnapshot : FIRDocumentSnapshot
+
+/** */
+- (instancetype)init
+ __attribute__((unavailable("FIRQueryDocumentSnapshot cannot be created directly.")));
+
+/**
+ * Retrieves all fields in the document as an `NSDictionary`.
+ *
+ * Server-provided timestamps that have not yet been set to their final value will be returned as
+ * `NSNull`. You can use `dataWithOptions()` to configure this behavior.
+ *
+ * @return An `NSDictionary` containing all fields in the document.
+ */
+- (NSDictionary<NSString *, id> *)data;
+
+/**
+ * Retrieves all fields in the document as a `Dictionary`.
+ *
+ * @param options `SnapshotOptions` to configure how data is returned from the snapshot (e.g. the
+ * desired behavior for server timestamps that have not yet been set to their final value).
+ * @return A `Dictionary` containing all fields in the document.
+ */
+- (NSDictionary<NSString *, id> *)dataWithOptions:(FIRSnapshotOptions *)options;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Public/FIRFirestore.h b/Firestore/Source/Public/FIRFirestore.h
index 91a96a5..4c85aba 100644
--- a/Firestore/Source/Public/FIRFirestore.h
+++ b/Firestore/Source/Public/FIRFirestore.h
@@ -139,6 +139,23 @@ NS_SWIFT_NAME(Firestore)
+ (void)enableLogging:(BOOL)logging
DEPRECATED_MSG_ATTRIBUTE("Use FIRSetLoggerLevel(FIRLoggerLevelDebug) to enable logging");
+#pragma mark - Network
+
+/**
+ * Re-enables usage of the network by this Firestore instance after a prior call to
+ * `disableNetworkWithCompletion`. Completion block, if provided, will be called once network uasge
+ * has been enabled.
+ */
+- (void)enableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable error))completion;
+
+/**
+ * Disables usage of the network by this Firestore instance. It can be re-enabled by via
+ * `enableNetworkWithCompletion`. While the network is disabled, any snapshot listeners or get calls
+ * will return results from cache and any write operations will be queued until the network is
+ * restored. The completion block, if provided, will be called once network usage has been disabled.
+ */
+- (void)disableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable error))completion;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Public/FIRQuery.h b/Firestore/Source/Public/FIRQuery.h
index 0f3aeed..ff15ac6 100644
--- a/Firestore/Source/Public/FIRQuery.h
+++ b/Firestore/Source/Public/FIRQuery.h
@@ -256,6 +256,19 @@ NS_SWIFT_NAME(Query)
isGreaterThanOrEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isGreaterThanOrEqualTo:));
// clang-format on
+/**
+ * Creates and returns a new `FIRQuery` with the additional filter that documents must
+ * satisfy the specified predicate.
+ *
+ * @param predicate The predicate the document must satisfy. Can be either comparison
+ * or compound of comparison. In particular, block-based predicate is not supported.
+ *
+ * @return The created `FIRQuery`.
+ */
+// clang-format off
+- (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate NS_SWIFT_NAME(filter(using:));
+// clang-format on
+
#pragma mark - Sorting Data
/**
* Creates and returns a new `FIRQuery` that's additionally sorted by the specified field.
diff --git a/Firestore/Source/Public/FIRQuerySnapshot.h b/Firestore/Source/Public/FIRQuerySnapshot.h
index c49a07a..1266832 100644
--- a/Firestore/Source/Public/FIRQuerySnapshot.h
+++ b/Firestore/Source/Public/FIRQuerySnapshot.h
@@ -19,8 +19,8 @@
NS_ASSUME_NONNULL_BEGIN
@class FIRDocumentChange;
-@class FIRDocumentSnapshot;
@class FIRQuery;
+@class FIRQueryDocumentSnapshot;
@class FIRSnapshotMetadata;
/**
@@ -50,7 +50,7 @@ NS_SWIFT_NAME(QuerySnapshot)
@property(nonatomic, readonly) NSInteger count;
/** An Array of the `FIRDocumentSnapshots` that make up this document set. */
-@property(nonatomic, strong, readonly) NSArray<FIRDocumentSnapshot *> *documents;
+@property(nonatomic, strong, readonly) NSArray<FIRQueryDocumentSnapshot *> *documents;
/**
* An array of the documents that changed since the last snapshot. If this is the first snapshot,
diff --git a/Firestore/Source/Public/FIRWriteBatch.h b/Firestore/Source/Public/FIRWriteBatch.h
index 5f0034c..8ff1bec 100644
--- a/Firestore/Source/Public/FIRWriteBatch.h
+++ b/Firestore/Source/Public/FIRWriteBatch.h
@@ -94,6 +94,11 @@ NS_SWIFT_NAME(WriteBatch)
/**
* Commits all of the writes in this write batch as a single atomic unit.
+ */
+- (void)commit;
+
+/**
+ * Commits all of the writes in this write batch as a single atomic unit.
*
* @param completion A block to be called once all of the writes in the batch have been
* successfully written to the backend as an atomic unit. This block will only execute
@@ -101,7 +106,7 @@ NS_SWIFT_NAME(WriteBatch)
* completion handler will not be called when the device is offline, though local
* changes will be visible immediately.
*/
-- (void)commitWithCompletion:(void (^)(NSError *_Nullable error))completion;
+- (void)commitWithCompletion:(nullable void (^)(NSError *_Nullable error))completion;
@end
diff --git a/Firestore/Source/Remote/FSTBufferedWriter.m b/Firestore/Source/Remote/FSTBufferedWriter.mm
index 47dbb21..47dbb21 100644
--- a/Firestore/Source/Remote/FSTBufferedWriter.m
+++ b/Firestore/Source/Remote/FSTBufferedWriter.mm
diff --git a/Firestore/Source/Remote/FSTDatastore.m b/Firestore/Source/Remote/FSTDatastore.mm
index 02d868c..02d868c 100644
--- a/Firestore/Source/Remote/FSTDatastore.m
+++ b/Firestore/Source/Remote/FSTDatastore.mm
diff --git a/Firestore/Source/Remote/FSTExistenceFilter.m b/Firestore/Source/Remote/FSTExistenceFilter.mm
index d5ec7b3..d5ec7b3 100644
--- a/Firestore/Source/Remote/FSTExistenceFilter.m
+++ b/Firestore/Source/Remote/FSTExistenceFilter.mm
diff --git a/Firestore/Source/Remote/FSTRemoteEvent.m b/Firestore/Source/Remote/FSTRemoteEvent.mm
index a97eb86..88999e4 100644
--- a/Firestore/Source/Remote/FSTRemoteEvent.m
+++ b/Firestore/Source/Remote/FSTRemoteEvent.mm
@@ -278,6 +278,14 @@ initWithSnapshotVersion:(FSTSnapshotVersion *)snapshotVersion
return self;
}
+- (NSDictionary<FSTBoxedTargetID *, FSTTargetChange *> *)targetChanges {
+ return static_cast<NSDictionary<FSTBoxedTargetID *, FSTTargetChange *> *>(_targetChanges);
+}
+
+- (NSDictionary<FSTDocumentKey *, FSTMaybeDocument *> *)documentUpdates {
+ return static_cast<NSDictionary<FSTDocumentKey *, FSTMaybeDocument *> *>(_documentUpdates);
+}
+
/** Adds a document update to this remote event */
- (void)addDocumentUpdate:(FSTMaybeDocument *)document {
_documentUpdates[document.key] = document;
@@ -352,6 +360,10 @@ initWithSnapshotVersion:(FSTSnapshotVersion *)snapshotVersion
return self;
}
+- (NSDictionary<FSTBoxedTargetID *, FSTExistenceFilter *> *)existenceFilters {
+ return static_cast<NSDictionary<FSTBoxedTargetID *, FSTExistenceFilter *> *>(_existenceFilters);
+}
+
- (FSTTargetChange *)targetChangeForTargetID:(FSTBoxedTargetID *)targetID {
FSTTargetChange *change = self.targetChanges[targetID];
if (!change) {
diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h
index 313ddb7..18331ff 100644
--- a/Firestore/Source/Remote/FSTRemoteStore.h
+++ b/Firestore/Source/Remote/FSTRemoteStore.h
@@ -83,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol FSTOnlineStateDelegate <NSObject>
/** Called whenever the online state of the watch stream changes */
-- (void)watchStreamDidChangeOnlineState:(FSTOnlineState)onlineState;
+- (void)applyChangedOnlineState:(FSTOnlineState)onlineState;
@end
diff --git a/Firestore/Source/Remote/FSTRemoteStore.m b/Firestore/Source/Remote/FSTRemoteStore.mm
index 063e487..123df49 100644
--- a/Firestore/Source/Remote/FSTRemoteStore.m
+++ b/Firestore/Source/Remote/FSTRemoteStore.mm
@@ -16,6 +16,8 @@
#import "Firestore/Source/Remote/FSTRemoteStore.h"
+#include <inttypes.h>
+
#import "Firestore/Source/Core/FSTQuery.h"
#import "Firestore/Source/Core/FSTSnapshotVersion.h"
#import "Firestore/Source/Core/FSTTransaction.h"
@@ -160,27 +162,38 @@ static const int kOnlineAttemptsBeforeFailure = 2;
[self enableNetwork];
}
-- (void)setOnlineStateToHealthy {
- self.shouldWarnOffline = NO;
- [self updateAndNotifyAboutOnlineState:FSTOnlineStateHealthy];
-}
-
-- (void)setOnlineStateToUnknown {
- // The state is set to unknown when a healthy stream is closed (e.g. due to a token timeout) or
- // when we have no active listens and therefore there's no need to start the stream. Assuming
- // there is (possibly in the future) an active listen, then we will eventually move to state
- // Online or Failed, but we always want to make at least kOnlineAttemptsBeforeFailure attempts
- // before failing, so we reset the count here.
- self.watchStreamFailures = 0;
- [self updateAndNotifyAboutOnlineState:FSTOnlineStateUnknown];
+/**
+ * Updates our OnlineState to the new state, updating local state and notifying the
+ * onlineStateHandler as appropriate.
+ */
+- (void)updateOnlineState:(FSTOnlineState)newState {
+ // Update and broadcast the new state.
+ if (newState != self.watchStreamOnlineState) {
+ if (newState == FSTOnlineStateHealthy) {
+ // We've connected to watch at least once. Don't warn the developer about being offline going
+ // forward.
+ self.shouldWarnOffline = NO;
+ } else if (newState == FSTOnlineStateUnknown) {
+ // The state is set to unknown when a healthy stream is closed (e.g. due to a token timeout)
+ // or when we have no active listens and therefore there's no need to start the stream.
+ // Assuming there is (possibly in the future) an active listen, then we will eventually move
+ // to state Online or Failed, but we always want to make at least kOnlineAttemptsBeforeFailure
+ // attempts before failing, so we reset the count here.
+ self.watchStreamFailures = 0;
+ }
+ self.watchStreamOnlineState = newState;
+ [self.onlineStateDelegate applyChangedOnlineState:newState];
+ }
}
+/**
+ * Updates our FSTOnlineState as appropriate after the watch stream reports a failure. The first
+ * failure moves us to the 'Unknown' state. We then may allow multiple failures (based on
+ * kOnlineAttemptsBeforeFailure) before we actually transition to FSTOnlineStateFailed.
+ */
- (void)updateOnlineStateAfterFailure {
- // The first failure after we are successfully connected moves us to the 'Unknown' state. We
- // then may make multiple attempts (based on kOnlineAttemptsBeforeFailure) before we actually
- // report failure.
if (self.watchStreamOnlineState == FSTOnlineStateHealthy) {
- [self setOnlineStateToUnknown];
+ [self updateOnlineState:FSTOnlineStateUnknown];
} else {
self.watchStreamFailures++;
if (self.watchStreamFailures >= kOnlineAttemptsBeforeFailure) {
@@ -188,19 +201,11 @@ static const int kOnlineAttemptsBeforeFailure = 2;
FSTWarn(@"Could not reach Firestore backend.");
self.shouldWarnOffline = NO;
}
- [self updateAndNotifyAboutOnlineState:FSTOnlineStateFailed];
+ [self updateOnlineState:FSTOnlineStateFailed];
}
}
}
-- (void)updateAndNotifyAboutOnlineState:(FSTOnlineState)watchStreamOnlineState {
- BOOL didChange = (watchStreamOnlineState != self.watchStreamOnlineState);
- self.watchStreamOnlineState = watchStreamOnlineState;
- if (didChange) {
- [self.onlineStateDelegate watchStreamDidChangeOnlineState:watchStreamOnlineState];
- }
-}
-
#pragma mark Online/Offline state
- (BOOL)isNetworkEnabled {
@@ -210,8 +215,9 @@ static const int kOnlineAttemptsBeforeFailure = 2;
}
- (void)enableNetwork {
- FSTAssert(self.watchStream == nil, @"enableNetwork: called with non-null watchStream.");
- FSTAssert(self.writeStream == nil, @"enableNetwork: called with non-null writeStream.");
+ if ([self isNetworkEnabled]) {
+ return;
+ }
// Create new streams (but note they're not started yet).
self.watchStream = [self.datastore createWatchStream];
@@ -227,47 +233,51 @@ static const int kOnlineAttemptsBeforeFailure = 2;
[self fillWritePipeline]; // This may start the writeStream.
// We move back to the unknown state because we might not want to re-open the stream
- [self setOnlineStateToUnknown];
+ [self updateOnlineState:FSTOnlineStateUnknown];
}
- (void)disableNetwork {
- [self updateAndNotifyAboutOnlineState:FSTOnlineStateFailed];
+ [self disableNetworkInternal];
+ // Set the FSTOnlineState to failed so get()'s return from cache, etc.
+ [self updateOnlineState:FSTOnlineStateFailed];
+}
- // NOTE: We're guaranteed not to get any further events from these streams (not even a close
- // event).
- [self.watchStream stop];
- [self.writeStream stop];
+/** Disables the network, setting the FSTOnlineState to the specified targetOnlineState. */
+- (void)disableNetworkInternal {
+ if ([self isNetworkEnabled]) {
+ // NOTE: We're guaranteed not to get any further events from these streams (not even a close
+ // event).
+ [self.watchStream stop];
+ [self.writeStream stop];
- [self cleanUpWatchStreamState];
- [self cleanUpWriteStreamState];
+ [self cleanUpWatchStreamState];
+ [self cleanUpWriteStreamState];
- self.writeStream = nil;
- self.watchStream = nil;
+ self.writeStream = nil;
+ self.watchStream = nil;
+ }
}
#pragma mark Shutdown
- (void)shutdown {
FSTLog(@"FSTRemoteStore %p shutting down", (__bridge void *)self);
-
- // Don't fire initial listener callbacks on shutdown.
- self.onlineStateDelegate = nil;
-
- // For now, all shutdown logic is handled by disableNetwork(). We might expand on this in the
- // future.
- if ([self isNetworkEnabled]) {
- [self disableNetwork];
- }
+ [self disableNetworkInternal];
+ // Set the FSTOnlineState to Unknown (rather than Failed) to avoid potentially triggering
+ // spurious listener events with cached data, etc.
+ [self updateOnlineState:FSTOnlineStateUnknown];
}
- (void)userDidChange:(FSTUser *)user {
FSTLog(@"FSTRemoteStore %p changing users: %@", (__bridge void *)self, user);
-
- // Tear down and re-create our network streams. This will ensure we get a fresh auth token
- // for the new user and re-fill the write pipeline with new mutations from the LocalStore
- // (since mutations are per-user).
- [self disableNetwork];
- [self enableNetwork];
+ if ([self isNetworkEnabled]) {
+ // Tear down and re-create our network streams. This will ensure we get a fresh auth token
+ // for the new user and re-fill the write pipeline with new mutations from the LocalStore
+ // (since mutations are per-user).
+ [self disableNetworkInternal];
+ [self updateOnlineState:FSTOnlineStateUnknown];
+ [self enableNetwork];
+ }
}
#pragma mark Watch Stream
@@ -348,7 +358,7 @@ static const int kOnlineAttemptsBeforeFailure = 2;
- (void)watchStreamDidChange:(FSTWatchChange *)change
snapshotVersion:(FSTSnapshotVersion *)snapshotVersion {
// Mark the connection as healthy because we got a message from the server.
- [self setOnlineStateToHealthy];
+ [self updateOnlineState:FSTOnlineStateHealthy];
FSTWatchTargetChange *watchTargetChange =
[change isKindOfClass:[FSTWatchTargetChange class]] ? (FSTWatchTargetChange *)change : nil;
@@ -391,7 +401,7 @@ static const int kOnlineAttemptsBeforeFailure = 2;
} else {
// We don't need to restart the watch stream because there are no active targets. The online
// state is set to unknown because there is no active attempt at establishing a connection.
- [self setOnlineStateToUnknown];
+ [self updateOnlineState:FSTOnlineStateUnknown];
}
}
@@ -460,8 +470,10 @@ static const int kOnlineAttemptsBeforeFailure = 2;
[remoteEvent handleExistenceFilterMismatchForTargetID:target];
// Clear the resume token for the query, since we're in a known mismatch state.
- queryData =
- [[FSTQueryData alloc] initWithQuery:query targetID:targetID purpose:queryData.purpose];
+ queryData = [[FSTQueryData alloc] initWithQuery:query
+ targetID:targetID
+ listenSequenceNumber:queryData.sequenceNumber
+ purpose:queryData.purpose];
self.listenTargets[target] = queryData;
// Cause a hard reset by unwatching and rewatching immediately, but deliberately don't
@@ -475,6 +487,7 @@ static const int kOnlineAttemptsBeforeFailure = 2;
FSTQueryData *requestQueryData =
[[FSTQueryData alloc] initWithQuery:query
targetID:targetID
+ listenSequenceNumber:queryData.sequenceNumber
purpose:FSTQueryPurposeExistenceFilterMismatch];
[self sendWatchRequestWithQueryData:requestQueryData];
}
@@ -532,6 +545,8 @@ static const int kOnlineAttemptsBeforeFailure = 2;
- (void)cleanUpWriteStreamState {
self.lastBatchSeen = kFSTBatchIDUnknown;
+ FSTLog(@"Stopping write stream with %lu pending writes",
+ (unsigned long)[self.pendingWrites count]);
[self.pendingWrites removeAllObjects];
}
diff --git a/Firestore/Source/Remote/FSTSerializerBeta.m b/Firestore/Source/Remote/FSTSerializerBeta.mm
index 04785c2..cf200ca 100644
--- a/Firestore/Source/Remote/FSTSerializerBeta.m
+++ b/Firestore/Source/Remote/FSTSerializerBeta.mm
@@ -16,6 +16,8 @@
#import "Firestore/Source/Remote/FSTSerializerBeta.h"
+#include <inttypes.h>
+
#import <GRPCClient/GRPCCall.h>
#import "Firestore/Protos/objc/google/firestore/v1beta1/Common.pbobjc.h"
@@ -161,41 +163,41 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - FSTFieldValue <=> Value proto
- (GCFSValue *)encodedFieldValue:(FSTFieldValue *)fieldValue {
- Class class = [fieldValue class];
- if (class == [FSTNullValue class]) {
+ Class fieldClass = [fieldValue class];
+ if (fieldClass == [FSTNullValue class]) {
return [self encodedNull];
- } else if (class == [FSTBooleanValue class]) {
+ } else if (fieldClass == [FSTBooleanValue class]) {
return [self encodedBool:[[fieldValue value] boolValue]];
- } else if (class == [FSTIntegerValue class]) {
+ } else if (fieldClass == [FSTIntegerValue class]) {
return [self encodedInteger:[[fieldValue value] longLongValue]];
- } else if (class == [FSTDoubleValue class]) {
+ } else if (fieldClass == [FSTDoubleValue class]) {
return [self encodedDouble:[[fieldValue value] doubleValue]];
- } else if (class == [FSTStringValue class]) {
+ } else if (fieldClass == [FSTStringValue class]) {
return [self encodedString:[fieldValue value]];
- } else if (class == [FSTTimestampValue class]) {
+ } else if (fieldClass == [FSTTimestampValue class]) {
return [self encodedTimestampValue:((FSTTimestampValue *)fieldValue).internalValue];
- } else if (class == [FSTGeoPointValue class]) {
+ } else if (fieldClass == [FSTGeoPointValue class]) {
return [self encodedGeoPointValue:[fieldValue value]];
- } else if (class == [FSTBlobValue class]) {
+ } else if (fieldClass == [FSTBlobValue class]) {
return [self encodedBlobValue:[fieldValue value]];
- } else if (class == [FSTReferenceValue class]) {
+ } else if (fieldClass == [FSTReferenceValue class]) {
FSTReferenceValue *ref = (FSTReferenceValue *)fieldValue;
return [self encodedReferenceValueForDatabaseID:[ref databaseID] key:[ref value]];
- } else if (class == [FSTObjectValue class]) {
+ } else if (fieldClass == [FSTObjectValue class]) {
GCFSValue *result = [GCFSValue message];
result.mapValue = [self encodedMapValue:(FSTObjectValue *)fieldValue];
return result;
- } else if (class == [FSTArrayValue class]) {
+ } else if (fieldClass == [FSTArrayValue class]) {
GCFSValue *result = [GCFSValue message];
result.arrayValue = [self encodedArrayValue:(FSTArrayValue *)fieldValue];
return result;
@@ -438,8 +440,8 @@ NS_ASSUME_NONNULL_BEGIN
proto.currentDocument.exists = YES;
} else if (mutationClass == [FSTDeleteMutation class]) {
- FSTDeleteMutation *delete = (FSTDeleteMutation *)mutation;
- proto.delete_p = [self encodedDocumentKey:delete.key];
+ FSTDeleteMutation *deleteMutation = (FSTDeleteMutation *)mutation;
+ proto.delete_p = [self encodedDocumentKey:deleteMutation.key];
} else {
FSTFail(@"Unknown mutation type %@", NSStringFromClass(mutationClass));
diff --git a/Firestore/Source/Remote/FSTStream.m b/Firestore/Source/Remote/FSTStream.mm
index 2c039be..dc7d01e 100644
--- a/Firestore/Source/Remote/FSTStream.m
+++ b/Firestore/Source/Remote/FSTStream.mm
@@ -343,9 +343,6 @@ static const NSTimeInterval kIdleTimeout = 60.0;
- (void)closeWithFinalState:(FSTStreamState)finalState error:(nullable NSError *)error {
FSTAssert(finalState == FSTStreamStateError || error == nil,
@"Can't provide an error when not in an error state.");
- FSTAssert(self.delegate,
- @"closeWithFinalState should only be called for a started stream that has an active "
- @"delegate.");
[self.workerDispatchQueue verifyIsCurrentQueue];
[self cancelIdleCheck];
@@ -542,7 +539,7 @@ static const NSTimeInterval kIdleTimeout = 60.0;
FSTWeakify(self);
[self.workerDispatchQueue dispatchAsync:^{
FSTStrongify(self);
- if (!self || ![self isStarted]) {
+ if (![self isStarted]) {
FSTLog(@"%@ Ignoring stream message from inactive stream.", NSStringFromClass([self class]));
}
diff --git a/Firestore/Source/Remote/FSTWatchChange.m b/Firestore/Source/Remote/FSTWatchChange.mm
index 926d027..926d027 100644
--- a/Firestore/Source/Remote/FSTWatchChange.m
+++ b/Firestore/Source/Remote/FSTWatchChange.mm
diff --git a/Firestore/Source/Util/FSTAsyncQueryListener.m b/Firestore/Source/Util/FSTAsyncQueryListener.mm
index d98e2dd..d98e2dd 100644
--- a/Firestore/Source/Util/FSTAsyncQueryListener.m
+++ b/Firestore/Source/Util/FSTAsyncQueryListener.mm
diff --git a/Firestore/Source/Util/FSTComparison.h b/Firestore/Source/Util/FSTComparison.h
deleted file mode 100644
index e6e57e6..0000000
--- a/Firestore/Source/Util/FSTComparison.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2017 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 <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-/** Compares two NSStrings. */
-NSComparisonResult FSTCompareStrings(NSString *left, NSString *right);
-
-/** Compares two BOOLs. */
-NSComparisonResult FSTCompareBools(BOOL left, BOOL right);
-
-/** Compares two integers. */
-NSComparisonResult FSTCompareInts(int left, int right);
-
-/** Compares two int32_t. */
-NSComparisonResult FSTCompareInt32s(int32_t left, int32_t right);
-
-/** Compares two int64_t. */
-NSComparisonResult FSTCompareInt64s(int64_t left, int64_t right);
-
-/** Compares two NSUIntegers. */
-NSComparisonResult FSTCompareUIntegers(NSUInteger left, NSUInteger right);
-
-/** Compares two doubles (using Firestore semantics for NaN). */
-NSComparisonResult FSTCompareDoubles(double left, double right);
-
-/** Compares a double and an int64_t. */
-NSComparisonResult FSTCompareMixed(double doubleValue, int64_t longValue);
-
-/** Compare two NSData byte sequences. */
-NSComparisonResult FSTCompareBytes(NSData *left, NSData *right);
-
-/** A simple NSComparator for comparing NSNumber instances. */
-extern const NSComparator FSTNumberComparator;
-
-/** A simple NSComparator for comparing NSString instances. */
-extern const NSComparator FSTStringComparator;
-
-/**
- * Compares the bitwise representation of two doubles, but normalizes NaN values. This is
- * similar to what the backend and android clients do, including comparing -0.0 as not equal to 0.0.
- */
-BOOL FSTDoubleBitwiseEquals(double left, double right);
-
-/**
- * Computes a bitwise hash of a double, but normalizes NaN values, suitable for use when using
- * FSTDoublesAreBitwiseEqual for equality.
- */
-NSUInteger FSTDoubleBitwiseHash(double d);
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTComparison.m b/Firestore/Source/Util/FSTComparison.m
deleted file mode 100644
index 9c5c3eb..0000000
--- a/Firestore/Source/Util/FSTComparison.m
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2017 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 "Firestore/Source/Util/FSTComparison.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-union DoubleBits {
- double d;
- uint64_t bits;
-};
-
-const NSComparator FSTNumberComparator = ^NSComparisonResult(NSNumber *left, NSNumber *right) {
- return [left compare:right];
-};
-
-const NSComparator FSTStringComparator = ^NSComparisonResult(NSString *left, NSString *right) {
- return FSTCompareStrings(left, right);
-};
-
-NSComparisonResult FSTCompareStrings(NSString *left, NSString *right) {
- // NOTE: NSLiteralSearch is necessary to compare the raw character codes. By default,
- // precomposed characters are considered equivalent to their decomposed equivalents.
- return [left compare:right options:NSLiteralSearch];
-}
-
-NSComparisonResult FSTCompareBools(BOOL left, BOOL right) {
- if (!left) {
- return right ? NSOrderedAscending : NSOrderedSame;
- } else {
- return right ? NSOrderedSame : NSOrderedDescending;
- }
-}
-
-NSComparisonResult FSTCompareInts(int left, int right) {
- if (left > right) {
- return NSOrderedDescending;
- }
- if (right > left) {
- return NSOrderedAscending;
- }
- return NSOrderedSame;
-}
-
-NSComparisonResult FSTCompareInt32s(int32_t left, int32_t right) {
- if (left > right) {
- return NSOrderedDescending;
- }
- if (right > left) {
- return NSOrderedAscending;
- }
- return NSOrderedSame;
-}
-
-NSComparisonResult FSTCompareInt64s(int64_t left, int64_t right) {
- if (left > right) {
- return NSOrderedDescending;
- }
- if (right > left) {
- return NSOrderedAscending;
- }
- return NSOrderedSame;
-}
-
-NSComparisonResult FSTCompareUIntegers(NSUInteger left, NSUInteger right) {
- if (left > right) {
- return NSOrderedDescending;
- }
- if (right > left) {
- return NSOrderedAscending;
- }
- return NSOrderedSame;
-}
-
-NSComparisonResult FSTCompareDoubles(double left, double right) {
- // NaN sorts equal to itself and before any other number.
- if (left < right) {
- return NSOrderedAscending;
- } else if (left > right) {
- return NSOrderedDescending;
- } else if (left == right) {
- return NSOrderedSame;
- } else {
- // One or both left and right is NaN.
- if (isnan(left)) {
- return isnan(right) ? NSOrderedSame : NSOrderedAscending;
- } else {
- return NSOrderedDescending;
- }
- }
-}
-
-static const double LONG_MIN_VALUE_AS_DOUBLE = (double)LLONG_MIN;
-static const double LONG_MAX_VALUE_AS_DOUBLE = (double)LLONG_MAX;
-
-NSComparisonResult FSTCompareMixed(double doubleValue, int64_t longValue) {
- // LLONG_MIN has an exact representation as double, so to check for a value outside the range
- // representable by long, we have to check for strictly less than LLONG_MIN. Note that this also
- // handles negative infinity.
- if (doubleValue < LONG_MIN_VALUE_AS_DOUBLE) {
- return NSOrderedAscending;
- }
-
- // LLONG_MAX has no exact representation as double (casting as we've done makes 2^63, which is
- // larger than LLONG_MAX), so consider any value greater than or equal to the threshold to be out
- // of range. This also handles positive infinity.
- if (doubleValue >= LONG_MAX_VALUE_AS_DOUBLE) {
- return NSOrderedDescending;
- }
-
- // In Firestore NaN is defined to compare before all other numbers.
- if (isnan(doubleValue)) {
- return NSOrderedAscending;
- }
-
- int64_t doubleAsLong = (int64_t)doubleValue;
- NSComparisonResult cmp = FSTCompareInt64s(doubleAsLong, longValue);
- if (cmp != NSOrderedSame) {
- return cmp;
- }
-
- // At this point the long representations are equal but this could be due to rounding.
- double longAsDouble = (double)longValue;
- return FSTCompareDoubles(doubleValue, longAsDouble);
-}
-
-NSComparisonResult FSTCompareBytes(NSData *left, NSData *right) {
- NSUInteger minLength = MIN(left.length, right.length);
- int result = memcmp(left.bytes, right.bytes, minLength);
- if (result < 0) {
- return NSOrderedAscending;
- } else if (result > 0) {
- return NSOrderedDescending;
- } else if (left.length < right.length) {
- return NSOrderedAscending;
- } else if (left.length > right.length) {
- return NSOrderedDescending;
- } else {
- return NSOrderedSame;
- }
-}
-
-/** Helper to normalize a double and then return the raw bits as a uint64_t. */
-uint64_t FSTDoubleBits(double d) {
- if (isnan(d)) {
- d = NAN;
- }
- union DoubleBits converter = {.d = d};
- return converter.bits;
-}
-
-BOOL FSTDoubleBitwiseEquals(double left, double right) {
- return FSTDoubleBits(left) == FSTDoubleBits(right);
-}
-
-NSUInteger FSTDoubleBitwiseHash(double d) {
- uint64_t bits = FSTDoubleBits(d);
- // Note that x ^ (x >> 32) works fine for both 32 and 64 bit definitions of NSUInteger
- return (((NSUInteger)bits) ^ (NSUInteger)(bits >> 32));
-}
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTDispatchQueue.m b/Firestore/Source/Util/FSTDispatchQueue.mm
index 6ce5d74..6ce5d74 100644
--- a/Firestore/Source/Util/FSTDispatchQueue.m
+++ b/Firestore/Source/Util/FSTDispatchQueue.mm
diff --git a/Firestore/Source/Util/FSTLogger.h b/Firestore/Source/Util/FSTLogger.h
index 699570a..c4e2b85 100644
--- a/Firestore/Source/Util/FSTLogger.h
+++ b/Firestore/Source/Util/FSTLogger.h
@@ -18,17 +18,9 @@
NS_ASSUME_NONNULL_BEGIN
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/** Logs to NSLog if [FIRFirestore isLoggingEnabled] is YES. */
void FSTLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
void FSTWarn(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTLogger.m b/Firestore/Source/Util/FSTLogger.mm
index f0081e0..f0081e0 100644
--- a/Firestore/Source/Util/FSTLogger.m
+++ b/Firestore/Source/Util/FSTLogger.mm
diff --git a/Firestore/Source/Util/FSTUsageValidation.h b/Firestore/Source/Util/FSTUsageValidation.h
index 34a3d64..a80dafa 100644
--- a/Firestore/Source/Util/FSTUsageValidation.h
+++ b/Firestore/Source/Util/FSTUsageValidation.h
@@ -18,10 +18,6 @@
NS_ASSUME_NONNULL_BEGIN
-#if __cplusplus
-extern "C" {
-#endif
-
/** Helper for creating a general exception for invalid usage of an API. */
NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...);
@@ -46,8 +42,4 @@ NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...);
@throw FSTInvalidUsage(@"FIRInvalidArgumentException", format, ##__VA_ARGS__); \
} while (0)
-#if __cplusplus
-} // extern "C"
-#endif
-
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTUsageValidation.m b/Firestore/Source/Util/FSTUsageValidation.mm
index 82128f4..82128f4 100644
--- a/Firestore/Source/Util/FSTUsageValidation.m
+++ b/Firestore/Source/Util/FSTUsageValidation.mm
diff --git a/Firestore/core/CMakeLists.txt b/Firestore/core/CMakeLists.txt
index c49b6db..2fc88c6 100644
--- a/Firestore/core/CMakeLists.txt
+++ b/Firestore/core/CMakeLists.txt
@@ -12,5 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+add_subdirectory(src/firebase/firestore)
+add_subdirectory(src/firebase/firestore/core)
+add_subdirectory(src/firebase/firestore/immutable)
+add_subdirectory(src/firebase/firestore/model)
+add_subdirectory(src/firebase/firestore/remote)
add_subdirectory(src/firebase/firestore/util)
+
+add_subdirectory(test/firebase/firestore)
+add_subdirectory(test/firebase/firestore/core)
+add_subdirectory(test/firebase/firestore/immutable)
+add_subdirectory(test/firebase/firestore/model)
+add_subdirectory(test/firebase/firestore/remote)
add_subdirectory(test/firebase/firestore/util)
diff --git a/Firestore/core/include/firebase/firestore/geo_point.h b/Firestore/core/include/firebase/firestore/geo_point.h
new file mode 100644
index 0000000..cc366be
--- /dev/null
+++ b/Firestore/core/include/firebase/firestore/geo_point.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_
+#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_
+
+namespace firebase {
+namespace firestore {
+
+/**
+ * An immutable object representing a geographical point in Firestore. The point
+ * is represented as a latitude/longitude pair.
+ *
+ * Latitude values are in the range of [-90, 90].
+ * Longitude values are in the range of [-180, 180].
+ */
+class GeoPoint {
+ public:
+ /**
+ * Creates a `GeoPoint` with both latitude and longitude being 0.
+ */
+ GeoPoint();
+
+ /**
+ * Creates a `GeoPoint` from the provided latitude and longitude degrees.
+ *
+ * @param latitude The latitude as number between -90 and 90.
+ * @param longitude The longitude as number between -180 and 180.
+ */
+ GeoPoint(double latitude, double longitude);
+
+ GeoPoint(const GeoPoint& other) = default;
+ GeoPoint(GeoPoint&& other) = default;
+ GeoPoint& operator=(const GeoPoint& other) = default;
+ GeoPoint& operator=(GeoPoint&& other) = default;
+
+ double latitude() const {
+ return latitude_;
+ }
+
+ double longitude() const {
+ return longitude_;
+ }
+
+ private:
+ double latitude_;
+ double longitude_;
+};
+
+/** Compares against another GeoPoint. */
+bool operator<(const GeoPoint& lhs, const GeoPoint& rhs);
+
+inline bool operator>(const GeoPoint& lhs, const GeoPoint& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator>=(const GeoPoint& lhs, const GeoPoint& rhs) {
+ return !(lhs < rhs);
+}
+
+inline bool operator<=(const GeoPoint& lhs, const GeoPoint& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator!=(const GeoPoint& lhs, const GeoPoint& rhs) {
+ return lhs < rhs || lhs > rhs;
+}
+
+inline bool operator==(const GeoPoint& lhs, const GeoPoint& rhs) {
+ return !(lhs != rhs);
+}
+
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_
diff --git a/Firestore/core/src/firebase/firestore/CMakeLists.txt b/Firestore/core/src/firebase/firestore/CMakeLists.txt
new file mode 100644
index 0000000..3f5522c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright 2018 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.
+
+# Public types to be used both internally and externally.
+cc_library(
+ firebase_firestore_types
+ SOURCES
+ geo_point.cc
+ DEPENDS
+ firebase_firestore_util
+)
diff --git a/Firestore/core/src/firebase/firestore/core/CMakeLists.txt b/Firestore/core/src/firebase/firestore/core/CMakeLists.txt
new file mode 100644
index 0000000..a62985c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/core/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright 2018 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.
+
+cc_library(
+ firebase_firestore_core
+ SOURCES
+ target_id_generator.cc
+ target_id_generator.h
+)
diff --git a/Firestore/core/src/firebase/firestore/core/target_id_generator.cc b/Firestore/core/src/firebase/firestore/core/target_id_generator.cc
new file mode 100644
index 0000000..6d23d64
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/core/target_id_generator.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h"
+
+namespace firebase {
+namespace firestore {
+namespace core {
+
+TargetIdGenerator::TargetIdGenerator(const TargetIdGenerator& value)
+ : generator_id_(value.generator_id_), previous_id_(value.previous_id_) {
+}
+
+TargetIdGenerator::TargetIdGenerator(TargetIdGeneratorId generator_id,
+ TargetId after)
+ : generator_id_(generator_id) {
+ const TargetId after_without_generator = (after >> kReservedBits)
+ << kReservedBits;
+ const TargetId after_generator = after - after_without_generator;
+ const TargetId generator = static_cast<TargetId>(generator_id);
+ if (after_generator >= generator) {
+ // For example, if:
+ // self.generatorID = 0b0000
+ // after = 0b1011
+ // afterGenerator = 0b0001
+ // Then:
+ // previous = 0b1010
+ // next = 0b1100
+ previous_id_ = after_without_generator | generator;
+ } else {
+ // For example, if:
+ // self.generatorID = 0b0001
+ // after = 0b1010
+ // afterGenerator = 0b0000
+ // Then:
+ // previous = 0b1001
+ // next = 0b1011
+ previous_id_ = (after_without_generator | generator) - (1 << kReservedBits);
+ }
+}
+
+TargetId TargetIdGenerator::NextId() {
+ previous_id_ += 1 << kReservedBits;
+ return previous_id_;
+}
+
+} // namespace core
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/core/target_id_generator.h b/Firestore/core/src/firebase/firestore/core/target_id_generator.h
new file mode 100644
index 0000000..7d30cf9
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/core/target_id_generator.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TARGET_ID_GENERATOR_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TARGET_ID_GENERATOR_H_
+
+#include "Firestore/core/src/firebase/firestore/core/types.h"
+
+namespace firebase {
+namespace firestore {
+namespace core {
+
+/** The set of all valid generators. */
+enum class TargetIdGeneratorId { LocalStore = 0, SyncEngine = 1 };
+
+/**
+ * Generates monotonically increasing integer IDs. There are separate generators
+ * for different scopes. While these generators will operate independently of
+ * each other, they are scoped, such that no two generators will ever produce
+ * the same ID. This is useful, because sometimes the backend may group IDs from
+ * separate parts of the client into the same ID space.
+ *
+ * Not thread-safe.
+ */
+class TargetIdGenerator {
+ public:
+ // Makes Objective-C++ code happy to provide a default ctor.
+ TargetIdGenerator() = default;
+
+ TargetIdGenerator(const TargetIdGenerator& value);
+
+ /**
+ * Creates and returns the TargetIdGenerator for the local store.
+ *
+ * @param after An ID to start at. Every call to NextId returns a larger id.
+ * @return An instance of TargetIdGenerator.
+ */
+ static TargetIdGenerator LocalStoreTargetIdGenerator(TargetId after) {
+ return TargetIdGenerator(TargetIdGeneratorId::LocalStore, after);
+ }
+
+ /**
+ * Creates and returns the TargetIdGenerator for the sync engine.
+ *
+ * @param after An ID to start at. Every call to NextId returns a larger id.
+ * @return An instance of TargetIdGenerator.
+ */
+ static TargetIdGenerator SyncEngineTargetIdGenerator(TargetId after) {
+ return TargetIdGenerator(TargetIdGeneratorId::SyncEngine, after);
+ }
+
+ TargetIdGeneratorId generator_id() {
+ return generator_id_;
+ }
+
+ TargetId NextId();
+
+ private:
+ TargetIdGenerator(TargetIdGeneratorId generator_id, TargetId after);
+ TargetIdGeneratorId generator_id_;
+ TargetId previous_id_;
+
+ static const int kReservedBits = 1;
+};
+
+} // namespace core
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TARGET_ID_GENERATOR_H_
diff --git a/Firestore/core/src/firebase/firestore/core/types.h b/Firestore/core/src/firebase/firestore/core/types.h
new file mode 100644
index 0000000..65c2b8c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/core/types.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TYPES_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TYPES_H_
+
+#include <stdint.h>
+
+namespace firebase {
+namespace firestore {
+namespace core {
+
+typedef int32_t TargetId;
+
+} // namespace core
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TYPES_H_
diff --git a/Firestore/core/src/firebase/firestore/geo_point.cc b/Firestore/core/src/firebase/firestore/geo_point.cc
new file mode 100644
index 0000000..fb01023
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/geo_point.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/include/firebase/firestore/geo_point.h"
+
+#include <math.h>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+namespace firestore {
+
+GeoPoint::GeoPoint() : GeoPoint(0, 0) {
+}
+
+GeoPoint::GeoPoint(double latitude, double longitude)
+ : latitude_(latitude), longitude_(longitude) {
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ !isnan(latitude) && -90 <= latitude && latitude <= 90,
+ -90 <= latitude && latitude <= 90,
+ "Latitude must be in the range of [-90, 90]");
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ !isnan(longitude) && -180 <= longitude && longitude <= 180,
+ -180 <= longitude && longitude <= 180,
+ "Latitude must be in the range of [-180, 180]");
+}
+
+bool operator<(const GeoPoint& lhs, const GeoPoint& rhs) {
+ if (lhs.latitude() == rhs.latitude()) {
+ return lhs.longitude() < rhs.longitude();
+ } else {
+ return lhs.latitude() < rhs.latitude();
+ }
+}
+
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt b/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt
new file mode 100644
index 0000000..e8a95cd
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/immutable/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright 2018 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.
+
+cc_library(
+ firebase_firestore_immutable
+ SOURCES
+ array_sorted_map.cc
+ array_sorted_map.h
+ map_entry.h
+)
diff --git a/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.cc b/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.cc
new file mode 100644
index 0000000..48e7553
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h"
+
+namespace firebase {
+namespace firestore {
+namespace immutable {
+namespace impl {
+
+// Define external storage for constants:
+constexpr ArraySortedMapBase::size_type ArraySortedMapBase::kFixedSize;
+
+} // namespace impl
+} // namespace immutable
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h b/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h
new file mode 100644
index 0000000..d0210a8
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_ARRAY_SORTED_MAP_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_ARRAY_SORTED_MAP_H_
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <memory>
+#include <utility>
+
+#include "Firestore/core/src/firebase/firestore/immutable/map_entry.h"
+
+namespace firebase {
+namespace firestore {
+namespace immutable {
+
+namespace impl {
+
+/**
+ * A base class for implementing ArraySortedMap, containing types and constants
+ * that don't depend upon the template parameters to the main class.
+ *
+ * Note that this exists as a base class rather than as just a namespace in
+ * order to make it possible for users of ArraySortedMap to avoid needing to
+ * declare storage for each instantiation of the template.
+ */
+class ArraySortedMapBase {
+ public:
+ /**
+ * The type of size() methods on immutable collections. Note that this is not
+ * size_t specifically to save space in the TreeSortedMap implementation.
+ */
+ using size_type = uint32_t;
+
+ /**
+ * The maximum size of an ArraySortedMap.
+ *
+ * This is the size threshold where we use a tree backed sorted map instead of
+ * an array backed sorted map. This is a more or less arbitrary chosen value,
+ * that was chosen to be large enough to fit most of object kind of Firebase
+ * data, but small enough to not notice degradation in performance for
+ * inserting and lookups. Feel free to empirically determine this constant,
+ * but don't expect much gain in real world performance.
+ */
+ // TODO(wilhuff): actually use this for switching implementations.
+ static constexpr size_type kFixedSize = 25;
+};
+
+/**
+ * A bounded-size array that allocates its contents directly in itself. This
+ * saves a heap allocation when compared with std::vector (though std::vector
+ * can resize itself while FixedArray cannot).
+ *
+ * Unlike std::array, FixedArray keeps track of its size and grows up to the
+ * fixed_size limit. Inserting more elements than fixed_size will trigger an
+ * assertion failure.
+ *
+ * ArraySortedMap does not actually contain its array: it contains a shared_ptr
+ * to a FixedArray.
+ *
+ * @tparam T The type of an element in the array.
+ * @tparam fixed_size the fixed size to use in creating the FixedArray.
+ */
+template <typename T, ArraySortedMapBase::size_type fixed_size>
+class FixedArray {
+ public:
+ using size_type = ArraySortedMapBase::size_type;
+ using array_type = std::array<T, fixed_size>;
+ using iterator = typename array_type::iterator;
+ using const_iterator = typename array_type::const_iterator;
+
+ FixedArray() {
+ }
+
+ template <typename SourceIterator>
+ FixedArray(SourceIterator src_begin, SourceIterator src_end) {
+ append(src_begin, src_end);
+ }
+
+ /**
+ * Appends to this array, copying from the given src_begin up to but not
+ * including the src_end.
+ */
+ template <typename SourceIterator>
+ void append(SourceIterator src_begin, SourceIterator src_end) {
+ size_type appending = static_cast<size_type>(src_end - src_begin);
+ size_type new_size = size_ + appending;
+ assert(new_size <= fixed_size);
+
+ std::copy(src_begin, src_end, end());
+ size_ = new_size;
+ }
+
+ /**
+ * Appends a single value to the array.
+ */
+ void append(T&& value) {
+ size_type new_size = size_ + 1;
+ assert(new_size <= fixed_size);
+
+ *end() = std::move(value);
+ size_ = new_size;
+ }
+
+ const_iterator begin() const {
+ return contents_.begin();
+ }
+
+ const_iterator end() const {
+ return begin() + size_;
+ }
+
+ size_type size() const {
+ return size_;
+ }
+
+ private:
+ iterator begin() {
+ return contents_.begin();
+ }
+
+ iterator end() {
+ return begin() + size_;
+ }
+
+ array_type contents_;
+ size_type size_ = 0;
+};
+
+} // namespace impl
+
+/**
+ * ArraySortedMap is a value type containing a map. It is immutable, but has
+ * methods to efficiently create new maps that are mutations of it.
+ */
+template <typename K, typename V, typename C = std::less<K>>
+class ArraySortedMap : public impl::ArraySortedMapBase {
+ public:
+ using key_comparator_type = KeyComparator<K, V, C>;
+
+ /**
+ * The type of the entries stored in the map.
+ */
+ using value_type = std::pair<K, V>;
+
+ /**
+ * The type of the fixed-size array containing entries of value_type.
+ */
+ using array_type = impl::FixedArray<value_type, kFixedSize>;
+ using const_iterator = typename array_type::const_iterator;
+
+ using array_pointer = std::shared_ptr<const array_type>;
+
+ /**
+ * Creates an empty ArraySortedMap.
+ */
+ explicit ArraySortedMap(const C& comparator = C())
+ : array_(EmptyArray()), key_comparator_(comparator) {
+ }
+
+ /**
+ * Creates an ArraySortedMap containing the given entries.
+ */
+ ArraySortedMap(std::initializer_list<value_type> entries,
+ const C& comparator = C())
+ : array_(std::make_shared<array_type>(entries.begin(), entries.end())),
+ key_comparator_(comparator) {
+ }
+
+ /**
+ * Creates a new map identical to this one, but with a key-value pair added or
+ * updated.
+ *
+ * @param key The key to insert/update.
+ * @param value The value to associate with the key.
+ * @return A new dictionary with the added/updated value.
+ */
+ ArraySortedMap insert(const K& key, const V& value) const {
+ const_iterator current_end = end();
+ const_iterator pos = LowerBound(key);
+ bool replacing_entry = false;
+
+ if (pos != current_end) {
+ // LowerBound found an entry where pos->first >= pair.first. Reversing the
+ // argument order here tests pair.first < pos->first.
+ replacing_entry = !key_comparator_(key, *pos);
+ if (replacing_entry && value == pos->second) {
+ return *this;
+ }
+ }
+
+ // Copy the segment before the found position. If not found, this is
+ // everything.
+ auto copy = std::make_shared<array_type>(begin(), pos);
+
+ // Copy the value to be inserted.
+ copy->append(value_type(key, value));
+
+ if (replacing_entry) {
+ // Skip the thing at pos because it compares the same as the pair above.
+ copy->append(pos + 1, current_end);
+ } else {
+ copy->append(pos, current_end);
+ }
+ return wrap(copy);
+ }
+
+ /**
+ * Creates a new map identical to this one, but with a key removed from it.
+ *
+ * @param key The key to remove.
+ * @return A new dictionary without that value.
+ */
+ ArraySortedMap erase(const K& key) const {
+ const_iterator current_end = end();
+ const_iterator pos = find(key);
+ if (pos == current_end) {
+ return *this;
+ } else if (size() <= 1) {
+ // If the key was found and it's the last entry, removing it would make
+ // the result empty.
+ return wrap(EmptyArray());
+ } else {
+ auto copy = std::make_shared<array_type>(begin(), pos);
+ copy->append(pos + 1, current_end);
+ return wrap(copy);
+ }
+ }
+
+ /**
+ * Finds a value in the map.
+ *
+ * @param key The key to look up.
+ * @return An iterator pointing to the entry containing the key, or end() if
+ * not found.
+ */
+ const_iterator find(const K& key) const {
+ const_iterator not_found = end();
+ const_iterator lower_bound = LowerBound(key);
+ if (lower_bound != not_found && !key_comparator_(key, *lower_bound)) {
+ return lower_bound;
+ } else {
+ return not_found;
+ }
+ }
+
+ // TODO(wilhuff): indexof
+
+ /** Returns true if the map contains no elements. */
+ bool empty() const {
+ return size() == 0;
+ }
+
+ /** Returns the number of items in this map. */
+ size_type size() const {
+ return array_->size();
+ }
+
+ /**
+ * Returns an iterator pointing to the first entry in the map. If there are
+ * no entries in the map, begin() == end().
+ */
+ const_iterator begin() const {
+ return array_->begin();
+ }
+
+ /**
+ * Returns an iterator pointing past the last entry in the map.
+ */
+ const_iterator end() const {
+ return array_->end();
+ }
+
+ private:
+ static array_pointer EmptyArray() {
+ static const array_pointer kEmptyArray =
+ std::make_shared<const array_type>();
+ return kEmptyArray;
+ }
+
+ ArraySortedMap(const array_pointer& array,
+ const key_comparator_type& key_comparator) noexcept
+ : array_(array), key_comparator_(key_comparator) {
+ }
+
+ ArraySortedMap wrap(const array_pointer& array) const noexcept {
+ return ArraySortedMap(array, key_comparator_);
+ }
+
+ const_iterator LowerBound(const K& key) const {
+ return std::lower_bound(begin(), end(), key, key_comparator_);
+ }
+
+ array_pointer array_;
+ key_comparator_type key_comparator_;
+};
+
+} // namespace immutable
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_ARRAY_SORTED_MAP_H_
diff --git a/Firestore/core/src/firebase/firestore/immutable/map_entry.h b/Firestore/core/src/firebase/firestore/immutable/map_entry.h
new file mode 100644
index 0000000..2130b5b
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/immutable/map_entry.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_MAP_ENTRY_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_MAP_ENTRY_H_
+
+#include <functional>
+#include <utility>
+
+namespace firebase {
+namespace firestore {
+namespace immutable {
+
+/**
+ * Compares two keys out of a map entry.
+ *
+ * @tparam K The type of the first value in the pair.
+ * @tparam V The type of the second value in the pair.
+ * @tparam C The comparator for use for values of type K
+ */
+template <typename K, typename V, typename C = std::less<K>>
+struct KeyComparator {
+ typedef std::pair<K, V> pair_type;
+
+ explicit KeyComparator(const C& comparator = C())
+ : key_comparator_(comparator) {
+ }
+
+ bool operator()(const K& lhs, const pair_type& rhs) const noexcept {
+ return key_comparator_(lhs, rhs.first);
+ }
+
+ bool operator()(const pair_type& lhs, const K& rhs) const noexcept {
+ return key_comparator_(lhs.first, rhs);
+ }
+
+ bool operator()(const pair_type& lhs, const pair_type& rhs) const noexcept {
+ return key_comparator_(lhs.first, rhs.first);
+ }
+
+ private:
+ C key_comparator_;
+};
+
+} // namespace immutable
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_MAP_ENTRY_H_
diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
new file mode 100644
index 0000000..aee0d86
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright 2018 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.
+
+cc_library(
+ firebase_firestore_model
+ SOURCES
+ database_id.cc
+ database_id.h
+ field_value.cc
+ field_value.h
+ timestamp.cc
+ timestamp.h
+ DEPENDS
+ absl_strings
+ firebase_firestore_util
+ firebase_firestore_types
+)
diff --git a/Firestore/core/src/firebase/firestore/model/database_id.cc b/Firestore/core/src/firebase/firestore/model/database_id.cc
new file mode 100644
index 0000000..af12d30
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/database_id.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/database_id.h"
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+constexpr const char* DatabaseId::kDefaultDatabaseId;
+
+DatabaseId::DatabaseId(const absl::string_view project_id,
+ const absl::string_view database_id)
+ : project_id_(project_id), database_id_(database_id) {
+ FIREBASE_ASSERT(!project_id.empty());
+ FIREBASE_ASSERT(!database_id.empty());
+}
+
+bool DatabaseId::IsDefaultDatabase() {
+ return database_id_ == kDefaultDatabaseId;
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/model/database_id.h b/Firestore/core/src/firebase/firestore/model/database_id.h
new file mode 100644
index 0000000..48c547c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/database_id.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DATABASE_ID_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DATABASE_ID_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+/** A DatabaseId represents a particular database in the Firestore. */
+class DatabaseId {
+ public:
+ /** The default name for "unset" database ID in resource names. */
+ static constexpr const char* kDefaultDatabaseId = "(default)";
+
+ /**
+ * Creates and returns a new DatabaseId.
+ *
+ * @param project_id The project for the database.
+ * @param database_id The database in the project to use.
+ */
+ DatabaseId(const absl::string_view project_id,
+ const absl::string_view database_id);
+
+ const std::string& project_id() const {
+ return project_id_;
+ }
+
+ const std::string& database_id() const {
+ return database_id_;
+ }
+
+ /** Whether this is the default database of the project. */
+ bool IsDefaultDatabase();
+
+ friend bool operator<(const DatabaseId& lhs, const DatabaseId& rhs);
+
+ private:
+ const std::string project_id_;
+ const std::string database_id_;
+};
+
+/** Compares against another DatabaseId. */
+inline bool operator<(const DatabaseId& lhs, const DatabaseId& rhs) {
+ return lhs.project_id_ < rhs.project_id_ ||
+ (lhs.project_id_ == rhs.project_id_ &&
+ lhs.database_id_ < rhs.database_id_);
+}
+
+inline bool operator>(const DatabaseId& lhs, const DatabaseId& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator>=(const DatabaseId& lhs, const DatabaseId& rhs) {
+ return !(lhs < rhs);
+}
+
+inline bool operator<=(const DatabaseId& lhs, const DatabaseId& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator!=(const DatabaseId& lhs, const DatabaseId& rhs) {
+ return lhs < rhs || lhs > rhs;
+}
+
+inline bool operator==(const DatabaseId& lhs, const DatabaseId& rhs) {
+ return !(lhs != rhs);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DATABASE_ID_H_
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.cc b/Firestore/core/src/firebase/firestore/model/field_value.cc
new file mode 100644
index 0000000..570226e
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/field_value.cc
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/field_value.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "Firestore/core/src/firebase/firestore/util/comparison.h"
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+using firebase::firestore::util::Comparator;
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+using Type = FieldValue::Type;
+using firebase::firestore::util::ComparisonResult;
+
+namespace {
+/**
+ * This deviates from the other platforms that define TypeOrder. Since
+ * we already define Type for union types, we use it together with this
+ * function to achive the equivalent order of types i.e.
+ * i) if two types are comparable, then they are of equal order;
+ * ii) otherwise, their order is the same as the order of their Type.
+ */
+bool Comparable(Type lhs, Type rhs) {
+ switch (lhs) {
+ case Type::Long:
+ case Type::Double:
+ return rhs == Type::Long || rhs == Type::Double;
+ case Type::Timestamp:
+ case Type::ServerTimestamp:
+ return rhs == Type::Timestamp || rhs == Type::ServerTimestamp;
+ default:
+ return lhs == rhs;
+ }
+}
+
+} // namespace
+
+FieldValue::FieldValue(const FieldValue& value) {
+ *this = value;
+}
+
+FieldValue::FieldValue(FieldValue&& value) {
+ *this = std::move(value);
+}
+
+FieldValue::~FieldValue() {
+ SwitchTo(Type::Null);
+}
+
+FieldValue& FieldValue::operator=(const FieldValue& value) {
+ SwitchTo(value.tag_);
+ switch (tag_) {
+ case Type::Null:
+ break;
+ case Type::Boolean:
+ boolean_value_ = value.boolean_value_;
+ break;
+ case Type::Long:
+ integer_value_ = value.integer_value_;
+ break;
+ case Type::Double:
+ double_value_ = value.double_value_;
+ break;
+ case Type::Timestamp:
+ timestamp_value_ = value.timestamp_value_;
+ break;
+ case Type::ServerTimestamp:
+ server_timestamp_value_ = value.server_timestamp_value_;
+ break;
+ case Type::String:
+ string_value_ = value.string_value_;
+ break;
+ case Type::Blob: {
+ // copy-and-swap
+ std::vector<uint8_t> tmp = value.blob_value_;
+ std::swap(blob_value_, tmp);
+ break;
+ }
+ case Type::GeoPoint:
+ geo_point_value_ = value.geo_point_value_;
+ break;
+ case Type::Array: {
+ // copy-and-swap
+ std::vector<FieldValue> tmp = value.array_value_;
+ std::swap(array_value_, tmp);
+ break;
+ }
+ case Type::Object: {
+ // copy-and-swap
+ std::map<const std::string, const FieldValue> tmp = value.object_value_;
+ std::swap(object_value_, tmp);
+ break;
+ }
+ default:
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ false, lhs.type(), "Unsupported type %d", value.type());
+ }
+ return *this;
+}
+
+FieldValue& FieldValue::operator=(FieldValue&& value) {
+ switch (value.tag_) {
+ case Type::String:
+ SwitchTo(Type::String);
+ string_value_.swap(value.string_value_);
+ return *this;
+ case Type::Blob:
+ SwitchTo(Type::Blob);
+ std::swap(blob_value_, value.blob_value_);
+ return *this;
+ case Type::Array:
+ SwitchTo(Type::Array);
+ std::swap(array_value_, value.array_value_);
+ return *this;
+ case Type::Object:
+ SwitchTo(Type::Object);
+ std::swap(object_value_, value.object_value_);
+ return *this;
+ default:
+ // We just copy over POD union types.
+ return *this = value;
+ }
+}
+
+const FieldValue& FieldValue::NullValue() {
+ static const FieldValue kNullInstance;
+ return kNullInstance;
+}
+
+const FieldValue& FieldValue::TrueValue() {
+ static const FieldValue kTrueInstance(true);
+ return kTrueInstance;
+}
+
+const FieldValue& FieldValue::FalseValue() {
+ static const FieldValue kFalseInstance(false);
+ return kFalseInstance;
+}
+
+const FieldValue& FieldValue::BooleanValue(bool value) {
+ return value ? TrueValue() : FalseValue();
+}
+
+const FieldValue& FieldValue::NanValue() {
+ static const FieldValue kNanInstance = FieldValue::DoubleValue(NAN);
+ return kNanInstance;
+}
+
+FieldValue FieldValue::IntegerValue(int64_t value) {
+ FieldValue result;
+ result.SwitchTo(Type::Long);
+ result.integer_value_ = value;
+ return result;
+}
+
+FieldValue FieldValue::DoubleValue(double value) {
+ FieldValue result;
+ result.SwitchTo(Type::Double);
+ result.double_value_ = value;
+ return result;
+}
+
+FieldValue FieldValue::TimestampValue(const Timestamp& value) {
+ FieldValue result;
+ result.SwitchTo(Type::Timestamp);
+ result.timestamp_value_ = value;
+ return result;
+}
+
+FieldValue FieldValue::ServerTimestampValue(const Timestamp& local_write_time,
+ const Timestamp& previous_value) {
+ FieldValue result;
+ result.SwitchTo(Type::ServerTimestamp);
+ result.server_timestamp_value_.local_write_time = local_write_time;
+ result.server_timestamp_value_.previous_value = previous_value;
+ result.server_timestamp_value_.has_previous_value_ = true;
+ return result;
+}
+
+FieldValue FieldValue::ServerTimestampValue(const Timestamp& local_write_time) {
+ FieldValue result;
+ result.SwitchTo(Type::ServerTimestamp);
+ result.server_timestamp_value_.local_write_time = local_write_time;
+ result.server_timestamp_value_.has_previous_value_ = false;
+ return result;
+}
+
+FieldValue FieldValue::StringValue(const char* value) {
+ std::string copy(value);
+ return StringValue(std::move(copy));
+}
+
+FieldValue FieldValue::StringValue(const std::string& value) {
+ std::string copy(value);
+ return StringValue(std::move(copy));
+}
+
+FieldValue FieldValue::StringValue(std::string&& value) {
+ FieldValue result;
+ result.SwitchTo(Type::String);
+ result.string_value_.swap(value);
+ return result;
+}
+
+FieldValue FieldValue::BlobValue(const uint8_t* source, size_t size) {
+ FieldValue result;
+ result.SwitchTo(Type::Blob);
+ std::vector<uint8_t> copy(source, source + size);
+ std::swap(result.blob_value_, copy);
+ return result;
+}
+
+FieldValue FieldValue::GeoPointValue(const GeoPoint& value) {
+ FieldValue result;
+ result.SwitchTo(Type::GeoPoint);
+ result.geo_point_value_ = value;
+ return result;
+}
+
+FieldValue FieldValue::ArrayValue(const std::vector<FieldValue>& value) {
+ std::vector<FieldValue> copy(value);
+ return ArrayValue(std::move(copy));
+}
+
+FieldValue FieldValue::ArrayValue(std::vector<FieldValue>&& value) {
+ FieldValue result;
+ result.SwitchTo(Type::Array);
+ std::swap(result.array_value_, value);
+ return result;
+}
+
+FieldValue FieldValue::ObjectValue(
+ const std::map<const std::string, const FieldValue>& value) {
+ std::map<const std::string, const FieldValue> copy(value);
+ return ObjectValue(std::move(copy));
+}
+
+FieldValue FieldValue::ObjectValue(
+ std::map<const std::string, const FieldValue>&& value) {
+ FieldValue result;
+ result.SwitchTo(Type::Object);
+ std::swap(result.object_value_, value);
+ return result;
+}
+
+bool operator<(const FieldValue& lhs, const FieldValue& rhs) {
+ if (!Comparable(lhs.type(), rhs.type())) {
+ return lhs.type() < rhs.type();
+ }
+
+ switch (lhs.type()) {
+ case Type::Null:
+ return false;
+ case Type::Boolean:
+ return Comparator<bool>()(lhs.boolean_value_, rhs.boolean_value_);
+ case Type::Long:
+ if (rhs.type() == Type::Long) {
+ return Comparator<int64_t>()(lhs.integer_value_, rhs.integer_value_);
+ } else {
+ return util::CompareMixedNumber(rhs.double_value_,
+ lhs.integer_value_) ==
+ ComparisonResult::Descending;
+ }
+ case Type::Double:
+ if (rhs.type() == Type::Double) {
+ return Comparator<double>()(lhs.double_value_, rhs.double_value_);
+ } else {
+ return util::CompareMixedNumber(lhs.double_value_,
+ rhs.integer_value_) ==
+ ComparisonResult::Ascending;
+ }
+ case Type::Timestamp:
+ if (rhs.type() == Type::Timestamp) {
+ return lhs.timestamp_value_ < rhs.timestamp_value_;
+ } else {
+ return true;
+ }
+ case Type::ServerTimestamp:
+ if (rhs.type() == Type::ServerTimestamp) {
+ return lhs.server_timestamp_value_.local_write_time <
+ rhs.server_timestamp_value_.local_write_time;
+ } else {
+ return false;
+ }
+ case Type::String:
+ return lhs.string_value_.compare(rhs.string_value_) < 0;
+ case Type::Blob:
+ return lhs.blob_value_ < rhs.blob_value_;
+ case Type::GeoPoint:
+ return lhs.geo_point_value_ < rhs.geo_point_value_;
+ case Type::Array:
+ return lhs.array_value_ < rhs.array_value_;
+ case Type::Object:
+ return lhs.object_value_ < rhs.object_value_;
+ default:
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ false, lhs.type(), "Unsupported type %d", lhs.type());
+ // return false if assertion does not abort the program. We will say
+ // each unsupported type takes only one value thus everything is equal.
+ return false;
+ }
+}
+
+void FieldValue::SwitchTo(const Type type) {
+ if (tag_ == type) {
+ return;
+ }
+ // Not same type. Destruct old type first and then initialize new type.
+ // Must call destructor explicitly for any non-POD type.
+ switch (tag_) {
+ case Type::Timestamp:
+ timestamp_value_.~Timestamp();
+ break;
+ case Type::ServerTimestamp:
+ server_timestamp_value_.~ServerTimestamp();
+ break;
+ case Type::String:
+ string_value_.~basic_string();
+ break;
+ case Type::Blob:
+ blob_value_.~vector();
+ break;
+ case Type::GeoPoint:
+ geo_point_value_.~GeoPoint();
+ break;
+ case Type::Array:
+ array_value_.~vector();
+ break;
+ case Type::Object:
+ object_value_.~map();
+ break;
+ default: {} // The other types where there is nothing to worry about.
+ }
+ tag_ = type;
+ // Must call constructor explicitly for any non-POD type to initialize.
+ switch (tag_) {
+ case Type::Timestamp:
+ new (&timestamp_value_) Timestamp(0, 0);
+ break;
+ case Type::ServerTimestamp:
+ new (&server_timestamp_value_) ServerTimestamp();
+ break;
+ case Type::String:
+ new (&string_value_) std::string();
+ break;
+ case Type::Blob:
+ // Do not even bother to allocate a new array of size 0.
+ new (&blob_value_) std::vector<uint8_t>();
+ break;
+ case Type::GeoPoint:
+ new (&geo_point_value_) GeoPoint();
+ break;
+ case Type::Array:
+ new (&array_value_) std::vector<FieldValue>();
+ break;
+ case Type::Object:
+ new (&object_value_) std::map<const std::string, const FieldValue>();
+ break;
+ default: {} // The other types where there is nothing to worry about.
+ }
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.h b/Firestore/core/src/firebase/firestore/model/field_value.h
new file mode 100644
index 0000000..4cd0b3d
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/field_value.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Firestore/core/include/firebase/firestore/geo_point.h"
+#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+struct ServerTimestamp {
+ Timestamp local_write_time;
+ Timestamp previous_value;
+ // TODO(zxu123): adopt absl::optional once abseil is ported.
+ bool has_previous_value_;
+};
+
+/**
+ * tagged-union class representing an immutable data value as stored in
+ * Firestore. FieldValue represents all the different kinds of values
+ * that can be stored in fields in a document.
+ */
+class FieldValue {
+ public:
+ /**
+ * All the different kinds of values that can be stored in fields in
+ * a document. The types of the same comparison order should be defined
+ * together as a group. The order of each group is defined by the Firestore
+ * backend and is available at:
+ * https://firebase.google.com/docs/firestore/manage-data/data-types
+ */
+ enum class Type {
+ Null, // Null
+ Boolean, // Boolean
+ Long, // Number type starts here
+ Double,
+ Timestamp, // Timestamp type starts here
+ ServerTimestamp,
+ String, // String
+ Blob, // Blob
+ Reference, // Reference
+ GeoPoint, // GeoPoint
+ Array, // Array
+ Object, // Object
+ // New enum should not always been added at the tail. Add it to the correct
+ // position instead, see the doc comment above.
+ };
+
+ FieldValue() : tag_(Type::Null) {
+ }
+
+ // Do not inline these ctor/dtor below, which contain call to non-trivial
+ // operator=.
+ FieldValue(const FieldValue& value);
+ FieldValue(FieldValue&& value);
+
+ ~FieldValue();
+
+ FieldValue& operator=(const FieldValue& value);
+ FieldValue& operator=(FieldValue&& value);
+
+ /** Returns the true type for this value. */
+ Type type() const {
+ return tag_;
+ }
+
+ /** factory methods. */
+ static const FieldValue& NullValue();
+ static const FieldValue& TrueValue();
+ static const FieldValue& FalseValue();
+ static const FieldValue& BooleanValue(bool value);
+ static const FieldValue& NanValue();
+ static FieldValue IntegerValue(int64_t value);
+ static FieldValue DoubleValue(double value);
+ static FieldValue TimestampValue(const Timestamp& value);
+ static FieldValue ServerTimestampValue(const Timestamp& local_write_time,
+ const Timestamp& previous_value);
+ static FieldValue ServerTimestampValue(const Timestamp& local_write_time);
+ static FieldValue StringValue(const char* value);
+ static FieldValue StringValue(const std::string& value);
+ static FieldValue StringValue(std::string&& value);
+ static FieldValue BlobValue(const uint8_t* source, size_t size);
+ // static FieldValue ReferenceValue();
+ static FieldValue GeoPointValue(const GeoPoint& value);
+ static FieldValue ArrayValue(const std::vector<FieldValue>& value);
+ static FieldValue ArrayValue(std::vector<FieldValue>&& value);
+ static FieldValue ObjectValue(
+ const std::map<const std::string, const FieldValue>& value);
+ static FieldValue ObjectValue(
+ std::map<const std::string, const FieldValue>&& value);
+
+ friend bool operator<(const FieldValue& lhs, const FieldValue& rhs);
+
+ private:
+ explicit FieldValue(bool value) : tag_(Type::Boolean), boolean_value_(value) {
+ }
+
+ /**
+ * Switch to the specified type, if different from the current type.
+ */
+ void SwitchTo(const Type type);
+
+ Type tag_;
+ union {
+ // There is no null type as tag_ alone is enough for Null FieldValue.
+ bool boolean_value_;
+ int64_t integer_value_;
+ double double_value_;
+ Timestamp timestamp_value_;
+ ServerTimestamp server_timestamp_value_;
+ std::string string_value_;
+ std::vector<uint8_t> blob_value_;
+ GeoPoint geo_point_value_;
+ std::vector<FieldValue> array_value_;
+ std::map<const std::string, const FieldValue> object_value_;
+ };
+};
+
+/** Compares against another FieldValue. */
+bool operator<(const FieldValue& lhs, const FieldValue& rhs);
+
+inline bool operator>(const FieldValue& lhs, const FieldValue& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator>=(const FieldValue& lhs, const FieldValue& rhs) {
+ return !(lhs < rhs);
+}
+
+inline bool operator<=(const FieldValue& lhs, const FieldValue& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator!=(const FieldValue& lhs, const FieldValue& rhs) {
+ return lhs < rhs || lhs > rhs;
+}
+
+inline bool operator==(const FieldValue& lhs, const FieldValue& rhs) {
+ return !(lhs != rhs);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
diff --git a/Firestore/core/src/firebase/firestore/model/timestamp.cc b/Firestore/core/src/firebase/firestore/model/timestamp.cc
new file mode 100644
index 0000000..b3d1597
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/timestamp.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
+
+#include <time.h>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+Timestamp::Timestamp(int64_t seconds, int32_t nanos)
+ : seconds_(seconds), nanos_(nanos) {
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ nanos >= 0, nanos >= 0, "timestamp nanoseconds out of range: %d", nanos);
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ nanos < 1e9, nanos < 1e9, "timestamp nanoseconds out of range: %d",
+ nanos);
+ // Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore
+ // supports.
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ seconds >= -62135596800L, seconds >= -62135596800L,
+ "timestamp seconds out of range: %lld", seconds);
+ // This will break in the year 10,000.
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ seconds < 253402300800L, seconds < 253402300800L,
+ "timestamp seconds out of range: %lld", seconds);
+}
+
+Timestamp::Timestamp() : seconds_(0), nanos_(0) {
+}
+
+Timestamp Timestamp::Now() {
+ return Timestamp(time(nullptr), 0);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/model/timestamp.h b/Firestore/core/src/firebase/firestore/model/timestamp.h
new file mode 100644
index 0000000..dd0349c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/timestamp.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TIMESTAMP_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TIMESTAMP_H_
+
+#include <stdint.h>
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+/**
+ * A Timestamp represents an absolute time from the backend at up to nanosecond
+ * precision. A Timestamp is always UTC.
+ */
+class Timestamp {
+ public:
+ /**
+ * Creates a new timestamp with seconds and nanos set to 0.
+ *
+ * PORTING NOTE: This does NOT set to current timestamp by default. To get the
+ * current timestamp, call Timestamp::Now().
+ */
+ Timestamp();
+
+ /**
+ * Creates a new timestamp.
+ *
+ * @param seconds the number of seconds since epoch.
+ * @param nanos the number of nanoseconds after the seconds.
+ */
+ Timestamp(int64_t seconds, int32_t nanos);
+
+ /** Returns a timestamp with the current date / time. */
+ static Timestamp Now();
+
+ int64_t seconds() const {
+ return seconds_;
+ }
+
+ int32_t nanos() const {
+ return nanos_;
+ }
+
+ private:
+ int64_t seconds_;
+ int32_t nanos_;
+};
+
+/** Compares against another Timestamp. */
+inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) {
+ return lhs.seconds() < rhs.seconds() ||
+ (lhs.seconds() == rhs.seconds() && lhs.nanos() < rhs.nanos());
+}
+
+inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) {
+ return !(lhs < rhs);
+}
+
+inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) {
+ return lhs < rhs || lhs > rhs;
+}
+
+inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) {
+ return !(lhs != rhs);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TIMESTAMP_H_
diff --git a/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt b/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
new file mode 100644
index 0000000..43320ce
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright 2018 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.
+
+cc_library(
+ firebase_firestore_remote
+ SOURCES
+ datastore.h
+ datastore.cc
+ DEPENDS
+ grpc::grpc
+)
diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.cc b/Firestore/core/src/firebase/firestore/remote/datastore.cc
new file mode 100644
index 0000000..f8a8988
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/remote/datastore.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/remote/datastore.h"
+
+namespace firebase {
+namespace firestore {
+namespace remote {
+
+Datastore::Datastore() {
+}
+
+Datastore::~Datastore() {
+}
+
+} // namespace remote
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.h b/Firestore/core/src/firebase/firestore/remote/datastore.h
new file mode 100644
index 0000000..807b75f
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/remote/datastore.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_DATASTORE_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_DATASTORE_H_
+
+namespace firebase {
+namespace firestore {
+namespace remote {
+
+class Datastore {
+ public:
+ Datastore();
+ ~Datastore();
+
+ Datastore(const Datastore& other) = delete;
+ Datastore(Datastore&& other) = delete;
+
+ Datastore& operator=(const Datastore& other) = delete;
+ Datastore& operator=(Datastore&& other) = delete;
+};
+
+} // namespace remote
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_DATASTORE_H_
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
index ce81363..3e32111 100644
--- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
@@ -12,8 +12,116 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-add_library(
+# firebase_firestore_util is the interface of this module. The rest of the
+# libraries in here are an implementation detail of making this a
+# mutli-platform build.
+
+include(CheckSymbolExists)
+include(CheckIncludeFiles)
+
+cc_library(
+ firebase_firestore_util_base
+ SOURCES
+ string_printf.cc
+ string_printf.h
+ DEPENDS
+ absl_base
+)
+
+## assert and log
+
+cc_library(
+ firebase_firestore_util_stdio
+ SOURCES
+ assert_stdio.cc
+ log_stdio.cc
+ DEPENDS
+ firebase_firestore_util_base
+ absl_base
+ EXCLUDE_FROM_ALL
+)
+
+cc_library(
+ firebase_firestore_util_apple
+ SOURCES
+ assert_apple.mm
+ log_apple.mm
+ string_apple.h
+ DEPENDS
+ FirebaseCore
+ absl_strings
+ EXCLUDE_FROM_ALL
+)
+
+# Export a dependency on the correct logging library for this platform. All
+# buildable libraries are built and tested but only the best fit is exported.
+if(APPLE)
+ list(APPEND UTIL_DEPENDS firebase_firestore_util_apple)
+else()
+ list(APPEND UTIL_DEPENDS firebase_firestore_util_stdio)
+endif()
+
+
+## secure_random
+
+check_symbol_exists(arc4random stdlib.h HAVE_ARC4RANDOM)
+cc_library(
+ firebase_firestore_util_arc4random
+ SOURCES
+ secure_random_arc4random.cc
+)
+
+get_target_property(
+ CMAKE_REQUIRED_INCLUDES
+ OpenSSL::Crypto INTERFACE_INCLUDE_DIRECTORIES
+)
+check_include_files(openssl/rand.h HAVE_OPENSSL_RAND_H)
+cc_library(
+ firebase_firestore_util_openssl
+ SOURCES
+ secure_random_openssl.cc
+ DEPENDS
+ OpenSSL::Crypto
+)
+
+if(HAVE_ARC4RANDOM)
+ list(APPEND UTIL_DEPENDS firebase_firestore_util_arc4random)
+
+elseif(HAVE_OPENSSL_RAND_H)
+ list(APPEND UTIL_DEPENDS firebase_firestore_util_openssl)
+
+else()
+ message(FATAL_ERROR "No implementation for SecureRandom available.")
+
+endif()
+
+
+## main library
+configure_file(
+ config.h.in
+ config.h
+)
+
+cc_library(
firebase_firestore_util
- autoid.cc
- secure_random_arc4random.cc
+ SOURCES
+ autoid.cc
+ autoid.h
+ bits.cc
+ bits.h
+ comparison.cc
+ comparison.h
+ config.h
+ firebase_assert.h
+ iterator_adaptors.h
+ log.h
+ ordered_code.cc
+ ordered_code.h
+ secure_random.h
+ string_util.cc
+ string_util.h
+ DEPENDS
+ ${UTIL_DEPENDS}
+ firebase_firestore_util_base
+ absl_base
)
diff --git a/Firestore/core/src/firebase/firestore/util/assert_apple.mm b/Firestore/core/src/firebase/firestore/util/assert_apple.mm
new file mode 100644
index 0000000..83b76e1
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/assert_apple.mm
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+#import <Foundation/Foundation.h>
+
+#include <string.h>
+
+#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+void FailAssert(const char* file,
+ const char* func,
+ const int line,
+ const char* format,
+ ...) {
+ va_list args;
+ va_start(args, format);
+ NSString* description =
+ [[NSString alloc] initWithFormat:WrapNSStringNoCopy(format)
+ arguments:args];
+ va_end(args);
+ [[NSAssertionHandler currentHandler]
+ handleFailureInFunction:WrapNSStringNoCopy(func)
+ file:WrapNSStringNoCopy(file)
+ lineNumber:line
+ description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@",
+ description];
+ abort();
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/assert_stdio.cc b/Firestore/core/src/firebase/firestore/util/assert_stdio.cc
new file mode 100644
index 0000000..1d2e333
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/assert_stdio.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include <stdarg.h>
+
+#include <stdexcept>
+#include <string>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+#include "absl/base/config.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+void FailAssert(const char* file,
+ const char* func,
+ const int line,
+ const char* format,
+ ...) {
+ std::string message;
+ StringAppendF(&message, "ASSERT: %s(%d) %s: ", file, line, func);
+
+ va_list args;
+ va_start(args, format);
+ StringAppendV(&message, format, args);
+ va_end(args);
+
+#if ABSL_HAVE_EXCEPTIONS
+ throw std::logic_error(message);
+
+#else
+ fprintf(stderr, "%s\n", message.c_str());
+ std::terminate();
+#endif
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/Port/bits.cc b/Firestore/core/src/firebase/firestore/util/bits.cc
index 3e61223..0bfe4c3 100644
--- a/Firestore/Port/bits.cc
+++ b/Firestore/core/src/firebase/firestore/util/bits.cc
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#include "Firestore/Port/bits.h"
+#include "Firestore/core/src/firebase/firestore/util/bits.h"
-#include <assert.h>
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
-namespace Firestore {
+namespace firebase {
+namespace firestore {
+namespace util {
int Bits::Log2Floor_Portable(uint32_t n) {
if (n == 0) return -1;
@@ -32,8 +34,10 @@ int Bits::Log2Floor_Portable(uint32_t n) {
log += shift;
}
}
- assert(value == 1);
+ FIREBASE_ASSERT(value == 1);
return log;
}
-} // namespace Firestore
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/Port/bits.h b/Firestore/core/src/firebase/firestore/util/bits.h
index d212bf8..185273f 100644
--- a/Firestore/Port/bits.h
+++ b/Firestore/core/src/firebase/firestore/util/bits.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef IPHONE_FIRESTORE_PORT_BITS_H_
-#define IPHONE_FIRESTORE_PORT_BITS_H_
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_BITS_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_BITS_H_
// Various bit-twiddling functions, all of which are static members of the Bits
// class (making it effectively a namespace). Operands are unsigned integers.
@@ -27,16 +27,20 @@
class Bits_Port32_Test;
class Bits_Port64_Test;
-namespace Firestore {
+namespace firebase {
+namespace firestore {
+namespace util {
class Bits {
public:
- // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0.
+ /** Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0. */
static int Log2Floor(uint32_t n);
static int Log2Floor64(uint64_t n);
- // Potentially faster version of Log2Floor() that returns an
- // undefined value if n == 0
+ /**
+ * Potentially faster version of Log2Floor() that returns an
+ * undefined value if n == 0.
+ */
static int Log2FloorNonZero(uint32_t n);
static int Log2FloorNonZero64(uint64_t n);
@@ -51,8 +55,8 @@ class Bits {
void operator=(Bits const&) = delete;
// Allow tests to call _Portable variants directly.
- friend class ::Bits_Port32_Test;
- friend class ::Bits_Port64_Test;
+ friend class Bits_Port32_Test;
+ friend class Bits_Port64_Test;
};
// ------------------------------------------------------------------------
@@ -155,6 +159,8 @@ inline int Bits::Log2FloorNonZero64_Portable(uint64_t n) {
}
}
-} // namespace Firestore
+} // namespace util
+} // namespace firestore
+} // namespace firebase
-#endif // IPHONE_FIRESTORE_PORT_BITS_H_
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_BITS_H_
diff --git a/Firestore/core/src/firebase/firestore/util/comparison.cc b/Firestore/core/src/firebase/firestore/util/comparison.cc
new file mode 100644
index 0000000..4bef843
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/comparison.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/comparison.h"
+
+#include <math.h>
+
+#include <limits>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+bool Comparator<absl::string_view>::operator()(
+ const absl::string_view& left, const absl::string_view& right) const {
+ // TODO(wilhuff): truncation aware comparison
+ return left < right;
+}
+
+bool Comparator<double>::operator()(double left, double right) const {
+ // NaN sorts equal to itself and before any other number.
+ if (left < right) {
+ return true;
+ } else if (left >= right) {
+ return false;
+ } else {
+ // One or both left and right is NaN.
+ return isnan(left) && !isnan(right);
+ }
+}
+
+static constexpr double INT64_MIN_VALUE_AS_DOUBLE =
+ static_cast<double>(std::numeric_limits<int64_t>::min());
+
+static constexpr double INT64_MAX_VALUE_AS_DOUBLE =
+ static_cast<double>(std::numeric_limits<int64_t>::max());
+
+ComparisonResult CompareMixedNumber(double double_value, int64_t int64_value) {
+ // LLONG_MIN has an exact representation as double, so to check for a value
+ // outside the range representable by long, we have to check for strictly less
+ // than LLONG_MIN. Note that this also handles negative infinity.
+ if (double_value < INT64_MIN_VALUE_AS_DOUBLE) {
+ return ComparisonResult::Ascending;
+ }
+
+ // LLONG_MAX has no exact representation as double (casting as we've done
+ // makes 2^63, which is larger than LLONG_MAX), so consider any value greater
+ // than or equal to the threshold to be out of range. This also handles
+ // positive infinity.
+ if (double_value >= INT64_MAX_VALUE_AS_DOUBLE) {
+ return ComparisonResult::Descending;
+ }
+
+ // In Firestore NaN is defined to compare before all other numbers.
+ if (isnan(double_value)) {
+ return ComparisonResult::Ascending;
+ }
+
+ auto double_as_int64 = static_cast<int64_t>(double_value);
+ ComparisonResult cmp = Compare<int64_t>(double_as_int64, int64_value);
+ if (cmp != ComparisonResult::Same) {
+ return cmp;
+ }
+
+ // At this point the long representations are equal but this could be due to
+ // rounding.
+ double int64_as_double = static_cast<double>(int64_value);
+ return Compare<double>(double_value, int64_as_double);
+}
+
+/** Helper to normalize a double and then return the raw bits as a uint64_t. */
+uint64_t DoubleBits(double d) {
+ if (isnan(d)) {
+ d = NAN;
+ }
+
+ // Unlike C, C++ does not define type punning through a union type.
+
+ // TODO(wilhuff): replace with absl::bit_cast
+ static_assert(sizeof(double) == sizeof(uint64_t), "doubles must be 8 bytes");
+ uint64_t bits;
+ memcpy(&bits, &d, sizeof(bits));
+ return bits;
+}
+
+bool DoubleBitwiseEquals(double left, double right) {
+ return DoubleBits(left) == DoubleBits(right);
+}
+
+size_t DoubleBitwiseHash(double d) {
+ uint64_t bits = DoubleBits(d);
+ // Note that x ^ (x >> 32) works fine for both 32 and 64 bit definitions of
+ // size_t
+ return static_cast<size_t>(bits) ^ static_cast<size_t>(bits >> 32);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/comparison.h b/Firestore/core/src/firebase/firestore/util/comparison.h
new file mode 100644
index 0000000..6fd1e2b
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/comparison.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPARISON_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPARISON_H_
+
+#if __OBJC__
+#import <Foundation/Foundation.h>
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <functional>
+#include <string>
+#include <vector>
+
+#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/**
+ * An enumeration describing the result of a three-way comparison among
+ * strongly-ordered values (i.e. where comparison between values always yields
+ * less-than, equal-to, or greater-than).
+ *
+ * This is equivalent to:
+ *
+ * * NSComparisonResult from the iOS/macOS Foundation framework.
+ * * std::strong_ordering from C++20
+ *
+ * The values of the constants are specifically chosen so as to make casting
+ * between this type and NSComparisonResult possible.
+ */
+enum class ComparisonResult {
+ /** The left hand side was less than the right. */
+ Ascending = -1,
+
+ /** The left hand side was equal to the right. */
+ Same = 0,
+
+ /** The left hand side was greater than the right. */
+ Descending = 1
+};
+
+/**
+ * Returns the reverse order (i.e. Ascending => Descending) etc.
+ */
+constexpr ComparisonResult ReverseOrder(ComparisonResult result) {
+ return static_cast<ComparisonResult>(-static_cast<int>(result));
+}
+
+/**
+ * A generalized comparator for types in Firestore, with ordering defined
+ * according to Firestore's semantics. This is useful as argument to e.g.
+ * std::sort.
+ *
+ * Comparators are only defined for the limited set of types for which
+ * Firestore defines an ordering.
+ */
+template <typename T>
+struct Comparator {
+ // By default comparison is not defined
+};
+
+/** Compares two strings. */
+template <>
+struct Comparator<absl::string_view> {
+ bool operator()(const absl::string_view& left,
+ const absl::string_view& right) const;
+};
+
+/** Compares two bools: false < true. */
+template <>
+struct Comparator<bool> : public std::less<bool> {};
+
+/** Compares two int32_t. */
+template <>
+struct Comparator<int32_t> : public std::less<int32_t> {};
+
+/** Compares two int64_t. */
+template <>
+struct Comparator<int64_t> : public std::less<int64_t> {};
+
+/** Compares two doubles (using Firestore semantics for NaN). */
+template <>
+struct Comparator<double> {
+ bool operator()(double left, double right) const;
+};
+
+/** Compare two byte sequences. */
+// TODO(wilhuff): perhaps absl::Span<uint8_t> would be better?
+template <>
+struct Comparator<std::vector<uint8_t>>
+ : public std::less<std::vector<uint8_t>> {};
+
+/**
+ * Perform a three-way comparison between the left and right values using
+ * the appropriate Comparator for the values based on their type.
+ */
+template <typename T>
+ComparisonResult Compare(const T& left, const T& right) {
+ Comparator<T> less_than;
+ if (less_than(left, right)) {
+ return ComparisonResult::Ascending;
+ } else if (less_than(right, left)) {
+ return ComparisonResult::Descending;
+ } else {
+ return ComparisonResult::Same;
+ }
+}
+
+#if __OBJC__
+/**
+ * Returns true if the given ComparisonResult and NSComparisonResult have the
+ * same integer values (at compile time).
+ */
+constexpr bool EqualValue(ComparisonResult lhs, NSComparisonResult rhs) {
+ return static_cast<int>(lhs) == static_cast<int>(rhs);
+}
+
+/**
+ * Performs a three-way comparison, identically to Compare, but converts the
+ * result to an NSComparisonResult.
+ *
+ * This function exists for interoperation with Objective-C++ and should
+ * eventually be removed.
+ */
+template <typename T>
+inline NSComparisonResult WrapCompare(const T& left, const T& right) {
+ static_assert(EqualValue(ComparisonResult::Ascending, NSOrderedAscending),
+ "Ascending invalid");
+ static_assert(EqualValue(ComparisonResult::Same, NSOrderedSame),
+ "Same invalid");
+ static_assert(EqualValue(ComparisonResult::Descending, NSOrderedDescending),
+ "Descending invalid");
+
+ return static_cast<NSComparisonResult>(Compare<T>(left, right));
+}
+#endif
+
+/** Compares a double and an int64_t. */
+ComparisonResult CompareMixedNumber(double doubleValue, int64_t longValue);
+
+/** Normalizes a double and then return the raw bits as a uint64_t. */
+uint64_t DoubleBits(double d);
+
+/**
+ * Compares the bitwise representation of two doubles, but normalizes NaN
+ * values. This is similar to what the backend and android clients do, including
+ * comparing -0.0 as not equal to 0.0.
+ */
+bool DoubleBitwiseEquals(double left, double right);
+
+/**
+ * Computes a bitwise hash of a double, but normalizes NaN values, suitable for
+ * use when using FSTDoublesAreBitwiseEqual for equality.
+ */
+size_t DoubleBitwiseHash(double d);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPARISON_H_
diff --git a/Firestore/core/src/firebase/firestore/util/config.h.in b/Firestore/core/src/firebase/firestore/util/config.h.in
new file mode 100644
index 0000000..e7a0c03
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/config.h.in
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_CONFIG_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_CONFIG_H_
+
+// This header defines macros for all available platform configuration values.
+// When building with CMake, it will substitute the lines marked with
+// cmakedefine with values corresponding to the local configuration.
+//
+// On Apple platforms we support building via CocoaPods without CMake. When
+// building this way we can't test the presence of features before building so
+// predefine all the platform-support feature macros to their expected values.
+
+#cmakedefine HAVE_ARC4RANDOM 1
+#if COCOAPODS
+# define HAVE_ARC4RANDOM 1
+#endif
+
+#cmakedefine HAVE_OPENSSL_RAND_H 1
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_CONFIG_H_
diff --git a/Firestore/core/src/firebase/firestore/util/firebase_assert.h b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
new file mode 100644
index 0000000..cff550a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 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.
+ */
+
+// To avoid naming-collision, this header is called firebase_assert.h instead
+// of assert.h.
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_
+
+#include <stdlib.h>
+
+#include "Firestore/core/src/firebase/firestore/util/log.h"
+
+#define FIREBASE_EXPAND_STRINGIFY_(X) #X
+#define FIREBASE_EXPAND_STRINGIFY(X) FIREBASE_EXPAND_STRINGIFY_(X)
+
+// FIREBASE_ASSERT_* macros are not compiled out of release builds. They should
+// be used for assertions that need to be propagated to end-users of SDKs.
+// FIREBASE_DEV_ASSERT_* macros are compiled out of release builds, similar to
+// the C assert() macro. They should be used for internal assertions that are
+// only shown to SDK developers.
+
+// Assert condition is true, if it's false log an assert with the specified
+// expression as a string.
+#define FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression) \
+ do { \
+ if (!(condition)) { \
+ firebase::firestore::util::FailAssert( \
+ __FILE__, __PRETTY_FUNCTION__, __LINE__, \
+ FIREBASE_EXPAND_STRINGIFY(expression)); \
+ } \
+ } while (0)
+
+// Assert condition is true, if it's false log an assert with the specified
+// expression as a string. Compiled out of release builds.
+#if defined(NDEBUG)
+#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \
+ { (void)(condition); }
+#else
+#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \
+ FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression)
+#endif // defined(NDEBUG)
+
+// Custom assert() implementation that is not compiled out in release builds.
+#define FIREBASE_ASSERT(expression) \
+ FIREBASE_ASSERT_WITH_EXPRESSION(expression, expression)
+
+// Custom assert() implementation that is compiled out in release builds.
+// Compiled out of release builds.
+#define FIREBASE_DEV_ASSERT(expression) \
+ FIREBASE_DEV_ASSERT_WITH_EXPRESSION(expression, expression)
+
+// Assert condition is true otherwise display the specified expression,
+// message and abort.
+#define FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, ...) \
+ do { \
+ if (!(condition)) { \
+ firebase::firestore::util::LogError( \
+ FIREBASE_EXPAND_STRINGIFY(expression)); \
+ firebase::firestore::util::FailAssert(__FILE__, __PRETTY_FUNCTION__, \
+ __LINE__, __VA_ARGS__); \
+ } \
+ } while (0)
+
+// Assert condition is true otherwise display the specified expression,
+// message and abort. Compiled out of release builds.
+#if defined(NDEBUG)
+#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \
+ ...) \
+ { (void)(condition); }
+#else
+#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \
+ ...) \
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, __VA_ARGS__)
+#endif // defined(NDEBUG)
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+// A no-return helper function. To raise an assertion, use Macro instead.
+void FailAssert(const char* file,
+ const char* func,
+ const int line,
+ const char* format,
+ ...);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_
diff --git a/Firestore/core/src/firebase/firestore/util/iterator_adaptors.h b/Firestore/core/src/firebase/firestore/util/iterator_adaptors.h
new file mode 100644
index 0000000..042fd72
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/iterator_adaptors.h
@@ -0,0 +1,812 @@
+/*
+ * Copyright 2005, 2018 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.
+ */
+
+// Provides some iterator adaptors and views.
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ITERATOR_ADAPTORS_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ITERATOR_ADAPTORS_H_
+
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+namespace internal {
+
+// value == true if Iter prohibits modification of its pointees.
+template <typename Iter>
+struct IsConstIter
+ : std::is_const<typename std::remove_reference<
+ typename std::iterator_traits<Iter>::reference>::type> {};
+
+template <bool Cond, typename T>
+struct AddConstIf : std::conditional<Cond, const T, T> {};
+
+// SynthIterTraits propagates the constness of the 'BaseIter' iterator
+// type to its own exported 'pointer' and 'reference' typedefs.
+template <typename BaseIter, typename Val>
+struct SynthIterTraits : std::iterator_traits<BaseIter> {
+ private:
+ static constexpr bool kIterConst = IsConstIter<BaseIter>::value;
+
+ public:
+ using value_type = typename std::remove_cv<Val>::type;
+ using pointer = typename AddConstIf<kIterConst, Val>::type*;
+ using reference = typename AddConstIf<kIterConst, Val>::type&;
+};
+
+// PointeeSynthIterTraits is similar to SynthIterTraits, but the 'Ptr'
+// parameter is a pointer-like type, and value_type is the pointee.
+template <typename BaseIter, typename Ptr>
+struct PointeeSynthIterTraits : std::iterator_traits<BaseIter> {
+ private:
+ static constexpr bool kIterConst = IsConstIter<BaseIter>::value;
+
+ public:
+ using value_type = typename std::pointer_traits<Ptr>::element_type;
+ using pointer = typename AddConstIf<kIterConst, value_type>::type*;
+ using reference = typename AddConstIf<kIterConst, value_type>::type&;
+};
+
+// CRTP base class for generating iterator adaptors.
+// 'Sub' is the derived type, and 'Policy' encodes
+// all of the behavior for the adaptor.
+// Policy requirements:
+// - type 'underlying_iterator': the underlying iterator type.
+// - type 'adapted_traits': the traits of the adaptor.
+// - static 'Extract(underlying_iterator)': convert iterator to reference.
+//
+template <typename Sub, typename Policy>
+class IteratorAdaptorBase {
+ private:
+ // Everything needed from the Policy type is expressed in this section.
+ using Iterator = typename Policy::underlying_iterator;
+ using OutTraits = typename Policy::adapted_traits;
+ static typename OutTraits::reference Extract(const Iterator& it) {
+ return Policy::Extract(it);
+ }
+
+ public:
+ using iterator_category = typename OutTraits::iterator_category;
+ using value_type = typename OutTraits::value_type;
+ using pointer = typename OutTraits::pointer;
+ using reference = typename OutTraits::reference;
+ using difference_type = typename OutTraits::difference_type;
+
+ IteratorAdaptorBase() : it_() {
+ }
+ // NOLINTNEXTLINE(runtime/explicit)
+ IteratorAdaptorBase(Iterator it) : it_(it) {
+ }
+
+ Sub& sub() {
+ return static_cast<Sub&>(*this);
+ }
+ const Sub& sub() const {
+ return static_cast<const Sub&>(*this);
+ }
+
+ const Iterator& base() const {
+ return it_;
+ }
+
+ reference get() const {
+ return Extract(base());
+ }
+ reference operator*() const {
+ return get();
+ }
+ pointer operator->() const {
+ return &get();
+ }
+ reference operator[](difference_type d) const {
+ return *(sub() + d);
+ }
+
+ Sub& operator++() {
+ ++it_;
+ return sub();
+ }
+ Sub& operator--() {
+ --it_;
+ return sub();
+ }
+ Sub operator++(int /*unused*/) {
+ return it_++;
+ }
+ Sub operator--(int /*unused*/) {
+ return it_--;
+ }
+
+ Sub& operator+=(difference_type d) {
+ it_ += d;
+ return sub();
+ }
+ Sub& operator-=(difference_type d) {
+ it_ -= d;
+ return sub();
+ }
+
+ bool operator==(Sub b) const {
+ return base() == b.base();
+ }
+ bool operator!=(Sub b) const {
+ return base() != b.base();
+ }
+ // These shouldn't be necessary, as implicit conversion from 'Iterator'
+ // should be enough to make such comparisons work.
+ bool operator==(Iterator b) const {
+ return *this == Sub(b);
+ }
+ bool operator!=(Iterator b) const {
+ return *this != Sub(b);
+ }
+
+ friend Sub operator+(Sub it, difference_type d) {
+ return it.base() + d;
+ }
+ friend Sub operator+(difference_type d, Sub it) {
+ return it + d;
+ }
+ friend Sub operator-(Sub it, difference_type d) {
+ return it.base() - d;
+ }
+ friend difference_type operator-(Sub a, Sub b) {
+ return a.base() - b.base();
+ }
+
+ friend bool operator<(Sub a, Sub b) {
+ return a.base() < b.base();
+ }
+ friend bool operator>(Sub a, Sub b) {
+ return a.base() > b.base();
+ }
+ friend bool operator<=(Sub a, Sub b) {
+ return a.base() <= b.base();
+ }
+ friend bool operator>=(Sub a, Sub b) {
+ return a.base() >= b.base();
+ }
+
+ private:
+ Iterator it_;
+};
+
+template <typename It>
+struct FirstPolicy {
+ using underlying_iterator = It;
+ using adapted_traits =
+ SynthIterTraits<underlying_iterator,
+ typename std::iterator_traits<
+ underlying_iterator>::value_type::first_type>;
+ static typename adapted_traits::reference Extract(
+ const underlying_iterator& it) {
+ return it->first;
+ }
+};
+
+template <typename It>
+struct SecondPolicy {
+ using underlying_iterator = It;
+ using adapted_traits =
+ SynthIterTraits<underlying_iterator,
+ typename std::iterator_traits<
+ underlying_iterator>::value_type::second_type>;
+ static typename adapted_traits::reference Extract(
+ const underlying_iterator& it) {
+ return it->second;
+ }
+};
+
+template <typename It>
+struct SecondPtrPolicy {
+ using underlying_iterator = It;
+ using adapted_traits =
+ PointeeSynthIterTraits<underlying_iterator,
+ typename std::iterator_traits<
+ underlying_iterator>::value_type::second_type>;
+ static typename adapted_traits::reference Extract(
+ const underlying_iterator& it) {
+ return *it->second;
+ }
+};
+
+template <typename It>
+struct PtrPolicy {
+ using underlying_iterator = It;
+ using adapted_traits = PointeeSynthIterTraits<
+ underlying_iterator,
+ typename std::iterator_traits<underlying_iterator>::value_type>;
+ static typename adapted_traits::reference Extract(
+ const underlying_iterator& it) {
+ return **it;
+ }
+};
+
+} // namespace internal
+
+// In both iterator adaptors, iterator_first<> and iterator_second<>,
+// we build a new iterator based on a parameterized iterator type, "It".
+// The value type, "Val" is determined by "It::value_type::first" or
+// "It::value_type::second", respectively.
+
+// iterator_first<> adapts an iterator to return the first value of a pair.
+// It is equivalent to calling it->first on every value.
+// Example:
+//
+// hash_map<string, int> values;
+// values["foo"] = 1;
+// values["bar"] = 2;
+// for (iterator_first<hash_map<string, int>::iterator> x = values.begin();
+// x != values.end(); ++x) {
+// printf("%s", x->c_str());
+// }
+template <typename It>
+struct iterator_first
+ : internal::IteratorAdaptorBase<iterator_first<It>,
+ internal::FirstPolicy<It>> {
+ using Base = internal::IteratorAdaptorBase<iterator_first<It>,
+ internal::FirstPolicy<It>>;
+ iterator_first() {
+ }
+ iterator_first(It it) // NOLINT(runtime/explicit)
+ : Base(it) {
+ }
+ template <typename It2>
+ iterator_first(iterator_first<It2> o) // NOLINT(runtime/explicit)
+ : Base(o.base()) {
+ }
+};
+
+template <typename It>
+iterator_first<It> make_iterator_first(It it) {
+ return iterator_first<It>(it);
+}
+
+// iterator_second<> adapts an iterator to return the second value of a pair.
+// It is equivalent to calling it->second on every value.
+// Example:
+//
+// hash_map<string, int> values;
+// values["foo"] = 1;
+// values["bar"] = 2;
+// for (iterator_second<hash_map<string, int>::iterator> x = values.begin();
+// x != values.end(); ++x) {
+// int v = *x;
+// printf("%d", v);
+// }
+template <typename It>
+struct iterator_second
+ : internal::IteratorAdaptorBase<iterator_second<It>,
+ internal::SecondPolicy<It>> {
+ using Base = internal::IteratorAdaptorBase<iterator_second<It>,
+ internal::SecondPolicy<It>>;
+ iterator_second() {
+ }
+ iterator_second(It it) // NOLINT(runtime/explicit)
+ : Base(it) {
+ }
+ template <typename It2>
+ iterator_second(iterator_second<It2> o) // NOLINT(runtime/explicit)
+ : Base(o.base()) {
+ }
+};
+
+template <typename It>
+iterator_second<It> make_iterator_second(It it) {
+ return iterator_second<It>(it);
+}
+
+// iterator_second_ptr<> adapts an iterator to return the dereferenced second
+// value of a pair.
+// It is equivalent to calling *it->second on every value.
+// The same result can be achieved by composition
+// iterator_ptr<iterator_second<> >
+// Can be used with maps where values are regular pointers or pointers wrapped
+// into linked_ptr. This iterator adaptor can be used by classes to give their
+// clients access to some of their internal data without exposing too much of
+// it.
+//
+// Example:
+// class MyClass {
+// public:
+// MyClass(const string& s);
+// string DebugString() const;
+// };
+// typedef hash_map<string, linked_ptr<MyClass> > MyMap;
+// typedef iterator_second_ptr<MyMap::iterator> MyMapValuesIterator;
+// MyMap values;
+// values["foo"].reset(new MyClass("foo"));
+// values["bar"].reset(new MyClass("bar"));
+// for (MyMapValuesIterator it = values.begin(); it != values.end(); ++it) {
+// printf("%s", it->DebugString().c_str());
+// }
+template <typename It>
+struct iterator_second_ptr
+ : internal::IteratorAdaptorBase<iterator_second_ptr<It>,
+ internal::SecondPtrPolicy<It>> {
+ using Base = internal::IteratorAdaptorBase<iterator_second_ptr<It>,
+ internal::SecondPtrPolicy<It>>;
+ iterator_second_ptr() {
+ }
+ iterator_second_ptr(It it) // NOLINT(runtime/explicit)
+ : Base(it) {
+ }
+ template <typename It2>
+ iterator_second_ptr(iterator_second_ptr<It2> o) // NOLINT(runtime/explicit)
+ : Base(o.base()) {
+ }
+};
+
+template <typename It>
+iterator_second_ptr<It> make_iterator_second_ptr(It it) {
+ return iterator_second_ptr<It>(it);
+}
+
+// iterator_ptr<> adapts an iterator to return the dereferenced value.
+// With this adaptor you can write *it instead of **it, or it->something instead
+// of (*it)->something.
+// Can be used with vectors and lists where values are regular pointers
+// or pointers wrapped into linked_ptr. This iterator adaptor can be used by
+// classes to give their clients access to some of their internal data without
+// exposing too much of it.
+//
+// Example:
+// class MyClass {
+// public:
+// MyClass(const string& s);
+// string DebugString() const;
+// };
+// typedef vector<linked_ptr<MyClass> > MyVector;
+// typedef iterator_ptr<MyVector::iterator> DereferencingIterator;
+// MyVector values;
+// values.push_back(make_linked_ptr(new MyClass("foo")));
+// values.push_back(make_linked_ptr(new MyClass("bar")));
+// for (DereferencingIterator it = values.begin(); it != values.end(); ++it) {
+// printf("%s", it->DebugString().c_str());
+// }
+//
+// Without iterator_ptr you would have to do (*it)->DebugString()
+template <typename It, typename Ptr /* ignored */ = void>
+struct iterator_ptr : internal::IteratorAdaptorBase<iterator_ptr<It, Ptr>,
+ internal::PtrPolicy<It>> {
+ using Base = internal::IteratorAdaptorBase<iterator_ptr<It, Ptr>,
+ internal::PtrPolicy<It>>;
+ iterator_ptr() {
+ }
+ iterator_ptr(It it) // NOLINT(runtime/explicit)
+ : Base(it) {
+ }
+ template <typename It2>
+ iterator_ptr(iterator_ptr<It2> o) // NOLINT(runtime/explicit)
+ : Base(o.base()) {
+ }
+};
+
+template <typename It>
+iterator_ptr<It> make_iterator_ptr(It it) {
+ return iterator_ptr<It>(it);
+}
+
+namespace internal {
+
+// Template that uses SFINAE to inspect Container abilities:
+// . Set has_size_type true, iff T::size_type is defined
+// . Define size_type as T::size_type if defined, or size_t otherwise
+template <typename C>
+struct container_traits {
+ private:
+ // Test for availability of C::size_type.
+ template <typename U, typename = void>
+ struct test_size_type : std::false_type {};
+ template <typename U>
+ struct test_size_type<U, absl::void_t<typename U::size_type>>
+ : std::true_type {};
+
+ // Conditional provisioning of a size_type which defaults to size_t.
+ template <bool Cond, typename U = void>
+ struct size_type_def {
+ using type = typename U::size_type;
+ };
+ template <typename U>
+ struct size_type_def<false, U> {
+ using type = size_t;
+ };
+
+ public:
+ // Determine whether C::size_type is available.
+ static const bool has_size_type = test_size_type<C>::value;
+
+ // Provide size_type as either C::size_type if available, or as size_t.
+ using size_type = typename size_type_def<has_size_type, C>::type;
+};
+
+template <typename C>
+struct IterGenerator {
+ using container_type = C;
+ using iterator = typename C::iterator;
+ using const_iterator = typename C::const_iterator;
+
+ static iterator begin(container_type& c) { // NOLINT(runtime/references)
+ return c.begin();
+ }
+ static iterator end(container_type& c) { // NOLINT(runtime/references)
+ return c.end();
+ }
+ static const_iterator begin(const container_type& c) {
+ return c.begin();
+ }
+ static const_iterator end(const container_type& c) {
+ return c.end();
+ }
+};
+
+template <typename SubIterGenerator>
+struct ReversingIterGeneratorAdaptor {
+ using container_type = typename SubIterGenerator::container_type;
+ using iterator = std::reverse_iterator<typename SubIterGenerator::iterator>;
+ using const_iterator =
+ std::reverse_iterator<typename SubIterGenerator::const_iterator>;
+
+ static iterator begin(container_type& c) { // NOLINT(runtime/references)
+ return iterator(SubIterGenerator::end(c));
+ }
+ static iterator end(container_type& c) { // NOLINT(runtime/references)
+ return iterator(SubIterGenerator::begin(c));
+ }
+ static const_iterator begin(const container_type& c) {
+ return const_iterator(SubIterGenerator::end(c));
+ }
+ static const_iterator end(const container_type& c) {
+ return const_iterator(SubIterGenerator::begin(c));
+ }
+};
+
+// C: the container type
+// Iter: the type of mutable iterator to generate
+// ConstIter: the type of constant iterator to generate
+// IterGenerator: a policy type that returns native iterators from a C
+template <typename C,
+ typename Iter,
+ typename ConstIter,
+ typename IterGenerator = internal::IterGenerator<C>>
+class iterator_view_helper {
+ public:
+ using container_type = C;
+ using iterator = Iter;
+ using const_iterator = ConstIter;
+ using value_type = typename std::iterator_traits<iterator>::value_type;
+ using size_type = typename internal::container_traits<C>::size_type;
+
+ explicit iterator_view_helper(
+ container_type& c) // NOLINT(runtime/references)
+ : c_(&c) {
+ }
+
+ iterator begin() {
+ return iterator(IterGenerator::begin(container()));
+ }
+ iterator end() {
+ return iterator(IterGenerator::end(container()));
+ }
+ const_iterator begin() const {
+ return const_iterator(IterGenerator::begin(container()));
+ }
+ const_iterator end() const {
+ return const_iterator(IterGenerator::end(container()));
+ }
+ const_iterator cbegin() const {
+ return begin();
+ }
+ const_iterator cend() const {
+ return end();
+ }
+ const container_type& container() const {
+ return *c_;
+ }
+ container_type& container() {
+ return *c_;
+ }
+
+ bool empty() const {
+ return begin() == end();
+ }
+ size_type size() const {
+ return c_->size();
+ }
+
+ private:
+ container_type* c_;
+};
+
+template <typename C,
+ typename ConstIter,
+ typename IterGenerator = internal::IterGenerator<C>>
+class const_iterator_view_helper {
+ public:
+ using container_type = C;
+ using const_iterator = ConstIter;
+ using value_type = typename std::iterator_traits<const_iterator>::value_type;
+ using size_type = typename internal::container_traits<C>::size_type;
+
+ explicit const_iterator_view_helper(const container_type& c) : c_(&c) {
+ }
+
+ // Allow implicit conversion from the corresponding iterator_view_helper.
+ // Erring on the side of constness should be allowed. E.g.:
+ // MyMap m;
+ // key_view_type<MyMap>::type keys = key_view(m); // ok
+ // key_view_type<const MyMap>::type const_keys = key_view(m); // ok
+ template <typename Iter>
+ const_iterator_view_helper(const iterator_view_helper<container_type,
+ Iter,
+ const_iterator,
+ IterGenerator>& v)
+ : c_(&v.container()) {
+ }
+
+ const_iterator begin() const {
+ return const_iterator(IterGenerator::begin(container()));
+ }
+ const_iterator end() const {
+ return const_iterator(IterGenerator::end(container()));
+ }
+ const_iterator cbegin() const {
+ return begin();
+ }
+ const_iterator cend() const {
+ return end();
+ }
+ const container_type& container() const {
+ return *c_;
+ }
+
+ bool empty() const {
+ return begin() == end();
+ }
+ size_type size() const {
+ return c_->size();
+ }
+
+ private:
+ const container_type* c_;
+};
+
+} // namespace internal
+
+// Note: The views like value_view, key_view should be in gtl namespace.
+// Currently there are lot of callers that reference the methods in the global
+// namespace.
+//
+// Traits to provide a typedef abstraction for the return value
+// of the key_view() and value_view() functions, such that
+// they can be declared as:
+//
+// template <typename C> key_view_t<C> key_view(C& c);
+// template <typename C> value_view_t<C> value_view(C& c);
+//
+// This abstraction allows callers of these functions to use readable
+// type names, and allows the maintainers of iterator_adaptors.h to
+// change the return types if needed without updating callers.
+
+template <typename C>
+struct key_view_type {
+ using type = internal::iterator_view_helper<
+ C,
+ iterator_first<typename C::iterator>,
+ iterator_first<typename C::const_iterator>>;
+};
+
+template <typename C>
+struct key_view_type<const C> {
+ using type = internal::
+ const_iterator_view_helper<C, iterator_first<typename C::const_iterator>>;
+};
+
+template <typename C>
+struct value_view_type {
+ using type = internal::iterator_view_helper<
+ C,
+ iterator_second<typename C::iterator>,
+ iterator_second<typename C::const_iterator>>;
+};
+
+template <typename C>
+struct value_view_type<const C> {
+ using type = internal::const_iterator_view_helper<
+ C,
+ iterator_second<typename C::const_iterator>>;
+};
+
+// The key_view and value_view functions provide pretty ways to iterate either
+// the keys or the values of a map using range based for loops.
+//
+// Example:
+// hash_map<int, string> my_map;
+// ...
+// for (string val : value_view(my_map)) {
+// ...
+// }
+//
+// Note: If you pass a temporary container to key_view or value_view, be careful
+// that the temporary container outlives the wrapper view to avoid dangling
+// references.
+// This is fine: PublishAll(value_view(Make());
+// This is not: for (const auto& v : value_view(Make())) Publish(v);
+
+template <typename C>
+typename key_view_type<C>::type key_view(
+ C& map) { // NOLINT(runtime/references)
+ return typename key_view_type<C>::type(map);
+}
+
+template <typename C>
+typename key_view_type<const C>::type key_view(const C& map) {
+ return typename key_view_type<const C>::type(map);
+}
+
+template <typename C>
+typename value_view_type<C>::type value_view(
+ C& map) { // NOLINT(runtime/references)
+ return typename value_view_type<C>::type(map);
+}
+
+template <typename C>
+typename value_view_type<const C>::type value_view(const C& map) {
+ return typename value_view_type<const C>::type(map);
+}
+
+// Abstract container view that dereferences the pointer-like .second member
+// of a container's std::pair elements, such as the elements of std::map<K,V*>
+// or of std::vector<std::pair<K,V*>>.
+//
+// Example:
+// map<int, string*> elements;
+// for (const string& element : deref_second_view(elements)) {
+// ...
+// }
+//
+// Note: If you pass a temporary container to deref_second_view, be careful that
+// the temporary container outlives the deref_second_view to avoid dangling
+// references.
+// This is fine: PublishAll(deref_second_view(Make());
+// This is not: for (const auto& v : deref_second_view(Make())) {
+// Publish(v);
+// }
+
+template <typename C>
+struct deref_second_view_type {
+ using type = internal::iterator_view_helper<
+ C,
+ iterator_second_ptr<typename C::iterator>,
+ iterator_second_ptr<typename C::const_iterator>>;
+};
+
+template <typename C>
+struct deref_second_view_type<const C> {
+ using type = internal::const_iterator_view_helper<
+ C,
+ iterator_second_ptr<typename C::const_iterator>>;
+};
+
+template <typename C>
+typename deref_second_view_type<C>::type deref_second_view(
+ C& map) { // NOLINT(runtime/references)
+ return typename deref_second_view_type<C>::type(map);
+}
+
+template <typename C>
+typename deref_second_view_type<const C>::type deref_second_view(const C& map) {
+ return typename deref_second_view_type<const C>::type(map);
+}
+
+// Abstract container view that dereferences pointer elements.
+//
+// Example:
+// vector<string*> elements;
+// for (const string& element : deref_view(elements)) {
+// ...
+// }
+//
+// Note: If you pass a temporary container to deref_view, be careful that the
+// temporary container outlives the deref_view to avoid dangling references.
+// This is fine: PublishAll(deref_view(Make());
+// This is not: for (const auto& v : deref_view(Make())) { Publish(v); }
+
+template <typename C>
+struct deref_view_type {
+ using type =
+ internal::iterator_view_helper<C,
+ iterator_ptr<typename C::iterator>,
+ iterator_ptr<typename C::const_iterator>>;
+};
+
+template <typename C>
+struct deref_view_type<const C> {
+ using type = internal::
+ const_iterator_view_helper<C, iterator_ptr<typename C::const_iterator>>;
+};
+
+template <typename C>
+typename deref_view_type<C>::type deref_view(
+ C& c) { // NOLINT(runtime/references)
+ return typename deref_view_type<C>::type(c);
+}
+
+template <typename C>
+typename deref_view_type<const C>::type deref_view(const C& c) {
+ return typename deref_view_type<const C>::type(c);
+}
+
+// Abstract container view that iterates backwards.
+//
+// Example:
+// vector<string> elements;
+// for (const string& element : reversed_view(elements)) {
+// ...
+// }
+//
+// Note: If you pass a temporary container to reversed_view_type, be careful
+// that the temporary container outlives the reversed_view to avoid dangling
+// references. This is fine: PublishAll(reversed_view(Make());
+// This is not: for (const auto& v : reversed_view(Make())) { Publish(v); }
+
+template <typename C>
+struct reversed_view_type {
+ private:
+ using policy =
+ internal::ReversingIterGeneratorAdaptor<internal::IterGenerator<C>>;
+
+ public:
+ using type = internal::iterator_view_helper<C,
+ typename policy::iterator,
+ typename policy::const_iterator,
+ policy>;
+};
+
+template <typename C>
+struct reversed_view_type<const C> {
+ private:
+ using policy =
+ internal::ReversingIterGeneratorAdaptor<internal::IterGenerator<C>>;
+
+ public:
+ using type = internal::
+ const_iterator_view_helper<C, typename policy::const_iterator, policy>;
+};
+
+template <typename C>
+typename reversed_view_type<C>::type reversed_view(
+ C& c) { // NOLINT(runtime/references)
+ return typename reversed_view_type<C>::type(c);
+}
+
+template <typename C>
+typename reversed_view_type<const C>::type reversed_view(const C& c) {
+ return typename reversed_view_type<const C>::type(c);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ITERATOR_ADAPTORS_H_
diff --git a/Firestore/core/src/firebase/firestore/util/log.h b/Firestore/core/src/firebase/firestore/util/log.h
new file mode 100644
index 0000000..d0cff4d
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/log.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_LOG_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_LOG_H_
+
+#include <stdarg.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/// @brief Levels used when logging messages.
+enum LogLevel {
+ /// Verbose Log Level
+ kLogLevelVerbose = 0,
+ /// Debug Log Level
+ kLogLevelDebug,
+ /// Info Log Level
+ kLogLevelInfo,
+ /// Warning Log Level
+ kLogLevelWarning,
+ /// Error Log Level
+ kLogLevelError,
+};
+
+// Common log methods.
+
+// All messages at or above the specified log level value are displayed.
+void LogSetLevel(LogLevel level);
+// Get the currently set log level.
+LogLevel LogGetLevel();
+// Log a debug message to the system log.
+void LogDebug(const char* format, ...);
+// Log an info message to the system log.
+void LogInfo(const char* format, ...);
+// Log a warning to the system log.
+void LogWarning(const char* format, ...);
+// Log an error to the system log.
+void LogError(const char* format, ...);
+// Log a firebase message (implemented by the platform specific logger).
+void LogMessageV(LogLevel log_level, const char* format, va_list args);
+// Log a firebase message via LogMessageV().
+void LogMessage(LogLevel log_level, const char* format, ...);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_LOG_H_
diff --git a/Firestore/core/src/firebase/firestore/util/log_apple.mm b/Firestore/core/src/firebase/firestore/util/log_apple.mm
new file mode 100644
index 0000000..cb2c58e
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/log_apple.mm
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/log.h"
+
+#import <FirebaseCore/FIRLogger.h>
+#import <Foundation/Foundation.h>
+
+#include <string>
+
+#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+namespace {
+
+// Translates a C++ LogLevel to the equivalent Objective-C FIRLoggerLevel
+FIRLoggerLevel ToFIRLoggerLevel(LogLevel level) {
+ switch (level) {
+ case kLogLevelVerbose: // fall through
+ case kLogLevelDebug:
+ return FIRLoggerLevelDebug;
+ case kLogLevelInfo:
+ return FIRLoggerLevelInfo;
+ case kLogLevelWarning:
+ return FIRLoggerLevelWarning;
+ case kLogLevelError:
+ return FIRLoggerLevelError;
+ default:
+ // Unsupported log level. FIRSetLoggerLevel will deal with it.
+ return static_cast<FIRLoggerLevel>(-1);
+ }
+}
+
+} // namespace
+
+void LogSetLevel(LogLevel level) {
+ FIRSetLoggerLevel(ToFIRLoggerLevel(level));
+}
+
+LogLevel LogGetLevel() {
+ // We return the true log level. True log level is what the SDK used to
+ // determine whether to log instead of what parameter is used in the last call
+ // of LogSetLevel().
+ if (FIRIsLoggableLevel(FIRLoggerLevelInfo, NO)) {
+ if (FIRIsLoggableLevel(FIRLoggerLevelDebug, NO)) {
+ // FIRLoggerLevelMax is actually kLogLevelDebug right now. We do not check
+ // further.
+ return kLogLevelDebug;
+ } else {
+ return kLogLevelInfo;
+ }
+ } else {
+ if (FIRIsLoggableLevel(FIRLoggerLevelWarning, NO)) {
+ return kLogLevelWarning;
+ } else {
+ return kLogLevelError;
+ }
+ }
+}
+
+void LogDebug(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerFirestore, @"I-FST000001",
+ WrapNSStringNoCopy(format), list);
+ va_end(list);
+}
+
+void LogInfo(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ FIRLogBasic(FIRLoggerLevelInfo, kFIRLoggerFirestore, @"I-FST000001",
+ WrapNSStringNoCopy(format), list);
+ va_end(list);
+}
+
+void LogWarning(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerFirestore, @"I-FST000001",
+ WrapNSStringNoCopy(format), list);
+ va_end(list);
+}
+
+void LogError(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ FIRLogBasic(FIRLoggerLevelError, kFIRLoggerFirestore, @"I-FST000001",
+ WrapNSStringNoCopy(format), list);
+ va_end(list);
+}
+
+void LogMessageV(LogLevel log_level, const char* format, va_list args) {
+ FIRLogBasic(ToFIRLoggerLevel(log_level), kFIRLoggerFirestore, @"I-FST000001",
+ WrapNSStringNoCopy(format), args);
+}
+
+void LogMessage(LogLevel log_level, const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ LogMessageV(log_level, format, list);
+ va_end(list);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/log_stdio.cc b/Firestore/core/src/firebase/firestore/util/log_stdio.cc
new file mode 100644
index 0000000..bca2dc9
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/log_stdio.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/log.h"
+
+#include <stdio.h>
+#include <string>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+LogLevel g_log_level = kLogLevelInfo;
+
+void LogSetLevel(LogLevel level) {
+ g_log_level = level;
+}
+
+LogLevel LogGetLevel() {
+ return g_log_level;
+}
+
+void LogDebug(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ LogMessageV(kLogLevelDebug, format, list);
+ va_end(list);
+}
+
+void LogInfo(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ LogMessageV(kLogLevelInfo, format, list);
+ va_end(list);
+}
+
+void LogWarning(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ LogMessageV(kLogLevelWarning, format, list);
+ va_end(list);
+}
+
+void LogError(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ LogMessageV(kLogLevelError, format, list);
+ va_end(list);
+}
+
+void LogMessageV(LogLevel log_level, const char* format, va_list args) {
+ if (log_level < g_log_level) {
+ return;
+ }
+ switch (log_level) {
+ case kLogLevelVerbose:
+ printf("VERBOSE: ");
+ break;
+ case kLogLevelDebug:
+ printf("DEBUG: ");
+ break;
+ case kLogLevelInfo:
+ break;
+ case kLogLevelWarning:
+ printf("WARNING: ");
+ break;
+ case kLogLevelError:
+ printf("ERROR: ");
+ break;
+ }
+ vprintf(format, args);
+ printf("\n");
+}
+
+void LogMessage(LogLevel log_level, const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ LogMessageV(log_level, format, list);
+ va_end(list);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/Port/ordered_code.cc b/Firestore/core/src/firebase/firestore/util/ordered_code.cc
index 038d445..688f15c 100644
--- a/Firestore/Port/ordered_code.cc
+++ b/Firestore/core/src/firebase/firestore/util/ordered_code.cc
@@ -14,15 +14,19 @@
* limitations under the License.
*/
-#include "Firestore/Port/ordered_code.h"
+#include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
-#include <assert.h>
+#include <absl/base/internal/endian.h>
+#include <absl/base/internal/unaligned_access.h>
+#include <absl/base/port.h>
-#include "Firestore/Port/bits.h"
+#include "Firestore/core/src/firebase/firestore/util/bits.h"
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
-#include "Firestore/Port/absl/absl_endian.h"
-#include "Firestore/Port/absl/absl_port.h"
-#include <leveldb/db.h> // For Slice
+#define UNALIGNED_LOAD32 ABSL_INTERNAL_UNALIGNED_LOAD32
+#define UNALIGNED_LOAD64 ABSL_INTERNAL_UNALIGNED_LOAD64
+#define UNALIGNED_STORE32 ABSL_INTERNAL_UNALIGNED_STORE32
+#define UNALIGNED_STORE64 ABSL_INTERNAL_UNALIGNED_STORE64
// We encode a string in different ways depending on whether the item
// should be in lexicographically increasing or decreasing order.
@@ -59,9 +63,9 @@
// turn is the same as the ordering of the encodings of those two
// characters. Moreover, for every finite string x, F(x) < F(<infinity>).
-namespace Firestore {
-
-using leveldb::Slice;
+namespace firebase {
+namespace firestore {
+namespace util {
static const char kEscape1 = '\000';
static const char kNullCharacter = '\xff'; // Combined with kEscape1
@@ -73,50 +77,57 @@ static const char kFFCharacter = '\000'; // Combined with kEscape2
static const char kEscape1_Separator[2] = {kEscape1, kSeparator};
-// Append to "*dest" the "len" bytes starting from "*src".
+/** Append to "*dest" the "len" bytes starting from "*src". */
inline static void AppendBytes(std::string* dest, const char* src, size_t len) {
dest->append(src, len);
}
-inline bool IsSpecialByte(char c) { return ((unsigned char)(c + 1)) < 2; }
+inline static bool IsSpecialByte(char c) {
+ return ((unsigned char)(c + 1)) < 2;
+}
-// Returns 0 if one or more of the bytes in the specified uint32 value
-// are the special values 0 or 255, and returns 4 otherwise. The
-// result of this routine can be added to "p" to either advance past
-// the next 4 bytes if they do not contain a special byte, or to
-// remain on this set of four bytes if they contain the next special
-// byte occurrence.
-//
-// REQUIRES: v is the value of loading the next 4 bytes from "*p" (we
-// pass in v rather than loading it because in some cases, the client
-// may already have the value in a register: "p" is just used for
-// assertion checking).
-inline int AdvanceIfNoSpecialBytes(uint32_t v_32, const char* p) {
- assert(UNALIGNED_LOAD32(p) == v_32);
+/**
+ * Returns 0 if one or more of the bytes in the specified uint32 value
+ * are the special values 0 or 255, and returns 4 otherwise. The
+ * result of this routine can be added to "p" to either advance past
+ * the next 4 bytes if they do not contain a special byte, or to
+ * remain on this set of four bytes if they contain the next special
+ * byte occurrence.
+ *
+ * REQUIRES: v_32 is the value of loading the next 4 bytes from "*p" (we
+ * pass in v_32 rather than loading it because in some cases, the client
+ * may already have the value in a register: "p" is just used for
+ * assertion checking).
+ */
+inline static int AdvanceIfNoSpecialBytes(uint32_t v_32, const char* p) {
+ FIREBASE_ASSERT(UNALIGNED_LOAD32(p) == v_32);
// See comments in SkipToNextSpecialByte if you wish to
// understand this expression (which checks for the occurrence
// of the special byte values 0 or 255 in any of the bytes of v_32).
if ((v_32 - 0x01010101u) & ~(v_32 + 0x01010101u) & 0x80808080u) {
// Special byte is in p[0..3]
- assert(IsSpecialByte(p[0]) || IsSpecialByte(p[1]) || IsSpecialByte(p[2]) ||
- IsSpecialByte(p[3]));
+ FIREBASE_ASSERT(IsSpecialByte(p[0]) || IsSpecialByte(p[1]) ||
+ IsSpecialByte(p[2]) || IsSpecialByte(p[3]));
return 0;
} else {
- assert(!IsSpecialByte(p[0]));
- assert(!IsSpecialByte(p[1]));
- assert(!IsSpecialByte(p[2]));
- assert(!IsSpecialByte(p[3]));
+ FIREBASE_ASSERT(!IsSpecialByte(p[0]));
+ FIREBASE_ASSERT(!IsSpecialByte(p[1]));
+ FIREBASE_ASSERT(!IsSpecialByte(p[2]));
+ FIREBASE_ASSERT(!IsSpecialByte(p[3]));
return 4;
}
}
-// Return a pointer to the first byte in the range "[start..limit)"
-// whose value is 0 or 255 (kEscape1 or kEscape2). If no such byte
-// exists in the range, returns "limit".
-inline const char* SkipToNextSpecialByte(const char* start, const char* limit) {
+/**
+ * Return a pointer to the first byte in the range "[start..limit)"
+ * whose value is 0 or 255 (kEscape1 or kEscape2). If no such byte
+ * exists in the range, returns "limit".
+ */
+inline static const char* SkipToNextSpecialByte(const char* start,
+ const char* limit) {
// If these constants were ever changed, this routine needs to change
- assert(kEscape1 == 0);
- assert((kEscape2 & 0xffu) == 255u);
+ FIREBASE_ASSERT(kEscape1 == 0);
+ FIREBASE_ASSERT((kEscape2 & 0xff) == 255);
const char* p = start;
while (p + 8 <= limit) {
// Find out if any of the next 8 bytes are either 0 or 255 (our
@@ -154,7 +165,8 @@ inline const char* SkipToNextSpecialByte(const char* start, const char* limit) {
if (IsSpecialByte(p[0])) return p;
if (IsSpecialByte(p[1])) return p + 1;
if (IsSpecialByte(p[2])) return p + 2;
- assert(IsSpecialByte(p[3])); // Last byte must be the special one
+ FIREBASE_ASSERT(
+ IsSpecialByte(p[3])); // Last byte must be the special one
return p + 3;
}
}
@@ -174,9 +186,12 @@ const char* OrderedCode::TEST_SkipToNextSpecialByte(const char* start,
return SkipToNextSpecialByte(start, limit);
}
-// Helper routine to encode "s" and append to "*dest", escaping special
-// characters.
-inline static void EncodeStringFragment(std::string* dest, Slice s) {
+/**
+ * Helper routine to encode "s" and append to "*dest", escaping special
+ * characters.
+ */
+inline static void EncodeStringFragment(std::string* dest,
+ absl::string_view s) {
const char* p = s.data();
const char* limit = p + s.size();
const char* copy_start = p;
@@ -184,44 +199,49 @@ inline static void EncodeStringFragment(std::string* dest, Slice s) {
p = SkipToNextSpecialByte(p, limit);
if (p >= limit) break; // No more special characters that need escaping
char c = *(p++);
- assert(IsSpecialByte(c));
+ FIREBASE_ASSERT(IsSpecialByte(c));
if (c == kEscape1) {
- AppendBytes(dest, copy_start, p - copy_start - 1);
+ AppendBytes(dest, copy_start, static_cast<size_t>(p - copy_start) - 1);
dest->push_back(kEscape1);
dest->push_back(kNullCharacter);
copy_start = p;
} else {
- assert(c == kEscape2);
- AppendBytes(dest, copy_start, p - copy_start - 1);
+ FIREBASE_ASSERT(c == kEscape2);
+ AppendBytes(dest, copy_start, static_cast<size_t>(p - copy_start) - 1);
dest->push_back(kEscape2);
dest->push_back(kFFCharacter);
copy_start = p;
}
}
if (p > copy_start) {
- AppendBytes(dest, copy_start, p - copy_start);
+ AppendBytes(dest, copy_start, static_cast<size_t>(p - copy_start));
}
}
-void OrderedCode::WriteString(std::string* dest, Slice s) {
+void OrderedCode::WriteString(std::string* dest, absl::string_view s) {
EncodeStringFragment(dest, s);
AppendBytes(dest, kEscape1_Separator, 2);
}
-// Return number of bytes needed to encode the non-length portion
-// of val in ordered coding. Returns number in range [0,8].
+/**
+ * Return number of bytes needed to encode the non-length portion
+ * of val in ordered coding. Returns number in range [0,8].
+ */
static inline unsigned int OrderedNumLength(uint64_t val) {
const int lg = Bits::Log2Floor64(val); // -1 if val==0
return static_cast<unsigned int>(lg + 1 + 7) / 8;
}
-// Append n bytes from src to *dst.
-// REQUIRES: n <= 9
-// REQUIRES: src[0..8] are readable bytes (even if n is smaller)
-//
-// If we use string::append() instead of this routine, it increases the
-// runtime of WriteNumIncreasing from ~9ns to ~13ns.
-static inline void AppendUpto9(std::string* dst, const char* src,
+/**
+ * Append n bytes from src to *dst.
+ * REQUIRES: n <= 9
+ * REQUIRES: src[0..8] are readable bytes (even if n is smaller)
+ *
+ * If we use string::append() instead of this routine, it increases the
+ * runtime of WriteNumIncreasing from ~9ns to ~13ns.
+ */
+static inline void AppendUpto9(std::string* dst,
+ const char* src,
unsigned int n) {
dst->append(src, 9); // Fixed-length append
const size_t extra = 9 - n; // How many extra bytes we added
@@ -238,10 +258,11 @@ void OrderedCode::WriteNumIncreasing(std::string* dest, uint64_t val) {
// call on *dest.
char buf[17];
- UNALIGNED_STORE64(buf + 1, absl::ghtonll(val)); // buf[0] may be needed for length
+ UNALIGNED_STORE64(buf + 1,
+ absl::ghtonll(val)); // buf[0] may be needed for length
const unsigned int length = OrderedNumLength(val);
char* start = buf + 9 - length - 1;
- *start = length;
+ *start = static_cast<char>(length);
AppendUpto9(dest, start, length + 1);
}
@@ -255,15 +276,19 @@ void OrderedCode::WriteInfinity(std::string* dest) {
WriteInfinityInternal(dest);
}
-void OrderedCode::WriteTrailingString(std::string* dest, Slice str) {
+void OrderedCode::WriteTrailingString(std::string* dest,
+ absl::string_view str) {
dest->append(str.data(), str.size());
}
-// Parse the encoding of a string previously encoded with or without
-// inversion. If parse succeeds, return true, consume encoding from
-// "*src", and if result != NULL append the decoded string to "*result".
-// Otherwise, return false and leave both undefined.
-inline static bool ReadStringInternal(Slice* src, std::string* result) {
+/**
+ * Parse the encoding of a string previously encoded with or without
+ * inversion. If parse succeeds, return true, consume encoding from
+ * "*src", and if result != NULL append the decoded string to "*result".
+ * Otherwise, return false and leave both undefined.
+ */
+inline static bool ReadStringInternal(absl::string_view* src,
+ std::string* result) {
const char* start = src->data();
const char* string_limit = src->data() + src->size();
@@ -278,16 +303,17 @@ inline static bool ReadStringInternal(Slice* src, std::string* result) {
// If inversion is required, instead of inverting 'c', we invert the
// character constants to which 'c' is compared. We get the same
// behavior but save the runtime cost of inverting 'c'.
- assert(IsSpecialByte(c));
+ FIREBASE_ASSERT(IsSpecialByte(c));
if (c == kEscape1) {
if (result) {
- AppendBytes(result, copy_start, start - copy_start - 1);
+ AppendBytes(result, copy_start,
+ static_cast<size_t>(start - copy_start) - 1);
}
// kEscape1 kSeparator ends component
// kEscape1 kNullCharacter represents '\0'
const char next = *(start++);
if (next == kSeparator) {
- src->remove_prefix(start - src->data());
+ src->remove_prefix(static_cast<size_t>(start - src->data()));
return true;
} else if (next == kNullCharacter) {
if (result) {
@@ -298,9 +324,10 @@ inline static bool ReadStringInternal(Slice* src, std::string* result) {
}
copy_start = start;
} else {
- assert(c == kEscape2);
+ FIREBASE_ASSERT(c == kEscape2);
if (result) {
- AppendBytes(result, copy_start, start - copy_start - 1);
+ AppendBytes(result, copy_start,
+ static_cast<size_t>(start - copy_start) - 1);
}
// kEscape2 kFFCharacter represents '\xff'
// kEscape2 kInfinity is an error
@@ -318,22 +345,22 @@ inline static bool ReadStringInternal(Slice* src, std::string* result) {
return false;
}
-bool OrderedCode::ReadString(Slice* src, std::string* result) {
+bool OrderedCode::ReadString(absl::string_view* src, std::string* result) {
return ReadStringInternal(src, result);
}
-bool OrderedCode::ReadNumIncreasing(Slice* src, uint64_t* result) {
+bool OrderedCode::ReadNumIncreasing(absl::string_view* src, uint64_t* result) {
if (src->empty()) {
return false; // Not enough bytes
}
// Decode length byte
- const int len = static_cast<unsigned char>((*src)[0]);
+ const size_t len = static_cast<size_t>((*src)[0]);
// If len > 0 and src is longer than 1, the first byte of "payload"
// must be non-zero (otherwise the encoding is not minimal).
// In opt mode, we don't enforce that encodings must be minimal.
- assert(0 == len || src->size() == 1 || (*src)[1] != '\0');
+ FIREBASE_ASSERT(0 == len || src->size() == 1 || (*src)[1] != '\0');
if (len + 1 > src->size() || len > 8) {
return false; // Not enough bytes or too many bytes
@@ -341,7 +368,7 @@ bool OrderedCode::ReadNumIncreasing(Slice* src, uint64_t* result) {
if (result) {
uint64_t tmp = 0;
- for (int i = 0; i < len; i++) {
+ for (size_t i = 0; i < len; i++) {
tmp <<= 8;
tmp |= static_cast<unsigned char>((*src)[1 + i]);
}
@@ -351,7 +378,7 @@ bool OrderedCode::ReadNumIncreasing(Slice* src, uint64_t* result) {
return true;
}
-inline static bool ReadInfinityInternal(Slice* src) {
+inline static bool ReadInfinityInternal(absl::string_view* src) {
if (src->size() >= 2 && ((*src)[0] == kEscape2) && ((*src)[1] == kInfinity)) {
src->remove_prefix(2);
return true;
@@ -360,9 +387,12 @@ inline static bool ReadInfinityInternal(Slice* src) {
}
}
-bool OrderedCode::ReadInfinity(Slice* src) { return ReadInfinityInternal(src); }
+bool OrderedCode::ReadInfinity(absl::string_view* src) {
+ return ReadInfinityInternal(src);
+}
-inline static bool ReadStringOrInfinityInternal(Slice* src, std::string* result,
+inline static bool ReadStringOrInfinityInternal(absl::string_view* src,
+ std::string* result,
bool* inf) {
if (ReadInfinityInternal(src)) {
if (inf) *inf = true;
@@ -381,12 +411,14 @@ inline static bool ReadStringOrInfinityInternal(Slice* src, std::string* result,
}
}
-bool OrderedCode::ReadStringOrInfinity(Slice* src, std::string* result,
+bool OrderedCode::ReadStringOrInfinity(absl::string_view* src,
+ std::string* result,
bool* inf) {
return ReadStringOrInfinityInternal(src, result, inf);
}
-bool OrderedCode::ReadTrailingString(Slice* src, std::string* result) {
+bool OrderedCode::ReadTrailingString(absl::string_view* src,
+ std::string* result) {
if (result) result->assign(src->data(), src->size());
src->remove_prefix(src->size());
return true;
@@ -394,7 +426,7 @@ bool OrderedCode::ReadTrailingString(Slice* src, std::string* result) {
void OrderedCode::TEST_Corrupt(std::string* str, int k) {
int seen_seps = 0;
- for (int i = 0; i < str->size() - 1; i++) {
+ for (size_t i = 0; i < str->size() - 1; i++) {
if ((*str)[i] == kEscape1 && (*str)[i + 1] == kSeparator) {
seen_seps++;
if (seen_seps == k) {
@@ -500,61 +532,70 @@ static const int8_t kBitsToLength[1 + 63] = {
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7,
7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10};
-// Calculates the encoding length in bytes of the signed number n.
+/** Calculates the encoding length in bytes of the signed number n. */
static inline int SignedEncodingLength(int64_t n) {
- return kBitsToLength[Bits::Log2Floor64(n < 0 ? ~n : n) + 1];
+ return kBitsToLength[Bits::Log2Floor64(
+ static_cast<uint64_t>(n < 0 ? ~n : n)) +
+ 1];
}
-// Slightly faster version for n > 0.
+/** Slightly faster version for n > 0. */
static inline int SignedEncodingLengthPositive(int64_t n) {
- return kBitsToLength[Bits::Log2FloorNonZero64(n) + 1];
+ return kBitsToLength[Bits::Log2FloorNonZero64(static_cast<uint64_t>(n)) + 1];
}
void OrderedCode::WriteSignedNumIncreasing(std::string* dest, int64_t val) {
- const uint64_t x = val < 0 ? ~val : val;
+ const int64_t x = val < 0 ? ~val : val;
if (x < 64) { // fast path for encoding length == 1
- *dest += kLengthToHeaderBits[1][0] ^ val;
+ *dest += static_cast<char>(kLengthToHeaderBits[1][0] ^ val);
return;
}
// buf = val in network byte order, sign extended to 10 bytes
const char sign_byte = val < 0 ? '\xff' : '\0';
char buf[10] = {
- sign_byte, sign_byte,
+ sign_byte,
+ sign_byte,
};
- UNALIGNED_STORE64(buf + 2, absl::ghtonll(val));
+ UNALIGNED_STORE64(buf + 2, absl::ghtonll(static_cast<uint64_t>(val)));
- static_assert(sizeof(buf) == kMaxSigned64Length, "max length size mismatch");
- const int len = SignedEncodingLengthPositive(x);
- assert(len >= 2);
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(sizeof(buf) == kMaxSigned64Length,
+ sizeof(buf) == kMaxSigned64Length,
+ "max length size mismatch");
+ const size_t len = static_cast<size_t>(SignedEncodingLengthPositive(x));
+ FIREBASE_ASSERT(len >= 2);
char* const begin = buf + sizeof(buf) - len;
begin[0] ^= kLengthToHeaderBits[len][0];
begin[1] ^= kLengthToHeaderBits[len][1]; // ok because len >= 2
dest->append(begin, len);
}
-bool OrderedCode::ReadSignedNumIncreasing(Slice* src, int64_t* result) {
+bool OrderedCode::ReadSignedNumIncreasing(absl::string_view* src,
+ int64_t* result) {
if (src->empty()) return false;
const uint64_t xor_mask = (!((*src)[0] & 0x80)) ? ~0ULL : 0ULL;
- const unsigned char first_byte = (*src)[0] ^ (xor_mask & 0xff);
+ const unsigned char first_byte = static_cast<unsigned char>(
+ static_cast<uint64_t>((*src)[0]) ^ (xor_mask & 0xff));
// now calculate and test length, and set x to raw (unmasked) result
- int len;
+ size_t len;
uint64_t x;
if (first_byte != 0xff) {
- len = 7 - Bits::Log2FloorNonZero(first_byte ^ 0xff);
+ len = static_cast<size_t>(7 - Bits::Log2FloorNonZero(first_byte ^ 0xff));
if (src->size() < len) return false;
x = xor_mask; // sign extend using xor_mask
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
x = (x << 8) | static_cast<unsigned char>((*src)[i]);
} else {
len = 8;
if (src->size() < len) return false;
- const unsigned char second_byte = (*src)[1] ^ (xor_mask & 0xff);
+ const unsigned char second_byte = static_cast<unsigned char>(
+ static_cast<uint64_t>((*src)[1]) ^ (xor_mask & 0xff));
if (second_byte >= 0x80) {
if (second_byte < 0xc0) {
len = 9;
} else {
- const unsigned char third_byte = (*src)[2] ^ (xor_mask & 0xff);
+ const unsigned char third_byte = static_cast<unsigned char>(
+ static_cast<uint64_t>((*src)[2]) ^ (xor_mask & 0xff));
if (second_byte == 0xc0 && third_byte < 0x80) {
len = 10;
} else {
@@ -568,12 +609,14 @@ bool OrderedCode::ReadSignedNumIncreasing(Slice* src, int64_t* result) {
x ^= kLengthToMask[len]; // remove spurious header bits
- assert(len == SignedEncodingLength(x));
+ FIREBASE_ASSERT(len == static_cast<size_t>(
+ SignedEncodingLength(static_cast<int64_t>(x))));
- if (result) *result = x;
- src->remove_prefix(len);
+ if (result) *result = static_cast<int64_t>(x);
+ src->remove_prefix(static_cast<size_t>(len));
return true;
}
-} // namespace Firestore
-
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/Port/ordered_code.h b/Firestore/core/src/firebase/firestore/util/ordered_code.h
index 7c390a5..57b84bd 100644
--- a/Firestore/Port/ordered_code.h
+++ b/Firestore/core/src/firebase/firestore/util/ordered_code.h
@@ -36,16 +36,16 @@
// This module is often useful when generating multi-part sstable
// keys that have to be ordered in a particular fashion.
-#ifndef IPHONE_FIRESTORE_PORT_ORDERED_CODE_H_
-#define IPHONE_FIRESTORE_PORT_ORDERED_CODE_H_
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ORDERED_CODE_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ORDERED_CODE_H_
#include <string>
-namespace leveldb {
-class Slice;
-}
+#include "absl/strings/string_view.h"
-namespace Firestore {
+namespace firebase {
+namespace firestore {
+namespace util {
class OrderedCode {
public:
@@ -60,19 +60,23 @@ class OrderedCode {
// is not called WriteStringIncreasing() for convenience and backward
// compatibility.
- static void WriteString(std::string* dest, leveldb::Slice str);
+ static void WriteString(std::string* dest, absl::string_view str);
static void WriteNumIncreasing(std::string* dest, uint64_t num);
static void WriteSignedNumIncreasing(std::string* dest, int64_t num);
- // Creates an encoding for the "infinite string", a value considered to
- // be lexicographically after any real string. Note that in the case of
- // WriteInfinityDecreasing(), this would come before any real string as
- // the ordering puts lexicographically greater values first.
+ /**
+ * Creates an encoding for the "infinite string", a value considered to
+ * be lexicographically after any real string. Note that in the case of
+ * WriteInfinityDecreasing(), this would come before any real string as
+ * the ordering puts lexicographically greater values first.
+ */
static void WriteInfinity(std::string* dest);
- // Special string append that can only be used at the tail end of
- // an encoded string -- blindly appends "str" to "*dest".
- static void WriteTrailingString(std::string* dest, leveldb::Slice str);
+ /**
+ * Special string append that can only be used at the tail end of
+ * an encoded string -- blindly appends "str" to "*dest".
+ */
+ static void WriteTrailingString(std::string* dest, absl::string_view str);
// -------------------------------------------------------------------
// Decoding routines: these extract an item earlier encoded using
@@ -83,26 +87,33 @@ class OrderedCode {
// "*result". Returns true if the next item was read successfully, false
// otherwise.
- static bool ReadString(leveldb::Slice* src, std::string* result);
- static bool ReadNumIncreasing(leveldb::Slice* src, uint64_t* result);
- static bool ReadSignedNumIncreasing(leveldb::Slice* src, int64_t* result);
+ static bool ReadString(absl::string_view* src, std::string* result);
+ static bool ReadNumIncreasing(absl::string_view* src, uint64_t* result);
+ static bool ReadSignedNumIncreasing(absl::string_view* src, int64_t* result);
- static bool ReadInfinity(leveldb::Slice* src);
- static bool ReadTrailingString(leveldb::Slice* src, std::string* result);
+ static bool ReadInfinity(absl::string_view* src);
+ static bool ReadTrailingString(absl::string_view* src, std::string* result);
- // REQUIRES: next item was encoded by WriteInfinity() or WriteString()
- static bool ReadStringOrInfinity(leveldb::Slice* src, std::string* result, bool* inf);
+ /** REQUIRES: next item was encoded by WriteInfinity() or WriteString(). */
+ static bool ReadStringOrInfinity(absl::string_view* src,
+ std::string* result,
+ bool* inf);
- // Helper for testing: corrupt "*str" by changing the kth item separator
- // in the string.
+ /**
+ * Helper for testing: corrupt "*str" by changing the kth item separator
+ * in the string.
+ */
static void TEST_Corrupt(std::string* str, int k);
- // Helper for testing.
- // SkipToNextSpecialByte is an internal routine defined in the .cc file
- // with the following semantics. Return a pointer to the first byte
- // in the range "[start..limit)" whose value is 0 or 255. If no such
- // byte exists in the range, returns "limit".
- static const char* TEST_SkipToNextSpecialByte(const char* start, const char* limit);
+ /**
+ * Helper for testing.
+ * SkipToNextSpecialByte is an internal routine defined in the .cc file
+ * with the following semantics. Return a pointer to the first byte
+ * in the range "[start..limit)" whose value is 0 or 255. If no such
+ * byte exists in the range, returns "limit".
+ */
+ static const char* TEST_SkipToNextSpecialByte(const char* start,
+ const char* limit);
// Not an instantiable class, but the class exists to make it easy to
// use with a single using statement.
@@ -111,6 +122,8 @@ class OrderedCode {
OrderedCode& operator=(const OrderedCode&) = delete;
};
-} // namespace Firestore
+} // namespace util
+} // namespace firestore
+} // namespace firebase
-#endif // IPHONE_FIRESTORE_PORT_ORDERED_CODE_H_
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ORDERED_CODE_H_
diff --git a/Firestore/core/src/firebase/firestore/util/secure_random.h b/Firestore/core/src/firebase/firestore/util/secure_random.h
index 72be1bd..95b41e1 100644
--- a/Firestore/core/src/firebase/firestore/util/secure_random.h
+++ b/Firestore/core/src/firebase/firestore/util/secure_random.h
@@ -50,6 +50,22 @@ class SecureRandom {
}
result_type operator()();
+
+ /** Returns a uniformly distributed pseudorandom integer in [0, n). */
+ inline result_type Uniform(result_type n) {
+ // Divides the range into buckets of size n plus leftovers.
+ const result_type rem = (max() - min()) % n + min() + 1;
+ result_type rnd;
+ // Generates random number until the number falls into a bucket.
+ do {
+ rnd = (*this)();
+ } while (rnd < rem);
+ return rnd % n;
+ }
+
+ inline bool OneIn(result_type n) {
+ return Uniform(n) == 0;
+ }
};
} // namespace util
diff --git a/Firestore/core/src/firebase/firestore/util/secure_random_arc4random.cc b/Firestore/core/src/firebase/firestore/util/secure_random_arc4random.cc
index a76ade3..83f72b5 100644
--- a/Firestore/core/src/firebase/firestore/util/secure_random_arc4random.cc
+++ b/Firestore/core/src/firebase/firestore/util/secure_random_arc4random.cc
@@ -16,7 +16,7 @@
#include "Firestore/core/src/firebase/firestore/util/secure_random.h"
-#include "Firestore/core/src/firebase/firestore/base/port.h"
+#include "Firestore/core/src/firebase/firestore/util/config.h"
#if HAVE_ARC4RANDOM
diff --git a/Firestore/core/src/firebase/firestore/util/secure_random_openssl.cc b/Firestore/core/src/firebase/firestore/util/secure_random_openssl.cc
new file mode 100644
index 0000000..d3f6e63
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/secure_random_openssl.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/secure_random.h"
+
+#include "Firestore/core/src/firebase/firestore/util/config.h"
+
+#if HAVE_OPENSSL_RAND_H
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+SecureRandom::result_type SecureRandom::operator()() {
+ result_type result;
+ int rc = RAND_bytes(reinterpret_cast<uint8_t*>(&result), sizeof(result));
+ if (rc <= 0) {
+ // OpenSSL's RAND_bytes can fail if there's not enough entropy. BoringSSL
+ // won't fail this way.
+ ERR_print_errors_fp(stderr);
+ abort();
+ }
+ return result;
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // HAVE_OPENSSL_RAND_H
diff --git a/Firestore/core/src/firebase/firestore/util/string_apple.h b/Firestore/core/src/firebase/firestore/util/string_apple.h
new file mode 100644
index 0000000..108ade7
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_apple.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_
+
+// Everything in this header exists for compatibility with Objective-C.
+#if __OBJC__
+
+#import <Foundation/Foundation.h>
+
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+// Translates a C string to the equivalent NSString without making a copy.
+inline NSString* WrapNSStringNoCopy(const char* c_str) {
+ return [[NSString alloc]
+ initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(c_str))
+ length:strlen(c_str)
+ encoding:NSUTF8StringEncoding
+ freeWhenDone:NO];
+}
+
+// Creates an absl::string_view wrapper for the contents of the given NSString.
+inline absl::string_view MakeStringView(NSString* str) {
+ return absl::string_view(
+ [str UTF8String], [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // __OBJC__
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_
diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.cc b/Firestore/core/src/firebase/firestore/util/string_printf.cc
new file mode 100644
index 0000000..9c4e31c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_printf.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+
+#include <stdio.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+ // First try with a small fixed size buffer
+ static const int kSpaceLength = 1024;
+ char space[kSpaceLength];
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result < kSpaceLength) {
+ if (result >= 0) {
+ // Normal case -- everything fit.
+ dst->append(space, static_cast<size_t>(result));
+ return;
+ }
+
+#ifdef _MSC_VER
+ // Error or MSVC running out of space. MSVC 8.0 and higher
+ // can be asked about space needed with the special idiom below:
+ va_copy(backup_ap, ap);
+ result = vsnprintf(nullptr, 0, format, backup_ap);
+ va_end(backup_ap);
+#endif
+ }
+
+ if (result < 0) {
+ // Just an error.
+ return;
+ }
+ size_t result_size = static_cast<size_t>(result);
+
+ // Increase the buffer size to the size requested by vsnprintf,
+ // plus one for the closing \0.
+ size_t initial_size = dst->size();
+ size_t target_size = initial_size + result_size;
+
+ dst->resize(target_size + 1);
+ char* buf = &(*dst)[initial_size];
+ size_t buf_remain = result_size + 1;
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ result = vsnprintf(buf, buf_remain, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result >= 0 && static_cast<size_t>(result) < buf_remain) {
+ // It fit and vsnprintf copied in directly. Resize down one to
+ // remove the trailing \0.
+ dst->resize(target_size);
+ } else {
+ // Didn't fit. Leave the original string unchanged.
+ dst->resize(initial_size);
+ }
+}
+
+std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.h b/Firestore/core/src/firebase/firestore/util/string_printf.h
new file mode 100644
index 0000000..10dfae9
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_printf.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
+
+#include <stdarg.h>
+
+#include <string>
+
+#include "absl/base/attributes.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/** Return a C++ string. */
+std::string StringPrintf(const char* format, ...) ABSL_PRINTF_ATTRIBUTE(1, 2);
+
+/** Append result to a supplied string. */
+void StringAppendF(std::string* dst, const char* format, ...)
+ ABSL_PRINTF_ATTRIBUTE(2, 3);
+
+/**
+ * Lower-level routine that takes a va_list and appends to a specified
+ * string. All other routines are just convenience wrappers around it.
+ */
+void StringAppendV(std::string* dst, const char* format, va_list ap);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
diff --git a/Firestore/Port/string_util.cc b/Firestore/core/src/firebase/firestore/util/string_util.cc
index 2587860..b7f1ed9 100644
--- a/Firestore/Port/string_util.cc
+++ b/Firestore/core/src/firebase/firestore/util/string_util.cc
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-#include "Firestore/Port/string_util.h"
+#include "Firestore/core/src/firebase/firestore/util/string_util.h"
-#include <leveldb/db.h>
+namespace firebase {
+namespace firestore {
+namespace util {
-namespace Firestore {
-
-std::string PrefixSuccessor(leveldb::Slice prefix) {
+std::string PrefixSuccessor(absl::string_view prefix) {
// We can increment the last character in the string and be done
// unless that character is 255 (0xff), in which case we have to erase the
// last character and increment the previous character, unless that
// is 255, etc. If the string is empty or consists entirely of
// 255's, we just return the empty string.
- std::string limit(prefix.data(), prefix.size());
+ std::string limit(prefix);
while (!limit.empty()) {
size_t index = limit.length() - 1;
if (limit[index] == '\xff') { // char literal avoids signed/unsigned.
@@ -39,7 +39,7 @@ std::string PrefixSuccessor(leveldb::Slice prefix) {
return limit;
}
-std::string ImmediateSuccessor(leveldb::Slice s) {
+std::string ImmediateSuccessor(absl::string_view s) {
// Return the input string, with an additional NUL byte appended.
std::string out;
out.reserve(s.size() + 1);
@@ -48,4 +48,6 @@ std::string ImmediateSuccessor(leveldb::Slice s) {
return out;
}
-} // namespace Firestore
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/string_util.h b/Firestore/core/src/firebase/firestore/util/string_util.h
new file mode 100644
index 0000000..3de177d
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_util.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 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.
+ */
+
+// Useful string functions and so forth. This is a grab-bag file.
+//
+// These functions work fine for UTF-8 strings as long as you can
+// consider them to be just byte strings. For example, due to the
+// design of UTF-8 you do not need to worry about accidental matches,
+// as long as all your inputs are valid UTF-8 (use \uHHHH, not \xHH or \oOOO).
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_UTIL_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_UTIL_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+/*
+ * Returns the smallest lexicographically larger string of equal or smaller
+ * length. Returns an empty string if there is no such successor (if the input
+ * is empty or consists entirely of 0xff bytes).
+ * Useful for calculating the smallest lexicographically larger string
+ * that will not be prefixed by the input string.
+ *
+ * Examples:
+ * "a" -> "b", "aaa" -> "aab", "aa\xff" -> "ab", "\xff" -> "", "" -> ""
+ */
+std::string PrefixSuccessor(absl::string_view prefix);
+
+/*
+ * Returns the immediate lexicographically-following string. This is useful to
+ * turn an inclusive range into something that can be used with Bigtable's
+ * SetLimitRow():
+ *
+ * // Inclusive range [min_element, max_element].
+ * string min_element = ...;
+ * string max_element = ...;
+ *
+ * // Equivalent range [range_start, range_end).
+ * string range_start = min_element;
+ * string range_end = ImmediateSuccessor(max_element);
+ *
+ * WARNING: Returns the input string with a '\0' appended; if you call c_str()
+ * on the result, it will compare equal to s.
+ *
+ * WARNING: Transforms "" -> "\0"; this doesn't account for Bigtable's special
+ * treatment of "" as infinity.
+ */
+std::string ImmediateSuccessor(absl::string_view s);
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_UTIL_H_
diff --git a/Firestore/core/test/firebase/firestore/CMakeLists.txt b/Firestore/core/test/firebase/firestore/CMakeLists.txt
new file mode 100644
index 0000000..ed5760f
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright 2018 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.
+
+cc_test(
+ firebase_firestore_types_test
+ SOURCES
+ geo_point_test.cc
+ DEPENDS
+ firebase_firestore_types
+)
diff --git a/Firestore/core/test/firebase/firestore/core/CMakeLists.txt b/Firestore/core/test/firebase/firestore/core/CMakeLists.txt
new file mode 100644
index 0000000..34993aa
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/core/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright 2018 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.
+
+cc_test(
+ firebase_firestore_core_test
+ SOURCES
+ target_id_generator_test.cc
+ DEPENDS
+ firebase_firestore_core
+)
diff --git a/Firestore/core/test/firebase/firestore/core/target_id_generator_test.cc b/Firestore/core/test/firebase/firestore/core/target_id_generator_test.cc
new file mode 100644
index 0000000..7eca335
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/core/target_id_generator_test.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h"
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace core {
+
+TEST(TargetIdGenerator, Constructor) {
+ TargetIdGenerator local_store_generator =
+ TargetIdGenerator::LocalStoreTargetIdGenerator(0);
+ TargetIdGenerator sync_engine_generator =
+ TargetIdGenerator::SyncEngineTargetIdGenerator(0);
+ EXPECT_EQ(TargetIdGeneratorId::LocalStore,
+ local_store_generator.generator_id());
+ EXPECT_EQ(2, local_store_generator.NextId());
+ EXPECT_EQ(TargetIdGeneratorId::SyncEngine,
+ sync_engine_generator.generator_id());
+ EXPECT_EQ(1, sync_engine_generator.NextId());
+}
+
+TEST(TargetIdGenerator, SkipPast) {
+ EXPECT_EQ(1, TargetIdGenerator::SyncEngineTargetIdGenerator(-1).NextId());
+ EXPECT_EQ(3, TargetIdGenerator::SyncEngineTargetIdGenerator(2).NextId());
+ EXPECT_EQ(5, TargetIdGenerator::SyncEngineTargetIdGenerator(4).NextId());
+
+ for (int i = 4; i < 12; ++i) {
+ TargetIdGenerator a = TargetIdGenerator::LocalStoreTargetIdGenerator(i);
+ TargetIdGenerator b = TargetIdGenerator::SyncEngineTargetIdGenerator(i);
+ EXPECT_EQ((i + 2) & ~1, a.NextId());
+ EXPECT_EQ((i + 1) | 1, b.NextId());
+ }
+
+ EXPECT_EQ(13, TargetIdGenerator::SyncEngineTargetIdGenerator(12).NextId());
+ EXPECT_EQ(24, TargetIdGenerator::LocalStoreTargetIdGenerator(22).NextId());
+}
+
+TEST(TargetIdGenerator, Increment) {
+ TargetIdGenerator a = TargetIdGenerator::LocalStoreTargetIdGenerator(0);
+ EXPECT_EQ(2, a.NextId());
+ EXPECT_EQ(4, a.NextId());
+ EXPECT_EQ(6, a.NextId());
+
+ TargetIdGenerator b = TargetIdGenerator::LocalStoreTargetIdGenerator(46);
+ EXPECT_EQ(48, b.NextId());
+ EXPECT_EQ(50, b.NextId());
+ EXPECT_EQ(52, b.NextId());
+ EXPECT_EQ(54, b.NextId());
+
+ TargetIdGenerator c = TargetIdGenerator::SyncEngineTargetIdGenerator(0);
+ EXPECT_EQ(1, c.NextId());
+ EXPECT_EQ(3, c.NextId());
+ EXPECT_EQ(5, c.NextId());
+
+ TargetIdGenerator d = TargetIdGenerator::SyncEngineTargetIdGenerator(46);
+ EXPECT_EQ(47, d.NextId());
+ EXPECT_EQ(49, d.NextId());
+ EXPECT_EQ(51, d.NextId());
+ EXPECT_EQ(53, d.NextId());
+}
+
+} // namespace core
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/geo_point_test.cc b/Firestore/core/test/firebase/firestore/geo_point_test.cc
new file mode 100644
index 0000000..bd8d76f
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/geo_point_test.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/include/firebase/firestore/geo_point.h"
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+
+TEST(GeoPoint, Getter) {
+ const GeoPoint zero;
+ EXPECT_EQ(0, zero.latitude());
+ EXPECT_EQ(0, zero.longitude());
+
+ const GeoPoint point{12, 34};
+ EXPECT_EQ(12, point.latitude());
+ EXPECT_EQ(34, point.longitude());
+}
+
+TEST(GeoPoint, Comparison) {
+ EXPECT_EQ(GeoPoint(12, 34), GeoPoint(12, 34));
+ EXPECT_LT(GeoPoint(12, 34), GeoPoint(34, 12));
+ EXPECT_LT(GeoPoint(12, 34), GeoPoint(12, 56));
+}
+
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/immutable/CMakeLists.txt b/Firestore/core/test/firebase/firestore/immutable/CMakeLists.txt
new file mode 100644
index 0000000..e7b0b6e
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/immutable/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright 2018 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.
+
+cc_test(
+ firebase_firestore_immutable_test
+ SOURCES
+ array_sorted_map_test.cc
+ DEPENDS
+ firebase_firestore_immutable
+ firebase_firestore_util
+)
diff --git a/Firestore/core/test/firebase/firestore/immutable/array_sorted_map_test.cc b/Firestore/core/test/firebase/firestore/immutable/array_sorted_map_test.cc
new file mode 100644
index 0000000..3ec1e64
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/immutable/array_sorted_map_test.cc
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h"
+
+#include <numeric>
+#include <random>
+
+#include "Firestore/core/src/firebase/firestore/util/secure_random.h"
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace immutable {
+
+typedef ArraySortedMap<int, int> IntMap;
+constexpr IntMap::size_type kFixedSize = IntMap::kFixedSize;
+
+template <typename K, typename V>
+testing::AssertionResult NotFound(const ArraySortedMap<K, V>& set,
+ const K& key) {
+ auto found = set.find(key);
+ if (found == set.end()) {
+ return testing::AssertionSuccess();
+ } else {
+ return testing::AssertionFailure()
+ << "Should not have found (" << found->first << ", " << found->second
+ << ") @ " << found;
+ }
+}
+
+template <typename K, typename V>
+testing::AssertionResult Found(const ArraySortedMap<K, V>& map,
+ const K& key,
+ const V& expected) {
+ auto found = map.find(key);
+ if (found == map.end()) {
+ return testing::AssertionFailure() << "Did not find key " << key;
+ }
+ if (found->second == expected) {
+ return testing::AssertionSuccess();
+ } else {
+ return testing::AssertionFailure() << "Found entry was (" << found->first
+ << ", " << found->second << ")";
+ }
+}
+
+/**
+ * Creates a vector containing a sequence of integers from the given starting
+ * element up to, but not including, the given end element, with values
+ * incremented by the given step.
+ *
+ * If step is negative the sequence is in descending order (but still starting
+ * at start and ending before end).
+ */
+std::vector<int> Sequence(int start, int end, int step = 1) {
+ std::vector<int> result;
+ if (step > 0) {
+ for (int i = start; i < end; i += step) {
+ result.push_back(i);
+ }
+ } else {
+ for (int i = start; i > end; i += step) {
+ result.push_back(i);
+ }
+ }
+ return result;
+}
+
+/**
+ * Creates a vector containing a sequence of integers with the given number of
+ * elements, from zero up to, but not including the given value.
+ */
+std::vector<int> Sequence(int num_elements) {
+ return Sequence(0, num_elements);
+}
+
+/**
+ * Creates a copy of the given vector with contents shuffled randomly.
+ */
+std::vector<int> Shuffled(const std::vector<int>& values) {
+ std::vector<int> result(values);
+ util::SecureRandom rng;
+ std::shuffle(result.begin(), result.end(), rng);
+ return result;
+}
+
+/**
+ * Creates a copy of the given vector with contents sorted.
+ */
+std::vector<int> Sorted(const std::vector<int>& values) {
+ std::vector<int> result(values);
+ std::sort(result.begin(), result.end());
+ return result;
+}
+
+/**
+ * Creates a vector of pairs where each pair has the same first and second
+ * corresponding to an element in the given vector.
+ */
+std::vector<std::pair<int, int>> Pairs(const std::vector<int>& values) {
+ std::vector<std::pair<int, int>> result;
+ for (auto&& value : values) {
+ result.emplace_back(value, value);
+ }
+ return result;
+}
+
+/**
+ * Creates an ArraySortedMap by inserting a pair for each value in the vector.
+ * Each pair will have the same key and value.
+ */
+IntMap ToMap(const std::vector<int>& values) {
+ IntMap result;
+ for (auto&& value : values) {
+ result = result.insert(value, value);
+ }
+ return result;
+}
+
+/**
+ * Appends the contents of the given container to a new vector.
+ */
+template <typename Container>
+std::vector<typename Container::value_type> Append(const Container& container) {
+ std::vector<typename Container::value_type> result;
+ result.insert(result.begin(), container.begin(), container.end());
+ return result;
+}
+
+// TODO(wilhuff): ReverseTraversal
+
+#define ASSERT_SEQ_EQ(x, y) ASSERT_EQ((x), Append(y));
+#define EXPECT_SEQ_EQ(x, y) EXPECT_EQ((x), Append(y));
+
+TEST(ArraySortedMap, SearchForSpecificKey) {
+ IntMap map{{1, 3}, {2, 4}};
+
+ ASSERT_TRUE(Found(map, 1, 3));
+ ASSERT_TRUE(Found(map, 2, 4));
+ ASSERT_TRUE(NotFound(map, 3));
+}
+
+TEST(ArraySortedMap, RemoveKeyValuePair) {
+ IntMap map{{1, 3}, {2, 4}};
+
+ IntMap new_map = map.erase(1);
+ ASSERT_TRUE(Found(new_map, 2, 4));
+ ASSERT_TRUE(NotFound(new_map, 1));
+
+ // Make sure the original one is not mutated
+ ASSERT_TRUE(Found(map, 1, 3));
+ ASSERT_TRUE(Found(map, 2, 4));
+}
+
+TEST(ArraySortedMap, MoreRemovals) {
+ IntMap map = IntMap()
+ .insert(1, 1)
+ .insert(50, 50)
+ .insert(3, 3)
+ .insert(4, 4)
+ .insert(7, 7)
+ .insert(9, 9)
+ .insert(1, 20)
+ .insert(18, 18)
+ .insert(3, 2)
+ .insert(4, 71)
+ .insert(7, 42)
+ .insert(9, 88);
+
+ ASSERT_TRUE(Found(map, 7, 42));
+ ASSERT_TRUE(Found(map, 3, 2));
+ ASSERT_TRUE(Found(map, 1, 20));
+
+ IntMap s1 = map.erase(7);
+ IntMap s2 = map.erase(3);
+ IntMap s3 = map.erase(1);
+
+ ASSERT_TRUE(NotFound(s1, 7));
+ ASSERT_TRUE(Found(s1, 3, 2));
+ ASSERT_TRUE(Found(s1, 1, 20));
+
+ ASSERT_TRUE(Found(s2, 7, 42));
+ ASSERT_TRUE(NotFound(s2, 3));
+ ASSERT_TRUE(Found(s2, 1, 20));
+
+ ASSERT_TRUE(Found(s3, 7, 42));
+ ASSERT_TRUE(Found(s3, 3, 2));
+ ASSERT_TRUE(NotFound(s3, 1));
+}
+
+TEST(ArraySortedMap, RemovesMiddle) {
+ IntMap map{{1, 1}, {2, 2}, {3, 3}};
+ ASSERT_TRUE(Found(map, 1, 1));
+ ASSERT_TRUE(Found(map, 2, 2));
+ ASSERT_TRUE(Found(map, 3, 3));
+
+ IntMap s1 = map.erase(2);
+ ASSERT_TRUE(Found(s1, 1, 1));
+ ASSERT_TRUE(NotFound(s1, 2));
+ ASSERT_TRUE(Found(s1, 3, 3));
+}
+
+TEST(ArraySortedMap, Increasing) {
+ auto total = static_cast<int>(kFixedSize);
+ IntMap map;
+
+ for (int i = 0; i < total; i++) {
+ map = map.insert(i, i);
+ }
+ ASSERT_EQ(kFixedSize, map.size());
+
+ for (int i = 0; i < total; i++) {
+ map = map.erase(i);
+ }
+ ASSERT_EQ(0u, map.size());
+}
+
+TEST(ArraySortedMap, Override) {
+ IntMap map = IntMap().insert(10, 10).insert(10, 8);
+
+ ASSERT_TRUE(Found(map, 10, 8));
+ ASSERT_FALSE(Found(map, 10, 10));
+}
+
+TEST(ArraySortedMap, ChecksSize) {
+ std::vector<int> to_insert = Sequence(kFixedSize);
+ IntMap map = ToMap(to_insert);
+
+ // Replacing an existing entry should not hit increase size
+ map = map.insert(5, 10);
+
+ int next = kFixedSize;
+ ASSERT_DEATH_IF_SUPPORTED(map.insert(next, next), "new_size <= fixed_size");
+}
+
+TEST(ArraySortedMap, Empty) {
+ IntMap map = IntMap().insert(10, 10).erase(10);
+ EXPECT_TRUE(map.empty());
+ EXPECT_EQ(0u, map.size());
+ EXPECT_TRUE(NotFound(map, 1));
+ EXPECT_TRUE(NotFound(map, 10));
+}
+
+TEST(ArraySortedMap, EmptyGet) {
+ IntMap map;
+ EXPECT_TRUE(NotFound(map, 10));
+}
+
+TEST(ArraySortedMap, EmptySize) {
+ IntMap map;
+ EXPECT_TRUE(map.empty());
+ EXPECT_EQ(0u, map.size());
+}
+
+TEST(ArraySortedMap, EmptyRemoval) {
+ IntMap map;
+ IntMap new_map = map.erase(1);
+ EXPECT_TRUE(new_map.empty());
+ EXPECT_EQ(0u, new_map.size());
+ EXPECT_TRUE(NotFound(new_map, 1));
+}
+
+TEST(ArraySortedMap, InsertionAndRemovalOfMaxItems) {
+ auto expected_size = kFixedSize;
+ int n = static_cast<int>(expected_size);
+ std::vector<int> to_insert = Shuffled(Sequence(n));
+ std::vector<int> to_remove = Shuffled(to_insert);
+
+ // Add them to the map
+ IntMap map = ToMap(to_insert);
+ ASSERT_EQ(expected_size, map.size())
+ << "Check if all N objects are in the map";
+
+ // check the order is correct
+ ASSERT_SEQ_EQ(Pairs(Sorted(to_insert)), map);
+
+ for (int i : to_remove) {
+ map = map.erase(i);
+ }
+ ASSERT_EQ(0u, map.size()) << "Check we removed all of the items";
+}
+
+TEST(ArraySortedMap, BalanceProblem) {
+ std::vector<int> to_insert{1, 7, 8, 5, 2, 6, 4, 0, 3};
+
+ IntMap map = ToMap(to_insert);
+ ASSERT_SEQ_EQ(Pairs(Sorted(to_insert)), map);
+}
+
+// TODO(wilhuff): Iterators
+
+// TODO(wilhuff): IndexOf
+
+TEST(ArraySortedMap, AvoidsCopying) {
+ IntMap map = IntMap().insert(10, 20);
+ auto found = map.find(10);
+ ASSERT_NE(found, map.end());
+ EXPECT_EQ(20, found->second);
+
+ // Verify that inserting something with equal keys and values just returns
+ // the same underlying array.
+ IntMap duped = map.insert(10, 20);
+ auto duped_found = duped.find(10);
+
+ // If everything worked correctly, the backing array should not have been
+ // copied and the pointer to the entry with 10 as key should be the same.
+ EXPECT_EQ(found, duped_found);
+}
+
+} // namespace immutable
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
new file mode 100644
index 0000000..0f83bf2
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright 2018 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.
+
+cc_test(
+ firebase_firestore_model_test
+ SOURCES
+ database_id_test.cc
+ field_value_test.cc
+ timestamp_test.cc
+ DEPENDS
+ firebase_firestore_model
+)
diff --git a/Firestore/core/test/firebase/firestore/model/database_id_test.cc b/Firestore/core/test/firebase/firestore/model/database_id_test.cc
new file mode 100644
index 0000000..e9c9439
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/model/database_id_test.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/database_id.h"
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+TEST(DatabaseId, Constructor) {
+ DatabaseId id("p", "d");
+ EXPECT_EQ("p", id.project_id());
+ EXPECT_EQ("d", id.database_id());
+ EXPECT_FALSE(id.IsDefaultDatabase());
+}
+
+TEST(DatabaseId, DefaultDb) {
+ DatabaseId id("p", DatabaseId::kDefaultDatabaseId);
+ EXPECT_EQ("p", id.project_id());
+ EXPECT_EQ(DatabaseId::kDefaultDatabaseId, id.database_id());
+ EXPECT_TRUE(id.IsDefaultDatabase());
+}
+
+TEST(DatabaseId, Comparison) {
+ EXPECT_LT(DatabaseId("a", "b"), DatabaseId("b", "a"));
+ EXPECT_LT(DatabaseId("a", "b"), DatabaseId("a", "c"));
+ EXPECT_EQ(DatabaseId("a", "b"), DatabaseId("a", "b"));
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/model/field_value_test.cc b/Firestore/core/test/firebase/firestore/model/field_value_test.cc
new file mode 100644
index 0000000..702c0f6
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/model/field_value_test.cc
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/field_value.h"
+
+#include <limits.h>
+
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+using Type = FieldValue::Type;
+
+namespace {
+
+const uint8_t* Bytes(const char* value) {
+ return reinterpret_cast<const uint8_t*>(value);
+}
+
+} // namespace
+
+TEST(FieldValue, NullType) {
+ const FieldValue value = FieldValue::NullValue();
+ EXPECT_EQ(Type::Null, value.type());
+ EXPECT_FALSE(value < value);
+}
+
+TEST(FieldValue, BooleanType) {
+ const FieldValue true_value = FieldValue::BooleanValue(true);
+ const FieldValue false_value = FieldValue::BooleanValue(false);
+ EXPECT_EQ(Type::Boolean, true_value.type());
+ EXPECT_FALSE(true_value < true_value);
+ EXPECT_FALSE(true_value < false_value);
+ EXPECT_FALSE(false_value < false_value);
+ EXPECT_TRUE(false_value < true_value);
+}
+
+TEST(FieldValue, NumberType) {
+ const FieldValue nan_value = FieldValue::NanValue();
+ const FieldValue integer_value = FieldValue::IntegerValue(10L);
+ const FieldValue double_value = FieldValue::DoubleValue(10.1);
+ EXPECT_EQ(Type::Double, nan_value.type());
+ EXPECT_EQ(Type::Long, integer_value.type());
+ EXPECT_EQ(Type::Double, double_value.type());
+ EXPECT_TRUE(nan_value < integer_value);
+ EXPECT_TRUE(nan_value < double_value);
+ EXPECT_FALSE(nan_value < nan_value);
+ EXPECT_FALSE(integer_value < nan_value);
+ EXPECT_FALSE(integer_value < nan_value);
+ EXPECT_TRUE(integer_value < double_value); // 10 < 10.1
+ EXPECT_FALSE(double_value < integer_value);
+ EXPECT_FALSE(integer_value < integer_value);
+ EXPECT_FALSE(double_value < double_value);
+
+ // Number comparison craziness
+ // Integers
+ EXPECT_TRUE(FieldValue::IntegerValue(1L) < FieldValue::IntegerValue(2L));
+ EXPECT_FALSE(FieldValue::IntegerValue(1L) < FieldValue::IntegerValue(1L));
+ EXPECT_FALSE(FieldValue::IntegerValue(2L) < FieldValue::IntegerValue(1L));
+ // Doubles
+ EXPECT_TRUE(FieldValue::DoubleValue(1.0) < FieldValue::DoubleValue(2.0));
+ EXPECT_FALSE(FieldValue::DoubleValue(1.0) < FieldValue::DoubleValue(1.0));
+ EXPECT_FALSE(FieldValue::DoubleValue(2.0) < FieldValue::DoubleValue(1.0));
+ EXPECT_TRUE(FieldValue::NanValue() < FieldValue::DoubleValue(1.0));
+ EXPECT_FALSE(FieldValue::NanValue() < FieldValue::NanValue());
+ EXPECT_FALSE(FieldValue::DoubleValue(1.0) < FieldValue::NanValue());
+ // Mixed
+ EXPECT_TRUE(FieldValue::DoubleValue(-1e20) <
+ FieldValue::IntegerValue(LLONG_MIN));
+ EXPECT_FALSE(FieldValue::DoubleValue(1e20) <
+ FieldValue::IntegerValue(LLONG_MAX));
+ EXPECT_TRUE(FieldValue::DoubleValue(1.234) < FieldValue::IntegerValue(2L));
+ EXPECT_FALSE(FieldValue::DoubleValue(2.345) < FieldValue::IntegerValue(1L));
+ EXPECT_FALSE(FieldValue::DoubleValue(1.0) < FieldValue::IntegerValue(1L));
+ EXPECT_FALSE(FieldValue::DoubleValue(1.234) < FieldValue::IntegerValue(1L));
+ EXPECT_FALSE(FieldValue::IntegerValue(LLONG_MIN) <
+ FieldValue::DoubleValue(-1e20));
+ EXPECT_TRUE(FieldValue::IntegerValue(LLONG_MAX) <
+ FieldValue::DoubleValue(1e20));
+ EXPECT_FALSE(FieldValue::IntegerValue(1) < FieldValue::DoubleValue(1.0));
+ EXPECT_TRUE(FieldValue::IntegerValue(1) < FieldValue::DoubleValue(1.234));
+}
+
+TEST(FieldValue, TimestampType) {
+ const FieldValue o = FieldValue::TimestampValue(Timestamp());
+ const FieldValue a = FieldValue::TimestampValue({100, 0});
+ const FieldValue b = FieldValue::TimestampValue({200, 0});
+ EXPECT_EQ(Type::Timestamp, a.type());
+ EXPECT_TRUE(o < a);
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(a < a);
+ const FieldValue c = FieldValue::ServerTimestampValue({100, 0});
+ const FieldValue d = FieldValue::ServerTimestampValue({200, 0}, {300, 0});
+ EXPECT_EQ(Type::ServerTimestamp, c.type());
+ EXPECT_EQ(Type::ServerTimestamp, d.type());
+ EXPECT_TRUE(c < d);
+ EXPECT_FALSE(c < c);
+ // Mixed
+ EXPECT_TRUE(o < c);
+ EXPECT_TRUE(a < c);
+ EXPECT_TRUE(b < c);
+ EXPECT_TRUE(b < d);
+ EXPECT_FALSE(c < o);
+ EXPECT_FALSE(c < a);
+ EXPECT_FALSE(c < b);
+ EXPECT_FALSE(d < b);
+}
+
+TEST(FieldValue, StringType) {
+ const FieldValue a = FieldValue::StringValue("abc");
+ std::string xyz("xyz");
+ const FieldValue b = FieldValue::StringValue(xyz);
+ const FieldValue c = FieldValue::StringValue(std::move(xyz));
+ EXPECT_EQ(Type::String, a.type());
+ EXPECT_EQ(Type::String, b.type());
+ EXPECT_EQ(Type::String, c.type());
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(a < a);
+}
+
+TEST(FieldValue, BlobType) {
+ const FieldValue a = FieldValue::BlobValue(Bytes("abc"), 4);
+ const FieldValue b = FieldValue::BlobValue(Bytes("def"), 4);
+ EXPECT_EQ(Type::Blob, a.type());
+ EXPECT_EQ(Type::Blob, b.type());
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(a < a);
+}
+
+TEST(FieldValue, GeoPointType) {
+ const FieldValue a = FieldValue::GeoPointValue({1, 2});
+ const FieldValue b = FieldValue::GeoPointValue({3, 4});
+ EXPECT_EQ(Type::GeoPoint, a.type());
+ EXPECT_EQ(Type::GeoPoint, b.type());
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(a < a);
+}
+
+TEST(FieldValue, ArrayType) {
+ const FieldValue empty = FieldValue::ArrayValue(std::vector<FieldValue>{});
+ std::vector<FieldValue> array{FieldValue::NullValue(),
+ FieldValue::BooleanValue(true),
+ FieldValue::BooleanValue(false)};
+ // copy the array
+ const FieldValue small = FieldValue::ArrayValue(array);
+ std::vector<FieldValue> another_array{FieldValue::BooleanValue(true),
+ FieldValue::BooleanValue(false)};
+ // move the array
+ const FieldValue large = FieldValue::ArrayValue(std::move(another_array));
+ EXPECT_EQ(Type::Array, empty.type());
+ EXPECT_EQ(Type::Array, small.type());
+ EXPECT_EQ(Type::Array, large.type());
+ EXPECT_TRUE(empty < small);
+ EXPECT_FALSE(small < empty);
+ EXPECT_FALSE(small < small);
+ EXPECT_TRUE(small < large);
+ EXPECT_FALSE(large < small);
+}
+
+TEST(FieldValue, ObjectType) {
+ const FieldValue empty =
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{});
+ std::map<const std::string, const FieldValue> object{
+ {"null", FieldValue::NullValue()},
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}};
+ // copy the map
+ const FieldValue small = FieldValue::ObjectValue(object);
+ std::map<const std::string, const FieldValue> another_object{
+ {"null", FieldValue::NullValue()}, {"true", FieldValue::FalseValue()}};
+ // move the array
+ const FieldValue large = FieldValue::ObjectValue(std::move(another_object));
+ EXPECT_EQ(Type::Object, empty.type());
+ EXPECT_EQ(Type::Object, small.type());
+ EXPECT_EQ(Type::Object, large.type());
+ EXPECT_TRUE(empty < small);
+ EXPECT_FALSE(small < empty);
+ EXPECT_FALSE(small < small);
+ EXPECT_TRUE(small < large);
+ EXPECT_FALSE(large < small);
+}
+
+TEST(FieldValue, Copy) {
+ FieldValue clone = FieldValue::TrueValue();
+ const FieldValue null_value = FieldValue::NullValue();
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+ EXPECT_EQ(FieldValue::NullValue(), null_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue true_value = FieldValue::TrueValue();
+ clone = true_value;
+ EXPECT_EQ(FieldValue::TrueValue(), clone);
+ EXPECT_EQ(FieldValue::TrueValue(), true_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::TrueValue(), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue nan_value = FieldValue::NanValue();
+ clone = nan_value;
+ EXPECT_EQ(FieldValue::NanValue(), clone);
+ EXPECT_EQ(FieldValue::NanValue(), nan_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::NanValue(), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue integer_value = FieldValue::IntegerValue(1L);
+ clone = integer_value;
+ EXPECT_EQ(FieldValue::IntegerValue(1L), clone);
+ EXPECT_EQ(FieldValue::IntegerValue(1L), integer_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::IntegerValue(1L), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue double_value = FieldValue::DoubleValue(1.0);
+ clone = double_value;
+ EXPECT_EQ(FieldValue::DoubleValue(1.0), clone);
+ EXPECT_EQ(FieldValue::DoubleValue(1.0), double_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::DoubleValue(1.0), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200});
+ clone = timestamp_value;
+ EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone);
+ EXPECT_EQ(FieldValue::TimestampValue({100, 200}), timestamp_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue server_timestamp_value =
+ FieldValue::ServerTimestampValue({1, 2}, {3, 4});
+ clone = server_timestamp_value;
+ EXPECT_EQ(FieldValue::ServerTimestampValue({1, 2}, {3, 4}), clone);
+ EXPECT_EQ(FieldValue::ServerTimestampValue({1, 2}, {3, 4}),
+ server_timestamp_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::ServerTimestampValue({1, 2}, {3, 4}), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue string_value = FieldValue::StringValue("abc");
+ clone = string_value;
+ EXPECT_EQ(FieldValue::StringValue("abc"), clone);
+ EXPECT_EQ(FieldValue::StringValue("abc"), string_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::StringValue("abc"), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4);
+ clone = blob_value;
+ EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), clone);
+ EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), blob_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2});
+ clone = geo_point_value;
+ EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone);
+ EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), geo_point_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue array_value = FieldValue::ArrayValue(std::vector<FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()});
+ clone = array_value;
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ clone);
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ array_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue object_value =
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}});
+ clone = object_value;
+ EXPECT_EQ(
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}}),
+ clone);
+ EXPECT_EQ(
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}}),
+ object_value);
+ clone = clone;
+ EXPECT_EQ(
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}}),
+ clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+}
+
+TEST(FieldValue, Move) {
+ FieldValue clone = FieldValue::TrueValue();
+
+ FieldValue null_value = FieldValue::NullValue();
+ clone = std::move(null_value);
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue true_value = FieldValue::TrueValue();
+ clone = std::move(true_value);
+ EXPECT_EQ(FieldValue::TrueValue(), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue nan_value = FieldValue::NanValue();
+ clone = std::move(nan_value);
+ EXPECT_EQ(FieldValue::NanValue(), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue integer_value = FieldValue::IntegerValue(1L);
+ clone = std::move(integer_value);
+ EXPECT_EQ(FieldValue::IntegerValue(1L), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue double_value = FieldValue::DoubleValue(1.0);
+ clone = std::move(double_value);
+ EXPECT_EQ(FieldValue::DoubleValue(1.0), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200});
+ clone = std::move(timestamp_value);
+ EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue string_value = FieldValue::StringValue("abc");
+ clone = std::move(string_value);
+ EXPECT_EQ(FieldValue::StringValue("abc"), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4);
+ clone = std::move(blob_value);
+ EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2});
+ clone = std::move(geo_point_value);
+ EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue array_value = FieldValue::ArrayValue(std::vector<FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()});
+ clone = std::move(array_value);
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue object_value =
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}});
+ clone = std::move(object_value);
+ EXPECT_EQ(
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>{
+ {"true", FieldValue::TrueValue()},
+ {"false", FieldValue::FalseValue()}}),
+ clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+}
+
+TEST(FieldValue, CompareMixedType) {
+ const FieldValue null_value = FieldValue::NullValue();
+ const FieldValue true_value = FieldValue::TrueValue();
+ const FieldValue number_value = FieldValue::NanValue();
+ const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200});
+ const FieldValue string_value = FieldValue::StringValue("abc");
+ const FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4);
+ const FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2});
+ const FieldValue array_value =
+ FieldValue::ArrayValue(std::vector<FieldValue>());
+ const FieldValue object_value =
+ FieldValue::ObjectValue(std::map<const std::string, const FieldValue>());
+ EXPECT_TRUE(null_value < true_value);
+ EXPECT_TRUE(true_value < number_value);
+ EXPECT_TRUE(number_value < timestamp_value);
+ EXPECT_TRUE(timestamp_value < string_value);
+ EXPECT_TRUE(string_value < blob_value);
+ EXPECT_TRUE(blob_value < geo_point_value);
+ EXPECT_TRUE(geo_point_value < array_value);
+ EXPECT_TRUE(array_value < object_value);
+}
+
+TEST(FieldValue, CompareWithOperator) {
+ const FieldValue small = FieldValue::NullValue();
+ const FieldValue large = FieldValue::TrueValue();
+
+ EXPECT_TRUE(small < large);
+ EXPECT_FALSE(small < small);
+ EXPECT_FALSE(large < small);
+
+ EXPECT_TRUE(large > small);
+ EXPECT_FALSE(small > small);
+ EXPECT_FALSE(small > large);
+
+ EXPECT_TRUE(large >= small);
+ EXPECT_TRUE(small >= small);
+ EXPECT_FALSE(small >= large);
+
+ EXPECT_TRUE(small <= large);
+ EXPECT_TRUE(small <= small);
+ EXPECT_FALSE(large <= small);
+
+ EXPECT_TRUE(small != large);
+ EXPECT_FALSE(small != small);
+
+ EXPECT_TRUE(small == small);
+ EXPECT_FALSE(small == large);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/model/timestamp_test.cc b/Firestore/core/test/firebase/firestore/model/timestamp_test.cc
new file mode 100644
index 0000000..55ee378
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/model/timestamp_test.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
+
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+TEST(Timestamp, Getter) {
+ const Timestamp timestamp_zero;
+ EXPECT_EQ(0, timestamp_zero.seconds());
+ EXPECT_EQ(0, timestamp_zero.nanos());
+
+ const Timestamp timestamp(100, 200);
+ EXPECT_EQ(100, timestamp.seconds());
+ EXPECT_EQ(200, timestamp.nanos());
+
+ const Timestamp timestamp_now = Timestamp::Now();
+ EXPECT_LT(0, timestamp_now.seconds());
+ EXPECT_LE(0, timestamp_now.nanos());
+}
+
+TEST(Timestamp, Comparison) {
+ EXPECT_TRUE(Timestamp() < Timestamp(1, 2));
+ EXPECT_TRUE(Timestamp(1, 2) < Timestamp(2, 1));
+ EXPECT_TRUE(Timestamp(2, 1) < Timestamp(2, 2));
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/remote/CMakeLists.txt b/Firestore/core/test/firebase/firestore/remote/CMakeLists.txt
new file mode 100644
index 0000000..7d99e6f
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/remote/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright 2018 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.
+
+cc_test(
+ firebase_firestore_remote_test
+ SOURCES
+ datastore_test.cc
+ DEPENDS
+ firebase_firestore_remote
+)
diff --git a/Firestore/core/test/firebase/firestore/remote/datastore_test.cc b/Firestore/core/test/firebase/firestore/remote/datastore_test.cc
new file mode 100644
index 0000000..46a19cc
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/remote/datastore_test.cc
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/remote/datastore.h"
+
+#include <grpc/grpc.h>
+#include <gtest/gtest.h>
+
+TEST(Datastore, CanLinkToGrpc) {
+ // This test doesn't actually do anything interesting as far as actually
+ // using gRPC is concerned but that it can run at all is proof that all the
+ // libraries required for gRPC to work are actually linked correctly into the
+ // test.
+ grpc_init();
+}
diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
index 223fa41..0bddf06 100644
--- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
@@ -12,12 +12,64 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set(CMAKE_CXX_EXTENSIONS ON)
+
+# Required to allow 0 length printf style strings for testing purposes.
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-zero-length")
+
+if(HAVE_ARC4RANDOM)
+ cc_test(
+ firebase_firestore_util_arc4random_test
+ SOURCES
+ secure_random_test.cc
+ DEPENDS
+ firebase_firestore_util_arc4random
+ )
+endif()
+
+if(HAVE_OPENSSL_RAND_H)
+ cc_test(
+ firebase_firestore_util_openssl_test
+ SOURCES
+ secure_random_test.cc
+ DEPENDS
+ firebase_firestore_util_openssl
+ )
+endif()
+
cc_test(
firebase_firestore_util_test
- autoid_test.cc
- secure_random_test.cc
+ SOURCES
+ autoid_test.cc
+ bits_test.cc
+ comparison_test.cc
+ iterator_adaptors_test.cc
+ ordered_code_test.cc
+ string_printf_test.cc
+ string_util_test.cc
+ DEPENDS
+ absl_base
+ absl_strings
+ firebase_firestore_util
+ gmock
)
-target_link_libraries(
- firebase_firestore_util_test
- firebase_firestore_util
+
+if(APPLE)
+ cc_test(
+ firebase_firestore_util_apple_test
+ SOURCES
+ assert_test.cc
+ log_test.cc
+ DEPENDS
+ firebase_firestore_util_apple
+ )
+endif(APPLE)
+
+cc_test(
+ firebase_firestore_util_stdio_test
+ SOURCES
+ assert_test.cc
+ log_test.cc
+ DEPENDS
+ firebase_firestore_util_stdio
)
diff --git a/Firestore/core/test/firebase/firestore/util/assert_test.cc b/Firestore/core/test/firebase/firestore/util/assert_test.cc
new file mode 100644
index 0000000..fb15e61
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/assert_test.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include <exception>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+namespace {
+
+void AssertWithExpression(bool condition) {
+ FIREBASE_ASSERT_WITH_EXPRESSION(condition, 1 + 2 + 3);
+}
+
+void Assert(bool condition) {
+ FIREBASE_ASSERT(condition == true);
+}
+
+void AssertMessageWithExpression(bool condition) {
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, 1 + 2 + 3, "connection %s",
+ condition ? "succeeded" : "failed");
+}
+
+} // namespace
+
+TEST(Assert, WithExpression) {
+ AssertWithExpression(true);
+
+ EXPECT_ANY_THROW(AssertWithExpression(false));
+}
+
+TEST(Assert, Vanilla) {
+ Assert(true);
+
+ EXPECT_ANY_THROW(Assert(false));
+}
+
+TEST(Assert, WithMessageAndExpression) {
+ AssertMessageWithExpression(true);
+
+ EXPECT_ANY_THROW(AssertMessageWithExpression(false));
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/autoid_test.cc b/Firestore/core/test/firebase/firestore/util/autoid_test.cc
index 730c683..079b990 100644
--- a/Firestore/core/test/firebase/firestore/util/autoid_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/autoid_test.cc
@@ -18,15 +18,15 @@
#include <ctype.h>
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
using firebase::firestore::util::CreateAutoId;
TEST(AutoId, IsSane) {
for (int i = 0; i < 50; i++) {
std::string auto_id = CreateAutoId();
- EXPECT_EQ(20, auto_id.length());
- for (int pos = 0; pos < 20; pos++) {
+ EXPECT_EQ(20u, auto_id.length());
+ for (size_t pos = 0; pos < 20; pos++) {
char c = auto_id[pos];
EXPECT_TRUE(isalpha(c) || isdigit(c))
<< "Should be printable ascii character: '" << c << "' in \""
diff --git a/Firestore/Port/bits_test.cc b/Firestore/core/test/firebase/firestore/util/bits_test.cc
index 8c3c246..cb0976b 100644
--- a/Firestore/Port/bits_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/bits_test.cc
@@ -14,24 +14,24 @@
* limitations under the License.
*/
-#include "Firestore/Port/bits.h"
+#include "Firestore/core/src/firebase/firestore/util/bits.h"
+#include <algorithm>
#include <iostream>
+#include <limits>
-#include "base/commandlineflags.h"
-#include "testing/base/public/gunit.h"
-#include "util/random/mt_random.h"
+#include "Firestore/core/src/firebase/firestore/util/secure_random.h"
+#include "gtest/gtest.h"
-using Firestore::Bits;
+namespace firebase {
+namespace firestore {
+namespace util {
-DEFINE_int32(num_iterations, 10000, "Number of test iterations to run.");
+const int kNumIterations = 10000; // "Number of test iterations to run.
class BitsTest : public testing::Test {
- public:
- BitsTest() : random_(testing::FLAGS_gunit_random_seed) {}
-
protected:
- MTRandom random_;
+ SecureRandom random_;
};
TEST_F(BitsTest, Log2EdgeCases) {
@@ -41,7 +41,7 @@ TEST_F(BitsTest, Log2EdgeCases) {
EXPECT_EQ(-1, Bits::Log2Floor64(0));
for (int i = 0; i < 32; i++) {
- uint32 n = 1U << i;
+ uint32_t n = 1U << i;
EXPECT_EQ(i, Bits::Log2Floor(n));
EXPECT_EQ(i, Bits::Log2FloorNonZero(n));
if (n > 2) {
@@ -53,7 +53,7 @@ TEST_F(BitsTest, Log2EdgeCases) {
}
for (int i = 0; i < 64; i++) {
- uint64 n = 1ULL << i;
+ uint64_t n = 1ULL << i;
EXPECT_EQ(i, Bits::Log2Floor64(n));
EXPECT_EQ(i, Bits::Log2FloorNonZero64(n));
if (n > 2) {
@@ -68,11 +68,11 @@ TEST_F(BitsTest, Log2EdgeCases) {
TEST_F(BitsTest, Log2Random) {
std::cout << "TestLog2Random" << std::endl;
- for (int i = 0; i < FLAGS_num_iterations; i++) {
+ for (int i = 0; i < kNumIterations; i++) {
int maxbit = -1;
- uint32 n = 0;
- while (!random_.OneIn(32)) {
- int bit = random_.Uniform(32);
+ uint32_t n = 0;
+ while (!random_.OneIn(32u)) {
+ int bit = static_cast<int>(random_.Uniform(32u));
n |= (1U << bit);
maxbit = std::max(bit, maxbit);
}
@@ -86,11 +86,11 @@ TEST_F(BitsTest, Log2Random) {
TEST_F(BitsTest, Log2Random64) {
std::cout << "TestLog2Random64" << std::endl;
- for (int i = 0; i < FLAGS_num_iterations; i++) {
+ for (int i = 0; i < kNumIterations; i++) {
int maxbit = -1;
- uint64 n = 0;
- while (!random_.OneIn(64)) {
- int bit = random_.Uniform(64);
+ uint64_t n = 0;
+ while (!random_.OneIn(64u)) {
+ int bit = static_cast<int>(random_.Uniform(64u));
n |= (1ULL << bit);
maxbit = std::max(bit, maxbit);
}
@@ -103,8 +103,8 @@ TEST_F(BitsTest, Log2Random64) {
TEST(Bits, Port32) {
for (int shift = 0; shift < 32; shift++) {
- for (int delta = -1; delta <= +1; delta++) {
- const uint32 v = (static_cast<uint32>(1) << shift) + delta;
+ for (uint32_t delta = 0; delta <= 2; delta++) {
+ const uint32_t v = (static_cast<uint32_t>(1) << shift) - 1 + delta;
EXPECT_EQ(Bits::Log2Floor_Portable(v), Bits::Log2Floor(v)) << v;
if (v != 0) {
EXPECT_EQ(Bits::Log2FloorNonZero_Portable(v), Bits::Log2FloorNonZero(v))
@@ -112,7 +112,7 @@ TEST(Bits, Port32) {
}
}
}
- static const uint32 M32 = kuint32max;
+ static const uint32_t M32 = std::numeric_limits<uint32_t>::max();
EXPECT_EQ(Bits::Log2Floor_Portable(M32), Bits::Log2Floor(M32)) << M32;
EXPECT_EQ(Bits::Log2FloorNonZero_Portable(M32), Bits::Log2FloorNonZero(M32))
<< M32;
@@ -120,8 +120,8 @@ TEST(Bits, Port32) {
TEST(Bits, Port64) {
for (int shift = 0; shift < 64; shift++) {
- for (int delta = -1; delta <= +1; delta++) {
- const uint64 v = (static_cast<uint64>(1) << shift) + delta;
+ for (uint64_t delta = 0; delta <= 2; delta++) {
+ const uint64_t v = (static_cast<uint64_t>(1) << shift) - 1 + delta;
EXPECT_EQ(Bits::Log2Floor64_Portable(v), Bits::Log2Floor64(v)) << v;
if (v != 0) {
EXPECT_EQ(Bits::Log2FloorNonZero64_Portable(v),
@@ -130,9 +130,13 @@ TEST(Bits, Port64) {
}
}
}
- static const uint64 M64 = kuint64max;
+ static const uint64_t M64 = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(Bits::Log2Floor64_Portable(M64), Bits::Log2Floor64(M64)) << M64;
EXPECT_EQ(Bits::Log2FloorNonZero64_Portable(M64),
Bits::Log2FloorNonZero64(M64))
<< M64;
}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/comparison_test.cc b/Firestore/core/test/firebase/firestore/util/comparison_test.cc
new file mode 100644
index 0000000..ccb3011
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/comparison_test.cc
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/comparison.h"
+
+#include <inttypes.h>
+#include <math.h>
+
+#include <limits>
+
+#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+#define ASSERT_SAME(comparison) \
+ do { \
+ ASSERT_EQ(ComparisonResult::Same, comparison); \
+ } while (0)
+
+#define ASSERT_ASCENDING(comparison) \
+ do { \
+ ASSERT_EQ(ComparisonResult::Ascending, comparison); \
+ } while (0)
+
+#define ASSERT_DESCENDING(comparison) \
+ do { \
+ ASSERT_EQ(ComparisonResult::Descending, comparison); \
+ } while (0)
+
+TEST(Comparison, ReverseOrder) {
+ ASSERT_ASCENDING(ReverseOrder(ComparisonResult::Descending));
+ ASSERT_DESCENDING(ReverseOrder(ComparisonResult::Ascending));
+ ASSERT_SAME(ReverseOrder(ComparisonResult::Same));
+}
+
+TEST(Comparison, StringCompare) {
+ ASSERT_ASCENDING(Compare<absl::string_view>("", "a"));
+ ASSERT_ASCENDING(Compare<absl::string_view>("a", "b"));
+ ASSERT_ASCENDING(Compare<absl::string_view>("a", "aa"));
+
+ ASSERT_DESCENDING(Compare<absl::string_view>("a", ""));
+ ASSERT_DESCENDING(Compare<absl::string_view>("b", "a"));
+ ASSERT_DESCENDING(Compare<absl::string_view>("aa", "a"));
+
+ ASSERT_SAME(Compare<absl::string_view>("", ""));
+ ASSERT_SAME(Compare<absl::string_view>("", std::string()));
+ ASSERT_SAME(Compare<absl::string_view>("a", "a"));
+}
+
+TEST(Comparison, BooleanCompare) {
+ ASSERT_SAME(Compare<bool>(false, false));
+ ASSERT_SAME(Compare<bool>(true, true));
+ ASSERT_ASCENDING(Compare<bool>(false, true));
+ ASSERT_DESCENDING(Compare<bool>(true, false));
+}
+
+TEST(Comparison, DoubleCompare) {
+ ASSERT_SAME(Compare<double>(NAN, NAN));
+ ASSERT_ASCENDING(Compare<double>(NAN, 0));
+ ASSERT_DESCENDING(Compare<double>(0, NAN));
+
+ ASSERT_SAME(Compare<double>(-INFINITY, -INFINITY));
+ ASSERT_SAME(Compare<double>(INFINITY, INFINITY));
+ ASSERT_ASCENDING(Compare<double>(-INFINITY, INFINITY));
+ ASSERT_DESCENDING(Compare<double>(INFINITY, -INFINITY));
+
+ ASSERT_SAME(Compare<double>(0, 0));
+ ASSERT_SAME(Compare<double>(-0, -0));
+ ASSERT_SAME(Compare<double>(-0, 0));
+}
+
+#define ASSERT_BIT_EQUALS(expected, actual) \
+ do { \
+ uint64_t expectedBits = DoubleBits(expected); \
+ uint64_t actualBits = DoubleBits(actual); \
+ if (expectedBits != actualBits) { \
+ std::string message = StringPrintf( \
+ "Expected <%f> to compare equal to <%f> " \
+ "with bits <%" PRIu64 "> equal to <%" PRIu64 ">", \
+ actual, expected, actualBits, expectedBits); \
+ FAIL() << message; \
+ } \
+ } while (0);
+
+#define ASSERT_MIXED_SAME(doubleValue, longValue) \
+ do { \
+ ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
+ if (result != ComparisonResult::Same) { \
+ std::string message = StringPrintf( \
+ "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
+ FAIL() << message; \
+ } \
+ } while (0);
+
+#define ASSERT_MIXED_DESCENDING(doubleValue, longValue) \
+ do { \
+ ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
+ if (result != ComparisonResult::Descending) { \
+ std::string message = StringPrintf( \
+ "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
+ FAIL() << message; \
+ } \
+ } while (0);
+
+#define ASSERT_MIXED_ASCENDING(doubleValue, longValue) \
+ do { \
+ ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
+ if (result != ComparisonResult::Ascending) { \
+ std::string message = StringPrintf( \
+ "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
+ FAIL() << message; \
+ } \
+ } while (0);
+
+TEST(Comparison, MixedNumberCompare) {
+ // Infinities
+ ASSERT_MIXED_ASCENDING(-INFINITY, LLONG_MIN);
+ ASSERT_MIXED_ASCENDING(-INFINITY, LLONG_MAX);
+ ASSERT_MIXED_ASCENDING(-INFINITY, 0LL);
+
+ ASSERT_MIXED_DESCENDING(INFINITY, LLONG_MIN);
+ ASSERT_MIXED_DESCENDING(INFINITY, LLONG_MAX);
+ ASSERT_MIXED_DESCENDING(INFINITY, 0LL);
+
+ // NaN
+ ASSERT_MIXED_ASCENDING(NAN, LLONG_MIN);
+ ASSERT_MIXED_ASCENDING(NAN, LLONG_MAX);
+ ASSERT_MIXED_ASCENDING(NAN, 0LL);
+
+ // Large values (note DBL_MIN is positive and near zero).
+ ASSERT_MIXED_ASCENDING(-DBL_MAX, LLONG_MIN);
+
+ // Tests around LLONG_MIN
+ ASSERT_BIT_EQUALS((double)LLONG_MIN, -0x1.0p63);
+ ASSERT_MIXED_SAME(-0x1.0p63, LLONG_MIN);
+ ASSERT_MIXED_ASCENDING(-0x1.0p63, LLONG_MIN + 1);
+
+ ASSERT_LT(-0x1.0000000000001p63, -0x1.0p63);
+ ASSERT_MIXED_ASCENDING(-0x1.0000000000001p63, LLONG_MIN);
+ ASSERT_MIXED_DESCENDING(-0x1.FFFFFFFFFFFFFp62, LLONG_MIN);
+
+ // Tests around LLONG_MAX
+ // Note LLONG_MAX cannot be exactly represented by a double, so the system
+ // rounds it to the nearest double, which is 2^63. This number, in turn is
+ // larger than the maximum representable as a long.
+ ASSERT_BIT_EQUALS(0x1.0p63, (double)LLONG_MAX);
+ ASSERT_MIXED_DESCENDING(0x1.0p63, LLONG_MAX);
+
+ // The largest value with an exactly long representation
+ ASSERT_EQ((int64_t)0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC00LL);
+ ASSERT_MIXED_SAME(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC00LL);
+
+ ASSERT_MIXED_DESCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFB00LL);
+ ASSERT_MIXED_DESCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFBFFLL);
+ ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC01LL);
+ ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFD00LL);
+
+ ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFEp62, 0x7FFFFFFFFFFFFC00LL);
+
+ // Tests around MAX_SAFE_INTEGER
+ ASSERT_MIXED_SAME(0x1.FFFFFFFFFFFFFp52, 0x1FFFFFFFFFFFFFLL);
+ ASSERT_MIXED_DESCENDING(0x1.FFFFFFFFFFFFFp52, 0x1FFFFFFFFFFFFELL);
+ ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFEp52, 0x1FFFFFFFFFFFFFLL);
+ ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFFp52, 0x20000000000000LL);
+
+ // Tests around MIN_SAFE_INTEGER
+ ASSERT_MIXED_SAME(-0x1.FFFFFFFFFFFFFp52, -0x1FFFFFFFFFFFFFLL);
+ ASSERT_MIXED_ASCENDING(-0x1.FFFFFFFFFFFFFp52, -0x1FFFFFFFFFFFFELL);
+ ASSERT_MIXED_DESCENDING(-0x1.FFFFFFFFFFFFEp52, -0x1FFFFFFFFFFFFFLL);
+ ASSERT_MIXED_DESCENDING(-0x1.FFFFFFFFFFFFFp52, -0x20000000000000LL);
+
+ // Tests around zero.
+ ASSERT_MIXED_SAME(-0.0, 0LL);
+ ASSERT_MIXED_SAME(0.0, 0LL);
+
+ // The smallest representable positive value should be greater than zero
+ ASSERT_MIXED_DESCENDING(DBL_MIN, 0LL);
+ ASSERT_MIXED_ASCENDING(-DBL_MIN, 0LL);
+
+ // Note that 0x1.0p-1074 is a hex floating point literal representing the
+ // minimum subnormal number: <https://en.wikipedia.org/wiki/Denormal_number>.
+ double minSubNormal = 0x1.0p-1074;
+ ASSERT_MIXED_DESCENDING(minSubNormal, 0LL);
+ ASSERT_MIXED_ASCENDING(-minSubNormal, 0LL);
+
+ // Other sanity checks
+ ASSERT_MIXED_ASCENDING(0.5, 1LL);
+ ASSERT_MIXED_DESCENDING(0.5, 0LL);
+ ASSERT_MIXED_ASCENDING(1.5, 2LL);
+ ASSERT_MIXED_DESCENDING(1.5, 1LL);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/iterator_adaptors_test.cc b/Firestore/core/test/firebase/firestore/util/iterator_adaptors_test.cc
new file mode 100644
index 0000000..4cd44cc
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/iterator_adaptors_test.cc
@@ -0,0 +1,1277 @@
+/*
+ * Copyright 2005, 2018 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/iterator_adaptors.h"
+
+#include <iterator>
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using std::unordered_map;
+using std::unordered_set;
+
+using firebase::firestore::util::deref_second_view;
+using firebase::firestore::util::deref_view;
+using firebase::firestore::util::iterator_first;
+using firebase::firestore::util::iterator_ptr;
+using firebase::firestore::util::iterator_second;
+using firebase::firestore::util::iterator_second_ptr;
+using firebase::firestore::util::key_view;
+using firebase::firestore::util::key_view_type;
+using firebase::firestore::util::make_iterator_first;
+using firebase::firestore::util::make_iterator_ptr;
+using firebase::firestore::util::make_iterator_second;
+using firebase::firestore::util::make_iterator_second_ptr;
+using firebase::firestore::util::value_view;
+using firebase::firestore::util::value_view_type;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::IsEmpty;
+using testing::Not;
+using testing::Pair;
+using testing::Pointwise;
+using testing::SizeIs;
+
+namespace {
+
+const char* kFirst[] = {"foo", "bar"};
+int kSecond[] = {1, 2};
+const int kCount = ABSL_ARRAYSIZE(kFirst);
+
+template <typename T>
+struct IsConst : std::false_type {};
+template <typename T>
+struct IsConst<const T> : std::true_type {};
+template <typename T>
+struct IsConst<T&> : IsConst<T> {};
+
+class IteratorAdaptorTest : public testing::Test {
+ protected:
+ // Objects declared here can be used by all tests in the test case for Foo.
+
+ virtual void SetUp() {
+ ASSERT_EQ(ABSL_ARRAYSIZE(kFirst), ABSL_ARRAYSIZE(kSecond));
+ }
+
+ virtual void TearDown() {
+ }
+
+ template <typename T>
+ class InlineStorageIter : public std::iterator<std::input_iterator_tag, T> {
+ public:
+ T* operator->() const {
+ return get();
+ }
+ T& operator*() const {
+ return *get();
+ }
+
+ private:
+ T* get() const {
+ return &v_;
+ }
+ mutable T v_;
+ };
+
+ struct X {
+ int d;
+ };
+};
+
+TEST_F(IteratorAdaptorTest, HashMapFirst) {
+ // Adapts an iterator to return the first value of a unordered_map::iterator.
+ typedef unordered_map<std::string, int> my_container;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = kSecond[i];
+ }
+ for (iterator_first<my_container::iterator> it = values.begin();
+ it != values.end(); ++it) {
+ ASSERT_GT(it->length(), 0u);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrUniquePtr) {
+ // Tests iterator_ptr with a vector<unique_ptr<int>>.
+ typedef std::vector<std::unique_ptr<int>> my_container;
+ typedef iterator_ptr<my_container::iterator> my_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::unique_ptr<int>(new int(kSecond[i])));
+ }
+ int i = 0;
+ for (my_iterator it = values.begin(); it != values.end(); ++it, ++i) {
+ int v = *it;
+ *it = v;
+ ASSERT_EQ(v, kSecond[i]);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorFirstConvertsToConst) {
+ // Adapts an iterator to return the first value of a unordered_map::iterator.
+ typedef unordered_map<std::string, int> my_container;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = kSecond[i];
+ }
+ iterator_first<my_container::iterator> iter = values.begin();
+ iterator_first<my_container::const_iterator> c_iter = iter;
+ for (; c_iter != values.end(); ++c_iter) {
+ ASSERT_GT(c_iter->length(), 0u);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorFirstConstEqNonConst) {
+ // verify that const and non-const iterators return the same reference.
+ typedef std::vector<std::pair<int, int>> my_container;
+ typedef iterator_first<my_container::iterator> my_iterator;
+ typedef iterator_first<my_container::const_iterator> my_const_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::make_pair(i, i + 1));
+ }
+ my_iterator iter1 = values.begin();
+ const my_iterator iter2 = iter1;
+ my_const_iterator c_iter1 = iter1;
+ const my_const_iterator c_iter2 = c_iter1;
+ for (int i = 0; i < kCount; ++i) {
+ int& v1 = iter1[i];
+ int& v2 = iter2[i];
+ EXPECT_EQ(&v1, &values[i].first);
+ EXPECT_EQ(&v1, &v2);
+ const int& cv1 = c_iter1[i];
+ const int& cv2 = c_iter2[i];
+ EXPECT_EQ(&cv1, &values[i].first);
+ EXPECT_EQ(&cv1, &cv2);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, HashMapSecond) {
+ // Adapts an iterator to return the second value of a unordered_map::iterator.
+ typedef unordered_map<std::string, int> my_container;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = kSecond[i];
+ }
+ for (iterator_second<my_container::iterator> it = values.begin();
+ it != values.end(); ++it) {
+ int v = *it;
+ ASSERT_GT(v, 0);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondConvertsToConst) {
+ // Adapts an iterator to return the first value of a unordered_map::iterator.
+ typedef unordered_map<std::string, int> my_container;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = kSecond[i];
+ }
+ iterator_second<my_container::iterator> iter = values.begin();
+ iterator_second<my_container::const_iterator> c_iter = iter;
+ for (; c_iter != values.end(); ++c_iter) {
+ int v = *c_iter;
+ ASSERT_GT(v, 0);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondConstEqNonConst) {
+ // verify that const and non-const iterators return the same reference.
+ typedef std::vector<std::pair<int, int>> my_container;
+ typedef iterator_second<my_container::iterator> my_iterator;
+ typedef iterator_second<my_container::const_iterator> my_const_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::make_pair(i, i + 1));
+ }
+ my_iterator iter1 = values.begin();
+ const my_iterator iter2 = iter1;
+ my_const_iterator c_iter1 = iter1;
+ const my_const_iterator c_iter2 = c_iter1;
+ for (int i = 0; i < kCount; ++i) {
+ int& v1 = iter1[i];
+ int& v2 = iter2[i];
+ EXPECT_EQ(&v1, &values[i].second);
+ EXPECT_EQ(&v1, &v2);
+ const int& cv1 = c_iter1[i];
+ const int& cv2 = c_iter2[i];
+ EXPECT_EQ(&cv1, &values[i].second);
+ EXPECT_EQ(&cv1, &cv2);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondPtrConvertsToConst) {
+ // Adapts an iterator to return the first value of a unordered_map::iterator.
+ typedef unordered_map<std::string, int*> my_container;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = &kSecond[i];
+ }
+ iterator_second_ptr<my_container::iterator> iter = values.begin();
+ iterator_second_ptr<my_container::const_iterator> c_iter = iter;
+ for (; c_iter != values.end(); ++c_iter) {
+ int v = *c_iter;
+ ASSERT_GT(v, 0);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondPtrConstMap) {
+ typedef const std::map<int, int*> ConstMap;
+ ConstMap empty_map;
+
+ iterator_second_ptr<ConstMap::const_iterator> it(empty_map.begin());
+ ASSERT_TRUE(it == make_iterator_second_ptr(empty_map.end()));
+ if ((false)) {
+ // Just checking syntax/compilation/type-checking.
+ // iterator_second_ptr<ConstMap::const_iterator>::value_type* v1 = &*it;
+ iterator_second_ptr<ConstMap::const_iterator>::pointer v1 = &*it;
+ iterator_second_ptr<ConstMap::const_iterator>::pointer v2 =
+ &*it.operator->();
+ if (&v1 != &v2) v1 = v2;
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrConst) {
+ // This is a regression test for a const-related bug that bit CL 47984515,
+ // where a client created an iterator whose value type was "T* const".
+ std::map<int*, int> m;
+ make_iterator_ptr(make_iterator_first(m.begin()));
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondPtrConstEqNonConst) {
+ // verify that const and non-const iterators return the same reference.
+ typedef std::vector<std::pair<int, int*>> my_container;
+ typedef iterator_second_ptr<my_container::iterator> my_iterator;
+ typedef iterator_second_ptr<my_container::const_iterator> my_const_iterator;
+ my_container values;
+ int ivalues[kCount];
+ for (int i = 0; i < kCount; ++i) {
+ ivalues[i] = i;
+ values.push_back(std::make_pair(i, &ivalues[i]));
+ }
+ my_iterator iter1 = values.begin();
+ const my_iterator iter2 = iter1;
+ my_const_iterator c_iter1 = iter1;
+ const my_const_iterator c_iter2 = c_iter1;
+ for (int i = 0; i < kCount; ++i) {
+ int& v1 = iter1[i];
+ int& v2 = iter2[i];
+ EXPECT_EQ(&v1, &ivalues[i]);
+ EXPECT_EQ(&v1, &v2);
+ const int& cv1 = c_iter1[i];
+ const int& cv2 = c_iter2[i];
+ EXPECT_EQ(&cv1, &ivalues[i]);
+ EXPECT_EQ(&cv1, &cv2);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, HashMapFirstConst) {
+ // Adapts an iterator to return the first value of a
+ // unordered_map::const_iterator.
+ typedef unordered_map<std::string, int> my_container;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = kSecond[i];
+ }
+ const unordered_map<std::string, int>* cvalues = &values;
+ for (iterator_first<my_container::const_iterator> it = cvalues->begin();
+ it != cvalues->end(); ++it) {
+ ASSERT_GT(it->length(), 0u);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, ListFirst) {
+ // Adapts an iterator to return the first value of a list::iterator.
+ typedef std::pair<std::string, int> my_pair;
+ typedef std::list<my_pair> my_list;
+ my_list values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(my_pair(kFirst[i], kSecond[i]));
+ }
+ int i = 0;
+ for (iterator_first<my_list::iterator> it = values.begin();
+ it != values.end(); ++it) {
+ ASSERT_EQ(*it, kFirst[i++]);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, ListSecondConst) {
+ // Adapts an iterator to return the second value from a list::const_iterator.
+ typedef std::pair<std::string, int> my_pair;
+ typedef std::list<my_pair> my_list;
+ my_list values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(my_pair(kFirst[i], kSecond[i]));
+ }
+ int i = 0;
+ const my_list* cvalues = &values;
+ for (iterator_second<my_list::const_iterator> it = cvalues->begin();
+ it != cvalues->end(); ++it) {
+ ASSERT_EQ(*it, kSecond[i++]);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, VectorSecond) {
+ // Adapts an iterator to return the second value of a vector::iterator.
+ std::vector<std::pair<std::string, int>> values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::pair<std::string, int>(kFirst[i], kSecond[i]));
+ }
+ int i = 0;
+ for (iterator_second<std::vector<std::pair<std::string, int>>::iterator> it =
+ values.begin();
+ it != values.end(); ++it) {
+ ASSERT_EQ(*it, kSecond[i++]);
+ }
+}
+
+// Tests iterator_second_ptr with a map where values are regular pointers.
+TEST_F(IteratorAdaptorTest, HashMapSecondPtr) {
+ typedef unordered_map<std::string, int*> my_container;
+ typedef iterator_second_ptr<my_container::iterator> my_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]] = kSecond + i;
+ }
+ for (my_iterator it = values.begin(); it != values.end(); ++it) {
+ int v = *it;
+
+ // Make sure the iterator reference type is assignable ("int&" and not
+ // "const int&"). If it isn't, this becomes a compile-time error.
+ *it = v;
+
+ ASSERT_GT(v, 0);
+ }
+}
+
+// Tests iterator_second_ptr with a map where values are wrapped into
+// linked_ptr.
+TEST_F(IteratorAdaptorTest, HashMapSecondPtrLinkedPtr) {
+ typedef unordered_map<std::string, std::shared_ptr<int>> my_container;
+ typedef iterator_second_ptr<my_container::iterator> my_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values[kFirst[i]].reset(new int(kSecond[i]));
+ }
+ for (my_iterator it = values.begin(); it != values.end(); ++it) {
+ ASSERT_EQ(&*it, it.operator->());
+ int v = *it;
+ *it = v;
+ ASSERT_GT(v, 0);
+ }
+}
+
+// Tests iterator_ptr with a vector where values are regular pointers.
+TEST_F(IteratorAdaptorTest, IteratorPtrPtr) {
+ typedef std::vector<int*> my_container;
+ typedef iterator_ptr<my_container::iterator> my_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(kSecond + i);
+ }
+ int i = 0;
+ for (my_iterator it = values.begin(); it != values.end(); ++it, ++i) {
+ int v = *it;
+ *it = v;
+ ASSERT_EQ(v, kSecond[i]);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrExplicitPtrType) {
+ struct A {};
+ struct B : A {};
+ std::vector<B*> v;
+ const std::vector<B*>& cv = v;
+ iterator_ptr<std::vector<B*>::iterator, A*> ip(v.begin());
+ iterator_ptr<std::vector<B*>::const_iterator, A*> cip(cv.begin());
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrtConstEqNonConst) {
+ // verify that const and non-const iterators return the same reference.
+ typedef std::vector<int*> my_container;
+ typedef iterator_ptr<my_container::iterator> my_iterator;
+ typedef iterator_ptr<my_container::const_iterator> my_const_iterator;
+ my_container values;
+
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(kSecond + i);
+ }
+ my_iterator iter1 = values.begin();
+ const my_iterator iter2 = iter1;
+ my_const_iterator c_iter1 = iter1;
+ const my_const_iterator c_iter2 = iter1;
+ for (int i = 0; i < kCount; ++i) {
+ int& v1 = iter1[i];
+ int& v2 = iter2[i];
+ EXPECT_EQ(&v1, kSecond + i);
+ EXPECT_EQ(&v1, &v2);
+ const int& cv1 = c_iter1[i];
+ const int& cv2 = c_iter2[i];
+ EXPECT_EQ(&cv1, kSecond + i);
+ EXPECT_EQ(&cv1, &cv2);
+ }
+}
+
+// Tests iterator_ptr with a vector where values are wrapped into
+// std::shared_ptr.
+TEST_F(IteratorAdaptorTest, IteratorPtrLinkedPtr) {
+ typedef std::vector<std::shared_ptr<int>> my_container;
+ typedef iterator_ptr<my_container::iterator> my_iterator;
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::make_shared<int>(kSecond[i]));
+ }
+ int i = 0;
+ for (my_iterator it = values.begin(); it != values.end(); ++it, ++i) {
+ ASSERT_EQ(&*it, it.operator->());
+ int v = *it;
+ *it = v;
+ ASSERT_EQ(v, kSecond[i]);
+ }
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrConvertsToConst) {
+ int value = 1;
+ std::vector<int*> values;
+ values.push_back(&value);
+ iterator_ptr<std::vector<int*>::iterator> iter = values.begin();
+ iterator_ptr<std::vector<int*>::const_iterator> c_iter = iter;
+ EXPECT_EQ(1, *c_iter);
+}
+
+TEST_F(IteratorAdaptorTest, IteratorFirstHasRandomAccessMethods) {
+ typedef std::vector<std::pair<std::string, int>> my_container;
+ typedef iterator_first<my_container::iterator> my_iterator;
+
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::pair<std::string, int>(kFirst[i], kSecond[i]));
+ }
+
+ my_iterator it1 = values.begin(), it2 = values.end();
+
+ EXPECT_EQ(kCount, it2 - it1);
+ EXPECT_TRUE(it1 < it2);
+ it1 += kCount;
+ EXPECT_TRUE(it1 == it2);
+ it1 -= kCount;
+ EXPECT_EQ(kFirst[0], *it1);
+ EXPECT_EQ(kFirst[1], *(it1 + 1));
+ EXPECT_TRUE(it1 == it2 - kCount);
+ EXPECT_TRUE(kCount + it1 == it2);
+ EXPECT_EQ(kFirst[1], it1[1]);
+ it2[-1] = "baz";
+ EXPECT_EQ("baz", values[kCount - 1].first);
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondHasRandomAccessMethods) {
+ typedef std::vector<std::pair<std::string, int>> my_container;
+ typedef iterator_second<my_container::iterator> my_iterator;
+
+ my_container values;
+ for (int i = 0; i < kCount; ++i) {
+ values.push_back(std::pair<std::string, int>(kFirst[i], kSecond[i]));
+ }
+
+ my_iterator it1 = values.begin(), it2 = values.end();
+
+ EXPECT_EQ(kCount, it2 - it1);
+ EXPECT_TRUE(it1 < it2);
+ it1 += kCount;
+ EXPECT_TRUE(it1 == it2);
+ it1 -= kCount;
+ EXPECT_EQ(kSecond[0], *it1);
+ EXPECT_EQ(kSecond[1], *(it1 + 1));
+ EXPECT_TRUE(it1 == it2 - kCount);
+ EXPECT_TRUE(kCount + it1 == it2);
+ EXPECT_EQ(kSecond[1], it1[1]);
+ it2[-1] = 99;
+ EXPECT_EQ(99, values[kCount - 1].second);
+}
+
+TEST_F(IteratorAdaptorTest, IteratorSecondPtrHasRandomAccessMethods) {
+ typedef std::vector<std::pair<std::string, int*>> my_container;
+ typedef iterator_second_ptr<my_container::iterator> my_iterator;
+
+ ASSERT_GE(kCount, 2);
+ int value1 = 17;
+ int value2 = 99;
+ my_container values;
+ values.push_back(std::pair<std::string, int*>(kFirst[0], &value1));
+ values.push_back(std::pair<std::string, int*>(kFirst[1], &value2));
+
+ my_iterator it1 = values.begin(), it2 = values.end();
+
+ EXPECT_EQ(2, it2 - it1);
+ EXPECT_TRUE(it1 < it2);
+ it1 += 2;
+ EXPECT_TRUE(it1 == it2);
+ it1 -= 2;
+ EXPECT_EQ(17, *it1);
+ EXPECT_EQ(99, *(it1 + 1));
+ EXPECT_TRUE(it1 == it2 - 2);
+ EXPECT_TRUE(2 + it1 == it2);
+ EXPECT_EQ(99, it1[1]);
+ it2[-1] = 88;
+ EXPECT_EQ(88, value2);
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrHasRandomAccessMethods) {
+ typedef std::vector<int*> my_container;
+ typedef iterator_ptr<my_container::iterator> my_iterator;
+
+ int value1 = 17;
+ int value2 = 99;
+ my_container values;
+ values.push_back(&value1);
+ values.push_back(&value2);
+
+ my_iterator it1 = values.begin(), it2 = values.end();
+
+ EXPECT_EQ(2, it2 - it1);
+ EXPECT_TRUE(it1 < it2);
+ it1 += 2;
+ EXPECT_TRUE(it1 == it2);
+ it1 -= 2;
+ EXPECT_EQ(17, *it1);
+ EXPECT_EQ(99, *(it1 + 1));
+ EXPECT_TRUE(it1 == it2 - 2);
+ EXPECT_TRUE(2 + it1 == it2);
+ EXPECT_EQ(99, it1[1]);
+ it2[-1] = 88;
+ EXPECT_EQ(88, value2);
+}
+
+class MyInputIterator
+ : public std::iterator<std::input_iterator_tag, const int*> {
+ public:
+ explicit MyInputIterator(int* x) : x_(x) {
+ }
+ const int* operator*() const {
+ return x_;
+ }
+ MyInputIterator& operator++() {
+ ++*x_;
+ return *this;
+ }
+
+ private:
+ int* x_;
+};
+
+TEST_F(IteratorAdaptorTest, IteratorPtrCanWrapInputIterator) {
+ int x = 0;
+ MyInputIterator it(&x);
+ iterator_ptr<MyInputIterator> it1(it);
+
+ EXPECT_EQ(0, *it1);
+ ++it1;
+ EXPECT_EQ(1, *it1);
+ ++it1;
+ EXPECT_EQ(2, *it1);
+ ++it1;
+}
+
+// Tests that a default-constructed adaptor is equal to an adaptor explicitly
+// constructed with a default underlying iterator.
+TEST_F(IteratorAdaptorTest, DefaultAdaptorConstructorUsesDefaultValue) {
+ iterator_first<std::pair<int, int>*> first_default;
+ iterator_first<std::pair<int, int>*> first_null(nullptr);
+ ASSERT_TRUE(first_default == first_null);
+
+ iterator_second<std::pair<int, int>*> second_default;
+ iterator_second<std::pair<int, int>*> second_null(nullptr);
+ ASSERT_TRUE(second_default == second_null);
+
+ iterator_second_ptr<std::pair<int, int*>*> second_ptr_default;
+ iterator_second_ptr<std::pair<int, int*>*> second_ptr_null(nullptr);
+ ASSERT_TRUE(second_ptr_default == second_ptr_null);
+
+ iterator_ptr<int**> ptr_default;
+ iterator_ptr<int**> ptr_null(nullptr);
+ ASSERT_TRUE(ptr_default == ptr_null);
+}
+
+// Non C++11 test.
+TEST_F(IteratorAdaptorTest, ValueView) {
+ typedef unordered_map<int, std::string> MapType;
+ MapType my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+ const MapType c_map(my_map);
+
+ std::set<std::string> vals;
+ auto view = value_view(c_map);
+ std::copy(view.begin(), view.end(), inserter(vals, vals.end()));
+
+ EXPECT_THAT(vals, ElementsAre("a", "b", "c"));
+}
+
+TEST_F(IteratorAdaptorTest, ValueView_Modify) {
+ typedef std::map<int, int> MapType;
+ MapType my_map;
+ my_map[0] = 0;
+ my_map[1] = 1;
+ my_map[2] = 2;
+ EXPECT_THAT(my_map, ElementsAre(Pair(0, 0), Pair(1, 1), Pair(2, 2)));
+
+ value_view_type<MapType>::type vv = value_view(my_map);
+ std::replace(vv.begin(), vv.end(), 2, 3);
+ std::replace(vv.begin(), vv.end(), 1, 2);
+
+ EXPECT_THAT(my_map, ElementsAre(Pair(0, 0), Pair(1, 2), Pair(2, 3)));
+}
+
+TEST_F(IteratorAdaptorTest, ValueViewOfValueView) {
+ typedef std::pair<int, std::string> pair_int_str;
+ typedef std::map<int, pair_int_str> map_int_pair_int_str;
+ map_int_pair_int_str my_map;
+ my_map[0] = std::make_pair(1, std::string("a"));
+ my_map[2] = std::make_pair(3, std::string("b"));
+ my_map[4] = std::make_pair(5, std::string("c"));
+
+ // This is basically typechecking of the generated views. So we generate the
+ // types and have the compiler verify the generated template instantiation.
+ typedef value_view_type<map_int_pair_int_str>::type
+ value_view_map_int_pair_int_str_type;
+
+ static_assert(
+ (std::is_same<pair_int_str,
+ value_view_map_int_pair_int_str_type::value_type>::value),
+ "value_view_value_type_");
+
+ typedef value_view_type<value_view_map_int_pair_int_str_type>::type
+ view_view_type;
+
+ static_assert((std::is_same<std::string, view_view_type::value_type>::value),
+ "view_view_type_");
+
+ value_view_map_int_pair_int_str_type vv = value_view(my_map);
+ view_view_type helper = value_view(vv);
+
+ EXPECT_THAT(std::set<std::string>(helper.begin(), helper.end()),
+ ElementsAre("a", "b", "c"));
+}
+
+TEST_F(IteratorAdaptorTest, ValueViewAndKeyViewCopy) {
+ std::map<int, std::string> my_map;
+ my_map[0] = "0";
+ my_map[1] = "1";
+ my_map[2] = "2";
+ std::set<int> keys;
+ std::set<std::string> vals;
+
+ auto kv = key_view(my_map);
+ std::copy(kv.begin(), kv.end(), inserter(keys, keys.end()));
+
+ auto vv = value_view(my_map);
+ std::copy(vv.begin(), vv.end(), inserter(vals, vals.end()));
+ EXPECT_THAT(keys, ElementsAre(0, 1, 2));
+ EXPECT_THAT(vals, ElementsAre("0", "1", "2"));
+}
+
+TEST_F(IteratorAdaptorTest, ValueViewAndKeyViewRangeBasedLoop) {
+ std::map<int, std::string> my_map;
+ my_map[0] = "0";
+ my_map[1] = "1";
+ my_map[2] = "2";
+ std::set<int> keys;
+ std::set<std::string> vals;
+ for (auto key : key_view(my_map)) {
+ keys.insert(key);
+ }
+ for (auto val : value_view(my_map)) {
+ vals.insert(val);
+ }
+ EXPECT_THAT(keys, ElementsAre(0, 1, 2));
+ EXPECT_THAT(vals, ElementsAre("0", "1", "2"));
+}
+
+template <int N, typename Value, typename Key>
+class FixedSizeContainer {
+ public:
+ // NOTE: the container does on purpose not define:
+ // reference, const_reference, pointer, const_pointer, size_type,
+ // difference_type, empty().
+ typedef std::pair<Value, Key> value_type;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+
+ FixedSizeContainer() {
+ }
+ const_iterator begin() const {
+ return &values[0];
+ }
+ iterator begin() {
+ return &values[0];
+ }
+ const_iterator end() const {
+ return &values[N];
+ }
+ iterator end() {
+ return &values[N];
+ }
+ value_type at(int n) const {
+ return values[n];
+ }
+ value_type& operator[](int n) {
+ return values[n];
+ }
+ int size() const {
+ return N;
+ }
+
+ private:
+ static constexpr int kAllocatedSize = N ? N : 1;
+ value_type values[kAllocatedSize];
+ // NOTE: the container does on purpose not define:
+ // reference, const_reference, pointer, const_pointer, size_type,
+ // difference_type, empty().
+};
+
+TEST_F(IteratorAdaptorTest, ProvidesEmpty) {
+ {
+ FixedSizeContainer<0, int, int> container0;
+ EXPECT_TRUE(value_view(container0).empty());
+ FixedSizeContainer<1, int, int> container1;
+ EXPECT_FALSE(value_view(container1).empty());
+ }
+ {
+ std::map<int, int> container;
+ EXPECT_TRUE(value_view(container).empty());
+ container.insert(std::make_pair(0, 0));
+ EXPECT_FALSE(value_view(container).empty());
+ }
+}
+
+TEST_F(IteratorAdaptorTest, ValueViewWithPoorlyTypedHomeGrownContainer) {
+ FixedSizeContainer<3, int, std::string> container;
+ container[0] = std::make_pair(0, std::string("0"));
+ container[1] = std::make_pair(1, std::string("1"));
+ container[2] = std::make_pair(2, std::string("2"));
+ EXPECT_EQ(3, container.size());
+ EXPECT_EQ(container.at(0), std::make_pair(0, std::string("0")));
+ EXPECT_EQ(container.at(1), std::make_pair(1, std::string("1")));
+ EXPECT_EQ(container.at(2), std::make_pair(2, std::string("2")));
+ std::vector<int> keys;
+ std::vector<std::string> vals;
+
+ auto kv = key_view(container);
+ std::copy(kv.begin(), kv.end(), back_inserter(keys));
+ auto vv = value_view(container);
+ std::copy(vv.begin(), vv.end(), back_inserter(vals));
+ EXPECT_THAT(keys, ElementsAre(0, 1, 2));
+ EXPECT_THAT(vals, ElementsAre("0", "1", "2"));
+}
+
+TEST_F(IteratorAdaptorTest, ValueViewConstIterators) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ std::set<std::string> vals;
+ // iterator_view_helper defines cbegin() and cend(); we're not invoking the
+ // C++11 functions of the same name.
+ for (iterator_second<unordered_map<int, std::string>::const_iterator> it =
+ value_view(my_map).cbegin();
+ it != value_view(my_map).cend(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find("a") != vals.end());
+ EXPECT_TRUE(vals.find("b") != vals.end());
+ EXPECT_TRUE(vals.find("c") != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ValueViewInConstContext) {
+ using firebase::firestore::util::internal::iterator_view_helper;
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ std::set<std::string> vals;
+ const iterator_view_helper<
+ unordered_map<int, std::string>,
+ iterator_second<unordered_map<int, std::string>::iterator>,
+ iterator_second<unordered_map<int, std::string>::const_iterator>>
+ const_view = value_view(my_map);
+ for (iterator_second<unordered_map<int, std::string>::const_iterator> it =
+ const_view.begin();
+ it != const_view.end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find("a") != vals.end());
+ EXPECT_TRUE(vals.find("b") != vals.end());
+ EXPECT_TRUE(vals.find("c") != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ConstValueView) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ const unordered_map<int, std::string>& const_map = my_map;
+
+ std::set<std::string> vals;
+ for (iterator_second<unordered_map<int, std::string>::const_iterator> it =
+ value_view(const_map).begin();
+ it != value_view(const_map).end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find("a") != vals.end());
+ EXPECT_TRUE(vals.find("b") != vals.end());
+ EXPECT_TRUE(vals.find("c") != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ConstValueViewConstIterators) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ const unordered_map<int, std::string>& const_map = my_map;
+
+ std::set<std::string> vals;
+ // iterator_view_helper defines cbegin() and cend(); we're not invoking the
+ // C++11 functions of the same name.
+ for (iterator_second<unordered_map<int, std::string>::const_iterator> it =
+ value_view(const_map).cbegin();
+ it != value_view(const_map).cend(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find("a") != vals.end());
+ EXPECT_TRUE(vals.find("b") != vals.end());
+ EXPECT_TRUE(vals.find("c") != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ConstValueViewInConstContext) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ const unordered_map<int, std::string>& const_map = my_map;
+
+ std::set<std::string> vals;
+ const value_view_type<const unordered_map<int, std::string>>::type
+ const_view = value_view(const_map);
+ for (iterator_second<unordered_map<int, std::string>::const_iterator> it =
+ const_view.begin();
+ it != const_view.end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find("a") != vals.end());
+ EXPECT_TRUE(vals.find("b") != vals.end());
+ EXPECT_TRUE(vals.find("c") != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, KeyView) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ std::set<int> vals;
+ for (iterator_first<unordered_map<int, std::string>::iterator> it =
+ key_view(my_map).begin();
+ it != key_view(my_map).end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, KeyViewConstIterators) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ std::set<int> vals;
+ // iterator_view_helper defines cbegin() and cend(); we're not invoking the
+ // C++11 functions of the same name.
+ for (iterator_first<unordered_map<int, std::string>::const_iterator> it =
+ key_view(my_map).cbegin();
+ it != key_view(my_map).cend(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, KeyViewInConstContext) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ std::set<int> vals;
+ const key_view_type<unordered_map<int, std::string>>::type const_view =
+ key_view(my_map);
+ for (iterator_first<unordered_map<int, std::string>::const_iterator> it =
+ const_view.begin();
+ it != const_view.end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ConstKeyView) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ const unordered_map<int, std::string>& const_map = my_map;
+
+ std::set<int> vals;
+ for (iterator_first<unordered_map<int, std::string>::const_iterator> it =
+ key_view(const_map).begin();
+ it != key_view(const_map).end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ConstKeyViewConstIterators) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ const unordered_map<int, std::string>& const_map = my_map;
+
+ std::set<int> vals;
+ // iterator_view_helper defines cbegin() and cend(); we're not invoking the
+ // C++11 functions of the same name.
+ for (iterator_first<unordered_map<int, std::string>::const_iterator> it =
+ key_view(const_map).cbegin();
+ it != key_view(const_map).cend(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ConstKeyViewInConstContext) {
+ unordered_map<int, std::string> my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ const unordered_map<int, std::string>& const_map = my_map;
+
+ std::set<int> vals;
+ const key_view_type<const unordered_map<int, std::string>>::type const_view =
+ key_view(const_map);
+ for (iterator_first<unordered_map<int, std::string>::const_iterator> it =
+ const_view.begin();
+ it != const_view.end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, IteratorViewHelperDefinesIterator) {
+ using firebase::firestore::util::internal::iterator_view_helper;
+ unordered_set<int> my_set;
+ my_set.insert(1);
+ my_set.insert(0);
+ my_set.insert(2);
+
+ typedef iterator_view_helper<unordered_set<int>, unordered_set<int>::iterator,
+ unordered_set<int>::const_iterator>
+ SetView;
+ SetView set_view(my_set);
+ unordered_set<int> vals;
+ for (SetView::iterator it = set_view.begin(); it != set_view.end(); ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, IteratorViewHelperDefinesConstIterator) {
+ using firebase::firestore::util::internal::iterator_view_helper;
+ unordered_set<int> my_set;
+ my_set.insert(1);
+ my_set.insert(0);
+ my_set.insert(2);
+
+ typedef iterator_view_helper<unordered_set<int>, unordered_set<int>::iterator,
+ unordered_set<int>::const_iterator>
+ SetView;
+ SetView set_view(my_set);
+ unordered_set<int> vals;
+ for (SetView::const_iterator it = set_view.begin(); it != set_view.end();
+ ++it) {
+ vals.insert(*it);
+ }
+
+ EXPECT_TRUE(vals.find(0) != vals.end());
+ EXPECT_TRUE(vals.find(1) != vals.end());
+ EXPECT_TRUE(vals.find(2) != vals.end());
+}
+
+TEST_F(IteratorAdaptorTest, ViewTypeParameterConstVsNonConst) {
+ typedef unordered_map<int, int> M;
+ M m;
+ const M& cm = m;
+
+ typedef key_view_type<M>::type KV;
+ typedef key_view_type<const M>::type KVC;
+ typedef value_view_type<M>::type VV;
+ typedef value_view_type<const M>::type VVC;
+
+ // key_view:
+ KV ABSL_ATTRIBUTE_UNUSED kv1 = key_view(m); // lvalue
+ KVC ABSL_ATTRIBUTE_UNUSED kv2 = key_view(m); // conversion to const
+ KVC ABSL_ATTRIBUTE_UNUSED kv3 = key_view(cm); // const from const lvalue
+ KVC ABSL_ATTRIBUTE_UNUSED kv4 = key_view(M()); // const from rvalue
+ // Direct initialization (without key_view function)
+ KV ABSL_ATTRIBUTE_UNUSED kv5(m);
+ KVC ABSL_ATTRIBUTE_UNUSED kv6(m);
+ KVC ABSL_ATTRIBUTE_UNUSED kv7(cm);
+ KVC ABSL_ATTRIBUTE_UNUSED kv8((M()));
+
+ // value_view:
+ VV ABSL_ATTRIBUTE_UNUSED vv1 = value_view(m); // lvalue
+ VVC ABSL_ATTRIBUTE_UNUSED vv2 = value_view(m); // conversion to const
+ VVC ABSL_ATTRIBUTE_UNUSED vv3 = value_view(cm); // const from const lvalue
+ VVC ABSL_ATTRIBUTE_UNUSED vv4 = value_view(M()); // const from rvalue
+ // Direct initialization (without value_view function)
+ VV ABSL_ATTRIBUTE_UNUSED vv5(m);
+ VVC ABSL_ATTRIBUTE_UNUSED vv6(m);
+ VVC ABSL_ATTRIBUTE_UNUSED vv7(cm);
+ VVC ABSL_ATTRIBUTE_UNUSED vv8((M()));
+}
+
+TEST_F(IteratorAdaptorTest, EmptyAndSize) {
+ {
+ FixedSizeContainer<0, int, std::string*> container;
+ EXPECT_TRUE(key_view(container).empty());
+ EXPECT_TRUE(value_view(container).empty());
+ EXPECT_EQ(0u, key_view(container).size());
+ EXPECT_EQ(0u, value_view(container).size());
+ }
+ {
+ FixedSizeContainer<2, int, std::string*> container;
+ EXPECT_FALSE(key_view(container).empty());
+ EXPECT_FALSE(value_view(container).empty());
+ EXPECT_EQ(2u, key_view(container).size());
+ EXPECT_EQ(2u, value_view(container).size());
+ }
+ {
+ std::map<std::string, std::string*> container;
+ EXPECT_TRUE(key_view(container).empty());
+ EXPECT_TRUE(value_view(container).empty());
+ EXPECT_EQ(0u, key_view(container).size());
+ EXPECT_EQ(0u, value_view(container).size());
+ std::string s0 = "s0";
+ std::string s1 = "s1";
+ container.insert(std::make_pair("0", &s0));
+ container.insert(std::make_pair("1", &s0));
+ EXPECT_FALSE(key_view(container).empty());
+ EXPECT_FALSE(value_view(container).empty());
+ EXPECT_EQ(2u, key_view(container).size());
+ EXPECT_EQ(2u, value_view(container).size());
+ }
+}
+
+TEST_F(IteratorAdaptorTest, View_IsEmpty) {
+ EXPECT_THAT(key_view(std::map<int, int>()), IsEmpty());
+ EXPECT_THAT(key_view(FixedSizeContainer<2, int, int>()), Not(IsEmpty()));
+}
+
+TEST_F(IteratorAdaptorTest, View_SizeIs) {
+ EXPECT_THAT(key_view(std::map<int, int>()), SizeIs(0));
+ EXPECT_THAT(key_view(FixedSizeContainer<2, int, int>()), SizeIs(2));
+}
+
+TEST_F(IteratorAdaptorTest, View_Pointwise) {
+ typedef std::map<int, std::string> MapType;
+ MapType my_map;
+ my_map[0] = "a";
+ my_map[1] = "b";
+ my_map[2] = "c";
+
+ std::vector<std::string> expected;
+ expected.push_back("a");
+ expected.push_back("b");
+ expected.push_back("c");
+
+ EXPECT_THAT(value_view(my_map), Pointwise(Eq(), expected));
+}
+
+TEST_F(IteratorAdaptorTest, DerefView) {
+ typedef std::vector<int*> ContainerType;
+ int v0 = 0;
+ int v1 = 1;
+ ContainerType c;
+ c.push_back(&v0);
+ c.push_back(&v1);
+ EXPECT_THAT(deref_view(c), ElementsAre(0, 1));
+ *deref_view(c).begin() = 2;
+ EXPECT_THAT(v0, 2);
+ EXPECT_THAT(deref_view(c), ElementsAre(2, 1));
+ const std::vector<int*> cc(c);
+ EXPECT_THAT(deref_view(cc), ElementsAre(2, 1));
+}
+
+TEST_F(IteratorAdaptorTest, ConstDerefView) {
+ typedef std::vector<const std::string*> ContainerType;
+ const std::string s0 = "0";
+ const std::string s1 = "1";
+ ContainerType c;
+ c.push_back(&s0);
+ c.push_back(&s1);
+ EXPECT_THAT(deref_view(c), ElementsAre("0", "1"));
+}
+
+TEST_F(IteratorAdaptorTest, DerefSecondView) {
+ typedef std::map<int, int*> ContainerType;
+ int v0 = 0;
+ int v1 = 1;
+ ContainerType c;
+ c.insert({10, &v0});
+ c.insert({11, &v1});
+ EXPECT_THAT(deref_second_view(c), ElementsAre(0, 1));
+ *deref_second_view(c).begin() = 2;
+ EXPECT_THAT(v0, 2);
+ EXPECT_THAT(deref_second_view(c), ElementsAre(2, 1));
+ const std::map<int, int*> cc(c);
+ EXPECT_THAT(deref_second_view(cc), ElementsAre(2, 1));
+}
+
+TEST_F(IteratorAdaptorTest, ConstDerefSecondView) {
+ typedef std::map<int, const std::string*> ContainerType;
+ const std::string s0 = "0";
+ const std::string s1 = "1";
+ ContainerType c;
+ c.insert({10, &s0});
+ c.insert({11, &s1});
+ EXPECT_THAT(deref_second_view(c), ElementsAre("0", "1"));
+}
+
+namespace {
+template <class T>
+std::vector<int> ToVec(const T& t) {
+ return std::vector<int>(t.begin(), t.end());
+}
+} // namespace
+
+TEST_F(IteratorAdaptorTest, ReverseView) {
+ using firebase::firestore::util::reversed_view;
+
+ int arr[] = {0, 1, 2, 3, 4, 5, 6};
+ int* arr_end = arr + sizeof(arr) / sizeof(arr[0]);
+ std::vector<int> vec(arr, arr_end);
+ const std::vector<int> cvec(arr, arr_end);
+
+ EXPECT_THAT(ToVec(reversed_view(vec)), ElementsAre(6, 5, 4, 3, 2, 1, 0));
+ EXPECT_THAT(ToVec(reversed_view(cvec)), ElementsAre(6, 5, 4, 3, 2, 1, 0));
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrConstConversions) {
+ // Users depend on this. It has to keep working.
+ std::vector<int*> v;
+ const std::vector<int*>& cv = v;
+ EXPECT_TRUE(make_iterator_ptr(cv.end()) == make_iterator_ptr(v.end()));
+ EXPECT_FALSE(make_iterator_ptr(cv.end()) != make_iterator_ptr(v.end()));
+ // EXPECT_TRUE(make_iterator_ptr(v.end()) == make_iterator_ptr(cv.end()));
+ // EXPECT_FALSE(make_iterator_ptr(v.end()) != make_iterator_ptr(cv.end()));
+}
+
+TEST_F(IteratorAdaptorTest, IteratorPtrDeepConst) {
+ typedef std::vector<int*> PtrsToMutable;
+ typedef iterator_ptr<PtrsToMutable::const_iterator> ConstIter;
+ EXPECT_TRUE((std::is_same<ConstIter::reference, const int&>::value));
+ EXPECT_TRUE(IsConst<ConstIter::reference>::value);
+
+ typedef iterator_ptr<PtrsToMutable::iterator> Iter;
+ EXPECT_TRUE((std::is_same<Iter::reference, int&>::value));
+ EXPECT_FALSE(IsConst<Iter::reference>::value);
+}
+
+TEST_F(IteratorAdaptorTest, ReverseViewCxx11) {
+ using firebase::firestore::util::reversed_view;
+
+ int arr[] = {0, 1, 2, 3, 4, 5, 6};
+ int* arr_end = arr + sizeof(arr) / sizeof(arr[0]);
+ std::vector<int> vec(arr, arr_end);
+
+ // Try updates and demonstrate this work with C++11 for loops.
+ for (auto& i : reversed_view(vec)) ++i;
+ EXPECT_THAT(vec, ElementsAre(1, 2, 3, 4, 5, 6, 7));
+}
+
+TEST_F(IteratorAdaptorTest, BaseIterDanglingRefFirst) {
+ // Some iterators will hold 'on-board storage' for a synthesized value.
+ // We must take care not to pull our adapted reference from
+ // a temporary copy of the base iterator. See b/15113033.
+ typedef std::pair<X, int> Val;
+ InlineStorageIter<Val> iter;
+ iterator_first<InlineStorageIter<Val>> iter2(iter);
+ EXPECT_EQ(&iter2.base()->first, &*iter2);
+ EXPECT_EQ(&iter2.base()->first.d, &iter2->d);
+}
+
+TEST_F(IteratorAdaptorTest, BaseIterDanglingRefSecond) {
+ typedef std::pair<int, X> Val;
+ InlineStorageIter<Val> iter;
+ iterator_second<InlineStorageIter<Val>> iter2(iter);
+ EXPECT_EQ(&iter2.base()->second, &*iter2);
+ EXPECT_EQ(&iter2.base()->second.d, &iter2->d);
+}
+
+} // namespace
diff --git a/Firestore/core/test/firebase/firestore/util/log_test.cc b/Firestore/core/test/firebase/firestore/util/log_test.cc
new file mode 100644
index 0000000..973b174
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/log_test.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/log.h"
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+// When running against the log_apple.mm implementation (backed by FIRLogger)
+// this test can fail if debug_mode gets persisted in the user defaults. Check
+// for defaults getting in your way with
+//
+// defaults read firebase_firestore_util_log_apple_test
+//
+// You can fix it with:
+//
+// defaults write firebase_firestore_util_log_apple_test
+// /google/firebase/debug_mode NO
+TEST(Log, SetAndGet) {
+ LogSetLevel(kLogLevelVerbose);
+
+ LogSetLevel(kLogLevelDebug);
+ EXPECT_EQ(kLogLevelDebug, LogGetLevel());
+
+ LogSetLevel(kLogLevelInfo);
+ EXPECT_EQ(kLogLevelInfo, LogGetLevel());
+
+ LogSetLevel(kLogLevelWarning);
+ EXPECT_EQ(kLogLevelWarning, LogGetLevel());
+
+ LogSetLevel(kLogLevelError);
+ EXPECT_EQ(kLogLevelError, LogGetLevel());
+}
+
+TEST(Log, LogAllKinds) {
+ LogDebug("test debug logging %d", 1);
+ LogInfo("test info logging %d", 2);
+ LogWarning("test warning logging %d", 3);
+ LogError("test error logging %d", 4);
+ LogMessage(kLogLevelError, "test va-args %s %c %d", "abc", ':', 123);
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/Port/ordered_code_test.cc b/Firestore/core/test/firebase/firestore/util/ordered_code_test.cc
index 0a339fc..fd2ce83 100644
--- a/Firestore/Port/ordered_code_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/ordered_code_test.cc
@@ -14,63 +14,22 @@
* limitations under the License.
*/
-#include "Firestore/Port/ordered_code.h"
+#include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
-// #include <float.h>
-// #include <stddef.h>
#include <iostream>
#include <limits>
-#include "base/logging.h"
-#include "testing/base/public/gunit.h"
-#include <leveldb/db.h>
-#include "util/random/acmrandom.h"
-
-using Firestore::OrderedCode;
-using leveldb::Slice;
-
-// Make Slices writeable to ostream, making all the CHECKs happy below.
-namespace {
-void WritePadding(std::ostream& o, size_t pad) {
- char fill_buf[32];
- memset(fill_buf, o.fill(), sizeof(fill_buf));
- while (pad) {
- size_t n = std::min(pad, sizeof(fill_buf));
- o.write(fill_buf, n);
- pad -= n;
- }
-}
-} // namespace
-
-namespace leveldb {
-
-std::ostream& operator<<(std::ostream& o, const Slice slice) {
- std::ostream::sentry sentry(o);
- if (sentry) {
- size_t lpad = 0;
- size_t rpad = 0;
- if (o.width() > slice.size()) {
- size_t pad = o.width() - slice.size();
- if ((o.flags() & o.adjustfield) == o.left) {
- rpad = pad;
- } else {
- lpad = pad;
- }
- }
- if (lpad) WritePadding(o, lpad);
- o.write(slice.data(), slice.size());
- if (rpad) WritePadding(o, rpad);
- o.width(0);
- }
- return o;
-}
+#include "Firestore/core/src/firebase/firestore/util/secure_random.h"
+#include "gtest/gtest.h"
-} // namespace leveldb
+namespace firebase {
+namespace firestore {
+namespace util {
-static std::string RandomString(ACMRandom* rnd, int len) {
+static std::string RandomString(SecureRandom* rnd, int len) {
std::string x;
for (int i = 0; i < len; i++) {
- x += rnd->Uniform(256);
+ x += static_cast<char>(rnd->Uniform(256));
}
return x;
}
@@ -82,7 +41,7 @@ static std::string RandomString(ACMRandom* rnd, int len) {
template <typename T>
static void OCWriteIncreasing(std::string* dest, const T& val);
template <typename T>
-static bool OCReadIncreasing(Slice* src, T* result);
+static bool OCReadIncreasing(absl::string_view* src, T* result);
// Read/WriteIncreasing<std::string>
template <>
@@ -90,7 +49,8 @@ void OCWriteIncreasing<std::string>(std::string* dest, const std::string& val) {
OrderedCode::WriteString(dest, val);
}
template <>
-bool OCReadIncreasing<std::string>(Slice* src, std::string* result) {
+bool OCReadIncreasing<std::string>(absl::string_view* src,
+ std::string* result) {
return OrderedCode::ReadString(src, result);
}
@@ -100,7 +60,7 @@ void OCWriteIncreasing<uint64_t>(std::string* dest, const uint64_t& val) {
OrderedCode::WriteNumIncreasing(dest, val);
}
template <>
-bool OCReadIncreasing<uint64_t>(Slice* src, uint64_t* result) {
+bool OCReadIncreasing<uint64_t>(absl::string_view* src, uint64_t* result) {
return OrderedCode::ReadNumIncreasing(src, result);
}
@@ -112,12 +72,13 @@ void OCWriteIncreasing<int64_t>(std::string* dest, const int64_t& val) {
OrderedCode::WriteSignedNumIncreasing(dest, val);
}
template <>
-bool OCReadIncreasing<int64_t>(Slice* src, int64_t* result) {
+bool OCReadIncreasing<int64_t>(absl::string_view* src, int64_t* result) {
return OrderedCode::ReadSignedNumIncreasing(src, result);
}
template <typename T>
std::string OCWrite(T val, Direction direction) {
+ EXPECT_EQ(INCREASING, direction); // DECREASING never implemented.
std::string result;
OCWriteIncreasing<T>(&result, val);
return result;
@@ -125,11 +86,13 @@ std::string OCWrite(T val, Direction direction) {
template <typename T>
void OCWriteToString(std::string* result, T val, Direction direction) {
+ EXPECT_EQ(INCREASING, direction); // DECREASING never implemented.
OCWriteIncreasing<T>(result, val);
}
template <typename T>
-bool OCRead(Slice* s, T* val, Direction direction) {
+bool OCRead(absl::string_view* s, T* val, Direction direction) {
+ EXPECT_EQ(INCREASING, direction); // DECREASING never implemented.
return OCReadIncreasing<T>(s, val);
}
@@ -139,16 +102,16 @@ bool OCRead(Slice* s, T* val, Direction direction) {
template <typename T>
static T TestRead(Direction d, const std::string& a) {
// gracefully reject any proper prefix of an encoding
- for (int i = 0; i < a.size() - 1; ++i) {
- Slice s(a.data(), i);
- CHECK(!OCRead<T>(&s, NULL, d));
- CHECK_EQ(s, a.substr(0, i));
+ for (size_t i = 0; i < a.size() - 1; ++i) {
+ absl::string_view s(a.data(), i);
+ EXPECT_TRUE(!OCRead<T>(&s, NULL, d));
+ EXPECT_EQ(s, a.substr(0, i));
}
- Slice s(a);
+ absl::string_view s(a);
T v;
- CHECK(OCRead<T>(&s, &v, d));
- CHECK(s.empty());
+ EXPECT_TRUE(OCRead<T>(&s, &v, d));
+ EXPECT_TRUE(s.empty());
return v;
}
@@ -166,12 +129,13 @@ static void TestWriteAppends(Direction d, T first, U second) {
std::string encoded_first_only = encoded;
OCWriteToString<U>(&encoded, second, d);
EXPECT_NE(encoded, encoded_first_only);
- EXPECT_TRUE(Slice(encoded).starts_with(encoded_first_only));
+ EXPECT_EQ(absl::string_view(encoded).substr(0, encoded_first_only.length()),
+ encoded_first_only);
}
template <typename T>
static void TestNumbers(T multiplier) {
- for (int j = 0; j < 2; ++j) {
+ for (int j = 0; j < 1; ++j) {
const Direction d = static_cast<Direction>(j);
// first test powers of 2 (and nearby numbers)
@@ -180,19 +144,23 @@ static void TestNumbers(T multiplier) {
TestWriteRead(d, multiplier * x);
if (x != std::numeric_limits<T>::max()) {
TestWriteRead(d, multiplier * (x + 1));
- } else if (multiplier < 0 && multiplier == -1) {
+ } else if (multiplier < 0 && static_cast<int64_t>(multiplier) == -1) {
TestWriteRead(d, -x - 1);
}
}
- ACMRandom rnd(301);
+ SecureRandom rnd; // Generate 32bit pseudo-random integer.
for (int bits = 1; bits <= std::numeric_limits<T>().digits; ++bits) {
// test random non-negative numbers with given number of significant bits
const uint64_t mask = (~0ULL) >> (64 - bits);
for (int i = 0; i < 1000; i++) {
- T x = rnd.Next64() & mask;
+ T x = static_cast<T>((static_cast<uint64_t>(rnd()) << 32 |
+ static_cast<uint64_t>(rnd())) &
+ mask);
TestWriteRead(d, multiplier * x);
- T y = rnd.Next64() & mask;
+ T y = static_cast<T>((static_cast<uint64_t>(rnd()) << 32 |
+ static_cast<uint64_t>(rnd())) &
+ mask);
TestWriteAppends(d, multiplier * x, multiplier * y);
}
}
@@ -200,7 +168,8 @@ static void TestNumbers(T multiplier) {
}
// Return true iff 'a' is "before" 'b' according to 'direction'
-static bool CompareStrings(const std::string& a, const std::string& b,
+static bool CompareStrings(const std::string& a,
+ const std::string& b,
Direction d) {
return (INCREASING == d) ? (a < b) : (b < a);
}
@@ -216,12 +185,12 @@ static void TestNumberOrdering() {
std::string str = OCWrite<T>(num, d);
std::string strplus1 = OCWrite<T>(num + 1, d);
- CHECK(CompareStrings(strminus1, str, d));
- CHECK(CompareStrings(str, strplus1, d));
+ EXPECT_TRUE(CompareStrings(strminus1, str, d));
+ EXPECT_TRUE(CompareStrings(str, strplus1, d));
// Compare 'str' with 'laststr'. When we approach 0, 'laststr' is
// not necessarily before 'strminus1'.
- CHECK(CompareStrings(laststr, str, d));
+ EXPECT_TRUE(CompareStrings(laststr, str, d));
laststr = str;
}
@@ -234,46 +203,46 @@ static void TestNumberOrdering() {
std::string str = OCWrite<T>(num, d);
std::string strplus1 = OCWrite<T>(num + 1, d);
- CHECK(CompareStrings(strminus1, str, d));
- CHECK(CompareStrings(str, strplus1, d));
+ EXPECT_TRUE(CompareStrings(strminus1, str, d));
+ EXPECT_TRUE(CompareStrings(str, strplus1, d));
// Compare 'str' with 'laststr'.
- CHECK(CompareStrings(laststr, str, d));
+ EXPECT_TRUE(CompareStrings(laststr, str, d));
laststr = str;
}
}
// Helper routine for testing TEST_SkipToNextSpecialByte
-static int FindSpecial(const std::string& x) {
+static size_t FindSpecial(const std::string& x) {
const char* p = x.data();
const char* limit = p + x.size();
const char* result = OrderedCode::TEST_SkipToNextSpecialByte(p, limit);
- return result - p;
+ return static_cast<size_t>(result - p);
}
TEST(OrderedCode, SkipToNextSpecialByte) {
- for (int len = 0; len < 256; len++) {
- ACMRandom rnd(301);
+ for (size_t len = 0; len < 256; len++) {
+ SecureRandom rnd;
std::string x;
while (x.size() < len) {
- char c = 1 + rnd.Uniform(254);
+ char c = 1 + static_cast<char>(rnd.Uniform(254));
ASSERT_NE(c, 0);
ASSERT_NE(c, 255);
x += c; // No 0 bytes, no 255 bytes
}
EXPECT_EQ(FindSpecial(x), x.size());
- for (int special_pos = 0; special_pos < len; special_pos++) {
+ for (size_t special_pos = 0; special_pos < len; special_pos++) {
for (int special_test = 0; special_test < 2; special_test++) {
- const char special_byte = (special_test == 0) ? 0 : 255;
+ const char special_byte = (special_test == 0) ? 0 : '\xff';
std::string y = x;
y[special_pos] = special_byte;
EXPECT_EQ(FindSpecial(y), special_pos);
if (special_pos < 16) {
// Add some special bytes after the one at special_pos to make sure
// we still return the earliest special byte in the string
- for (int rest = special_pos + 1; rest < len; rest++) {
+ for (size_t rest = special_pos + 1; rest < len; rest++) {
if (rnd.OneIn(3)) {
- y[rest] = rnd.OneIn(2) ? 0 : 255;
+ y[rest] = rnd.OneIn(2) ? 0 : '\xff';
EXPECT_EQ(FindSpecial(y), special_pos);
}
}
@@ -297,9 +266,9 @@ TEST(OrderedCode, ExhaustiveFindSpecial) {
for (int b0 = 0; b0 < 256; b0++) {
for (int b1 = 0; b1 < 256; b1++) {
for (int b2 = 0; b2 < 256; b2++) {
- buf[start_offset + 0] = b0;
- buf[start_offset + 1] = b1;
- buf[start_offset + 2] = b2;
+ buf[start_offset + 0] = static_cast<char>(b0);
+ buf[start_offset + 1] = static_cast<char>(b1);
+ buf[start_offset + 2] = static_cast<char>(b2);
char* expected;
if (b0 == 0 || b0 == 255) {
expected = &buf[start_offset];
@@ -320,16 +289,22 @@ TEST(OrderedCode, ExhaustiveFindSpecial) {
EXPECT_EQ(count, 256 * 256 * 256 * 2);
}
-TEST(Uint64, EncodeDecode) { TestNumbers<uint64_t>(1); }
+TEST(OrderedCodeUint64, EncodeDecode) {
+ TestNumbers<uint64_t>(1);
+}
-TEST(Uint64, Ordering) { TestNumberOrdering<uint64_t>(); }
+TEST(OrderedCodeUint64, Ordering) {
+ TestNumberOrdering<uint64_t>();
+}
-TEST(Int64, EncodeDecode) {
+TEST(OrderedCodeInt64, EncodeDecode) {
TestNumbers<int64_t>(1);
TestNumbers<int64_t>(-1);
}
-TEST(Int64, Ordering) { TestNumberOrdering<int64_t>(); }
+TEST(OrderedCodeInt64, Ordering) {
+ TestNumberOrdering<int64_t>();
+}
// Returns the bitwise complement of s.
static inline std::string StrNot(const std::string& s) {
@@ -340,7 +315,7 @@ static inline std::string StrNot(const std::string& s) {
template <typename T>
static void TestInvalidEncoding(Direction d, const std::string& s) {
- Slice p(s);
+ absl::string_view p(s);
EXPECT_FALSE(OCRead<T>(&p, static_cast<T*>(NULL), d));
EXPECT_EQ(s, p);
}
@@ -363,22 +338,22 @@ TEST(OrderedCodeInvalidEncodingsTest, NonCanonical) {
// and thus should be avoided to not mess up the string ordering of
// encodings.
- ACMRandom rnd(301);
+ SecureRandom rnd;
for (int n = 2; n <= 9; ++n) {
// The zero in non_minimal[1] is "redundant".
std::string non_minimal =
std::string(1, n - 1) + std::string(1, 0) + RandomString(&rnd, n - 2);
- EXPECT_EQ(n, non_minimal.length());
+ EXPECT_EQ(static_cast<size_t>(n), non_minimal.length());
EXPECT_NE(OCWrite<uint64_t>(0, INCREASING), non_minimal);
- if (DEBUG_MODE) {
- Slice s(non_minimal);
- EXPECT_DEATH_IF_SUPPORTED(OrderedCode::ReadNumIncreasing(&s, NULL),
- "ssertion failed");
- } else {
- TestRead<uint64_t>(INCREASING, non_minimal);
- }
+
+#if defined(NDEBUG)
+ TestRead<uint64_t>(INCREASING, non_minimal);
+#else // defined(NDEBUG)
+ absl::string_view s(non_minimal);
+ EXPECT_ANY_THROW(OrderedCode::ReadNumIncreasing(&s, NULL));
+#endif // defined(NDEBUG)
}
for (int n = 2; n <= 10; ++n) {
@@ -387,31 +362,32 @@ TEST(OrderedCodeInvalidEncodingsTest, NonCanonical) {
std::string(n / 8, 0xff) + std::string(1, 0xff << (8 - (n % 8)));
// There are more than 7 zero bits between header bits and "payload".
std::string non_minimal =
- header + std::string(1, rnd.Uniform(256) & ~*header.rbegin()) +
- RandomString(&rnd, n - header.length() - 1);
- EXPECT_EQ(n, non_minimal.length());
+ header +
+ std::string(1,
+ static_cast<char>(rnd.Uniform(256)) & ~*header.rbegin()) +
+ RandomString(&rnd, n - static_cast<int>(header.length()) - 1);
+ EXPECT_EQ(static_cast<size_t>(n), non_minimal.length());
EXPECT_NE(OCWrite<int64_t>(0, INCREASING), non_minimal);
- if (DEBUG_MODE) {
- Slice s(non_minimal);
- EXPECT_DEATH_IF_SUPPORTED(OrderedCode::ReadSignedNumIncreasing(&s, NULL),
- "ssertion failed")
- << n;
- s = non_minimal;
- } else {
- TestRead<int64_t>(INCREASING, non_minimal);
- }
+
+#if defined(NDEBUG)
+ TestRead<int64_t>(INCREASING, non_minimal);
+#else // defined(NDEBUG)
+ absl::string_view s(non_minimal);
+ EXPECT_ANY_THROW(OrderedCode::ReadSignedNumIncreasing(&s, NULL));
+ s = non_minimal;
+#endif // defined(NDEBUG)
}
}
// ---------------------------------------------------------------------
// Strings
-TEST(String, Infinity) {
+TEST(OrderedCodeString, Infinity) {
const std::string value("\xff\xff foo");
bool is_inf;
std::string encoding, parsed;
- Slice s;
+ absl::string_view s;
// Check encoding/decoding of "infinity" for ascending order
encoding.clear();
@@ -419,11 +395,11 @@ TEST(String, Infinity) {
encoding.push_back('a');
s = encoding;
EXPECT_TRUE(OrderedCode::ReadInfinity(&s));
- EXPECT_EQ(1, s.size());
+ EXPECT_EQ(1u, s.size());
s = encoding;
is_inf = false;
EXPECT_TRUE(OrderedCode::ReadStringOrInfinity(&s, NULL, &is_inf));
- EXPECT_EQ(1, s.size());
+ EXPECT_EQ(1u, s.size());
EXPECT_TRUE(is_inf);
// Check ReadStringOrInfinity() can parse ordinary strings
@@ -434,14 +410,14 @@ TEST(String, Infinity) {
is_inf = false;
parsed.clear();
EXPECT_TRUE(OrderedCode::ReadStringOrInfinity(&s, &parsed, &is_inf));
- EXPECT_EQ(1, s.size());
+ EXPECT_EQ(1u, s.size());
EXPECT_FALSE(is_inf);
EXPECT_EQ(value, parsed);
}
-TEST(String, EncodeDecode) {
- ACMRandom rnd(301);
- for (int i = 0; i < 2; ++i) {
+TEST(OrderedCodeString, EncodeDecode) {
+ SecureRandom rnd;
+ for (int i = 0; i < 1; ++i) {
const Direction d = static_cast<Direction>(i);
for (int len = 0; len < 256; len++) {
@@ -457,48 +433,48 @@ TEST(String, EncodeDecode) {
OCWriteToString<std::string>(&out, b, d);
std::string a2, b2, dummy;
- Slice s = out;
- Slice s2 = out;
- CHECK(OCRead<std::string>(&s, &a2, d));
- CHECK(OCRead<std::string>(&s2, NULL, d));
- CHECK_EQ(s, s2);
-
- CHECK(OCRead<std::string>(&s, &b2, d));
- CHECK(OCRead<std::string>(&s2, NULL, d));
- CHECK_EQ(s, s2);
-
- CHECK(!OCRead<std::string>(&s, &dummy, d));
- CHECK(!OCRead<std::string>(&s2, NULL, d));
- CHECK_EQ(a, a2);
- CHECK_EQ(b, b2);
- CHECK(s.empty());
- CHECK(s2.empty());
+ absl::string_view s = out;
+ absl::string_view s2 = out;
+ EXPECT_TRUE(OCRead<std::string>(&s, &a2, d));
+ EXPECT_TRUE(OCRead<std::string>(&s2, NULL, d));
+ EXPECT_EQ(s, s2);
+
+ EXPECT_TRUE(OCRead<std::string>(&s, &b2, d));
+ EXPECT_TRUE(OCRead<std::string>(&s2, NULL, d));
+ EXPECT_EQ(s, s2);
+
+ EXPECT_TRUE(!OCRead<std::string>(&s, &dummy, d));
+ EXPECT_TRUE(!OCRead<std::string>(&s2, NULL, d));
+ EXPECT_EQ(a, a2);
+ EXPECT_EQ(b, b2);
+ EXPECT_TRUE(s.empty());
+ EXPECT_TRUE(s2.empty());
}
}
}
}
// 'str' is a static C-style string that may contain '\0'
-#define STATIC_STR(str) Slice((str), sizeof(str) - 1)
+#define STATIC_STR(str) absl::string_view((str), sizeof(str) - 1)
-static std::string EncodeStringIncreasing(Slice value) {
+static std::string EncodeStringIncreasing(absl::string_view value) {
std::string encoded;
OrderedCode::WriteString(&encoded, value);
return encoded;
}
-TEST(String, Increasing) {
+TEST(OrderedCodeString, Increasing) {
// Here are a series of strings in non-decreasing order, including
// consecutive strings such that the second one is equal to, a proper
// prefix of, or has the same length as the first one. Most also contain
// the special escaping characters '\x00' and '\xff'.
- ASSERT_EQ(EncodeStringIncreasing(STATIC_STR("")),
+ EXPECT_EQ(EncodeStringIncreasing(STATIC_STR("")),
EncodeStringIncreasing(STATIC_STR("")));
ASSERT_LT(EncodeStringIncreasing(STATIC_STR("")),
EncodeStringIncreasing(STATIC_STR("\x00")));
- ASSERT_EQ(EncodeStringIncreasing(STATIC_STR("\x00")),
+ EXPECT_EQ(EncodeStringIncreasing(STATIC_STR("\x00")),
EncodeStringIncreasing(STATIC_STR("\x00")));
ASSERT_LT(EncodeStringIncreasing(STATIC_STR("\x00")),
@@ -507,7 +483,7 @@ TEST(String, Increasing) {
ASSERT_LT(EncodeStringIncreasing(STATIC_STR("\x01")),
EncodeStringIncreasing(STATIC_STR("a")));
- ASSERT_EQ(EncodeStringIncreasing(STATIC_STR("a")),
+ EXPECT_EQ(EncodeStringIncreasing(STATIC_STR("a")),
EncodeStringIncreasing(STATIC_STR("a")));
ASSERT_LT(EncodeStringIncreasing(STATIC_STR("a")),
@@ -526,3 +502,7 @@ TEST(String, Increasing) {
OrderedCode::WriteInfinity(&infinity);
ASSERT_LT(EncodeStringIncreasing(std::string(1 << 20, '\xff')), infinity);
}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/secure_random_test.cc b/Firestore/core/test/firebase/firestore/util/secure_random_test.cc
index f96f3de..0b7a51b 100644
--- a/Firestore/core/test/firebase/firestore/util/secure_random_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/secure_random_test.cc
@@ -16,7 +16,7 @@
#include "Firestore/core/src/firebase/firestore/util/secure_random.h"
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
using firebase::firestore::util::SecureRandom;
@@ -30,3 +30,28 @@ TEST(SecureRandomTest, ResultsAreBounded) {
EXPECT_LE(value, rng.max());
}
}
+
+TEST(SecureRandomTest, Uniform) {
+ SecureRandom rng;
+ int count[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ for (int i = 0; i < 1000; i++) {
+ count[rng.Uniform(10)]++;
+ }
+ for (int i = 0; i < 10; i++) {
+ // Practically, each count should be close to 100.
+ EXPECT_LT(50, count[i]) << count[i];
+ }
+}
+
+TEST(SecureRandomTest, OneIn) {
+ SecureRandom rng;
+ int count = 0;
+
+ for (int i = 0; i < 1000; i++) {
+ if (rng.OneIn(10)) count++;
+ }
+ // Practically, count should be close to 100.
+ EXPECT_LT(50, count) << count;
+ EXPECT_GT(150, count) << count;
+}
diff --git a/Firestore/core/test/firebase/firestore/util/string_printf_test.cc b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc
new file mode 100644
index 0000000..085be84
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+
+#include <gtest/gtest.h>
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+TEST(StringPrintf, Empty) {
+ EXPECT_EQ("", StringPrintf(""));
+ EXPECT_EQ("", StringPrintf("%s", std::string().c_str()));
+ EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringAppendFTest, Empty) {
+ std::string value("Hello");
+ const char* empty = "";
+ StringAppendF(&value, "%s", empty);
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, EmptyString) {
+ std::string value("Hello");
+ StringAppendF(&value, "%s", "");
+ EXPECT_EQ("Hello", value);
+}
+
+TEST(StringAppendFTest, String) {
+ std::string value("Hello");
+ StringAppendF(&value, " %s", "World");
+ EXPECT_EQ("Hello World", value);
+}
+
+TEST(StringAppendFTest, Int) {
+ std::string value("Hello");
+ StringAppendF(&value, " %d", 123);
+ EXPECT_EQ("Hello 123", value);
+}
+
+TEST(StringPrintf, DontOverwriteErrno) {
+ // Check that errno isn't overwritten unless we're printing
+ // something significantly larger than what people are normally
+ // printing in their badly written PLOG() statements.
+ errno = ECHILD;
+ std::string value = StringPrintf("Hello, %s!", "World");
+ EXPECT_EQ(ECHILD, errno);
+}
+
+TEST(StringPrintf, LargeBuf) {
+ // Check that the large buffer is handled correctly.
+ size_t n = 2048;
+ char* buf = new char[n + 1];
+ memset(buf, ' ', n);
+ buf[n] = 0;
+ std::string value = StringPrintf("%s", buf);
+ EXPECT_EQ(buf, value);
+ delete[] buf;
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/Port/string_util_test.cc b/Firestore/core/test/firebase/firestore/util/string_util_test.cc
index ac8ce56..f94596f 100644
--- a/Firestore/Port/string_util_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/string_util_test.cc
@@ -14,17 +14,15 @@
* limitations under the License.
*/
-#include "Firestore/Port/string_util.h"
+#include "Firestore/core/src/firebase/firestore/util/string_util.h"
-#include "leveldb/db.h"
+#include <gtest/gtest.h>
-#include "gtest/gtest.h"
+namespace firebase {
+namespace firestore {
+namespace util {
-using Firestore::PrefixSuccessor;
-using Firestore::ImmediateSuccessor;
-using leveldb::Slice;
-
-TEST(Util, PrefixSuccessor) {
+TEST(StringUtil, PrefixSuccessor) {
EXPECT_EQ(PrefixSuccessor("a"), "b");
EXPECT_EQ(PrefixSuccessor("aaAA"), "aaAB");
EXPECT_EQ(PrefixSuccessor("aaa\xff"), "aab");
@@ -34,7 +32,11 @@ TEST(Util, PrefixSuccessor) {
EXPECT_EQ(PrefixSuccessor(""), "");
}
-TEST(Util, ImmediateSuccessor) {
- EXPECT_EQ(ImmediateSuccessor("hello"), Slice("hello\0", 6));
- EXPECT_EQ(ImmediateSuccessor(""), Slice("\0", 1));
+TEST(StringUtil, ImmediateSuccessor) {
+ EXPECT_EQ(ImmediateSuccessor("hello"), std::string("hello\0", 6));
+ EXPECT_EQ(ImmediateSuccessor(""), std::string("\0", 1));
}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/third_party/Immutable/FSTArraySortedDictionary.m b/Firestore/third_party/Immutable/FSTArraySortedDictionary.m
index ad1d68a..e9325a7 100644
--- a/Firestore/third_party/Immutable/FSTArraySortedDictionary.m
+++ b/Firestore/third_party/Immutable/FSTArraySortedDictionary.m
@@ -142,19 +142,6 @@ NS_ASSUME_NONNULL_BEGIN
}
}
-- (nullable id)predecessorKey:(id)key {
- NSInteger pos = [self findKey:key];
- if (pos == NSNotFound) {
- [NSException raise:NSInternalInconsistencyException
- format:@"Can't get predecessor key for non-existent key"];
- return nil;
- } else if (pos == 0) {
- return nil;
- } else {
- return self.keys[pos - 1];
- }
-}
-
- (NSUInteger)indexOfKey:(id)key {
return [self findKey:key];
}
diff --git a/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h b/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h
index a2264ec..cbb4da3 100644
--- a/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h
+++ b/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h
@@ -71,14 +71,6 @@ extern const int kSortedDictionaryArrayToRBTreeSizeThreshold;
- (ValueType)objectForKeyedSubscript:(KeyType)key;
/**
- * Gets the key before the given key in sorted order.
- *
- * @param key The key to look before.
- * @return The key before the given one.
- */
-- (nullable KeyType)predecessorKey:(KeyType)key;
-
-/**
* Returns the index of the key or NSNotFound if the key is not found.
*
* @param key The key to return the index for.
diff --git a/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m b/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m
index 6e78961..87c21a5 100644
--- a/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m
+++ b/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m
@@ -82,10 +82,6 @@ const int kSortedDictionaryArrayToRBTreeSizeThreshold = 25;
return [self objectForKey:key];
}
-- (nullable id)predecessorKey:(id)key {
- @throw FSTAbstractMethodException(); // NOLINT
-}
-
- (NSUInteger)indexOfKey:(id)key {
@throw FSTAbstractMethodException(); // NOLINT
}
diff --git a/Firestore/third_party/Immutable/FSTImmutableSortedSet.h b/Firestore/third_party/Immutable/FSTImmutableSortedSet.h
index d0f9906..b432f98 100644
--- a/Firestore/third_party/Immutable/FSTImmutableSortedSet.h
+++ b/Firestore/third_party/Immutable/FSTImmutableSortedSet.h
@@ -23,8 +23,6 @@ NS_ASSUME_NONNULL_BEGIN
- (NSUInteger)count;
- (BOOL)isEmpty;
-- (KeyType)predecessorObject:(KeyType)entry;
-
/**
* Returns the index of the object or NSNotFound if the object is not found.
*
diff --git a/Firestore/third_party/Immutable/FSTImmutableSortedSet.m b/Firestore/third_party/Immutable/FSTImmutableSortedSet.m
index a23068e..1b63c2c 100644
--- a/Firestore/third_party/Immutable/FSTImmutableSortedSet.m
+++ b/Firestore/third_party/Immutable/FSTImmutableSortedSet.m
@@ -76,10 +76,6 @@ NS_ASSUME_NONNULL_BEGIN
return [self.dictionary maxKey];
}
-- (id)predecessorObject:(id)entry {
- return [self.dictionary predecessorKey:entry];
-}
-
- (NSUInteger)indexOfObject:(id)object {
return [self.dictionary indexOfKey:object];
}
diff --git a/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m b/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m
index b3e691f..ec0c483 100644
--- a/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m
+++ b/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m
@@ -87,36 +87,6 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
-- (nullable id)predecessorKey:(id)key {
- NSComparisonResult cmp;
- id<FSTLLRBNode> node = self.root;
- id<FSTLLRBNode> rightParent = nil;
- while (![node isEmpty]) {
- cmp = self.comparator(key, node.key);
- if (cmp == NSOrderedSame) {
- if (![node.left isEmpty]) {
- node = node.left;
- while (![node.right isEmpty]) {
- node = node.right;
- }
- return node.key;
- } else if (rightParent != nil) {
- return rightParent.key;
- } else {
- return nil;
- }
- } else if (cmp == NSOrderedAscending) {
- node = node.left;
- } else if (cmp == NSOrderedDescending) {
- rightParent = node;
- node = node.right;
- }
- }
- @throw [NSException exceptionWithName:@"NonexistentKey"
- reason:@"getPredecessorKey called with nonexistent key."
- userInfo:@{@"key" : [key description]}];
-}
-
- (NSUInteger)indexOfKey:(id)key {
NSUInteger prunedNodes = 0;
id<FSTLLRBNode> node = self.root;
diff --git a/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m b/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m
index a799686..bf17496 100644
--- a/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m
+++ b/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m
@@ -252,25 +252,6 @@
XCTAssertEqual((int)next, (int)toInsert.count, @"Check we traversed all of the items");
}
-- (void)testPredecessorKey {
- FSTArraySortedDictionary *map =
- [[FSTArraySortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@50 forKey:@50];
- map = [map dictionaryBySettingObject:@3 forKey:@3];
- map = [map dictionaryBySettingObject:@4 forKey:@4];
- map = [map dictionaryBySettingObject:@7 forKey:@7];
- map = [map dictionaryBySettingObject:@9 forKey:@9];
-
- XCTAssertNil([map predecessorKey:@1], @"First object doesn't have a predecessor");
- XCTAssertEqualObjects([map predecessorKey:@3], @1, @"@1");
- XCTAssertEqualObjects([map predecessorKey:@4], @3, @"@3");
- XCTAssertEqualObjects([map predecessorKey:@7], @4, @"@4");
- XCTAssertEqualObjects([map predecessorKey:@9], @7, @"@7");
- XCTAssertEqualObjects([map predecessorKey:@50], @9, @"@9");
- XCTAssertThrows([map predecessorKey:@777], @"Expect exception about nonexistent key");
-}
-
// This is a macro instead of a method so that the failures show on the proper lines.
#define ASSERT_ENUMERATOR(enumerator, start, end, step) \
do { \
@@ -288,15 +269,12 @@
- (void)testEnumerator {
NSUInteger n = 100;
NSMutableArray *toInsert = [NSMutableArray arrayWithCapacity:n];
- NSMutableArray *toRemove = [NSMutableArray arrayWithCapacity:n];
for (int i = 0; i < n; i++) {
[toInsert addObject:@(i)];
- [toRemove addObject:@(i)];
}
[self shuffleArray:toInsert];
- [self shuffleArray:toRemove];
FSTArraySortedDictionary *map =
[[FSTArraySortedDictionary alloc] initWithComparator:self.defaultComparator];
diff --git a/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m b/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m
index 344efba..3e06b30 100644
--- a/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m
+++ b/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m
@@ -437,25 +437,6 @@
}
}
-- (void)testPredecessorKey {
- FSTTreeSortedDictionary *map =
- [[FSTTreeSortedDictionary alloc] initWithComparator:[self defaultComparator]];
- map = [map dictionaryBySettingObject:@1 forKey:@1];
- map = [map dictionaryBySettingObject:@50 forKey:@50];
- map = [map dictionaryBySettingObject:@3 forKey:@3];
- map = [map dictionaryBySettingObject:@4 forKey:@4];
- map = [map dictionaryBySettingObject:@7 forKey:@7];
- map = [map dictionaryBySettingObject:@9 forKey:@9];
-
- XCTAssertNil([map predecessorKey:@1], @"First object doesn't have a predecessor");
- XCTAssertEqualObjects([map predecessorKey:@3], @1, @"@1");
- XCTAssertEqualObjects([map predecessorKey:@4], @3, @"@3");
- XCTAssertEqualObjects([map predecessorKey:@7], @4, @"@4");
- XCTAssertEqualObjects([map predecessorKey:@9], @7, @"@7");
- XCTAssertEqualObjects([map predecessorKey:@50], @9, @"@9");
- XCTAssertThrows([map predecessorKey:@777], @"Expect exception about nonexistent key");
-}
-
// This is a macro instead of a method so that the failures show on the proper lines.
#define ASSERT_ENUMERATOR(enumerator, start, end, step) \
do { \
diff --git a/Firestore/third_party/abseil-cpp/CMakeLists.txt b/Firestore/third_party/abseil-cpp/CMakeLists.txt
index 6d3789e..4a23b70 100644
--- a/Firestore/third_party/abseil-cpp/CMakeLists.txt
+++ b/Firestore/third_party/abseil-cpp/CMakeLists.txt
@@ -72,7 +72,6 @@ endif()
# commented: used only for standalone test
#add_subdirectory(cctz)
#add_subdirectory(googletest)
-check_target(${ABSL_CCTZ_TARGET})
## check targets
if(BUILD_TESTING)
diff --git a/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt b/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt
index 689f64e..e7b5139 100644
--- a/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt
+++ b/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt
@@ -17,14 +17,7 @@
add_subdirectory(base)
-add_subdirectory(algorithm)
-add_subdirectory(container)
-add_subdirectory(debugging)
add_subdirectory(memory)
add_subdirectory(meta)
add_subdirectory(numeric)
add_subdirectory(strings)
-add_subdirectory(synchronization)
-add_subdirectory(time)
-add_subdirectory(types)
-add_subdirectory(utility)
diff --git a/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt b/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt
index 4b7b53a..cfa119a 100644
--- a/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt
+++ b/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt
@@ -16,8 +16,6 @@
list(APPEND BASE_PUBLIC_HEADERS
"attributes.h"
- "call_once.h"
- "casts.h"
"config.h"
"dynamic_annotations.h"
"log_severity.h"
@@ -25,50 +23,21 @@ list(APPEND BASE_PUBLIC_HEADERS
"optimization.h"
"policy_checks.h"
"port.h"
- "thread_annotations.h"
)
list(APPEND BASE_INTERNAL_HEADERS
"internal/atomic_hook.h"
- "internal/cycleclock.h"
"internal/endian.h"
- "internal/exception_testing.h"
- "internal/exception_safety_testing.h"
- "internal/identity.h"
- "internal/invoke.h"
- "internal/inline_variable.h"
- "internal/low_level_alloc.h"
- "internal/low_level_scheduling.h"
- "internal/malloc_extension.h"
- "internal/malloc_hook_c.h"
- "internal/malloc_hook.h"
- "internal/malloc_hook_invoke.h"
- "internal/per_thread_tls.h"
- "internal/pretty_function.h"
"internal/raw_logging.h"
- "internal/scheduling_mode.h"
- "internal/spinlock.h"
- "internal/spinlock_wait.h"
- "internal/sysinfo.h"
- "internal/thread_identity.h"
"internal/throw_delegate.h"
- "internal/tsan_mutex_interface.h"
"internal/unaligned_access.h"
- "internal/unscaledcycleclock.h"
)
# absl_base main library
list(APPEND BASE_SRC
- "internal/cycleclock.cc"
"internal/raw_logging.cc"
- "internal/spinlock.cc"
- "internal/sysinfo.cc"
- "internal/thread_identity.cc"
- "internal/unscaledcycleclock.cc"
- "internal/low_level_alloc.cc"
- "internal/malloc_hook.cc"
${BASE_PUBLIC_HEADERS}
${BASE_INTERNAL_HEADERS}
)
@@ -80,25 +49,10 @@ absl_library(
${BASE_SRC}
PUBLIC_LIBRARIES
absl_dynamic_annotations
- absl_spinlock_wait
EXPORT_NAME
base
)
-# malloc extension library
-set(MALLOC_EXTENSION_SRC "internal/malloc_extension.cc")
-set(MALLOC_EXTENSION_PUBLIC_LIBRARIES absl::base)
-
-absl_library(
- TARGET
- absl_malloc_extension
- SOURCES
- ${MALLOC_EXTENSION_SRC}
- PUBLIC_LIBRARIES
- ${MALLOC_EXTENSION_PUBLIC_LIBRARIES}
- EXPORT_NAME
- malloc_extension
-)
# throw delegate library
set(THROW_DELEGATE_SRC "internal/throw_delegate.cc")
@@ -116,28 +70,6 @@ absl_library(
throw_delegate
)
-if(BUILD_TESTING)
- # exception-safety testing library
- set(EXCEPTION_SAFETY_TESTING_SRC "internal/exception_safety_testing.cc")
- set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
- ${ABSL_TEST_COMMON_LIBRARIES}
- absl::base
- absl::memory
- absl::meta
- absl::strings
- absl::types
- )
-
-absl_library(
- TARGET
- absl_base_internal_exception_safety_testing
- SOURCES
- ${EXCEPTION_SAFETY_TESTING_SRC}
- PUBLIC_LIBRARIES
- ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
-)
-endif()
-
# dynamic_annotations library
set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc")
@@ -150,140 +82,10 @@ absl_library(
)
-# spinlock_wait library
-set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc")
-
-absl_library(
- TARGET
- absl_spinlock_wait
- SOURCES
- ${SPINLOCK_WAIT_SRC}
-)
-
-
-# malloc_internal library
-list(APPEND MALLOC_INTERNAL_SRC
- "internal/low_level_alloc.cc"
- "internal/malloc_hook.cc"
- "internal/malloc_hook_mmap_linux.inc"
-)
-
-absl_library(
- TARGET
- absl_malloc_internal
- SOURCES
- ${MALLOC_INTERNAL_SRC}
- PUBLIC_LIBRARIES
- absl_dynamic_annotations
-)
-
-
-
#
## TESTS
#
-# call once test
-set(CALL_ONCE_TEST_SRC "call_once_test.cc")
-set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- call_once_test
- SOURCES
- ${CALL_ONCE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CALL_ONCE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test bit_cast_test
-set(BIT_CAST_TEST_SRC "bit_cast_test.cc")
-
-absl_test(
- TARGET
- bit_cast_test
- SOURCES
- ${BIT_CAST_TEST_SRC}
-)
-
-
-# test absl_throw_delegate_test
-set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc")
-set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate)
-
-absl_test(
- TARGET
- throw_delegate_test
- SOURCES
- ${THROW_DELEGATE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test invoke_test
-set(INVOKE_TEST_SRC "invoke_test.cc")
-set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- invoke_test
- SOURCES
- ${INVOKE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INVOKE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test inline_variable_test
-list(APPEND INLINE_VARIABLE_TEST_SRC
- "internal/inline_variable_testing.h"
- "inline_variable_test.cc"
- "inline_variable_test_a.cc"
- "inline_variable_test_b.cc"
-)
-
-set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base)
-
-absl_test(
- TARGET
- inline_variable_test
- SOURCES
- ${INLINE_VARIABLE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test spinlock_test_common
-set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc")
-set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- spinlock_test_common
- SOURCES
- ${SPINLOCK_TEST_COMMON_SRC}
- PUBLIC_LIBRARIES
- ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES}
-)
-
-
-# test spinlock_test
-set(SPINLOCK_TEST_SRC "spinlock_test_common.cc")
-set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- spinlock_test
- SOURCES
- ${SPINLOCK_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SPINLOCK_TEST_PUBLIC_LIBRARIES}
-)
-
-
# test endian_test
set(ENDIAN_TEST_SRC "internal/endian_test.cc")
@@ -297,7 +99,7 @@ absl_test(
# test config_test
set(CONFIG_TEST_SRC "config_test.cc")
-set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
+set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base)
absl_test(
TARGET
config_test
@@ -320,80 +122,3 @@ absl_test(
PUBLIC_LIBRARIES
${RAW_LOGGING_TEST_PUBLIC_LIBRARIES}
)
-
-
-# test sysinfo_test
-set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc")
-set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- sysinfo_test
- SOURCES
- ${SYSINFO_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SYSINFO_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test low_level_alloc_test
-set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc")
-set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base)
-
-absl_test(
- TARGET
- low_level_alloc_test
- SOURCES
- ${LOW_LEVEL_ALLOC_TEST_SRC}
- PUBLIC_LIBRARIES
- ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test thread_identity_test
-set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc")
-set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- thread_identity_test
- SOURCES
- ${THREAD_IDENTITY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES}
-)
-
-#test exceptions_safety_testing_test
-set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
-set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES absl::base absl::memory absl::meta absl::strings absl::optional)
-
-absl_test(
- TARGET
- absl_exception_safety_testing_test
- SOURCES
- ${EXCEPTION_SAFETY_TESTING_TEST_SRC}
- PUBLIC_LIBRARIES
- ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
- ${ABSL_EXCEPTIONS_FLAG}
-)
-
-# test absl_malloc_extension_system_malloc_test
-set(MALLOC_EXTENSION_SYSTEM_MALLOC_TEST_SRC "internal/malloc_extension_test.cc")
-set(MALLOC_EXTENSION_SYSTEM_MALLOC_TEST_PUBLIC_LIBRARIES absl::base absl_malloc_extension)
-set(MALLOC_EXTENSION_SYSTEM_MALLOC_TEST_PRIVATE_COMPILE_FLAGS "-DABSL_MALLOC_EXTENSION_TEST_ALLOW_MISSING_EXTENSION=1")
-
-absl_test(
- TARGET
- absl_malloc_extension_system_malloc_test
- SOURCES
- ${MALLOC_EXTENSION_SYSTEM_MALLOC_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MALLOC_EXTENSION_SYSTEM_MALLOC_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
- ${MALLOC_EXTENSION_SYSTEM_MALLOC_TEST_PRIVATE_COMPILE_FLAGS}
-)
-
-
-
-
diff --git a/Firestore/third_party/abseil-cpp/absl/base/config_test.cc b/Firestore/third_party/abseil-cpp/absl/base/config_test.cc
index c839712..4e6dd6a 100644
--- a/Firestore/third_party/abseil-cpp/absl/base/config_test.cc
+++ b/Firestore/third_party/abseil-cpp/absl/base/config_test.cc
@@ -17,7 +17,6 @@
#include <cstdint>
#include "gtest/gtest.h"
-#include "absl/synchronization/internal/thread_pool.h"
namespace {
@@ -41,20 +40,4 @@ TEST(ConfigTest, Endianness) {
#endif
}
-#if defined(ABSL_HAVE_THREAD_LOCAL)
-TEST(ConfigTest, ThreadLocal) {
- static thread_local int mine_mine_mine = 16;
- EXPECT_EQ(16, mine_mine_mine);
- {
- absl::synchronization_internal::ThreadPool pool(1);
- pool.Schedule([&] {
- EXPECT_EQ(16, mine_mine_mine);
- mine_mine_mine = 32;
- EXPECT_EQ(32, mine_mine_mine);
- });
- }
- EXPECT_EQ(16, mine_mine_mine);
-}
-#endif
-
} // namespace
diff --git a/Firestore/third_party/abseil-cpp/absl/base/macros.h b/Firestore/third_party/abseil-cpp/absl/base/macros.h
index 5ae0f05..c81f8c6 100644
--- a/Firestore/third_party/abseil-cpp/absl/base/macros.h
+++ b/Firestore/third_party/abseil-cpp/absl/base/macros.h
@@ -196,7 +196,7 @@ enum LinkerInitialized {
#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
#else
#define ABSL_ASSERT(expr) \
- (ABSL_PREDICT_TRUE((expr)) ? (void)0 : [] { assert(false && #expr); }())
+ (void) (ABSL_PREDICT_TRUE((expr)) ? (void)0 : [] { assert(false && #expr); }())
#endif
#endif // ABSL_BASE_MACROS_H_
diff --git a/Firestore/third_party/abseil-cpp/absl/meta/CMakeLists.txt b/Firestore/third_party/abseil-cpp/absl/meta/CMakeLists.txt
index d56fced..a25dd61 100644
--- a/Firestore/third_party/abseil-cpp/absl/meta/CMakeLists.txt
+++ b/Firestore/third_party/abseil-cpp/absl/meta/CMakeLists.txt
@@ -44,6 +44,3 @@ absl_test(
PUBLIC_LIBRARIES
${TYPE_TRAITS_TEST_PUBLIC_LIBRARIES} absl::meta
)
-
-
-
diff --git a/Firestore/third_party/abseil-cpp/absl/numeric/int128_test.cc b/Firestore/third_party/abseil-cpp/absl/numeric/int128_test.cc
index d674cb1..b9d3647 100644
--- a/Firestore/third_party/abseil-cpp/absl/numeric/int128_test.cc
+++ b/Firestore/third_party/abseil-cpp/absl/numeric/int128_test.cc
@@ -22,7 +22,6 @@
#include <vector>
#include "gtest/gtest.h"
-#include "absl/base/internal/cycleclock.h"
#include "absl/meta/type_traits.h"
#if defined(_MSC_VER) && _MSC_VER == 1900
diff --git a/Firestore/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/Firestore/third_party/abseil-cpp/absl/strings/CMakeLists.txt
index 83cb934..a31f05d 100644
--- a/Firestore/third_party/abseil-cpp/absl/strings/CMakeLists.txt
+++ b/Firestore/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -48,7 +48,6 @@ list(APPEND STRINGS_SRC
"ascii.cc"
"escaping.cc"
"internal/memutil.cc"
- "internal/memutil.h"
"internal/utf8.cc"
"internal/ostringstream.cc"
"match.cc"
diff --git a/Gemfile.lock b/Gemfile.lock
index ea2bdde..e553857 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,12 +1,12 @@
GIT
remote: https://github.com/CocoaPods/CocoaPods.git
- revision: 71211b5046cb1c9f5ad33e45d42f16b43eabfb8f
+ revision: df6872de04fd1808fde71c824530e3a784e6a2d2
specs:
- cocoapods (1.4.0.beta.2)
+ cocoapods (1.4.0)
activesupport (>= 4.0.2, < 5)
claide (>= 1.0.2, < 2.0)
- cocoapods-core (= 1.4.0.beta.2)
- cocoapods-deintegrate (>= 1.0.1, < 2.0)
+ cocoapods-core (= 1.4.0)
+ cocoapods-deintegrate (>= 1.0.2, < 2.0)
cocoapods-downloader (>= 1.1.3, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
@@ -20,23 +20,24 @@ GIT
molinillo (~> 0.6.4)
nap (~> 1.0)
ruby-macho (~> 1.1)
- xcodeproj (>= 1.5.3, < 2.0)
+ xcodeproj (>= 1.5.4, < 2.0)
GIT
remote: https://github.com/CocoaPods/Core.git
- revision: 8cf88a076d916cf80821744a59ca1c431ccc046f
+ revision: b4fb2f193897c789c094d126ebca91034edc261d
specs:
- cocoapods-core (1.4.0.beta.2)
+ cocoapods-core (1.4.0)
activesupport (>= 4.0.2, < 6)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
GIT
remote: https://github.com/CocoaPods/Xcodeproj.git
- revision: aa866f4bd3f4269ae4ad1ec340ae077524f8e24d
+ revision: 531d8aa8ab4805c84f5e0fe94181ae3995430d05
specs:
- xcodeproj (1.5.3)
+ xcodeproj (1.5.4)
CFPropertyList (~> 2.3.3)
+ atomos (~> 0.1.0)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.2.3)
@@ -44,14 +45,15 @@ GIT
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (2.3.5)
+ CFPropertyList (2.3.6)
activesupport (4.2.10)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
+ atomos (0.1.0)
claide (1.0.2)
- cocoapods-deintegrate (1.0.1)
+ cocoapods-deintegrate (1.0.2)
cocoapods-downloader (1.1.3)
cocoapods-plugins (1.0.0)
nap
@@ -67,9 +69,9 @@ GEM
fourflusher (2.0.1)
fuzzy_match (2.0.4)
gh_inspector (1.0.3)
- i18n (0.9.1)
+ i18n (0.9.3)
concurrent-ruby (~> 1.0)
- minitest (5.10.3)
+ minitest (5.11.1)
molinillo (0.6.4)
nanaimo (0.2.3)
nap (1.1.0)
@@ -88,4 +90,4 @@ DEPENDENCIES
xcodeproj!
BUNDLED WITH
- 1.15.4
+ 1.16.0
diff --git a/README.md b/README.md
index e14e096..848e202 100644
--- a/README.md
+++ b/README.md
@@ -31,20 +31,25 @@ locations described via the Podfile syntax documented
**CocoaPods 1.4.0** or later is required.
+If source pods are included, **FirebaseCore** must also be included.
+
For example, to access FirebaseMessaging via a checked out version of the
firebase-ios-sdk repo do:
```
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
+pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
```
To access via a branch:
```
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
+pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master'
```
To access via a tag (Release tags will be available starting with Firebase 4.7.0:
```
pod 'FirebaseAuth', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :tag => '4.7.0'
+pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :tag => '4.7.0'
```
If your Podfile does not include *use_frameworks!*, you need to workaround
@@ -132,16 +137,18 @@ We've seen an amazing amount of interest and contributions to improve the Fireba
very grateful! We'd like to empower as many developers as we can to be able to use Firebase and
participate in the Firebase community.
-### macOS
+### macOS and tvOS
FirebaseAuth, FirebaseCore, FirebaseDatabase and FirebaseStorage now compile, run unit tests, and
-work on macOS, thanks to contributions from the community. There are a few tweaks needed, like
-ensuring iOS-only or macOS-only code is correctly guarded with checks for `TARGET_OS_IOS` and
-`TARGET_OS_OSX`.
-
-Keep in mind that macOS is not officially supported by Firebase, and this repository is actively
-developed primarily for iOS. While we can catch basic unit test issues with Travis, there may be
-some changes where the SDK no longer works as expected on macOS. If you encounter this, please
-[file an issue](https://github.com/firebase/firebase-ios-sdk/issues) for it.
+work on macOS and tvOS, thanks to contributions from the community. There are a few tweaks needed,
+like ensuring iOS-only, macOS-only, or tvOS-only code is correctly guarded with checks for
+`TARGET_OS_IOS`, `TARGET_OS_OSX` and `TARGET_OS_TV`.
+
+For tvOS, checkout the [Sample](Example/tvOSSample).
+
+Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is
+actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there
+may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter
+this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
## Roadmap
diff --git a/cmake/CompilerSetup.cmake b/cmake/CompilerSetup.cmake
new file mode 100644
index 0000000..aa4289a
--- /dev/null
+++ b/cmake/CompilerSetup.cmake
@@ -0,0 +1,96 @@
+# Copyright 2018 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.
+
+# C++ Compiler setup
+
+# We use C++11
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(CLANG ON)
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(GNU ON)
+endif()
+
+if(CLANG OR GNU)
+ set(
+ common_flags
+ -Wall -Wextra -Werror
+
+ # Be super pedantic about format strings
+ -Wformat
+
+ # Avoid use of uninitialized values
+ -Wuninitialized
+ -fno-common
+
+ # Delete unused things
+ -Wunused-function -Wunused-value -Wunused-variable
+ )
+
+ set(
+ cxx_flags
+
+ # Cut down on symbol clutter
+ # TODO(wilhuff) try -fvisibility=hidden
+ -fvisibility-inlines-hidden
+ )
+
+ set(
+ c_flags
+ -Wstrict-prototypes
+ )
+
+ if(CLANG)
+ list(
+ APPEND common_flags
+ -Wconditional-uninitialized -Werror=return-type -Winfinite-recursion -Wmove
+ -Wrange-loop-analysis -Wunreachable-code
+ )
+ endif()
+
+ foreach(flag ${common_flags} ${c_flags})
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
+ endforeach()
+
+ foreach(flag ${common_flags} ${cxx_flags})
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
+ endforeach()
+endif()
+
+if(APPLE)
+ # CMake has no special support for Objective-C as a distinct language but
+ # enabling modules and other clang extensions would apply even to regular C++
+ # sources which is nonportable. Keep these flags separate to avoid misuse.
+ set(
+ OBJC_FLAGS
+ -Werror=deprecated-objc-isa-usage
+ -Werror=non-modular-include-in-framework-module
+ -Werror=objc-root-class
+
+ -Wblock-capture-autoreleasing
+ -Wimplicit-atomic-properties
+ -Wnon-modular-include-in-framework-module
+
+ -fobjc-arc
+ -fmodules
+ -fno-autolink
+
+ -F${FIREBASE_INSTALL_DIR}/Frameworks
+ )
+endif(APPLE)
diff --git a/cmake/ExternalProjectFlags.cmake b/cmake/ExternalProjectFlags.cmake
new file mode 100644
index 0000000..ed4db2c
--- /dev/null
+++ b/cmake/ExternalProjectFlags.cmake
@@ -0,0 +1,71 @@
+# Copyright 2018 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.
+
+include(CMakeParseArguments)
+
+# Assemble the git-related arguments to an external project making use of the
+# latest features where available but avoiding them when run under CMake
+# versions that don't support them.
+#
+# The complete set of git-related arguments are stored as a list in the
+# variable named by RESULT_VAR in the calling scope.
+#
+# Currently this handles:
+# * GIT_SUBMODULES -- added on CMake 3.0 or later. Earlier CMakes will
+# check out all submodules.
+# * GIT_SHALLOW -- added by default on CMake 3.6 or later. Disable by passing
+# GIT_SHALLOW OFF
+# * GIT_PROGRESS -- added by default on CMake 3.8 or later. Disable by
+# passing GIT_PROGRESS OFF
+function(ExternalProject_GitSource RESULT_VAR)
+ # Parse arguments
+ set(options "")
+ set(single_value GIT_REPOSITORY GIT_TAG GIT_PROGRESS GIT_SHALLOW)
+ set(multi_value GIT_SUBMODULES)
+ cmake_parse_arguments(EP "${options}" "${single_value}" "${multi_value}" ${ARGN})
+
+ set(
+ result
+ GIT_REPOSITORY ${EP_GIT_REPOSITORY}
+ GIT_TAG ${EP_GIT_TAG}
+ ${EP_UNPARSED_ARGUMENTS}
+ )
+
+ # CMake 3.0 added support for constraining the set of submodules to clone
+ if(NOT (CMAKE_VERSION VERSION_LESS "3.0") AND EP_GIT_SUBMODULES)
+ list(APPEND result GIT_SUBMODULES ${EP_GIT_SUBMODULES})
+ endif()
+
+ # CMake 3.6 added support for shallow git clones. Use a shallow clone if
+ # available
+ if(NOT (CMAKE_VERSION VERSION_LESS "3.6"))
+ if(NOT EP_GIT_SHALLOW)
+ set(EP_GIT_SHALLOW ON)
+ endif()
+
+ list(APPEND result GIT_SHALLOW ${EP_GIT_SHALLOW})
+ endif()
+
+ # CMake 3.8 added support for showing progress for large downloads
+ if(NOT (CMAKE_VERSION VERSION_LESS "3.8"))
+ if(NOT EP_GIT_PROGRESS)
+ set(EP_GIT_PROGRESS ON)
+ endif()
+
+ list(APPEND result GIT_PROGRESS ${EP_GIT_PROGRESS})
+ endif()
+
+ set(${RESULT_VAR} ${result} PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/FindFirebaseCore.cmake b/cmake/FindFirebaseCore.cmake
new file mode 100644
index 0000000..eec29dd
--- /dev/null
+++ b/cmake/FindFirebaseCore.cmake
@@ -0,0 +1,56 @@
+# Copyright 2017 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.
+
+find_library(
+ FIREBASECORE_LIBRARY
+ FirebaseCore
+ PATHS ${FIREBASE_INSTALL_DIR}/Frameworks
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+ FirebaseCore
+ DEFAULT_MSG
+ FIREBASECORE_LIBRARY
+)
+
+if(FIREBASECORE_FOUND)
+ # Emulate CocoaPods behavior which makes all headers available unqualified.
+ set(
+ FIREBASECORE_INCLUDE_DIRS
+ ${FIREBASECORE_LIBRARY}/Headers
+ ${FIREBASECORE_LIBRARY}/PrivateHeaders
+ )
+
+ set(
+ FIREBASECORE_LIBRARIES
+ ${FIREBASECORE_LIBRARY}
+ "-framework Foundation"
+ )
+
+ if(NOT TARGET FirebaseCore)
+ # Add frameworks as INTERFACE libraries rather than IMPORTED so that
+ # framework behavior is preserved.
+ add_library(FirebaseCore INTERFACE)
+
+ set_property(
+ TARGET FirebaseCore APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES ${FIREBASECORE_INCLUDE_DIRS}
+ )
+ set_property(
+ TARGET FirebaseCore APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES ${FIREBASECORE_LIBRARIES}
+ )
+ endif()
+endif(FIREBASECORE_FOUND)
diff --git a/cmake/FindGRPC.cmake b/cmake/FindGRPC.cmake
new file mode 100644
index 0000000..f594b9e
--- /dev/null
+++ b/cmake/FindGRPC.cmake
@@ -0,0 +1,142 @@
+# Copyright 2018 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.
+
+include(FindPackageHandleStandardArgs)
+include(FindZLIB)
+
+set(BINARY_DIR ${FIREBASE_INSTALL_DIR}/external/grpc)
+
+## ZLIB
+
+# the grpc ExternalProject already figures out if zlib should be built or
+# referenced from its installed location. If it elected to allow grpc to build
+# zlib then it will be available at this location.
+find_library(
+ ZLIB_LIBRARY
+ NAMES z
+ HINTS ${BINARY_DIR}/src/grpc-build/third_party/zlib
+)
+
+# If found above, the standard package will honor the ZLIB_LIBRARY variable.
+find_package(ZLIB REQUIRED)
+
+
+## BoringSSL/OpenSSL
+
+find_path(
+ OPENSSL_INCLUDE_DIR openssl/ssl.h
+ HINTS ${BINARY_DIR}/src/grpc/third_party/boringssl/include
+)
+
+find_library(
+ OPENSSL_SSL_LIBRARY
+ NAMES ssl
+ HINTS ${BINARY_DIR}/src/grpc-build/third_party/boringssl/ssl
+)
+
+find_library(
+ OPENSSL_CRYPTO_LIBRARY
+ NAMES crypto
+ HINTS ${BINARY_DIR}/src/grpc-build/third_party/boringssl/crypto
+)
+
+find_package(OpenSSL REQUIRED)
+
+
+## C-Ares
+
+find_library(
+ CARES_LIBRARY
+ NAMES cares
+ HINTS ${BINARY_DIR}/src/grpc-build/third_party/cares/cares/lib
+)
+if(NOT (CARES_LIBRARY STREQUAL "CARES_LIBRARY-NOTFOUND"))
+ if (NOT TARGET c-ares::ares)
+ add_library(c-ares::ares UNKNOWN IMPORTED)
+ set_target_properties(
+ c-ares::ares PROPERTIES
+ IMPORTED_LOCATION ${CARES_LIBRARY}
+ )
+ endif()
+endif()
+
+
+## GRPC
+
+find_path(
+ GRPC_INCLUDE_DIR grpc/grpc.h
+ HINTS
+ $ENV{GRPC_ROOT}/include
+ ${GRPC_ROOT}/include
+ ${BINARY_DIR}/src/grpc/include
+)
+
+find_library(
+ GPR_LIBRARY
+ NAMES gpr
+ HINTS
+ $ENV{GRPC_ROOT}/lib
+ ${GRPC_ROOT}/lib
+ ${BINARY_DIR}/src/grpc-build
+)
+
+find_library(
+ GRPC_LIBRARY
+ NAMES grpc
+ HINTS
+ $ENV{GRPC_ROOT}/lib
+ ${GRPC_ROOT}/lib
+ ${BINARY_DIR}/src/grpc-build
+)
+
+find_package_handle_standard_args(
+ gRPC
+ DEFAULT_MSG
+ GRPC_INCLUDE_DIR
+ GRPC_LIBRARY
+ GPR_LIBRARY
+)
+
+if(GRPC_FOUND)
+ set(GRPC_INCLUDE_DIRS ${GRPC_INCLUDE_DIR})
+ set(GRPC_LIBRARIES ${GRPC_LIBRARY})
+
+ if (NOT TARGET grpc::gpr)
+ add_library(grpc::gpr UNKNOWN IMPORTED)
+ set_target_properties(
+ grpc::gpr PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR}
+ IMPORTED_LOCATION ${GPR_LIBRARY}
+ )
+ endif()
+
+ if (NOT TARGET grpc::grpc)
+ set(
+ GRPC_LINK_LIBRARIES
+ c-ares::ares
+ grpc::gpr
+ OpenSSL::SSL
+ OpenSSL::Crypto
+ ZLIB::ZLIB
+ )
+
+ add_library(grpc::grpc UNKNOWN IMPORTED)
+ set_target_properties(
+ grpc::grpc PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR}
+ INTERFACE_LINK_LIBRARIES "${GRPC_LINK_LIBRARIES}"
+ IMPORTED_LOCATION ${GRPC_LIBRARY}
+ )
+ endif()
+endif(GRPC_FOUND)
diff --git a/cmake/FindLevelDB.cmake b/cmake/FindLevelDB.cmake
new file mode 100644
index 0000000..b664fa8
--- /dev/null
+++ b/cmake/FindLevelDB.cmake
@@ -0,0 +1,55 @@
+# Copyright 2017 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.
+
+set(binary_dir ${FIREBASE_INSTALL_DIR}/external/leveldb/src/leveldb)
+
+find_path(
+ LEVELDB_INCLUDE_DIR leveldb/db.h
+ HINTS
+ $ENV{LEVELDB_ROOT}/include
+ ${LEVELDB_ROOT}/include
+ ${binary_dir}/include
+ PATH_SUFFIXES leveldb
+)
+
+find_library(
+ LEVELDB_LIBRARY
+ NAMES leveldb
+ HINTS
+ $ENV{LEVELDB_ROOT}/lib
+ ${LEVELDB_ROOT}/lib
+ ${binary_dir}/out-static
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+ LevelDB
+ DEFAULT_MSG
+ LEVELDB_INCLUDE_DIR
+ LEVELDB_LIBRARY
+)
+
+if(LEVELDB_FOUND)
+ set(LEVELDB_INCLUDE_DIRS ${LEVELDB_INCLUDE_DIR})
+ set(LEVELDB_LIBRARIES ${LEVELDB_LIBRARY})
+
+ if (NOT TARGET LevelDB::LevelDB)
+ add_library(LevelDB::LevelDB UNKNOWN IMPORTED)
+ set_target_properties(
+ LevelDB::LevelDB PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES ${LEVELDB_INCLUDE_DIR}
+ IMPORTED_LOCATION ${LEVELDB_LIBRARY}
+ )
+ endif()
+endif(LEVELDB_FOUND)
diff --git a/cmake/external/FirebaseCore.cmake b/cmake/external/FirebaseCore.cmake
new file mode 100644
index 0000000..8be6969
--- /dev/null
+++ b/cmake/external/FirebaseCore.cmake
@@ -0,0 +1,23 @@
+# Copyright 2017 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.
+
+include(xcodebuild)
+
+if(APPLE)
+ # FirebaseCore is only available as a CocoaPod build.
+ xcodebuild(FirebaseCore)
+else()
+ # On non-Apple platforms, there's no way to build FirebaseCore.
+ add_custom_target(FirebaseCore)
+endif()
diff --git a/cmake/external/firestore.cmake b/cmake/external/firestore.cmake
index 5316873..1a89435 100644
--- a/cmake/external/firestore.cmake
+++ b/cmake/external/firestore.cmake
@@ -14,27 +14,26 @@
include(ExternalProject)
-set(source_dir ${PROJECT_SOURCE_DIR}/Firestore)
-set(binary_dir ${PROJECT_BINARY_DIR}/Firestore)
-
ExternalProject_Add(
Firestore
- DEPENDS googletest
+ DEPENDS
+ FirebaseCore
+ googletest
+ leveldb
+ grpc
# Lay the binary directory out as if this were a subproject. This makes it
# possible to build and test in it directly.
- PREFIX ${binary_dir}
- SOURCE_DIR ${source_dir}
- BINARY_DIR ${binary_dir}
+ PREFIX ${PROJECT_BINARY_DIR}/external/Firestore
+ SOURCE_DIR ${PROJECT_SOURCE_DIR}/Firestore
+ BINARY_DIR ${PROJECT_BINARY_DIR}/Firestore
+
+ CMAKE_ARGS
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DCMAKE_INSTALL_PREFIX:PATH=${FIREBASE_INSTALL_DIR}
+
BUILD_ALWAYS ON
- # Even though this isn't installed, set up the INSTALL_DIR so that
- # find_package can find dependencies built from source.
- INSTALL_DIR ${FIREBASE_INSTALL_DIR}
INSTALL_COMMAND ""
TEST_BEFORE_INSTALL ON
-
- CMAKE_ARGS
- -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
- -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)
diff --git a/cmake/external/googletest.cmake b/cmake/external/googletest.cmake
index a956e9f..56a5f13 100644
--- a/cmake/external/googletest.cmake
+++ b/cmake/external/googletest.cmake
@@ -13,22 +13,26 @@
# limitations under the License.
include(ExternalProject)
+include(ExternalProjectFlags)
+
+ExternalProject_GitSource(
+ GOOGLETEST_GIT
+ GIT_REPOSITORY "https://github.com/google/googletest.git"
+ GIT_TAG "release-1.8.0"
+)
ExternalProject_Add(
googletest
+ DEPENDS
+ FirebaseCore # for sequencing
- URL "https://github.com/google/googletest/archive/release-1.8.0.tar.gz"
- URL_HASH "SHA256=58a6f4277ca2bc8565222b3bbd58a177609e9c488e8a72649359ba51450db7d8"
+ ${GOOGLETEST_GIT}
- PREFIX ${PROJECT_BINARY_DIR}/third_party/googletest
-
- DOWNLOAD_DIR ${FIREBASE_DOWNLOAD_DIR}
- INSTALL_DIR ${FIREBASE_INSTALL_DIR}
+ PREFIX ${PROJECT_BINARY_DIR}/external/googletest
+ # Just download the sources without building.
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
TEST_COMMAND ""
-
- CMAKE_ARGS
- -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
- -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
- -DBUILD_SHARED_LIBS:BOOL=OFF
)
diff --git a/cmake/external/grpc.cmake b/cmake/external/grpc.cmake
new file mode 100644
index 0000000..fb54960
--- /dev/null
+++ b/cmake/external/grpc.cmake
@@ -0,0 +1,83 @@
+# Copyright 2018 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.
+
+include(ExternalProject)
+include(ExternalProjectFlags)
+include(FindZLIB)
+
+if(GRPC_ROOT)
+ # If the user has supplied a GRPC_ROOT then just use it. Add an empty custom
+ # target so that the superbuild dependencies still work.
+ add_custom_target(grpc)
+
+else()
+ set(
+ GIT_SUBMODULES
+ third_party/boringssl
+ third_party/cares/cares
+ )
+
+ set(
+ CMAKE_ARGS
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DgRPC_BUILD_TESTS:BOOL=OFF
+ -DBUILD_SHARED_LIBS:BOOL=OFF
+ )
+
+ # zlib can be built by grpc but we can avoid it on platforms that provide it
+ # by default.
+ find_package(ZLIB)
+ if(ZLIB_FOUND)
+ list(
+ APPEND CMAKE_ARGS
+ -DgRPC_ZLIB_PROVIDER:STRING=package
+ -DZLIB_INCLUDE_DIR=${ZLIB_INCLUDE_DIR}
+ -DZLIB_LIBRARY=${ZLIB_LIBRARY}
+ )
+
+ else()
+ list(
+ APPEND GIT_SUBMODULES
+ third_party/zlib
+ )
+
+ endif(ZLIB_FOUND)
+
+ ExternalProject_GitSource(
+ GRPC_GIT
+ GIT_REPOSITORY "https://github.com/grpc/grpc.git"
+ GIT_TAG "v1.8.3"
+ GIT_SUBMODULES ${GIT_SUBMODULES}
+ )
+
+ ExternalProject_Add(
+ grpc
+ DEPENDS
+ leveldb # for sequencing
+
+ ${GRPC_GIT}
+
+ PREFIX ${PROJECT_BINARY_DIR}/external/grpc
+
+ CMAKE_ARGS ${CMAKE_ARGS}
+
+ BUILD_COMMAND
+ ${CMAKE_COMMAND} --build . --target grpc
+
+ TEST_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+
+endif(GRPC_ROOT)
+
diff --git a/cmake/external/leveldb.cmake b/cmake/external/leveldb.cmake
new file mode 100644
index 0000000..5b2068a
--- /dev/null
+++ b/cmake/external/leveldb.cmake
@@ -0,0 +1,79 @@
+# Copyright 2017 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.
+
+include(ExternalProject)
+include(ExternalProjectFlags)
+
+if(WIN32 OR LEVELDB_ROOT)
+ # If the user has supplied a LEVELDB_ROOT then just use it. Add an empty
+ # custom target so that the superbuild depdendencies don't all have to be
+ # conditional.
+ #
+ # Also, unfortunately, LevelDB does not build on Windows (yet)
+ # See:
+ # https://github.com/google/leveldb/issues/363
+ # https://github.com/google/leveldb/issues/466
+ add_custom_target(leveldb)
+
+else()
+ # Clean up warning output to reduce noise in the build
+ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
+ set(
+ LEVELDB_CXX_FLAGS "\
+ -Wno-deprecated-declarations"
+ )
+ endif()
+
+ # Map CMake compiler configuration down onto the leveldb Makefile
+ set(
+ LEVELDB_OPT "\
+ $<$<CONFIG:Debug>:${CMAKE_CXX_FLAGS_DEBUG}> \
+ $<$<CONFIG:Release>:${CMAKE_CXX_FLAGS_RELEASE}>"
+ )
+
+ ExternalProject_GitSource(
+ LEVELDB_GIT
+ GIT_REPOSITORY "https://github.com/google/leveldb.git"
+ GIT_TAG "v1.20"
+ )
+
+ ExternalProject_Add(
+ leveldb
+ DEPENDS
+ googletest # for sequencing
+
+ ${LEVELDB_GIT}
+
+ PREFIX ${PROJECT_BINARY_DIR}/external/leveldb
+
+ # LevelDB's configuration is done in the Makefile
+ CONFIGURE_COMMAND ""
+
+ # The Makefile-based build of leveldb does not support building
+ # out-of-source.
+ BUILD_IN_SOURCE ON
+
+ # Only build the leveldb library skipping the tools and in-memory
+ # implementation we don't use.
+ BUILD_COMMAND
+ env CXXFLAGS=${LEVELDB_CXX_FLAGS} OPT=${LEVELDB_OPT}
+ make -j out-static/libleveldb.a
+
+ INSTALL_DIR ${FIREBASE_INSTALL_DIR}
+
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+
+endif(WIN32 OR LEVELDB_ROOT)
diff --git a/cmake/utils.cmake b/cmake/utils.cmake
index 54044d6..1c3cbd6 100644
--- a/cmake/utils.cmake
+++ b/cmake/utils.cmake
@@ -12,16 +12,80 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Defines a new test executable and does all the things we want done with
-# tests:
+include(CMakeParseArguments)
+
+# cc_library(
+# target
+# SOURCES sources...
+# DEPENDS libraries...
+# )
+#
+# Defines a new library target with the given target name, sources, and dependencies.
+function(cc_library name)
+ set(flag EXCLUDE_FROM_ALL)
+ set(multi DEPENDS SOURCES)
+ cmake_parse_arguments(ccl "${flag}" "" "${multi}" ${ARGN})
+
+ add_library(
+ ${name}
+ ${ccl_SOURCES}
+ )
+ add_objc_flags(${name} ccl)
+ target_link_libraries(
+ ${name}
+ PUBLIC
+ ${ccl_DEPENDS}
+ )
+
+ if(ccl_EXCLUDE_FROM_ALL)
+ set_property(
+ TARGET ${name}
+ PROPERTY EXCLUDE_FROM_ALL ON
+ )
+ endif()
+
+endfunction()
+
+# cc_test(
+# target
+# SOURCES sources...
+# DEPENDS libraries...
+# )
#
-# * add_executable (with the given arguments)
-# * add_Test - defines a test with the same name
-# * declares that the test links against gtest
-# * adds the executable as a dependency of the `check` target.
+# Defines a new test executable target with the given target name, sources, and
+# dependencies. Implicitly adds DEPENDS on GTest::GTest and GTest::Main.
function(cc_test name)
- add_executable(${name} ${ARGN})
+ set(multi DEPENDS SOURCES)
+ cmake_parse_arguments(cct "" "" "${multi}" ${ARGN})
+
+ list(APPEND cct_DEPENDS GTest::GTest GTest::Main)
+
+ add_executable(${name} ${cct_SOURCES})
+ add_objc_flags(${name} cct)
add_test(${name} ${name})
- target_link_libraries(${name} GTest::GTest GTest::Main)
+ target_link_libraries(${name} ${cct_DEPENDS})
+endfunction()
+
+# add_objc_flags(target sources...)
+#
+# Adds OBJC_FLAGS to the compile options of the given target if any of the
+# sources have filenames that indicate they are are Objective-C.
+function(add_objc_flags target)
+ set(_has_objc OFF)
+
+ foreach(source ${ARGN})
+ get_filename_component(ext ${source} EXT)
+ if((ext STREQUAL ".m") OR (ext STREQUAL ".mm"))
+ set(_has_objc ON)
+ endif()
+ endforeach()
+
+ if(_has_objc)
+ target_compile_options(
+ ${target}
+ PRIVATE
+ ${OBJC_FLAGS}
+ )
+ endif()
endfunction()
diff --git a/cmake/xcodebuild.cmake b/cmake/xcodebuild.cmake
new file mode 100644
index 0000000..01a2961
--- /dev/null
+++ b/cmake/xcodebuild.cmake
@@ -0,0 +1,89 @@
+# Copyright 2017 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.
+
+include(CMakeParseArguments)
+include(ExternalProject)
+
+# Builds an existing Xcode project or workspace as an external project in CMake.
+#
+# xcodebuild(<framework> [<option>...])
+#
+# Options:
+# ``DEPENDS <projects>...``
+# Targets on which the project depends
+# ``SCHEME <scheme>``
+# The scheme to build in the workspace, defaults to <framework>-<platform>,
+# where <platform> is always "macOS".
+# ``WORKSPACE <workspace>``
+# Location of the xcworkspace file containing the target to build. Defaults to
+# Example/Firebase.xcworkspace.
+function(xcodebuild framework)
+ # Parse arguments
+ set(options "")
+ set(single_value SCHEME WORKSPACE)
+ set(multi_value DEPENDS)
+ cmake_parse_arguments(xcb "${options}" "${single_value}" "${multi_value}" ${ARGN})
+
+ if(NOT xcb_WORKSPACE)
+ set(xcb_WORKSPACE ${PROJECT_SOURCE_DIR}/Example/Firebase.xcworkspace)
+ endif()
+
+ # TODO(mcg): Investigate supporting non-macOS platforms
+ # The canonical way to build and test for iOS is via Xcode and CocoaPods so
+ # it's not super important to make this work here
+ set(platform macOS)
+ set(destination "platform=macOS,arch=x86_64")
+ set(scheme "${framework}-${platform}")
+
+ # CMake has a variety of release types, but Xcode has just one by default.
+ if(CMAKE_BUILD_TYPE STREQUAL Debug)
+ set(configuration Debug)
+ else()
+ set(configuration Release)
+ endif()
+
+ # Pipe build output through xcpretty if it's available
+ find_program(xcpretty_cmd xcpretty)
+ if(xcpretty_cmd)
+ set(pipe_xcpretty "|" ${xcpretty_cmd})
+ endif()
+
+ ExternalProject_Add(
+ ${framework}
+ DEPENDS ${xcb_DEPENDS}
+
+ PREFIX ${PROJECT_BINARY_DIR}/external/${framework}
+
+ # The source directory doesn't actually matter
+ SOURCE_DIR ${PROJECT_SOURCE_DIR}
+ BINARY_DIR ${PROJECT_BINARY_DIR}/Frameworks
+
+ CONFIGURE_COMMAND ""
+
+ BUILD_COMMAND
+ xcodebuild
+ -workspace ${xcb_WORKSPACE}
+ -scheme ${scheme}
+ -configuration ${configuration}
+ -destination ${destination}
+ CONFIGURATION_BUILD_DIR=<BINARY_DIR>
+ build
+ ${pipe_xcpretty}
+ BUILD_ALWAYS ${BUILD_PODS}
+
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+
+endfunction()
diff --git a/patch/FirebaseAnalytics.h b/patch/FirebaseAnalytics.h
index 72c55c6..4850741 100644
--- a/patch/FirebaseAnalytics.h
+++ b/patch/FirebaseAnalytics.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2018 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.
+ */
+
// Firebase Analytics umbrella header for interoperating with open source builds
// More details at https://github.com/firebase/firebase-ios-sdk#source-pod-integration
diff --git a/scripts/cpplint.py b/scripts/cpplint.py
new file mode 100644
index 0000000..53dbe81
--- /dev/null
+++ b/scripts/cpplint.py
@@ -0,0 +1,6228 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Does google-lint on c++ files.
+
+The goal of this script is to identify places in the code that *may*
+be in non-compliance with google style. It does not attempt to fix
+up these problems -- the point is to educate. It does also not
+attempt to find all problems, or to ensure that everything it does
+find is legitimately a problem.
+
+In particular, we can get very confused by /* and // inside strings!
+We do a small hack, which is to ignore //'s with "'s after them on the
+same line, but it is far from perfect (in either direction).
+"""
+
+import codecs
+import copy
+import getopt
+import math # for log
+import os
+import re
+import sre_compile
+import string
+import sys
+import unicodedata
+
+
+_USAGE = """
+Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
+ [--counting=total|toplevel|detailed] [--root=subdir]
+ [--linelength=digits] [--headers=x,y,...]
+ [--quiet]
+ <file> [file] ...
+
+ The style guidelines this tries to follow are those in
+ https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+
+ Every problem is given a confidence score from 1-5, with 5 meaning we are
+ certain of the problem, and 1 meaning it could be a legitimate construct.
+ This will miss some errors, and is not a substitute for a code review.
+
+ To suppress false-positive errors of a certain category, add a
+ 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
+ suppresses errors of all categories on that line.
+
+ The files passed in will be linted; at least one file must be provided.
+ Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the
+ extensions with the --extensions flag.
+
+ Flags:
+
+ output=vs7
+ By default, the output is formatted to ease emacs parsing. Visual Studio
+ compatible output (vs7) may also be used. Other formats are unsupported.
+
+ verbose=#
+ Specify a number 0-5 to restrict errors to certain verbosity levels.
+
+ quiet
+ Don't print anything if no errors are found.
+
+ filter=-x,+y,...
+ Specify a comma-separated list of category-filters to apply: only
+ error messages whose category names pass the filters will be printed.
+ (Category names are printed with the message and look like
+ "[whitespace/indent]".) Filters are evaluated left to right.
+ "-FOO" and "FOO" means "do not print categories that start with FOO".
+ "+FOO" means "do print categories that start with FOO".
+
+ Examples: --filter=-whitespace,+whitespace/braces
+ --filter=whitespace,runtime/printf,+runtime/printf_format
+ --filter=-,+build/include_what_you_use
+
+ To see a list of all the categories used in cpplint, pass no arg:
+ --filter=
+
+ counting=total|toplevel|detailed
+ The total number of errors found is always printed. If
+ 'toplevel' is provided, then the count of errors in each of
+ the top-level categories like 'build' and 'whitespace' will
+ also be printed. If 'detailed' is provided, then a count
+ is provided for each category like 'build/class'.
+
+ root=subdir
+ The root directory used for deriving header guard CPP variable.
+ By default, the header guard CPP variable is calculated as the relative
+ path to the directory that contains .git, .hg, or .svn. When this flag
+ is specified, the relative path is calculated from the specified
+ directory. If the specified directory does not exist, this flag is
+ ignored.
+
+ Examples:
+ Assuming that top/src/.git exists (and cwd=top/src), the header guard
+ CPP variables for top/src/chrome/browser/ui/browser.h are:
+
+ No flag => CHROME_BROWSER_UI_BROWSER_H_
+ --root=chrome => BROWSER_UI_BROWSER_H_
+ --root=chrome/browser => UI_BROWSER_H_
+ --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_
+
+ linelength=digits
+ This is the allowed line length for the project. The default value is
+ 80 characters.
+
+ Examples:
+ --linelength=120
+
+ extensions=extension,extension,...
+ The allowed file extensions that cpplint will check
+
+ Examples:
+ --extensions=hpp,cpp
+
+ headers=x,y,...
+ The header extensions that cpplint will treat as .h in checks. Values are
+ automatically added to --extensions list.
+
+ Examples:
+ --headers=hpp,hxx
+ --headers=hpp
+
+ cpplint.py supports per-directory configurations specified in CPPLINT.cfg
+ files. CPPLINT.cfg file can contain a number of key=value pairs.
+ Currently the following options are supported:
+
+ set noparent
+ filter=+filter1,-filter2,...
+ exclude_files=regex
+ linelength=80
+ root=subdir
+ headers=x,y,...
+
+ "set noparent" option prevents cpplint from traversing directory tree
+ upwards looking for more .cfg files in parent directories. This option
+ is usually placed in the top-level project directory.
+
+ The "filter" option is similar in function to --filter flag. It specifies
+ message filters in addition to the |_DEFAULT_FILTERS| and those specified
+ through --filter command-line flag.
+
+ "exclude_files" allows to specify a regular expression to be matched against
+ a file name. If the expression matches, the file is skipped and not run
+ through liner.
+
+ "linelength" allows to specify the allowed line length for the project.
+
+ The "root" option is similar in function to the --root flag (see example
+ above). Paths are relative to the directory of the CPPLINT.cfg.
+
+ The "headers" option is similar in function to the --headers flag
+ (see example above).
+
+ CPPLINT.cfg has an effect on files in the same directory and all
+ sub-directories, unless overridden by a nested configuration file.
+
+ Example file:
+ filter=-build/include_order,+build/include_alpha
+ exclude_files=.*\.cc
+
+ The above example disables build/include_order warning and enables
+ build/include_alpha as well as excludes all .cc from being
+ processed by linter, in the current directory (where the .cfg
+ file is located) and all sub-directories.
+"""
+
+# We categorize each error message we print. Here are the categories.
+# We want an explicit list so we can list them all in cpplint --filter=.
+# If you add a new error message with a new category, add it to the list
+# here! cpplint_unittest.py should tell you if you forget to do this.
+_ERROR_CATEGORIES = [
+ 'build/class',
+ 'build/c++11',
+ 'build/c++14',
+ 'build/c++tr1',
+ 'build/deprecated',
+ 'build/endif_comment',
+ 'build/explicit_make_pair',
+ 'build/forward_decl',
+ 'build/header_guard',
+ 'build/include',
+ 'build/include_alpha',
+ 'build/include_order',
+ 'build/include_what_you_use',
+ 'build/namespaces',
+ 'build/printf_format',
+ 'build/storage_class',
+ 'legal/copyright',
+ 'readability/alt_tokens',
+ 'readability/braces',
+ 'readability/casting',
+ 'readability/check',
+ 'readability/constructors',
+ 'readability/fn_size',
+ 'readability/inheritance',
+ 'readability/multiline_comment',
+ 'readability/multiline_string',
+ 'readability/namespace',
+ 'readability/nolint',
+ 'readability/nul',
+ 'readability/strings',
+ 'readability/todo',
+ 'readability/utf8',
+ 'runtime/arrays',
+ 'runtime/casting',
+ 'runtime/explicit',
+ 'runtime/int',
+ 'runtime/init',
+ 'runtime/invalid_increment',
+ 'runtime/member_string_references',
+ 'runtime/memset',
+ 'runtime/indentation_namespace',
+ 'runtime/operator',
+ 'runtime/printf',
+ 'runtime/printf_format',
+ 'runtime/references',
+ 'runtime/string',
+ 'runtime/threadsafe_fn',
+ 'runtime/vlog',
+ 'whitespace/blank_line',
+ 'whitespace/braces',
+ 'whitespace/comma',
+ 'whitespace/comments',
+ 'whitespace/empty_conditional_body',
+ 'whitespace/empty_if_body',
+ 'whitespace/empty_loop_body',
+ 'whitespace/end_of_line',
+ 'whitespace/ending_newline',
+ 'whitespace/forcolon',
+ 'whitespace/indent',
+ 'whitespace/line_length',
+ 'whitespace/newline',
+ 'whitespace/operators',
+ 'whitespace/parens',
+ 'whitespace/semicolon',
+ 'whitespace/tab',
+ 'whitespace/todo',
+ ]
+
+# These error categories are no longer enforced by cpplint, but for backwards-
+# compatibility they may still appear in NOLINT comments.
+_LEGACY_ERROR_CATEGORIES = [
+ 'readability/streams',
+ 'readability/function',
+ ]
+
+# The default state of the category filter. This is overridden by the --filter=
+# flag. By default all errors are on, so only add here categories that should be
+# off by default (i.e., categories that must be enabled by the --filter= flags).
+# All entries here should start with a '-' or '+', as in the --filter= flag.
+_DEFAULT_FILTERS = ['-build/include_alpha']
+
+# The default list of categories suppressed for C (not C++) files.
+_DEFAULT_C_SUPPRESSED_CATEGORIES = [
+ 'readability/casting',
+ ]
+
+# The default list of categories suppressed for Linux Kernel files.
+_DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [
+ 'whitespace/tab',
+ ]
+
+# We used to check for high-bit characters, but after much discussion we
+# decided those were OK, as long as they were in UTF-8 and didn't represent
+# hard-coded international strings, which belong in a separate i18n file.
+
+# C++ headers
+_CPP_HEADERS = frozenset([
+ # Legacy
+ 'algobase.h',
+ 'algo.h',
+ 'alloc.h',
+ 'builtinbuf.h',
+ 'bvector.h',
+ 'complex.h',
+ 'defalloc.h',
+ 'deque.h',
+ 'editbuf.h',
+ 'fstream.h',
+ 'function.h',
+ 'hash_map',
+ 'hash_map.h',
+ 'hash_set',
+ 'hash_set.h',
+ 'hashtable.h',
+ 'heap.h',
+ 'indstream.h',
+ 'iomanip.h',
+ 'iostream.h',
+ 'istream.h',
+ 'iterator.h',
+ 'list.h',
+ 'map.h',
+ 'multimap.h',
+ 'multiset.h',
+ 'ostream.h',
+ 'pair.h',
+ 'parsestream.h',
+ 'pfstream.h',
+ 'procbuf.h',
+ 'pthread_alloc',
+ 'pthread_alloc.h',
+ 'rope',
+ 'rope.h',
+ 'ropeimpl.h',
+ 'set.h',
+ 'slist',
+ 'slist.h',
+ 'stack.h',
+ 'stdiostream.h',
+ 'stl_alloc.h',
+ 'stl_relops.h',
+ 'streambuf.h',
+ 'stream.h',
+ 'strfile.h',
+ 'strstream.h',
+ 'tempbuf.h',
+ 'tree.h',
+ 'type_traits.h',
+ 'vector.h',
+ # 17.6.1.2 C++ library headers
+ 'algorithm',
+ 'array',
+ 'atomic',
+ 'bitset',
+ 'chrono',
+ 'codecvt',
+ 'complex',
+ 'condition_variable',
+ 'deque',
+ 'exception',
+ 'forward_list',
+ 'fstream',
+ 'functional',
+ 'future',
+ 'initializer_list',
+ 'iomanip',
+ 'ios',
+ 'iosfwd',
+ 'iostream',
+ 'istream',
+ 'iterator',
+ 'limits',
+ 'list',
+ 'locale',
+ 'map',
+ 'memory',
+ 'mutex',
+ 'new',
+ 'numeric',
+ 'ostream',
+ 'queue',
+ 'random',
+ 'ratio',
+ 'regex',
+ 'scoped_allocator',
+ 'set',
+ 'sstream',
+ 'stack',
+ 'stdexcept',
+ 'streambuf',
+ 'string',
+ 'strstream',
+ 'system_error',
+ 'thread',
+ 'tuple',
+ 'typeindex',
+ 'typeinfo',
+ 'type_traits',
+ 'unordered_map',
+ 'unordered_set',
+ 'utility',
+ 'valarray',
+ 'vector',
+ # 17.6.1.2 C++ headers for C library facilities
+ 'cassert',
+ 'ccomplex',
+ 'cctype',
+ 'cerrno',
+ 'cfenv',
+ 'cfloat',
+ 'cinttypes',
+ 'ciso646',
+ 'climits',
+ 'clocale',
+ 'cmath',
+ 'csetjmp',
+ 'csignal',
+ 'cstdalign',
+ 'cstdarg',
+ 'cstdbool',
+ 'cstddef',
+ 'cstdint',
+ 'cstdio',
+ 'cstdlib',
+ 'cstring',
+ 'ctgmath',
+ 'ctime',
+ 'cuchar',
+ 'cwchar',
+ 'cwctype',
+ ])
+
+# Type names
+_TYPES = re.compile(
+ r'^(?:'
+ # [dcl.type.simple]
+ r'(char(16_t|32_t)?)|wchar_t|'
+ r'bool|short|int|long|signed|unsigned|float|double|'
+ # [support.types]
+ r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|'
+ # [cstdint.syn]
+ r'(u?int(_fast|_least)?(8|16|32|64)_t)|'
+ r'(u?int(max|ptr)_t)|'
+ r')$')
+
+
+# These headers are excluded from [build/include] and [build/include_order]
+# checks:
+# - Anything not following google file name conventions (containing an
+# uppercase character, such as Python.h or nsStringAPI.h, for example).
+# - Lua headers.
+_THIRD_PARTY_HEADERS_PATTERN = re.compile(
+ r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
+
+# Pattern for matching FileInfo.BaseName() against test file name
+_TEST_FILE_SUFFIX = r'(_test|_unittest|_regtest)$'
+
+# Pattern that matches only complete whitespace, possibly across multiple lines.
+_EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL)
+
+# Assertion macros. These are defined in base/logging.h and
+# testing/base/public/gunit.h.
+_CHECK_MACROS = [
+ 'DCHECK', 'CHECK',
+ 'EXPECT_TRUE', 'ASSERT_TRUE',
+ 'EXPECT_FALSE', 'ASSERT_FALSE',
+ ]
+
+# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
+_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
+
+for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
+ ('>=', 'GE'), ('>', 'GT'),
+ ('<=', 'LE'), ('<', 'LT')]:
+ _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
+ _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
+
+for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
+ ('>=', 'LT'), ('>', 'LE'),
+ ('<=', 'GT'), ('<', 'GE')]:
+ _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
+
+# Alternative tokens and their replacements. For full list, see section 2.5
+# Alternative tokens [lex.digraph] in the C++ standard.
+#
+# Digraphs (such as '%:') are not included here since it's a mess to
+# match those on a word boundary.
+_ALT_TOKEN_REPLACEMENT = {
+ 'and': '&&',
+ 'bitor': '|',
+ 'or': '||',
+ 'xor': '^',
+ 'compl': '~',
+ 'bitand': '&',
+ 'and_eq': '&=',
+ 'or_eq': '|=',
+ 'xor_eq': '^=',
+ 'not': '!',
+ 'not_eq': '!='
+ }
+
+# Compile regular expression that matches all the above keywords. The "[ =()]"
+# bit is meant to avoid matching these keywords outside of boolean expressions.
+#
+# False positives include C-style multi-line comments and multi-line strings
+# but those have always been troublesome for cpplint.
+_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
+ r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
+
+
+# These constants define types of headers for use with
+# _IncludeState.CheckNextIncludeOrder().
+_C_SYS_HEADER = 1
+_CPP_SYS_HEADER = 2
+_LIKELY_MY_HEADER = 3
+_POSSIBLE_MY_HEADER = 4
+_OTHER_HEADER = 5
+
+# These constants define the current inline assembly state
+_NO_ASM = 0 # Outside of inline assembly block
+_INSIDE_ASM = 1 # Inside inline assembly block
+_END_ASM = 2 # Last line of inline assembly block
+_BLOCK_ASM = 3 # The whole block is an inline assembly block
+
+# Match start of assembly blocks
+_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
+ r'(?:\s+(volatile|__volatile__))?'
+ r'\s*[{(]')
+
+# Match strings that indicate we're working on a C (not C++) file.
+_SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|'
+ r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))')
+
+# Match string that indicates we're working on a Linux Kernel file.
+_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)')
+
+_regexp_compile_cache = {}
+
+# {str, set(int)}: a map from error categories to sets of linenumbers
+# on which those errors are expected and should be suppressed.
+_error_suppressions = {}
+
+# The root directory used for deriving header guard CPP variable.
+# This is set by --root flag.
+_root = None
+_root_debug = False
+
+# The allowed line length of files.
+# This is set by --linelength flag.
+_line_length = 80
+
+# The allowed extensions for file names
+# This is set by --extensions flag.
+_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
+
+# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc.
+# This is set by --headers flag.
+_hpp_headers = set(['h'])
+
+# {str, bool}: a map from error categories to booleans which indicate if the
+# category should be suppressed for every line.
+_global_error_suppressions = {}
+
+def ProcessHppHeadersOption(val):
+ global _hpp_headers
+ try:
+ _hpp_headers = set(val.split(','))
+ # Automatically append to extensions list so it does not have to be set 2 times
+ _valid_extensions.update(_hpp_headers)
+ except ValueError:
+ PrintUsage('Header extensions must be comma seperated list.')
+
+def IsHeaderExtension(file_extension):
+ return file_extension in _hpp_headers
+
+def ParseNolintSuppressions(filename, raw_line, linenum, error):
+ """Updates the global list of line error-suppressions.
+
+ Parses any NOLINT comments on the current line, updating the global
+ error_suppressions store. Reports an error if the NOLINT comment
+ was malformed.
+
+ Args:
+ filename: str, the name of the input file.
+ raw_line: str, the line of input text, with comments.
+ linenum: int, the number of the current line.
+ error: function, an error handler.
+ """
+ matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)
+ if matched:
+ if matched.group(1):
+ suppressed_line = linenum + 1
+ else:
+ suppressed_line = linenum
+ category = matched.group(2)
+ if category in (None, '(*)'): # => "suppress all"
+ _error_suppressions.setdefault(None, set()).add(suppressed_line)
+ else:
+ if category.startswith('(') and category.endswith(')'):
+ category = category[1:-1]
+ if category in _ERROR_CATEGORIES:
+ _error_suppressions.setdefault(category, set()).add(suppressed_line)
+ elif category not in _LEGACY_ERROR_CATEGORIES:
+ error(filename, linenum, 'readability/nolint', 5,
+ 'Unknown NOLINT error category: %s' % category)
+
+
+def ProcessGlobalSuppresions(lines):
+ """Updates the list of global error suppressions.
+
+ Parses any lint directives in the file that have global effect.
+
+ Args:
+ lines: An array of strings, each representing a line of the file, with the
+ last element being empty if the file is terminated with a newline.
+ """
+ for line in lines:
+ if _SEARCH_C_FILE.search(line):
+ for category in _DEFAULT_C_SUPPRESSED_CATEGORIES:
+ _global_error_suppressions[category] = True
+ if _SEARCH_KERNEL_FILE.search(line):
+ for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES:
+ _global_error_suppressions[category] = True
+
+
+def ResetNolintSuppressions():
+ """Resets the set of NOLINT suppressions to empty."""
+ _error_suppressions.clear()
+ _global_error_suppressions.clear()
+
+
+def IsErrorSuppressedByNolint(category, linenum):
+ """Returns true if the specified error category is suppressed on this line.
+
+ Consults the global error_suppressions map populated by
+ ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions.
+
+ Args:
+ category: str, the category of the error.
+ linenum: int, the current line number.
+ Returns:
+ bool, True iff the error should be suppressed due to a NOLINT comment or
+ global suppression.
+ """
+ return (_global_error_suppressions.get(category, False) or
+ linenum in _error_suppressions.get(category, set()) or
+ linenum in _error_suppressions.get(None, set()))
+
+
+def Match(pattern, s):
+ """Matches the string with the pattern, caching the compiled regexp."""
+ # The regexp compilation caching is inlined in both Match and Search for
+ # performance reasons; factoring it out into a separate function turns out
+ # to be noticeably expensive.
+ if pattern not in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].match(s)
+
+
+def ReplaceAll(pattern, rep, s):
+ """Replaces instances of pattern in a string with a replacement.
+
+ The compiled regex is kept in a cache shared by Match and Search.
+
+ Args:
+ pattern: regex pattern
+ rep: replacement text
+ s: search string
+
+ Returns:
+ string with replacements made (or original string if no replacements)
+ """
+ if pattern not in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].sub(rep, s)
+
+
+def Search(pattern, s):
+ """Searches the string for the pattern, caching the compiled regexp."""
+ if pattern not in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].search(s)
+
+
+def _IsSourceExtension(s):
+ """File extension (excluding dot) matches a source file extension."""
+ return s in ('c', 'cc', 'cpp', 'cxx')
+
+
+class _IncludeState(object):
+ """Tracks line numbers for includes, and the order in which includes appear.
+
+ include_list contains list of lists of (header, line number) pairs.
+ It's a lists of lists rather than just one flat list to make it
+ easier to update across preprocessor boundaries.
+
+ Call CheckNextIncludeOrder() once for each header in the file, passing
+ in the type constants defined above. Calls in an illegal order will
+ raise an _IncludeError with an appropriate error message.
+
+ """
+ # self._section will move monotonically through this set. If it ever
+ # needs to move backwards, CheckNextIncludeOrder will raise an error.
+ _INITIAL_SECTION = 0
+ _MY_H_SECTION = 1
+ _C_SECTION = 2
+ _CPP_SECTION = 3
+ _OTHER_H_SECTION = 4
+
+ _TYPE_NAMES = {
+ _C_SYS_HEADER: 'C system header',
+ _CPP_SYS_HEADER: 'C++ system header',
+ _LIKELY_MY_HEADER: 'header this file implements',
+ _POSSIBLE_MY_HEADER: 'header this file may implement',
+ _OTHER_HEADER: 'other header',
+ }
+ _SECTION_NAMES = {
+ _INITIAL_SECTION: "... nothing. (This can't be an error.)",
+ _MY_H_SECTION: 'a header this file implements',
+ _C_SECTION: 'C system header',
+ _CPP_SECTION: 'C++ system header',
+ _OTHER_H_SECTION: 'other header',
+ }
+
+ def __init__(self):
+ self.include_list = [[]]
+ self.ResetSection('')
+
+ def FindHeader(self, header):
+ """Check if a header has already been included.
+
+ Args:
+ header: header to check.
+ Returns:
+ Line number of previous occurrence, or -1 if the header has not
+ been seen before.
+ """
+ for section_list in self.include_list:
+ for f in section_list:
+ if f[0] == header:
+ return f[1]
+ return -1
+
+ def ResetSection(self, directive):
+ """Reset section checking for preprocessor directive.
+
+ Args:
+ directive: preprocessor directive (e.g. "if", "else").
+ """
+ # The name of the current section.
+ self._section = self._INITIAL_SECTION
+ # The path of last found header.
+ self._last_header = ''
+
+ # Update list of includes. Note that we never pop from the
+ # include list.
+ if directive in ('if', 'ifdef', 'ifndef'):
+ self.include_list.append([])
+ elif directive in ('else', 'elif'):
+ self.include_list[-1] = []
+
+ def SetLastHeader(self, header_path):
+ self._last_header = header_path
+
+ def CanonicalizeAlphabeticalOrder(self, header_path):
+ """Returns a path canonicalized for alphabetical comparison.
+
+ - replaces "-" with "_" so they both cmp the same.
+ - removes '-inl' since we don't require them to be after the main header.
+ - lowercase everything, just in case.
+
+ Args:
+ header_path: Path to be canonicalized.
+
+ Returns:
+ Canonicalized path.
+ """
+ return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
+
+ def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path):
+ """Check if a header is in alphabetical order with the previous header.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ header_path: Canonicalized header to be checked.
+
+ Returns:
+ Returns true if the header is in alphabetical order.
+ """
+ # If previous section is different from current section, _last_header will
+ # be reset to empty string, so it's always less than current header.
+ #
+ # If previous line was a blank line, assume that the headers are
+ # intentionally sorted the way they are.
+ if (self._last_header > header_path and
+ Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])):
+ return False
+ return True
+
+ def CheckNextIncludeOrder(self, header_type):
+ """Returns a non-empty error message if the next header is out of order.
+
+ This function also updates the internal state to be ready to check
+ the next include.
+
+ Args:
+ header_type: One of the _XXX_HEADER constants defined above.
+
+ Returns:
+ The empty string if the header is in the right order, or an
+ error message describing what's wrong.
+
+ """
+ error_message = ('Found %s after %s' %
+ (self._TYPE_NAMES[header_type],
+ self._SECTION_NAMES[self._section]))
+
+ last_section = self._section
+
+ if header_type == _C_SYS_HEADER:
+ if self._section <= self._C_SECTION:
+ self._section = self._C_SECTION
+ else:
+ self._last_header = ''
+ return error_message
+ elif header_type == _CPP_SYS_HEADER:
+ if self._section <= self._CPP_SECTION:
+ self._section = self._CPP_SECTION
+ else:
+ self._last_header = ''
+ return error_message
+ elif header_type == _LIKELY_MY_HEADER:
+ if self._section <= self._MY_H_SECTION:
+ self._section = self._MY_H_SECTION
+ else:
+ self._section = self._OTHER_H_SECTION
+ elif header_type == _POSSIBLE_MY_HEADER:
+ if self._section <= self._MY_H_SECTION:
+ self._section = self._MY_H_SECTION
+ else:
+ # This will always be the fallback because we're not sure
+ # enough that the header is associated with this file.
+ self._section = self._OTHER_H_SECTION
+ else:
+ assert header_type == _OTHER_HEADER
+ self._section = self._OTHER_H_SECTION
+
+ if last_section != self._section:
+ self._last_header = ''
+
+ return ''
+
+
+class _CppLintState(object):
+ """Maintains module-wide state.."""
+
+ def __init__(self):
+ self.verbose_level = 1 # global setting.
+ self.error_count = 0 # global count of reported errors
+ # filters to apply when emitting error messages
+ self.filters = _DEFAULT_FILTERS[:]
+ # backup of filter list. Used to restore the state after each file.
+ self._filters_backup = self.filters[:]
+ self.counting = 'total' # In what way are we counting errors?
+ self.errors_by_category = {} # string to int dict storing error counts
+ self.quiet = False # Suppress non-error messagess?
+
+ # output format:
+ # "emacs" - format that emacs can parse (default)
+ # "vs7" - format that Microsoft Visual Studio 7 can parse
+ self.output_format = 'emacs'
+
+ def SetOutputFormat(self, output_format):
+ """Sets the output format for errors."""
+ self.output_format = output_format
+
+ def SetQuiet(self, quiet):
+ """Sets the module's quiet settings, and returns the previous setting."""
+ last_quiet = self.quiet
+ self.quiet = quiet
+ return last_quiet
+
+ def SetVerboseLevel(self, level):
+ """Sets the module's verbosity, and returns the previous setting."""
+ last_verbose_level = self.verbose_level
+ self.verbose_level = level
+ return last_verbose_level
+
+ def SetCountingStyle(self, counting_style):
+ """Sets the module's counting options."""
+ self.counting = counting_style
+
+ def SetFilters(self, filters):
+ """Sets the error-message filters.
+
+ These filters are applied when deciding whether to emit a given
+ error message.
+
+ Args:
+ filters: A string of comma-separated filters (eg "+whitespace/indent").
+ Each filter should start with + or -; else we die.
+
+ Raises:
+ ValueError: The comma-separated filters did not all start with '+' or '-'.
+ E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
+ """
+ # Default filters always have less priority than the flag ones.
+ self.filters = _DEFAULT_FILTERS[:]
+ self.AddFilters(filters)
+
+ def AddFilters(self, filters):
+ """ Adds more filters to the existing list of error-message filters. """
+ for filt in filters.split(','):
+ clean_filt = filt.strip()
+ if clean_filt:
+ self.filters.append(clean_filt)
+ for filt in self.filters:
+ if not (filt.startswith('+') or filt.startswith('-')):
+ raise ValueError('Every filter in --filters must start with + or -'
+ ' (%s does not)' % filt)
+
+ def BackupFilters(self):
+ """ Saves the current filter list to backup storage."""
+ self._filters_backup = self.filters[:]
+
+ def RestoreFilters(self):
+ """ Restores filters previously backed up."""
+ self.filters = self._filters_backup[:]
+
+ def ResetErrorCounts(self):
+ """Sets the module's error statistic back to zero."""
+ self.error_count = 0
+ self.errors_by_category = {}
+
+ def IncrementErrorCount(self, category):
+ """Bumps the module's error statistic."""
+ self.error_count += 1
+ if self.counting in ('toplevel', 'detailed'):
+ if self.counting != 'detailed':
+ category = category.split('/')[0]
+ if category not in self.errors_by_category:
+ self.errors_by_category[category] = 0
+ self.errors_by_category[category] += 1
+
+ def PrintErrorCounts(self):
+ """Print a summary of errors by category, and the total."""
+ for category, count in self.errors_by_category.iteritems():
+ sys.stderr.write('Category \'%s\' errors found: %d\n' %
+ (category, count))
+ sys.stdout.write('Total errors found: %d\n' % self.error_count)
+
+_cpplint_state = _CppLintState()
+
+
+def _OutputFormat():
+ """Gets the module's output format."""
+ return _cpplint_state.output_format
+
+
+def _SetOutputFormat(output_format):
+ """Sets the module's output format."""
+ _cpplint_state.SetOutputFormat(output_format)
+
+def _Quiet():
+ """Return's the module's quiet setting."""
+ return _cpplint_state.quiet
+
+def _SetQuiet(quiet):
+ """Set the module's quiet status, and return previous setting."""
+ return _cpplint_state.SetQuiet(quiet)
+
+
+def _VerboseLevel():
+ """Returns the module's verbosity setting."""
+ return _cpplint_state.verbose_level
+
+
+def _SetVerboseLevel(level):
+ """Sets the module's verbosity, and returns the previous setting."""
+ return _cpplint_state.SetVerboseLevel(level)
+
+
+def _SetCountingStyle(level):
+ """Sets the module's counting options."""
+ _cpplint_state.SetCountingStyle(level)
+
+
+def _Filters():
+ """Returns the module's list of output filters, as a list."""
+ return _cpplint_state.filters
+
+
+def _SetFilters(filters):
+ """Sets the module's error-message filters.
+
+ These filters are applied when deciding whether to emit a given
+ error message.
+
+ Args:
+ filters: A string of comma-separated filters (eg "whitespace/indent").
+ Each filter should start with + or -; else we die.
+ """
+ _cpplint_state.SetFilters(filters)
+
+def _AddFilters(filters):
+ """Adds more filter overrides.
+
+ Unlike _SetFilters, this function does not reset the current list of filters
+ available.
+
+ Args:
+ filters: A string of comma-separated filters (eg "whitespace/indent").
+ Each filter should start with + or -; else we die.
+ """
+ _cpplint_state.AddFilters(filters)
+
+def _BackupFilters():
+ """ Saves the current filter list to backup storage."""
+ _cpplint_state.BackupFilters()
+
+def _RestoreFilters():
+ """ Restores filters previously backed up."""
+ _cpplint_state.RestoreFilters()
+
+class _FunctionState(object):
+ """Tracks current function name and the number of lines in its body."""
+
+ _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
+ _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
+
+ def __init__(self):
+ self.in_a_function = False
+ self.lines_in_function = 0
+ self.current_function = ''
+
+ def Begin(self, function_name):
+ """Start analyzing function body.
+
+ Args:
+ function_name: The name of the function being tracked.
+ """
+ self.in_a_function = True
+ self.lines_in_function = 0
+ self.current_function = function_name
+
+ def Count(self):
+ """Count line in current function body."""
+ if self.in_a_function:
+ self.lines_in_function += 1
+
+ def Check(self, error, filename, linenum):
+ """Report if too many lines in function body.
+
+ Args:
+ error: The function to call with any errors found.
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ """
+ if not self.in_a_function:
+ return
+
+ if Match(r'T(EST|est)', self.current_function):
+ base_trigger = self._TEST_TRIGGER
+ else:
+ base_trigger = self._NORMAL_TRIGGER
+ trigger = base_trigger * 2**_VerboseLevel()
+
+ if self.lines_in_function > trigger:
+ error_level = int(math.log(self.lines_in_function / base_trigger, 2))
+ # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
+ if error_level > 5:
+ error_level = 5
+ error(filename, linenum, 'readability/fn_size', error_level,
+ 'Small and focused functions are preferred:'
+ ' %s has %d non-comment lines'
+ ' (error triggered by exceeding %d lines).' % (
+ self.current_function, self.lines_in_function, trigger))
+
+ def End(self):
+ """Stop analyzing function body."""
+ self.in_a_function = False
+
+
+class _IncludeError(Exception):
+ """Indicates a problem with the include order in a file."""
+ pass
+
+
+class FileInfo(object):
+ """Provides utility functions for filenames.
+
+ FileInfo provides easy access to the components of a file's path
+ relative to the project root.
+ """
+
+ def __init__(self, filename):
+ self._filename = filename
+
+ def FullName(self):
+ """Make Windows paths like Unix."""
+ return os.path.abspath(self._filename).replace('\\', '/')
+
+ def RepositoryName(self):
+ """FullName after removing the local path to the repository.
+
+ If we have a real absolute path name here we can try to do something smart:
+ detecting the root of the checkout and truncating /path/to/checkout from
+ the name so that we get header guards that don't include things like
+ "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+ people on different computers who have checked the source out to different
+ locations won't see bogus errors.
+ """
+ fullname = self.FullName()
+
+ if os.path.exists(fullname):
+ project_dir = os.path.dirname(fullname)
+
+ if os.path.exists(os.path.join(project_dir, ".svn")):
+ # If there's a .svn file in the current directory, we recursively look
+ # up the directory tree for the top of the SVN checkout
+ root_dir = project_dir
+ one_up_dir = os.path.dirname(root_dir)
+ while os.path.exists(os.path.join(one_up_dir, ".svn")):
+ root_dir = os.path.dirname(root_dir)
+ one_up_dir = os.path.dirname(one_up_dir)
+
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
+ # searching up from the current path.
+ root_dir = current_dir = os.path.dirname(fullname)
+ while current_dir != os.path.dirname(current_dir):
+ if (os.path.exists(os.path.join(current_dir, ".git")) or
+ os.path.exists(os.path.join(current_dir, ".hg")) or
+ os.path.exists(os.path.join(current_dir, ".svn"))):
+ root_dir = current_dir
+ current_dir = os.path.dirname(current_dir)
+
+ if (os.path.exists(os.path.join(root_dir, ".git")) or
+ os.path.exists(os.path.join(root_dir, ".hg")) or
+ os.path.exists(os.path.join(root_dir, ".svn"))):
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Don't know what to do; header guard warnings may be wrong...
+ return fullname
+
+ def Split(self):
+ """Splits the file into the directory, basename, and extension.
+
+ For 'chrome/browser/browser.cc', Split() would
+ return ('chrome/browser', 'browser', '.cc')
+
+ Returns:
+ A tuple of (directory, basename, extension).
+ """
+
+ googlename = self.RepositoryName()
+ project, rest = os.path.split(googlename)
+ return (project,) + os.path.splitext(rest)
+
+ def BaseName(self):
+ """File base name - text after the final slash, before the final period."""
+ return self.Split()[1]
+
+ def Extension(self):
+ """File extension - text following the final period."""
+ return self.Split()[2]
+
+ def NoExtension(self):
+ """File has no source file extension."""
+ return '/'.join(self.Split()[0:2])
+
+ def IsSource(self):
+ """File has a source file extension."""
+ return _IsSourceExtension(self.Extension()[1:])
+
+
+def _ShouldPrintError(category, confidence, linenum):
+ """If confidence >= verbose, category passes filter and is not suppressed."""
+
+ # There are three ways we might decide not to print an error message:
+ # a "NOLINT(category)" comment appears in the source,
+ # the verbosity level isn't high enough, or the filters filter it out.
+ if IsErrorSuppressedByNolint(category, linenum):
+ return False
+
+ if confidence < _cpplint_state.verbose_level:
+ return False
+
+ is_filtered = False
+ for one_filter in _Filters():
+ if one_filter.startswith('-'):
+ if category.startswith(one_filter[1:]):
+ is_filtered = True
+ elif one_filter.startswith('+'):
+ if category.startswith(one_filter[1:]):
+ is_filtered = False
+ else:
+ assert False # should have been checked for in SetFilter.
+ if is_filtered:
+ return False
+
+ return True
+
+
+def Error(filename, linenum, category, confidence, message):
+ """Logs the fact we've found a lint error.
+
+ We log where the error was found, and also our confidence in the error,
+ that is, how certain we are this is a legitimate style regression, and
+ not a misidentification or a use that's sometimes justified.
+
+ False positives can be suppressed by the use of
+ "cpplint(category)" comments on the offending line. These are
+ parsed into _error_suppressions.
+
+ Args:
+ filename: The name of the file containing the error.
+ linenum: The number of the line containing the error.
+ category: A string used to describe the "category" this bug
+ falls under: "whitespace", say, or "runtime". Categories
+ may have a hierarchy separated by slashes: "whitespace/indent".
+ confidence: A number from 1-5 representing a confidence score for
+ the error, with 5 meaning that we are certain of the problem,
+ and 1 meaning that it could be a legitimate construct.
+ message: The error message.
+ """
+ if _ShouldPrintError(category, confidence, linenum):
+ _cpplint_state.IncrementErrorCount(category)
+ if _cpplint_state.output_format == 'vs7':
+ sys.stderr.write('%s(%s): error cpplint: [%s] %s [%d]\n' % (
+ filename, linenum, category, message, confidence))
+ elif _cpplint_state.output_format == 'eclipse':
+ sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+ else:
+ sys.stderr.write('%s:%s: %s [%s] [%d]\n' % (
+ filename, linenum, message, category, confidence))
+
+
+# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard.
+_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
+ r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
+# Match a single C style comment on the same line.
+_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/'
+# Matches multi-line C style comments.
+# This RE is a little bit more complicated than one might expect, because we
+# have to take care of space removals tools so we can handle comments inside
+# statements better.
+# The current rule is: We only clear spaces from both sides when we're at the
+# end of the line. Otherwise, we try to remove spaces from the right side,
+# if this doesn't work we try on left side but only if there's a non-character
+# on the right.
+_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
+ r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' +
+ _RE_PATTERN_C_COMMENTS + r'\s+|' +
+ r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' +
+ _RE_PATTERN_C_COMMENTS + r')')
+
+
+def IsCppString(line):
+ """Does line terminate so, that the next symbol is in string constant.
+
+ This function does not consider single-line nor multi-line comments.
+
+ Args:
+ line: is a partial line of code starting from the 0..n.
+
+ Returns:
+ True, if next character appended to 'line' is inside a
+ string constant.
+ """
+
+ line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
+ return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
+
+
+def CleanseRawStrings(raw_lines):
+ """Removes C++11 raw strings from lines.
+
+ Before:
+ static const char kData[] = R"(
+ multi-line string
+ )";
+
+ After:
+ static const char kData[] = ""
+ (replaced by blank line)
+ "";
+
+ Args:
+ raw_lines: list of raw lines.
+
+ Returns:
+ list of lines with C++11 raw strings replaced by empty strings.
+ """
+
+ delimiter = None
+ lines_without_raw_strings = []
+ for line in raw_lines:
+ if delimiter:
+ # Inside a raw string, look for the end
+ end = line.find(delimiter)
+ if end >= 0:
+ # Found the end of the string, match leading space for this
+ # line and resume copying the original lines, and also insert
+ # a "" on the last line.
+ leading_space = Match(r'^(\s*)\S', line)
+ line = leading_space.group(1) + '""' + line[end + len(delimiter):]
+ delimiter = None
+ else:
+ # Haven't found the end yet, append a blank line.
+ line = '""'
+
+ # Look for beginning of a raw string, and replace them with
+ # empty strings. This is done in a loop to handle multiple raw
+ # strings on the same line.
+ while delimiter is None:
+ # Look for beginning of a raw string.
+ # See 2.14.15 [lex.string] for syntax.
+ #
+ # Once we have matched a raw string, we check the prefix of the
+ # line to make sure that the line is not part of a single line
+ # comment. It's done this way because we remove raw strings
+ # before removing comments as opposed to removing comments
+ # before removing raw strings. This is because there are some
+ # cpplint checks that requires the comments to be preserved, but
+ # we don't want to check comments that are inside raw strings.
+ matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line)
+ if (matched and
+ not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//',
+ matched.group(1))):
+ delimiter = ')' + matched.group(2) + '"'
+
+ end = matched.group(3).find(delimiter)
+ if end >= 0:
+ # Raw string ended on same line
+ line = (matched.group(1) + '""' +
+ matched.group(3)[end + len(delimiter):])
+ delimiter = None
+ else:
+ # Start of a multi-line raw string
+ line = matched.group(1) + '""'
+ else:
+ break
+
+ lines_without_raw_strings.append(line)
+
+ # TODO(unknown): if delimiter is not None here, we might want to
+ # emit a warning for unterminated string.
+ return lines_without_raw_strings
+
+
+def FindNextMultiLineCommentStart(lines, lineix):
+ """Find the beginning marker for a multiline comment."""
+ while lineix < len(lines):
+ if lines[lineix].strip().startswith('/*'):
+ # Only return this marker if the comment goes beyond this line
+ if lines[lineix].strip().find('*/', 2) < 0:
+ return lineix
+ lineix += 1
+ return len(lines)
+
+
+def FindNextMultiLineCommentEnd(lines, lineix):
+ """We are inside a comment, find the end marker."""
+ while lineix < len(lines):
+ if lines[lineix].strip().endswith('*/'):
+ return lineix
+ lineix += 1
+ return len(lines)
+
+
+def RemoveMultiLineCommentsFromRange(lines, begin, end):
+ """Clears a range of lines for multi-line comments."""
+ # Having // dummy comments makes the lines non-empty, so we will not get
+ # unnecessary blank line warnings later in the code.
+ for i in range(begin, end):
+ lines[i] = '/**/'
+
+
+def RemoveMultiLineComments(filename, lines, error):
+ """Removes multiline (c-style) comments from lines."""
+ lineix = 0
+ while lineix < len(lines):
+ lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
+ if lineix_begin >= len(lines):
+ return
+ lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
+ if lineix_end >= len(lines):
+ error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
+ 'Could not find end of multi-line comment')
+ return
+ RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
+ lineix = lineix_end + 1
+
+
+def CleanseComments(line):
+ """Removes //-comments and single-line C-style /* */ comments.
+
+ Args:
+ line: A line of C++ source.
+
+ Returns:
+ The line with single-line comments removed.
+ """
+ commentpos = line.find('//')
+ if commentpos != -1 and not IsCppString(line[:commentpos]):
+ line = line[:commentpos].rstrip()
+ # get rid of /* ... */
+ return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
+
+
+class CleansedLines(object):
+ """Holds 4 copies of all lines with different preprocessing applied to them.
+
+ 1) elided member contains lines without strings and comments.
+ 2) lines member contains lines without comments.
+ 3) raw_lines member contains all the lines without processing.
+ 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw
+ strings removed.
+ All these members are of <type 'list'>, and of the same length.
+ """
+
+ def __init__(self, lines):
+ self.elided = []
+ self.lines = []
+ self.raw_lines = lines
+ self.num_lines = len(lines)
+ self.lines_without_raw_strings = CleanseRawStrings(lines)
+ for linenum in range(len(self.lines_without_raw_strings)):
+ self.lines.append(CleanseComments(
+ self.lines_without_raw_strings[linenum]))
+ elided = self._CollapseStrings(self.lines_without_raw_strings[linenum])
+ self.elided.append(CleanseComments(elided))
+
+ def NumLines(self):
+ """Returns the number of lines represented."""
+ return self.num_lines
+
+ @staticmethod
+ def _CollapseStrings(elided):
+ """Collapses strings and chars on a line to simple "" or '' blocks.
+
+ We nix strings first so we're not fooled by text like '"http://"'
+
+ Args:
+ elided: The line being processed.
+
+ Returns:
+ The line with collapsed strings.
+ """
+ if _RE_PATTERN_INCLUDE.match(elided):
+ return elided
+
+ # Remove escaped characters first to make quote/single quote collapsing
+ # basic. Things that look like escaped characters shouldn't occur
+ # outside of strings and chars.
+ elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
+
+ # Replace quoted strings and digit separators. Both single quotes
+ # and double quotes are processed in the same loop, otherwise
+ # nested quotes wouldn't work.
+ collapsed = ''
+ while True:
+ # Find the first quote character
+ match = Match(r'^([^\'"]*)([\'"])(.*)$', elided)
+ if not match:
+ collapsed += elided
+ break
+ head, quote, tail = match.groups()
+
+ if quote == '"':
+ # Collapse double quoted strings
+ second_quote = tail.find('"')
+ if second_quote >= 0:
+ collapsed += head + '""'
+ elided = tail[second_quote + 1:]
+ else:
+ # Unmatched double quote, don't bother processing the rest
+ # of the line since this is probably a multiline string.
+ collapsed += elided
+ break
+ else:
+ # Found single quote, check nearby text to eliminate digit separators.
+ #
+ # There is no special handling for floating point here, because
+ # the integer/fractional/exponent parts would all be parsed
+ # correctly as long as there are digits on both sides of the
+ # separator. So we are fine as long as we don't see something
+ # like "0.'3" (gcc 4.9.0 will not allow this literal).
+ if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head):
+ match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail)
+ collapsed += head + match_literal.group(1).replace("'", '')
+ elided = match_literal.group(2)
+ else:
+ second_quote = tail.find('\'')
+ if second_quote >= 0:
+ collapsed += head + "''"
+ elided = tail[second_quote + 1:]
+ else:
+ # Unmatched single quote
+ collapsed += elided
+ break
+
+ return collapsed
+
+
+def FindEndOfExpressionInLine(line, startpos, stack):
+ """Find the position just after the end of current parenthesized expression.
+
+ Args:
+ line: a CleansedLines line.
+ startpos: start searching at this position.
+ stack: nesting stack at startpos.
+
+ Returns:
+ On finding matching end: (index just after matching end, None)
+ On finding an unclosed expression: (-1, None)
+ Otherwise: (-1, new stack at end of this line)
+ """
+ for i in xrange(startpos, len(line)):
+ char = line[i]
+ if char in '([{':
+ # Found start of parenthesized expression, push to expression stack
+ stack.append(char)
+ elif char == '<':
+ # Found potential start of template argument list
+ if i > 0 and line[i - 1] == '<':
+ # Left shift operator
+ if stack and stack[-1] == '<':
+ stack.pop()
+ if not stack:
+ return (-1, None)
+ elif i > 0 and Search(r'\boperator\s*$', line[0:i]):
+ # operator<, don't add to stack
+ continue
+ else:
+ # Tentative start of template argument list
+ stack.append('<')
+ elif char in ')]}':
+ # Found end of parenthesized expression.
+ #
+ # If we are currently expecting a matching '>', the pending '<'
+ # must have been an operator. Remove them from expression stack.
+ while stack and stack[-1] == '<':
+ stack.pop()
+ if not stack:
+ return (-1, None)
+ if ((stack[-1] == '(' and char == ')') or
+ (stack[-1] == '[' and char == ']') or
+ (stack[-1] == '{' and char == '}')):
+ stack.pop()
+ if not stack:
+ return (i + 1, None)
+ else:
+ # Mismatched parentheses
+ return (-1, None)
+ elif char == '>':
+ # Found potential end of template argument list.
+
+ # Ignore "->" and operator functions
+ if (i > 0 and
+ (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))):
+ continue
+
+ # Pop the stack if there is a matching '<'. Otherwise, ignore
+ # this '>' since it must be an operator.
+ if stack:
+ if stack[-1] == '<':
+ stack.pop()
+ if not stack:
+ return (i + 1, None)
+ elif char == ';':
+ # Found something that look like end of statements. If we are currently
+ # expecting a '>', the matching '<' must have been an operator, since
+ # template argument list should not contain statements.
+ while stack and stack[-1] == '<':
+ stack.pop()
+ if not stack:
+ return (-1, None)
+
+ # Did not find end of expression or unbalanced parentheses on this line
+ return (-1, stack)
+
+
+def CloseExpression(clean_lines, linenum, pos):
+ """If input points to ( or { or [ or <, finds the position that closes it.
+
+ If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the
+ linenum/pos that correspond to the closing of the expression.
+
+ TODO(unknown): cpplint spends a fair bit of time matching parentheses.
+ Ideally we would want to index all opening and closing parentheses once
+ and have CloseExpression be just a simple lookup, but due to preprocessor
+ tricks, this is not so easy.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ pos: A position on the line.
+
+ Returns:
+ A tuple (line, linenum, pos) pointer *past* the closing brace, or
+ (line, len(lines), -1) if we never find a close. Note we ignore
+ strings and comments when matching; and the line we return is the
+ 'cleansed' line at linenum.
+ """
+
+ line = clean_lines.elided[linenum]
+ if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]):
+ return (line, clean_lines.NumLines(), -1)
+
+ # Check first line
+ (end_pos, stack) = FindEndOfExpressionInLine(line, pos, [])
+ if end_pos > -1:
+ return (line, linenum, end_pos)
+
+ # Continue scanning forward
+ while stack and linenum < clean_lines.NumLines() - 1:
+ linenum += 1
+ line = clean_lines.elided[linenum]
+ (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack)
+ if end_pos > -1:
+ return (line, linenum, end_pos)
+
+ # Did not find end of expression before end of file, give up
+ return (line, clean_lines.NumLines(), -1)
+
+
+def FindStartOfExpressionInLine(line, endpos, stack):
+ """Find position at the matching start of current expression.
+
+ This is almost the reverse of FindEndOfExpressionInLine, but note
+ that the input position and returned position differs by 1.
+
+ Args:
+ line: a CleansedLines line.
+ endpos: start searching at this position.
+ stack: nesting stack at endpos.
+
+ Returns:
+ On finding matching start: (index at matching start, None)
+ On finding an unclosed expression: (-1, None)
+ Otherwise: (-1, new stack at beginning of this line)
+ """
+ i = endpos
+ while i >= 0:
+ char = line[i]
+ if char in ')]}':
+ # Found end of expression, push to expression stack
+ stack.append(char)
+ elif char == '>':
+ # Found potential end of template argument list.
+ #
+ # Ignore it if it's a "->" or ">=" or "operator>"
+ if (i > 0 and
+ (line[i - 1] == '-' or
+ Match(r'\s>=\s', line[i - 1:]) or
+ Search(r'\boperator\s*$', line[0:i]))):
+ i -= 1
+ else:
+ stack.append('>')
+ elif char == '<':
+ # Found potential start of template argument list
+ if i > 0 and line[i - 1] == '<':
+ # Left shift operator
+ i -= 1
+ else:
+ # If there is a matching '>', we can pop the expression stack.
+ # Otherwise, ignore this '<' since it must be an operator.
+ if stack and stack[-1] == '>':
+ stack.pop()
+ if not stack:
+ return (i, None)
+ elif char in '([{':
+ # Found start of expression.
+ #
+ # If there are any unmatched '>' on the stack, they must be
+ # operators. Remove those.
+ while stack and stack[-1] == '>':
+ stack.pop()
+ if not stack:
+ return (-1, None)
+ if ((char == '(' and stack[-1] == ')') or
+ (char == '[' and stack[-1] == ']') or
+ (char == '{' and stack[-1] == '}')):
+ stack.pop()
+ if not stack:
+ return (i, None)
+ else:
+ # Mismatched parentheses
+ return (-1, None)
+ elif char == ';':
+ # Found something that look like end of statements. If we are currently
+ # expecting a '<', the matching '>' must have been an operator, since
+ # template argument list should not contain statements.
+ while stack and stack[-1] == '>':
+ stack.pop()
+ if not stack:
+ return (-1, None)
+
+ i -= 1
+
+ return (-1, stack)
+
+
+def ReverseCloseExpression(clean_lines, linenum, pos):
+ """If input points to ) or } or ] or >, finds the position that opens it.
+
+ If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the
+ linenum/pos that correspond to the opening of the expression.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ pos: A position on the line.
+
+ Returns:
+ A tuple (line, linenum, pos) pointer *at* the opening brace, or
+ (line, 0, -1) if we never find the matching opening brace. Note
+ we ignore strings and comments when matching; and the line we
+ return is the 'cleansed' line at linenum.
+ """
+ line = clean_lines.elided[linenum]
+ if line[pos] not in ')}]>':
+ return (line, 0, -1)
+
+ # Check last line
+ (start_pos, stack) = FindStartOfExpressionInLine(line, pos, [])
+ if start_pos > -1:
+ return (line, linenum, start_pos)
+
+ # Continue scanning backward
+ while stack and linenum > 0:
+ linenum -= 1
+ line = clean_lines.elided[linenum]
+ (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack)
+ if start_pos > -1:
+ return (line, linenum, start_pos)
+
+ # Did not find start of expression before beginning of file, give up
+ return (line, 0, -1)
+
+
+def CheckForCopyright(filename, lines, error):
+ """Logs an error if no Copyright message appears at the top of the file."""
+
+ # We'll say it should occur by line 10. Don't forget there's a
+ # dummy line at the front.
+ for line in xrange(1, min(len(lines), 11)):
+ if re.search(r'Copyright', lines[line], re.I): break
+ else: # means no copyright line was found
+ error(filename, 0, 'legal/copyright', 5,
+ 'No copyright message found. '
+ 'You should have a line: "Copyright [year] <Copyright Owner>"')
+
+
+def GetIndentLevel(line):
+ """Return the number of leading spaces in line.
+
+ Args:
+ line: A string to check.
+
+ Returns:
+ An integer count of leading spaces, possibly zero.
+ """
+ indent = Match(r'^( *)\S', line)
+ if indent:
+ return len(indent.group(1))
+ else:
+ return 0
+
+def PathSplitToList(path):
+ """Returns the path split into a list by the separator.
+
+ Args:
+ path: An absolute or relative path (e.g. '/a/b/c/' or '../a')
+
+ Returns:
+ A list of path components (e.g. ['a', 'b', 'c]).
+ """
+ lst = []
+ while True:
+ (head, tail) = os.path.split(path)
+ if head == path: # absolute paths end
+ lst.append(head)
+ break
+ if tail == path: # relative paths end
+ lst.append(tail)
+ break
+
+ path = head
+ lst.append(tail)
+
+ lst.reverse()
+ return lst
+
+def GetHeaderGuardCPPVariable(filename):
+ """Returns the CPP variable that should be used as a header guard.
+
+ Args:
+ filename: The name of a C++ header file.
+
+ Returns:
+ The CPP variable that should be used as a header guard in the
+ named file.
+
+ """
+
+ # Restores original filename in case that cpplint is invoked from Emacs's
+ # flymake.
+ filename = re.sub(r'_flymake\.h$', '.h', filename)
+ filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
+ # Replace 'c++' with 'cpp'.
+ filename = filename.replace('C++', 'cpp').replace('c++', 'cpp')
+
+ fileinfo = FileInfo(filename)
+ file_path_from_root = fileinfo.RepositoryName()
+
+ def FixupPathFromRoot():
+ if _root_debug:
+ sys.stderr.write("\n_root fixup, _root = '%s', repository name = '%s'\n"
+ %(_root, fileinfo.RepositoryName()))
+
+ # Process the file path with the --root flag if it was set.
+ if not _root:
+ if _root_debug:
+ sys.stderr.write("_root unspecified\n")
+ return file_path_from_root
+
+ def StripListPrefix(lst, prefix):
+ # f(['x', 'y'], ['w, z']) -> None (not a valid prefix)
+ if lst[:len(prefix)] != prefix:
+ return None
+ # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd']
+ return lst[(len(prefix)):]
+
+ # root behavior:
+ # --root=subdir , lstrips subdir from the header guard
+ maybe_path = StripListPrefix(PathSplitToList(file_path_from_root),
+ PathSplitToList(_root))
+
+ if _root_debug:
+ sys.stderr.write("_root lstrip (maybe_path=%s, file_path_from_root=%s," +
+ " _root=%s)\n" %(maybe_path, file_path_from_root, _root))
+
+ if maybe_path:
+ return os.path.join(*maybe_path)
+
+ # --root=.. , will prepend the outer directory to the header guard
+ full_path = fileinfo.FullName()
+ root_abspath = os.path.abspath(_root)
+
+ maybe_path = StripListPrefix(PathSplitToList(full_path),
+ PathSplitToList(root_abspath))
+
+ if _root_debug:
+ sys.stderr.write("_root prepend (maybe_path=%s, full_path=%s, " +
+ "root_abspath=%s)\n" %(maybe_path, full_path, root_abspath))
+
+ if maybe_path:
+ return os.path.join(*maybe_path)
+
+ if _root_debug:
+ sys.stderr.write("_root ignore, returning %s\n" %(file_path_from_root))
+
+ # --root=FAKE_DIR is ignored
+ return file_path_from_root
+
+ file_path_from_root = FixupPathFromRoot()
+ return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'
+
+
+def CheckForHeaderGuard(filename, clean_lines, error):
+ """Checks that the file contains a header guard.
+
+ Logs an error if no #ifndef header guard is present. For other
+ headers, checks that the full pathname is used.
+
+ Args:
+ filename: The name of the C++ header file.
+ clean_lines: A CleansedLines instance containing the file.
+ error: The function to call with any errors found.
+ """
+
+ # Don't check for header guards if there are error suppression
+ # comments somewhere in this file.
+ #
+ # Because this is silencing a warning for a nonexistent line, we
+ # only support the very specific NOLINT(build/header_guard) syntax,
+ # and not the general NOLINT or NOLINT(*) syntax.
+ raw_lines = clean_lines.lines_without_raw_strings
+ for i in raw_lines:
+ if Search(r'//\s*NOLINT\(build/header_guard\)', i):
+ return
+
+ cppvar = GetHeaderGuardCPPVariable(filename)
+
+ ifndef = ''
+ ifndef_linenum = 0
+ define = ''
+ endif = ''
+ endif_linenum = 0
+ for linenum, line in enumerate(raw_lines):
+ linesplit = line.split()
+ if len(linesplit) >= 2:
+ # find the first occurrence of #ifndef and #define, save arg
+ if not ifndef and linesplit[0] == '#ifndef':
+ # set ifndef to the header guard presented on the #ifndef line.
+ ifndef = linesplit[1]
+ ifndef_linenum = linenum
+ if not define and linesplit[0] == '#define':
+ define = linesplit[1]
+ # find the last occurrence of #endif, save entire line
+ if line.startswith('#endif'):
+ endif = line
+ endif_linenum = linenum
+
+ if not ifndef or not define or ifndef != define:
+ error(filename, 0, 'build/header_guard', 5,
+ 'No #ifndef header guard found, suggested CPP variable is: %s' %
+ cppvar)
+ return
+
+ # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
+ # for backward compatibility.
+ if ifndef != cppvar:
+ error_level = 0
+ if ifndef != cppvar + '_':
+ error_level = 5
+
+ ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum,
+ error)
+ error(filename, ifndef_linenum, 'build/header_guard', error_level,
+ '#ifndef header guard has wrong style, please use: %s' % cppvar)
+
+ # Check for "//" comments on endif line.
+ ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum,
+ error)
+ match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)
+ if match:
+ if match.group(1) == '_':
+ # Issue low severity warning for deprecated double trailing underscore
+ error(filename, endif_linenum, 'build/header_guard', 0,
+ '#endif line should be "#endif // %s"' % cppvar)
+ return
+
+ # Didn't find the corresponding "//" comment. If this file does not
+ # contain any "//" comments at all, it could be that the compiler
+ # only wants "/**/" comments, look for those instead.
+ no_single_line_comments = True
+ for i in xrange(1, len(raw_lines) - 1):
+ line = raw_lines[i]
+ if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line):
+ no_single_line_comments = False
+ break
+
+ if no_single_line_comments:
+ match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif)
+ if match:
+ if match.group(1) == '_':
+ # Low severity warning for double trailing underscore
+ error(filename, endif_linenum, 'build/header_guard', 0,
+ '#endif line should be "#endif /* %s */"' % cppvar)
+ return
+
+ # Didn't find anything
+ error(filename, endif_linenum, 'build/header_guard', 5,
+ '#endif line should be "#endif // %s"' % cppvar)
+
+
+def CheckHeaderFileIncluded(filename, include_state, error):
+ """Logs an error if a .cc file does not include its header."""
+
+ # Do not check test files
+ fileinfo = FileInfo(filename)
+ if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()):
+ return
+
+ headerfile = filename[0:len(filename) - len(fileinfo.Extension())] + '.h'
+ if not os.path.exists(headerfile):
+ return
+ headername = FileInfo(headerfile).RepositoryName()
+ first_include = 0
+ for section_list in include_state.include_list:
+ for f in section_list:
+ if headername in f[0] or f[0] in headername:
+ return
+ if not first_include:
+ first_include = f[1]
+
+ error(filename, first_include, 'build/include', 5,
+ '%s should include its header file %s' % (fileinfo.RepositoryName(),
+ headername))
+
+
+def CheckForBadCharacters(filename, lines, error):
+ """Logs an error for each line containing bad characters.
+
+ Two kinds of bad characters:
+
+ 1. Unicode replacement characters: These indicate that either the file
+ contained invalid UTF-8 (likely) or Unicode replacement characters (which
+ it shouldn't). Note that it's possible for this to throw off line
+ numbering if the invalid UTF-8 occurred adjacent to a newline.
+
+ 2. NUL bytes. These are problematic for some tools.
+
+ Args:
+ filename: The name of the current file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+ for linenum, line in enumerate(lines):
+ if u'\ufffd' in line:
+ error(filename, linenum, 'readability/utf8', 5,
+ 'Line contains invalid UTF-8 (or Unicode replacement character).')
+ if '\0' in line:
+ error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.')
+
+
+def CheckForNewlineAtEOF(filename, lines, error):
+ """Logs an error if there is no newline char at the end of the file.
+
+ Args:
+ filename: The name of the current file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ # The array lines() was created by adding two newlines to the
+ # original file (go figure), then splitting on \n.
+ # To verify that the file ends in \n, we just have to make sure the
+ # last-but-two element of lines() exists and is empty.
+ if len(lines) < 3 or lines[-2]:
+ error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
+ 'Could not find a newline character at the end of the file.')
+
+
+def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
+ """Logs an error if we see /* ... */ or "..." that extend past one line.
+
+ /* ... */ comments are legit inside macros, for one line.
+ Otherwise, we prefer // comments, so it's ok to warn about the
+ other. Likewise, it's ok for strings to extend across multiple
+ lines, as long as a line continuation character (backslash)
+ terminates each line. Although not currently prohibited by the C++
+ style guide, it's ugly and unnecessary. We don't do well with either
+ in this lint program, so we warn about both.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Remove all \\ (escaped backslashes) from the line. They are OK, and the
+ # second (escaped) slash may trigger later \" detection erroneously.
+ line = line.replace('\\\\', '')
+
+ if line.count('/*') > line.count('*/'):
+ error(filename, linenum, 'readability/multiline_comment', 5,
+ 'Complex multi-line /*...*/-style comment found. '
+ 'Lint may give bogus warnings. '
+ 'Consider replacing these with //-style comments, '
+ 'with #if 0...#endif, '
+ 'or with more clearly structured multi-line comments.')
+
+ if (line.count('"') - line.count('\\"')) % 2:
+ error(filename, linenum, 'readability/multiline_string', 5,
+ 'Multi-line string ("...") found. This lint script doesn\'t '
+ 'do well with such strings, and may give bogus warnings. '
+ 'Use C++11 raw strings or concatenation instead.')
+
+
+# (non-threadsafe name, thread-safe alternative, validation pattern)
+#
+# The validation pattern is used to eliminate false positives such as:
+# _rand(); // false positive due to substring match.
+# ->rand(); // some member function rand().
+# ACMRandom rand(seed); // some variable named rand.
+# ISAACRandom rand(); // another variable named rand.
+#
+# Basically we require the return value of these functions to be used
+# in some expression context on the same line by matching on some
+# operator before the function name. This eliminates constructors and
+# member function calls.
+_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)'
+_THREADING_LIST = (
+ ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'),
+ ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'),
+ ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'),
+ ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'),
+ ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'),
+ ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'),
+ ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'),
+ ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'),
+ ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'),
+ ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'),
+ ('strtok(', 'strtok_r(',
+ _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'),
+ ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'),
+ )
+
+
+def CheckPosixThreading(filename, clean_lines, linenum, error):
+ """Checks for calls to thread-unsafe functions.
+
+ Much code has been originally written without consideration of
+ multi-threading. Also, engineers are relying on their old experience;
+ they have learned posix before threading extensions were added. These
+ tests guide the engineers to use thread-safe functions (when using
+ posix directly).
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST:
+ # Additional pattern matching check to confirm that this is the
+ # function we are looking for
+ if Search(pattern, line):
+ error(filename, linenum, 'runtime/threadsafe_fn', 2,
+ 'Consider using ' + multithread_safe_func +
+ '...) instead of ' + single_thread_func +
+ '...) for improved thread safety.')
+
+
+def CheckVlogArguments(filename, clean_lines, linenum, error):
+ """Checks that VLOG() is only used for defining a logging level.
+
+ For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and
+ VLOG(FATAL) are not.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line):
+ error(filename, linenum, 'runtime/vlog', 5,
+ 'VLOG() should be used with numeric verbosity level. '
+ 'Use LOG() if you want symbolic severity levels.')
+
+# Matches invalid increment: *count++, which moves pointer instead of
+# incrementing a value.
+_RE_PATTERN_INVALID_INCREMENT = re.compile(
+ r'^\s*\*\w+(\+\+|--);')
+
+
+def CheckInvalidIncrement(filename, clean_lines, linenum, error):
+ """Checks for invalid increment *count++.
+
+ For example following function:
+ void increment_counter(int* count) {
+ *count++;
+ }
+ is invalid, because it effectively does count++, moving pointer, and should
+ be replaced with ++*count, (*count)++ or *count += 1.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ if _RE_PATTERN_INVALID_INCREMENT.match(line):
+ error(filename, linenum, 'runtime/invalid_increment', 5,
+ 'Changing pointer instead of value (or unused value of operator*).')
+
+
+def IsMacroDefinition(clean_lines, linenum):
+ if Search(r'^#define', clean_lines[linenum]):
+ return True
+
+ if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]):
+ return True
+
+ return False
+
+
+def IsForwardClassDeclaration(clean_lines, linenum):
+ return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum])
+
+
+class _BlockInfo(object):
+ """Stores information about a generic block of code."""
+
+ def __init__(self, linenum, seen_open_brace):
+ self.starting_linenum = linenum
+ self.seen_open_brace = seen_open_brace
+ self.open_parentheses = 0
+ self.inline_asm = _NO_ASM
+ self.check_namespace_indentation = False
+
+ def CheckBegin(self, filename, clean_lines, linenum, error):
+ """Run checks that applies to text up to the opening brace.
+
+ This is mostly for checking the text after the class identifier
+ and the "{", usually where the base class is specified. For other
+ blocks, there isn't much to check, so we always pass.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ pass
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ """Run checks that applies to text after the closing brace.
+
+ This is mostly used for checking end of namespace comments.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ pass
+
+ def IsBlockInfo(self):
+ """Returns true if this block is a _BlockInfo.
+
+ This is convenient for verifying that an object is an instance of
+ a _BlockInfo, but not an instance of any of the derived classes.
+
+ Returns:
+ True for this class, False for derived classes.
+ """
+ return self.__class__ == _BlockInfo
+
+
+class _ExternCInfo(_BlockInfo):
+ """Stores information about an 'extern "C"' block."""
+
+ def __init__(self, linenum):
+ _BlockInfo.__init__(self, linenum, True)
+
+
+class _ClassInfo(_BlockInfo):
+ """Stores information about a class."""
+
+ def __init__(self, name, class_or_struct, clean_lines, linenum):
+ _BlockInfo.__init__(self, linenum, False)
+ self.name = name
+ self.is_derived = False
+ self.check_namespace_indentation = True
+ if class_or_struct == 'struct':
+ self.access = 'public'
+ self.is_struct = True
+ else:
+ self.access = 'private'
+ self.is_struct = False
+
+ # Remember initial indentation level for this class. Using raw_lines here
+ # instead of elided to account for leading comments.
+ self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum])
+
+ # Try to find the end of the class. This will be confused by things like:
+ # class A {
+ # } *x = { ...
+ #
+ # But it's still good enough for CheckSectionSpacing.
+ self.last_line = 0
+ depth = 0
+ for i in range(linenum, clean_lines.NumLines()):
+ line = clean_lines.elided[i]
+ depth += line.count('{') - line.count('}')
+ if not depth:
+ self.last_line = i
+ break
+
+ def CheckBegin(self, filename, clean_lines, linenum, error):
+ # Look for a bare ':'
+ if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
+ self.is_derived = True
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ # If there is a DISALLOW macro, it should appear near the end of
+ # the class.
+ seen_last_thing_in_class = False
+ for i in xrange(linenum - 1, self.starting_linenum, -1):
+ match = Search(
+ r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' +
+ self.name + r'\)',
+ clean_lines.elided[i])
+ if match:
+ if seen_last_thing_in_class:
+ error(filename, i, 'readability/constructors', 3,
+ match.group(1) + ' should be the last thing in the class')
+ break
+
+ if not Match(r'^\s*$', clean_lines.elided[i]):
+ seen_last_thing_in_class = True
+
+ # Check that closing brace is aligned with beginning of the class.
+ # Only do this if the closing brace is indented by only whitespaces.
+ # This means we will not check single-line class definitions.
+ indent = Match(r'^( *)\}', clean_lines.elided[linenum])
+ if indent and len(indent.group(1)) != self.class_indent:
+ if self.is_struct:
+ parent = 'struct ' + self.name
+ else:
+ parent = 'class ' + self.name
+ error(filename, linenum, 'whitespace/indent', 3,
+ 'Closing brace should be aligned with beginning of %s' % parent)
+
+
+class _NamespaceInfo(_BlockInfo):
+ """Stores information about a namespace."""
+
+ def __init__(self, name, linenum):
+ _BlockInfo.__init__(self, linenum, False)
+ self.name = name or ''
+ self.check_namespace_indentation = True
+
+ def CheckEnd(self, filename, clean_lines, linenum, error):
+ """Check end of namespace comments."""
+ line = clean_lines.raw_lines[linenum]
+
+ # Check how many lines is enclosed in this namespace. Don't issue
+ # warning for missing namespace comments if there aren't enough
+ # lines. However, do apply checks if there is already an end of
+ # namespace comment and it's incorrect.
+ #
+ # TODO(unknown): We always want to check end of namespace comments
+ # if a namespace is large, but sometimes we also want to apply the
+ # check if a short namespace contained nontrivial things (something
+ # other than forward declarations). There is currently no logic on
+ # deciding what these nontrivial things are, so this check is
+ # triggered by namespace size only, which works most of the time.
+ if (linenum - self.starting_linenum < 10
+ and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)):
+ return
+
+ # Look for matching comment at end of namespace.
+ #
+ # Note that we accept C style "/* */" comments for terminating
+ # namespaces, so that code that terminate namespaces inside
+ # preprocessor macros can be cpplint clean.
+ #
+ # We also accept stuff like "// end of namespace <name>." with the
+ # period at the end.
+ #
+ # Besides these, we don't accept anything else, otherwise we might
+ # get false negatives when existing comment is a substring of the
+ # expected namespace.
+ if self.name:
+ # Named namespace
+ if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' +
+ re.escape(self.name) + r'[\*/\.\\\s]*$'),
+ line):
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Namespace should be terminated with "// namespace %s"' %
+ self.name)
+ else:
+ # Anonymous namespace
+ if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
+ # If "// namespace anonymous" or "// anonymous namespace (more text)",
+ # mention "// anonymous namespace" as an acceptable form
+ if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line):
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Anonymous namespace should be terminated with "// namespace"'
+ ' or "// anonymous namespace"')
+ else:
+ error(filename, linenum, 'readability/namespace', 5,
+ 'Anonymous namespace should be terminated with "// namespace"')
+
+
+class _PreprocessorInfo(object):
+ """Stores checkpoints of nesting stacks when #if/#else is seen."""
+
+ def __init__(self, stack_before_if):
+ # The entire nesting stack before #if
+ self.stack_before_if = stack_before_if
+
+ # The entire nesting stack up to #else
+ self.stack_before_else = []
+
+ # Whether we have already seen #else or #elif
+ self.seen_else = False
+
+
+class NestingState(object):
+ """Holds states related to parsing braces."""
+
+ def __init__(self):
+ # Stack for tracking all braces. An object is pushed whenever we
+ # see a "{", and popped when we see a "}". Only 3 types of
+ # objects are possible:
+ # - _ClassInfo: a class or struct.
+ # - _NamespaceInfo: a namespace.
+ # - _BlockInfo: some other type of block.
+ self.stack = []
+
+ # Top of the previous stack before each Update().
+ #
+ # Because the nesting_stack is updated at the end of each line, we
+ # had to do some convoluted checks to find out what is the current
+ # scope at the beginning of the line. This check is simplified by
+ # saving the previous top of nesting stack.
+ #
+ # We could save the full stack, but we only need the top. Copying
+ # the full nesting stack would slow down cpplint by ~10%.
+ self.previous_stack_top = []
+
+ # Stack of _PreprocessorInfo objects.
+ self.pp_stack = []
+
+ def SeenOpenBrace(self):
+ """Check if we have seen the opening brace for the innermost block.
+
+ Returns:
+ True if we have seen the opening brace, False if the innermost
+ block is still expecting an opening brace.
+ """
+ return (not self.stack) or self.stack[-1].seen_open_brace
+
+ def InNamespaceBody(self):
+ """Check if we are currently one level inside a namespace body.
+
+ Returns:
+ True if top of the stack is a namespace block, False otherwise.
+ """
+ return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
+
+ def InExternC(self):
+ """Check if we are currently one level inside an 'extern "C"' block.
+
+ Returns:
+ True if top of the stack is an extern block, False otherwise.
+ """
+ return self.stack and isinstance(self.stack[-1], _ExternCInfo)
+
+ def InClassDeclaration(self):
+ """Check if we are currently one level inside a class or struct declaration.
+
+ Returns:
+ True if top of the stack is a class/struct, False otherwise.
+ """
+ return self.stack and isinstance(self.stack[-1], _ClassInfo)
+
+ def InAsmBlock(self):
+ """Check if we are currently one level inside an inline ASM block.
+
+ Returns:
+ True if the top of the stack is a block containing inline ASM.
+ """
+ return self.stack and self.stack[-1].inline_asm != _NO_ASM
+
+ def InTemplateArgumentList(self, clean_lines, linenum, pos):
+ """Check if current position is inside template argument list.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ pos: position just after the suspected template argument.
+ Returns:
+ True if (linenum, pos) is inside template arguments.
+ """
+ while linenum < clean_lines.NumLines():
+ # Find the earliest character that might indicate a template argument
+ line = clean_lines.elided[linenum]
+ match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:])
+ if not match:
+ linenum += 1
+ pos = 0
+ continue
+ token = match.group(1)
+ pos += len(match.group(0))
+
+ # These things do not look like template argument list:
+ # class Suspect {
+ # class Suspect x; }
+ if token in ('{', '}', ';'): return False
+
+ # These things look like template argument list:
+ # template <class Suspect>
+ # template <class Suspect = default_value>
+ # template <class Suspect[]>
+ # template <class Suspect...>
+ if token in ('>', '=', '[', ']', '.'): return True
+
+ # Check if token is an unmatched '<'.
+ # If not, move on to the next character.
+ if token != '<':
+ pos += 1
+ if pos >= len(line):
+ linenum += 1
+ pos = 0
+ continue
+
+ # We can't be sure if we just find a single '<', and need to
+ # find the matching '>'.
+ (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1)
+ if end_pos < 0:
+ # Not sure if template argument list or syntax error in file
+ return False
+ linenum = end_line
+ pos = end_pos
+ return False
+
+ def UpdatePreprocessor(self, line):
+ """Update preprocessor stack.
+
+ We need to handle preprocessors due to classes like this:
+ #ifdef SWIG
+ struct ResultDetailsPageElementExtensionPoint {
+ #else
+ struct ResultDetailsPageElementExtensionPoint : public Extension {
+ #endif
+
+ We make the following assumptions (good enough for most files):
+ - Preprocessor condition evaluates to true from #if up to first
+ #else/#elif/#endif.
+
+ - Preprocessor condition evaluates to false from #else/#elif up
+ to #endif. We still perform lint checks on these lines, but
+ these do not affect nesting stack.
+
+ Args:
+ line: current line to check.
+ """
+ if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
+ # Beginning of #if block, save the nesting stack here. The saved
+ # stack will allow us to restore the parsing state in the #else case.
+ self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
+ elif Match(r'^\s*#\s*(else|elif)\b', line):
+ # Beginning of #else block
+ if self.pp_stack:
+ if not self.pp_stack[-1].seen_else:
+ # This is the first #else or #elif block. Remember the
+ # whole nesting stack up to this point. This is what we
+ # keep after the #endif.
+ self.pp_stack[-1].seen_else = True
+ self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
+
+ # Restore the stack to how it was before the #if
+ self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
+ else:
+ # TODO(unknown): unexpected #else, issue warning?
+ pass
+ elif Match(r'^\s*#\s*endif\b', line):
+ # End of #if or #else blocks.
+ if self.pp_stack:
+ # If we saw an #else, we will need to restore the nesting
+ # stack to its former state before the #else, otherwise we
+ # will just continue from where we left off.
+ if self.pp_stack[-1].seen_else:
+ # Here we can just use a shallow copy since we are the last
+ # reference to it.
+ self.stack = self.pp_stack[-1].stack_before_else
+ # Drop the corresponding #if
+ self.pp_stack.pop()
+ else:
+ # TODO(unknown): unexpected #endif, issue warning?
+ pass
+
+ # TODO(unknown): Update() is too long, but we will refactor later.
+ def Update(self, filename, clean_lines, linenum, error):
+ """Update nesting state with current line.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Remember top of the previous nesting stack.
+ #
+ # The stack is always pushed/popped and not modified in place, so
+ # we can just do a shallow copy instead of copy.deepcopy. Using
+ # deepcopy would slow down cpplint by ~28%.
+ if self.stack:
+ self.previous_stack_top = self.stack[-1]
+ else:
+ self.previous_stack_top = None
+
+ # Update pp_stack
+ self.UpdatePreprocessor(line)
+
+ # Count parentheses. This is to avoid adding struct arguments to
+ # the nesting stack.
+ if self.stack:
+ inner_block = self.stack[-1]
+ depth_change = line.count('(') - line.count(')')
+ inner_block.open_parentheses += depth_change
+
+ # Also check if we are starting or ending an inline assembly block.
+ if inner_block.inline_asm in (_NO_ASM, _END_ASM):
+ if (depth_change != 0 and
+ inner_block.open_parentheses == 1 and
+ _MATCH_ASM.match(line)):
+ # Enter assembly block
+ inner_block.inline_asm = _INSIDE_ASM
+ else:
+ # Not entering assembly block. If previous line was _END_ASM,
+ # we will now shift to _NO_ASM state.
+ inner_block.inline_asm = _NO_ASM
+ elif (inner_block.inline_asm == _INSIDE_ASM and
+ inner_block.open_parentheses == 0):
+ # Exit assembly block
+ inner_block.inline_asm = _END_ASM
+
+ # Consume namespace declaration at the beginning of the line. Do
+ # this in a loop so that we catch same line declarations like this:
+ # namespace proto2 { namespace bridge { class MessageSet; } }
+ while True:
+ # Match start of namespace. The "\b\s*" below catches namespace
+ # declarations even if it weren't followed by a whitespace, this
+ # is so that we don't confuse our namespace checker. The
+ # missing spaces will be flagged by CheckSpacing.
+ namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
+ if not namespace_decl_match:
+ break
+
+ new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
+ self.stack.append(new_namespace)
+
+ line = namespace_decl_match.group(2)
+ if line.find('{') != -1:
+ new_namespace.seen_open_brace = True
+ line = line[line.find('{') + 1:]
+
+ # Look for a class declaration in whatever is left of the line
+ # after parsing namespaces. The regexp accounts for decorated classes
+ # such as in:
+ # class LOCKABLE API Object {
+ # };
+ class_decl_match = Match(
+ r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?'
+ r'(class|struct)\s+(?:[A-Z_]+\s+)*(\w+(?:::\w+)*))'
+ r'(.*)$', line)
+ if (class_decl_match and
+ (not self.stack or self.stack[-1].open_parentheses == 0)):
+ # We do not want to accept classes that are actually template arguments:
+ # template <class Ignore1,
+ # class Ignore2 = Default<Args>,
+ # template <Args> class Ignore3>
+ # void Function() {};
+ #
+ # To avoid template argument cases, we scan forward and look for
+ # an unmatched '>'. If we see one, assume we are inside a
+ # template argument list.
+ end_declaration = len(class_decl_match.group(1))
+ if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration):
+ self.stack.append(_ClassInfo(
+ class_decl_match.group(3), class_decl_match.group(2),
+ clean_lines, linenum))
+ line = class_decl_match.group(4)
+
+ # If we have not yet seen the opening brace for the innermost block,
+ # run checks here.
+ if not self.SeenOpenBrace():
+ self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
+
+ # Update access control if we are inside a class/struct
+ if self.stack and isinstance(self.stack[-1], _ClassInfo):
+ classinfo = self.stack[-1]
+ access_match = Match(
+ r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'
+ r':(?:[^:]|$)',
+ line)
+ if access_match:
+ classinfo.access = access_match.group(2)
+
+ # Check that access keywords are indented +1 space. Skip this
+ # check if the keywords are not preceded by whitespaces.
+ indent = access_match.group(1)
+ if (len(indent) != classinfo.class_indent + 1 and
+ Match(r'^\s*$', indent)):
+ if classinfo.is_struct:
+ parent = 'struct ' + classinfo.name
+ else:
+ parent = 'class ' + classinfo.name
+ slots = ''
+ if access_match.group(3):
+ slots = access_match.group(3)
+ error(filename, linenum, 'whitespace/indent', 3,
+ '%s%s: should be indented +1 space inside %s' % (
+ access_match.group(2), slots, parent))
+
+ # Consume braces or semicolons from what's left of the line
+ while True:
+ # Match first brace, semicolon, or closed parenthesis.
+ matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
+ if not matched:
+ break
+
+ token = matched.group(1)
+ if token == '{':
+ # If namespace or class hasn't seen a opening brace yet, mark
+ # namespace/class head as complete. Push a new block onto the
+ # stack otherwise.
+ if not self.SeenOpenBrace():
+ self.stack[-1].seen_open_brace = True
+ elif Match(r'^extern\s*"[^"]*"\s*\{', line):
+ self.stack.append(_ExternCInfo(linenum))
+ else:
+ self.stack.append(_BlockInfo(linenum, True))
+ if _MATCH_ASM.match(line):
+ self.stack[-1].inline_asm = _BLOCK_ASM
+
+ elif token == ';' or token == ')':
+ # If we haven't seen an opening brace yet, but we already saw
+ # a semicolon, this is probably a forward declaration. Pop
+ # the stack for these.
+ #
+ # Similarly, if we haven't seen an opening brace yet, but we
+ # already saw a closing parenthesis, then these are probably
+ # function arguments with extra "class" or "struct" keywords.
+ # Also pop these stack for these.
+ if not self.SeenOpenBrace():
+ self.stack.pop()
+ else: # token == '}'
+ # Perform end of block checks and pop the stack.
+ if self.stack:
+ self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
+ self.stack.pop()
+ line = matched.group(2)
+
+ def InnermostClass(self):
+ """Get class info on the top of the stack.
+
+ Returns:
+ A _ClassInfo object if we are inside a class, or None otherwise.
+ """
+ for i in range(len(self.stack), 0, -1):
+ classinfo = self.stack[i - 1]
+ if isinstance(classinfo, _ClassInfo):
+ return classinfo
+ return None
+
+ def CheckCompletedBlocks(self, filename, error):
+ """Checks that all classes and namespaces have been completely parsed.
+
+ Call this when all lines in a file have been processed.
+ Args:
+ filename: The name of the current file.
+ error: The function to call with any errors found.
+ """
+ # Note: This test can result in false positives if #ifdef constructs
+ # get in the way of brace matching. See the testBuildClass test in
+ # cpplint_unittest.py for an example of this.
+ for obj in self.stack:
+ if isinstance(obj, _ClassInfo):
+ error(filename, obj.starting_linenum, 'build/class', 5,
+ 'Failed to find complete declaration of class %s' %
+ obj.name)
+ elif isinstance(obj, _NamespaceInfo):
+ error(filename, obj.starting_linenum, 'build/namespaces', 5,
+ 'Failed to find complete declaration of namespace %s' %
+ obj.name)
+
+
+def CheckForNonStandardConstructs(filename, clean_lines, linenum,
+ nesting_state, error):
+ r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
+
+ Complain about several constructs which gcc-2 accepts, but which are
+ not standard C++. Warning about these in lint is one way to ease the
+ transition to new compilers.
+ - put storage class first (e.g. "static const" instead of "const static").
+ - "%lld" instead of %qd" in printf-type functions.
+ - "%1$d" is non-standard in printf-type functions.
+ - "\%" is an undefined character escape sequence.
+ - text after #endif is not allowed.
+ - invalid inner-style forward declaration.
+ - >? and <? operators, and their >?= and <?= cousins.
+
+ Additionally, check for constructor/destructor style violations and reference
+ members, as it is very convenient to do so while checking for
+ gcc-2 compliance.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ """
+
+ # Remove comments from the line, but leave in strings for now.
+ line = clean_lines.lines[linenum]
+
+ if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
+ error(filename, linenum, 'runtime/printf_format', 3,
+ '%q in format strings is deprecated. Use %ll instead.')
+
+ if Search(r'printf\s*\(.*".*%\d+\$', line):
+ error(filename, linenum, 'runtime/printf_format', 2,
+ '%N$ formats are unconventional. Try rewriting to avoid them.')
+
+ # Remove escaped backslashes before looking for undefined escapes.
+ line = line.replace('\\\\', '')
+
+ if Search(r'("|\').*\\(%|\[|\(|{)', line):
+ error(filename, linenum, 'build/printf_format', 3,
+ '%, [, (, and { are undefined character escapes. Unescape them.')
+
+ # For the rest, work with both comments and strings removed.
+ line = clean_lines.elided[linenum]
+
+ if Search(r'\b(const|volatile|void|char|short|int|long'
+ r'|float|double|signed|unsigned'
+ r'|schar|u?int8|u?int16|u?int32|u?int64)'
+ r'\s+(register|static|extern|typedef)\b',
+ line):
+ error(filename, linenum, 'build/storage_class', 5,
+ 'Storage-class specifier (static, extern, typedef, etc) should be '
+ 'at the beginning of the declaration.')
+
+ if Match(r'\s*#\s*endif\s*[^/\s]+', line):
+ error(filename, linenum, 'build/endif_comment', 5,
+ 'Uncommented text after #endif is non-standard. Use a comment.')
+
+ if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
+ error(filename, linenum, 'build/forward_decl', 5,
+ 'Inner-style forward declarations are invalid. Remove this line.')
+
+ if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
+ line):
+ error(filename, linenum, 'build/deprecated', 3,
+ '>? and <? (max and min) operators are non-standard and deprecated.')
+
+ if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
+ # TODO(unknown): Could it be expanded safely to arbitrary references,
+ # without triggering too many false positives? The first
+ # attempt triggered 5 warnings for mostly benign code in the regtest, hence
+ # the restriction.
+ # Here's the original regexp, for the reference:
+ # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
+ # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
+ error(filename, linenum, 'runtime/member_string_references', 2,
+ 'const string& members are dangerous. It is much better to use '
+ 'alternatives, such as pointers or simple constants.')
+
+ # Everything else in this function operates on class declarations.
+ # Return early if the top of the nesting stack is not a class, or if
+ # the class head is not completed yet.
+ classinfo = nesting_state.InnermostClass()
+ if not classinfo or not classinfo.seen_open_brace:
+ return
+
+ # The class may have been declared with namespace or classname qualifiers.
+ # The constructor and destructor will not have those qualifiers.
+ base_classname = classinfo.name.split('::')[-1]
+
+ # Look for single-argument constructors that aren't marked explicit.
+ # Technically a valid construct, but against style.
+ explicit_constructor_match = Match(
+ r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?'
+ r'(?:(?:inline|constexpr)\s+)*%s\s*'
+ r'\(((?:[^()]|\([^()]*\))*)\)'
+ % re.escape(base_classname),
+ line)
+
+ if explicit_constructor_match:
+ is_marked_explicit = explicit_constructor_match.group(1)
+
+ if not explicit_constructor_match.group(2):
+ constructor_args = []
+ else:
+ constructor_args = explicit_constructor_match.group(2).split(',')
+
+ # collapse arguments so that commas in template parameter lists and function
+ # argument parameter lists don't split arguments in two
+ i = 0
+ while i < len(constructor_args):
+ constructor_arg = constructor_args[i]
+ while (constructor_arg.count('<') > constructor_arg.count('>') or
+ constructor_arg.count('(') > constructor_arg.count(')')):
+ constructor_arg += ',' + constructor_args[i + 1]
+ del constructor_args[i + 1]
+ constructor_args[i] = constructor_arg
+ i += 1
+
+ defaulted_args = [arg for arg in constructor_args if '=' in arg]
+ noarg_constructor = (not constructor_args or # empty arg list
+ # 'void' arg specifier
+ (len(constructor_args) == 1 and
+ constructor_args[0].strip() == 'void'))
+ onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg
+ not noarg_constructor) or
+ # all but at most one arg defaulted
+ (len(constructor_args) >= 1 and
+ not noarg_constructor and
+ len(defaulted_args) >= len(constructor_args) - 1))
+ initializer_list_constructor = bool(
+ onearg_constructor and
+ Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
+ copy_constructor = bool(
+ onearg_constructor and
+ Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
+ % re.escape(base_classname), constructor_args[0].strip()))
+
+ if (not is_marked_explicit and
+ onearg_constructor and
+ not initializer_list_constructor and
+ not copy_constructor):
+ if defaulted_args:
+ error(filename, linenum, 'runtime/explicit', 5,
+ 'Constructors callable with one argument '
+ 'should be marked explicit.')
+ else:
+ error(filename, linenum, 'runtime/explicit', 5,
+ 'Single-parameter constructors should be marked explicit.')
+ elif is_marked_explicit and not onearg_constructor:
+ if noarg_constructor:
+ error(filename, linenum, 'runtime/explicit', 5,
+ 'Zero-parameter constructors should not be marked explicit.')
+
+
+def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
+ """Checks for the correctness of various spacing around function calls.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Since function calls often occur inside if/for/while/switch
+ # expressions - which have their own, more liberal conventions - we
+ # first see if we should be looking inside such an expression for a
+ # function call, to which we can apply more strict standards.
+ fncall = line # if there's no control flow construct, look at whole line
+ for pattern in (r'\bif\s*\((.*)\)\s*{',
+ r'\bfor\s*\((.*)\)\s*{',
+ r'\bwhile\s*\((.*)\)\s*[{;]',
+ r'\bswitch\s*\((.*)\)\s*{'):
+ match = Search(pattern, line)
+ if match:
+ fncall = match.group(1) # look inside the parens for function calls
+ break
+
+ # Except in if/for/while/switch, there should never be space
+ # immediately inside parens (eg "f( 3, 4 )"). We make an exception
+ # for nested parens ( (a+b) + c ). Likewise, there should never be
+ # a space before a ( when it's a function argument. I assume it's a
+ # function argument when the char before the whitespace is legal in
+ # a function name (alnum + _) and we're not starting a macro. Also ignore
+ # pointers and references to arrays and functions coz they're too tricky:
+ # we use a very simple way to recognize these:
+ # " (something)(maybe-something)" or
+ # " (something)(maybe-something," or
+ # " (something)[something]"
+ # Note that we assume the contents of [] to be short enough that
+ # they'll never need to wrap.
+ if ( # Ignore control structures.
+ not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b',
+ fncall) and
+ # Ignore pointers/references to functions.
+ not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
+ # Ignore pointers/references to arrays.
+ not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
+ if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call
+ error(filename, linenum, 'whitespace/parens', 4,
+ 'Extra space after ( in function call')
+ elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Extra space after (')
+ if (Search(r'\w\s+\(', fncall) and
+ not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and
+ not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and
+ not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and
+ not Search(r'\bcase\s+\(', fncall)):
+ # TODO(unknown): Space after an operator function seem to be a common
+ # error, silence those for now by restricting them to highest verbosity.
+ if Search(r'\boperator_*\b', line):
+ error(filename, linenum, 'whitespace/parens', 0,
+ 'Extra space before ( in function call')
+ else:
+ error(filename, linenum, 'whitespace/parens', 4,
+ 'Extra space before ( in function call')
+ # If the ) is followed only by a newline or a { + newline, assume it's
+ # part of a control statement (if/while/etc), and don't complain
+ if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
+ # If the closing parenthesis is preceded by only whitespaces,
+ # try to give a more descriptive error message.
+ if Search(r'^\s+\)', fncall):
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Closing ) should be moved to the previous line')
+ else:
+ error(filename, linenum, 'whitespace/parens', 2,
+ 'Extra space before )')
+
+
+def IsBlankLine(line):
+ """Returns true if the given line is blank.
+
+ We consider a line to be blank if the line is empty or consists of
+ only white spaces.
+
+ Args:
+ line: A line of a string.
+
+ Returns:
+ True, if the given line is blank.
+ """
+ return not line or line.isspace()
+
+
+def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
+ error):
+ is_namespace_indent_item = (
+ len(nesting_state.stack) > 1 and
+ nesting_state.stack[-1].check_namespace_indentation and
+ isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and
+ nesting_state.previous_stack_top == nesting_state.stack[-2])
+
+ if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
+ clean_lines.elided, line):
+ CheckItemIndentationInNamespace(filename, clean_lines.elided,
+ line, error)
+
+
+def CheckForFunctionLengths(filename, clean_lines, linenum,
+ function_state, error):
+ """Reports for long function bodies.
+
+ For an overview why this is done, see:
+ https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
+
+ Uses a simplistic algorithm assuming other style guidelines
+ (especially spacing) are followed.
+ Only checks unindented functions, so class members are unchecked.
+ Trivial bodies are unchecked, so constructors with huge initializer lists
+ may be missed.
+ Blank/comment lines are not counted so as to avoid encouraging the removal
+ of vertical space and comments just to get through a lint check.
+ NOLINT *on the last line of a function* disables this check.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ function_state: Current function name and lines in body so far.
+ error: The function to call with any errors found.
+ """
+ lines = clean_lines.lines
+ line = lines[linenum]
+ joined_line = ''
+
+ starting_func = False
+ regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ...
+ match_result = Match(regexp, line)
+ if match_result:
+ # If the name is all caps and underscores, figure it's a macro and
+ # ignore it, unless it's TEST or TEST_F.
+ function_name = match_result.group(1).split()[-1]
+ if function_name == 'TEST' or function_name == 'TEST_F' or (
+ not Match(r'[A-Z_]+$', function_name)):
+ starting_func = True
+
+ if starting_func:
+ body_found = False
+ for start_linenum in xrange(linenum, clean_lines.NumLines()):
+ start_line = lines[start_linenum]
+ joined_line += ' ' + start_line.lstrip()
+ if Search(r'(;|})', start_line): # Declarations and trivial functions
+ body_found = True
+ break # ... ignore
+ elif Search(r'{', start_line):
+ body_found = True
+ function = Search(r'((\w|:)*)\(', line).group(1)
+ if Match(r'TEST', function): # Handle TEST... macros
+ parameter_regexp = Search(r'(\(.*\))', joined_line)
+ if parameter_regexp: # Ignore bad syntax
+ function += parameter_regexp.group(1)
+ else:
+ function += '()'
+ function_state.Begin(function)
+ break
+ if not body_found:
+ # No body for the function (or evidence of a non-function) was found.
+ error(filename, linenum, 'readability/fn_size', 5,
+ 'Lint failed to find start of function body.')
+ elif Match(r'^\}\s*$', line): # function end
+ function_state.Check(error, filename, linenum)
+ function_state.End()
+ elif not Match(r'^\s*$', line):
+ function_state.Count() # Count non-blank/non-comment lines.
+
+
+_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
+
+
+def CheckComment(line, filename, linenum, next_line_start, error):
+ """Checks for common mistakes in comments.
+
+ Args:
+ line: The line in question.
+ filename: The name of the current file.
+ linenum: The number of the line to check.
+ next_line_start: The first non-whitespace column of the next line.
+ error: The function to call with any errors found.
+ """
+ commentpos = line.find('//')
+ if commentpos != -1:
+ # Check if the // may be in quotes. If so, ignore it
+ if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0:
+ # Allow one space for new scopes, two spaces otherwise:
+ if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and
+ ((commentpos >= 1 and
+ line[commentpos-1] not in string.whitespace) or
+ (commentpos >= 2 and
+ line[commentpos-2] not in string.whitespace))):
+ error(filename, linenum, 'whitespace/comments', 2,
+ 'At least two spaces is best between code and comments')
+
+ # Checks for common mistakes in TODO comments.
+ comment = line[commentpos:]
+ match = _RE_PATTERN_TODO.match(comment)
+ if match:
+ # One whitespace is correct; zero whitespace is handled elsewhere.
+ leading_whitespace = match.group(1)
+ if len(leading_whitespace) > 1:
+ error(filename, linenum, 'whitespace/todo', 2,
+ 'Too many spaces before TODO')
+
+ username = match.group(2)
+ if not username:
+ error(filename, linenum, 'readability/todo', 2,
+ 'Missing username in TODO; it should look like '
+ '"// TODO(my_username): Stuff."')
+
+ middle_whitespace = match.group(3)
+ # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison
+ if middle_whitespace != ' ' and middle_whitespace != '':
+ error(filename, linenum, 'whitespace/todo', 2,
+ 'TODO(my_username) should be followed by a space')
+
+ # If the comment contains an alphanumeric character, there
+ # should be a space somewhere between it and the // unless
+ # it's a /// or //! Doxygen comment.
+ if (Match(r'//[^ ]*\w', comment) and
+ not Match(r'(///|//\!)(\s+|$)', comment)):
+ error(filename, linenum, 'whitespace/comments', 4,
+ 'Should have a space between // and comment')
+
+
+def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
+ """Checks for the correctness of various spacing issues in the code.
+
+ Things we check for: spaces around operators, spaces after
+ if/for/while/switch, no spaces around parens in function calls, two
+ spaces between code and comment, don't start a block with a blank
+ line, don't end a function with a blank line, don't add a blank line
+ after public/protected/private, don't have too many blank lines in a row.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+
+ # Don't use "elided" lines here, otherwise we can't check commented lines.
+ # Don't want to use "raw" either, because we don't want to check inside C++11
+ # raw strings,
+ raw = clean_lines.lines_without_raw_strings
+ line = raw[linenum]
+
+ # Before nixing comments, check if the line is blank for no good
+ # reason. This includes the first line after a block is opened, and
+ # blank lines at the end of a function (ie, right before a line like '}'
+ #
+ # Skip all the blank line checks if we are immediately inside a
+ # namespace body. In other words, don't issue blank line warnings
+ # for this block:
+ # namespace {
+ #
+ # }
+ #
+ # A warning about missing end of namespace comments will be issued instead.
+ #
+ # Also skip blank line checks for 'extern "C"' blocks, which are formatted
+ # like namespaces.
+ if (IsBlankLine(line) and
+ not nesting_state.InNamespaceBody() and
+ not nesting_state.InExternC()):
+ elided = clean_lines.elided
+ prev_line = elided[linenum - 1]
+ prevbrace = prev_line.rfind('{')
+ # TODO(unknown): Don't complain if line before blank line, and line after,
+ # both start with alnums and are indented the same amount.
+ # This ignores whitespace at the start of a namespace block
+ # because those are not usually indented.
+ if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
+ # OK, we have a blank line at the start of a code block. Before we
+ # complain, we check if it is an exception to the rule: The previous
+ # non-empty line has the parameters of a function header that are indented
+ # 4 spaces (because they did not fit in a 80 column line when placed on
+ # the same line as the function name). We also check for the case where
+ # the previous line is indented 6 spaces, which may happen when the
+ # initializers of a constructor do not fit into a 80 column line.
+ exception = False
+ if Match(r' {6}\w', prev_line): # Initializer list?
+ # We are looking for the opening column of initializer list, which
+ # should be indented 4 spaces to cause 6 space indentation afterwards.
+ search_position = linenum-2
+ while (search_position >= 0
+ and Match(r' {6}\w', elided[search_position])):
+ search_position -= 1
+ exception = (search_position >= 0
+ and elided[search_position][:5] == ' :')
+ else:
+ # Search for the function arguments or an initializer list. We use a
+ # simple heuristic here: If the line is indented 4 spaces; and we have a
+ # closing paren, without the opening paren, followed by an opening brace
+ # or colon (for initializer lists) we assume that it is the last line of
+ # a function header. If we have a colon indented 4 spaces, it is an
+ # initializer list.
+ exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
+ prev_line)
+ or Match(r' {4}:', prev_line))
+
+ if not exception:
+ error(filename, linenum, 'whitespace/blank_line', 2,
+ 'Redundant blank line at the start of a code block '
+ 'should be deleted.')
+ # Ignore blank lines at the end of a block in a long if-else
+ # chain, like this:
+ # if (condition1) {
+ # // Something followed by a blank line
+ #
+ # } else if (condition2) {
+ # // Something else
+ # }
+ if linenum + 1 < clean_lines.NumLines():
+ next_line = raw[linenum + 1]
+ if (next_line
+ and Match(r'\s*}', next_line)
+ and next_line.find('} else ') == -1):
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ 'Redundant blank line at the end of a code block '
+ 'should be deleted.')
+
+ matched = Match(r'\s*(public|protected|private):', prev_line)
+ if matched:
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ 'Do not leave a blank line after "%s:"' % matched.group(1))
+
+ # Next, check comments
+ next_line_start = 0
+ if linenum + 1 < clean_lines.NumLines():
+ next_line = raw[linenum + 1]
+ next_line_start = len(next_line) - len(next_line.lstrip())
+ CheckComment(line, filename, linenum, next_line_start, error)
+
+ # get rid of comments and strings
+ line = clean_lines.elided[linenum]
+
+ # You shouldn't have spaces before your brackets, except maybe after
+ # 'delete []' or 'return []() {};'
+ if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Extra space before [')
+
+ # In range-based for, we wanted spaces before and after the colon, but
+ # not around "::" tokens that might appear.
+ if (Search(r'for *\(.*[^:]:[^: ]', line) or
+ Search(r'for *\(.*[^: ]:[^:]', line)):
+ error(filename, linenum, 'whitespace/forcolon', 2,
+ 'Missing space around colon in range-based for loop')
+
+
+def CheckOperatorSpacing(filename, clean_lines, linenum, error):
+ """Checks for horizontal spacing around operators.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Don't try to do spacing checks for operator methods. Do this by
+ # replacing the troublesome characters with something else,
+ # preserving column position for all other characters.
+ #
+ # The replacement is done repeatedly to avoid false positives from
+ # operators that call operators.
+ while True:
+ match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line)
+ if match:
+ line = match.group(1) + ('_' * len(match.group(2))) + match.group(3)
+ else:
+ break
+
+ # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
+ # Otherwise not. Note we only check for non-spaces on *both* sides;
+ # sometimes people put non-spaces on one side when aligning ='s among
+ # many lines (not that this is behavior that I approve of...)
+ if ((Search(r'[\w.]=', line) or
+ Search(r'=[\w.]', line))
+ and not Search(r'\b(if|while|for) ', line)
+ # Operators taken from [lex.operators] in C++11 standard.
+ and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line)
+ and not Search(r'operator=', line)):
+ error(filename, linenum, 'whitespace/operators', 4,
+ 'Missing spaces around =')
+
+ # It's ok not to have spaces around binary operators like + - * /, but if
+ # there's too little whitespace, we get concerned. It's hard to tell,
+ # though, so we punt on this one for now. TODO.
+
+ # You should always have whitespace around binary operators.
+ #
+ # Check <= and >= first to avoid false positives with < and >, then
+ # check non-include lines for spacing around < and >.
+ #
+ # If the operator is followed by a comma, assume it's be used in a
+ # macro context and don't do any checks. This avoids false
+ # positives.
+ #
+ # Note that && is not included here. This is because there are too
+ # many false positives due to RValue references.
+ match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around %s' % match.group(1))
+ elif not Match(r'#.*include', line):
+ # Look for < that is not surrounded by spaces. This is only
+ # triggered if both sides are missing spaces, even though
+ # technically should should flag if at least one side is missing a
+ # space. This is done to avoid some false positives with shifts.
+ match = Match(r'^(.*[^\s<])<[^\s=<,]', line)
+ if match:
+ (_, _, end_pos) = CloseExpression(
+ clean_lines, linenum, len(match.group(1)))
+ if end_pos <= -1:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around <')
+
+ # Look for > that is not surrounded by spaces. Similar to the
+ # above, we only trigger if both sides are missing spaces to avoid
+ # false positives with shifts.
+ match = Match(r'^(.*[^-\s>])>[^\s=>,]', line)
+ if match:
+ (_, _, start_pos) = ReverseCloseExpression(
+ clean_lines, linenum, len(match.group(1)))
+ if start_pos <= -1:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around >')
+
+ # We allow no-spaces around << when used like this: 10<<20, but
+ # not otherwise (particularly, not when used as streams)
+ #
+ # We also allow operators following an opening parenthesis, since
+ # those tend to be macros that deal with operators.
+ match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line)
+ if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and
+ not (match.group(1) == 'operator' and match.group(2) == ';')):
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around <<')
+
+ # We allow no-spaces around >> for almost anything. This is because
+ # C++11 allows ">>" to close nested templates, which accounts for
+ # most cases when ">>" is not followed by a space.
+ #
+ # We still warn on ">>" followed by alpha character, because that is
+ # likely due to ">>" being used for right shifts, e.g.:
+ # value >> alpha
+ #
+ # When ">>" is used to close templates, the alphanumeric letter that
+ # follows would be part of an identifier, and there should still be
+ # a space separating the template type and the identifier.
+ # type<type<type>> alpha
+ match = Search(r'>>[a-zA-Z_]', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 3,
+ 'Missing spaces around >>')
+
+ # There shouldn't be space around unary operators
+ match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
+ if match:
+ error(filename, linenum, 'whitespace/operators', 4,
+ 'Extra space for operator %s' % match.group(1))
+
+
+def CheckParenthesisSpacing(filename, clean_lines, linenum, error):
+ """Checks for horizontal spacing around parentheses.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # No spaces after an if, while, switch, or for
+ match = Search(r' (if\(|for\(|while\(|switch\()', line)
+ if match:
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Missing space before ( in %s' % match.group(1))
+
+ # For if/for/while/switch, the left and right parens should be
+ # consistent about how many spaces are inside the parens, and
+ # there should either be zero or one spaces inside the parens.
+ # We don't want: "if ( foo)" or "if ( foo )".
+ # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
+ match = Search(r'\b(if|for|while|switch)\s*'
+ r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
+ line)
+ if match:
+ if len(match.group(2)) != len(match.group(4)):
+ if not (match.group(3) == ';' and
+ len(match.group(2)) == 1 + len(match.group(4)) or
+ not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Mismatching spaces inside () in %s' % match.group(1))
+ if len(match.group(2)) not in [0, 1]:
+ error(filename, linenum, 'whitespace/parens', 5,
+ 'Should have zero or one spaces inside ( and ) in %s' %
+ match.group(1))
+
+
+def CheckCommaSpacing(filename, clean_lines, linenum, error):
+ """Checks for horizontal spacing near commas and semicolons.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ raw = clean_lines.lines_without_raw_strings
+ line = clean_lines.elided[linenum]
+
+ # You should always have a space after a comma (either as fn arg or operator)
+ #
+ # This does not apply when the non-space character following the
+ # comma is another comma, since the only time when that happens is
+ # for empty macro arguments.
+ #
+ # We run this check in two passes: first pass on elided lines to
+ # verify that lines contain missing whitespaces, second pass on raw
+ # lines to confirm that those missing whitespaces are not due to
+ # elided comments.
+ if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and
+ Search(r',[^,\s]', raw[linenum])):
+ error(filename, linenum, 'whitespace/comma', 3,
+ 'Missing space after ,')
+
+ # You should always have a space after a semicolon
+ # except for few corner cases
+ # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
+ # space after ;
+ if Search(r';[^\s};\\)/]', line):
+ error(filename, linenum, 'whitespace/semicolon', 3,
+ 'Missing space after ;')
+
+
+def _IsType(clean_lines, nesting_state, expr):
+ """Check if expression looks like a type name, returns true if so.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ expr: The expression to check.
+ Returns:
+ True, if token looks like a type.
+ """
+ # Keep only the last token in the expression
+ last_word = Match(r'^.*(\b\S+)$', expr)
+ if last_word:
+ token = last_word.group(1)
+ else:
+ token = expr
+
+ # Match native types and stdint types
+ if _TYPES.match(token):
+ return True
+
+ # Try a bit harder to match templated types. Walk up the nesting
+ # stack until we find something that resembles a typename
+ # declaration for what we are looking for.
+ typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) +
+ r'\b')
+ block_index = len(nesting_state.stack) - 1
+ while block_index >= 0:
+ if isinstance(nesting_state.stack[block_index], _NamespaceInfo):
+ return False
+
+ # Found where the opening brace is. We want to scan from this
+ # line up to the beginning of the function, minus a few lines.
+ # template <typename Type1, // stop scanning here
+ # ...>
+ # class C
+ # : public ... { // start scanning here
+ last_line = nesting_state.stack[block_index].starting_linenum
+
+ next_block_start = 0
+ if block_index > 0:
+ next_block_start = nesting_state.stack[block_index - 1].starting_linenum
+ first_line = last_line
+ while first_line >= next_block_start:
+ if clean_lines.elided[first_line].find('template') >= 0:
+ break
+ first_line -= 1
+ if first_line < next_block_start:
+ # Didn't find any "template" keyword before reaching the next block,
+ # there are probably no template things to check for this block
+ block_index -= 1
+ continue
+
+ # Look for typename in the specified range
+ for i in xrange(first_line, last_line + 1, 1):
+ if Search(typename_pattern, clean_lines.elided[i]):
+ return True
+ block_index -= 1
+
+ return False
+
+
+def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error):
+ """Checks for horizontal spacing near commas.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Except after an opening paren, or after another opening brace (in case of
+ # an initializer list, for instance), you should have spaces before your
+ # braces when they are delimiting blocks, classes, namespaces etc.
+ # And since you should never have braces at the beginning of a line,
+ # this is an easy test. Except that braces used for initialization don't
+ # follow the same rule; we often don't want spaces before those.
+ match = Match(r'^(.*[^ ({>]){', line)
+
+ if match:
+ # Try a bit harder to check for brace initialization. This
+ # happens in one of the following forms:
+ # Constructor() : initializer_list_{} { ... }
+ # Constructor{}.MemberFunction()
+ # Type variable{};
+ # FunctionCall(type{}, ...);
+ # LastArgument(..., type{});
+ # LOG(INFO) << type{} << " ...";
+ # map_of_type[{...}] = ...;
+ # ternary = expr ? new type{} : nullptr;
+ # OuterTemplate<InnerTemplateConstructor<Type>{}>
+ #
+ # We check for the character following the closing brace, and
+ # silence the warning if it's one of those listed above, i.e.
+ # "{.;,)<>]:".
+ #
+ # To account for nested initializer list, we allow any number of
+ # closing braces up to "{;,)<". We can't simply silence the
+ # warning on first sight of closing brace, because that would
+ # cause false negatives for things that are not initializer lists.
+ # Silence this: But not this:
+ # Outer{ if (...) {
+ # Inner{...} if (...){ // Missing space before {
+ # }; }
+ #
+ # There is a false negative with this approach if people inserted
+ # spurious semicolons, e.g. "if (cond){};", but we will catch the
+ # spurious semicolon with a separate check.
+ leading_text = match.group(1)
+ (endline, endlinenum, endpos) = CloseExpression(
+ clean_lines, linenum, len(match.group(1)))
+ trailing_text = ''
+ if endpos > -1:
+ trailing_text = endline[endpos:]
+ for offset in xrange(endlinenum + 1,
+ min(endlinenum + 3, clean_lines.NumLines() - 1)):
+ trailing_text += clean_lines.elided[offset]
+ # We also suppress warnings for `uint64_t{expression}` etc., as the style
+ # guide recommends brace initialization for integral types to avoid
+ # overflow/truncation.
+ if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text)
+ and not _IsType(clean_lines, nesting_state, leading_text)):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Missing space before {')
+
+ # Make sure '} else {' has spaces.
+ if Search(r'}else', line):
+ error(filename, linenum, 'whitespace/braces', 5,
+ 'Missing space before else')
+
+ # You shouldn't have a space before a semicolon at the end of the line.
+ # There's a special case for "for" since the style guide allows space before
+ # the semicolon there.
+ if Search(r':\s*;\s*$', line):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Semicolon defining empty statement. Use {} instead.')
+ elif Search(r'^\s*;\s*$', line):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Line contains only semicolon. If this should be an empty statement, '
+ 'use {} instead.')
+ elif (Search(r'\s+;\s*$', line) and
+ not Search(r'\bfor\b', line)):
+ error(filename, linenum, 'whitespace/semicolon', 5,
+ 'Extra space before last semicolon. If this should be an empty '
+ 'statement, use {} instead.')
+
+
+def IsDecltype(clean_lines, linenum, column):
+ """Check if the token ending on (linenum, column) is decltype().
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: the number of the line to check.
+ column: end column of the token to check.
+ Returns:
+ True if this token is decltype() expression, False otherwise.
+ """
+ (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column)
+ if start_col < 0:
+ return False
+ if Search(r'\bdecltype\s*$', text[0:start_col]):
+ return True
+ return False
+
+
+def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
+ """Checks for additional blank line issues related to sections.
+
+ Currently the only thing checked here is blank line before protected/private.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ class_info: A _ClassInfo objects.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ # Skip checks if the class is small, where small means 25 lines or less.
+ # 25 lines seems like a good cutoff since that's the usual height of
+ # terminals, and any class that can't fit in one screen can't really
+ # be considered "small".
+ #
+ # Also skip checks if we are on the first line. This accounts for
+ # classes that look like
+ # class Foo { public: ... };
+ #
+ # If we didn't find the end of the class, last_line would be zero,
+ # and the check will be skipped by the first condition.
+ if (class_info.last_line - class_info.starting_linenum <= 24 or
+ linenum <= class_info.starting_linenum):
+ return
+
+ matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
+ if matched:
+ # Issue warning if the line before public/protected/private was
+ # not a blank line, but don't do this if the previous line contains
+ # "class" or "struct". This can happen two ways:
+ # - We are at the beginning of the class.
+ # - We are forward-declaring an inner class that is semantically
+ # private, but needed to be public for implementation reasons.
+ # Also ignores cases where the previous line ends with a backslash as can be
+ # common when defining classes in C macros.
+ prev_line = clean_lines.lines[linenum - 1]
+ if (not IsBlankLine(prev_line) and
+ not Search(r'\b(class|struct)\b', prev_line) and
+ not Search(r'\\$', prev_line)):
+ # Try a bit harder to find the beginning of the class. This is to
+ # account for multi-line base-specifier lists, e.g.:
+ # class Derived
+ # : public Base {
+ end_class_head = class_info.starting_linenum
+ for i in range(class_info.starting_linenum, linenum):
+ if Search(r'\{\s*$', clean_lines.lines[i]):
+ end_class_head = i
+ break
+ if end_class_head < linenum - 1:
+ error(filename, linenum, 'whitespace/blank_line', 3,
+ '"%s:" should be preceded by a blank line' % matched.group(1))
+
+
+def GetPreviousNonBlankLine(clean_lines, linenum):
+ """Return the most recent non-blank line and its line number.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file contents.
+ linenum: The number of the line to check.
+
+ Returns:
+ A tuple with two elements. The first element is the contents of the last
+ non-blank line before the current line, or the empty string if this is the
+ first non-blank line. The second is the line number of that line, or -1
+ if this is the first non-blank line.
+ """
+
+ prevlinenum = linenum - 1
+ while prevlinenum >= 0:
+ prevline = clean_lines.elided[prevlinenum]
+ if not IsBlankLine(prevline): # if not a blank line...
+ return (prevline, prevlinenum)
+ prevlinenum -= 1
+ return ('', -1)
+
+
+def CheckBraces(filename, clean_lines, linenum, error):
+ """Looks for misplaced braces (e.g. at the end of line).
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[linenum] # get rid of comments and strings
+
+ if Match(r'\s*{\s*$', line):
+ # We allow an open brace to start a line in the case where someone is using
+ # braces in a block to explicitly create a new scope, which is commonly used
+ # to control the lifetime of stack-allocated variables. Braces are also
+ # used for brace initializers inside function calls. We don't detect this
+ # perfectly: we just don't complain if the last non-whitespace character on
+ # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the
+ # previous line starts a preprocessor block. We also allow a brace on the
+ # following line if it is part of an array initialization and would not fit
+ # within the 80 character limit of the preceding line.
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if (not Search(r'[,;:}{(]\s*$', prevline) and
+ not Match(r'\s*#', prevline) and
+ not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)):
+ error(filename, linenum, 'whitespace/braces', 4,
+ '{ should almost always be at the end of the previous line')
+
+ # An else clause should be on the same line as the preceding closing brace.
+ if Match(r'\s*else\b\s*(?:if\b|\{|$)', line):
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if Match(r'\s*}\s*$', prevline):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'An else should appear on the same line as the preceding }')
+
+ # If braces come on one side of an else, they should be on both.
+ # However, we have to worry about "else if" that spans multiple lines!
+ if Search(r'else if\s*\(', line): # could be multi-line if
+ brace_on_left = bool(Search(r'}\s*else if\s*\(', line))
+ # find the ( after the if
+ pos = line.find('else if')
+ pos = line.find('(', pos)
+ if pos > 0:
+ (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
+ brace_on_right = endline[endpos:].find('{') != -1
+ if brace_on_left != brace_on_right: # must be brace after if
+ error(filename, linenum, 'readability/braces', 5,
+ 'If an else has a brace on one side, it should have it on both')
+ elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
+ error(filename, linenum, 'readability/braces', 5,
+ 'If an else has a brace on one side, it should have it on both')
+
+ # Likewise, an else should never have the else clause on the same line
+ if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'Else clause should never be on same line as else (use 2 lines)')
+
+ # In the same way, a do/while should never be on one line
+ if Match(r'\s*do [^\s{]', line):
+ error(filename, linenum, 'whitespace/newline', 4,
+ 'do/while clauses should not be on a single line')
+
+ # Check single-line if/else bodies. The style guide says 'curly braces are not
+ # required for single-line statements'. We additionally allow multi-line,
+ # single statements, but we reject anything with more than one semicolon in
+ # it. This means that the first semicolon after the if should be at the end of
+ # its line, and the line after that should have an indent level equal to or
+ # lower than the if. We also check for ambiguous if/else nesting without
+ # braces.
+ if_else_match = Search(r'\b(if\s*\(|else\b)', line)
+ if if_else_match and not Match(r'\s*#', line):
+ if_indent = GetIndentLevel(line)
+ endline, endlinenum, endpos = line, linenum, if_else_match.end()
+ if_match = Search(r'\bif\s*\(', line)
+ if if_match:
+ # This could be a multiline if condition, so find the end first.
+ pos = if_match.end() - 1
+ (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos)
+ # Check for an opening brace, either directly after the if or on the next
+ # line. If found, this isn't a single-statement conditional.
+ if (not Match(r'\s*{', endline[endpos:])
+ and not (Match(r'\s*$', endline[endpos:])
+ and endlinenum < (len(clean_lines.elided) - 1)
+ and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))):
+ while (endlinenum < len(clean_lines.elided)
+ and ';' not in clean_lines.elided[endlinenum][endpos:]):
+ endlinenum += 1
+ endpos = 0
+ if endlinenum < len(clean_lines.elided):
+ endline = clean_lines.elided[endlinenum]
+ # We allow a mix of whitespace and closing braces (e.g. for one-liner
+ # methods) and a single \ after the semicolon (for macros)
+ endpos = endline.find(';')
+ if not Match(r';[\s}]*(\\?)$', endline[endpos:]):
+ # Semicolon isn't the last character, there's something trailing.
+ # Output a warning if the semicolon is not contained inside
+ # a lambda expression.
+ if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$',
+ endline):
+ error(filename, linenum, 'readability/braces', 4,
+ 'If/else bodies with multiple statements require braces')
+ elif endlinenum < len(clean_lines.elided) - 1:
+ # Make sure the next line is dedented
+ next_line = clean_lines.elided[endlinenum + 1]
+ next_indent = GetIndentLevel(next_line)
+ # With ambiguous nested if statements, this will error out on the
+ # if that *doesn't* match the else, regardless of whether it's the
+ # inner one or outer one.
+ if (if_match and Match(r'\s*else\b', next_line)
+ and next_indent != if_indent):
+ error(filename, linenum, 'readability/braces', 4,
+ 'Else clause should be indented at the same level as if. '
+ 'Ambiguous nested if/else chains require braces.')
+ elif next_indent > if_indent:
+ error(filename, linenum, 'readability/braces', 4,
+ 'If/else bodies with multiple statements require braces')
+
+
+def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
+ """Looks for redundant trailing semicolon.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[linenum]
+
+ # Block bodies should not be followed by a semicolon. Due to C++11
+ # brace initialization, there are more places where semicolons are
+ # required than not, so we use a whitelist approach to check these
+ # rather than a blacklist. These are the places where "};" should
+ # be replaced by just "}":
+ # 1. Some flavor of block following closing parenthesis:
+ # for (;;) {};
+ # while (...) {};
+ # switch (...) {};
+ # Function(...) {};
+ # if (...) {};
+ # if (...) else if (...) {};
+ #
+ # 2. else block:
+ # if (...) else {};
+ #
+ # 3. const member function:
+ # Function(...) const {};
+ #
+ # 4. Block following some statement:
+ # x = 42;
+ # {};
+ #
+ # 5. Block at the beginning of a function:
+ # Function(...) {
+ # {};
+ # }
+ #
+ # Note that naively checking for the preceding "{" will also match
+ # braces inside multi-dimensional arrays, but this is fine since
+ # that expression will not contain semicolons.
+ #
+ # 6. Block following another block:
+ # while (true) {}
+ # {};
+ #
+ # 7. End of namespaces:
+ # namespace {};
+ #
+ # These semicolons seems far more common than other kinds of
+ # redundant semicolons, possibly due to people converting classes
+ # to namespaces. For now we do not warn for this case.
+ #
+ # Try matching case 1 first.
+ match = Match(r'^(.*\)\s*)\{', line)
+ if match:
+ # Matched closing parenthesis (case 1). Check the token before the
+ # matching opening parenthesis, and don't warn if it looks like a
+ # macro. This avoids these false positives:
+ # - macro that defines a base class
+ # - multi-line macro that defines a base class
+ # - macro that defines the whole class-head
+ #
+ # But we still issue warnings for macros that we know are safe to
+ # warn, specifically:
+ # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P
+ # - TYPED_TEST
+ # - INTERFACE_DEF
+ # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
+ #
+ # We implement a whitelist of safe macros instead of a blacklist of
+ # unsafe macros, even though the latter appears less frequently in
+ # google code and would have been easier to implement. This is because
+ # the downside for getting the whitelist wrong means some extra
+ # semicolons, while the downside for getting the blacklist wrong
+ # would result in compile errors.
+ #
+ # In addition to macros, we also don't want to warn on
+ # - Compound literals
+ # - Lambdas
+ # - alignas specifier with anonymous structs
+ # - decltype
+ closing_brace_pos = match.group(1).rfind(')')
+ opening_parenthesis = ReverseCloseExpression(
+ clean_lines, linenum, closing_brace_pos)
+ if opening_parenthesis[2] > -1:
+ line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
+ macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix)
+ func = Match(r'^(.*\])\s*$', line_prefix)
+ if ((macro and
+ macro.group(1) not in (
+ 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
+ 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',
+ 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
+ (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or
+ Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or
+ Search(r'\bdecltype$', line_prefix) or
+ Search(r'\s+=\s*$', line_prefix)):
+ match = None
+ if (match and
+ opening_parenthesis[1] > 1 and
+ Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):
+ # Multi-line lambda-expression
+ match = None
+
+ else:
+ # Try matching cases 2-3.
+ match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)
+ if not match:
+ # Try matching cases 4-6. These are always matched on separate lines.
+ #
+ # Note that we can't simply concatenate the previous line to the
+ # current line and do a single match, otherwise we may output
+ # duplicate warnings for the blank line case:
+ # if (cond) {
+ # // blank line
+ # }
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if prevline and Search(r'[;{}]\s*$', prevline):
+ match = Match(r'^(\s*)\{', line)
+
+ # Check matching closing brace
+ if match:
+ (endline, endlinenum, endpos) = CloseExpression(
+ clean_lines, linenum, len(match.group(1)))
+ if endpos > -1 and Match(r'^\s*;', endline[endpos:]):
+ # Current {} pair is eligible for semicolon check, and we have found
+ # the redundant semicolon, output warning here.
+ #
+ # Note: because we are scanning forward for opening braces, and
+ # outputting warnings for the matching closing brace, if there are
+ # nested blocks with trailing semicolons, we will get the error
+ # messages in reversed order.
+
+ # We need to check the line forward for NOLINT
+ raw_lines = clean_lines.raw_lines
+ ParseNolintSuppressions(filename, raw_lines[endlinenum-1], endlinenum-1,
+ error)
+ ParseNolintSuppressions(filename, raw_lines[endlinenum], endlinenum,
+ error)
+
+ error(filename, endlinenum, 'readability/braces', 4,
+ "You don't need a ; after a }")
+
+
+def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
+ """Look for empty loop/conditional body with only a single semicolon.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Search for loop keywords at the beginning of the line. Because only
+ # whitespaces are allowed before the keywords, this will also ignore most
+ # do-while-loops, since those lines should start with closing brace.
+ #
+ # We also check "if" blocks here, since an empty conditional block
+ # is likely an error.
+ line = clean_lines.elided[linenum]
+ matched = Match(r'\s*(for|while|if)\s*\(', line)
+ if matched:
+ # Find the end of the conditional expression.
+ (end_line, end_linenum, end_pos) = CloseExpression(
+ clean_lines, linenum, line.find('('))
+
+ # Output warning if what follows the condition expression is a semicolon.
+ # No warning for all other cases, including whitespace or newline, since we
+ # have a separate check for semicolons preceded by whitespace.
+ if end_pos >= 0 and Match(r';', end_line[end_pos:]):
+ if matched.group(1) == 'if':
+ error(filename, end_linenum, 'whitespace/empty_conditional_body', 5,
+ 'Empty conditional bodies should use {}')
+ else:
+ error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
+ 'Empty loop bodies should use {} or continue')
+
+ # Check for if statements that have completely empty bodies (no comments)
+ # and no else clauses.
+ if end_pos >= 0 and matched.group(1) == 'if':
+ # Find the position of the opening { for the if statement.
+ # Return without logging an error if it has no brackets.
+ opening_linenum = end_linenum
+ opening_line_fragment = end_line[end_pos:]
+ # Loop until EOF or find anything that's not whitespace or opening {.
+ while not Search(r'^\s*\{', opening_line_fragment):
+ if Search(r'^(?!\s*$)', opening_line_fragment):
+ # Conditional has no brackets.
+ return
+ opening_linenum += 1
+ if opening_linenum == len(clean_lines.elided):
+ # Couldn't find conditional's opening { or any code before EOF.
+ return
+ opening_line_fragment = clean_lines.elided[opening_linenum]
+ # Set opening_line (opening_line_fragment may not be entire opening line).
+ opening_line = clean_lines.elided[opening_linenum]
+
+ # Find the position of the closing }.
+ opening_pos = opening_line_fragment.find('{')
+ if opening_linenum == end_linenum:
+ # We need to make opening_pos relative to the start of the entire line.
+ opening_pos += end_pos
+ (closing_line, closing_linenum, closing_pos) = CloseExpression(
+ clean_lines, opening_linenum, opening_pos)
+ if closing_pos < 0:
+ return
+
+ # Now construct the body of the conditional. This consists of the portion
+ # of the opening line after the {, all lines until the closing line,
+ # and the portion of the closing line before the }.
+ if (clean_lines.raw_lines[opening_linenum] !=
+ CleanseComments(clean_lines.raw_lines[opening_linenum])):
+ # Opening line ends with a comment, so conditional isn't empty.
+ return
+ if closing_linenum > opening_linenum:
+ # Opening line after the {. Ignore comments here since we checked above.
+ body = list(opening_line[opening_pos+1:])
+ # All lines until closing line, excluding closing line, with comments.
+ body.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum])
+ # Closing line before the }. Won't (and can't) have comments.
+ body.append(clean_lines.elided[closing_linenum][:closing_pos-1])
+ body = '\n'.join(body)
+ else:
+ # If statement has brackets and fits on a single line.
+ body = opening_line[opening_pos+1:closing_pos-1]
+
+ # Check if the body is empty
+ if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body):
+ return
+ # The body is empty. Now make sure there's not an else clause.
+ current_linenum = closing_linenum
+ current_line_fragment = closing_line[closing_pos:]
+ # Loop until EOF or find anything that's not whitespace or else clause.
+ while Search(r'^\s*$|^(?=\s*else)', current_line_fragment):
+ if Search(r'^(?=\s*else)', current_line_fragment):
+ # Found an else clause, so don't log an error.
+ return
+ current_linenum += 1
+ if current_linenum == len(clean_lines.elided):
+ break
+ current_line_fragment = clean_lines.elided[current_linenum]
+
+ # The body is empty and there's no else clause until EOF or other code.
+ error(filename, end_linenum, 'whitespace/empty_if_body', 4,
+ ('If statement had no body and no else clause'))
+
+
+def FindCheckMacro(line):
+ """Find a replaceable CHECK-like macro.
+
+ Args:
+ line: line to search on.
+ Returns:
+ (macro name, start position), or (None, -1) if no replaceable
+ macro is found.
+ """
+ for macro in _CHECK_MACROS:
+ i = line.find(macro)
+ if i >= 0:
+ # Find opening parenthesis. Do a regular expression match here
+ # to make sure that we are matching the expected CHECK macro, as
+ # opposed to some other macro that happens to contain the CHECK
+ # substring.
+ matched = Match(r'^(.*\b' + macro + r'\s*)\(', line)
+ if not matched:
+ continue
+ return (macro, len(matched.group(1)))
+ return (None, -1)
+
+
+def CheckCheck(filename, clean_lines, linenum, error):
+ """Checks the use of CHECK and EXPECT macros.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Decide the set of replacement macros that should be suggested
+ lines = clean_lines.elided
+ (check_macro, start_pos) = FindCheckMacro(lines[linenum])
+ if not check_macro:
+ return
+
+ # Find end of the boolean expression by matching parentheses
+ (last_line, end_line, end_pos) = CloseExpression(
+ clean_lines, linenum, start_pos)
+ if end_pos < 0:
+ return
+
+ # If the check macro is followed by something other than a
+ # semicolon, assume users will log their own custom error messages
+ # and don't suggest any replacements.
+ if not Match(r'\s*;', last_line[end_pos:]):
+ return
+
+ if linenum == end_line:
+ expression = lines[linenum][start_pos + 1:end_pos - 1]
+ else:
+ expression = lines[linenum][start_pos + 1:]
+ for i in xrange(linenum + 1, end_line):
+ expression += lines[i]
+ expression += last_line[0:end_pos - 1]
+
+ # Parse expression so that we can take parentheses into account.
+ # This avoids false positives for inputs like "CHECK((a < 4) == b)",
+ # which is not replaceable by CHECK_LE.
+ lhs = ''
+ rhs = ''
+ operator = None
+ while expression:
+ matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||'
+ r'==|!=|>=|>|<=|<|\()(.*)$', expression)
+ if matched:
+ token = matched.group(1)
+ if token == '(':
+ # Parenthesized operand
+ expression = matched.group(2)
+ (end, _) = FindEndOfExpressionInLine(expression, 0, ['('])
+ if end < 0:
+ return # Unmatched parenthesis
+ lhs += '(' + expression[0:end]
+ expression = expression[end:]
+ elif token in ('&&', '||'):
+ # Logical and/or operators. This means the expression
+ # contains more than one term, for example:
+ # CHECK(42 < a && a < b);
+ #
+ # These are not replaceable with CHECK_LE, so bail out early.
+ return
+ elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'):
+ # Non-relational operator
+ lhs += token
+ expression = matched.group(2)
+ else:
+ # Relational operator
+ operator = token
+ rhs = matched.group(2)
+ break
+ else:
+ # Unparenthesized operand. Instead of appending to lhs one character
+ # at a time, we do another regular expression match to consume several
+ # characters at once if possible. Trivial benchmark shows that this
+ # is more efficient when the operands are longer than a single
+ # character, which is generally the case.
+ matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression)
+ if not matched:
+ matched = Match(r'^(\s*\S)(.*)$', expression)
+ if not matched:
+ break
+ lhs += matched.group(1)
+ expression = matched.group(2)
+
+ # Only apply checks if we got all parts of the boolean expression
+ if not (lhs and operator and rhs):
+ return
+
+ # Check that rhs do not contain logical operators. We already know
+ # that lhs is fine since the loop above parses out && and ||.
+ if rhs.find('&&') > -1 or rhs.find('||') > -1:
+ return
+
+ # At least one of the operands must be a constant literal. This is
+ # to avoid suggesting replacements for unprintable things like
+ # CHECK(variable != iterator)
+ #
+ # The following pattern matches decimal, hex integers, strings, and
+ # characters (in that order).
+ lhs = lhs.strip()
+ rhs = rhs.strip()
+ match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$'
+ if Match(match_constant, lhs) or Match(match_constant, rhs):
+ # Note: since we know both lhs and rhs, we can provide a more
+ # descriptive error message like:
+ # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42)
+ # Instead of:
+ # Consider using CHECK_EQ instead of CHECK(a == b)
+ #
+ # We are still keeping the less descriptive message because if lhs
+ # or rhs gets long, the error message might become unreadable.
+ error(filename, linenum, 'readability/check', 2,
+ 'Consider using %s instead of %s(a %s b)' % (
+ _CHECK_REPLACEMENT[check_macro][operator],
+ check_macro, operator))
+
+
+def CheckAltTokens(filename, clean_lines, linenum, error):
+ """Check alternative keywords being used in boolean expressions.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Avoid preprocessor lines
+ if Match(r'^\s*#', line):
+ return
+
+ # Last ditch effort to avoid multi-line comments. This will not help
+ # if the comment started before the current line or ended after the
+ # current line, but it catches most of the false positives. At least,
+ # it provides a way to workaround this warning for people who use
+ # multi-line comments in preprocessor macros.
+ #
+ # TODO(unknown): remove this once cpplint has better support for
+ # multi-line comments.
+ if line.find('/*') >= 0 or line.find('*/') >= 0:
+ return
+
+ for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
+ error(filename, linenum, 'readability/alt_tokens', 2,
+ 'Use operator %s instead of %s' % (
+ _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
+
+
+def GetLineWidth(line):
+ """Determines the width of the line in column positions.
+
+ Args:
+ line: A string, which may be a Unicode string.
+
+ Returns:
+ The width of the line in column positions, accounting for Unicode
+ combining characters and wide characters.
+ """
+ if isinstance(line, unicode):
+ width = 0
+ for uc in unicodedata.normalize('NFC', line):
+ if unicodedata.east_asian_width(uc) in ('W', 'F'):
+ width += 2
+ elif not unicodedata.combining(uc):
+ width += 1
+ return width
+ else:
+ return len(line)
+
+
+def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
+ error):
+ """Checks rules from the 'C++ style rules' section of cppguide.html.
+
+ Most of these rules are hard to test (naming, comment style), but we
+ do what we can. In particular we check for 2-space indents, line lengths,
+ tab usage, spaces inside code, etc.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+
+ # Don't use "elided" lines here, otherwise we can't check commented lines.
+ # Don't want to use "raw" either, because we don't want to check inside C++11
+ # raw strings,
+ raw_lines = clean_lines.lines_without_raw_strings
+ line = raw_lines[linenum]
+ prev = raw_lines[linenum - 1] if linenum > 0 else ''
+
+ if line.find('\t') != -1:
+ error(filename, linenum, 'whitespace/tab', 1,
+ 'Tab found; better to use spaces')
+
+ # One or three blank spaces at the beginning of the line is weird; it's
+ # hard to reconcile that with 2-space indents.
+ # NOTE: here are the conditions rob pike used for his tests. Mine aren't
+ # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces
+ # if(RLENGTH > 20) complain = 0;
+ # if(match($0, " +(error|private|public|protected):")) complain = 0;
+ # if(match(prev, "&& *$")) complain = 0;
+ # if(match(prev, "\\|\\| *$")) complain = 0;
+ # if(match(prev, "[\",=><] *$")) complain = 0;
+ # if(match($0, " <<")) complain = 0;
+ # if(match(prev, " +for \\(")) complain = 0;
+ # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
+ scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$'
+ classinfo = nesting_state.InnermostClass()
+ initial_spaces = 0
+ cleansed_line = clean_lines.elided[linenum]
+ while initial_spaces < len(line) and line[initial_spaces] == ' ':
+ initial_spaces += 1
+ # There are certain situations we allow one space, notably for
+ # section labels, and also lines containing multi-line raw strings.
+ # We also don't check for lines that look like continuation lines
+ # (of lines ending in double quotes, commas, equals, or angle brackets)
+ # because the rules for how to indent those are non-trivial.
+ if (not Search(r'[",=><] *$', prev) and
+ (initial_spaces == 1 or initial_spaces == 3) and
+ not Match(scope_or_label_pattern, cleansed_line) and
+ not (clean_lines.raw_lines[linenum] != line and
+ Match(r'^\s*""', line))):
+ error(filename, linenum, 'whitespace/indent', 3,
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 2-space indent?')
+
+ if line and line[-1].isspace():
+ error(filename, linenum, 'whitespace/end_of_line', 4,
+ 'Line ends in whitespace. Consider deleting these extra spaces.')
+
+ # Check if the line is a header guard.
+ is_header_guard = False
+ if IsHeaderExtension(file_extension):
+ cppvar = GetHeaderGuardCPPVariable(filename)
+ if (line.startswith('#ifndef %s' % cppvar) or
+ line.startswith('#define %s' % cppvar) or
+ line.startswith('#endif // %s' % cppvar)):
+ is_header_guard = True
+ # #include lines and header guards can be long, since there's no clean way to
+ # split them.
+ #
+ # URLs can be long too. It's possible to split these, but it makes them
+ # harder to cut&paste.
+ #
+ # The "$Id:...$" comment may also get very long without it being the
+ # developers fault.
+ if (not line.startswith('#include') and not is_header_guard and
+ not Match(r'^\s*//.*http(s?)://\S*$', line) and
+ not Match(r'^\s*//\s*[^\s]*$', line) and
+ not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
+ line_width = GetLineWidth(line)
+ if line_width > _line_length:
+ error(filename, linenum, 'whitespace/line_length', 2,
+ 'Lines should be <= %i characters long' % _line_length)
+
+ if (cleansed_line.count(';') > 1 and
+ # for loops are allowed two ;'s (and may run over two lines).
+ cleansed_line.find('for') == -1 and
+ (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
+ GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
+ # It's ok to have many commands in a switch case that fits in 1 line
+ not ((cleansed_line.find('case ') != -1 or
+ cleansed_line.find('default:') != -1) and
+ cleansed_line.find('break;') != -1)):
+ error(filename, linenum, 'whitespace/newline', 0,
+ 'More than one command on the same line')
+
+ # Some more style checks
+ CheckBraces(filename, clean_lines, linenum, error)
+ CheckTrailingSemicolon(filename, clean_lines, linenum, error)
+ CheckEmptyBlockBody(filename, clean_lines, linenum, error)
+ CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
+ CheckOperatorSpacing(filename, clean_lines, linenum, error)
+ CheckParenthesisSpacing(filename, clean_lines, linenum, error)
+ CheckCommaSpacing(filename, clean_lines, linenum, error)
+ CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error)
+ CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
+ CheckCheck(filename, clean_lines, linenum, error)
+ CheckAltTokens(filename, clean_lines, linenum, error)
+ classinfo = nesting_state.InnermostClass()
+ if classinfo:
+ CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
+
+
+_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
+# Matches the first component of a filename delimited by -s and _s. That is:
+# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
+_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
+
+
+def _DropCommonSuffixes(filename):
+ """Drops common suffixes like _test.cc or -inl.h from filename.
+
+ For example:
+ >>> _DropCommonSuffixes('foo/foo-inl.h')
+ 'foo/foo'
+ >>> _DropCommonSuffixes('foo/bar/foo.cc')
+ 'foo/bar/foo'
+ >>> _DropCommonSuffixes('foo/foo_internal.h')
+ 'foo/foo'
+ >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
+ 'foo/foo_unusualinternal'
+
+ Args:
+ filename: The input filename.
+
+ Returns:
+ The filename with the common suffix removed.
+ """
+ for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
+ 'inl.h', 'impl.h', 'internal.h'):
+ if (filename.endswith(suffix) and len(filename) > len(suffix) and
+ filename[-len(suffix) - 1] in ('-', '_')):
+ return filename[:-len(suffix) - 1]
+ return os.path.splitext(filename)[0]
+
+
+def _ClassifyInclude(fileinfo, include, is_system):
+ """Figures out what kind of header 'include' is.
+
+ Args:
+ fileinfo: The current file cpplint is running over. A FileInfo instance.
+ include: The path to a #included file.
+ is_system: True if the #include used <> rather than "".
+
+ Returns:
+ One of the _XXX_HEADER constants.
+
+ For example:
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
+ _C_SYS_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
+ _CPP_SYS_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
+ _LIKELY_MY_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
+ ... 'bar/foo_other_ext.h', False)
+ _POSSIBLE_MY_HEADER
+ >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
+ _OTHER_HEADER
+ """
+ # This is a list of all standard c++ header files, except
+ # those already checked for above.
+ is_cpp_h = include in _CPP_HEADERS
+
+ if is_system:
+ if is_cpp_h:
+ return _CPP_SYS_HEADER
+ else:
+ return _C_SYS_HEADER
+
+ # If the target file and the include we're checking share a
+ # basename when we drop common extensions, and the include
+ # lives in . , then it's likely to be owned by the target file.
+ target_dir, target_base = (
+ os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
+ include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
+ if target_base == include_base and (
+ include_dir == target_dir or
+ include_dir == os.path.normpath(target_dir + '/../public')):
+ return _LIKELY_MY_HEADER
+
+ # If the target and include share some initial basename
+ # component, it's possible the target is implementing the
+ # include, so it's allowed to be first, but we'll never
+ # complain if it's not there.
+ target_first_component = _RE_FIRST_COMPONENT.match(target_base)
+ include_first_component = _RE_FIRST_COMPONENT.match(include_base)
+ if (target_first_component and include_first_component and
+ target_first_component.group(0) ==
+ include_first_component.group(0)):
+ return _POSSIBLE_MY_HEADER
+
+ return _OTHER_HEADER
+
+
+
+def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
+ """Check rules that are applicable to #include lines.
+
+ Strings on #include lines are NOT removed from elided line, to make
+ certain tasks easier. However, to prevent false positives, checks
+ applicable to #include lines in CheckLanguage must be put here.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ error: The function to call with any errors found.
+ """
+ fileinfo = FileInfo(filename)
+ line = clean_lines.lines[linenum]
+
+ # "include" should use the new style "foo/bar.h" instead of just "bar.h"
+ # Only do this check if the included header follows google naming
+ # conventions. If not, assume that it's a 3rd party API that
+ # requires special include conventions.
+ #
+ # We also make an exception for Lua headers, which follow google
+ # naming convention but not the include convention.
+ match = Match(r'#include\s*"([^/]+\.h)"', line)
+ if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)):
+ error(filename, linenum, 'build/include', 4,
+ 'Include the directory when naming .h files')
+
+ # we shouldn't include a file more than once. actually, there are a
+ # handful of instances where doing so is okay, but in general it's
+ # not.
+ match = _RE_PATTERN_INCLUDE.search(line)
+ if match:
+ include = match.group(2)
+ is_system = (match.group(1) == '<')
+ duplicate_line = include_state.FindHeader(include)
+ if duplicate_line >= 0:
+ error(filename, linenum, 'build/include', 4,
+ '"%s" already included at %s:%s' %
+ (include, filename, duplicate_line))
+ elif (include.endswith('.cc') and
+ os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)):
+ error(filename, linenum, 'build/include', 4,
+ 'Do not include .cc files from other packages')
+ elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
+ include_state.include_list[-1].append((include, linenum))
+
+ # We want to ensure that headers appear in the right order:
+ # 1) for foo.cc, foo.h (preferred location)
+ # 2) c system files
+ # 3) cpp system files
+ # 4) for foo.cc, foo.h (deprecated location)
+ # 5) other google headers
+ #
+ # We classify each include statement as one of those 5 types
+ # using a number of techniques. The include_state object keeps
+ # track of the highest type seen, and complains if we see a
+ # lower type after that.
+ error_message = include_state.CheckNextIncludeOrder(
+ _ClassifyInclude(fileinfo, include, is_system))
+ if error_message:
+ error(filename, linenum, 'build/include_order', 4,
+ '%s. Should be: %s.h, c system, c++ system, other.' %
+ (error_message, fileinfo.BaseName()))
+ canonical_include = include_state.CanonicalizeAlphabeticalOrder(include)
+ if not include_state.IsInAlphabeticalOrder(
+ clean_lines, linenum, canonical_include):
+ error(filename, linenum, 'build/include_alpha', 4,
+ 'Include "%s" not in alphabetical order' % include)
+ include_state.SetLastHeader(canonical_include)
+
+
+
+def _GetTextInside(text, start_pattern):
+ r"""Retrieves all the text between matching open and close parentheses.
+
+ Given a string of lines and a regular expression string, retrieve all the text
+ following the expression and between opening punctuation symbols like
+ (, [, or {, and the matching close-punctuation symbol. This properly nested
+ occurrences of the punctuations, so for the text like
+ printf(a(), b(c()));
+ a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
+ start_pattern must match string having an open punctuation symbol at the end.
+
+ Args:
+ text: The lines to extract text. Its comments and strings must be elided.
+ It can be single line and can span multiple lines.
+ start_pattern: The regexp string indicating where to start extracting
+ the text.
+ Returns:
+ The extracted text.
+ None if either the opening string or ending punctuation could not be found.
+ """
+ # TODO(unknown): Audit cpplint.py to see what places could be profitably
+ # rewritten to use _GetTextInside (and use inferior regexp matching today).
+
+ # Give opening punctuations to get the matching close-punctuations.
+ matching_punctuation = {'(': ')', '{': '}', '[': ']'}
+ closing_punctuation = set(matching_punctuation.itervalues())
+
+ # Find the position to start extracting text.
+ match = re.search(start_pattern, text, re.M)
+ if not match: # start_pattern not found in text.
+ return None
+ start_position = match.end(0)
+
+ assert start_position > 0, (
+ 'start_pattern must ends with an opening punctuation.')
+ assert text[start_position - 1] in matching_punctuation, (
+ 'start_pattern must ends with an opening punctuation.')
+ # Stack of closing punctuations we expect to have in text after position.
+ punctuation_stack = [matching_punctuation[text[start_position - 1]]]
+ position = start_position
+ while punctuation_stack and position < len(text):
+ if text[position] == punctuation_stack[-1]:
+ punctuation_stack.pop()
+ elif text[position] in closing_punctuation:
+ # A closing punctuation without matching opening punctuations.
+ return None
+ elif text[position] in matching_punctuation:
+ punctuation_stack.append(matching_punctuation[text[position]])
+ position += 1
+ if punctuation_stack:
+ # Opening punctuations left without matching close-punctuations.
+ return None
+ # punctuations match.
+ return text[start_position:position - 1]
+
+
+# Patterns for matching call-by-reference parameters.
+#
+# Supports nested templates up to 2 levels deep using this messy pattern:
+# < (?: < (?: < [^<>]*
+# >
+# | [^<>] )*
+# >
+# | [^<>] )*
+# >
+_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]*
+_RE_PATTERN_TYPE = (
+ r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?'
+ r'(?:\w|'
+ r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|'
+ r'::)+')
+# A call-by-reference parameter ends with '& identifier'.
+_RE_PATTERN_REF_PARAM = re.compile(
+ r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*'
+ r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]')
+# A call-by-const-reference parameter either ends with 'const& identifier'
+# or looks like 'const type& identifier' when 'type' is atomic.
+_RE_PATTERN_CONST_REF_PARAM = (
+ r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +
+ r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')
+# Stream types.
+_RE_PATTERN_REF_STREAM_PARAM = (
+ r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')')
+
+
+def CheckLanguage(filename, clean_lines, linenum, file_extension,
+ include_state, nesting_state, error):
+ """Checks rules from the 'C++ language rules' section of cppguide.html.
+
+ Some of these rules are hard to test (function overloading, using
+ uint32 inappropriately), but we do the best we can.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+ # If the line is empty or consists of entirely a comment, no need to
+ # check it.
+ line = clean_lines.elided[linenum]
+ if not line:
+ return
+
+ match = _RE_PATTERN_INCLUDE.search(line)
+ if match:
+ CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
+ return
+
+ # Reset include state across preprocessor directives. This is meant
+ # to silence warnings for conditional includes.
+ match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line)
+ if match:
+ include_state.ResetSection(match.group(1))
+
+ # Make Windows paths like Unix.
+ fullname = os.path.abspath(filename).replace('\\', '/')
+
+ # Perform other checks now that we are sure that this is not an include line
+ CheckCasts(filename, clean_lines, linenum, error)
+ CheckGlobalStatic(filename, clean_lines, linenum, error)
+ CheckPrintf(filename, clean_lines, linenum, error)
+
+ if IsHeaderExtension(file_extension):
+ # TODO(unknown): check that 1-arg constructors are explicit.
+ # How to tell it's a constructor?
+ # (handled in CheckForNonStandardConstructs for now)
+ # TODO(unknown): check that classes declare or disable copy/assign
+ # (level 1 error)
+ pass
+
+ # Check if people are using the verboten C basic types. The only exception
+ # we regularly allow is "unsigned short port" for port.
+ if Search(r'\bshort port\b', line):
+ if not Search(r'\bunsigned short port\b', line):
+ error(filename, linenum, 'runtime/int', 4,
+ 'Use "unsigned short" for ports, not "short"')
+ else:
+ match = Search(r'\b(short|long(?! +double)|long long)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/int', 4,
+ 'Use int16/int64/etc, rather than the C type %s' % match.group(1))
+
+ # Check if some verboten operator overloading is going on
+ # TODO(unknown): catch out-of-line unary operator&:
+ # class X {};
+ # int operator&(const X& x) { return 42; } // unary operator&
+ # The trick is it's hard to tell apart from binary operator&:
+ # class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
+ if Search(r'\boperator\s*&\s*\(\s*\)', line):
+ error(filename, linenum, 'runtime/operator', 4,
+ 'Unary operator& is dangerous. Do not use it.')
+
+ # Check for suspicious usage of "if" like
+ # } if (a == b) {
+ if Search(r'\}\s*if\s*\(', line):
+ error(filename, linenum, 'readability/braces', 4,
+ 'Did you mean "else if"? If not, start a new line for "if".')
+
+ # Check for potential format string bugs like printf(foo).
+ # We constrain the pattern not to pick things like DocidForPrintf(foo).
+ # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
+ # TODO(unknown): Catch the following case. Need to change the calling
+ # convention of the whole function to process multiple line to handle it.
+ # printf(
+ # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
+ printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
+ if printf_args:
+ match = Match(r'([\w.\->()]+)$', printf_args)
+ if match and match.group(1) != '__VA_ARGS__':
+ function_name = re.search(r'\b((?:string)?printf)\s*\(',
+ line, re.I).group(1)
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Potential format string bug. Do %s("%%s", %s) instead.'
+ % (function_name, match.group(1)))
+
+ # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
+ match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
+ if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
+ error(filename, linenum, 'runtime/memset', 4,
+ 'Did you mean "memset(%s, 0, %s)"?'
+ % (match.group(1), match.group(2)))
+
+ if Search(r'\busing namespace\b', line):
+ error(filename, linenum, 'build/namespaces', 5,
+ 'Do not use namespace using-directives. '
+ 'Use using-declarations instead.')
+
+ # Detect variable-length arrays.
+ match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
+ if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
+ match.group(3).find(']') == -1):
+ # Split the size using space and arithmetic operators as delimiters.
+ # If any of the resulting tokens are not compile time constants then
+ # report the error.
+ tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
+ is_const = True
+ skip_next = False
+ for tok in tokens:
+ if skip_next:
+ skip_next = False
+ continue
+
+ if Search(r'sizeof\(.+\)', tok): continue
+ if Search(r'arraysize\(\w+\)', tok): continue
+
+ tok = tok.lstrip('(')
+ tok = tok.rstrip(')')
+ if not tok: continue
+ if Match(r'\d+', tok): continue
+ if Match(r'0[xX][0-9a-fA-F]+', tok): continue
+ if Match(r'k[A-Z0-9]\w*', tok): continue
+ if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
+ if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
+ # A catch all for tricky sizeof cases, including 'sizeof expression',
+ # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
+ # requires skipping the next token because we split on ' ' and '*'.
+ if tok.startswith('sizeof'):
+ skip_next = True
+ continue
+ is_const = False
+ break
+ if not is_const:
+ error(filename, linenum, 'runtime/arrays', 1,
+ 'Do not use variable-length arrays. Use an appropriately named '
+ "('k' followed by CamelCase) compile-time constant for the size.")
+
+ # Check for use of unnamed namespaces in header files. Registration
+ # macros are typically OK, so we allow use of "namespace {" on lines
+ # that end with backslashes.
+ if (IsHeaderExtension(file_extension)
+ and Search(r'\bnamespace\s*{', line)
+ and line[-1] != '\\'):
+ error(filename, linenum, 'build/namespaces', 4,
+ 'Do not use unnamed namespaces in header files. See '
+ 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+ ' for more information.')
+
+
+def CheckGlobalStatic(filename, clean_lines, linenum, error):
+ """Check for unsafe global or static objects.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Match two lines at a time to support multiline declarations
+ if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line):
+ line += clean_lines.elided[linenum + 1].strip()
+
+ # Check for people declaring static/global STL strings at the top level.
+ # This is dangerous because the C++ language does not guarantee that
+ # globals with constructors are initialized before the first access, and
+ # also because globals can be destroyed when some threads are still running.
+ # TODO(unknown): Generalize this to also find static unique_ptr instances.
+ # TODO(unknown): File bugs for clang-tidy to find these.
+ match = Match(
+ r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +'
+ r'([a-zA-Z0-9_:]+)\b(.*)',
+ line)
+
+ # Remove false positives:
+ # - String pointers (as opposed to values).
+ # string *pointer
+ # const string *pointer
+ # string const *pointer
+ # string *const pointer
+ #
+ # - Functions and template specializations.
+ # string Function<Type>(...
+ # string Class<Type>::Method(...
+ #
+ # - Operators. These are matched separately because operator names
+ # cross non-word boundaries, and trying to match both operators
+ # and functions at the same time would decrease accuracy of
+ # matching identifiers.
+ # string Class::operator*()
+ if (match and
+ not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and
+ not Search(r'\boperator\W', line) and
+ not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))):
+ if Search(r'\bconst\b', line):
+ error(filename, linenum, 'runtime/string', 4,
+ 'For a static/global string constant, use a C style string '
+ 'instead: "%schar%s %s[]".' %
+ (match.group(1), match.group(2) or '', match.group(3)))
+ else:
+ error(filename, linenum, 'runtime/string', 4,
+ 'Static/global string variables are not permitted.')
+
+ if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or
+ Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)):
+ error(filename, linenum, 'runtime/init', 4,
+ 'You seem to be initializing a member variable with itself.')
+
+
+def CheckPrintf(filename, clean_lines, linenum, error):
+ """Check for printf related issues.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # When snprintf is used, the second argument shouldn't be a literal.
+ match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
+ if match and match.group(2) != '0':
+ # If 2nd arg is zero, snprintf is used to calculate size.
+ error(filename, linenum, 'runtime/printf', 3,
+ 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
+ 'to snprintf.' % (match.group(1), match.group(2)))
+
+ # Check if some verboten C functions are being used.
+ if Search(r'\bsprintf\s*\(', line):
+ error(filename, linenum, 'runtime/printf', 5,
+ 'Never use sprintf. Use snprintf instead.')
+ match = Search(r'\b(strcpy|strcat)\s*\(', line)
+ if match:
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Almost always, snprintf is better than %s' % match.group(1))
+
+
+def IsDerivedFunction(clean_lines, linenum):
+ """Check if current line contains an inherited function.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ Returns:
+ True if current line contains a function with "override"
+ virt-specifier.
+ """
+ # Scan back a few lines for start of current function
+ for i in xrange(linenum, max(-1, linenum - 10), -1):
+ match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])
+ if match:
+ # Look for "override" after the matching closing parenthesis
+ line, _, closing_paren = CloseExpression(
+ clean_lines, i, len(match.group(1)))
+ return (closing_paren >= 0 and
+ Search(r'\boverride\b', line[closing_paren:]))
+ return False
+
+
+def IsOutOfLineMethodDefinition(clean_lines, linenum):
+ """Check if current line contains an out-of-line method definition.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ Returns:
+ True if current line contains an out-of-line method definition.
+ """
+ # Scan back a few lines for start of current function
+ for i in xrange(linenum, max(-1, linenum - 10), -1):
+ if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):
+ return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None
+ return False
+
+
+def IsInitializerList(clean_lines, linenum):
+ """Check if current line is inside constructor initializer list.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ Returns:
+ True if current line appears to be inside constructor initializer
+ list, False otherwise.
+ """
+ for i in xrange(linenum, 1, -1):
+ line = clean_lines.elided[i]
+ if i == linenum:
+ remove_function_body = Match(r'^(.*)\{\s*$', line)
+ if remove_function_body:
+ line = remove_function_body.group(1)
+
+ if Search(r'\s:\s*\w+[({]', line):
+ # A lone colon tend to indicate the start of a constructor
+ # initializer list. It could also be a ternary operator, which
+ # also tend to appear in constructor initializer lists as
+ # opposed to parameter lists.
+ return True
+ if Search(r'\}\s*,\s*$', line):
+ # A closing brace followed by a comma is probably the end of a
+ # brace-initialized member in constructor initializer list.
+ return True
+ if Search(r'[{};]\s*$', line):
+ # Found one of the following:
+ # - A closing brace or semicolon, probably the end of the previous
+ # function.
+ # - An opening brace, probably the start of current class or namespace.
+ #
+ # Current line is probably not inside an initializer list since
+ # we saw one of those things without seeing the starting colon.
+ return False
+
+ # Got to the beginning of the file without seeing the start of
+ # constructor initializer list.
+ return False
+
+
+def CheckForNonConstReference(filename, clean_lines, linenum,
+ nesting_state, error):
+ """Check for non-const references.
+
+ Separate from CheckLanguage since it scans backwards from current
+ line, instead of scanning forward.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: The function to call with any errors found.
+ """
+ # Do nothing if there is no '&' on current line.
+ line = clean_lines.elided[linenum]
+ if '&' not in line:
+ return
+
+ # If a function is inherited, current function doesn't have much of
+ # a choice, so any non-const references should not be blamed on
+ # derived function.
+ if IsDerivedFunction(clean_lines, linenum):
+ return
+
+ # Don't warn on out-of-line method definitions, as we would warn on the
+ # in-line declaration, if it isn't marked with 'override'.
+ if IsOutOfLineMethodDefinition(clean_lines, linenum):
+ return
+
+ # Long type names may be broken across multiple lines, usually in one
+ # of these forms:
+ # LongType
+ # ::LongTypeContinued &identifier
+ # LongType::
+ # LongTypeContinued &identifier
+ # LongType<
+ # ...>::LongTypeContinued &identifier
+ #
+ # If we detected a type split across two lines, join the previous
+ # line to current line so that we can match const references
+ # accordingly.
+ #
+ # Note that this only scans back one line, since scanning back
+ # arbitrary number of lines would be expensive. If you have a type
+ # that spans more than 2 lines, please use a typedef.
+ if linenum > 1:
+ previous = None
+ if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line):
+ # previous_line\n + ::current_line
+ previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$',
+ clean_lines.elided[linenum - 1])
+ elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line):
+ # previous_line::\n + current_line
+ previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$',
+ clean_lines.elided[linenum - 1])
+ if previous:
+ line = previous.group(1) + line.lstrip()
+ else:
+ # Check for templated parameter that is split across multiple lines
+ endpos = line.rfind('>')
+ if endpos > -1:
+ (_, startline, startpos) = ReverseCloseExpression(
+ clean_lines, linenum, endpos)
+ if startpos > -1 and startline < linenum:
+ # Found the matching < on an earlier line, collect all
+ # pieces up to current line.
+ line = ''
+ for i in xrange(startline, linenum + 1):
+ line += clean_lines.elided[i].strip()
+
+ # Check for non-const references in function parameters. A single '&' may
+ # found in the following places:
+ # inside expression: binary & for bitwise AND
+ # inside expression: unary & for taking the address of something
+ # inside declarators: reference parameter
+ # We will exclude the first two cases by checking that we are not inside a
+ # function body, including one that was just introduced by a trailing '{'.
+ # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].
+ if (nesting_state.previous_stack_top and
+ not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or
+ isinstance(nesting_state.previous_stack_top, _NamespaceInfo))):
+ # Not at toplevel, not within a class, and not within a namespace
+ return
+
+ # Avoid initializer lists. We only need to scan back from the
+ # current line for something that starts with ':'.
+ #
+ # We don't need to check the current line, since the '&' would
+ # appear inside the second set of parentheses on the current line as
+ # opposed to the first set.
+ if linenum > 0:
+ for i in xrange(linenum - 1, max(0, linenum - 10), -1):
+ previous_line = clean_lines.elided[i]
+ if not Search(r'[),]\s*$', previous_line):
+ break
+ if Match(r'^\s*:\s+\S', previous_line):
+ return
+
+ # Avoid preprocessors
+ if Search(r'\\\s*$', line):
+ return
+
+ # Avoid constructor initializer lists
+ if IsInitializerList(clean_lines, linenum):
+ return
+
+ # We allow non-const references in a few standard places, like functions
+ # called "swap()" or iostream operators like "<<" or ">>". Do not check
+ # those function parameters.
+ #
+ # We also accept & in static_assert, which looks like a function but
+ # it's actually a declaration expression.
+ whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
+ r'operator\s*[<>][<>]|'
+ r'static_assert|COMPILE_ASSERT'
+ r')\s*\(')
+ if Search(whitelisted_functions, line):
+ return
+ elif not Search(r'\S+\([^)]*$', line):
+ # Don't see a whitelisted function on this line. Actually we
+ # didn't see any function name on this line, so this is likely a
+ # multi-line parameter list. Try a bit harder to catch this case.
+ for i in xrange(2):
+ if (linenum > i and
+ Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
+ return
+
+ decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body
+ for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
+ if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and
+ not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)):
+ error(filename, linenum, 'runtime/references', 2,
+ 'Is this a non-const reference? '
+ 'If so, make const or use a pointer: ' +
+ ReplaceAll(' *<', '<', parameter))
+
+
+def CheckCasts(filename, clean_lines, linenum, error):
+ """Various cast related checks.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ # Check to see if they're using an conversion function cast.
+ # I just try to capture the most common basic types, though there are more.
+ # Parameterless conversion functions, such as bool(), are allowed as they are
+ # probably a member operator declaration or default constructor.
+ match = Search(
+ r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b'
+ r'(int|float|double|bool|char|int32|uint32|int64|uint64)'
+ r'(\([^)].*)', line)
+ expecting_function = ExpectingFunctionArgs(clean_lines, linenum)
+ if match and not expecting_function:
+ matched_type = match.group(2)
+
+ # matched_new_or_template is used to silence two false positives:
+ # - New operators
+ # - Template arguments with function types
+ #
+ # For template arguments, we match on types immediately following
+ # an opening bracket without any spaces. This is a fast way to
+ # silence the common case where the function type is the first
+ # template argument. False negative with less-than comparison is
+ # avoided because those operators are usually followed by a space.
+ #
+ # function<double(double)> // bracket + no space = false positive
+ # value < double(42) // bracket + space = true positive
+ matched_new_or_template = match.group(1)
+
+ # Avoid arrays by looking for brackets that come after the closing
+ # parenthesis.
+ if Match(r'\([^()]+\)\s*\[', match.group(3)):
+ return
+
+ # Other things to ignore:
+ # - Function pointers
+ # - Casts to pointer types
+ # - Placement new
+ # - Alias declarations
+ matched_funcptr = match.group(3)
+ if (matched_new_or_template is None and
+ not (matched_funcptr and
+ (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(',
+ matched_funcptr) or
+ matched_funcptr.startswith('(*)'))) and
+ not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and
+ not Search(r'new\(\S+\)\s*' + matched_type, line)):
+ error(filename, linenum, 'readability/casting', 4,
+ 'Using deprecated casting style. '
+ 'Use static_cast<%s>(...) instead' %
+ matched_type)
+
+ if not expecting_function:
+ CheckCStyleCast(filename, clean_lines, linenum, 'static_cast',
+ r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
+
+ # This doesn't catch all cases. Consider (const char * const)"hello".
+ #
+ # (char *) "foo" should always be a const_cast (reinterpret_cast won't
+ # compile).
+ if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast',
+ r'\((char\s?\*+\s?)\)\s*"', error):
+ pass
+ else:
+ # Check pointer casts for other than string constants
+ CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast',
+ r'\((\w+\s?\*+\s?)\)', error)
+
+ # In addition, we look for people taking the address of a cast. This
+ # is dangerous -- casts can assign to temporaries, so the pointer doesn't
+ # point where you think.
+ #
+ # Some non-identifier character is required before the '&' for the
+ # expression to be recognized as a cast. These are casts:
+ # expression = &static_cast<int*>(temporary());
+ # function(&(int*)(temporary()));
+ #
+ # This is not a cast:
+ # reference_type&(int* function_param);
+ match = Search(
+ r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'
+ r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line)
+ if match:
+ # Try a better error message when the & is bound to something
+ # dereferenced by the casted pointer, as opposed to the casted
+ # pointer itself.
+ parenthesis_error = False
+ match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line)
+ if match:
+ _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1)))
+ if x1 >= 0 and clean_lines.elided[y1][x1] == '(':
+ _, y2, x2 = CloseExpression(clean_lines, y1, x1)
+ if x2 >= 0:
+ extended_line = clean_lines.elided[y2][x2:]
+ if y2 < clean_lines.NumLines() - 1:
+ extended_line += clean_lines.elided[y2 + 1]
+ if Match(r'\s*(?:->|\[)', extended_line):
+ parenthesis_error = True
+
+ if parenthesis_error:
+ error(filename, linenum, 'readability/casting', 4,
+ ('Are you taking an address of something dereferenced '
+ 'from a cast? Wrapping the dereferenced expression in '
+ 'parentheses will make the binding more obvious'))
+ else:
+ error(filename, linenum, 'runtime/casting', 4,
+ ('Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'))
+
+
+def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):
+ """Checks for a C-style cast by looking for the pattern.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ cast_type: The string for the C++ cast to recommend. This is either
+ reinterpret_cast, static_cast, or const_cast, depending.
+ pattern: The regular expression used to find C-style casts.
+ error: The function to call with any errors found.
+
+ Returns:
+ True if an error was emitted.
+ False otherwise.
+ """
+ line = clean_lines.elided[linenum]
+ match = Search(pattern, line)
+ if not match:
+ return False
+
+ # Exclude lines with keywords that tend to look like casts
+ context = line[0:match.start(1) - 1]
+ if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context):
+ return False
+
+ # Try expanding current context to see if we one level of
+ # parentheses inside a macro.
+ if linenum > 0:
+ for i in xrange(linenum - 1, max(0, linenum - 5), -1):
+ context = clean_lines.elided[i] + context
+ if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context):
+ return False
+
+ # operator++(int) and operator--(int)
+ if context.endswith(' operator++') or context.endswith(' operator--'):
+ return False
+
+ # A single unnamed argument for a function tends to look like old style cast.
+ # If we see those, don't issue warnings for deprecated casts.
+ remainder = line[match.end(0):]
+ if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)',
+ remainder):
+ return False
+
+ # At this point, all that should be left is actual casts.
+ error(filename, linenum, 'readability/casting', 4,
+ 'Using C-style cast. Use %s<%s>(...) instead' %
+ (cast_type, match.group(1)))
+
+ return True
+
+
+def ExpectingFunctionArgs(clean_lines, linenum):
+ """Checks whether where function type arguments are expected.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+
+ Returns:
+ True if the line at 'linenum' is inside something that expects arguments
+ of function types.
+ """
+ line = clean_lines.elided[linenum]
+ return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
+ (linenum >= 2 and
+ (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$',
+ clean_lines.elided[linenum - 1]) or
+ Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$',
+ clean_lines.elided[linenum - 2]) or
+ Search(r'\bstd::m?function\s*\<\s*$',
+ clean_lines.elided[linenum - 1]))))
+
+
+_HEADERS_CONTAINING_TEMPLATES = (
+ ('<deque>', ('deque',)),
+ ('<functional>', ('unary_function', 'binary_function',
+ 'plus', 'minus', 'multiplies', 'divides', 'modulus',
+ 'negate',
+ 'equal_to', 'not_equal_to', 'greater', 'less',
+ 'greater_equal', 'less_equal',
+ 'logical_and', 'logical_or', 'logical_not',
+ 'unary_negate', 'not1', 'binary_negate', 'not2',
+ 'bind1st', 'bind2nd',
+ 'pointer_to_unary_function',
+ 'pointer_to_binary_function',
+ 'ptr_fun',
+ 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
+ 'mem_fun_ref_t',
+ 'const_mem_fun_t', 'const_mem_fun1_t',
+ 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
+ 'mem_fun_ref',
+ )),
+ ('<limits>', ('numeric_limits',)),
+ ('<list>', ('list',)),
+ ('<map>', ('map', 'multimap',)),
+ ('<memory>', ('allocator', 'make_shared', 'make_unique', 'shared_ptr',
+ 'unique_ptr', 'weak_ptr')),
+ ('<queue>', ('queue', 'priority_queue',)),
+ ('<set>', ('set', 'multiset',)),
+ ('<stack>', ('stack',)),
+ ('<string>', ('char_traits', 'basic_string',)),
+ ('<tuple>', ('tuple',)),
+ ('<unordered_map>', ('unordered_map', 'unordered_multimap')),
+ ('<unordered_set>', ('unordered_set', 'unordered_multiset')),
+ ('<utility>', ('pair',)),
+ ('<vector>', ('vector',)),
+
+ # gcc extensions.
+ # Note: std::hash is their hash, ::hash is our hash
+ ('<hash_map>', ('hash_map', 'hash_multimap',)),
+ ('<hash_set>', ('hash_set', 'hash_multiset',)),
+ ('<slist>', ('slist',)),
+ )
+
+_HEADERS_MAYBE_TEMPLATES = (
+ ('<algorithm>', ('copy', 'max', 'min', 'min_element', 'sort',
+ 'transform',
+ )),
+ ('<utility>', ('forward', 'make_pair', 'move', 'swap')),
+ )
+
+_RE_PATTERN_STRING = re.compile(r'\bstring\b')
+
+_re_pattern_headers_maybe_templates = []
+for _header, _templates in _HEADERS_MAYBE_TEMPLATES:
+ for _template in _templates:
+ # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
+ # type::max().
+ _re_pattern_headers_maybe_templates.append(
+ (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
+ _template,
+ _header))
+
+# Other scripts may reach in and modify this pattern.
+_re_pattern_templates = []
+for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
+ for _template in _templates:
+ _re_pattern_templates.append(
+ (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
+ _template + '<>',
+ _header))
+
+
+def FilesBelongToSameModule(filename_cc, filename_h):
+ """Check if these two filenames belong to the same module.
+
+ The concept of a 'module' here is a as follows:
+ foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
+ same 'module' if they are in the same directory.
+ some/path/public/xyzzy and some/path/internal/xyzzy are also considered
+ to belong to the same module here.
+
+ If the filename_cc contains a longer path than the filename_h, for example,
+ '/absolute/path/to/base/sysinfo.cc', and this file would include
+ 'base/sysinfo.h', this function also produces the prefix needed to open the
+ header. This is used by the caller of this function to more robustly open the
+ header file. We don't have access to the real include paths in this context,
+ so we need this guesswork here.
+
+ Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
+ according to this implementation. Because of this, this function gives
+ some false positives. This should be sufficiently rare in practice.
+
+ Args:
+ filename_cc: is the path for the .cc file
+ filename_h: is the path for the header path
+
+ Returns:
+ Tuple with a bool and a string:
+ bool: True if filename_cc and filename_h belong to the same module.
+ string: the additional prefix needed to open the header file.
+ """
+
+ fileinfo = FileInfo(filename_cc)
+ if not fileinfo.IsSource():
+ return (False, '')
+ filename_cc = filename_cc[:-len(fileinfo.Extension())]
+ matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo.BaseName())
+ if matched_test_suffix:
+ filename_cc = filename_cc[:-len(matched_test_suffix.group(1))]
+ filename_cc = filename_cc.replace('/public/', '/')
+ filename_cc = filename_cc.replace('/internal/', '/')
+
+ if not filename_h.endswith('.h'):
+ return (False, '')
+ filename_h = filename_h[:-len('.h')]
+ if filename_h.endswith('-inl'):
+ filename_h = filename_h[:-len('-inl')]
+ filename_h = filename_h.replace('/public/', '/')
+ filename_h = filename_h.replace('/internal/', '/')
+
+ files_belong_to_same_module = filename_cc.endswith(filename_h)
+ common_path = ''
+ if files_belong_to_same_module:
+ common_path = filename_cc[:-len(filename_h)]
+ return files_belong_to_same_module, common_path
+
+
+def UpdateIncludeState(filename, include_dict, io=codecs):
+ """Fill up the include_dict with new includes found from the file.
+
+ Args:
+ filename: the name of the header to read.
+ include_dict: a dictionary in which the headers are inserted.
+ io: The io factory to use to read the file. Provided for testability.
+
+ Returns:
+ True if a header was successfully added. False otherwise.
+ """
+ headerfile = None
+ try:
+ headerfile = io.open(filename, 'r', 'utf8', 'replace')
+ except IOError:
+ return False
+ linenum = 0
+ for line in headerfile:
+ linenum += 1
+ clean_line = CleanseComments(line)
+ match = _RE_PATTERN_INCLUDE.search(clean_line)
+ if match:
+ include = match.group(2)
+ include_dict.setdefault(include, linenum)
+ return True
+
+
+def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
+ io=codecs):
+ """Reports for missing stl includes.
+
+ This function will output warnings to make sure you are including the headers
+ necessary for the stl containers and functions that you use. We only give one
+ reason to include a header. For example, if you use both equal_to<> and
+ less<> in a .h file, only one (the latter in the file) of these will be
+ reported as a reason to include the <functional>.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ include_state: An _IncludeState instance.
+ error: The function to call with any errors found.
+ io: The IO factory to use to read the header file. Provided for unittest
+ injection.
+ """
+ required = {} # A map of header name to linenumber and the template entity.
+ # Example of required: { '<functional>': (1219, 'less<>') }
+
+ for linenum in xrange(clean_lines.NumLines()):
+ line = clean_lines.elided[linenum]
+ if not line or line[0] == '#':
+ continue
+
+ # String is special -- it is a non-templatized type in STL.
+ matched = _RE_PATTERN_STRING.search(line)
+ if matched:
+ # Don't warn about strings in non-STL namespaces:
+ # (We check only the first match per line; good enough.)
+ prefix = line[:matched.start()]
+ if prefix.endswith('std::') or not prefix.endswith('::'):
+ required['<string>'] = (linenum, 'string')
+
+ for pattern, template, header in _re_pattern_headers_maybe_templates:
+ if pattern.search(line):
+ required[header] = (linenum, template)
+
+ # The following function is just a speed up, no semantics are changed.
+ if not '<' in line: # Reduces the cpu time usage by skipping lines.
+ continue
+
+ for pattern, template, header in _re_pattern_templates:
+ matched = pattern.search(line)
+ if matched:
+ # Don't warn about IWYU in non-STL namespaces:
+ # (We check only the first match per line; good enough.)
+ prefix = line[:matched.start()]
+ if prefix.endswith('std::') or not prefix.endswith('::'):
+ required[header] = (linenum, template)
+
+ # The policy is that if you #include something in foo.h you don't need to
+ # include it again in foo.cc. Here, we will look at possible includes.
+ # Let's flatten the include_state include_list and copy it into a dictionary.
+ include_dict = dict([item for sublist in include_state.include_list
+ for item in sublist])
+
+ # Did we find the header for this file (if any) and successfully load it?
+ header_found = False
+
+ # Use the absolute path so that matching works properly.
+ abs_filename = FileInfo(filename).FullName()
+
+ # For Emacs's flymake.
+ # If cpplint is invoked from Emacs's flymake, a temporary file is generated
+ # by flymake and that file name might end with '_flymake.cc'. In that case,
+ # restore original file name here so that the corresponding header file can be
+ # found.
+ # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
+ # instead of 'foo_flymake.h'
+ abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
+
+ # include_dict is modified during iteration, so we iterate over a copy of
+ # the keys.
+ header_keys = include_dict.keys()
+ for header in header_keys:
+ (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
+ fullpath = common_path + header
+ if same_module and UpdateIncludeState(fullpath, include_dict, io):
+ header_found = True
+
+ # If we can't find the header file for a .cc, assume it's because we don't
+ # know where to look. In that case we'll give up as we're not sure they
+ # didn't include it in the .h file.
+ # TODO(unknown): Do a better job of finding .h files so we are confident that
+ # not having the .h file means there isn't one.
+ if filename.endswith('.cc') and not header_found:
+ return
+
+ # All the lines have been processed, report the errors found.
+ for required_header_unstripped in required:
+ template = required[required_header_unstripped][1]
+ if required_header_unstripped.strip('<>"') not in include_dict:
+ error(filename, required[required_header_unstripped][0],
+ 'build/include_what_you_use', 4,
+ 'Add #include ' + required_header_unstripped + ' for ' + template)
+
+
+_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
+
+
+def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
+ """Check that make_pair's template arguments are deduced.
+
+ G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are
+ specified explicitly, and such use isn't intended in any case.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+ match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
+ if match:
+ error(filename, linenum, 'build/explicit_make_pair',
+ 4, # 4 = high confidence
+ 'For C++11-compatibility, omit template arguments from make_pair'
+ ' OR use pair directly OR if appropriate, construct a pair directly')
+
+
+def CheckRedundantVirtual(filename, clean_lines, linenum, error):
+ """Check if line contains a redundant "virtual" function-specifier.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ # Look for "virtual" on current line.
+ line = clean_lines.elided[linenum]
+ virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line)
+ if not virtual: return
+
+ # Ignore "virtual" keywords that are near access-specifiers. These
+ # are only used in class base-specifier and do not apply to member
+ # functions.
+ if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or
+ Match(r'^\s+(public|protected|private)\b', virtual.group(3))):
+ return
+
+ # Ignore the "virtual" keyword from virtual base classes. Usually
+ # there is a column on the same line in these cases (virtual base
+ # classes are rare in google3 because multiple inheritance is rare).
+ if Match(r'^.*[^:]:[^:].*$', line): return
+
+ # Look for the next opening parenthesis. This is the start of the
+ # parameter list (possibly on the next line shortly after virtual).
+ # TODO(unknown): doesn't work if there are virtual functions with
+ # decltype() or other things that use parentheses, but csearch suggests
+ # that this is rare.
+ end_col = -1
+ end_line = -1
+ start_col = len(virtual.group(2))
+ for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())):
+ line = clean_lines.elided[start_line][start_col:]
+ parameter_list = Match(r'^([^(]*)\(', line)
+ if parameter_list:
+ # Match parentheses to find the end of the parameter list
+ (_, end_line, end_col) = CloseExpression(
+ clean_lines, start_line, start_col + len(parameter_list.group(1)))
+ break
+ start_col = 0
+
+ if end_col < 0:
+ return # Couldn't find end of parameter list, give up
+
+ # Look for "override" or "final" after the parameter list
+ # (possibly on the next few lines).
+ for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())):
+ line = clean_lines.elided[i][end_col:]
+ match = Search(r'\b(override|final)\b', line)
+ if match:
+ error(filename, linenum, 'readability/inheritance', 4,
+ ('"virtual" is redundant since function is '
+ 'already declared as "%s"' % match.group(1)))
+
+ # Set end_col to check whole lines after we are done with the
+ # first line.
+ end_col = 0
+ if Search(r'[^\w]\s*$', line):
+ break
+
+
+def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error):
+ """Check if line contains a redundant "override" or "final" virt-specifier.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ # Look for closing parenthesis nearby. We need one to confirm where
+ # the declarator ends and where the virt-specifier starts to avoid
+ # false positives.
+ line = clean_lines.elided[linenum]
+ declarator_end = line.rfind(')')
+ if declarator_end >= 0:
+ fragment = line[declarator_end:]
+ else:
+ if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0:
+ fragment = line
+ else:
+ return
+
+ # Check that at most one of "override" or "final" is present, not both
+ if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment):
+ error(filename, linenum, 'readability/inheritance', 4,
+ ('"override" is redundant since function is '
+ 'already declared as "final"'))
+
+
+
+
+# Returns true if we are at a new block, and it is directly
+# inside of a namespace.
+def IsBlockInNameSpace(nesting_state, is_forward_declaration):
+ """Checks that the new block is directly in a namespace.
+
+ Args:
+ nesting_state: The _NestingState object that contains info about our state.
+ is_forward_declaration: If the class is a forward declared class.
+ Returns:
+ Whether or not the new block is directly in a namespace.
+ """
+ if is_forward_declaration:
+ if len(nesting_state.stack) >= 1 and (
+ isinstance(nesting_state.stack[-1], _NamespaceInfo)):
+ return True
+ else:
+ return False
+
+ return (len(nesting_state.stack) > 1 and
+ nesting_state.stack[-1].check_namespace_indentation and
+ isinstance(nesting_state.stack[-2], _NamespaceInfo))
+
+
+def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
+ raw_lines_no_comments, linenum):
+ """This method determines if we should apply our namespace indentation check.
+
+ Args:
+ nesting_state: The current nesting state.
+ is_namespace_indent_item: If we just put a new class on the stack, True.
+ If the top of the stack is not a class, or we did not recently
+ add the class, False.
+ raw_lines_no_comments: The lines without the comments.
+ linenum: The current line number we are processing.
+
+ Returns:
+ True if we should apply our namespace indentation check. Currently, it
+ only works for classes and namespaces inside of a namespace.
+ """
+
+ is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments,
+ linenum)
+
+ if not (is_namespace_indent_item or is_forward_declaration):
+ return False
+
+ # If we are in a macro, we do not want to check the namespace indentation.
+ if IsMacroDefinition(raw_lines_no_comments, linenum):
+ return False
+
+ return IsBlockInNameSpace(nesting_state, is_forward_declaration)
+
+
+# Call this method if the line is directly inside of a namespace.
+# If the line above is blank (excluding comments) or the start of
+# an inner namespace, it cannot be indented.
+def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum,
+ error):
+ line = raw_lines_no_comments[linenum]
+ if Match(r'^\s+', line):
+ error(filename, linenum, 'runtime/indentation_namespace', 4,
+ 'Do not indent within a namespace')
+
+
+def ProcessLine(filename, file_extension, clean_lines, line,
+ include_state, function_state, nesting_state, error,
+ extra_check_functions=[]):
+ """Processes a single line in the file.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ clean_lines: An array of strings, each representing a line of the file,
+ with comments stripped.
+ line: Number of line being processed.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ function_state: A _FunctionState instance which counts function lines, etc.
+ nesting_state: A NestingState instance which maintains information about
+ the current stack of nested blocks being parsed.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+ raw_lines = clean_lines.raw_lines
+ ParseNolintSuppressions(filename, raw_lines[line], line, error)
+ nesting_state.Update(filename, clean_lines, line, error)
+ CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
+ error)
+ if nesting_state.InAsmBlock(): return
+ CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
+ CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
+ CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
+ CheckLanguage(filename, clean_lines, line, file_extension, include_state,
+ nesting_state, error)
+ CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
+ CheckForNonStandardConstructs(filename, clean_lines, line,
+ nesting_state, error)
+ CheckVlogArguments(filename, clean_lines, line, error)
+ CheckPosixThreading(filename, clean_lines, line, error)
+ CheckInvalidIncrement(filename, clean_lines, line, error)
+ CheckMakePairUsesDeduction(filename, clean_lines, line, error)
+ CheckRedundantVirtual(filename, clean_lines, line, error)
+ CheckRedundantOverrideOrFinal(filename, clean_lines, line, error)
+ for check_fn in extra_check_functions:
+ check_fn(filename, clean_lines, line, error)
+
+def FlagCxx11Features(filename, clean_lines, linenum, error):
+ """Flag those c++11 features that we only allow in certain places.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
+
+ # Flag unapproved C++ TR1 headers.
+ if include and include.group(1).startswith('tr1/'):
+ error(filename, linenum, 'build/c++tr1', 5,
+ ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1))
+
+ # Flag unapproved C++11 headers.
+ if include and include.group(1) in ('cfenv',
+ 'condition_variable',
+ 'fenv.h',
+ 'future',
+ 'mutex',
+ 'thread',
+ 'chrono',
+ 'ratio',
+ 'regex',
+ 'system_error',
+ ):
+ error(filename, linenum, 'build/c++11', 5,
+ ('<%s> is an unapproved C++11 header.') % include.group(1))
+
+ # The only place where we need to worry about C++11 keywords and library
+ # features in preprocessor directives is in macro definitions.
+ if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return
+
+ # These are classes and free functions. The classes are always
+ # mentioned as std::*, but we only catch the free functions if
+ # they're not found by ADL. They're alphabetical by header.
+ for top_name in (
+ # type_traits
+ 'alignment_of',
+ 'aligned_union',
+ ):
+ if Search(r'\bstd::%s\b' % top_name, line):
+ error(filename, linenum, 'build/c++11', 5,
+ ('std::%s is an unapproved C++11 class or function. Send c-style '
+ 'an example of where it would make your code more readable, and '
+ 'they may let you use it.') % top_name)
+
+
+def FlagCxx14Features(filename, clean_lines, linenum, error):
+ """Flag those C++14 features that we restrict.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ linenum: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[linenum]
+
+ include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
+
+ # Flag unapproved C++14 headers.
+ if include and include.group(1) in ('scoped_allocator', 'shared_mutex'):
+ error(filename, linenum, 'build/c++14', 5,
+ ('<%s> is an unapproved C++14 header.') % include.group(1))
+
+
+def ProcessFileData(filename, file_extension, lines, error,
+ extra_check_functions=[]):
+ """Performs lint checks and reports any errors to the given error function.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ lines: An array of strings, each representing a line of the file, with the
+ last element being empty if the file is terminated with a newline.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ filename, line number, error level, and message
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+ lines = (['// marker so line numbers and indices both start at 1'] + lines +
+ ['// marker so line numbers end in a known way'])
+
+ include_state = _IncludeState()
+ function_state = _FunctionState()
+ nesting_state = NestingState()
+
+ ResetNolintSuppressions()
+
+ CheckForCopyright(filename, lines, error)
+ ProcessGlobalSuppresions(lines)
+ RemoveMultiLineComments(filename, lines, error)
+ clean_lines = CleansedLines(lines)
+
+ if IsHeaderExtension(file_extension):
+ CheckForHeaderGuard(filename, clean_lines, error)
+
+ for line in xrange(clean_lines.NumLines()):
+ ProcessLine(filename, file_extension, clean_lines, line,
+ include_state, function_state, nesting_state, error,
+ extra_check_functions)
+ FlagCxx11Features(filename, clean_lines, line, error)
+ nesting_state.CheckCompletedBlocks(filename, error)
+
+ CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
+
+ # Check that the .cc file has included its header if it exists.
+ if _IsSourceExtension(file_extension):
+ CheckHeaderFileIncluded(filename, include_state, error)
+
+ # We check here rather than inside ProcessLine so that we see raw
+ # lines rather than "cleaned" lines.
+ CheckForBadCharacters(filename, lines, error)
+
+ CheckForNewlineAtEOF(filename, lines, error)
+
+def ProcessConfigOverrides(filename):
+ """ Loads the configuration files and processes the config overrides.
+
+ Args:
+ filename: The name of the file being processed by the linter.
+
+ Returns:
+ False if the current |filename| should not be processed further.
+ """
+
+ abs_filename = os.path.abspath(filename)
+ cfg_filters = []
+ keep_looking = True
+ while keep_looking:
+ abs_path, base_name = os.path.split(abs_filename)
+ if not base_name:
+ break # Reached the root directory.
+
+ cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
+ abs_filename = abs_path
+ if not os.path.isfile(cfg_file):
+ continue
+
+ try:
+ with open(cfg_file) as file_handle:
+ for line in file_handle:
+ line, _, _ = line.partition('#') # Remove comments.
+ if not line.strip():
+ continue
+
+ name, _, val = line.partition('=')
+ name = name.strip()
+ val = val.strip()
+ if name == 'set noparent':
+ keep_looking = False
+ elif name == 'filter':
+ cfg_filters.append(val)
+ elif name == 'exclude_files':
+ # When matching exclude_files pattern, use the base_name of
+ # the current file name or the directory name we are processing.
+ # For example, if we are checking for lint errors in /foo/bar/baz.cc
+ # and we found the .cfg file at /foo/CPPLINT.cfg, then the config
+ # file's "exclude_files" filter is meant to be checked against "bar"
+ # and not "baz" nor "bar/baz.cc".
+ if base_name:
+ pattern = re.compile(val)
+ if pattern.match(base_name):
+ if _cpplint_state.quiet:
+ # Suppress "Ignoring file" warning when using --quiet.
+ return False
+ sys.stderr.write('Ignoring "%s": file excluded by "%s". '
+ 'File path component "%s" matches '
+ 'pattern "%s"\n' %
+ (filename, cfg_file, base_name, val))
+ return False
+ elif name == 'linelength':
+ global _line_length
+ try:
+ _line_length = int(val)
+ except ValueError:
+ sys.stderr.write('Line length must be numeric.')
+ elif name == 'root':
+ global _root
+ # root directories are specified relative to CPPLINT.cfg dir.
+ _root = os.path.join(os.path.dirname(cfg_file), val)
+ elif name == 'headers':
+ ProcessHppHeadersOption(val)
+ else:
+ sys.stderr.write(
+ 'Invalid configuration option (%s) in file %s\n' %
+ (name, cfg_file))
+
+ except IOError:
+ sys.stderr.write(
+ "Skipping config file '%s': Can't open for reading\n" % cfg_file)
+ keep_looking = False
+
+ # Apply all the accumulated filters in reverse order (top-level directory
+ # config options having the least priority).
+ for filter in reversed(cfg_filters):
+ _AddFilters(filter)
+
+ return True
+
+
+def ProcessFile(filename, vlevel, extra_check_functions=[]):
+ """Does google-lint on a single file.
+
+ Args:
+ filename: The name of the file to parse.
+
+ vlevel: The level of errors to report. Every error of confidence
+ >= verbose_level will be reported. 0 is a good default.
+
+ extra_check_functions: An array of additional check functions that will be
+ run on each source line. Each function takes 4
+ arguments: filename, clean_lines, line, error
+ """
+
+ _SetVerboseLevel(vlevel)
+ _BackupFilters()
+ old_errors = _cpplint_state.error_count
+
+ if not ProcessConfigOverrides(filename):
+ _RestoreFilters()
+ return
+
+ lf_lines = []
+ crlf_lines = []
+ try:
+ # Support the UNIX convention of using "-" for stdin. Note that
+ # we are not opening the file with universal newline support
+ # (which codecs doesn't support anyway), so the resulting lines do
+ # contain trailing '\r' characters if we are reading a file that
+ # has CRLF endings.
+ # If after the split a trailing '\r' is present, it is removed
+ # below.
+ if filename == '-':
+ lines = codecs.StreamReaderWriter(sys.stdin,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace').read().split('\n')
+ else:
+ lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+
+ # Remove trailing '\r'.
+ # The -1 accounts for the extra trailing blank line we get from split()
+ for linenum in range(len(lines) - 1):
+ if lines[linenum].endswith('\r'):
+ lines[linenum] = lines[linenum].rstrip('\r')
+ crlf_lines.append(linenum + 1)
+ else:
+ lf_lines.append(linenum + 1)
+
+ except IOError:
+ sys.stderr.write(
+ "Skipping input '%s': Can't open for reading\n" % filename)
+ _RestoreFilters()
+ return
+
+ # Note, if no dot is found, this will give the entire filename as the ext.
+ file_extension = filename[filename.rfind('.') + 1:]
+
+ # When reading from stdin, the extension is unknown, so no cpplint tests
+ # should rely on the extension.
+ if filename != '-' and file_extension not in _valid_extensions:
+ sys.stderr.write('Ignoring %s; not a valid file name '
+ '(%s)\n' % (filename, ', '.join(_valid_extensions)))
+ else:
+ ProcessFileData(filename, file_extension, lines, Error,
+ extra_check_functions)
+
+ # If end-of-line sequences are a mix of LF and CR-LF, issue
+ # warnings on the lines with CR.
+ #
+ # Don't issue any warnings if all lines are uniformly LF or CR-LF,
+ # since critique can handle these just fine, and the style guide
+ # doesn't dictate a particular end of line sequence.
+ #
+ # We can't depend on os.linesep to determine what the desired
+ # end-of-line sequence should be, since that will return the
+ # server-side end-of-line sequence.
+ if lf_lines and crlf_lines:
+ # Warn on every line with CR. An alternative approach might be to
+ # check whether the file is mostly CRLF or just LF, and warn on the
+ # minority, we bias toward LF here since most tools prefer LF.
+ for linenum in crlf_lines:
+ Error(filename, linenum, 'whitespace/newline', 1,
+ 'Unexpected \\r (^M) found; better to use only \\n')
+
+ # Suppress printing anything if --quiet was passed unless the error
+ # count has increased after processing this file.
+ if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count:
+ sys.stdout.write('Done processing %s\n' % filename)
+ _RestoreFilters()
+
+
+def PrintUsage(message):
+ """Prints a brief usage string and exits, optionally with an error message.
+
+ Args:
+ message: The optional error message.
+ """
+ sys.stderr.write(_USAGE)
+ if message:
+ sys.exit('\nFATAL ERROR: ' + message)
+ else:
+ sys.exit(1)
+
+
+def PrintCategories():
+ """Prints a list of all the error-categories used by error messages.
+
+ These are the categories used to filter messages via --filter.
+ """
+ sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
+ sys.exit(0)
+
+
+def ParseArguments(args):
+ """Parses the command line arguments.
+
+ This may set the output format and verbosity level as side-effects.
+
+ Args:
+ args: The command line arguments:
+
+ Returns:
+ The list of filenames to lint.
+ """
+ try:
+ (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
+ 'counting=',
+ 'filter=',
+ 'root=',
+ 'linelength=',
+ 'extensions=',
+ 'headers=',
+ 'quiet'])
+ except getopt.GetoptError:
+ PrintUsage('Invalid arguments.')
+
+ verbosity = _VerboseLevel()
+ output_format = _OutputFormat()
+ filters = ''
+ quiet = _Quiet()
+ counting_style = ''
+
+ for (opt, val) in opts:
+ if opt == '--help':
+ PrintUsage(None)
+ elif opt == '--output':
+ if val not in ('emacs', 'vs7', 'eclipse'):
+ PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
+ output_format = val
+ elif opt == '--quiet':
+ quiet = True
+ elif opt == '--verbose':
+ verbosity = int(val)
+ elif opt == '--filter':
+ filters = val
+ if not filters:
+ PrintCategories()
+ elif opt == '--counting':
+ if val not in ('total', 'toplevel', 'detailed'):
+ PrintUsage('Valid counting options are total, toplevel, and detailed')
+ counting_style = val
+ elif opt == '--root':
+ global _root
+ _root = val
+ elif opt == '--linelength':
+ global _line_length
+ try:
+ _line_length = int(val)
+ except ValueError:
+ PrintUsage('Line length must be digits.')
+ elif opt == '--extensions':
+ global _valid_extensions
+ try:
+ _valid_extensions = set(val.split(','))
+ except ValueError:
+ PrintUsage('Extensions must be comma seperated list.')
+ elif opt == '--headers':
+ ProcessHppHeadersOption(val)
+
+ if not filenames:
+ PrintUsage('No files were specified.')
+
+ _SetOutputFormat(output_format)
+ _SetQuiet(quiet)
+ _SetVerboseLevel(verbosity)
+ _SetFilters(filters)
+ _SetCountingStyle(counting_style)
+
+ return filenames
+
+
+def main():
+ filenames = ParseArguments(sys.argv[1:])
+
+ # Change stderr to write with replacement characters so we don't die
+ # if we try to print something containing non-ASCII characters.
+ sys.stderr = codecs.StreamReaderWriter(sys.stderr,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace')
+
+ _cpplint_state.ResetErrorCounts()
+ for filename in filenames:
+ ProcessFile(filename, _cpplint_state.verbose_level)
+ # If --quiet is passed, suppress printing error count unless there are errors.
+ if not _cpplint_state.quiet or _cpplint_state.error_count > 0:
+ _cpplint_state.PrintErrorCounts()
+
+ sys.exit(_cpplint_state.error_count > 0)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/lint.sh b/scripts/lint.sh
new file mode 100755
index 0000000..442f7f8
--- /dev/null
+++ b/scripts/lint.sh
@@ -0,0 +1,18 @@
+# Copyright 2018 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.
+
+find Firestore/core \( \
+ -name \*.h -o \
+ -name \*.cc \) -print0 \
+ | xargs -0 python scripts/cpplint.py --quiet
diff --git a/scripts/style.sh b/scripts/style.sh
index 494a937..1b41b13 100755
--- a/scripts/style.sh
+++ b/scripts/style.sh
@@ -21,13 +21,27 @@
# Commonly
# ./scripts/style.sh master
-set -euo pipefail
+if [[ $(clang-format --version) != **"version 6"** ]]; then
+ echo "Please upgrade to clang-format version 6."
+ echo "If it's installed via homebrew you can run: brew upgrade clang-format"
+ exit 1
+fi
+if [[ $# -gt 0 && "$1" = "test-only" ]]; then
+ test_only=true
+ options="-output-replacements-xml"
+ shift
+else
+ test_only=false
+ options="-i"
+fi
+
+files=$(
(
if [[ $# -gt 0 ]]; then
if git rev-parse "$1" -- >& /dev/null; then
# Argument was a branch name show files changed since that branch
- git diff --name-only --relative
+ git diff --name-only --relative --diff-filter=ACMR "$1"
else
# Otherwise assume the passed things are files or directories
find "$@" -type f
@@ -45,6 +59,12 @@ set -euo pipefail
\%/third_party/% d
\%/Firestore/Port/% d
+# Generated source
+\%/Firestore/core/src/firebase/firestore/util/config.h% d
+
+# Sources pulled in by travis bundler
+\%/vendor/bundle/% d
+
# Sources within the tree that are not subject to formatting
\%^./(Example|Firebase)/(Auth|AuthSamples|Database|Messaging)/% d
@@ -53,4 +73,19 @@ set -euo pipefail
# Format C-ish sources only
\%\.(h|m|mm|cc)$% p
-' | xargs clang-format -style=file -i
+'
+)
+needs_formatting=false
+for f in $files; do
+ clang-format -style=file $options $f | grep "<replacement " > /dev/null
+ if [[ "$test_only" = true && $? -ne 1 ]]; then
+ echo "$f needs formatting."
+ needs_formatting=true
+ fi
+done
+
+if [[ "$needs_formatting" = true ]]; then
+ echo "Proposed commit is not style compliant."
+ echo "Run scripts/style.sh and git add the result."
+ exit 1
+fi
diff --git a/test.sh b/test.sh
index 627fbad..ee3be7c 100755
--- a/test.sh
+++ b/test.sh
@@ -18,7 +18,7 @@ test_iOS() {
-workspace Example/Firebase.xcworkspace \
-scheme AllUnitTests_iOS \
-sdk iphonesimulator \
- -destination 'platform=iOS Simulator,OS=10.3.1,name=iPhone 7' \
+ -destination 'platform=iOS Simulator,name=iPhone 7' \
build \
test \
ONLY_ACTIVE_ARCH=YES \
@@ -39,6 +39,19 @@ test_macOS() {
| xcpretty
}
+test_tvOS() {
+ xcodebuild \
+ -workspace Example/Firebase.xcworkspace \
+ -scheme AllUnitTests_tvOS \
+ -sdk appletvsimulator \
+ -destination 'platform=tvOS Simulator,name=Apple TV' \
+ build \
+ test \
+ ONLY_ACTIVE_ARCH=YES \
+ CODE_SIGNING_REQUIRED=NO \
+ | xcpretty
+}
+
test_iOS; RESULT=$?
if [ $RESULT != 0 ]; then exit $RESULT; fi
@@ -54,5 +67,6 @@ fi
if [ $RESULT != 0 ]; then exit $RESULT; fi
-# Also test Firestore
-Firestore/test.sh
+test_tvOS; RESULT=$?
+
+if [ $RESULT != 0 ]; then exit $RESULT; fi