diff options
90 files changed, 2194 insertions, 1195 deletions
diff --git a/Firebase/Messaging/CHANGELOG.md b/Firebase/Messaging/CHANGELOG.md index 78dc8d9..22b5031 100644 --- a/Firebase/Messaging/CHANGELOG.md +++ b/Firebase/Messaging/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2018-05-29 -- v3.0.1 +- Clean up a few deprecation warnings. + # 2018-05-08 -- v3.0.0 - Remove deprecated delegate property `remoteMessageDelegate`, please use `delegate` instead. - Remove deprecated method `messaging:didRefreshRegistrationToken:` defined in FIRMessagingDelegate protocol, please use `messaging:didReceiveRegistrationToken:` instead. diff --git a/Firebase/Messaging/FIRMMessageCode.h b/Firebase/Messaging/FIRMMessageCode.h index c1b8ffb..0d7e027 100644 --- a/Firebase/Messaging/FIRMMessageCode.h +++ b/Firebase/Messaging/FIRMMessageCode.h @@ -45,6 +45,7 @@ typedef NS_ENUM(NSInteger, FIRMessagingMessageCode) { kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenDelete = 2021, // I-FCM002021 kFIRMessagingMessageCodeAPNSTokenNotAvailableDuringTokenFetch = 2022, // I-FCM002022 kFIRMessagingMessageCodeTokenDelegateMethodsNotImplemented = 2023, // I-FCM002023 + kFIRMessagingMessageCodeTopicFormatIsDeprecated = 2024, // FIRMessagingClient.m kFIRMessagingMessageCodeClient000 = 4000, // I-FCM004000 kFIRMessagingMessageCodeClient001 = 4001, // I-FCM004001 diff --git a/Firebase/Messaging/FIRMessaging.m b/Firebase/Messaging/FIRMessaging.m index 3c1c730..3c4d999 100644 --- a/Firebase/Messaging/FIRMessaging.m +++ b/Firebase/Messaging/FIRMessaging.m @@ -421,10 +421,7 @@ NSString *const kFIRMessagingPlistAutoInitEnabled = openURL:url sourceApplication:FIRMessagingAppIdentifier() annotation:@{}]; -#pragma clang diagnostic pop } else if ([appDelegate respondsToSelector:handleOpenURLSelector]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" [appDelegate application:application handleOpenURL:url]; #pragma clang diagnostic pop } @@ -700,6 +697,11 @@ NSString *const kFIRMessagingPlistAutoInitEnabled = completion:(nullable FIRMessagingTopicOperationCompletion)completion { if (self.defaultFcmToken.length && topic.length) { NSString *normalizeTopic = [[self class ] normalizeTopic:topic]; + if ([FIRMessagingPubSub hasTopicsPrefix:topic]) { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated, + @"Format '%@' is deprecated. Only '%@' should be used in " + @"subscribeToTopic.", topic, normalizeTopic); + } if (normalizeTopic.length) { [self.pubsub subscribeToTopic:normalizeTopic handler:completion]; } else { @@ -721,6 +723,11 @@ NSString *const kFIRMessagingPlistAutoInitEnabled = completion:(nullable FIRMessagingTopicOperationCompletion)completion { if (self.defaultFcmToken.length && topic.length) { NSString *normalizeTopic = [[self class] normalizeTopic:topic]; + if ([FIRMessagingPubSub hasTopicsPrefix:topic]) { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated, + @"Format '%@' is deprecated. Only '%@' should be used in " + @"unsubscribeFromTopic.", topic, normalizeTopic); + } if (normalizeTopic.length) { [self.pubsub unsubscribeFromTopic:normalizeTopic handler:completion]; } else { diff --git a/Firebase/Messaging/FIRMessagingContextManagerService.m b/Firebase/Messaging/FIRMessagingContextManagerService.m index c7be606..f79e79c 100644 --- a/Firebase/Messaging/FIRMessagingContextManagerService.m +++ b/Firebase/Messaging/FIRMessagingContextManagerService.m @@ -172,8 +172,10 @@ typedef NS_ENUM(NSUInteger, FIRMessagingContextManagerMessageType) { if (userInfo.count) { notification.userInfo = userInfo; } - +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [[UIApplication sharedApplication] scheduleLocalNotification:notification]; +#pragma clang diagnostic pop } + (NSDictionary *)parseDataFromMessage:(NSDictionary *)message { diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index fd6d9ba..ca8b598 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -43,7 +43,6 @@ 5492E03420213FFC00B64F25 /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; }; 5492E03520213FFC00B64F25 /* FSTSpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E03020213FFC00B64F25 /* FSTSpecTests.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 */; }; @@ -148,6 +147,7 @@ 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; 7346E61D20325C6900FD6CEF /* FSTDispatchQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */; }; 73866AA12082B0A5009BB4FF /* FIRArrayTransformTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 73866A9F2082B069009BB4FF /* FIRArrayTransformTests.mm */; }; + 73FE5066020EF9B2892C86BF /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; }; 8C82D4D3F9AB63E79CC52DC8 /* Pods_Firestore_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECEBABC7E7B693BE808A1052 /* Pods_Firestore_IntegrationTests_iOS.framework */; }; AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB356EF6200EA5EB0089B766 /* field_value_test.cc */; }; @@ -256,6 +256,7 @@ 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = "<group>"; }; 3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; }; 3F0992A4B83C60841C52E960 /* Pods-Firestore_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.release.xcconfig"; sourceTree = "<group>"; }; + 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = hard_assert_test.cc; sourceTree = "<group>"; }; 54131E9620ADE678001DF3FF /* string_format_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_format_test.cc; sourceTree = "<group>"; }; 54511E8D209805F8005BD28F /* hashing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashing_test.cc; sourceTree = "<group>"; }; 5467FAFF203E56F8009C9584 /* FIRFirestoreTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRFirestoreTests.mm; sourceTree = "<group>"; }; @@ -273,7 +274,6 @@ 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>"; }; 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>"; }; @@ -468,9 +468,9 @@ buildActionMask = 2147483647; files = ( 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, - 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, C8D3CE2343E53223E6487F2C /* Pods_Firestore_Example_iOS.framework in Frameworks */, + 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -478,10 +478,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, - 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, 5D405BE298CE4692CB00790A /* Pods_Firestore_Tests_iOS.framework in Frameworks */, + 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, + 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -489,10 +489,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */, - DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */, DE03B2D61F2149D600A30B9C /* Foundation.framework in Frameworks */, 8C82D4D3F9AB63E79CC52DC8 /* Pods_Firestore_IntegrationTests_iOS.framework in Frameworks */, + DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */, + DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -549,14 +549,14 @@ B6FB4687208F9B9100554BA2 /* executor_std_test.cc */, B6FB4688208F9B9100554BA2 /* executor_test.cc */, B6FB468A208F9B9100554BA2 /* executor_test.h */, - 54131E9820AE076C001DF3FF /* hard_assert_test.cc */, + 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */, 54511E8D209805F8005BD28F /* hashing_test.cc */, 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */, 54C2294E1FECABAE007D065B /* log_test.cc */, AB380D03201BC6E400D97691 /* ordered_code_test.cc */, 54740A531FC913E500713A1A /* secure_random_test.cc */, - 54A0352B20A3B3D7003E0143 /* status_test_util.h */, 54A0352C20A3B3D7003E0143 /* status_test.cc */, + 54A0352B20A3B3D7003E0143 /* status_test_util.h */, 54A0352D20A3B3D7003E0143 /* statusor_test.cc */, 54131E9620ADE678001DF3FF /* string_format_test.cc */, AB380CFC201A2EE200D97691 /* string_util_test.cc */, @@ -640,10 +640,10 @@ isa = PBXGroup; children = ( 6003F58A195388D20070C39A /* Firestore_Example_iOS.app */, - 6003F5AE195388D20070C39A /* Firestore_Tests_iOS.xctest */, DE03B2E91F2149D600A30B9C /* Firestore_IntegrationTests_iOS.xctest */, - DE0761E41F2FE611003233AF /* SwiftBuildTest.app */, 54C9EDF12040E16300A969CD /* Firestore_SwiftTests_iOS.xctest */, + 6003F5AE195388D20070C39A /* Firestore_Tests_iOS.xctest */, + DE0761E41F2FE611003233AF /* SwiftBuildTest.app */, ); name = Products; sourceTree = "<group>"; @@ -651,15 +651,15 @@ 6003F58C195388D20070C39A /* Frameworks */ = { isa = PBXGroup; children = ( - 6003F58D195388D20070C39A /* Foundation.framework */, 6003F58F195388D20070C39A /* CoreGraphics.framework */, - 6003F591195388D20070C39A /* UIKit.framework */, - 6003F5AF195388D20070C39A /* XCTest.framework */, + 6003F58D195388D20070C39A /* Foundation.framework */, 5918805E993304321A05E82B /* Pods_Firestore_Example_iOS.framework */, BB92EB03E3F92485023F64ED /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework */, 379B34A1536045869826D82A /* Pods_Firestore_Example_iOS_SwiftBuildTest.framework */, ECEBABC7E7B693BE808A1052 /* Pods_Firestore_IntegrationTests_iOS.framework */, 2B50B3A0DF77100EEE887891 /* Pods_Firestore_Tests_iOS.framework */, + 6003F591195388D20070C39A /* UIKit.framework */, + 6003F5AF195388D20070C39A /* XCTest.framework */, ); name = Frameworks; sourceTree = "<group>"; @@ -667,14 +667,14 @@ 6003F593195388D20070C39A /* iOS */ = { isa = PBXGroup; children = ( + 6003F594195388D20070C39A /* Supporting Files */, 6003F59C195388D20070C39A /* FIRAppDelegate.h */, 6003F59D195388D20070C39A /* FIRAppDelegate.m */, - 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */, 6003F5A5195388D20070C39A /* FIRViewController.h */, 6003F5A6195388D20070C39A /* FIRViewController.m */, - 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */, 6003F5A8195388D20070C39A /* Images.xcassets */, - 6003F594195388D20070C39A /* Supporting Files */, + 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */, + 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */, ); path = iOS; sourceTree = "<group>"; @@ -700,8 +700,8 @@ DE51B17B1F0D48AC0013853F /* Model */, DE51B1B21F0D48AC0013853F /* Remote */, DE51B1931F0D48AC0013853F /* SpecTests */, - DE51B1851F0D48AC0013853F /* Util */, 6003F5B6195388D20070C39A /* Supporting Files */, + DE51B1851F0D48AC0013853F /* Util */, ); path = Tests; sourceTree = "<group>"; @@ -709,8 +709,8 @@ 6003F5B6195388D20070C39A /* Supporting Files */ = { isa = PBXGroup; children = ( - 6003F5B7195388D20070C39A /* Tests-Info.plist */, 6003F5B8195388D20070C39A /* InfoPlist.strings */, + 6003F5B7195388D20070C39A /* Tests-Info.plist */, ); name = "Supporting Files"; sourceTree = "<group>"; @@ -719,8 +719,8 @@ isa = PBXGroup; children = ( 8E002F4AD5D9B6197C940847 /* Firestore.podspec */, - D3CC3DC5338DCAF43A211155 /* README.md */, 12F4357299652983A615F886 /* LICENSE */, + D3CC3DC5338DCAF43A211155 /* README.md */, ); name = "Podspec Metadata"; sourceTree = "<group>"; @@ -728,12 +728,12 @@ AAEA2A72CFD1FA5AD34462F7 /* Pods */ = { isa = PBXGroup; children = ( - 3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */, - 3F0992A4B83C60841C52E960 /* Pods-Firestore_Example_iOS.release.xcconfig */, 69E6C311558EC77729A16CF1 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */, 11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */, 05C3D82261C3BE976889FF09 /* Pods-Firestore_Example_iOS-SwiftBuildTest.debug.xcconfig */, 74ACEC3603BE58B57A7E8D4C /* Pods-Firestore_Example_iOS-SwiftBuildTest.release.xcconfig */, + 3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */, + 3F0992A4B83C60841C52E960 /* Pods-Firestore_Example_iOS.release.xcconfig */, 1277F98C20D2DF0867496976 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */, F354C0FE92645B56A6C6FD44 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */, E592181BFD7C53C305123739 /* Pods-Firestore_Tests_iOS.debug.xcconfig */, @@ -813,6 +813,7 @@ 5492E0872021552A00B64F25 /* FSTLevelDBMutationQueueTests.mm */, 5492E0982021552C00B64F25 /* FSTLevelDBQueryCacheTests.mm */, 5492E0922021552B00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm */, + 132E36BB104830BD806351AC /* FSTLevelDBTransactionTests.mm */, 5492E08A2021552A00B64F25 /* FSTLocalSerializerTests.mm */, 5492E0912021552B00B64F25 /* FSTLocalStoreTests.h */, 5492E0832021552A00B64F25 /* FSTLocalStoreTests.mm */, @@ -830,7 +831,6 @@ 5492E0852021552A00B64F25 /* FSTRemoteDocumentCacheTests.h */, 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */, 5492E0932021552B00B64F25 /* StringViewTests.mm */, - 132E36BB104830BD806351AC /* FSTLevelDBTransactionTests.mm */, ); path = Local; sourceTree = "<group>"; @@ -838,12 +838,12 @@ DE51B17B1F0D48AC0013853F /* Model */ = { isa = PBXGroup; children = ( - 54A0352320A3AEC3003E0143 /* field_transform_test.mm */, 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */, 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */, 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */, 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */, 5492E0B72021555100B64F25 /* FSTMutationTests.mm */, + 54A0352320A3AEC3003E0143 /* field_transform_test.mm */, 54A0352220A3AEC3003E0143 /* transform_operations_test.mm */, ); path = Model; @@ -872,7 +872,7 @@ DE51B1851F0D48AC0013853F /* Util */ = { isa = PBXGroup; children = ( - 5492E0382021401E00B64F25 /* FSTAssertTests.mm */, + 7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */, 54E9281C1F33950B00C1953E /* FSTEventAccumulator.h */, 5492E0392021401F00B64F25 /* FSTEventAccumulator.mm */, DE51B1881F0D48AC0013853F /* FSTHelpers.h */, @@ -881,7 +881,6 @@ 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */, 54E9282A1F339CAD00C1953E /* XCTestCase+Await.h */, 5492E0372021401E00B64F25 /* XCTestCase+Await.mm */, - 7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */, ); path = Util; sourceTree = "<group>"; @@ -889,6 +888,7 @@ DE51B1931F0D48AC0013853F /* SpecTests */ = { isa = PBXGroup; children = ( + DE51B19C1F0D48AC0013853F /* json */, 5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */, 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */, DE51B1961F0D48AC0013853F /* FSTMockDatastore.h */, @@ -897,7 +897,6 @@ 5492E03020213FFC00B64F25 /* FSTSpecTests.mm */, DE51B19A1F0D48AC0013853F /* FSTSyncEngineTestDriver.h */, 5492E02E20213FFC00B64F25 /* FSTSyncEngineTestDriver.mm */, - DE51B19C1F0D48AC0013853F /* json */, ); path = SpecTests; sourceTree = "<group>"; @@ -905,7 +904,7 @@ DE51B19C1F0D48AC0013853F /* json */ = { isa = PBXGroup; children = ( - 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */, + DE51B1A71F0D48AC0013853F /* README.md */, 54DA129C1F315EE100DD57A1 /* collection_spec_test.json */, 54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */, 54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */, @@ -914,9 +913,9 @@ 54DA12A11F315EE100DD57A1 /* offline_spec_test.json */, 54DA12A21F315EE100DD57A1 /* orderby_spec_test.json */, 54DA12A31F315EE100DD57A1 /* persistence_spec_test.json */, + 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */, 54DA12A41F315EE100DD57A1 /* resume_token_spec_test.json */, 54DA12A51F315EE100DD57A1 /* write_spec_test.json */, - DE51B1A71F0D48AC0013853F /* README.md */, ); path = json; sourceTree = "<group>"; @@ -964,10 +963,10 @@ isa = PBXGroup; children = ( 73866A9F2082B069009BB4FF /* FIRArrayTransformTests.mm */, - 6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */, 5492E070202154D600B64F25 /* FIRCursorTests.mm */, 5492E06C202154D500B64F25 /* FIRDatabaseTests.mm */, 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */, + 6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */, 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */, 5492E069202154D500B64F25 /* FIRQueryTests.mm */, 5492E06E202154D600B64F25 /* FIRServerTimestampTests.mm */, @@ -1148,9 +1147,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */, 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */, - 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1159,18 +1158,18 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */, + 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, + 54DA12A61F315EE100DD57A1 /* collection_spec_test.json in Resources */, + 54DA12A71F315EE100DD57A1 /* existence_filter_spec_test.json in Resources */, 54DA12A81F315EE100DD57A1 /* limbo_spec_test.json in Resources */, + 54DA12A91F315EE100DD57A1 /* limit_spec_test.json in Resources */, 54DA12AA1F315EE100DD57A1 /* listen_spec_test.json in Resources */, - 54DA12A61F315EE100DD57A1 /* collection_spec_test.json in Resources */, - 54DA12AE1F315EE100DD57A1 /* resume_token_spec_test.json in Resources */, - 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, - 54DA12AF1F315EE100DD57A1 /* write_spec_test.json in Resources */, - 54DA12AD1F315EE100DD57A1 /* persistence_spec_test.json in Resources */, 54DA12AB1F315EE100DD57A1 /* offline_spec_test.json in Resources */, - 54DA12A71F315EE100DD57A1 /* existence_filter_spec_test.json in Resources */, 54DA12AC1F315EE100DD57A1 /* orderby_spec_test.json in Resources */, - 54DA12A91F315EE100DD57A1 /* limit_spec_test.json in Resources */, + 54DA12AD1F315EE100DD57A1 /* persistence_spec_test.json in Resources */, + 3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */, + 54DA12AE1F315EE100DD57A1 /* resume_token_spec_test.json in Resources */, + 54DA12AF1F315EE100DD57A1 /* write_spec_test.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1178,8 +1177,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - DE03B2DD1F2149D600A30B9C /* InfoPlist.strings in Resources */, DE03B3631F215E1A00A30B9C /* CAcert.pem in Resources */, + DE03B2DD1F2149D600A30B9C /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1456,118 +1455,117 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7346E61D20325C6900FD6CEF /* FSTDispatchQueueTests.mm in Sources */, - DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */, - ABE6637A201FA81900ED349A /* database_id_test.cc in Sources */, - 5492E0AF2021552D00B64F25 /* FSTReferenceSetTests.mm in Sources */, - 549CCA5120A36DBC00BCEB75 /* tree_sorted_map_test.cc in Sources */, - 5492E09E2021552D00B64F25 /* FSTEagerGarbageCollectorTests.mm in Sources */, - 5492E0C62021557E00B64F25 /* FSTWatchChange+Testing.mm in Sources */, - 5492E064202154B900B64F25 /* FSTQueryListenerTests.mm in Sources */, + 5492E050202154AA00B64F25 /* FIRCollectionReferenceTests.mm in Sources */, + 5492E053202154AB00B64F25 /* FIRDocumentReferenceTests.mm in Sources */, + 5492E055202154AB00B64F25 /* FIRDocumentSnapshotTests.mm in Sources */, + 5492E056202154AB00B64F25 /* FIRFieldPathTests.mm in Sources */, + 5492E054202154AB00B64F25 /* FIRFieldValueTests.mm in Sources */, + 5467FB01203E5717009C9584 /* FIRFirestoreTests.mm in Sources */, + 5492E052202154AB00B64F25 /* FIRGeoPointTests.mm in Sources */, + 5492E059202154AB00B64F25 /* FIRQuerySnapshotTests.mm in Sources */, + 5492E051202154AA00B64F25 /* FIRQueryTests.mm in Sources */, + 5492E057202154AB00B64F25 /* FIRSnapshotMetadataTests.mm in Sources */, B65D34A9203C995B0076A5E1 /* FIRTimestampTest.m in Sources */, - 5492E03320213FFC00B64F25 /* FSTSyncEngineTestDriver.mm in Sources */, - AB380CFE201A2F4500D97691 /* string_util_test.cc in Sources */, - 5492E0A42021552D00B64F25 /* FSTMemoryQueryCacheTests.mm in Sources */, - 54C2294F1FECABAE007D065B /* log_test.cc in Sources */, - B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */, - 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */, - 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */, - 54131E9720ADE679001DF3FF /* string_format_test.cc in Sources */, 5492E058202154AB00B64F25 /* FSTAPIHelpers.mm in Sources */, - AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */, - 5492E0A82021552D00B64F25 /* FSTLevelDBLocalStoreTests.mm in Sources */, - 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */, - ABC1D7DE2023A05300BA84F0 /* user_test.cc in Sources */, - 5491BC721FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */, - ABC1D7DD2023A04F00BA84F0 /* empty_credentials_provider_test.cc in Sources */, - DE2EF0861F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m in Sources */, - B686F2AF2023DDEE0028D6BE /* field_path_test.cc in Sources */, - 54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */, - 5492E03120213FFC00B64F25 /* FSTLevelDBSpecTests.mm in Sources */, - B6FB468F208F9BAE00554BA2 /* executor_std_test.cc in Sources */, - 5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */, + DE2EF0851F3D0B6E003D0CDC /* FSTArraySortedDictionaryTests.m in Sources */, + 5492E0C82021557E00B64F25 /* FSTDatastoreTests.mm in Sources */, + 7346E61D20325C6900FD6CEF /* FSTDispatchQueueTests.mm in Sources */, + 5492E0B92021555100B64F25 /* FSTDocumentKeyTests.mm in Sources */, 5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */, - 54740A581FC914F000713A1A /* autoid_test.cc in Sources */, - 5492E0A62021552D00B64F25 /* FSTPersistenceTestHelpers.mm in Sources */, - B6FB468E208F9BAB00554BA2 /* executor_libdispatch_test.mm in Sources */, - 5467FB01203E5717009C9584 /* FIRFirestoreTests.mm in Sources */, - B6FB4684208EA0EC00554BA2 /* async_queue_libdispatch_test.mm in Sources */, - 5492E0A12021552D00B64F25 /* FSTMemoryLocalStoreTests.mm in Sources */, + 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */, + 5492E09E2021552D00B64F25 /* FSTEagerGarbageCollectorTests.mm in Sources */, + 5492E03E2021401F00B64F25 /* FSTEventAccumulator.mm in Sources */, 5492E067202154B900B64F25 /* FSTEventManagerTests.mm in Sources */, - 54A0353020A3B3D8003E0143 /* statusor_test.cc in Sources */, 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */, - 54A0352620A3AED0003E0143 /* field_transform_test.mm in Sources */, - 5492E055202154AB00B64F25 /* FIRDocumentSnapshotTests.mm in Sources */, - 5492E03E2021401F00B64F25 /* FSTEventAccumulator.mm in Sources */, - 54A0352720A3AED0003E0143 /* transform_operations_test.mm in Sources */, - DE2EF0851F3D0B6E003D0CDC /* FSTArraySortedDictionaryTests.m in Sources */, - 5492E0AA2021552D00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm in Sources */, - 5492E0AC2021552D00B64F25 /* FSTMutationQueueTests.mm in Sources */, - 5492E056202154AB00B64F25 /* FIRFieldPathTests.mm in Sources */, - 5492E03220213FFC00B64F25 /* FSTMockDatastore.mm in Sources */, - ABC1D7E12023A40C00BA84F0 /* token_test.cc in Sources */, - 54A0353520A3D8CB003E0143 /* iterator_adaptors_test.cc 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 */, - AB6B908620322E6D00CC290A /* maybe_document_test.cc in Sources */, + 54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */, + 5492E03F2021401F00B64F25 /* FSTHelpers.mm in Sources */, + DE2EF0861F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m in Sources */, + DE2EF0871F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m in Sources */, + 5491BC721FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */, + 5492E0A72021552D00B64F25 /* FSTLevelDBKeyTests.mm in Sources */, + 5492E0A82021552D00B64F25 /* FSTLevelDBLocalStoreTests.mm in Sources */, 5492E09F2021552D00B64F25 /* FSTLevelDBMigrationsTests.mm in Sources */, - 546854AA20A36867004BDBD5 /* datastore_test.cc in Sources */, - 5492E053202154AB00B64F25 /* FIRDocumentReferenceTests.mm in Sources */, - 5492E09D2021552D00B64F25 /* FSTLocalStoreTests.mm in Sources */, + 5492E0A02021552D00B64F25 /* FSTLevelDBMutationQueueTests.mm in Sources */, + 5492E0AE2021552D00B64F25 /* FSTLevelDBQueryCacheTests.mm in Sources */, + 5492E0AA2021552D00B64F25 /* FSTLevelDBRemoteDocumentCacheTests.mm in Sources */, + 5492E03120213FFC00B64F25 /* FSTLevelDBSpecTests.mm in Sources */, + 132E3E53179DE287D875F3F2 /* FSTLevelDBTransactionTests.mm in Sources */, 5492E0A32021552D00B64F25 /* FSTLocalSerializerTests.mm in Sources */, - 5492E0A72021552D00B64F25 /* FSTLevelDBKeyTests.mm in Sources */, - B6FB4685208EA0F000554BA2 /* async_queue_std_test.cc in Sources */, - 5492E0A22021552D00B64F25 /* FSTQueryCacheTests.mm in Sources */, + 5492E09D2021552D00B64F25 /* FSTLocalStoreTests.mm in Sources */, + 5492E0A12021552D00B64F25 /* FSTMemoryLocalStoreTests.mm in Sources */, + 5492E0AD2021552D00B64F25 /* FSTMemoryMutationQueueTests.mm in Sources */, + 5492E0A42021552D00B64F25 /* FSTMemoryQueryCacheTests.mm in Sources */, 5492E0A52021552D00B64F25 /* FSTMemoryRemoteDocumentCacheTests.mm in Sources */, - AB6B908820322E8800CC290A /* no_document_test.cc in Sources */, - 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */, - 5492E0B92021555100B64F25 /* FSTDocumentKeyTests.mm in Sources */, - DE2EF0871F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m in Sources */, - 5492E0C82021557E00B64F25 /* FSTDatastoreTests.mm in Sources */, - 54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */, + 5492E03420213FFC00B64F25 /* FSTMemorySpecTests.mm in Sources */, + 5492E03220213FFC00B64F25 /* FSTMockDatastore.mm in Sources */, + 5492E0AC2021552D00B64F25 /* FSTMutationQueueTests.mm in Sources */, + 5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */, + 5492E0A62021552D00B64F25 /* FSTPersistenceTestHelpers.mm in Sources */, + 5492E0A22021552D00B64F25 /* FSTQueryCacheTests.mm in Sources */, + 5492E064202154B900B64F25 /* FSTQueryListenerTests.mm in Sources */, + 5492E068202154B900B64F25 /* FSTQueryTests.mm in Sources */, + 5492E0AF2021552D00B64F25 /* FSTReferenceSetTests.mm in Sources */, + 5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */, + 5492E0C92021557E00B64F25 /* FSTRemoteEventTests.mm in Sources */, + 5492E0C72021557E00B64F25 /* FSTSerializerBetaTests.mm in Sources */, + 5492E03520213FFC00B64F25 /* FSTSpecTests.mm in Sources */, + 5492E03320213FFC00B64F25 /* FSTSyncEngineTestDriver.mm in Sources */, + DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */, + 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */, 5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */, - B6FB467D208E9D3C00554BA2 /* async_queue_test.cc in Sources */, - 54A0352F20A3B3D8003E0143 /* status_test.cc in Sources */, + 5492E0C62021557E00B64F25 /* FSTWatchChange+Testing.mm in Sources */, + 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */, + 5492E0AB2021552D00B64F25 /* StringViewTests.mm in Sources */, 5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */, - B6152AD7202A53CB000E5744 /* document_key_test.cc in Sources */, 5467FB08203E6A44009C9584 /* app_testing.mm in Sources */, - 54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */, - AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */, - 5492E03F2021401F00B64F25 /* FSTHelpers.mm in Sources */, - 549CCA5220A36DBC00BCEB75 /* sorted_map_test.cc in Sources */, - 5492E068202154B900B64F25 /* FSTQueryTests.mm in Sources */, - 5492E0AB2021552D00B64F25 /* StringViewTests.mm in Sources */, - 5492E0C92021557E00B64F25 /* FSTRemoteEventTests.mm in Sources */, - ABC1D7E42024AFDE00BA84F0 /* firebase_credentials_provider_test.mm in Sources */, - AB6B908420322E4D00CC290A /* document_test.cc in Sources */, - ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */, - 5492E0AE2021552D00B64F25 /* FSTLevelDBQueryCacheTests.mm in Sources */, - ABC1D7DC2023A04B00BA84F0 /* credentials_provider_test.cc in Sources */, - 54511E8E209805F8005BD28F /* hashing_test.cc in Sources */, - 5492E059202154AB00B64F25 /* FIRQuerySnapshotTests.mm in Sources */, - 5492E050202154AA00B64F25 /* FIRCollectionReferenceTests.mm in Sources */, - ABA495BB202B7E80008A7851 /* snapshot_version_test.cc in Sources */, - 5492E0A02021552D00B64F25 /* FSTLevelDBMutationQueueTests.mm in Sources */, 54EB764D202277B30088B8F3 /* array_sorted_map_test.cc in Sources */, - 54131E9920AE076D001DF3FF /* hard_assert_test.cc in Sources */, - 5492E03420213FFC00B64F25 /* FSTMemorySpecTests.mm in Sources */, + B6FB4684208EA0EC00554BA2 /* async_queue_libdispatch_test.mm in Sources */, + B6FB4685208EA0F000554BA2 /* async_queue_std_test.cc in Sources */, + B6FB467D208E9D3C00554BA2 /* async_queue_test.cc in Sources */, + 54740A581FC914F000713A1A /* autoid_test.cc in Sources */, AB380D02201BC69F00D97691 /* bits_test.cc in Sources */, 548DB929200D59F600E00ABC /* comparison_test.cc in Sources */, - 549CCA5720A36E1F00BCEB75 /* field_mask_test.cc in Sources */, - 5492E03D2021401F00B64F25 /* FSTAssertTests.mm in Sources */, + ABC1D7DC2023A04B00BA84F0 /* credentials_provider_test.cc in Sources */, + ABE6637A201FA81900ED349A /* database_id_test.cc in Sources */, AB38D93020236E21000A432D /* database_info_test.cc in Sources */, - 5492E052202154AB00B64F25 /* FIRGeoPointTests.mm in Sources */, - 5492E0C72021557E00B64F25 /* FSTSerializerBetaTests.mm in Sources */, + 546854AA20A36867004BDBD5 /* datastore_test.cc in Sources */, + B6152AD7202A53CB000E5744 /* document_key_test.cc in Sources */, + AB6B908420322E4D00CC290A /* document_test.cc in Sources */, + ABC1D7DD2023A04F00BA84F0 /* empty_credentials_provider_test.cc in Sources */, + B6FB468E208F9BAB00554BA2 /* executor_libdispatch_test.mm in Sources */, + B6FB468F208F9BAE00554BA2 /* executor_std_test.cc in Sources */, B6FB4690208F9BB300554BA2 /* executor_test.cc in Sources */, - 5492E03520213FFC00B64F25 /* FSTSpecTests.mm in Sources */, - 5492E057202154AB00B64F25 /* FIRSnapshotMetadataTests.mm in Sources */, + 549CCA5720A36E1F00BCEB75 /* field_mask_test.cc in Sources */, + B686F2AF2023DDEE0028D6BE /* field_path_test.cc in Sources */, + 54A0352620A3AED0003E0143 /* field_transform_test.mm in Sources */, + AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */, + ABC1D7E42024AFDE00BA84F0 /* firebase_credentials_provider_test.mm in Sources */, + AB7BAB342012B519001E0872 /* geo_point_test.cc in Sources */, + 73FE5066020EF9B2892C86BF /* hard_assert_test.cc in Sources */, + 54511E8E209805F8005BD28F /* hashing_test.cc in Sources */, + 54A0353520A3D8CB003E0143 /* iterator_adaptors_test.cc in Sources */, + 54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */, + 54C2294F1FECABAE007D065B /* log_test.cc in Sources */, + AB6B908620322E6D00CC290A /* maybe_document_test.cc in Sources */, + AB6B908820322E8800CC290A /* no_document_test.cc in Sources */, + AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */, + 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */, + B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */, 54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */, + ABA495BB202B7E80008A7851 /* snapshot_version_test.cc in Sources */, + 549CCA5220A36DBC00BCEB75 /* sorted_map_test.cc in Sources */, 549CCA5020A36DBC00BCEB75 /* sorted_set_test.cc in Sources */, - 5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */, - 132E3E53179DE287D875F3F2 /* FSTLevelDBTransactionTests.mm in Sources */, + 54A0352F20A3B3D8003E0143 /* status_test.cc in Sources */, + 54A0353020A3B3D8003E0143 /* statusor_test.cc in Sources */, + 54131E9720ADE679001DF3FF /* string_format_test.cc in Sources */, + AB380CFE201A2F4500D97691 /* string_util_test.cc in Sources */, + AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */, + 54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */, + ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */, + ABC1D7E12023A40C00BA84F0 /* token_test.cc in Sources */, + 54A0352720A3AED0003E0143 /* transform_operations_test.mm in Sources */, + 549CCA5120A36DBC00BCEB75 /* tree_sorted_map_test.cc in Sources */, + ABC1D7DE2023A05300BA84F0 /* user_test.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1576,24 +1574,24 @@ buildActionMask = 2147483647; files = ( 73866AA12082B0A5009BB4FF /* FIRArrayTransformTests.mm in Sources */, + 5492E079202154D600B64F25 /* FIRCursorTests.mm in Sources */, + 5492E075202154D600B64F25 /* FIRDatabaseTests.mm in Sources */, + 5492E073202154D600B64F25 /* FIRFieldsTests.mm in Sources */, 6161B5032047140C00A99DBB /* FIRFirestoreSourceTests.mm in Sources */, - 5492E076202154D600B64F25 /* FIRValidationTests.mm in Sources */, + 5492E074202154D600B64F25 /* FIRListenerRegistrationTests.mm in Sources */, 5492E072202154D600B64F25 /* FIRQueryTests.mm in Sources */, - 5491BC731FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */, - 5492E0442021457E00B64F25 /* XCTestCase+Await.mm in Sources */, + 5492E077202154D600B64F25 /* FIRServerTimestampTests.mm in Sources */, 5492E07A202154D600B64F25 /* FIRTypeTests.mm in Sources */, - 5492E0422021440500B64F25 /* FSTHelpers.mm in Sources */, + 5492E076202154D600B64F25 /* FIRValidationTests.mm in Sources */, + 5492E078202154D600B64F25 /* FIRWriteBatchTests.mm in Sources */, + 5492E082202154EC00B64F25 /* FSTDatastoreTests.mm in Sources */, 5492E041202143E700B64F25 /* FSTEventAccumulator.mm in Sources */, + 5492E0422021440500B64F25 /* FSTHelpers.mm in Sources */, + 5491BC731FB44593008B3588 /* FSTIntegrationTestCase.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 */, + 5492E0442021457E00B64F25 /* XCTestCase+Await.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Firestore/Example/LibFuzzer.podspec b/Firestore/Example/LibFuzzer.podspec new file mode 100644 index 0000000..0f677f5 --- /dev/null +++ b/Firestore/Example/LibFuzzer.podspec @@ -0,0 +1,45 @@ +# 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. + +# A podspec for libFuzzer. Excludes the 'FuzzerMain.cpp' because the pod +# installation would require the 'LLVMFuzzerTestOneInput' function to be +# linked when the pod is being created, but it will be available in +# the fuzzing application. Hence, users of this Pod are required to +# provide their main function similar to 'FuzzerMain.cpp'. +# See the build script of libFuzzer for more details: +# https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer/build.sh + +Pod::Spec.new do |s| + s.name = 'LibFuzzer' + s.version = '1.0' + s.summary = 'libFuzzer for fuzz testing' + s.homepage = 'https://llvm.org/docs/LibFuzzer.html' + s.license = { :type => 'BSD-Like' } + s.authors = 'LLVM Team' + + # Check out only libFuzzer folder. + s.source = { + :svn => 'https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer' + } + + # Add all source files, except for the FuzzerMain.cpp. + s.source_files = '*.{h,cpp,def}' + s.exclude_files = 'FuzzerMain.cpp' + + s.library = 'c++' + + s.pod_target_xcconfig = { + 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' + } +end diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index 920e3c5..e6e1a19 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -33,7 +33,6 @@ #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h" @@ -42,6 +41,7 @@ #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -118,7 +118,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)rejectFailedWriteWithBatchID:(FSTBatchID)batchID error:(NSError *)error { - FSTFail(@"Not implemented"); + HARD_FAIL("Not implemented"); } - (void)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { @@ -129,7 +129,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)rejectListenWithTargetID:(const TargetId)targetID error:(NSError *)error { - FSTFail(@"Not implemented"); + HARD_FAIL("Not implemented"); } @end diff --git a/Firestore/Example/Tests/Integration/FSTStreamTests.mm b/Firestore/Example/Tests/Integration/FSTStreamTests.mm index 2e5c9b6..b944a93 100644 --- a/Firestore/Example/Tests/Integration/FSTStreamTests.mm +++ b/Firestore/Example/Tests/Integration/FSTStreamTests.mm @@ -24,12 +24,12 @@ #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h" #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -121,7 +121,7 @@ using firebase::firestore::model::SnapshotVersion; * to be called. */ - (void)awaitNotificationFromBlock:(void (^)(void))block { - FSTAssert(_expectation == nil, @"Previous expectation still active"); + HARD_ASSERT(_expectation == nil, "Previous expectation still active"); XCTestExpectation *expectation = [self.testCase expectationWithDescription:@"awaitCallbackInBlock"]; _expectation = expectation; diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm index dd34556..63c3d72 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm @@ -16,12 +16,11 @@ #import "Firestore/Example/Tests/SpecTests/FSTMockDatastore.h" +#import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" @@ -29,6 +28,7 @@ #include "Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" using firebase::firestore::auth::CredentialsProvider; @@ -79,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN credentials:credentials serializer:serializer]; if (self) { - FSTAssert(datastore, @"Datastore must not be nil"); + HARD_ASSERT(datastore, "Datastore must not be nil"); _datastore = datastore; _activeTargets = [NSMutableDictionary dictionary]; } @@ -89,7 +89,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Overridden FSTWatchStream methods. - (void)startWithDelegate:(id<FSTWatchStreamDelegate>)delegate { - FSTAssert(!self.open, @"Trying to start already started watch stream"); + HARD_ASSERT(!self.open, "Trying to start already started watch stream"); self.open = YES; self.delegate = delegate; [self notifyStreamOpen]; @@ -117,7 +117,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)watchQuery:(FSTQueryData *)query { - FSTLog(@"watchQuery: %d: %@", query.targetID, query.query); + LOG_DEBUG("watchQuery: %s: %s", query.targetID, query.query); self.datastore.watchStreamRequestCount += 1; // Snapshot version is ignored on the wire FSTQueryData *sentQueryData = [query queryDataByReplacingSnapshotVersion:SnapshotVersion::None() @@ -127,7 +127,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)unwatchTargetID:(FSTTargetID)targetID { - FSTLog(@"unwatchTargetID: %d", targetID); + LOG_DEBUG("unwatchTargetID: %s", targetID); [self.activeTargets removeObjectForKey:@(targetID)]; } @@ -147,7 +147,7 @@ NS_ASSUME_NONNULL_BEGIN // Technically removing an unknown target is valid (e.g. it could race with a // server-side removal), but we want to pay extra careful attention in tests // that we only remove targets we listened too. - FSTFail(@"Removing a non-active target"); + HARD_FAIL("Removing a non-active target"); } [self.activeTargets removeObjectForKey:targetID]; } @@ -203,7 +203,7 @@ NS_ASSUME_NONNULL_BEGIN credentials:credentials serializer:serializer]; if (self) { - FSTAssert(datastore, @"Datastore must not be nil"); + HARD_ASSERT(datastore, "Datastore must not be nil"); _datastore = datastore; _sentMutations = [NSMutableArray array]; } @@ -213,7 +213,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Overridden FSTWriteStream methods. - (void)startWithDelegate:(id<FSTWriteStreamDelegate>)delegate { - FSTAssert(!self.open, @"Trying to start already started write stream"); + HARD_ASSERT(!self.open, "Trying to start already started write stream"); self.open = YES; [self.sentMutations removeAllObjects]; self.delegate = delegate; @@ -257,8 +257,8 @@ NS_ASSUME_NONNULL_BEGIN * Returns the next write that was "sent to the backend", failing if there are no queued sent */ - (NSArray<FSTMutation *> *)nextSentWrite { - FSTAssert(self.sentMutations.count > 0, - @"Writes need to happen before you can call nextSentWrite."); + HARD_ASSERT(self.sentMutations.count > 0, + "Writes need to happen before you can call nextSentWrite."); NSArray<FSTMutation *> *result = [self.sentMutations objectAtIndex:0]; [self.sentMutations removeObjectAtIndex:0]; return result; @@ -291,7 +291,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Overridden FSTDatastore methods. - (FSTWatchStream *)createWatchStream { - // FSTAssert(self.databaseInfo, @"DatabaseInfo must not be nil"); self.watchStream = [[FSTMockWatchStream alloc] initWithDatastore:self workerDispatchQueue:self.workerDispatchQueue @@ -302,7 +301,6 @@ NS_ASSUME_NONNULL_BEGIN } - (FSTWriteStream *)createWriteStream { - // FSTAssert(self.databaseInfo, @"DatabaseInfo must not be nil"); self.writeStream = [[FSTMockWriteStream alloc] initWithDatastore:self workerDispatchQueue:self.workerDispatchQueue @@ -313,7 +311,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)authorizeAndStartRPC:(GRPCProtoCall *)rpc completion:(FSTVoidErrorBlock)completion { - FSTFail(@"FSTMockDatastore shouldn't be starting any RPCs."); + HARD_FAIL("FSTMockDatastore shouldn't be starting any RPCs."); } #pragma mark - Method exposed for tests to call. diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 5a7cb72..77010e5 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -34,10 +34,8 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h" @@ -46,6 +44,8 @@ #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -233,7 +233,7 @@ static NSString *const kNoIOSTag = @"no-ios"; - (void)doWatchEntity:(NSDictionary *)watchEntity snapshot:(NSNumber *_Nullable)watchSnapshot { if (watchEntity[@"docs"]) { - FSTAssert(!watchEntity[@"doc"], @"Exactly one of |doc| or |docs| needs to be set."); + HARD_ASSERT(!watchEntity[@"doc"], "Exactly one of |doc| or |docs| needs to be set."); int count = 0; NSArray *docs = watchEntity[@"docs"]; for (NSDictionary *doc in docs) { @@ -277,13 +277,13 @@ static NSString *const kNoIOSTag = @"no-ios"; document:nil]; [self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot]]; } else { - FSTFail(@"Either key, doc or docs must be set."); + HARD_FAIL("Either key, doc or docs must be set."); } } - (void)doWatchFilter:(NSArray *)watchFilter snapshot:(NSNumber *_Nullable)watchSnapshot { NSArray<NSNumber *> *targets = watchFilter[0]; - FSTAssert(targets.count == 1, @"ExistenceFilters currently support exactly one target only."); + HARD_ASSERT(targets.count == 1, "ExistenceFilters currently support exactly one target only."); int keyCount = watchFilter.count == 0 ? 0 : (int)watchFilter.count - 1; @@ -308,7 +308,7 @@ static NSString *const kNoIOSTag = @"no-ios"; NSNumber *runBackoffTimer = closeSpec[@"runBackoffTimer"]; // TODO(b/72313632): Incorporate backoff in iOS Spec Tests. - FSTAssert(runBackoffTimer.boolValue, @"iOS Spec Tests don't support backoff."); + HARD_ASSERT(runBackoffTimer.boolValue, "iOS Spec Tests don't support backoff."); [self.driver receiveWatchStreamError:code userInfo:errorSpec]; } @@ -323,8 +323,8 @@ static NSString *const kNoIOSTag = @"no-ios"; [self.driver receiveWriteAckWithVersion:version mutationResults:@[ mutationResult ]]; if (expectUserCallback.boolValue) { - FSTAssert(write.done, @"Write should be done"); - FSTAssert(!write.error, @"Ack should not fail"); + HARD_ASSERT(write.done, "Write should be done"); + HARD_ASSERT(!write.error, "Ack should not fail"); } } @@ -336,7 +336,7 @@ static NSString *const kNoIOSTag = @"no-ios"; FSTOutstandingWrite *write = [self.driver receiveWriteError:code userInfo:errorSpec]; if (expectUserCallback.boolValue) { - FSTAssert(write.done, @"Write should be done"); + HARD_ASSERT(write.done, "Write should be done"); XCTAssertNotNil(write.error, @"Write should have failed"); XCTAssertEqualObjects(write.error.domain, FIRFirestoreErrorDomain); XCTAssertEqual(write.error.code, code); @@ -358,7 +358,7 @@ static NSString *const kNoIOSTag = @"no-ios"; } else if ([timer isEqualToString:@"online_state_timeout"]) { timerID = FSTTimerIDOnlineStateTimeout; } else { - FSTFail(@"runTimer spec step specified unknown timer: %@", timer); + HARD_FAIL("runTimer spec step specified unknown timer: %s", timer); } [self.driver runTimer:timerID]; @@ -427,7 +427,7 @@ static NSString *const kNoIOSTag = @"no-ios"; [self doWatchStreamClose:step[@"watchStreamClose"]]; } else if (step[@"watchProto"]) { // watchProto isn't yet used, and it's unclear how to create arbitrary protos from JSON. - FSTFail(@"watchProto is not yet supported."); + HARD_FAIL("watchProto is not yet supported."); } else if (step[@"writeAck"]) { [self doWriteAck:step[@"writeAck"]]; } else if (step[@"failWrite"]) { @@ -620,7 +620,7 @@ static NSString *const kNoIOSTag = @"no-ios"; @try { [self setUpForSpecWithConfig:config]; for (NSDictionary *step in steps) { - FSTLog(@"Doing step %@", step); + LOG_DEBUG("Doing step %s", step); [self doStep:step]; [self validateStepExpectations:step[@"expect"]]; [self validateStateExpectations:step[@"stateExpect"]]; diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 2aa0e30..d346197 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -30,8 +30,6 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTWatchChange.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Example/Tests/Core/FSTSyncEngine+Testing.h" #import "Firestore/Example/Tests/SpecTests/FSTMockDatastore.h" @@ -41,6 +39,8 @@ #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" using firebase::firestore::auth::EmptyCredentialsProvider; using firebase::firestore::auth::HashUser; @@ -183,9 +183,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)validateUsage { // We could relax this if we found a reason to. - FSTAssert(self.events.count == 0, - @"You must clear all pending events by calling" - " capturedEventsSinceLastCall before calling shutdown."); + HARD_ASSERT(self.events.count == 0, + "You must clear all pending events by calling" + " capturedEventsSinceLastCall before calling shutdown."); } - (void)shutdown { @@ -197,12 +197,12 @@ NS_ASSUME_NONNULL_BEGIN - (void)validateNextWriteSent:(FSTMutation *)expectedWrite { NSArray<FSTMutation *> *request = [self.datastore nextSentWrite]; // Make sure the write went through the pipe like we expected it to. - FSTAssert(request.count == 1, @"Only single mutation requests are supported at the moment"); + HARD_ASSERT(request.count == 1, "Only single mutation requests are supported at the moment"); FSTMutation *actualWrite = request[0]; - FSTAssert([actualWrite isEqual:expectedWrite], - @"Mock datastore received write %@ but first outstanding mutation was %@", actualWrite, - expectedWrite); - FSTLog(@"A write was sent: %@", actualWrite); + HARD_ASSERT([actualWrite isEqual:expectedWrite], + "Mock datastore received write %s but first outstanding mutation was %s", actualWrite, + expectedWrite); + LOG_DEBUG("A write was sent: %s", actualWrite); } - (int)sentWritesCount { @@ -271,7 +271,7 @@ NS_ASSUME_NONNULL_BEGIN [[self currentOutstandingWrites] removeObjectAtIndex:0]; } - FSTLog(@"Failing a write."); + LOG_DEBUG("Failing a write."); [self.dispatchQueue dispatchSync:^{ [self.datastore failWriteWithError:error]; }]; @@ -321,11 +321,11 @@ NS_ASSUME_NONNULL_BEGIN FSTOutstandingWrite *write = [[FSTOutstandingWrite alloc] init]; write.write = mutation; [[self currentOutstandingWrites] addObject:write]; - FSTLog(@"sending a user write."); + LOG_DEBUG("sending a user write."); [self.dispatchQueue dispatchSync:^{ [self.syncEngine writeMutations:@[ mutation ] completion:^(NSError *_Nullable error) { - FSTLog(@"A callback was called with error: %@", error); + LOG_DEBUG("A callback was called with error: %s", error); write.done = YES; write.error = error; }]; @@ -347,7 +347,7 @@ NS_ASSUME_NONNULL_BEGIN [self.datastore failWatchStreamWithError:error]; // Unlike web, stream should re-open synchronously (if we have any listeners) if (self.queryListeners.count > 0) { - FSTAssert(self.datastore.isWatchStreamOpen, @"Watch stream is open"); + HARD_ASSERT(self.datastore.isWatchStreamOpen, "Watch stream is open"); } }]; } diff --git a/Firestore/Example/Tests/Util/FSTAssertTests.mm b/Firestore/Example/Tests/Util/FSTAssertTests.mm deleted file mode 100644 index 0cba03f..0000000 --- a/Firestore/Example/Tests/Util/FSTAssertTests.mm +++ /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/Util/FSTAssert.h" - -#import <XCTest/XCTest.h> - -@interface FSTAssertTests : XCTestCase -@end - -@implementation FSTAssertTests - -- (void)testFail { - @try { - [self failingMethod]; - XCTFail("Should not have succeeded"); - } @catch (NSException *ex) { - XCTAssertEqualObjects(ex.name, NSInternalInconsistencyException); - XCTAssertEqualObjects(ex.reason, @"FIRESTORE INTERNAL ASSERTION FAILED: 0:foo:bar"); - } -} - -// A method guaranteed to fail. Note that the return type is intentionally something that is -// not actually returned in the body to ensure that the function attribute declarations in the -// macro properly mark this macro invocation as never returning. -- (int)failingMethod { - FSTFail(@"%d:%s:%@", 0, "foo", @"bar"); -} - -- (void)testCFail { - @try { - failingFunction(); - XCTFail("Should not have succeeded"); - } @catch (NSException *ex) { - XCTAssertEqualObjects(ex.name, NSInternalInconsistencyException); - XCTAssertEqualObjects(ex.reason, @"FIRESTORE INTERNAL ASSERTION FAILED: 0:foo:bar"); - } -} - -// A function guaranteed to fail. Note that the return type is intentionally something that is -// not actually returned in the body to ensure that the function attribute declarations in the -// macro properly mark this macro invocation as never returning. -int failingFunction() { - FSTCFail(@"%d:%s:%@", 0, "foo", @"bar"); -} - -- (void)testAssertNonFailing { - @try { - FSTAssert(YES, @"shouldn't fail"); - } @catch (NSException *ex) { - XCTFail("Should not have failed, but got %@", ex); - } -} - -- (void)testAssertFailing { - @try { - FSTAssert(NO, @"should fail"); - XCTFail("Should not have succeeded"); - } @catch (NSException *ex) { - XCTAssertEqualObjects(ex.name, NSInternalInconsistencyException); - XCTAssertEqualObjects(ex.reason, @"FIRESTORE INTERNAL ASSERTION FAILED: should fail"); - } -} - -- (void)testCAssertNonFailing { - @try { - nonAssertingFunction(); - } @catch (NSException *ex) { - XCTFail("Should not have failed, but got %@", ex); - } -} - -int nonAssertingFunction() { - FSTCAssert(YES, @"shouldn't fail"); - return 0; -} - -- (void)testCAssertFailing { - @try { - assertingFunction(); - XCTFail("Should not have succeeded"); - } @catch (NSException *ex) { - XCTAssertEqualObjects(ex.name, NSInternalInconsistencyException); - XCTAssertEqualObjects(ex.reason, @"FIRESTORE INTERNAL ASSERTION FAILED: should fail"); - } -} - -int assertingFunction() { - FSTCAssert(NO, @"should fail"); -} - -@end diff --git a/Firestore/Example/Tests/Util/FSTEventAccumulator.mm b/Firestore/Example/Tests/Util/FSTEventAccumulator.mm index 3ab6035..835dc68 100644 --- a/Firestore/Example/Tests/Util/FSTEventAccumulator.mm +++ b/Firestore/Example/Tests/Util/FSTEventAccumulator.mm @@ -18,12 +18,12 @@ #import <XCTest/XCTest.h> +#import "Firestore/Example/Tests/Util/XCTestCase+Await.h" #import "Firestore/Source/Public/FIRDocumentSnapshot.h" #import "Firestore/Source/Public/FIRQuerySnapshot.h" #import "Firestore/Source/Public/FIRSnapshotMetadata.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Example/Tests/Util/XCTestCase+Await.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" NS_ASSUME_NONNULL_BEGIN @@ -54,7 +54,7 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray<id> *)awaitEvents:(NSUInteger)events name:(NSString *)name { @synchronized(self) { - FSTAssert(!self.expectation, @"Existing expectation still pending?"); + HARD_ASSERT(!self.expectation, "Existing expectation still pending?"); self.expectation = [self.testCase expectationWithDescription:name]; self.maxEvents = self.maxEvents + events; [self checkFulfilled]; @@ -91,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN if ([event isKindOfClass:[FIRDocumentSnapshot class]]) { return ((FIRDocumentSnapshot *)event).metadata.hasPendingWrites; } else { - FSTAssert([event isKindOfClass:[FIRQuerySnapshot class]], @"Unexpected event: %@", event); + HARD_ASSERT([event isKindOfClass:[FIRQuerySnapshot class]], "Unexpected event: %s", event); return ((FIRQuerySnapshot *)event).metadata.hasPendingWrites; } } diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index bc2f005..5ed4fd5 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -40,7 +40,6 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTWatchChange.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -140,7 +139,7 @@ FSTFieldValue *FSTTestFieldValue(id _Nullable value) { FSTObjectValue *FSTTestObjectValue(NSDictionary<NSString *, id> *data) { FSTFieldValue *wrapped = FSTTestFieldValue(data); - FSTCAssert([wrapped isKindOfClass:[FSTObjectValue class]], @"Unsupported value: %@", data); + HARD_ASSERT([wrapped isKindOfClass:[FSTObjectValue class]], "Unsupported value: %s", data); return (FSTObjectValue *)wrapped; } @@ -195,15 +194,15 @@ id<FSTFilter> FSTTestFilter(const absl::string_view field, NSString *opString, i } else if ([opString isEqualToString:@"array_contains"]) { op = FSTRelationFilterOperatorArrayContains; } else { - FSTCFail(@"Unsupported operator type: %@", opString); + HARD_FAIL("Unsupported operator type: %s", opString); } FSTFieldValue *data = FSTTestFieldValue(value); if ([data isEqual:[FSTDoubleValue nanValue]]) { - FSTCAssert(op == FSTRelationFilterOperatorEqual, @"Must use == with NAN."); + HARD_ASSERT(op == FSTRelationFilterOperatorEqual, "Must use == with NAN."); return [[FSTNanFilter alloc] initWithField:path]; } else if ([data isEqual:[FSTNullValue nullValue]]) { - FSTCAssert(op == FSTRelationFilterOperatorEqual, @"Must use == with Null."); + HARD_ASSERT(op == FSTRelationFilterOperatorEqual, "Must use == with Null."); return [[FSTNullFilter alloc] initWithField:path]; } else { return [FSTRelationFilter filterWithField:path filterOperator:op value:data]; @@ -218,7 +217,7 @@ FSTSortOrder *FSTTestOrderBy(const absl::string_view field, NSString *direction) } else if ([direction isEqualToString:@"desc"]) { ascending = NO; } else { - FSTCFail(@"Unsupported direction: %@", direction); + HARD_FAIL("Unsupported direction: %s", direction); } return [FSTSortOrder sortOrderWithFieldPath:path ascending:ascending]; } @@ -272,8 +271,8 @@ FSTTransformMutation *FSTTestTransformMutation(NSString *path, NSDictionary<NSSt FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource(util::MakeStringView(path))]; FSTUserDataConverter *converter = FSTTestUserDataConverter(); FSTParsedUpdateData *result = [converter parsedUpdateData:data]; - FSTCAssert(result.data.value.count == 0, - @"FSTTestTransformMutation() only expects transforms; no other data"); + HARD_ASSERT(result.data.value.count == 0, + "FSTTestTransformMutation() only expects transforms; no other data"); return [[FSTTransformMutation alloc] initWithKey:key fieldTransforms:std::move(result.fieldTransforms)]; } diff --git a/Firestore/Source/API/FIRCollectionReference.mm b/Firestore/Source/API/FIRCollectionReference.mm index 3f1559e..dc157ed 100644 --- a/Firestore/Source/API/FIRCollectionReference.mm +++ b/Firestore/Source/API/FIRCollectionReference.mm @@ -23,7 +23,6 @@ #import "Firestore/Source/API/FIRQuery+Internal.h" #import "Firestore/Source/API/FIRQuery_Init.h" #import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -68,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN // Override the designated initializer from the super class. - (instancetype)initWithQuery:(FSTQuery *)query firestore:(FIRFirestore *)firestore { - FSTFail(@"Use FIRCollectionReference initWithPath: initializer."); + HARD_FAIL("Use FIRCollectionReference initWithPath: initializer."); } // NSObject Methods diff --git a/Firestore/Source/API/FIRDocumentChange.mm b/Firestore/Source/API/FIRDocumentChange.mm index 7bb24d2..0b1413f 100644 --- a/Firestore/Source/API/FIRDocumentChange.mm +++ b/Firestore/Source/API/FIRDocumentChange.mm @@ -21,7 +21,8 @@ #import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Util/FSTAssert.h" + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" NS_ASSUME_NONNULL_BEGIN @@ -45,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN } else if (change.type == FSTDocumentViewChangeTypeRemoved) { return FIRDocumentChangeTypeRemoved; } else { - FSTFail(@"Unknown FSTDocumentViewChange: %ld", (long)change.type); + HARD_FAIL("Unknown FSTDocumentViewChange: %s", change.type); } } @@ -64,11 +65,11 @@ NS_ASSUME_NONNULL_BEGIN documentKey:change.document.key document:change.document fromCache:snapshot.isFromCache]; - FSTAssert(change.type == FSTDocumentViewChangeTypeAdded, - @"Invalid event type for first snapshot"); - FSTAssert(!lastDocument || - snapshot.query.comparator(lastDocument, change.document) == NSOrderedAscending, - @"Got added events in wrong order"); + HARD_ASSERT(change.type == FSTDocumentViewChangeTypeAdded, + "Invalid event type for first snapshot"); + HARD_ASSERT(!lastDocument || snapshot.query.comparator(lastDocument, change.document) == + NSOrderedAscending, + "Got added events in wrong order"); [changes addObject:[[FIRDocumentChange alloc] initWithType:FIRDocumentChangeTypeAdded document:document oldIndex:NSNotFound @@ -95,7 +96,7 @@ NS_ASSUME_NONNULL_BEGIN NSUInteger newIndex = NSNotFound; if (change.type != FSTDocumentViewChangeTypeAdded) { oldIndex = [indexTracker indexOfKey:change.document.key]; - FSTAssert(oldIndex != NSNotFound, @"Index for document not found"); + HARD_ASSERT(oldIndex != NSNotFound, "Index for document not found"); indexTracker = [indexTracker documentSetByRemovingKey:change.document.key]; } if (change.type != FSTDocumentViewChangeTypeRemoved) { diff --git a/Firestore/Source/API/FIRDocumentReference.mm b/Firestore/Source/API/FIRDocumentReference.mm index 5ad606c..b83f3cb 100644 --- a/Firestore/Source/API/FIRDocumentReference.mm +++ b/Firestore/Source/API/FIRDocumentReference.mm @@ -36,13 +36,13 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTAsyncQueryListener.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -269,7 +269,7 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions return; } - FSTAssert(snapshot.documents.count <= 1, @"Too many document returned on a document query"); + HARD_ASSERT(snapshot.documents.count <= 1, "Too many document returned on a document query"); FSTDocument *document = [snapshot.documents documentForKey:key]; FIRDocumentSnapshot *result = [FIRDocumentSnapshot snapshotWithFirestore:firestore diff --git a/Firestore/Source/API/FIRDocumentSnapshot.mm b/Firestore/Source/API/FIRDocumentSnapshot.mm index 388b3b3..dff5b7f 100644 --- a/Firestore/Source/API/FIRDocumentSnapshot.mm +++ b/Firestore/Source/API/FIRDocumentSnapshot.mm @@ -26,11 +26,11 @@ #import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -275,7 +275,7 @@ static FSTServerTimestampBehavior InternalServerTimestampBehavor( - (NSDictionary<NSString *, id> *)data { NSDictionary<NSString *, id> *data = [super data]; - FSTAssert(data, @"Document in a QueryDocumentSnapshot should exist"); + HARD_ASSERT(data, "Document in a QueryDocumentSnapshot should exist"); return data; } @@ -283,7 +283,7 @@ static FSTServerTimestampBehavior InternalServerTimestampBehavor( (FIRServerTimestampBehavior)serverTimestampBehavior { NSDictionary<NSString *, id> *data = [super dataWithServerTimestampBehavior:serverTimestampBehavior]; - FSTAssert(data, @"Document in a QueryDocumentSnapshot should exist"); + HARD_ASSERT(data, "Document in a QueryDocumentSnapshot should exist"); return data; } diff --git a/Firestore/Source/API/FIRFirestore.mm b/Firestore/Source/API/FIRFirestore.mm index 5486b75..3671b51 100644 --- a/Firestore/Source/API/FIRFirestore.mm +++ b/Firestore/Source/API/FIRFirestore.mm @@ -32,9 +32,7 @@ #import "Firestore/Source/API/FIRWriteBatch+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" #import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" @@ -42,6 +40,8 @@ #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" @@ -158,7 +158,7 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; FIRFirestore *firestore = instances[key]; if (!firestore) { NSString *projectID = app.options.projectID; - FSTAssert(projectID, @"FirebaseOptions.projectID cannot be nil."); + HARD_ASSERT(projectID, "FirebaseOptions.projectID cannot be nil."); FSTDispatchQueue *workerDispatchQueue = [FSTDispatchQueue queueWith:dispatch_queue_create("com.google.firebase.firestore", DISPATCH_QUEUE_SERIAL)]; @@ -242,35 +242,35 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; @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."); + HARD_ASSERT(_settings.host, "FirestoreSettings.host cannot be nil."); + HARD_ASSERT(_settings.dispatchQueue, "FirestoreSettings.dispatchQueue cannot be nil."); if (!_settings.timestampsInSnapshotsEnabled) { - FSTWarn( - @"The behavior for system Date objects stored in Firestore is going to change " - "AND YOUR APP MAY BREAK.\n" - "To hide this warning and ensure your app does not break, you need to add " - "the following code to your app before calling any other Cloud Firestore methods:\n" - "\n" - "let db = Firestore.firestore()\n" - "let settings = db.settings\n" - "settings.areTimestampsInSnapshotsEnabled = true\n" - "db.settings = settings\n" - "\n" - "With this change, timestamps stored in Cloud Firestore will be read back as " - "Firebase Timestamp objects instead of as system Date objects. So you will " - "also need to update code expecting a Date to instead expect a Timestamp. " - "For example:\n" - "\n" - "// old:\n" - "let date: Date = documentSnapshot.get(\"created_at\") as! Date\n" - "// new:\n" - "let timestamp: Timestamp = documentSnapshot.get(\"created_at\") as! Timestamp\n" - "let date: Date = timestamp.dateValue()\n" - "\n" - "Please audit all existing usages of Date when you enable the new behavior. In a " - "future release, the behavior will be changed to the new behavior, so if you do not " - "follow these steps, YOUR APP MAY BREAK."); + LOG_WARN( + "The behavior for system Date objects stored in Firestore is going to change " + "AND YOUR APP MAY BREAK.\n" + "To hide this warning and ensure your app does not break, you need to add " + "the following code to your app before calling any other Cloud Firestore methods:\n" + "\n" + "let db = Firestore.firestore()\n" + "let settings = db.settings\n" + "settings.areTimestampsInSnapshotsEnabled = true\n" + "db.settings = settings\n" + "\n" + "With this change, timestamps stored in Cloud Firestore will be read back as " + "Firebase Timestamp objects instead of as system Date objects. So you will " + "also need to update code expecting a Date to instead expect a Timestamp. " + "For example:\n" + "\n" + "// old:\n" + "let date: Date = documentSnapshot.get(\"created_at\") as! Date\n" + "// new:\n" + "let timestamp: Timestamp = documentSnapshot.get(\"created_at\") as! Timestamp\n" + "let date: Date = timestamp.dateValue()\n" + "\n" + "Please audit all existing usages of Date when you enable the new behavior. In a " + "future release, the behavior will be changed to the new behavior, so if you do not " + "follow these steps, YOUR APP MAY BREAK."); } const DatabaseInfo database_info(*self.databaseID, util::MakeStringView(_persistenceKey), diff --git a/Firestore/Source/API/FIRQuery.mm b/Firestore/Source/API/FIRQuery.mm index ad4d2aa..08c912d 100644 --- a/Firestore/Source/API/FIRQuery.mm +++ b/Firestore/Source/API/FIRQuery.mm @@ -34,13 +34,13 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTAsyncQueryListener.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; diff --git a/Firestore/Source/API/FIRQuerySnapshot.mm b/Firestore/Source/API/FIRQuerySnapshot.mm index fb7a849..7a6018b 100644 --- a/Firestore/Source/API/FIRQuerySnapshot.mm +++ b/Firestore/Source/API/FIRQuerySnapshot.mm @@ -25,7 +25,8 @@ #import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Util/FSTAssert.h" + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Source/API/FIRTransaction.mm b/Firestore/Source/API/FIRTransaction.mm index b5bdefa..8eb82bb 100644 --- a/Firestore/Source/API/FIRTransaction.mm +++ b/Firestore/Source/API/FIRTransaction.mm @@ -22,9 +22,10 @@ #import "Firestore/Source/API/FSTUserDataConverter.h" #import "Firestore/Source/Core/FSTTransaction.h" #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + NS_ASSUME_NONNULL_BEGIN #pragma mark - FIRTransaction @@ -111,8 +112,8 @@ NS_ASSUME_NONNULL_BEGIN completion(nil, error); return; } - FSTAssert(documents.count == 1, - @"Mismatch in docs returned from document lookup."); + HARD_ASSERT(documents.count == 1, + "Mismatch in docs returned from document lookup."); FSTMaybeDocument *internalDoc = documents.firstObject; if ([internalDoc isKindOfClass:[FSTDeletedDocument class]]) { completion(nil, nil); diff --git a/Firestore/Source/API/FSTUserDataConverter.mm b/Firestore/Source/API/FSTUserDataConverter.mm index 3484539..44e46da 100644 --- a/Firestore/Source/API/FSTUserDataConverter.mm +++ b/Firestore/Source/API/FSTUserDataConverter.mm @@ -29,7 +29,6 @@ #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" @@ -39,6 +38,7 @@ #include "Firestore/core/src/firebase/firestore/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" @@ -532,8 +532,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { [FSTParseContext contextWithSource:FSTUserDataSourceArgument path:absl::make_unique<FieldPath>(FieldPath::EmptyPath())]; FSTFieldValue *_Nullable parsed = [self parseData:input context:context]; - FSTAssert(parsed, @"Parsed data should not be nil."); - FSTAssert(context.fieldTransforms->empty(), @"Field transforms should have been disallowed."); + HARD_ASSERT(parsed, "Parsed data should not be nil."); + HARD_ASSERT(context.fieldTransforms->empty(), "Field transforms should have been disallowed."); return parsed; } @@ -626,8 +626,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { // deleted. [context appendToFieldMaskWithFieldPath:*context.path]; } else if (context.dataSource == FSTUserDataSourceUpdate) { - FSTAssert(context.path->size() > 0, - @"FieldValue.delete() at the top level should have already been handled."); + HARD_ASSERT(context.path->size() > 0, + "FieldValue.delete() at the top level should have already been handled."); FSTThrowInvalidArgument( @"FieldValue.delete() can only appear at the top level of your " "update data%@", @@ -662,7 +662,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { transformOperation:std::move(array_remove)]; } else { - FSTFail(@"Unknown FIRFieldValue type: %@", NSStringFromClass([fieldValue class])); + HARD_FAIL("Unknown FIRFieldValue type: %s", NSStringFromClass([fieldValue class])); } } @@ -741,7 +741,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { default: // All documented codes should be handled above, so this shouldn't happen. - FSTCFail(@"Unknown NSNumber objCType %s on %@", cType, input); + HARD_FAIL("Unknown NSNumber objCType %s on %s", cType, input); } } else if ([input isKindOfClass:[NSString class]]) { @@ -780,8 +780,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { if (context.dataSource == FSTUserDataSourceMergeSet) { return nil; } else if (context.dataSource == FSTUserDataSourceUpdate) { - FSTAssert(context.path->size() > 0, - @"FieldValue.delete() at the top level should have already been handled."); + HARD_ASSERT(context.path->size() > 0, + "FieldValue.delete() at the top level should have already been handled."); FSTThrowInvalidArgument( @"FieldValue.delete() can only appear at the top level of your update data%@", [context fieldDescription]); @@ -808,7 +808,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { // Return nil so this value is omitted from the parsed result. return nil; } else { - FSTFail(@"Unknown FIRFieldValue type: %@", NSStringFromClass([input class])); + HARD_FAIL("Unknown FIRFieldValue type: %s", NSStringFromClass([input class])); } } else { @@ -828,8 +828,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { path:absl::make_unique<FieldPath>(FieldPath::EmptyPath())]; FSTFieldValue *parsedElement = [self parseData:element context:[context contextForArrayIndex:i]]; - FSTAssert(parsedElement && context.fieldTransforms->size() == 0, - @"Failed to properly parse array transform element: %@", element); + HARD_ASSERT(parsedElement && context.fieldTransforms->size() == 0, + "Failed to properly parse array transform element: %s", element); results.push_back(parsedElement); } return results; diff --git a/Firestore/Source/Core/FSTEventManager.mm b/Firestore/Source/Core/FSTEventManager.mm index b02fc5f..69d5ef1 100644 --- a/Firestore/Source/Core/FSTEventManager.mm +++ b/Firestore/Source/Core/FSTEventManager.mm @@ -19,7 +19,8 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Core/FSTSyncEngine.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Util/FSTAssert.h" + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" NS_ASSUME_NONNULL_BEGIN @@ -50,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN } - (instancetype)init { - FSTFail(@"FSTListenOptions init not supported"); + HARD_FAIL("FSTListenOptions init not supported"); return nil; } @@ -116,8 +117,8 @@ NS_ASSUME_NONNULL_BEGIN } - (void)queryDidChangeViewSnapshot:(FSTViewSnapshot *)snapshot { - FSTAssert(snapshot.documentChanges.count > 0 || snapshot.syncStateChanged, - @"We got a new snapshot with no changes?"); + HARD_ASSERT(snapshot.documentChanges.count > 0 || snapshot.syncStateChanged, + "We got a new snapshot with no changes?"); if (!self.options.includeDocumentMetadataChanges) { // Remove the metadata-only changes. @@ -161,8 +162,8 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)shouldRaiseInitialEventForSnapshot:(FSTViewSnapshot *)snapshot onlineState:(FSTOnlineState)onlineState { - FSTAssert(!self.raisedInitialEvent, - @"Determining whether to raise initial event, but already had first event."); + HARD_ASSERT(!self.raisedInitialEvent, + "Determining whether to raise initial event, but already had first event."); // Always raise the first event when we're synced if (!snapshot.fromCache) { @@ -175,7 +176,7 @@ NS_ASSUME_NONNULL_BEGIN // Don't raise the event if we're online, aren't synced yet (checked // above) and are waiting for a sync. if (self.options.waitForSyncWhenOnline && maybeOnline) { - FSTAssert(snapshot.fromCache, @"Waiting for sync, but snapshot is not from cache."); + HARD_ASSERT(snapshot.fromCache, "Waiting for sync, but snapshot is not from cache."); return NO; } @@ -203,7 +204,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)raiseInitialEventForSnapshot:(FSTViewSnapshot *)snapshot { - FSTAssert(!self.raisedInitialEvent, @"Trying to raise initial events for second time"); + HARD_ASSERT(!self.raisedInitialEvent, "Trying to raise initial events for second time"); snapshot = [[FSTViewSnapshot alloc] initWithQuery:snapshot.query documents:snapshot.documents diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm index cede958..dc918d0 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.mm +++ b/Firestore/Source/Core/FSTFirestoreClient.mm @@ -42,14 +42,14 @@ #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -226,7 +226,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)userDidChange:(const User &)user { [self.workerDispatchQueue verifyIsCurrentQueue]; - FSTLog(@"User Changed: %s", user.uid().c_str()); + LOG_DEBUG("User Changed: %s", user.uid()); [self.syncEngine userDidChange:user]; } @@ -320,8 +320,8 @@ NS_ASSUME_NONNULL_BEGIN FSTView *view = [[FSTView alloc] initWithQuery:query.query remoteDocuments:DocumentKeySet{}]; FSTViewDocumentChanges *viewDocChanges = [view computeChangesWithDocuments:docs]; FSTViewChange *viewChange = [view applyChangesToDocuments:viewDocChanges]; - FSTAssert(viewChange.limboChanges.count == 0, - @"View returned limbo documents during local-only query execution."); + HARD_ASSERT(viewChange.limboChanges.count == 0, + "View returned limbo documents during local-only query execution."); FSTViewSnapshot *snapshot = viewChange.snapshot; FIRSnapshotMetadata *metadata = diff --git a/Firestore/Source/Core/FSTQuery.mm b/Firestore/Source/Core/FSTQuery.mm index 13ebadb..eb6d087 100644 --- a/Firestore/Source/Core/FSTQuery.mm +++ b/Firestore/Source/Core/FSTQuery.mm @@ -23,11 +23,11 @@ #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -62,7 +62,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe case FSTRelationFilterOperatorArrayContains: return @"array_contains"; default: - FSTCFail(@"Unknown FSTRelationFilterOperator %lu", (unsigned long)filterOperator); + HARD_FAIL("Unknown FSTRelationFilterOperator %s", filterOperator); } } @@ -152,10 +152,10 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe - (BOOL)matchesDocument:(FSTDocument *)document { if (_field.IsKeyFieldPath()) { - FSTAssert([self.value isKindOfClass:[FSTReferenceValue class]], - @"Comparing on key, but filter value not a FSTReferenceValue."); - FSTAssert(self.filterOperator != FSTRelationFilterOperatorArrayContains, - @"arrayContains queries don't make sense on document keys."); + HARD_ASSERT([self.value isKindOfClass:[FSTReferenceValue class]], + "Comparing on key, but filter value not a FSTReferenceValue."); + HARD_ASSERT(self.filterOperator != FSTRelationFilterOperatorArrayContains, + "arrayContains queries don't make sense on document keys."); FSTReferenceValue *refValue = (FSTReferenceValue *)self.value; NSComparisonResult comparison = FSTDocumentKeyComparator(document.key, refValue.value); return [self matchesComparison:comparison]; @@ -214,7 +214,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe case FSTRelationFilterOperatorGreaterThan: return comparison == NSOrderedDescending; default: - FSTFail(@"Unknown operator: %ld", (long)self.filterOperator); + HARD_FAIL("Unknown operator: %s", self.filterOperator); } } @@ -354,8 +354,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } 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."); + HARD_ASSERT(value1 != nil && value2 != nil, + "Trying to compare documents on fields that don't exist."); result = [value1 compare:value2]; } if (!self.isAscending) { @@ -433,21 +433,22 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe - (BOOL)sortsBeforeDocument:(FSTDocument *)document usingSortOrder:(NSArray<FSTSortOrder *> *)sortOrder { - FSTAssert(self.position.count <= sortOrder.count, - @"FSTIndexPosition has more components than provided sort order."); + HARD_ASSERT(self.position.count <= sortOrder.count, + "FSTIndexPosition has more components than provided sort order."); __block NSComparisonResult result = NSOrderedSame; [self.position enumerateObjectsUsingBlock:^(FSTFieldValue *fieldValue, NSUInteger idx, BOOL *stop) { FSTSortOrder *sortOrderComponent = sortOrder[idx]; NSComparisonResult comparison; if (sortOrderComponent.field == FieldPath::KeyFieldPath()) { - FSTAssert([fieldValue isKindOfClass:[FSTReferenceValue class]], - @"FSTBound has a non-key value where the key path is being used %@", fieldValue); + HARD_ASSERT([fieldValue isKindOfClass:[FSTReferenceValue class]], + "FSTBound has a non-key value where the key path is being used %s", fieldValue); 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."); + HARD_ASSERT(docValue != nil, + "Field should exist since document matched the orderBy already."); comparison = [fieldValue compare:docValue]; } @@ -600,10 +601,9 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe ]; } } else { - FSTAssert(!inequalityField || *inequalityField == *firstSortOrderField, - @"First orderBy %s should match inequality field %s.", - firstSortOrderField->CanonicalString().c_str(), - inequalityField->CanonicalString().c_str()); + HARD_ASSERT(!inequalityField || *inequalityField == *firstSortOrderField, + "First orderBy %s should match inequality field %s.", + firstSortOrderField->CanonicalString(), inequalityField->CanonicalString()); __block BOOL foundKeyOrder = NO; @@ -631,7 +631,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } - (instancetype)queryByAddingFilter:(id<FSTFilter>)filter { - FSTAssert(!DocumentKey::IsDocumentKey(_path), @"No filtering allowed for document query"); + HARD_ASSERT(!DocumentKey::IsDocumentKey(_path), "No filtering allowed for document query"); const FieldPath *newInequalityField = nullptr; if ([filter isKindOfClass:[FSTRelationFilter class]] && @@ -639,9 +639,9 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe newInequalityField = &filter.field; } const FieldPath *queryInequalityField = [self inequalityFilterField]; - FSTAssert( + HARD_ASSERT( !queryInequalityField || !newInequalityField || *queryInequalityField == *newInequalityField, - @"Query must only have one inequality field."); + "Query must only have one inequality field."); return [[FSTQuery alloc] initWithPath:self.path filterBy:[self.filters arrayByAddingObject:filter] @@ -652,7 +652,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } - (instancetype)queryByAddingSortOrder:(FSTSortOrder *)sortOrder { - FSTAssert(!DocumentKey::IsDocumentKey(_path), @"No ordering is allowed for a document query."); + HARD_ASSERT(!DocumentKey::IsDocumentKey(_path), "No ordering is allowed for a document query."); // TODO(klimt): Validate that the same key isn't added twice. return [[FSTQuery alloc] initWithPath:self.path @@ -709,7 +709,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } didCompareOnKeyField = didCompareOnKeyField || orderBy.field == FieldPath::KeyFieldPath(); } - FSTAssert(didCompareOnKeyField, @"sortOrder of query did not include key ordering"); + HARD_ASSERT(didCompareOnKeyField, "sortOrder of query did not include key ordering"); return NSOrderedSame; }; } diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm index ed97d6c..7d0c1a3 100644 --- a/Firestore/Source/Core/FSTSyncEngine.mm +++ b/Firestore/Source/Core/FSTSyncEngine.mm @@ -38,14 +38,14 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" using firebase::firestore::auth::HashUser; using firebase::firestore::auth::User; @@ -183,7 +183,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; - (FSTTargetID)listenToQuery:(FSTQuery *)query { [self assertDelegateExistsForSelector:_cmd]; - FSTAssert(self.queryViewsByQuery[query] == nil, @"We already listen to query: %@", query); + HARD_ASSERT(self.queryViewsByQuery[query] == nil, "We already listen to query: %s", query); FSTQueryData *queryData = [self.localStore allocateQuery:query]; FSTDocumentDictionary *docs = [self.localStore executeQuery:query]; @@ -192,8 +192,8 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:std::move(remoteKeys)]; FSTViewDocumentChanges *viewDocChanges = [view computeChangesWithDocuments:docs]; FSTViewChange *viewChange = [view applyChangesToDocuments:viewDocChanges]; - FSTAssert(viewChange.limboChanges.count == 0, - @"View returned limbo docs before target ack from the server."); + HARD_ASSERT(viewChange.limboChanges.count == 0, + "View returned limbo docs before target ack from the server."); FSTQueryView *queryView = [[FSTQueryView alloc] initWithQuery:query targetID:queryData.targetID @@ -211,7 +211,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; [self assertDelegateExistsForSelector:_cmd]; FSTQueryView *queryView = self.queryViewsByQuery[query]; - FSTAssert(queryView, @"Trying to stop listening to a query not found"); + HARD_ASSERT(queryView, "Trying to stop listening to a query not found"); [self.localStore releaseQuery:query]; [self.remoteStore stopListeningToTargetID:queryView.targetID]; @@ -257,7 +257,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; updateBlock:(FSTTransactionBlock)updateBlock completion:(FSTVoidIDErrorBlock)completion { [workerDispatchQueue verifyIsCurrentQueue]; - FSTAssert(retries >= 0, @"Got negative number of retries for transaction"); + HARD_ASSERT(retries >= 0, "Got negative number of retries for transaction"); FSTTransaction *transaction = [self.remoteStore transaction]; updateBlock(transaction, ^(id _Nullable result, NSError *_Nullable error) { [workerDispatchQueue dispatchAsync:^{ @@ -303,7 +303,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; const auto iter = self->_limboKeysByTarget.find([targetID intValue]); if (iter == self->_limboKeysByTarget.end()) { FSTQueryView *qv = self.queryViewsByTarget[targetID]; - FSTAssert(qv, @"Missing queryview for non-limbo query: %i", [targetID intValue]); + HARD_ASSERT(qv, "Missing queryview for non-limbo query: %s", [targetID intValue]); [targetChange.mapping filterUpdatesUsingExistingKeys:qv.view.syncedDocuments]; } else { [remoteEvent synthesizeDeleteForLimboTargetChange:targetChange key:iter->second]; @@ -319,8 +319,8 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; [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."); + HARD_ASSERT(viewChange.limboChanges.count == 0, + "OnlineState should not affect limbo documents."); if (viewChange.snapshot) { [newViewSnapshots addObject:viewChange.snapshot]; } @@ -360,7 +360,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; [self applyRemoteEvent:event]; } else { FSTQueryView *queryView = self.queryViewsByTarget[@(targetID)]; - FSTAssert(queryView, @"Unknown targetId: %d", targetID); + HARD_ASSERT(queryView, "Unknown targetId: %s", targetID); [self.localStore releaseQuery:queryView.query]; [self removeAndCleanupQuery:queryView]; [self.delegate handleError:error forQuery:queryView.query]; @@ -408,8 +408,8 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; } - (void)assertDelegateExistsForSelector:(SEL)methodSelector { - FSTAssert(self.delegate, @"Tried to call '%@' before delegate was registered.", - NSStringFromSelector(methodSelector)); + HARD_ASSERT(self.delegate, "Tried to call '%s' before delegate was registered.", + NSStringFromSelector(methodSelector)); } - (void)removeAndCleanupQuery:(FSTQueryView *)queryView { @@ -470,12 +470,12 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; break; case FSTLimboDocumentChangeTypeRemoved: - FSTLog(@"Document no longer in limbo: %s", limboChange.key.ToString().c_str()); + LOG_DEBUG("Document no longer in limbo: %s", limboChange.key.ToString()); [self.limboDocumentRefs removeReferenceToKey:limboChange.key forID:targetID]; break; default: - FSTFail(@"Unknown limbo change type: %ld", (long)limboChange.type); + HARD_FAIL("Unknown limbo change type: %s", limboChange.type); } } [self garbageCollectLimboDocuments]; @@ -485,7 +485,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1; DocumentKey key{limboChange.key}; if (_limboTargetsByKey.find(key) == _limboTargetsByKey.end()) { - FSTLog(@"New document in limbo: %s", key.ToString().c_str()); + LOG_DEBUG("New document in limbo: %s", key.ToString()); TargetId limboTargetID = _targetIdGenerator.NextId(); FSTQuery *query = [FSTQuery queryWithPath:key.path()]; FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query diff --git a/Firestore/Source/Core/FSTTransaction.mm b/Firestore/Source/Core/FSTTransaction.mm index 5c36b20..da5cf71 100644 --- a/Firestore/Source/Core/FSTTransaction.mm +++ b/Firestore/Source/Core/FSTTransaction.mm @@ -26,13 +26,13 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTDatastore.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::Precondition; @@ -79,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN * writes sent to the backend. */ - (BOOL)recordVersionForDocument:(FSTMaybeDocument *)doc error:(NSError **)error { - FSTAssert(error != nil, @"nil error parameter"); + HARD_ASSERT(error != nil, "nil error parameter"); *error = nil; SnapshotVersion docVersion = doc.version; if ([doc isKindOfClass:[FSTDeletedDocument class]]) { @@ -189,7 +189,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *error = nil; const Precondition precondition = [self preconditionForUpdateWithDocumentKey:key error:&error]; if (precondition.IsNone()) { - FSTAssert(error, @"Got nil precondition, but error was not set"); + HARD_ASSERT(error, "Got nil precondition, but error was not set"); self.lastWriteError = error; } else { [self writeMutations:[data mutationsWithKey:key precondition:precondition]]; diff --git a/Firestore/Source/Core/FSTView.mm b/Firestore/Source/Core/FSTView.mm index d254a82..63efd4e 100644 --- a/Firestore/Source/Core/FSTView.mm +++ b/Firestore/Source/Core/FSTView.mm @@ -24,9 +24,9 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; @@ -235,8 +235,8 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang newDoc = (FSTDocument *)maybeNewDoc; } if (newDoc) { - FSTAssert([key isEqual:newDoc.key], @"Mismatching key in document changes: %@ != %s", key, - newDoc.key.ToString().c_str()); + HARD_ASSERT([key isEqual:newDoc.key], "Mismatching key in document changes: %s != %s", key, + newDoc.key.ToString()); if (![self.query matchesDocument:newDoc]) { newDoc = nil; } @@ -300,8 +300,8 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang } } - FSTAssert(!needsRefill || !previousChanges, - @"View was refilled using docs that themselves needed refilling."); + HARD_ASSERT(!needsRefill || !previousChanges, + "View was refilled using docs that themselves needed refilling."); return [[FSTViewDocumentChanges alloc] initWithDocumentSet:newDocumentSet changeSet:changeSet @@ -315,7 +315,7 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges targetChange:(nullable FSTTargetChange *)targetChange { - FSTAssert(!docChanges.needsRefill, @"Cannot apply changes that need a refill"); + HARD_ASSERT(!docChanges.needsRefill, "Cannot apply changes that need a refill"); FSTDocumentSet *oldDocuments = self.documentSet; self.documentSet = docChanges.documentSet; @@ -476,7 +476,7 @@ static inline int DocumentViewChangeTypePosition(FSTDocumentViewChangeType chang // equivalently. return 2; default: - FSTCFail(@"Unknown FSTDocumentViewChangeType %lu", (unsigned long)changeType); + HARD_FAIL("Unknown FSTDocumentViewChangeType %s", changeType); } } diff --git a/Firestore/Source/Core/FSTViewSnapshot.mm b/Firestore/Source/Core/FSTViewSnapshot.mm index ae366fb..ac5b376 100644 --- a/Firestore/Source/Core/FSTViewSnapshot.mm +++ b/Firestore/Source/Core/FSTViewSnapshot.mm @@ -19,10 +19,10 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::model::DocumentKey; @@ -154,8 +154,7 @@ NS_ASSUME_NONNULL_BEGIN // Removed -> Modified // Metadata -> Added // Removed -> Metadata - FSTFail(@"Unsupported combination of changes: %ld after %ld", (long)change.type, - (long)oldChange.type); + HARD_FAIL("Unsupported combination of changes: %s after %s", change.type, oldChange.type); } } diff --git a/Firestore/Source/Local/FSTLevelDB.mm b/Firestore/Source/Local/FSTLevelDB.mm index bc2f2eb..321d47a 100644 --- a/Firestore/Source/Local/FSTLevelDB.mm +++ b/Firestore/Source/Local/FSTLevelDB.mm @@ -24,13 +24,12 @@ #import "Firestore/Source/Local/FSTLevelDBQueryCache.h" #import "Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTLogger.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" #include "leveldb/db.h" @@ -133,7 +132,7 @@ using leveldb::WriteOptions; #pragma mark - Startup - (BOOL)start:(NSError **)error { - FSTAssert(!self.isStarted, @"FSTLevelDB double-started!"); + HARD_ASSERT(!self.isStarted, "FSTLevelDB double-started!"); self.started = YES; NSString *directory = self.directory; if (![self ensureDirectory:directory error:error]) { @@ -208,7 +207,7 @@ using leveldb::WriteOptions; } - (LevelDbTransaction *)currentTransaction { - FSTAssert(_transaction != nullptr, @"Attempting to access transaction before one has started"); + HARD_ASSERT(_transaction != nullptr, "Attempting to access transaction before one has started"); return _transaction.get(); } @@ -227,18 +226,18 @@ using leveldb::WriteOptions; } - (void)startTransaction:(absl::string_view)label { - FSTAssert(_transaction == nullptr, @"Starting a transaction while one is already outstanding"); + HARD_ASSERT(_transaction == nullptr, "Starting a transaction while one is already outstanding"); _transaction = absl::make_unique<LevelDbTransaction>(_ptr.get(), label); } - (void)commitTransaction { - FSTAssert(_transaction != nullptr, @"Committing a transaction before one is started"); + HARD_ASSERT(_transaction != nullptr, "Committing a transaction before one is started"); _transaction->Commit(); _transaction.reset(); } - (void)shutdown { - FSTAssert(self.isStarted, @"FSTLevelDB shutdown without start!"); + HARD_ASSERT(self.isStarted, "FSTLevelDB shutdown without start!"); self.started = NO; _ptr.reset(); } diff --git a/Firestore/Source/Local/FSTLevelDBMigrations.mm b/Firestore/Source/Local/FSTLevelDBMigrations.mm index fefd0f7..bd72c97 100644 --- a/Firestore/Source/Local/FSTLevelDBMigrations.mm +++ b/Firestore/Source/Local/FSTLevelDBMigrations.mm @@ -21,8 +21,8 @@ #import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h" #import "Firestore/Source/Local/FSTLevelDBKey.h" #import "Firestore/Source/Local/FSTLevelDBQueryCache.h" -#import "Firestore/Source/Util/FSTAssert.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/strings/match.h" #include "leveldb/write_batch.h" @@ -80,8 +80,8 @@ static void AddTargetCount(LevelDbTransaction *transaction) { FSTPBTargetGlobal *targetGlobal = [FSTLevelDBQueryCache readTargetMetadataWithTransaction:transaction]; - FSTCAssert(targetGlobal != nil, - @"We should have a metadata row as it was added in an earlier migration"); + HARD_ASSERT(targetGlobal != nil, + "We should have a metadata row as it was added in an earlier migration"); targetGlobal.targetCount = count; transaction->Put([FSTLevelDBTargetGlobalKey key], targetGlobal); } diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm index 2c9f68d..3b4687c 100644 --- a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm +++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm @@ -27,12 +27,12 @@ #import "Firestore/Source/Local/FSTLocalSerializer.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/src/firebase/firestore/util/string_util.h" #include "absl/strings/match.h" @@ -120,7 +120,7 @@ using leveldb::WriteOptions; } else { FSTBatchID lastAcked = metadata.lastAcknowledgedBatchId; if (lastAcked >= nextBatchID) { - FSTAssert([self isEmpty], @"Reset nextBatchID is only possible when the queue is empty"); + HARD_ASSERT([self isEmpty], "Reset nextBatchID is only possible when the queue is empty"); lastAcked = kFSTBatchIDUnknown; metadata.lastAcknowledgedBatchId = lastAcked; @@ -184,7 +184,7 @@ using leveldb::WriteOptions; // In all the cases above there was at least one row for the current user and each case has // set things up such that iterator points to it. if (![rowKey decodeKey:it->key()]) { - FSTFail(@"There should have been a key previous to %s", userEnd.c_str()); + HARD_FAIL("There should have been a key previous to %s", userEnd); } if (rowKey.batchID > maxBatchID) { @@ -215,8 +215,8 @@ using leveldb::WriteOptions; - (void)acknowledgeBatch:(FSTMutationBatch *)batch streamToken:(nullable NSData *)streamToken { FSTBatchID batchID = batch.batchID; - FSTAssert(batchID > self.highestAcknowledgedBatchID, - @"Mutation batchIDs must be acknowledged in order"); + HARD_ASSERT(batchID > self.highestAcknowledgedBatchID, + "Mutation batchIDs must be acknowledged in order"); FSTPBMutationQueue *metadata = self.metadata; metadata.lastAcknowledgedBatchId = batchID; @@ -248,8 +248,7 @@ using leveldb::WriteOptions; } else if (status.IsNotFound()) { return nil; } else { - FSTFail(@"metadataForKey: failed loading key %s with status: %s", key.c_str(), - status.ToString().c_str()); + HARD_FAIL("metadataForKey: failed loading key %s with status: %s", key, status.ToString()); } } @@ -290,8 +289,8 @@ using leveldb::WriteOptions; if (status.IsNotFound()) { return nil; } - FSTFail(@"Lookup mutation batch (%@, %d) failed with status: %s", self.userID, batchID, - status.ToString().c_str()); + HARD_FAIL("Lookup mutation batch (%s, %s) failed with status: %s", self.userID, batchID, + status.ToString()); } return [self decodedMutationBatch:value]; @@ -318,7 +317,7 @@ using leveldb::WriteOptions; return nil; } - FSTAssert(rowKey.batchID >= nextBatchID, @"Should have found mutation after %d", nextBatchID); + HARD_ASSERT(rowKey.batchID >= nextBatchID, "Should have found mutation after %s", nextBatchID); return [self decodedMutationBatch:it->value()]; } @@ -385,9 +384,9 @@ using leveldb::WriteOptions; if (mutationIterator->Valid()) { foundKeyDescription = [FSTLevelDBKey descriptionForKey:mutationIterator->key()]; } - FSTFail( - @"Dangling document-mutation reference found: " - @"%@ points to %@; seeking there found %@", + HARD_FAIL( + "Dangling document-mutation reference found: " + "%s points to %s; seeking there found %s", [FSTLevelDBKey descriptionForKey:indexIterator->key()], [FSTLevelDBKey descriptionForKey:mutationKey], foundKeyDescription); } @@ -398,7 +397,7 @@ using leveldb::WriteOptions; } - (NSArray<FSTMutationBatch *> *)allMutationBatchesAffectingQuery:(FSTQuery *)query { - FSTAssert(![query isDocumentQuery], @"Document queries shouldn't go down this path"); + HARD_ASSERT(![query isDocumentQuery], "Document queries shouldn't go down this path"); NSString *userID = self.userID; const ResourcePath &queryPath = query.path; @@ -460,9 +459,9 @@ using leveldb::WriteOptions; if (mutationIterator->Valid()) { foundKeyDescription = [FSTLevelDBKey descriptionForKey:mutationIterator->key()]; } - FSTFail( - @"Dangling document-mutation reference found: " - @"Missing batch %@; seeking there found %@", + HARD_FAIL( + "Dangling document-mutation reference found: " + "Missing batch %s; seeking there found %s", [FSTLevelDBKey descriptionForKey:mutationKey], foundKeyDescription); } @@ -497,12 +496,12 @@ using leveldb::WriteOptions; // As a sanity check, verify that the mutation batch exists before deleting it. checkIterator->Seek(key); - FSTAssert(checkIterator->Valid(), @"Mutation batch %@ did not exist", - [FSTLevelDBKey descriptionForKey:key]); + HARD_ASSERT(checkIterator->Valid(), "Mutation batch %s did not exist", + [FSTLevelDBKey descriptionForKey:key]); - FSTAssert(key == checkIterator->key(), @"Mutation batch %@ not found; found %@", - [FSTLevelDBKey descriptionForKey:key], - [FSTLevelDBKey descriptionForKey:checkIterator->key()]); + HARD_ASSERT(key == checkIterator->key(), "Mutation batch %s not found; found %s", + [FSTLevelDBKey descriptionForKey:key], + [FSTLevelDBKey descriptionForKey:checkIterator->key()]); _db.currentTransaction->Delete(key); @@ -538,10 +537,10 @@ using leveldb::WriteOptions; [danglingMutationReferences addObject:[FSTLevelDBKey descriptionForKey:indexIterator->key()]]; } - FSTAssert(danglingMutationReferences.count == 0, - @"Document leak -- detected dangling mutation references when queue " - @"is empty. Dangling keys: %@", - danglingMutationReferences); + HARD_ASSERT(danglingMutationReferences.count == 0, + "Document leak -- detected dangling mutation references when queue " + "is empty. Dangling keys: %s", + danglingMutationReferences); } - (std::string)mutationKeyForBatch:(FSTMutationBatch *)batch { @@ -560,7 +559,7 @@ using leveldb::WriteOptions; NSError *error; FSTPBMutationQueue *proto = [FSTPBMutationQueue parseFromData:data error:&error]; if (!proto) { - FSTFail(@"FSTPBMutationQueue failed to parse: %@", error); + HARD_FAIL("FSTPBMutationQueue failed to parse: %s", error); } return proto; @@ -574,7 +573,7 @@ using leveldb::WriteOptions; NSError *error; FSTPBWriteBatch *proto = [FSTPBWriteBatch parseFromData:data error:&error]; if (!proto) { - FSTFail(@"FSTPBMutationBatch failed to parse: %@", error); + HARD_FAIL("FSTPBMutationBatch failed to parse: %s", error); } return [self.serializer decodedMutationBatch:proto]; diff --git a/Firestore/Source/Local/FSTLevelDBQueryCache.mm b/Firestore/Source/Local/FSTLevelDBQueryCache.mm index 68b6f98..f28370a 100644 --- a/Firestore/Source/Local/FSTLevelDBQueryCache.mm +++ b/Firestore/Source/Local/FSTLevelDBQueryCache.mm @@ -26,10 +26,10 @@ #import "Firestore/Source/Local/FSTLevelDBKey.h" #import "Firestore/Source/Local/FSTLocalSerializer.h" #import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/strings/match.h" NS_ASSUME_NONNULL_BEGIN @@ -70,8 +70,7 @@ using firebase::firestore::model::DocumentKeySet; 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()); + HARD_FAIL("metadataForKey: failed loading key %s with status: %s", key, status.ToString()); } NSData *data = @@ -80,7 +79,7 @@ using firebase::firestore::model::DocumentKeySet; NSError *error; FSTPBTargetGlobal *proto = [FSTPBTargetGlobal parseFromData:data error:&error]; if (!proto) { - FSTFail(@"FSTPBTargetGlobal failed to parse: %@", error); + HARD_FAIL("FSTPBTargetGlobal failed to parse: %s", error); } return proto; @@ -93,8 +92,7 @@ using firebase::firestore::model::DocumentKeySet; 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()); + HARD_FAIL("metadataForKey: failed loading key %s with status: %s", key, status.ToString()); } NSData *data = @@ -103,7 +101,7 @@ using firebase::firestore::model::DocumentKeySet; NSError *error; FSTPBTargetGlobal *proto = [FSTPBTargetGlobal parseFromData:data error:&error]; if (!proto) { - FSTFail(@"FSTPBTargetGlobal failed to parse: %@", error); + HARD_FAIL("FSTPBTargetGlobal failed to parse: %s", error); } return proto; @@ -111,7 +109,7 @@ using firebase::firestore::model::DocumentKeySet; - (instancetype)initWithDB:(FSTLevelDB *)db serializer:(FSTLocalSerializer *)serializer { if (self = [super init]) { - FSTAssert(db, @"db must not be NULL"); + HARD_ASSERT(db, "db must not be NULL"); _db = db; _serializer = serializer; } @@ -121,9 +119,9 @@ using firebase::firestore::model::DocumentKeySet; - (void)start { // TODO(gsoltis): switch this usage of ptr to currentTransaction FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db.ptr]; - FSTAssert( + HARD_ASSERT( metadata != nil, - @"Found nil metadata, expected schema to be at version 0 which ensures metadata existence"); + "Found nil metadata, expected schema to be at version 0 which ensures metadata existence"); _lastRemoteSnapshotVersion = [self.serializer decodedVersion:metadata.lastRemoteSnapshotVersion]; self.metadata = metadata; @@ -224,7 +222,7 @@ using firebase::firestore::model::DocumentKeySet; NSError *error; FSTPBTarget *proto = [FSTPBTarget parseFromData:data error:&error]; if (!proto) { - FSTFail(@"FSTPBTarget failed to parse: %@", error); + HARD_FAIL("FSTPBTarget failed to parse: %s", error); } return [self.serializer decodedQueryData:proto]; @@ -263,9 +261,9 @@ using firebase::firestore::model::DocumentKeySet; if (targetIterator->Valid()) { foundKeyDescription = [FSTLevelDBKey descriptionForKey:targetIterator->key()]; } - FSTFail( - @"Dangling query-target reference found: " - @"%@ points to %@; seeking there found %@", + HARD_FAIL( + "Dangling query-target reference found: " + "%s points to %s; seeking there found %s", [FSTLevelDBKey descriptionForKey:indexItererator->key()], [FSTLevelDBKey descriptionForKey:targetKey], foundKeyDescription); } diff --git a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm index f655e3a..534d2a4 100644 --- a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm +++ b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm @@ -26,10 +26,10 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentDictionary.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "leveldb/db.h" #include "leveldb/write_batch.h" @@ -77,8 +77,8 @@ using leveldb::Status; } else if (status.ok()) { return [self decodeMaybeDocument:value withKey:documentKey]; } else { - FSTFail(@"Fetch document for key (%s) failed with status: %s", documentKey.ToString().c_str(), - status.ToString().c_str()); + HARD_FAIL("Fetch document for key (%s) failed with status: %s", documentKey.ToString(), + status.ToString()); } } @@ -118,13 +118,13 @@ using leveldb::Status; NSError *error; FSTPBMaybeDocument *proto = [FSTPBMaybeDocument parseFromData:data error:&error]; if (!proto) { - FSTFail(@"FSTPBMaybeDocument failed to parse: %@", error); + HARD_FAIL("FSTPBMaybeDocument failed to parse: %s", error); } FSTMaybeDocument *maybeDocument = [self.serializer decodedMaybeDocument:proto]; - FSTAssert([maybeDocument.key isEqualToKey:documentKey], - @"Read document has key (%s) instead of expected key (%s).", - maybeDocument.key.ToString().c_str(), documentKey.ToString().c_str()); + HARD_ASSERT([maybeDocument.key isEqualToKey:documentKey], + "Read document has key (%s) instead of expected key (%s).", + maybeDocument.key.ToString(), documentKey.ToString()); return maybeDocument; } diff --git a/Firestore/Source/Local/FSTLocalDocumentsView.mm b/Firestore/Source/Local/FSTLocalDocumentsView.mm index 471840a..48c963e 100644 --- a/Firestore/Source/Local/FSTLocalDocumentsView.mm +++ b/Firestore/Source/Local/FSTLocalDocumentsView.mm @@ -23,11 +23,11 @@ #import "Firestore/Source/Model/FSTDocumentDictionary.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::ResourcePath; @@ -178,7 +178,7 @@ NS_ASSUME_NONNULL_BEGIN } else if ([mutatedDoc isKindOfClass:[FSTDocument class]]) { result = [result dictionaryBySettingObject:(FSTDocument *)mutatedDoc forKey:key]; } else { - FSTFail(@"Unknown document: %@", mutatedDoc); + HARD_FAIL("Unknown document: %s", mutatedDoc); } }]; return result; diff --git a/Firestore/Source/Local/FSTLocalSerializer.mm b/Firestore/Source/Local/FSTLocalSerializer.mm index 2c5ab4d..662419a 100644 --- a/Firestore/Source/Local/FSTLocalSerializer.mm +++ b/Firestore/Source/Local/FSTLocalSerializer.mm @@ -29,11 +29,11 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/include/firebase/firestore/timestamp.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::Timestamp; using firebase::firestore::model::DocumentKey; @@ -64,7 +64,7 @@ using firebase::firestore::model::SnapshotVersion; } else if ([document isKindOfClass:[FSTDocument class]]) { proto.document = [self encodedDocument:(FSTDocument *)document]; } else { - FSTFail(@"Unknown document type %@", NSStringFromClass([document class])); + HARD_FAIL("Unknown document type %s", NSStringFromClass([document class])); } return proto; @@ -79,7 +79,7 @@ using firebase::firestore::model::SnapshotVersion; return [self decodedDeletedDocument:proto.noDocument]; default: - FSTFail(@"Unknown MaybeDocument %@", proto); + HARD_FAIL("Unknown MaybeDocument %s", proto); } } @@ -164,9 +164,9 @@ using firebase::firestore::model::SnapshotVersion; - (FSTPBTarget *)encodedQueryData:(FSTQueryData *)queryData { FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - FSTAssert(queryData.purpose == FSTQueryPurposeListen, - @"only queries with purpose %lu may be stored, got %lu", - (unsigned long)FSTQueryPurposeListen, (unsigned long)queryData.purpose); + HARD_ASSERT(queryData.purpose == FSTQueryPurposeListen, + "only queries with purpose %s may be stored, got %s", FSTQueryPurposeListen, + queryData.purpose); FSTPBTarget *proto = [FSTPBTarget message]; proto.targetId = queryData.targetID; @@ -203,7 +203,7 @@ using firebase::firestore::model::SnapshotVersion; break; default: - FSTFail(@"Unknown Target.targetType %" PRId32, target.targetTypeOneOfCase); + HARD_FAIL("Unknown Target.targetType %s", target.targetTypeOneOfCase); } return [[FSTQueryData alloc] initWithQuery:query diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 0d6a785..7469c71 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -36,13 +36,13 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTLogger.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" using firebase::firestore::auth::User; using firebase::firestore::core::TargetIdGenerator; @@ -236,10 +236,10 @@ NS_ASSUME_NONNULL_BEGIN - (FSTMaybeDocumentDictionary *)rejectBatchID:(FSTBatchID)batchID { return self.persistence.run("Reject batch", [&]() -> FSTMaybeDocumentDictionary * { FSTMutationBatch *toReject = [self.mutationQueue lookupMutationBatch:batchID]; - FSTAssert(toReject, @"Attempt to reject nonexistent batch!"); + HARD_ASSERT(toReject, "Attempt to reject nonexistent batch!"); FSTBatchID lastAcked = [self.mutationQueue highestAcknowledgedBatchID]; - FSTAssert(batchID > lastAcked, @"Acknowledged batches can't be rejected."); + HARD_ASSERT(batchID > lastAcked, "Acknowledged batches can't be rejected."); DocumentKeySet affected = [self removeMutationBatch:toReject]; @@ -304,7 +304,7 @@ NS_ASSUME_NONNULL_BEGIN [queryCache addMatchingKeys:update.addedDocuments forTargetID:targetID]; } else { - FSTFail(@"Unknown mapping type: %@", mapping); + HARD_FAIL("Unknown mapping type: %s", mapping); } } }]; @@ -324,11 +324,11 @@ NS_ASSUME_NONNULL_BEGIN SnapshotVersion{doc.version} >= SnapshotVersion{existingDoc.version}) { [self.remoteDocumentCache addEntry:doc]; } else { - FSTLog( - @"FSTLocalStore Ignoring outdated watch update for %s. " - "Current version: %s Watch version: %s", - key.ToString().c_str(), existingDoc.version.timestamp().ToString().c_str(), - doc.version.timestamp().ToString().c_str()); + LOG_DEBUG( + "FSTLocalStore Ignoring outdated watch update for %s. " + "Current version: %s Watch version: %s", + key.ToString(), existingDoc.version.timestamp().ToString(), + doc.version.timestamp().ToString()); } // The document might be garbage because it was unreferenced by everything. @@ -345,10 +345,9 @@ NS_ASSUME_NONNULL_BEGIN const SnapshotVersion &lastRemoteVersion = [self.queryCache lastRemoteSnapshotVersion]; const SnapshotVersion &remoteVersion = remoteEvent.snapshotVersion; if (remoteVersion != SnapshotVersion::None()) { - FSTAssert(remoteVersion >= lastRemoteVersion, - @"Watch stream reverted to previous snapshot?? (%s < %s)", - remoteVersion.timestamp().ToString().c_str(), - lastRemoteVersion.timestamp().ToString().c_str()); + HARD_ASSERT(remoteVersion >= lastRemoteVersion, + "Watch stream reverted to previous snapshot?? (%s < %s)", + remoteVersion.timestamp().ToString(), lastRemoteVersion.timestamp().ToString()); [self.queryCache setLastRemoteSnapshotVersion:remoteVersion]; } @@ -369,7 +368,7 @@ NS_ASSUME_NONNULL_BEGIN FSTReferenceSet *localViewReferences = self.localViewReferences; for (FSTLocalViewChanges *view in viewChanges) { FSTQueryData *queryData = [self.queryCache queryDataForQuery:view.query]; - FSTAssert(queryData, @"Local view changes contain unallocated query."); + HARD_ASSERT(queryData, "Local view changes contain unallocated query."); FSTTargetID targetID = queryData.targetID; for (const DocumentKey &key : view.removedKeys) { [self->_persistence.referenceDelegate removeReference:key target:targetID]; @@ -409,8 +408,8 @@ NS_ASSUME_NONNULL_BEGIN }); // Sanity check to ensure that even when resuming a query it's not currently active. FSTBoxedTargetID *boxedTargetID = @(queryData.targetID); - FSTAssert(!self.targetIDs[boxedTargetID], @"Tried to allocate an already allocated query: %@", - query); + HARD_ASSERT(!self.targetIDs[boxedTargetID], "Tried to allocate an already allocated query: %s", + query); self.targetIDs[boxedTargetID] = queryData; return queryData; } @@ -418,7 +417,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)releaseQuery:(FSTQuery *)query { self.persistence.run("Release query", [&]() { FSTQueryData *queryData = [self.queryCache queryDataForQuery:query]; - FSTAssert(queryData, @"Tried to release nonexistent query: %@", query); + HARD_ASSERT(queryData, "Tried to release nonexistent query: %s", query); [self.localViewReferences removeReferencesForID:queryData.targetID]; if (self.garbageCollector.isEager) { @@ -530,14 +529,14 @@ NS_ASSUME_NONNULL_BEGIN FSTMaybeDocument *_Nullable doc = remoteDoc; auto ackVersionIter = versions.find(docKey); - FSTAssert(ackVersionIter != versions.end(), - @"docVersions should contain every doc in the write."); + HARD_ASSERT(ackVersionIter != versions.end(), + "docVersions should contain every doc in the write."); const SnapshotVersion &ackVersion = ackVersionIter->second; if (!doc || doc.version < ackVersion) { doc = [batch applyTo:doc documentKey:docKey mutationBatchResult:batchResult]; if (!doc) { - FSTAssert(!remoteDoc, @"Mutation batch %@ applied to document %@ resulted in nil.", batch, - remoteDoc); + HARD_ASSERT(!remoteDoc, "Mutation batch %s applied to document %s resulted in nil.", batch, + remoteDoc); } else { [self.remoteDocumentCache addEntry:doc]; } diff --git a/Firestore/Source/Local/FSTMemoryMutationQueue.mm b/Firestore/Source/Local/FSTMemoryMutationQueue.mm index e05ee64..8faf893 100644 --- a/Firestore/Source/Local/FSTMemoryMutationQueue.mm +++ b/Firestore/Source/Local/FSTMemoryMutationQueue.mm @@ -21,11 +21,11 @@ #import "Firestore/Source/Local/FSTMemoryPersistence.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/third_party/Immutable/FSTImmutableSortedSet.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::ResourcePath; @@ -102,8 +102,8 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, self.nextBatchID = 1; self.highestAcknowledgedBatchID = kFSTBatchIDUnknown; } - FSTAssert(self.highestAcknowledgedBatchID < self.nextBatchID, - @"highestAcknowledgedBatchID must be less than the nextBatchID"); + HARD_ASSERT(self.highestAcknowledgedBatchID < self.nextBatchID, + "highestAcknowledgedBatchID must be less than the nextBatchID"); } - (BOOL)isEmpty { @@ -120,16 +120,16 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, NSMutableArray<FSTMutationBatch *> *queue = self.queue; FSTBatchID batchID = batch.batchID; - FSTAssert(batchID > self.highestAcknowledgedBatchID, - @"Mutation batchIDs must be acknowledged in order"); + HARD_ASSERT(batchID > self.highestAcknowledgedBatchID, + "Mutation batchIDs must be acknowledged in order"); NSInteger batchIndex = [self indexOfExistingBatchID:batchID action:@"acknowledged"]; // Verify that the batch in the queue is the one to be acknowledged. FSTMutationBatch *check = queue[(NSUInteger)batchIndex]; - FSTAssert(batchID == check.batchID, @"Queue ordering failure: expected batch %d, got batch %d", - batchID, check.batchID); - FSTAssert(![check isTombstone], @"Can't acknowledge a previously removed batch"); + HARD_ASSERT(batchID == check.batchID, "Queue ordering failure: expected batch %s, got batch %s", + batchID, check.batchID); + HARD_ASSERT(![check isTombstone], "Can't acknowledge a previously removed batch"); self.highestAcknowledgedBatchID = batchID; self.lastStreamToken = streamToken; @@ -137,7 +137,7 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, - (FSTMutationBatch *)addMutationBatchWithWriteTime:(FIRTimestamp *)localWriteTime mutations:(NSArray<FSTMutation *> *)mutations { - FSTAssert(mutations.count > 0, @"Mutation batches should not be empty"); + HARD_ASSERT(mutations.count > 0, "Mutation batches should not be empty"); FSTBatchID batchID = self.nextBatchID; self.nextBatchID += 1; @@ -145,7 +145,8 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, NSMutableArray<FSTMutationBatch *> *queue = self.queue; if (queue.count > 0) { FSTMutationBatch *prior = queue[queue.count - 1]; - FSTAssert(prior.batchID < batchID, @"Mutation batchIDs must be monotonically increasing order"); + HARD_ASSERT(prior.batchID < batchID, + "Mutation batchIDs must be monotonically increasing order"); } FSTMutationBatch *batch = [[FSTMutationBatch alloc] initWithBatchID:batchID @@ -173,7 +174,7 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, } FSTMutationBatch *batch = queue[(NSUInteger)index]; - FSTAssert(batch.batchID == batchID, @"If found batch must match"); + HARD_ASSERT(batch.batchID == batchID, "If found batch must match"); return [batch isTombstone] ? nil : batch; } @@ -233,7 +234,7 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, } FSTMutationBatch *batch = [self lookupMutationBatch:reference.ID]; - FSTAssert(batch, @"Batches in the index must exist in the main table"); + HARD_ASSERT(batch, "Batches in the index must exist in the main table"); [result addObject:batch]; }; @@ -292,7 +293,7 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, - (void)removeMutationBatches:(NSArray<FSTMutationBatch *> *)batches { NSUInteger batchCount = batches.count; - FSTAssert(batchCount > 0, @"Should not remove mutations when none exist."); + HARD_ASSERT(batchCount > 0, "Should not remove mutations when none exist."); FSTBatchID firstBatchID = batches[0].batchID; @@ -302,7 +303,7 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, // Find the position of the first batch for removal. This need not be the first entry in the // queue. NSUInteger startIndex = [self indexOfExistingBatchID:firstBatchID action:@"removed"]; - FSTAssert(queue[startIndex].batchID == firstBatchID, @"Removed batches must exist in the queue"); + HARD_ASSERT(queue[startIndex].batchID == firstBatchID, "Removed batches must exist in the queue"); // Check that removed batches are contiguous (while excluding tombstones). NSUInteger batchIndex = 1; @@ -314,8 +315,8 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, continue; } - FSTAssert(batch.batchID == batches[batchIndex].batchID, - @"Removed batches must be contiguous in the queue"); + HARD_ASSERT(batch.batchID == batches[batchIndex].batchID, + "Removed batches must be contiguous in the queue"); batchIndex++; queueIndex++; } @@ -359,8 +360,8 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, - (void)performConsistencyCheck { if (self.queue.count == 0) { - FSTAssert([self.batchesByDocumentKey isEmpty], - @"Document leak -- detected dangling mutation references when queue is empty."); + HARD_ASSERT([self.batchesByDocumentKey isEmpty], + "Document leak -- detected dangling mutation references when queue is empty."); } } @@ -431,7 +432,7 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left, */ - (NSUInteger)indexOfExistingBatchID:(FSTBatchID)batchID action:(NSString *)action { NSInteger index = [self indexOfBatchID:batchID]; - FSTAssert(index >= 0 && index < self.queue.count, @"Batches must exist to be %@", action); + HARD_ASSERT(index >= 0 && index < self.queue.count, "Batches must exist to be %s", action); return (NSUInteger)index; } diff --git a/Firestore/Source/Local/FSTMemoryPersistence.mm b/Firestore/Source/Local/FSTMemoryPersistence.mm index 3466f3e..5e35aa4 100644 --- a/Firestore/Source/Local/FSTMemoryPersistence.mm +++ b/Firestore/Source/Local/FSTMemoryPersistence.mm @@ -21,9 +21,9 @@ #import "Firestore/Source/Local/FSTMemoryMutationQueue.h" #import "Firestore/Source/Local/FSTMemoryQueryCache.h" #import "Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::auth::HashUser; using firebase::firestore::auth::User; @@ -67,14 +67,14 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)start:(NSError **)error { // No durable state to read on startup. - FSTAssert(!self.isStarted, @"FSTMemoryPersistence double-started!"); + HARD_ASSERT(!self.isStarted, "FSTMemoryPersistence double-started!"); self.started = YES; return YES; } - (void)shutdown { // No durable state to ensure is closed on shutdown. - FSTAssert(self.isStarted, @"FSTMemoryPersistence shutdown without start!"); + HARD_ASSERT(self.isStarted, "FSTMemoryPersistence shutdown without start!"); self.started = NO; } diff --git a/Firestore/Source/Local/FSTPersistence.h b/Firestore/Source/Local/FSTPersistence.h index 417ff3f..a2ce76f 100644 --- a/Firestore/Source/Local/FSTPersistence.h +++ b/Firestore/Source/Local/FSTPersistence.h @@ -17,8 +17,9 @@ #import <Foundation/Foundation.h> #import "Firestore/Source/Core/FSTTypes.h" -#import "Firestore/Source/Util/FSTAssert.h" + #include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @class FSTDocumentKey; @protocol FSTMutationQueue; @@ -181,7 +182,7 @@ struct FSTTransactionRunner { typename std::enable_if<std::is_void<decltype(block())>::value, void>::type { __strong id<FSTTransactional> strongDb = _db; if (!strongDb && _expect_db) { - FSTCFail(@"Transaction runner accessed without underlying db when it expected one"); + HARD_FAIL("Transaction runner accessed without underlying db when it expected one"); } if (strongDb) { [strongDb startTransaction:label]; @@ -198,7 +199,7 @@ struct FSTTransactionRunner { using ReturnT = decltype(block()); __strong id<FSTTransactional> strongDb = _db; if (!strongDb && _expect_db) { - FSTCFail(@"Transaction runner accessed without underlying db when it expected one"); + HARD_FAIL("Transaction runner accessed without underlying db when it expected one"); } if (strongDb) { [strongDb startTransaction:label]; diff --git a/Firestore/Source/Model/FSTDocument.mm b/Firestore/Source/Model/FSTDocument.mm index 8c4c801..376075e 100644 --- a/Firestore/Source/Model/FSTDocument.mm +++ b/Firestore/Source/Model/FSTDocument.mm @@ -19,10 +19,10 @@ #include <utility> #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" diff --git a/Firestore/Source/Model/FSTDocumentKey.mm b/Firestore/Source/Model/FSTDocumentKey.mm index d29df86..ad3968e 100644 --- a/Firestore/Source/Model/FSTDocumentKey.mm +++ b/Firestore/Source/Model/FSTDocumentKey.mm @@ -20,9 +20,9 @@ #include <utility> #import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -53,8 +53,8 @@ NS_ASSUME_NONNULL_BEGIN /** Designated initializer. */ - (instancetype)initWithPath:(ResourcePath)path { - FSTAssert([FSTDocumentKey isDocumentKey:path], @"invalid document key path: %s", - path.CanonicalString().c_str()); + HARD_ASSERT([FSTDocumentKey isDocumentKey:path], "invalid document key path: %s", + path.CanonicalString()); if (self = [super init]) { _path = path; diff --git a/Firestore/Source/Model/FSTFieldValue.mm b/Firestore/Source/Model/FSTFieldValue.mm index 9e77d39..6a13511 100644 --- a/Firestore/Source/Model/FSTFieldValue.mm +++ b/Firestore/Source/Model/FSTFieldValue.mm @@ -21,12 +21,12 @@ #import "Firestore/Source/API/FIRGeoPoint+Internal.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -99,8 +99,8 @@ NS_ASSUME_NONNULL_BEGIN if (self.typeOrder > other.typeOrder) { return NSOrderedDescending; } else { - FSTAssert(self.typeOrder < other.typeOrder, - @"defaultCompare should not be used for values of same type."); + HARD_ASSERT(self.typeOrder < other.typeOrder, + "defaultCompare should not be used for values of same type."); return NSOrderedAscending; } } @@ -231,8 +231,8 @@ NS_ASSUME_NONNULL_BEGIN if ([other isKindOfClass:[FSTDoubleValue class]]) { return WrapCompare(thisDouble, ((FSTDoubleValue *)other).internalValue); } else { - FSTAssert([other isKindOfClass:[FSTIntegerValue class]], @"Unknown number value: %@", - other); + HARD_ASSERT([other isKindOfClass:[FSTIntegerValue class]], "Unknown number value: %s", + other); auto result = CompareMixedNumber(thisDouble, ((FSTIntegerValue *)other).internalValue); return static_cast<NSComparisonResult>(result); } @@ -241,7 +241,8 @@ NS_ASSUME_NONNULL_BEGIN if ([other isKindOfClass:[FSTIntegerValue class]]) { return WrapCompare(thisInt, ((FSTIntegerValue *)other).internalValue); } else { - FSTAssert([other isKindOfClass:[FSTDoubleValue class]], @"Unknown number value: %@", other); + HARD_ASSERT([other isKindOfClass:[FSTDoubleValue class]], "Unknown number value: %s", + other); double otherDouble = ((FSTDoubleValue *)other).internalValue; auto result = ReverseOrder(CompareMixedNumber(otherDouble, thisInt)); return static_cast<NSComparisonResult>(result); @@ -499,7 +500,7 @@ struct Comparator<NSString *> { case FSTServerTimestampBehaviorPrevious: return self.previousValue ? [self.previousValue valueWithOptions:options] : [NSNull null]; default: - FSTFail(@"Unexpected server timestamp option: %ld", (long)options.serverTimestampBehavior); + HARD_FAIL("Unexpected server timestamp option: %s", options.serverTimestampBehavior); } } @@ -825,7 +826,7 @@ static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, - (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value forPath:(const FieldPath &)fieldPath { - FSTAssert(fieldPath.size() > 0, @"Cannot set value with an empty path"); + HARD_ASSERT(fieldPath.size() > 0, "Cannot set value with an empty path"); NSString *childName = util::WrapNSString(fieldPath.first_segment()); if (fieldPath.size() == 1) { @@ -849,7 +850,7 @@ static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, } - (FSTObjectValue *)objectByDeletingPath:(const FieldPath &)fieldPath { - FSTAssert(fieldPath.size() > 0, @"Cannot delete an empty path"); + HARD_ASSERT(fieldPath.size() > 0, "Cannot delete an empty path"); NSString *childName = util::WrapNSString(fieldPath.first_segment()); if (fieldPath.size() == 1) { return [[FSTObjectValue alloc] diff --git a/Firestore/Source/Model/FSTMutation.mm b/Firestore/Source/Model/FSTMutation.mm index 82a535e..d124c78 100644 --- a/Firestore/Source/Model/FSTMutation.mm +++ b/Firestore/Source/Model/FSTMutation.mm @@ -25,7 +25,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -34,6 +33,7 @@ #include "Firestore/core/src/firebase/firestore/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/types/optional.h" @@ -153,7 +153,7 @@ NS_ASSUME_NONNULL_BEGIN localWriteTime:(FIRTimestamp *)localWriteTime mutationResult:(nullable FSTMutationResult *)mutationResult { if (mutationResult) { - FSTAssert(!mutationResult.transformResults, @"Transform results received by FSTSetMutation."); + HARD_ASSERT(!mutationResult.transformResults, "Transform results received by FSTSetMutation."); } if (!self.precondition.IsValidFor(maybeDoc)) { @@ -169,11 +169,11 @@ NS_ASSUME_NONNULL_BEGIN hasLocalMutations:hasLocalMutations]; } - FSTAssert([maybeDoc isMemberOfClass:[FSTDocument class]], @"Unknown MaybeDocument type %@", - [maybeDoc class]); + HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", + [maybeDoc class]); FSTDocument *doc = (FSTDocument *)maybeDoc; - FSTAssert([doc.key isEqual:self.key], @"Can only set a document with the same key"); + HARD_ASSERT([doc.key isEqual:self.key], "Can only set a document with the same key"); return [FSTDocument documentWithData:self.value key:doc.key version:doc.version @@ -236,7 +236,8 @@ NS_ASSUME_NONNULL_BEGIN localWriteTime:(FIRTimestamp *)localWriteTime mutationResult:(nullable FSTMutationResult *)mutationResult { if (mutationResult) { - FSTAssert(!mutationResult.transformResults, @"Transform results received by FSTPatchMutation."); + HARD_ASSERT(!mutationResult.transformResults, + "Transform results received by FSTPatchMutation."); } if (!self.precondition.IsValidFor(maybeDoc)) { @@ -254,11 +255,11 @@ NS_ASSUME_NONNULL_BEGIN hasLocalMutations:hasLocalMutations]; } - FSTAssert([maybeDoc isMemberOfClass:[FSTDocument class]], @"Unknown MaybeDocument type %@", - [maybeDoc class]); + HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", + [maybeDoc class]); FSTDocument *doc = (FSTDocument *)maybeDoc; - FSTAssert([doc.key isEqual:self.key], @"Can only patch a document with the same key"); + HARD_ASSERT([doc.key isEqual:self.key], "Can only patch a document with the same key"); FSTObjectValue *newData = [self patchObjectValue:doc.data]; return [FSTDocument documentWithData:newData @@ -340,8 +341,8 @@ NS_ASSUME_NONNULL_BEGIN localWriteTime:(FIRTimestamp *)localWriteTime mutationResult:(nullable FSTMutationResult *)mutationResult { if (mutationResult) { - FSTAssert(mutationResult.transformResults, - @"Transform results missing for FSTTransformMutation."); + HARD_ASSERT(mutationResult.transformResults, + "Transform results missing for FSTTransformMutation."); } if (!self.precondition.IsValidFor(maybeDoc)) { @@ -350,11 +351,11 @@ NS_ASSUME_NONNULL_BEGIN // We only support transforms with precondition exists, so we can only apply it to an existing // document - FSTAssert([maybeDoc isMemberOfClass:[FSTDocument class]], @"Unknown MaybeDocument type %@", - [maybeDoc class]); + HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", + [maybeDoc class]); FSTDocument *doc = (FSTDocument *)maybeDoc; - FSTAssert([doc.key isEqual:self.key], @"Can only transform a document with the same key"); + HARD_ASSERT([doc.key isEqual:self.key], "Can only transform a document with the same key"); BOOL hasLocalMutations = (mutationResult == nil); NSArray<FSTFieldValue *> *transformResults; @@ -386,9 +387,9 @@ NS_ASSUME_NONNULL_BEGIN serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument serverTransformResults:(NSArray<FSTFieldValue *> *)serverTransformResults { NSMutableArray<FSTFieldValue *> *transformResults = [NSMutableArray array]; - FSTAssert(self.fieldTransforms.size() == serverTransformResults.count, - @"server transform result count (%lu) should match field transforms count (%zu)", - (unsigned long)serverTransformResults.count, self.fieldTransforms.size()); + HARD_ASSERT(self.fieldTransforms.size() == serverTransformResults.count, + "server transform result count (%s) should match field transforms count (%s)", + (unsigned long)serverTransformResults.count, self.fieldTransforms.size()); for (NSUInteger i = 0; i < serverTransformResults.count; i++) { const FieldTransform &fieldTransform = self.fieldTransforms[i]; @@ -433,8 +434,8 @@ serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument - (FSTObjectValue *)transformObject:(FSTObjectValue *)objectValue transformResults:(NSArray<FSTFieldValue *> *)transformResults { - FSTAssert(transformResults.count == self.fieldTransforms.size(), - @"Transform results length mismatch."); + HARD_ASSERT(transformResults.count == self.fieldTransforms.size(), + "Transform results length mismatch."); for (size_t i = 0; i < self.fieldTransforms.size(); i++) { const FieldTransform &fieldTransform = self.fieldTransforms[i]; @@ -478,8 +479,8 @@ serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument localWriteTime:(FIRTimestamp *)localWriteTime mutationResult:(nullable FSTMutationResult *)mutationResult { if (mutationResult) { - FSTAssert(!mutationResult.transformResults, - @"Transform results received by FSTDeleteMutation."); + HARD_ASSERT(!mutationResult.transformResults, + "Transform results received by FSTDeleteMutation."); } if (!self.precondition.IsValidFor(maybeDoc)) { @@ -487,7 +488,7 @@ serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument } if (maybeDoc) { - FSTAssert([maybeDoc.key isEqual:self.key], @"Can only delete a document with the same key"); + HARD_ASSERT([maybeDoc.key isEqual:self.key], "Can only delete a document with the same key"); } return [FSTDeletedDocument documentWithKey:self.key version:SnapshotVersion::None()]; diff --git a/Firestore/Source/Model/FSTMutationBatch.mm b/Firestore/Source/Model/FSTMutationBatch.mm index 1e9189c..b3f4dde 100644 --- a/Firestore/Source/Model/FSTMutationBatch.mm +++ b/Firestore/Source/Model/FSTMutationBatch.mm @@ -22,7 +22,8 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTAssert.h" + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeyHash; @@ -76,15 +77,14 @@ const FSTBatchID kFSTBatchIDUnknown = -1; - (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc documentKey:(const DocumentKey &)documentKey mutationBatchResult:(FSTMutationBatchResult *_Nullable)mutationBatchResult { - FSTAssert(!maybeDoc || [maybeDoc.key isEqualToKey:documentKey], - @"applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString().c_str(), - maybeDoc.key.ToString().c_str()); + HARD_ASSERT(!maybeDoc || [maybeDoc.key isEqualToKey:documentKey], + "applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString(), + maybeDoc.key.ToString()); FSTMaybeDocument *baseDoc = maybeDoc; if (mutationBatchResult) { - FSTAssert(mutationBatchResult.mutationResults.count == self.mutations.count, - @"Mismatch between mutations length (%lu) and results length (%lu)", - (unsigned long)self.mutations.count, - (unsigned long)mutationBatchResult.mutationResults.count); + HARD_ASSERT(mutationBatchResult.mutationResults.count == self.mutations.count, + "Mismatch between mutations length (%s) and results length (%s)", + self.mutations.count, mutationBatchResult.mutationResults.count); } for (NSUInteger i = 0; i < self.mutations.count; i++) { @@ -168,9 +168,9 @@ const FSTBatchID kFSTBatchIDUnknown = -1; commitVersion:(SnapshotVersion)commitVersion mutationResults:(NSArray<FSTMutationResult *> *)mutationResults streamToken:(nullable NSData *)streamToken { - FSTAssert(batch.mutations.count == mutationResults.count, - @"Mutations sent %lu must equal results received %lu", - (unsigned long)batch.mutations.count, (unsigned long)mutationResults.count); + HARD_ASSERT(batch.mutations.count == mutationResults.count, + "Mutations sent %s must equal results received %s", batch.mutations.count, + mutationResults.count); DocumentVersionMap docVersions; NSArray<FSTMutation *> *mutations = batch.mutations; diff --git a/Firestore/Source/Remote/FSTDatastore.mm b/Firestore/Source/Remote/FSTDatastore.mm index f0852fe..5f79122 100644 --- a/Firestore/Source/Remote/FSTDatastore.mm +++ b/Firestore/Source/Remote/FSTDatastore.mm @@ -31,9 +31,7 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Protos/objc/google/firestore/v1beta1/Firestore.pbrpc.h" @@ -43,6 +41,8 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -130,8 +130,8 @@ typedef GRPCProtoCall * (^RPCFactory)(void); } else if ([error.domain isEqualToString:FIRFirestoreErrorDomain]) { return error; } else if ([error.domain isEqualToString:kGRPCErrorDomain]) { - FSTAssert(error.code >= GRPCErrorCodeCancelled && error.code <= GRPCErrorCodeUnauthenticated, - @"Unknown GRPC error code: %ld", (long)error.code); + HARD_ASSERT(error.code >= GRPCErrorCodeCancelled && error.code <= GRPCErrorCodeUnauthenticated, + "Unknown GRPC error code: %s", error.code); return [NSError errorWithDomain:FIRFirestoreErrorDomain code:error.code userInfo:error.userInfo]; } else { @@ -142,14 +142,14 @@ typedef GRPCProtoCall * (^RPCFactory)(void); } + (BOOL)isAbortedError:(NSError *)error { - FSTAssert([error.domain isEqualToString:FIRFirestoreErrorDomain], - @"isAbortedError: only works with errors emitted by FSTDatastore."); + HARD_ASSERT([error.domain isEqualToString:FIRFirestoreErrorDomain], + "isAbortedError: only works with errors emitted by FSTDatastore."); return error.code == FIRFirestoreErrorCodeAborted; } + (BOOL)isPermanentWriteError:(NSError *)error { - FSTAssert([error.domain isEqualToString:FIRFirestoreErrorDomain], - @"isPerminanteWriteError: only works with errors emitted by FSTDatastore."); + HARD_ASSERT([error.domain isEqualToString:FIRFirestoreErrorDomain], + "isPerminanteWriteError: only works with errors emitted by FSTDatastore."); switch (error.code) { case FIRFirestoreErrorCodeCancelled: case FIRFirestoreErrorCodeUnknown: @@ -217,8 +217,8 @@ typedef GRPCProtoCall * (^RPCFactory)(void); /** Logs the (whitelisted) headers returned for an GRPCProtoCall RPC. */ + (void)logHeadersForRPC:(GRPCProtoCall *)rpc RPCName:(NSString *)rpcName { if ([FIRFirestore isLoggingEnabled]) { - FSTLog(@"RPC %@ returned headers (whitelisted): %@", rpcName, - [FSTDatastore extractWhiteListedHeaders:rpc.responseHeaders]); + LOG_DEBUG("RPC %s returned headers (whitelisted): %s", rpcName, + [FSTDatastore extractWhiteListedHeaders:rpc.responseHeaders]); } } @@ -239,7 +239,7 @@ typedef GRPCProtoCall * (^RPCFactory)(void); handler:^(GCFSCommitResponse *response, NSError *_Nullable error) { error = [FSTDatastore firestoreErrorForError:error]; [self.workerDispatchQueue dispatchAsync:^{ - FSTLog(@"RPC CommitRequest completed. Error: %@", error); + LOG_DEBUG("RPC CommitRequest completed. Error: %s", error); [FSTDatastore logHeadersForRPC:rpc RPCName:@"CommitRequest"]; completion(error); }]; @@ -272,7 +272,7 @@ typedef GRPCProtoCall * (^RPCFactory)(void); error = [FSTDatastore firestoreErrorForError:error]; [self.workerDispatchQueue dispatchAsync:^{ if (error) { - FSTLog(@"RPC BatchGetDocuments completed. Error: %@", error); + LOG_DEBUG("RPC BatchGetDocuments completed. Error: %s", error); [FSTDatastore logHeadersForRPC:rpc RPCName:@"BatchGetDocuments"]; completion(nil, error); return; @@ -285,9 +285,9 @@ typedef GRPCProtoCall * (^RPCFactory)(void); closure->results.insert({doc.key, doc}); } else { // Streaming response is done, call completion - FSTLog(@"RPC BatchGetDocuments completed successfully."); + LOG_DEBUG("RPC BatchGetDocuments completed successfully."); [FSTDatastore logHeadersForRPC:rpc RPCName:@"BatchGetDocuments"]; - FSTAssert(!response, @"Got response after done."); + HARD_ASSERT(!response, "Got response after done."); NSMutableArray<FSTMaybeDocument *> *docs = [NSMutableArray arrayWithCapacity:closure->results.size()]; for (auto &&entry : closure->results) { diff --git a/Firestore/Source/Remote/FSTExponentialBackoff.mm b/Firestore/Source/Remote/FSTExponentialBackoff.mm index 20b50a5..2bddbf7 100644 --- a/Firestore/Source/Remote/FSTExponentialBackoff.mm +++ b/Firestore/Source/Remote/FSTExponentialBackoff.mm @@ -18,10 +18,10 @@ #include <random> -#include "Firestore/core/src/firebase/firestore/util/secure_random.h" - #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" + +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/secure_random.h" using firebase::firestore::util::SecureRandom; @@ -71,8 +71,7 @@ using firebase::firestore::util::SecureRandom; // First schedule the block using the current base (which may be 0 and should be honored as such). NSTimeInterval delayWithJitter = _currentBase + [self jitterDelay]; if (_currentBase > 0) { - FSTLog(@"Backing off for %.2f seconds (base delay: %.2f seconds)", delayWithJitter, - _currentBase); + LOG_DEBUG("Backing off for %s seconds (base delay: %s seconds)", delayWithJitter, _currentBase); } self.timerCallback = diff --git a/Firestore/Source/Remote/FSTOnlineStateTracker.mm b/Firestore/Source/Remote/FSTOnlineStateTracker.mm index e782397..fb993e5 100644 --- a/Firestore/Source/Remote/FSTOnlineStateTracker.mm +++ b/Firestore/Source/Remote/FSTOnlineStateTracker.mm @@ -16,9 +16,10 @@ #import "Firestore/Source/Remote/FSTOnlineStateTracker.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" NS_ASSUME_NONNULL_BEGIN @@ -74,19 +75,18 @@ static const NSTimeInterval kOnlineStateTimeout = 10; if (self.watchStreamFailures == 0) { [self setAndBroadcastState:FSTOnlineStateUnknown]; - FSTAssert(!self.onlineStateTimer, @"onlineStateTimer shouldn't be started yet"); + HARD_ASSERT(!self.onlineStateTimer, "onlineStateTimer shouldn't be started yet"); self.onlineStateTimer = [self.queue dispatchAfterDelay:kOnlineStateTimeout timerID:FSTTimerIDOnlineStateTimeout block:^{ self.onlineStateTimer = nil; - FSTAssert( + HARD_ASSERT( self.state == FSTOnlineStateUnknown, - @"Timer should be canceled if we transitioned to a different state."); - FSTLog( - @"Watch stream didn't reach Online or Offline within %f seconds. " - @"Considering " - "client offline.", + "Timer should be canceled if we transitioned to a different state."); + LOG_DEBUG( + "Watch stream didn't reach Online or Offline within %s seconds. " + "Considering client offline.", kOnlineStateTimeout); [self logClientOfflineWarningIfNecessary]; [self setAndBroadcastState:FSTOnlineStateOffline]; @@ -104,8 +104,8 @@ static const NSTimeInterval kOnlineStateTimeout = 10; // To get to FSTOnlineStateOnline, updateState: must have been called which would have reset // our heuristics. - FSTAssert(self.watchStreamFailures == 0, @"watchStreamFailures must be 0"); - FSTAssert(!self.onlineStateTimer, @"onlineStateTimer must be nil"); + HARD_ASSERT(self.watchStreamFailures == 0, "watchStreamFailures must be 0"); + HARD_ASSERT(!self.onlineStateTimer, "onlineStateTimer must be nil"); } else { self.watchStreamFailures++; if (self.watchStreamFailures >= kMaxWatchStreamFailures) { @@ -138,7 +138,7 @@ static const NSTimeInterval kOnlineStateTimeout = 10; - (void)logClientOfflineWarningIfNecessary { if (self.shouldWarnClientIsOffline) { - FSTWarn(@"Could not reach Firestore backend."); + LOG_WARN("Could not reach Firestore backend."); self.shouldWarnClientIsOffline = NO; } } diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 438072e..67af650 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -22,11 +22,12 @@ #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Remote/FSTWatchChange.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" -#import "Firestore/Source/Util/FSTLogger.h" + #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::SnapshotVersion; @@ -443,14 +444,14 @@ initWithSnapshotVersion:(SnapshotVersion)snapshotVersion } - (void)addWatchChanges:(NSArray<FSTWatchChange *> *)watchChanges { - FSTAssert(!self.frozen, @"Trying to modify frozen FSTWatchChangeAggregator"); + HARD_ASSERT(!self.frozen, "Trying to modify frozen FSTWatchChangeAggregator"); for (FSTWatchChange *watchChange in watchChanges) { [self addWatchChange:watchChange]; } } - (void)addWatchChange:(FSTWatchChange *)watchChange { - FSTAssert(!self.frozen, @"Trying to modify frozen FSTWatchChangeAggregator"); + HARD_ASSERT(!self.frozen, "Trying to modify frozen FSTWatchChangeAggregator"); if ([watchChange isKindOfClass:[FSTDocumentWatchChange class]]) { [self addDocumentChange:(FSTDocumentWatchChange *)watchChange]; } else if ([watchChange isKindOfClass:[FSTWatchTargetChange class]]) { @@ -458,7 +459,7 @@ initWithSnapshotVersion:(SnapshotVersion)snapshotVersion } else if ([watchChange isKindOfClass:[FSTExistenceFilterWatchChange class]]) { [self addExistenceFilterChange:(FSTExistenceFilterWatchChange *)watchChange]; } else { - FSTFail(@"Unknown watch change: %@", watchChange); + HARD_FAIL("Unknown watch change: %s", watchChange); } } @@ -560,7 +561,7 @@ initWithSnapshotVersion:(SnapshotVersion)snapshotVersion // We need to keep track of removed targets to we can post-filter and remove any target // changes. [self recordResponseForTargetID:targetID]; - FSTAssert(!targetChange.cause, @"WatchChangeAggregator does not handle errored targets."); + HARD_ASSERT(!targetChange.cause, "WatchChangeAggregator does not handle errored targets."); break; case FSTWatchTargetChangeStateCurrent: if ([self isActiveTarget:targetID]) { @@ -577,7 +578,7 @@ initWithSnapshotVersion:(SnapshotVersion)snapshotVersion } break; default: - FSTWarn(@"Unknown target watch change type: %ld", (long)targetChange.state); + LOG_WARN("Unknown target watch change type: %s", targetChange.state); } } } diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 0ea4887..7338ffb 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -31,12 +31,12 @@ #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTStream.h" #import "Firestore/Source/Remote/FSTWatchChange.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTLogger.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -154,8 +154,8 @@ static const int kMaxPendingWrites = 10; #pragma mark Online/Offline state - (BOOL)isNetworkEnabled { - FSTAssert((self.watchStream == nil) == (self.writeStream == nil), - @"WatchStream and WriteStream should both be null or non-null"); + HARD_ASSERT((self.watchStream == nil) == (self.writeStream == nil), + "WatchStream and WriteStream should both be null or non-null"); return self.watchStream != nil; } @@ -205,7 +205,7 @@ static const int kMaxPendingWrites = 10; #pragma mark Shutdown - (void)shutdown { - FSTLog(@"FSTRemoteStore %p shutting down", (__bridge void *)self); + LOG_DEBUG("FSTRemoteStore %s shutting down", (__bridge void *)self); [self disableNetworkInternal]; // Set the FSTOnlineState to Unknown (rather than Offline) to avoid potentially triggering // spurious listener events with cached data, etc. @@ -213,7 +213,7 @@ static const int kMaxPendingWrites = 10; } - (void)userDidChange:(const User &)user { - FSTLog(@"FSTRemoteStore %p changing users: %s", (__bridge void *)self, user.uid().c_str()); + LOG_DEBUG("FSTRemoteStore %s changing users: %s", (__bridge void *)self, user.uid()); 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 @@ -227,16 +227,16 @@ static const int kMaxPendingWrites = 10; #pragma mark Watch Stream - (void)startWatchStream { - FSTAssert([self shouldStartWatchStream], - @"startWatchStream: called when shouldStartWatchStream: is false."); + HARD_ASSERT([self shouldStartWatchStream], + "startWatchStream: called when shouldStartWatchStream: is false."); [self.watchStream startWithDelegate:self]; [self.onlineStateTracker handleWatchStreamStart]; } - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { NSNumber *targetKey = @(queryData.targetID); - FSTAssert(!self.listenTargets[targetKey], @"listenToQuery called with duplicate target id: %@", - targetKey); + HARD_ASSERT(!self.listenTargets[targetKey], "listenToQuery called with duplicate target id: %s", + targetKey); self.listenTargets[targetKey] = queryData; @@ -255,7 +255,7 @@ static const int kMaxPendingWrites = 10; - (void)stopListeningToTargetID:(FSTTargetID)targetID { FSTBoxedTargetID *targetKey = @(targetID); FSTQueryData *queryData = self.listenTargets[targetKey]; - FSTAssert(queryData, @"unlistenToTarget: target not currently watched: %@", targetKey); + HARD_ASSERT(queryData, "unlistenToTarget: target not currently watched: %s", targetKey); [self.listenTargets removeObjectForKey:targetKey]; if ([self isNetworkEnabled] && [self.watchStream isOpen]) { @@ -331,9 +331,9 @@ static const int kMaxPendingWrites = 10; } - (void)watchStreamWasInterruptedWithError:(nullable NSError *)error { - FSTAssert([self isNetworkEnabled], - @"watchStreamWasInterruptedWithError: should only be called when the network is " - "enabled"); + HARD_ASSERT([self isNetworkEnabled], + "watchStreamWasInterruptedWithError: should only be called when the network is " + "enabled"); [self cleanUpWatchStreamState]; [self.onlineStateTracker handleWatchStreamFailure]; @@ -388,8 +388,8 @@ static const int kMaxPendingWrites = 10; [FSTDeletedDocument documentWithKey:key version:snapshotVersion]; [remoteEvent addDocumentUpdate:deletedDoc]; } else { - FSTAssert(filter.count == 1, @"Single document existence filter with count: %" PRId32, - filter.count); + HARD_ASSERT(filter.count == 1, "Single document existence filter with count: %s", + filter.count); } } else { @@ -401,14 +401,14 @@ static const int kMaxPendingWrites = 10; FSTUpdateMapping *update = (FSTUpdateMapping *)mapping; trackedRemote = [update applyTo:trackedRemote]; } else { - FSTAssert([mapping isKindOfClass:[FSTResetMapping class]], - @"Expected either reset or update mapping but got something else %@", mapping); + HARD_ASSERT([mapping isKindOfClass:[FSTResetMapping class]], + "Expected either reset or update mapping but got something else %s", mapping); trackedRemote = ((FSTResetMapping *)mapping).documents; } } if (trackedRemote.size() != static_cast<size_t>(filter.count)) { - FSTLog(@"Existence filter mismatch, resetting mapping"); + LOG_DEBUG("Existence filter mismatch, resetting mapping"); // Make sure the mismatch is exposed in the remote event [remoteEvent handleExistenceFilterMismatchForTargetID:target]; @@ -461,7 +461,7 @@ static const int kMaxPendingWrites = 10; /** Process a target error and passes the error along to SyncEngine. */ - (void)processTargetErrorForWatchChange:(FSTWatchTargetChange *)change { - FSTAssert(change.cause, @"Handling target error without a cause"); + HARD_ASSERT(change.cause, "Handling target error without a cause"); // Ignore targets that have been removed already. for (FSTBoxedTargetID *targetID in change.targetIDs) { if (self.listenTargets[targetID]) { @@ -482,16 +482,15 @@ static const int kMaxPendingWrites = 10; } - (void)startWriteStream { - FSTAssert([self shouldStartWriteStream], - @"startWriteStream: called when shouldStartWriteStream: is false."); + HARD_ASSERT([self shouldStartWriteStream], + "startWriteStream: called when shouldStartWriteStream: is false."); [self.writeStream startWithDelegate:self]; } - (void)cleanUpWriteStreamState { self.lastBatchSeen = kFSTBatchIDUnknown; - FSTLog(@"Stopping write stream with %lu pending writes", - (unsigned long)[self.pendingWrites count]); + LOG_DEBUG("Stopping write stream with %s pending writes", [self.pendingWrites count]); [self.pendingWrites removeAllObjects]; } @@ -527,7 +526,7 @@ static const int kMaxPendingWrites = 10; /** Given mutations to commit, actually commits them to the backend. */ - (void)commitBatch:(FSTMutationBatch *)batch { - FSTAssert([self canWriteMutations], @"commitBatch called when mutations can't be written"); + HARD_ASSERT([self canWriteMutations], "commitBatch called when mutations can't be written"); self.lastBatchSeen = batch.batchID; [self.pendingWrites addObject:batch]; @@ -591,8 +590,8 @@ static const int kMaxPendingWrites = 10; * has been terminated by the client or the server. */ - (void)writeStreamWasInterruptedWithError:(nullable NSError *)error { - FSTAssert([self isNetworkEnabled], - @"writeStreamDidClose: should only be called when the network is enabled"); + HARD_ASSERT([self isNetworkEnabled], + "writeStreamDidClose: should only be called when the network is enabled"); // If the write stream closed due to an error, invoke the error callbacks if there are pending // writes. @@ -618,8 +617,8 @@ static const int kMaxPendingWrites = 10; // stream is no longer valid. if ([FSTDatastore isPermanentWriteError:error] || [FSTDatastore isAbortedError:error]) { NSString *token = [self.writeStream.lastStreamToken base64EncodedStringWithOptions:0]; - FSTLog(@"FSTRemoteStore %p error before completed handshake; resetting stream token %@: %@", - (__bridge void *)self, token, error); + LOG_DEBUG("FSTRemoteStore %s error before completed handshake; resetting stream token %s: %s", + (__bridge void *)self, token, error); self.writeStream.lastStreamToken = nil; [self.localStore setLastStreamToken:nil]; } diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index f862ec3..ab40dd6 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -41,7 +41,6 @@ #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" -#import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -51,6 +50,7 @@ #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" #include "absl/types/optional.h" @@ -128,10 +128,10 @@ NS_ASSUME_NONNULL_BEGIN - (DocumentKey)decodedDocumentKey:(NSString *)name { const ResourcePath path = [self decodedResourcePathWithDatabaseID:name]; - FSTAssert(path[1] == self.databaseID->project_id(), - @"Tried to deserialize key from different project."); - FSTAssert(path[3] == self.databaseID->database_id(), - @"Tried to deserialize key from different datbase."); + HARD_ASSERT(path[1] == self.databaseID->project_id(), + "Tried to deserialize key from different project."); + HARD_ASSERT(path[3] == self.databaseID->database_id(), + "Tried to deserialize key from different datbase."); return DocumentKey{[self localResourcePathForQualifiedResourcePath:path]}; } @@ -145,8 +145,8 @@ NS_ASSUME_NONNULL_BEGIN - (ResourcePath)decodedResourcePathWithDatabaseID:(NSString *)name { const ResourcePath path = ResourcePath::FromString(util::MakeStringView(name)); - FSTAssert([self validQualifiedResourcePath:path], @"Tried to deserialize invalid key %s", - path.CanonicalString().c_str()); + HARD_ASSERT([self validQualifiedResourcePath:path], "Tried to deserialize invalid key %s", + path.CanonicalString()); return path; } @@ -172,8 +172,8 @@ NS_ASSUME_NONNULL_BEGIN } - (ResourcePath)localResourcePathForQualifiedResourcePath:(const ResourcePath &)resourceName { - FSTAssert(resourceName.size() > 4 && resourceName[4] == "documents", - @"Tried to deserialize invalid key %s", resourceName.CanonicalString().c_str()); + HARD_ASSERT(resourceName.size() > 4 && resourceName[4] == "documents", + "Tried to deserialize invalid key %s", resourceName.CanonicalString()); return resourceName.PopFirst(5); } @@ -229,7 +229,7 @@ NS_ASSUME_NONNULL_BEGIN return result; } else { - FSTFail(@"Unhandled type %@ on %@", NSStringFromClass([fieldValue class]), fieldValue); + HARD_FAIL("Unhandled type %s on %s", NSStringFromClass([fieldValue class]), fieldValue); } } @@ -273,7 +273,7 @@ NS_ASSUME_NONNULL_BEGIN return [self decodedMapValue:valueProto.mapValue]; default: - FSTFail(@"Unhandled type %d on %@", valueProto.valueTypeOneOfCase, valueProto); + HARD_FAIL("Unhandled type %s on %s", valueProto.valueTypeOneOfCase, valueProto); } } @@ -327,9 +327,9 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSValue *)encodedReferenceValueForDatabaseID:(const DatabaseId *)databaseID key:(const DocumentKey &)key { - FSTAssert(*databaseID == *self.databaseID, @"Database %s:%s cannot encode reference from %s:%s", - self.databaseID->project_id().c_str(), self.databaseID->database_id().c_str(), - databaseID->project_id().c_str(), databaseID->database_id().c_str()); + HARD_ASSERT(*databaseID == *self.databaseID, "Database %s:%s cannot encode reference from %s:%s", + self.databaseID->project_id(), self.databaseID->database_id(), + databaseID->project_id(), databaseID->database_id()); GCFSValue *result = [GCFSValue message]; result.referenceValue = [self encodedResourcePathForDatabaseID:databaseID path:key.path()]; return result; @@ -342,9 +342,9 @@ NS_ASSUME_NONNULL_BEGIN const DocumentKey key{[self localResourcePathForQualifiedResourcePath:path]}; const DatabaseId database_id(project, database); - FSTAssert(database_id == *self.databaseID, @"Database %s:%s cannot encode reference from %s:%s", - self.databaseID->project_id().c_str(), self.databaseID->database_id().c_str(), - database_id.project_id().c_str(), database_id.database_id().c_str()); + HARD_ASSERT(database_id == *self.databaseID, "Database %s:%s cannot encode reference from %s:%s", + self.databaseID->project_id(), self.databaseID->database_id(), + database_id.project_id(), database_id.database_id()); return [FSTReferenceValue referenceValue:key databaseID:self.databaseID]; } @@ -425,27 +425,27 @@ NS_ASSUME_NONNULL_BEGIN case GCFSBatchGetDocumentsResponse_Result_OneOfCase_Missing: return [self decodedDeletedDocument:response]; default: - FSTFail(@"Unknown document type: %@", response); + HARD_FAIL("Unknown document type: %s", response); } } - (FSTDocument *)decodedFoundDocument:(GCFSBatchGetDocumentsResponse *)response { - FSTAssert(!!response.found, @"Tried to deserialize a found document from a deleted document."); + HARD_ASSERT(!!response.found, "Tried to deserialize a found document from a deleted document."); const DocumentKey key = [self decodedDocumentKey:response.found.name]; FSTObjectValue *value = [self decodedFields:response.found.fields]; SnapshotVersion version = [self decodedVersion:response.found.updateTime]; - FSTAssert(version != SnapshotVersion::None(), - @"Got a document response with no snapshot version"); + HARD_ASSERT(version != SnapshotVersion::None(), + "Got a document response with no snapshot version"); return [FSTDocument documentWithData:value key:key version:version hasLocalMutations:NO]; } - (FSTDeletedDocument *)decodedDeletedDocument:(GCFSBatchGetDocumentsResponse *)response { - FSTAssert(!!response.missing, @"Tried to deserialize a deleted document from a found document."); + HARD_ASSERT(!!response.missing, "Tried to deserialize a deleted document from a found document."); const DocumentKey key = [self decodedDocumentKey:response.missing]; SnapshotVersion version = [self decodedVersion:response.readTime]; - FSTAssert(version != SnapshotVersion::None(), - @"Got a no document response with no snapshot version"); + HARD_ASSERT(version != SnapshotVersion::None(), + "Got a no document response with no snapshot version"); return [FSTDeletedDocument documentWithKey:key version:version]; } @@ -480,7 +480,7 @@ NS_ASSUME_NONNULL_BEGIN proto.delete_p = [self encodedDocumentKey:deleteMutation.key]; } else { - FSTFail(@"Unknown mutation type %@", NSStringFromClass(mutationClass)); + HARD_FAIL("Unknown mutation type %s", NSStringFromClass(mutationClass)); } if (!mutation.precondition.IsNone()) { @@ -513,8 +513,8 @@ NS_ASSUME_NONNULL_BEGIN precondition:precondition]; case GCFSWrite_Operation_OneOfCase_Transform: { - FSTAssert(precondition == Precondition::Exists(true), - @"Transforms must have precondition \"exists == true\""); + HARD_ASSERT(precondition == Precondition::Exists(true), + "Transforms must have precondition \"exists == true\""); return [[FSTTransformMutation alloc] initWithKey:[self decodedDocumentKey:mutation.transform.document] @@ -523,19 +523,19 @@ NS_ASSUME_NONNULL_BEGIN default: // Note that insert is intentionally unhandled, since we don't ever deal in them. - FSTFail(@"Unknown mutation operation: %d", mutation.operationOneOfCase); + HARD_FAIL("Unknown mutation operation: %s", mutation.operationOneOfCase); } } - (GCFSPrecondition *)encodedPrecondition:(const Precondition &)precondition { - FSTAssert(!precondition.IsNone(), @"Can't serialize an empty precondition"); + HARD_ASSERT(!precondition.IsNone(), "Can't serialize an empty precondition"); GCFSPrecondition *message = [GCFSPrecondition message]; if (precondition.type() == Precondition::Type::UpdateTime) { message.updateTime = [self encodedVersion:precondition.update_time()]; } else if (precondition.type() == Precondition::Type::Exists) { message.exists = precondition == Precondition::Exists(true); } else { - FSTFail(@"Unknown precondition: %@", precondition.description()); + HARD_FAIL("Unknown precondition: %s", precondition.description()); } return message; } @@ -552,7 +552,7 @@ NS_ASSUME_NONNULL_BEGIN return Precondition::UpdateTime([self decodedVersion:precondition.updateTime]); default: - FSTFail(@"Unrecognized Precondition one-of case %@", precondition); + HARD_FAIL("Unrecognized Precondition one-of case %s", precondition); } } @@ -599,7 +599,7 @@ NS_ASSUME_NONNULL_BEGIN encodedArrayTransformElements:ArrayTransform::Elements(fieldTransform.transformation())]; } else { - FSTFail(@"Unknown transform: %d type", fieldTransform.transformation().type()); + HARD_FAIL("Unknown transform: %s type", fieldTransform.transformation().type()); } return proto; } @@ -623,9 +623,9 @@ NS_ASSUME_NONNULL_BEGIN for (GCFSDocumentTransform_FieldTransform *proto in protos) { switch (proto.transformTypeOneOfCase) { case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_SetToServerValue: { - FSTAssert( + HARD_ASSERT( proto.setToServerValue == GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime, - @"Unknown transform setToServerValue: %d", proto.setToServerValue); + "Unknown transform setToServerValue: %s", proto.setToServerValue); fieldTransforms.emplace_back( FieldPath::FromServerFormat(util::MakeStringView(proto.fieldPath)), absl::make_unique<ServerTimestampTransform>(ServerTimestampTransform::Get())); @@ -653,7 +653,7 @@ NS_ASSUME_NONNULL_BEGIN } default: - FSTFail(@"Unknown transform: %@", proto); + HARD_FAIL("Unknown transform: %s", proto); } } @@ -711,7 +711,7 @@ NS_ASSUME_NONNULL_BEGIN case FSTQueryPurposeLimboResolution: return @"limbo-document"; default: - FSTFail(@"Unrecognized query purpose: %lu", (unsigned long)purpose); + HARD_FAIL("Unrecognized query purpose: %s", purpose); } } @@ -742,8 +742,8 @@ NS_ASSUME_NONNULL_BEGIN - (FSTQuery *)decodedQueryFromDocumentsTarget:(GCFSTarget_DocumentsTarget *)target { NSArray<NSString *> *documents = target.documentsArray; - FSTAssert(documents.count == 1, @"DocumentsTarget contained other than 1 document %lu", - (unsigned long)documents.count); + HARD_ASSERT(documents.count == 1, "DocumentsTarget contained other than 1 document %s", + (unsigned long)documents.count); NSString *name = documents[0]; return [FSTQuery queryWithPath:[self decodedQueryPath:name]]; @@ -756,7 +756,7 @@ NS_ASSUME_NONNULL_BEGIN queryTarget.parent = [self encodedQueryPath:query.path]; } else { const ResourcePath &path = query.path; - FSTAssert(path.size() % 2 != 0, @"Document queries with filters are not supported."); + HARD_ASSERT(path.size() % 2 != 0, "Document queries with filters are not supported."); queryTarget.parent = [self encodedQueryPath:path.PopLast()]; GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message]; from.collectionId = util::WrapNSString(path.last_segment()); @@ -795,8 +795,8 @@ NS_ASSUME_NONNULL_BEGIN GCFSStructuredQuery *query = target.structuredQuery; NSUInteger fromCount = query.fromArray_Count; if (fromCount > 0) { - FSTAssert(fromCount == 1, - @"StructuredQuery.from with more than one collection is not supported."); + HARD_ASSERT(fromCount == 1, + "StructuredQuery.from with more than one collection is not supported."); GCFSStructuredQuery_CollectionSelector *from = query.fromArray[0]; path = path.Append(util::MakeString(from.collectionId)); @@ -870,8 +870,8 @@ NS_ASSUME_NONNULL_BEGIN NSArray<GCFSStructuredQuery_Filter *> *filters; if (proto.filterTypeOneOfCase == GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter) { - FSTAssert(proto.compositeFilter.op == GCFSStructuredQuery_CompositeFilter_Operator_And, - @"Only AND-type composite filters are supported, got %d", proto.compositeFilter.op); + HARD_ASSERT(proto.compositeFilter.op == GCFSStructuredQuery_CompositeFilter_Operator_And, + "Only AND-type composite filters are supported, got %s", proto.compositeFilter.op); filters = proto.compositeFilter.filtersArray; } else { filters = @[ proto ]; @@ -880,7 +880,7 @@ NS_ASSUME_NONNULL_BEGIN for (GCFSStructuredQuery_Filter *filter in filters) { switch (filter.filterTypeOneOfCase) { case GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter: - FSTFail(@"Nested composite filters are not supported"); + HARD_FAIL("Nested composite filters are not supported"); case GCFSStructuredQuery_Filter_FilterType_OneOfCase_FieldFilter: [result addObject:[self decodedRelationFilter:filter.fieldFilter]]; @@ -891,7 +891,7 @@ NS_ASSUME_NONNULL_BEGIN break; default: - FSTFail(@"Unrecognized Filter.filterType %d", filter.filterTypeOneOfCase); + HARD_FAIL("Unrecognized Filter.filterType %s", filter.filterTypeOneOfCase); } } return result; @@ -921,7 +921,7 @@ NS_ASSUME_NONNULL_BEGIN } else if ([filter isKindOfClass:[FSTNullFilter class]]) { proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNull; } else { - FSTFail(@"Unrecognized filter: %@", filter); + HARD_FAIL("Unrecognized filter: %s", static_cast<id>(filter)); } return proto; } @@ -936,7 +936,7 @@ NS_ASSUME_NONNULL_BEGIN return [[FSTNullFilter alloc] initWithField:field]; default: - FSTFail(@"Unrecognized UnaryFilter.operator %d", proto.op); + HARD_FAIL("Unrecognized UnaryFilter.operator %s", proto.op); } } @@ -962,7 +962,7 @@ NS_ASSUME_NONNULL_BEGIN case FSTRelationFilterOperatorArrayContains: return GCFSStructuredQuery_FieldFilter_Operator_ArrayContains; default: - FSTFail(@"Unhandled FSTRelationFilterOperator: %ld", (long)filterOperator); + HARD_FAIL("Unhandled FSTRelationFilterOperator: %s", filterOperator); } } @@ -982,7 +982,7 @@ NS_ASSUME_NONNULL_BEGIN case GCFSStructuredQuery_FieldFilter_Operator_ArrayContains: return FSTRelationFilterOperatorArrayContains; default: - FSTFail(@"Unhandled FieldFilter.operator: %d", filterOperator); + HARD_FAIL("Unhandled FieldFilter.operator: %s", filterOperator); } } @@ -1026,7 +1026,7 @@ NS_ASSUME_NONNULL_BEGIN ascending = NO; break; default: - FSTFail(@"Unrecognized GCFSStructuredQuery_Direction %d", proto.direction); + HARD_FAIL("Unrecognized GCFSStructuredQuery_Direction %s", proto.direction); } return [FSTSortOrder sortOrderWithFieldPath:fieldPath ascending:ascending]; } @@ -1074,7 +1074,7 @@ NS_ASSUME_NONNULL_BEGIN return [self decodedExistenceFilterWatchChange:watchChange.filter]; default: - FSTFail(@"Unknown WatchChange.changeType %" PRId32, watchChange.responseTypeOneOfCase); + HARD_FAIL("Unknown WatchChange.changeType %s", watchChange.responseTypeOneOfCase); } } @@ -1127,7 +1127,7 @@ NS_ASSUME_NONNULL_BEGIN case GCFSTargetChange_TargetChangeType_Reset: return FSTWatchTargetChangeStateReset; default: - FSTFail(@"Unexpected TargetChange.state: %" PRId32, state); + HARD_FAIL("Unexpected TargetChange.state: %s", state); } } @@ -1143,7 +1143,7 @@ NS_ASSUME_NONNULL_BEGIN FSTObjectValue *value = [self decodedFields:change.document.fields]; const DocumentKey key = [self decodedDocumentKey:change.document.name]; SnapshotVersion version = [self decodedVersion:change.document.updateTime]; - FSTAssert(version != SnapshotVersion::None(), @"Got a document change with no snapshot version"); + HARD_ASSERT(version != SnapshotVersion::None(), "Got a document change with no snapshot version"); FSTMaybeDocument *document = [FSTDocument documentWithData:value key:key version:version hasLocalMutations:NO]; diff --git a/Firestore/Source/Remote/FSTStream.mm b/Firestore/Source/Remote/FSTStream.mm index f4ec675..3a6c035 100644 --- a/Firestore/Source/Remote/FSTStream.mm +++ b/Firestore/Source/Remote/FSTStream.mm @@ -26,10 +26,8 @@ #import "Firestore/Source/Remote/FSTExponentialBackoff.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" -#import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Protos/objc/google/firestore/v1beta1/Firestore.pbrpc.h" @@ -38,6 +36,8 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; @@ -258,11 +258,11 @@ static const NSTimeInterval kIdleTimeout = 60.0; return; } - FSTLog(@"%@ %p start", NSStringFromClass([self class]), (__bridge void *)self); - FSTAssert(self.state == FSTStreamStateInitial, @"Already started"); + LOG_DEBUG("%s %s start", NSStringFromClass([self class]), (__bridge void *)self); + HARD_ASSERT(self.state == FSTStreamStateInitial, "Already started"); self.state = FSTStreamStateAuth; - FSTAssert(_delegate == nil, @"Delegate must be nil"); + HARD_ASSERT(_delegate == nil, "Delegate must be nil"); _delegate = delegate; _credentials->GetToken( @@ -281,8 +281,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; // Streams can be stopped while waiting for authorization. return; } - FSTAssert(self.state == FSTStreamStateAuth, @"State should still be auth (was %ld)", - (long)self.state); + HARD_ASSERT(self.state == FSTStreamStateAuth, "State should still be auth (was %s)", self.state); // TODO(mikelehen): We should force a refresh if the previous RPC failed due to an expired token, // but I'm not sure how to detect that right now. http://b/32762461 @@ -301,7 +300,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; prepareHeadersForRPC:_rpc databaseID:&self.databaseInfo->database_id() token:(token.user().is_authenticated() ? token.token() : absl::string_view())]; - FSTAssert(_callbackFilter == nil, @"GRX Filter must be nil"); + HARD_ASSERT(_callbackFilter == nil, "GRX Filter must be nil"); _callbackFilter = [[FSTCallbackFilter alloc] initWithStream:self]; [_rpc startWithWriteable:_callbackFilter]; @@ -311,10 +310,10 @@ static const NSTimeInterval kIdleTimeout = 60.0; /** Backs off after an error. */ - (void)performBackoffWithDelegate:(id)delegate { - FSTLog(@"%@ %p backoff", NSStringFromClass([self class]), (__bridge void *)self); + LOG_DEBUG("%s %s backoff", NSStringFromClass([self class]), (__bridge void *)self); [self.workerDispatchQueue verifyIsCurrentQueue]; - FSTAssert(self.state == FSTStreamStateError, @"Should only perform backoff in an error case"); + HARD_ASSERT(self.state == FSTStreamStateError, "Should only perform backoff in an error case"); self.state = FSTStreamStateBackoff; FSTWeakify(self); @@ -334,13 +333,13 @@ static const NSTimeInterval kIdleTimeout = 60.0; // In order to have performed a backoff the stream must have been in an error state just prior // to entering the backoff state. If we weren't stopped we must be in the backoff state. - FSTAssert(self.state == FSTStreamStateBackoff, @"State should still be backoff (was %ld)", - (long)self.state); + HARD_ASSERT(self.state == FSTStreamStateBackoff, "State should still be backoff (was %s)", + self.state); // Momentarily set state to FSTStreamStateInitial as `start` expects it. self.state = FSTStreamStateInitial; [self startWithDelegate:delegate]; - FSTAssert([self isStarted], @"Stream should have started."); + HARD_ASSERT([self isStarted], "Stream should have started."); } /** @@ -365,8 +364,8 @@ static const NSTimeInterval kIdleTimeout = 60.0; * @param error the NSError the connection was closed with. */ - (void)closeWithFinalState:(FSTStreamState)finalState error:(nullable NSError *)error { - FSTAssert(finalState == FSTStreamStateError || error == nil, - @"Can't provide an error when not in an error state."); + HARD_ASSERT(finalState == FSTStreamStateError || error == nil, + "Can't provide an error when not in an error state."); [self.workerDispatchQueue verifyIsCurrentQueue]; @@ -381,13 +380,13 @@ static const NSTimeInterval kIdleTimeout = 60.0; // If this is an intentional close ensure we don't delay our next connection attempt. [self.backoff reset]; } else if (error != nil && error.code == FIRFirestoreErrorCodeResourceExhausted) { - FSTLog(@"%@ %p Using maximum backoff delay to prevent overloading the backend.", [self class], - (__bridge void *)self); + LOG_DEBUG("%s %s Using maximum backoff delay to prevent overloading the backend.", [self class], + (__bridge void *)self); [self.backoff resetToMax]; } if (finalState != FSTStreamStateError) { - FSTLog(@"%@ %p Performing stream teardown", [self class], (__bridge void *)self); + LOG_DEBUG("%s %s Performing stream teardown", [self class], (__bridge void *)self); [self tearDown]; } @@ -395,7 +394,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; // Clean up the underlying RPC. If this close: is in response to an error, don't attempt to // call half-close to avoid secondary failures. if (finalState != FSTStreamStateError) { - FSTLog(@"%@ %p Closing stream client-side", [self class], (__bridge void *)self); + LOG_DEBUG("%s %s Closing stream client-side", [self class], (__bridge void *)self); @synchronized(self.requestsWriter) { [self.requestsWriter finishWithError:nil]; } @@ -426,15 +425,14 @@ static const NSTimeInterval kIdleTimeout = 60.0; } - (void)stop { - FSTLog(@"%@ %p stop", NSStringFromClass([self class]), (__bridge void *)self); + LOG_DEBUG("%s %s stop", NSStringFromClass([self class]), (__bridge void *)self); if ([self isStarted]) { [self closeWithFinalState:FSTStreamStateStopped error:nil]; } } - (void)inhibitBackoff { - FSTAssert(![self isStarted], @"Can only inhibit backoff after an error (was %ld)", - (long)self.state); + HARD_ASSERT(![self isStarted], "Can only inhibit backoff after an error (was %s)", self.state); [self.workerDispatchQueue verifyIsCurrentQueue]; // Clear the error condition. @@ -550,8 +548,8 @@ static const NSTimeInterval kIdleTimeout = 60.0; * Called by the stream when the underlying RPC has been closed for whatever reason. */ - (void)handleStreamClose:(nullable NSError *)error { - FSTLog(@"%@ %p close: %@", NSStringFromClass([self class]), (__bridge void *)self, error); - FSTAssert([self isStarted], @"handleStreamClose: called for non-started stream."); + LOG_DEBUG("%s %s close: %s", NSStringFromClass([self class]), (__bridge void *)self, error); + HARD_ASSERT([self isStarted], "handleStreamClose: called for non-started stream."); // In theory the stream could close cleanly, however, in our current model we never expect this // to happen because if we stop a stream ourselves, this callback will never be called. To @@ -572,14 +570,14 @@ static const NSTimeInterval kIdleTimeout = 60.0; */ - (void)writeValue:(id)value { [self.workerDispatchQueue enterCheckedOperation:^{ - FSTAssert([self isStarted], @"writeValue: called for stopped stream."); + HARD_ASSERT([self isStarted], "writeValue: called for stopped stream."); if (!self.messageReceived) { self.messageReceived = YES; if ([FIRFirestore isLoggingEnabled]) { - FSTLog(@"%@ %p headers (whitelisted): %@", NSStringFromClass([self class]), - (__bridge void *)self, - [FSTDatastore extractWhiteListedHeaders:self.rpc.responseHeaders]); + LOG_DEBUG("%s %s headers (whitelisted): %s", NSStringFromClass([self class]), + (__bridge void *)self, + [FSTDatastore extractWhiteListedHeaders:self.rpc.responseHeaders]); } } NSError *error; @@ -606,7 +604,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; - (void)writesFinishedWithError:(nullable NSError *)error __used { error = [FSTDatastore firestoreErrorForError:error]; [self.workerDispatchQueue enterCheckedOperation:^{ - FSTAssert([self isStarted], @"writesFinishedWithError: called for stopped stream."); + HARD_ASSERT([self isStarted], "writesFinishedWithError: called for stopped stream."); [self handleStreamClose:error]; }]; @@ -657,7 +655,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; } - (void)watchQuery:(FSTQueryData *)query { - FSTAssert([self isOpen], @"Not yet open"); + HARD_ASSERT([self isOpen], "Not yet open"); [self.workerDispatchQueue verifyIsCurrentQueue]; GCFSListenRequest *request = [GCFSListenRequest message]; @@ -665,19 +663,19 @@ static const NSTimeInterval kIdleTimeout = 60.0; request.addTarget = [_serializer encodedTarget:query]; request.labels = [_serializer encodedListenRequestLabelsForQueryData:query]; - FSTLog(@"FSTWatchStream %p watch: %@", (__bridge void *)self, request); + LOG_DEBUG("FSTWatchStream %s watch: %s", (__bridge void *)self, request); [self writeRequest:request]; } - (void)unwatchTargetID:(FSTTargetID)targetID { - FSTAssert([self isOpen], @"Not yet open"); + HARD_ASSERT([self isOpen], "Not yet open"); [self.workerDispatchQueue verifyIsCurrentQueue]; GCFSListenRequest *request = [GCFSListenRequest message]; request.database = [_serializer encodedDatabaseID]; request.removeTarget = targetID; - FSTLog(@"FSTWatchStream %p unwatch: %@", (__bridge void *)self, request); + LOG_DEBUG("FSTWatchStream %s unwatch: %s", (__bridge void *)self, request); [self writeRequest:request]; } @@ -686,7 +684,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; * watchStreamDidChange:snapshotVersion: callback. */ - (void)handleStreamMessage:(GCFSListenResponse *)proto { - FSTLog(@"FSTWatchStream %p response: %@", (__bridge void *)self, proto); + LOG_DEBUG("FSTWatchStream %s response: %s", (__bridge void *)self, proto); [self.workerDispatchQueue verifyIsCurrentQueue]; // A successful response means the stream is healthy. @@ -756,8 +754,8 @@ static const NSTimeInterval kIdleTimeout = 60.0; - (void)writeHandshake { // The initial request cannot contain mutations, but must contain a projectID. - FSTAssert([self isOpen], @"Not yet open"); - FSTAssert(!self.handshakeComplete, @"Handshake sent out of turn"); + HARD_ASSERT([self isOpen], "Not yet open"); + HARD_ASSERT(!self.handshakeComplete, "Handshake sent out of turn"); [self.workerDispatchQueue verifyIsCurrentQueue]; GCFSWriteRequest *request = [GCFSWriteRequest message]; @@ -765,13 +763,13 @@ static const NSTimeInterval kIdleTimeout = 60.0; // TODO(dimond): Support stream resumption. We intentionally do not set the stream token on the // handshake, ignoring any stream token we might have. - FSTLog(@"FSTWriteStream %p initial request: %@", (__bridge void *)self, request); + LOG_DEBUG("FSTWriteStream %s initial request: %s", (__bridge void *)self, request); [self writeRequest:request]; } - (void)writeMutations:(NSArray<FSTMutation *> *)mutations { - FSTAssert([self isOpen], @"Not yet open"); - FSTAssert(self.handshakeComplete, @"Mutations sent out of turn"); + HARD_ASSERT([self isOpen], "Not yet open"); + HARD_ASSERT(self.handshakeComplete, "Mutations sent out of turn"); [self.workerDispatchQueue verifyIsCurrentQueue]; NSMutableArray<GCFSWrite *> *protos = [NSMutableArray arrayWithCapacity:mutations.count]; @@ -783,7 +781,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; request.writesArray = protos; request.streamToken = self.lastStreamToken; - FSTLog(@"FSTWriteStream %p mutation request: %@", (__bridge void *)self, request); + LOG_DEBUG("FSTWriteStream %s mutation request: %s", (__bridge void *)self, request); [self writeRequest:request]; } @@ -792,7 +790,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; * that on to the mutationResultsHandler. */ - (void)handleStreamMessage:(GCFSWriteResponse *)response { - FSTLog(@"FSTWriteStream %p response: %@", (__bridge void *)self, response); + LOG_DEBUG("FSTWriteStream %s response: %s", (__bridge void *)self, response); [self.workerDispatchQueue verifyIsCurrentQueue]; // Always capture the last stream token. diff --git a/Firestore/Source/Util/FSTAssert.h b/Firestore/Source/Util/FSTAssert.h deleted file mode 100644 index 610d306..0000000 --- a/Firestore/Source/Util/FSTAssert.h +++ /dev/null @@ -1,77 +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 - -// Fails the current Objective-C method if the given condition is false. -// -// Unlike NSAssert, this macro is never compiled out if assertions are disabled. -#define FSTAssert(condition, format, ...) \ - do { \ - if (!(condition)) { \ - FSTFail((format), ##__VA_ARGS__); \ - } \ - } while (0) - -// Fails the current C function if the given condition is false. -// -// Unlike NSCAssert, this macro is never compiled out if assertions are disabled. -#define FSTCAssert(condition, format, ...) \ - do { \ - if (!(condition)) { \ - FSTCFail((format), ##__VA_ARGS__); \ - } \ - } while (0) - -// Unconditionally fails the current Objective-C method. -// -// This macro fails by calling [[NSAssertionHandler currentHandler] handleFailureInMethod]. It -// also calls abort(3) in order to make this macro appear to never return, even though the call -// to handleFailureInMethod itself never returns. -#define FSTFail(format, ...) \ - do { \ - NSString *_file = [NSString stringWithUTF8String:__FILE__]; \ - NSString *_description = [NSString stringWithFormat:(format), ##__VA_ARGS__]; \ - [[NSAssertionHandler currentHandler] \ - handleFailureInMethod:_cmd \ - object:self \ - file:_file \ - lineNumber:__LINE__ \ - description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@", _description]; \ - abort(); \ - } while (0) - -// Unconditionally fails the current C function. -// -// This macro fails by calling [[NSAssertionHandler currentHandler] handleFailureInFunction]. It -// also calls abort(3) in order to make this macro appear to never return, even though the call -// to handleFailureInFunction itself never returns. -#define FSTCFail(format, ...) \ - do { \ - NSString *_file = [NSString stringWithUTF8String:__FILE__]; \ - NSString *_function = [NSString stringWithUTF8String:__PRETTY_FUNCTION__]; \ - NSString *_description = [NSString stringWithFormat:(format), ##__VA_ARGS__]; \ - [[NSAssertionHandler currentHandler] \ - handleFailureInFunction:_function \ - file:_file \ - lineNumber:__LINE__ \ - description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@", _description]; \ - abort(); \ - } while (0) - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Util/FSTDispatchQueue.mm b/Firestore/Source/Util/FSTDispatchQueue.mm index 01b2732..b921484 100644 --- a/Firestore/Source/Util/FSTDispatchQueue.mm +++ b/Firestore/Source/Util/FSTDispatchQueue.mm @@ -19,11 +19,11 @@ #include <memory> #include <utility> -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/memory/memory.h" using firebase::firestore::util::AsyncQueue; @@ -74,7 +74,7 @@ NS_ASSUME_NONNULL_BEGIN case TimerId::OnlineStateTimeout: return converted; default: - FSTAssert(false, @"Unknown value of enum FSTTimerID."); + HARD_FAIL("Unknown value of enum FSTTimerID."); } } diff --git a/Firestore/Source/Util/FSTLogger.mm b/Firestore/Source/Util/FSTLogger.mm deleted file mode 100644 index f0081e0..0000000 --- a/Firestore/Source/Util/FSTLogger.mm +++ /dev/null @@ -1,41 +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/FSTLogger.h" - -#import <FirebaseCore/FIRLogger.h> - -#import "Firestore/Source/API/FIRFirestore+Internal.h" - -NS_ASSUME_NONNULL_BEGIN - -void FSTLog(NSString *format, ...) { - if ([FIRFirestore isLoggingEnabled]) { - va_list args; - va_start(args, format); - FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerFirestore, @"I-FST000001", format, args); - va_end(args); - } -} - -void FSTWarn(NSString *format, ...) { - va_list args; - va_start(args, format); - FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerFirestore, @"I-FST000001", format, args); - va_end(args); -} - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Util/FSTUsageValidation.h b/Firestore/Source/Util/FSTUsageValidation.h index 05933ea..afc5412 100644 --- a/Firestore/Source/Util/FSTUsageValidation.h +++ b/Firestore/Source/Util/FSTUsageValidation.h @@ -30,7 +30,7 @@ NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...); * invalid method arguments. * * For recoverable runtime errors, use NSError**. - * For internal programming errors, use FSTFail(). + * For internal programming errors, use HARD_FAIL(). */ #define FSTThrowInvalidUsage(exceptionName, format, ...) \ do { \ diff --git a/Firestore/core/include/firebase/firestore/CMakeLists.txt b/Firestore/core/include/firebase/firestore/CMakeLists.txt index e4e7acd..0c7fd48 100644 --- a/Firestore/core/include/firebase/firestore/CMakeLists.txt +++ b/Firestore/core/include/firebase/firestore/CMakeLists.txt @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Hack to make the headers show up in IDEs +# Workaround to make the headers show up in IDEs # (see https://stackoverflow.com/questions/27039019/ and open issue on CMake # issue tracker: https://gitlab.kitware.com/cmake/cmake/issues/15234) add_custom_target(firebase_firestore_types_ide SOURCES diff --git a/Firestore/core/include/firebase/firestore/collection_reference.h b/Firestore/core/include/firebase/firestore/collection_reference.h new file mode 100644 index 0000000..4d47248 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/collection_reference.h @@ -0,0 +1,98 @@ +/* + * 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_COLLECTION_REFERENCE_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_COLLECTION_REFERENCE_H_ + +namespace firebase { +namespace firestore { + +class CollectionReferenceInternal; +class FirestoreInternal; + +/** + * A CollectionReference refers to a collection of documents location in a + * Firestore database and can be used for adding documents, getting document + * references, and querying for documents. + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class CollectionReference { + public: + /** + * @brief Default constructor. This creates an invalid CollectionReference. + * Attempting to perform any operations on this reference will fail unless a + * valid CollectionReference has been assigned to it. + */ + CollectionReference(); + + /** + * @brief Copy constructor. It's totally okay (and efficient) to copy + * CollectionReference instances, as they simply point to the same location in + * the database. + * + * @param[in] reference CollectionReference to copy from. + */ + CollectionReference(const CollectionReference& reference); + + /** + * @brief Move constructor. Moving is an efficient operation for + * CollectionReference instances. + * + * @param[in] reference CollectionReference to move data from. + */ + CollectionReference(CollectionReference&& reference); + + /** @brief Required virtual destructor. */ + virtual ~CollectionReference(); + + /** + * @brief Copy assignment operator. It's totally okay (and efficient) to copy + * CollectionReference instances, as they simply point to the same location in + * the database. + * + * @param[in] reference CollectionReference to copy from. + * + * @returns Reference to the destination CollectionReference. + */ + CollectionReference& operator=(const CollectionReference& reference); + + /** + * @brief Move assignment operator. Moving is an efficient operation for + * CollectionReference instances. + * + * @param[in] reference CollectionReference to move data from. + * + * @returns Reference to the destination CollectionReference. + */ + CollectionReference& operator=(CollectionReference&& reference); + + protected: + explicit CollectionReference(CollectionReferenceInternal* internal); + + private: + friend class DocumentReference; + friend class DocumentReferenceInternal; + friend class FirestoreInternal; + + // TODO(zxu123): investigate possibility to use std::unique_ptr or + // firebase::UniquePtr. + CollectionReferenceInternal* internal_ = nullptr; +}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_COLLECTION_REFERENCE_H_ diff --git a/Firestore/core/include/firebase/firestore/document_change.h b/Firestore/core/include/firebase/firestore/document_change.h new file mode 100644 index 0000000..4812290 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/document_change.h @@ -0,0 +1,34 @@ +/* + * 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_DOCUMENT_CHANGE_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_CHANGE_H_ + +namespace firebase { +namespace firestore { + +/** + * A DocumentChange represents a change to the documents matching a query. It + * contains the document affected and the type of change that occurred (added, + * modified, or removed). + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class DocumentChange {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_CHANGE_H_ diff --git a/Firestore/core/include/firebase/firestore/document_reference.h b/Firestore/core/include/firebase/firestore/document_reference.h index d295188..9385ed3 100644 --- a/Firestore/core/include/firebase/firestore/document_reference.h +++ b/Firestore/core/include/firebase/firestore/document_reference.h @@ -29,6 +29,17 @@ #include <functional> #endif +#include "firebase/app.h" +#include "firebase/firestore/collection_reference.h" +#include "firebase/firestore/document_snapshot.h" +#include "firebase/firestore/event_listener.h" +#include "firebase/firestore/field_value.h" +#include "firebase/firestore/firestore.h" +#include "firebase/firestore/firestore_errors.h" +#include "firebase/firestore/listener_registration.h" +#include "firebase/firestore/set_options.h" +#include "firebase/future.h" + // TODO(rsgowman): Note that RTDB uses: // #if defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN // to protect move operators from older compilers. But all our supported @@ -36,34 +47,12 @@ // here so we don't forget to mention this during the API review, and should be // removed once this note has migrated to the API review doc. -// TODO(rsgowman): replace these forward decls with appropriate includes (once -// they exist) -namespace firebase { -class App; -template <typename T> -class Future; -} // namespace firebase - namespace firebase { namespace firestore { -// TODO(rsgowman): replace these forward decls with appropriate includes (once -// they exist) -class FieldValue; -class DocumentSnapshot; +class DocumentReferenceInternal; class Firestore; -class Error; -template <typename T> -class EventListener; -class ListenerRegistration; -class CollectionReference; -class DocumentListenOptions; -// TODO(rsgowman): not quite a forward decl, but required to make the default -// parameter to Set() "compile". -class SetOptions { - public: - SetOptions(); -}; +class FirestoreInternal; // TODO(rsgowman): move this into the FieldValue header #ifdef STLPORT @@ -80,12 +69,19 @@ using MapFieldValue = std::unordered_map<std::string, FieldValue>; * * Create a DocumentReference via Firebase::Document(const string& path). * + * NOT thread-safe: an instance should not be used from multiple threads + * * Subclassing Note: Firestore classes are not meant to be subclassed except for * use in test mocks. Subclassing is not supported in production code and new * SDK releases may break code that does so. */ class DocumentReference { public: + enum class MetadataChanges { + kExclude, + kInclude, + }; + /** * @brief Default constructor. This creates an invalid DocumentReference. * Attempting to perform any operations on this reference will fail (and cause @@ -269,28 +265,15 @@ class DocumentReference { * this DocumentReference. (Ownership is not transferred; you are responsible * for making sure that listener is valid as long as this DocumentReference is * valid and the listener is registered.) + * @param[in] metadata_changes Indicates whether metadata-only changes (i.e. + * only DocumentSnapshot.getMetadata() changed) should trigger snapshot + * events. * * @return A registration object that can be used to remove the listener. */ virtual ListenerRegistration AddSnapshotListener( - EventListener<DocumentSnapshot>* listener); - - /** - * @brief Starts listening to the document referenced by this - * DocumentReference. - * - * @param[in] options The options to use for this listen. - * @param[in] listener The event listener that will be called with the - * snapshots, which must remain in memory until you remove the listener from - * this DocumentReference. (Ownership is not transferred; you are responsible - * for making sure that listener is valid as long as this DocumentReference is - * valid and the listener is registered.) - * - * @return A registration object that can be used to remove the listener. - */ - virtual ListenerRegistration AddSnapshotListener( - const DocumentListenOptions& options, - EventListener<DocumentSnapshot>* listener); + EventListener<DocumentSnapshot>* listener, + MetadataChanges metadata_changes = MetadataChanges::kExclude); #if defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN) /** @@ -299,6 +282,9 @@ class DocumentReference { * * @param[in] callback function or lambda to call. When this function is * called, exactly one of the parameters will be non-null. + * @param[in] metadata_changes Indicates whether metadata-only changes (i.e. + * only DocumentSnapshot.getMetadata() changed) should trigger snapshot + * events. * * @return A registration object that can be used to remove the listener. * @@ -306,28 +292,21 @@ class DocumentReference { * std::function is not supported on STLPort. */ virtual ListenerRegistration AddSnapshotListener( - std::function<void(const DocumentSnapshot*, const Error*)> callback); - - /** - * @brief Starts listening to the document referenced by this - * DocumentReference. - * - * @param[in] options The options to use for this listen. - * @param[in] callback function or lambda to call. When this function is - * called, exactly one of the parameters will be non-null. - * - * @return A registration object that can be used to remove the listener. - * - * @note This method is not available when using STLPort on Android, as - * std::function is not supported on STLPort. - */ - virtual ListenerRegistration AddSnapshotListener( - const DocumentListenOptions& options, - std::function<void(const DocumentSnapshot*, const Error*)> callback); + std::function<void(const DocumentSnapshot*, const Error*)> callback, + MetadataChanges metadata_changes = MetadataChanges::kExclude); #endif // defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN) + + protected: + explicit DocumentReference(DocumentReferenceInternal* internal); + + private: + friend class FirestoreInternal; + + // TODO(zxu123): investigate possibility to use std::unique_ptr or + // firebase::UniquePtr. + DocumentReferenceInternal* internal_ = nullptr; }; -// TODO(rsgowman): probably define and inline here. bool operator==(const DocumentReference& lhs, const DocumentReference& rhs); inline bool operator!=(const DocumentReference& lhs, diff --git a/Firestore/core/include/firebase/firestore/document_snapshot.h b/Firestore/core/include/firebase/firestore/document_snapshot.h new file mode 100644 index 0000000..3be72b5 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/document_snapshot.h @@ -0,0 +1,38 @@ +/* + * 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_DOCUMENT_SNAPSHOT_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_SNAPSHOT_H_ + +namespace firebase { +namespace firestore { + +/** + * A DocumentSnapshot contains data read from a document in your Firestore + * database. The data can be extracted with the data() method or by using + * FooValue() to access a specific field, where Foo is the type of that field. + * + * For a DocumentSnapshot that points to a non-existing document, any data + * access will cause a failed assertion. You can use the exists() method to + * explicitly verify a documents existence. + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class DocumentSnapshot {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_SNAPSHOT_H_ diff --git a/Firestore/core/include/firebase/firestore/event_listener.h b/Firestore/core/include/firebase/firestore/event_listener.h index 6c94428..cbe8a28 100644 --- a/Firestore/core/include/firebase/firestore/event_listener.h +++ b/Firestore/core/include/firebase/firestore/event_listener.h @@ -22,19 +22,19 @@ #ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_EVENT_LISTENER_H_ #define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_EVENT_LISTENER_H_ +#include "firebase/firestore/firestore_errors.h" + namespace firebase { namespace firestore { -// TODO(rsgowman): replace these forward decl's with appropriate includes (once -// they exist) -class Error; - /** * @brief An interface for event listeners. */ template <typename T> class EventListener { public: + virtual ~EventListener() { + } /** * @brief OnEvent will be called with the new value or the error if an error * occurred. @@ -44,7 +44,7 @@ class EventListener { * @param value The value of the event. null if there was an error. * @param error The error if there was error. null otherwise. */ - void OnEvent(const T* value, const Error* error); + virtual void OnEvent(const T* value, const Error* error) = 0; }; } // namespace firestore diff --git a/Firestore/core/include/firebase/firestore/field_path.h b/Firestore/core/include/firebase/firestore/field_path.h new file mode 100644 index 0000000..29e1dea --- /dev/null +++ b/Firestore/core/include/firebase/firestore/field_path.h @@ -0,0 +1,34 @@ +/* + * 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_FIELD_PATH_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIELD_PATH_H_ + +namespace firebase { +namespace firestore { + +/** + * A FieldPath refers to a field in a document. The path may consist of a single + * field name (referring to a top level field in the document), or a list of + * field names (referring to a nested field in the document). + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class FieldPath {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIELD_PATH_H_ diff --git a/Firestore/core/include/firebase/firestore/field_value.h b/Firestore/core/include/firebase/firestore/field_value.h new file mode 100644 index 0000000..d919de4 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/field_value.h @@ -0,0 +1,33 @@ +/* + * 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_FIELD_VALUE_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIELD_VALUE_H_ + +namespace firebase { +namespace firestore { + +/** + * Sentinel values that can be used when writing document fields with setData() + * or updateData(). + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class FieldValue {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIELD_VALUE_H_ diff --git a/Firestore/core/include/firebase/firestore/firestore.h b/Firestore/core/include/firebase/firestore/firestore.h index 793fdd0..6591a72 100644 --- a/Firestore/core/include/firebase/firestore/firestore.h +++ b/Firestore/core/include/firebase/firestore/firestore.h @@ -22,23 +22,19 @@ #ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_H_ #define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_H_ +#include <memory> #include <string> -// TODO(rsgowman): replace these forward decl's with appropriate includes (once -// they exist) -namespace firebase { -class App; -class InitResult; -} // namespace firebase +#include "firebase/app.h" +#include "firebase/firestore/collection_reference.h" +#include "firebase/firestore/document_reference.h" +#include "firebase/firestore/settings.h" namespace firebase { namespace firestore { -// TODO(rsgowman): replace these forward decl's with appropriate includes (once -// they exist) class DocumentReference; -class CollectionReference; -class Settings; +class FirestoreInternal; /** * @brief Entry point for the Firebase Firestore C++ SDK. @@ -152,6 +148,16 @@ class Firestore { /** Globally enables / disables Firestore logging for the SDK. */ static void set_logging_enabled(bool logging_enabled); + + Firestore(const Firestore& src) = delete; + Firestore& operator=(const Firestore& src) = delete; + + private: + explicit Firestore(::firebase::App* app); + + // TODO(zxu123): investigate possibility to use std::unique_ptr or + // firebase::UniquePtr. + FirestoreInternal* internal_ = nullptr; }; } // namespace firestore diff --git a/Firestore/core/include/firebase/firestore/firestore_errors.h b/Firestore/core/include/firebase/firestore/firestore_errors.h index 7a0ff7c..92c0c92 100644 --- a/Firestore/core/include/firebase/firestore/firestore_errors.h +++ b/Firestore/core/include/firebase/firestore/firestore_errors.h @@ -109,6 +109,10 @@ enum FirestoreErrorCode { Unauthenticated = 16 }; +// TODO(zxu123): decide whether we actually want an Error class or just use +// enum. +using Error = FirestoreErrorCode; + } // namespace firestore } // namespace firebase diff --git a/Firestore/core/include/firebase/firestore/listener_registration.h b/Firestore/core/include/firebase/firestore/listener_registration.h new file mode 100644 index 0000000..a37c2aa --- /dev/null +++ b/Firestore/core/include/firebase/firestore/listener_registration.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_INCLUDE_FIREBASE_FIRESTORE_LISTENER_REGISTRATION_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_LISTENER_REGISTRATION_H_ + +namespace firebase { +namespace firestore { + +class FirestoreInternal; +class ListenerRegistrationInternal; + +/** Represents a listener that can be removed by calling remove. */ +class ListenerRegistration { + public: + /** + * @brief Default constructor. This creates a no-op instance. + */ + ListenerRegistration(); + + /** + * @brief Copy constructor. It's totally okay to copy ListenerRegistration + * instances. + * + * @param[in] registration ListenerRegistration to copy from. + */ + ListenerRegistration(const ListenerRegistration& registration); + + /** + * @brief Move constructor. Moving is an efficient operation for + * ListenerRegistration instances. + * + * @param[in] registration ListenerRegistration to move data from. + */ + ListenerRegistration(ListenerRegistration&& registration); + + ~ListenerRegistration(); + + /** + * @brief Copy assignment operator. It's totally okay to copy + * ListenerRegistration instances. + * + * @param[in] registration ListenerRegistration to copy from. + * + * @returns Reference to the destination ListenerRegistration. + */ + ListenerRegistration& operator=(const ListenerRegistration& registration); + + /** + * @brief Move assignment operator. Moving is an efficient operation for + * ListenerRegistration instances. + * + * @param[in] registration ListenerRegistration to move data from. + * + * @returns Reference to the destination ListenerRegistration. + */ + ListenerRegistration& operator=(ListenerRegistration&& registration); + + /** + * Removes the listener being tracked by this ListenerRegistration. After the + * initial call, subsequent calls have no effect. + */ + void Remove(); + + private: + friend class DocumentReferenceInternal; + friend class ListenerRegistrationInternal; + friend class FirestoreInternal; + + explicit ListenerRegistration(ListenerRegistrationInternal* internal); + + FirestoreInternal* firestore_ = nullptr; + ListenerRegistrationInternal* internal_ = nullptr; +}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_LISTENER_REGISTRATION_H_ diff --git a/Firestore/core/include/firebase/firestore/query.h b/Firestore/core/include/firebase/firestore/query.h new file mode 100644 index 0000000..da6dfdd --- /dev/null +++ b/Firestore/core/include/firebase/firestore/query.h @@ -0,0 +1,33 @@ +/* + * 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_QUERY_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_QUERY_H_ + +namespace firebase { +namespace firestore { + +/** + * A Query which you can read or listen to. You can also construct refined + * Query objects by adding filters and ordering. + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class Query {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_QUERY_H_ diff --git a/Firestore/core/include/firebase/firestore/query_snapshot.h b/Firestore/core/include/firebase/firestore/query_snapshot.h new file mode 100644 index 0000000..ffa2bd6 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/query_snapshot.h @@ -0,0 +1,34 @@ +/* + * 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_QUERY_SNAPSHOT_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_QUERY_SNAPSHOT_H_ + +namespace firebase { +namespace firestore { + +/** + * A QuerySnapshot contains zero or more DocumentSnapshot objects. It can be + * iterated using a range-based for loop and its size can be inspected with + * empty() and count(). + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class QuerySnapshot {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_QUERY_SNAPSHOT_H_ diff --git a/Firestore/core/include/firebase/firestore/set_options.h b/Firestore/core/include/firebase/firestore/set_options.h new file mode 100644 index 0000000..802f3b5 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/set_options.h @@ -0,0 +1,39 @@ +/* + * 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_SET_OPTIONS_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SET_OPTIONS_H_ + +namespace firebase { +namespace firestore { + +/** + * An options object that configures the behavior of Set() calls. By providing + * the SetOptions objects returned by Merge(), the Set() methods in + * DocumentReference, WriteBatch and Transaction can be configured to perform + * granular merges instead of overwriting the target documents in their + * entirety. + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class SetOptions { + public: + SetOptions(); +}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SET_OPTIONS_H_ diff --git a/Firestore/Source/Util/FSTLogger.h b/Firestore/core/include/firebase/firestore/settings.h index c4e2b85..9356b26 100644 --- a/Firestore/Source/Util/FSTLogger.h +++ b/Firestore/core/include/firebase/firestore/settings.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Google + * 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. @@ -14,13 +14,19 @@ * limitations under the License. */ -#import <Foundation/Foundation.h> +#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SETTINGS_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SETTINGS_H_ -NS_ASSUME_NONNULL_BEGIN +namespace firebase { +namespace firestore { -/** Logs to NSLog if [FIRFirestore isLoggingEnabled] is YES. */ -void FSTLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2); +class SettingsInternal; -void FSTWarn(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2); +/** Settings used to configure a Firestore instance. */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class Settings {}; -NS_ASSUME_NONNULL_END +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SETTINGS_H_ diff --git a/Firestore/core/include/firebase/firestore/snapshot_metadata.h b/Firestore/core/include/firebase/firestore/snapshot_metadata.h new file mode 100644 index 0000000..9bcc54c --- /dev/null +++ b/Firestore/core/include/firebase/firestore/snapshot_metadata.h @@ -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. + */ + +#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SNAPSHOT_METADATA_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SNAPSHOT_METADATA_H_ + +namespace firebase { +namespace firestore { + +/** Metadata about a snapshot, describing the state of the snapshot. */ +class SnapshotMetadata { + public: + SnapshotMetadata(bool has_pending_writes, bool is_from_cache) + : has_pending_writes_(has_pending_writes), is_from_cache_(is_from_cache) { + } + + bool has_pending_writes() const { + return has_pending_writes_; + } + + bool is_from_cache() const { + return is_from_cache_; + } + + private: + const bool has_pending_writes_; + const bool is_from_cache_; +}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_SNAPSHOT_METADATA_H_ diff --git a/Firestore/core/include/firebase/firestore/transaction.h b/Firestore/core/include/firebase/firestore/transaction.h new file mode 100644 index 0000000..be043b8 --- /dev/null +++ b/Firestore/core/include/firebase/firestore/transaction.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_INCLUDE_FIREBASE_FIRESTORE_TRANSACTION_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TRANSACTION_H_ + +namespace firebase { +namespace firestore { + +/** + * Transaction provides methods to read and write data within a transaction. + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class Transaction {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TRANSACTION_H_ diff --git a/Firestore/core/include/firebase/firestore/write_batch.h b/Firestore/core/include/firebase/firestore/write_batch.h new file mode 100644 index 0000000..bd2c12f --- /dev/null +++ b/Firestore/core/include/firebase/firestore/write_batch.h @@ -0,0 +1,39 @@ +/* + * 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_WRITE_BATCH_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_WRITE_BATCH_H_ + +namespace firebase { +namespace firestore { + +/** + * A write batch is used to perform multiple writes as a single atomic unit. + * + * A WriteBatch object provides methods for adding writes to the write batch. + * None of the writes will be committed (or visible locally) until commit() is + * called. + * + * Unlike transactions, write batches are persisted offline and therefore are + * preferable when you don't need to condition your writes on read data. + */ +// TODO(zxu123): add more methods to complete the class and make it useful. +class WriteBatch {}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_WRITE_BATCH_H_ diff --git a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc index 3581ef5..da9f004 100644 --- a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc +++ b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc @@ -212,9 +212,7 @@ void LevelDbTransaction::Commit() { batch.Put(it->first, it->second); } - if (util::LogGetLevel() <= util::kLogLevelDebug) { - util::LogDebug("Committing transaction: %s", ToString().c_str()); - } + LOG_DEBUG("Committing transaction: %s", ToString()); Status status = db_->Write(write_options_, &batch); HARD_ASSERT(status.ok(), "Failed to commit transaction:\n%s\n Failed: %s", diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.cc b/Firestore/core/src/firebase/firestore/remote/serializer.cc index 47c2abf..ccc5ac3 100644 --- a/Firestore/core/src/firebase/firestore/remote/serializer.cc +++ b/Firestore/core/src/firebase/firestore/remote/serializer.cc @@ -499,45 +499,94 @@ Serializer::DecodeMaybeDocument(const uint8_t* bytes, size_t length) const { std::unique_ptr<MaybeDocument> Serializer::DecodeBatchGetDocumentsResponse( Reader* reader) const { - Tag tag = reader->ReadTag(); if (!reader->status().ok()) return nullptr; - // Ensure the tag matches the wire type - switch (tag.field_number) { - case google_firestore_v1beta1_BatchGetDocumentsResponse_found_tag: - case google_firestore_v1beta1_BatchGetDocumentsResponse_missing_tag: - if (tag.wire_type != PB_WT_STRING) { - reader->set_status( - Status(FirestoreErrorCode::DataLoss, - "Input proto bytes cannot be parsed (mismatch between " - "the wiretype and the field number (tag))")); - } - break; + // Initialize BatchGetDocumentsResponse fields to their default values + std::unique_ptr<MaybeDocument> found; + std::string missing; + // We explicitly ignore the 'transaction' field + SnapshotVersion read_time = SnapshotVersion::None(); - default: - reader->set_status(Status( - FirestoreErrorCode::DataLoss, - "Input proto bytes cannot be parsed (invalid field number (tag))")); - } + while (reader->bytes_left()) { + Tag tag = reader->ReadTag(); + if (!reader->status().ok()) return nullptr; - if (!reader->status().ok()) return nullptr; + // Ensure the tag matches the wire type + switch (tag.field_number) { + case google_firestore_v1beta1_BatchGetDocumentsResponse_found_tag: + case google_firestore_v1beta1_BatchGetDocumentsResponse_missing_tag: + case google_firestore_v1beta1_BatchGetDocumentsResponse_transaction_tag: + case google_firestore_v1beta1_BatchGetDocumentsResponse_read_time_tag: + if (tag.wire_type != PB_WT_STRING) { + reader->set_status( + Status(FirestoreErrorCode::DataLoss, + "Input proto bytes cannot be parsed (mismatch between " + "the wiretype and the field number (tag))")); + } + break; - switch (tag.field_number) { - case google_firestore_v1beta1_BatchGetDocumentsResponse_found_tag: - return reader->ReadNestedMessage<std::unique_ptr<MaybeDocument>>( - [this](Reader* reader) -> std::unique_ptr<MaybeDocument> { - return DecodeDocument(reader); - }); - case google_firestore_v1beta1_BatchGetDocumentsResponse_missing_tag: - // TODO(rsgowman): Right now, we only support Document (and don't support - // NoDocument). That should change in the next PR or so. - abort(); - default: - // This indicates an internal error as we've already ensured that this is - // a valid field_number. - HARD_FAIL( - "Somehow got an unexpected field number (tag) after verifying that " - "the field number was expected."); + default: + reader->set_status(Status( + FirestoreErrorCode::DataLoss, + "Input proto bytes cannot be parsed (invalid field number (tag))")); + } + + if (!reader->status().ok()) return nullptr; + + switch (tag.field_number) { + case google_firestore_v1beta1_BatchGetDocumentsResponse_found_tag: + // 'found' and 'missing' are part of a oneof. The proto docs claim that + // if both are set on the wire, the last one wins. + missing = ""; + + // TODO(rsgowman): If multiple 'found' values are found, we should merge + // them (rather than using the last one.) + found = reader->ReadNestedMessage<std::unique_ptr<MaybeDocument>>( + [this](Reader* reader) -> std::unique_ptr<MaybeDocument> { + return DecodeDocument(reader); + }); + break; + + case google_firestore_v1beta1_BatchGetDocumentsResponse_missing_tag: + // 'found' and 'missing' are part of a oneof. The proto docs claim that + // if both are set on the wire, the last one wins. + found = nullptr; + + missing = reader->ReadString(); + break; + + case google_firestore_v1beta1_BatchGetDocumentsResponse_transaction_tag: + // This field is ignored by the client sdk, but we still need to extract + // it. + // TODO(rsgowman) switch this to reader->SkipField() (or whatever we end + // up calling it) once that exists. Possibly group this with other + // ignored and/or unknown fields + reader->ReadString(); + break; + + case google_firestore_v1beta1_BatchGetDocumentsResponse_read_time_tag: + read_time = SnapshotVersion{ + reader->ReadNestedMessage<Timestamp>(DecodeTimestamp)}; + break; + + default: + // This indicates an internal error as we've already ensured that this + // is a valid field_number. + HARD_FAIL( + "Somehow got an unexpected field number (tag) after verifying that " + "the field number was expected."); + } + } + + if (found != nullptr) { + return found; + } else if (!missing.empty()) { + return absl::make_unique<NoDocument>(DecodeKey(missing), read_time); + } else { + reader->set_status(Status(FirestoreErrorCode::DataLoss, + "Invalid BatchGetDocumentsReponse message: " + "Neither 'found' nor 'missing' fields set.")); + return nullptr; } } diff --git a/Firestore/core/src/firebase/firestore/util/log.h b/Firestore/core/src/firebase/firestore/util/log.h index 1944596..248d434 100644 --- a/Firestore/core/src/firebase/firestore/util/log.h +++ b/Firestore/core/src/firebase/firestore/util/log.h @@ -17,44 +17,65 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_LOG_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_LOG_H_ -#include <cstdarg> +#include <string> + +#include "Firestore/core/src/firebase/firestore/util/string_format.h" namespace firebase { namespace firestore { namespace util { -/// @brief Levels used when logging messages. +// Levels used when logging messages. enum LogLevel { - /// Verbose Log Level - kLogLevelVerbose = 0, - /// Debug Log Level + // Debug Log Level kLogLevelDebug, - /// Info Log Level - kLogLevelInfo, - /// Warning Log Level + // Warning Log Level kLogLevelWarning, - /// Error Log Level - kLogLevelError, }; -// Common log methods. +// Log a message if kLogLevelDebug is enabled. Arguments are not evaluated if +// logging is disabled. +// +// @param format A format string suitable for use with `util::StringFormat` +// @param ... C++ variadic arguments that match the format string. Not C +// varargs. +#define LOG_DEBUG(...) \ + do { \ + namespace _util = firebase::firestore::util; \ + if (_util::LogIsLoggable(_util::kLogLevelDebug)) { \ + std::string _message = _util::StringFormat(__VA_ARGS__); \ + _util::LogMessage(_util::kLogLevelDebug, _message); \ + } \ + } while (0) + +// Log a message if kLogLevelWarn is enabled (it is by default). Arguments are +// not evaluated if logging is disabled. +// +// @param format A format string suitable for use with `util::StringFormat` +// @param ... C++ variadic arguments that match the format string. Not C +// varargs. +#define LOG_WARN(...) \ + do { \ + namespace _util = firebase::firestore::util; \ + if (_util::LogIsLoggable(_util::kLogLevelWarning)) { \ + std::string _message = _util::StringFormat(__VA_ARGS__); \ + _util::LogMessage(_util::kLogLevelWarning, _message); \ + } \ + } while (0) + +// Tests to see if the given log level is loggable. +bool LogIsLoggable(LogLevel level); + +// Is debug logging enabled? +inline bool LogIsDebugEnabled() { + return LogIsLoggable(kLogLevelDebug); +} // 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, ...); + +// Log a message at the given level. +void LogMessage(LogLevel log_level, const std::string& message); } // namespace util } // namespace firestore diff --git a/Firestore/core/src/firebase/firestore/util/log_apple.mm b/Firestore/core/src/firebase/firestore/util/log_apple.mm index cb2c58e..45e4f55 100644 --- a/Firestore/core/src/firebase/firestore/util/log_apple.mm +++ b/Firestore/core/src/firebase/firestore/util/log_apple.mm @@ -19,6 +19,7 @@ #import <FirebaseCore/FIRLogger.h> #import <Foundation/Foundation.h> +#include <cstdarg> #include <string> #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -32,90 +33,40 @@ 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, ...) { +// Actually logs a message via FIRLogger. This must be a C varargs function +// so that we can call FIRLogBasic which takes a `va_list`. +void LogMessageV(LogLevel level, NSString* 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); -} + FIRLogBasic(ToFIRLoggerLevel(level), kFIRLoggerFirestore, @"I-FST000001", + format, 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); +} // namespace + +void LogSetLevel(LogLevel level) { + FIRSetLoggerLevel(ToFIRLoggerLevel(level)); } -void LogMessageV(LogLevel log_level, const char* format, va_list args) { - FIRLogBasic(ToFIRLoggerLevel(log_level), kFIRLoggerFirestore, @"I-FST000001", - WrapNSStringNoCopy(format), args); +bool LogIsLoggable(LogLevel level) { + return FIRIsLoggableLevel(ToFIRLoggerLevel(level), NO); } -void LogMessage(LogLevel log_level, const char* format, ...) { - va_list list; - va_start(list, format); - LogMessageV(log_level, format, list); - va_end(list); +void LogMessage(LogLevel level, const std::string& message) { + LogMessageV(level, @"%s", message.c_str()); } } // namespace util diff --git a/Firestore/core/src/firebase/firestore/util/log_stdio.cc b/Firestore/core/src/firebase/firestore/util/log_stdio.cc index b277406..6fff885 100644 --- a/Firestore/core/src/firebase/firestore/util/log_stdio.cc +++ b/Firestore/core/src/firebase/firestore/util/log_stdio.cc @@ -19,77 +19,42 @@ #include <cstdio> #include <string> +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + namespace firebase { namespace firestore { namespace util { -LogLevel g_log_level = kLogLevelInfo; +LogLevel g_log_level = kLogLevelWarning; 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); +bool LogIsLoggable(LogLevel level) { + return level >= g_log_level; } -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) { +void LogMessage(LogLevel log_level, const std::string& message) { if (log_level < g_log_level) { return; } + + const char* level_word; + switch (log_level) { - case kLogLevelVerbose: - printf("VERBOSE: "); - break; case kLogLevelDebug: - printf("DEBUG: "); - break; - case kLogLevelInfo: + level_word = "DEBUG"; break; case kLogLevelWarning: - printf("WARNING: "); + level_word = "WARNING"; break; - case kLogLevelError: - printf("ERROR: "); + default: + UNREACHABLE(); 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); + printf("%s: %s\n", level_word, message.c_str()); } } // namespace util diff --git a/Firestore/core/src/firebase/firestore/util/string_format.h b/Firestore/core/src/firebase/firestore/util/string_format.h index 3d7a1dc..d691984 100644 --- a/Firestore/core/src/firebase/firestore/util/string_format.h +++ b/Firestore/core/src/firebase/firestore/util/string_format.h @@ -21,6 +21,7 @@ #include <string> #include <utility> +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/base/attributes.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" @@ -80,6 +81,37 @@ class FormatArg : public absl::AlphaNum { : AlphaNum{bool_value ? "true" : "false"} { } +#if __OBJC__ + /** + * Creates a FormatArg from any pointer to an object derived from NSObject. + */ + template < + typename T, + typename = typename std::enable_if<std::is_base_of<NSObject, T>{}>::type> + FormatArg(T* object, internal::FormatChoice<0>) + : AlphaNum{MakeStringView([object description])} { + } + + /** + * Creates a FormatArg from any Objective-C Class type. Objective-C Class + * types are a special struct that aren't of a type derived from NSObject. + */ + FormatArg(Class object, internal::FormatChoice<0>) + : AlphaNum{MakeStringView(NSStringFromClass(object))} { + } + + /** + * Creates a FormatArg from any id pointer. Note that instances of `id<Foo>` + * (which means "pointer conforming to the protocol Foo") do not match this + * without first casting to type `id`. There's no way to express a template of + * `id<T>` since `id<Foo>` isn't actually a C++ template and `id` isn't a + * parameterized C++ class. + */ + FormatArg(id object, internal::FormatChoice<0>) + : AlphaNum{MakeStringView([object description])} { + } +#endif + /** * Creates a FormatArg from a character string literal. This is * handled specially to avoid ambiguity with generic pointers, which are diff --git a/Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm b/Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm index c87949a..bb2f836 100644 --- a/Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm +++ b/Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm @@ -17,8 +17,6 @@ #import <XCTest/XCTest.h> #import <objc/runtime.h> -#import "Firestore/Source/Util/FSTAssert.h" - #include "gtest/gtest.h" /** diff --git a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc index dd0fae2..999acb8 100644 --- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc +++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc @@ -42,6 +42,7 @@ #include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" +#include "absl/types/optional.h" #include "google/protobuf/stubs/common.h" #include "google/protobuf/util/message_differencer.h" #include "gtest/gtest.h" @@ -109,6 +110,13 @@ class SerializerTest : public ::testing::Test { ExpectDeserializationRoundTrip(key, value, update_time, proto); } + void ExpectNoDocumentDeserializationRoundTrip( + const DocumentKey& key, + const SnapshotVersion& read_time, + const v1beta1::BatchGetDocumentsResponse& proto) { + ExpectDeserializationRoundTrip(key, absl::nullopt, read_time, proto); + } + /** * Checks the status. Don't use directly; use one of the relevant macros * instead. eg: @@ -138,13 +146,21 @@ class SerializerTest : public ::testing::Test { * * @param status the expected (failed) status. Only the code() is verified. */ - void ExpectFailedStatusDuringDecode(Status status, - const std::vector<uint8_t>& bytes) { + void ExpectFailedStatusDuringFieldValueDecode( + Status status, const std::vector<uint8_t>& bytes) { StatusOr<FieldValue> bad_status = serializer.DecodeFieldValue(bytes); ASSERT_NOT_OK(bad_status); EXPECT_EQ(status.code(), bad_status.status().code()); } + void ExpectFailedStatusDuringMaybeDocumentDecode( + Status status, const std::vector<uint8_t>& bytes) { + StatusOr<std::unique_ptr<MaybeDocument>> bad_status = + serializer.DecodeMaybeDocument(bytes); + ASSERT_NOT_OK(bad_status); + EXPECT_EQ(status.code(), bad_status.status().code()); + } + v1beta1::Value ValueProto(nullptr_t) { std::vector<uint8_t> bytes = EncodeFieldValue(&serializer, FieldValue::NullValue()); @@ -222,20 +238,21 @@ class SerializerTest : public ::testing::Test { /** * Creates entries in the proto that we don't care about. * - * We ignore create time in our serializer. We never set it, and never read it - * (other than to throw it away). But the server could (and probably does) set - * it, so we need to be able to discard it properly. The ExpectRoundTrip deals - * with this asymmetry. + * We ignore certain fields in our serializer. We never set them, and never + * read them (other than to throw them away). But the server could (and + * probably does) set them, so we need to be able to discard them properly. + * The ExpectRoundTrip deals with this asymmetry. * * This method adds these ignored fields to the proto. */ void TouchIgnoredBatchGetDocumentsResponseFields( v1beta1::BatchGetDocumentsResponse* proto) { + proto->set_transaction("random bytes"); + // TODO(rsgowman): This method currently assumes that this is a 'found' // document. We (probably) will need to adjust this to work with NoDocuments // too. v1beta1::Document* doc_proto = proto->mutable_found(); - google::protobuf::Timestamp* create_time_proto = doc_proto->mutable_create_time(); create_time_proto->set_seconds(8765); @@ -279,8 +296,8 @@ class SerializerTest : public ::testing::Test { bool ok = actual_proto.ParseFromArray(bytes.data(), bytes.size()); EXPECT_TRUE(ok); - // TODO(rsgowman): Right now, we only support Document (and don't support - // NoDocument). That should change in the next PR or so. + // Note that the client can only serialize Documents (and cannot serialize + // NoDocuments) EXPECT_TRUE(proto.has_found()); // Slight weirdness: When we *encode* a document for sending it to the @@ -303,8 +320,8 @@ class SerializerTest : public ::testing::Test { void ExpectDeserializationRoundTrip( const DocumentKey& key, - const FieldValue& value, - const SnapshotVersion& update_time, + const absl::optional<FieldValue> value, + const SnapshotVersion& version, // either update_time or read_time const v1beta1::BatchGetDocumentsResponse& proto) { size_t size = proto.ByteSizeLong(); std::vector<uint8_t> bytes(size); @@ -316,13 +333,20 @@ class SerializerTest : public ::testing::Test { std::unique_ptr<MaybeDocument> actual_model = std::move(actual_model_status).ValueOrDie(); - // TODO(rsgowman): Right now, we only support Document (and don't support - // NoDocument). That should change in the next PR or so. - EXPECT_EQ(MaybeDocument::Type::Document, actual_model->type()); - Document* actual_doc_model = static_cast<Document*>(actual_model.get()); EXPECT_EQ(key, actual_model->key()); - EXPECT_EQ(value, actual_doc_model->data()); - EXPECT_EQ(update_time, actual_model->version()); + EXPECT_EQ(version, actual_model->version()); + switch (actual_model->type()) { + case MaybeDocument::Type::Document: { + Document* actual_doc_model = static_cast<Document*>(actual_model.get()); + EXPECT_EQ(value, actual_doc_model->data()); + break; + } + case MaybeDocument::Type::NoDocument: + EXPECT_FALSE(value.has_value()); + break; + case MaybeDocument::Type::Unknown: + FAIL() << "We somehow created an invalid model object"; + } } std::string message_differences; @@ -457,7 +481,7 @@ TEST_F(SerializerTest, BadNullValue) { // Alter the null value from 0 to 1. Mutate(&bytes[1], /*expected_initial_value=*/0, /*new_value=*/1); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -468,7 +492,7 @@ TEST_F(SerializerTest, BadBoolValue) { // Alter the bool value from 1 to 2. (Value values are 0,1) Mutate(&bytes[1], /*expected_initial_value=*/1, /*new_value=*/2); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -487,7 +511,7 @@ TEST_F(SerializerTest, BadIntegerValue) { bytes.resize(12); bytes[11] = 0x7f; - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -499,7 +523,7 @@ TEST_F(SerializerTest, BadStringValue) { // used by the encoded tag.) Mutate(&bytes[2], /*expected_initial_value=*/1, /*new_value=*/5); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -510,7 +534,7 @@ TEST_F(SerializerTest, BadTimestampValue_TooLarge) { // Add some time, which should push us above the maximum allowed timestamp. Mutate(&bytes[4], 0x82, 0x83); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -521,7 +545,7 @@ TEST_F(SerializerTest, BadTimestampValue_TooSmall) { // Remove some time, which should push us below the minimum allowed timestamp. Mutate(&bytes[4], 0x92, 0x91); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -540,9 +564,9 @@ TEST_F(SerializerTest, BadTag) { // status. Remove this EXPECT_ANY_THROW statement (and reenable the // following commented out statement) once the corresponding assert has been // removed from serializer.cc. - EXPECT_ANY_THROW(ExpectFailedStatusDuringDecode( + EXPECT_ANY_THROW(ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes)); - // ExpectFailedStatusDuringDecode( + // ExpectFailedStatusDuringFieldValueDecode( // Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -555,7 +579,7 @@ TEST_F(SerializerTest, TagVarintWiretypeStringMismatch) { // would do.) Mutate(&bytes[0], /*expected_initial_value=*/0x08, /*new_value=*/0x0a); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -566,7 +590,7 @@ TEST_F(SerializerTest, TagStringWiretypeVarintMismatch) { // 0x88 represents a string value encoded as a varint. Mutate(&bytes[0], /*expected_initial_value=*/0x8a, /*new_value=*/0x88); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -579,13 +603,13 @@ TEST_F(SerializerTest, IncompleteFieldValue) { ASSERT_EQ(0x00, bytes[1]); bytes.pop_back(); - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } TEST_F(SerializerTest, IncompleteTag) { std::vector<uint8_t> bytes; - ExpectFailedStatusDuringDecode( + ExpectFailedStatusDuringFieldValueDecode( Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); } @@ -679,5 +703,35 @@ TEST_F(SerializerTest, EncodesNonEmptyDocument) { ExpectRoundTrip(key, fields, update_time, proto); } +TEST_F(SerializerTest, DecodesNoDocument) { + // We can't actually *encode* a NoDocument; the method exposed by the + // serializer requires both the document key and contents (as an ObjectValue, + // i.e. map.) The contents can be empty, but not missing. As a result, this + // test will only verify the ability to decode a NoDocument. + + DocumentKey key = DocumentKey::FromPathString("path/to/the/doc"); + SnapshotVersion read_time = + SnapshotVersion{{/*seconds=*/1234, /*nanoseconds=*/5678}}; + + v1beta1::BatchGetDocumentsResponse proto; + proto.set_missing(serializer.EncodeKey(key)); + google::protobuf::Timestamp* read_time_proto = proto.mutable_read_time(); + read_time_proto->set_seconds(read_time.timestamp().seconds()); + read_time_proto->set_nanos(read_time.timestamp().nanoseconds()); + + ExpectNoDocumentDeserializationRoundTrip(key, read_time, proto); +} + +TEST_F(SerializerTest, DecodeMaybeDocWithoutFoundOrMissingSetShouldFail) { + v1beta1::BatchGetDocumentsResponse proto; + + std::vector<uint8_t> bytes(proto.ByteSizeLong()); + bool status = proto.SerializeToArray(bytes.data(), bytes.size()); + EXPECT_TRUE(status); + + ExpectFailedStatusDuringMaybeDocumentDecode( + Status(FirestoreErrorCode::DataLoss, "ignored"), bytes); +} + // TODO(rsgowman): Test [en|de]coding multiple protos into the same output // vector. diff --git a/Firestore/core/test/firebase/firestore/util/log_test.cc b/Firestore/core/test/firebase/firestore/util/log_test.cc index 973b174..73050ea 100644 --- a/Firestore/core/test/firebase/firestore/util/log_test.cc +++ b/Firestore/core/test/firebase/firestore/util/log_test.cc @@ -33,27 +33,19 @@ namespace util { // defaults write firebase_firestore_util_log_apple_test // /google/firebase/debug_mode NO TEST(Log, SetAndGet) { - LogSetLevel(kLogLevelVerbose); + EXPECT_FALSE(LogIsDebugEnabled()); LogSetLevel(kLogLevelDebug); - EXPECT_EQ(kLogLevelDebug, LogGetLevel()); - - LogSetLevel(kLogLevelInfo); - EXPECT_EQ(kLogLevelInfo, LogGetLevel()); + EXPECT_TRUE(LogIsDebugEnabled()); LogSetLevel(kLogLevelWarning); - EXPECT_EQ(kLogLevelWarning, LogGetLevel()); - - LogSetLevel(kLogLevelError); - EXPECT_EQ(kLogLevelError, LogGetLevel()); + EXPECT_FALSE(LogIsDebugEnabled()); } 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); + LOG_DEBUG("test debug logging %s", 1); + LOG_WARN("test warning logging %s", 3); + LOG_DEBUG("test va-args %s %s %s", "abc", std::string{"def"}, 123); } } // namespace util diff --git a/Firestore/third_party/Immutable/FSTArraySortedDictionary.m b/Firestore/third_party/Immutable/FSTArraySortedDictionary.m index e9325a7..985b514 100644 --- a/Firestore/third_party/Immutable/FSTArraySortedDictionary.m +++ b/Firestore/third_party/Immutable/FSTArraySortedDictionary.m @@ -1,7 +1,6 @@ #import "Firestore/third_party/Immutable/FSTArraySortedDictionary.h" #import "Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h" NS_ASSUME_NONNULL_BEGIN @@ -38,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN for (id key in keys) { values[pos++] = dictionary[key]; } - FSTAssert(values.count == keys.count, @"We added as many keys as values"); + NSAssert(values.count == keys.count, @"We added as many keys as values"); return [[FSTArraySortedDictionary alloc] initWithComparator:comparator keys:keys values:values]; } @@ -50,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN - (id)initWithComparator:(NSComparator)comparator keys:(NSArray *)keys values:(NSArray *)values { self = [super init]; if (self != nil) { - FSTAssert(keys.count == values.count, @"keys and values must have the same count"); + NSAssert(keys.count == values.count, @"keys and values must have the same count"); _comparator = comparator; _keys = keys; _values = values; diff --git a/Firestore/third_party/Immutable/FSTLLRBValueNode.m b/Firestore/third_party/Immutable/FSTLLRBValueNode.m index 194a393..e2590a1 100644 --- a/Firestore/third_party/Immutable/FSTLLRBValueNode.m +++ b/Firestore/third_party/Immutable/FSTLLRBValueNode.m @@ -1,6 +1,5 @@ #import "Firestore/third_party/Immutable/FSTLLRBValueNode.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/third_party/Immutable/FSTLLRBEmptyNode.h" NS_ASSUME_NONNULL_BEGIN @@ -64,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setLeft:(nullable id<FSTLLRBNode>)left { // Setting the left node should be only done by the builder, so doing it after someone has // memoized count is an error. - FSTAssert(_count == NSNotFound, @"Can't update left node after using count"); + NSAssert(_count == NSNotFound, @"Can't update left node after using count"); _left = left; } diff --git a/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m b/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m index bf17496..a220a3c 100644 --- a/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m +++ b/Firestore/third_party/Immutable/Tests/FSTArraySortedDictionaryTests.m @@ -2,8 +2,6 @@ #import <XCTest/XCTest.h> -#import "Firestore/Source/Util/FSTAssert.h" - @interface FSTArraySortedDictionary (Test) // Override methods to return subtype. - (FSTArraySortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey; @@ -17,7 +15,7 @@ - (NSComparator)defaultComparator { return ^(id obj1, id obj2) { - FSTAssert([obj1 respondsToSelector:@selector(compare:)] && + NSAssert([obj1 respondsToSelector:@selector(compare:)] && [obj2 respondsToSelector:@selector(compare:)], @"Objects must support compare: %@ %@", obj1, obj2); return [obj1 compare:obj2]; diff --git a/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m b/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m index 3e06b30..c6e522c 100644 --- a/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m +++ b/Firestore/third_party/Immutable/Tests/FSTTreeSortedDictionaryTests.m @@ -4,7 +4,6 @@ #import "Firestore/third_party/Immutable/FSTLLRBNode.h" #import "Firestore/third_party/Immutable/FSTLLRBValueNode.h" #import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h" -#import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/third_party/Immutable/Tests/FSTLLRBValueNode+Test.h" @@ -21,7 +20,7 @@ - (NSComparator)defaultComparator { return ^(id obj1, id obj2) { - FSTAssert([obj1 respondsToSelector:@selector(compare:)] && + NSAssert([obj1 respondsToSelector:@selector(compare:)] && [obj2 respondsToSelector:@selector(compare:)], @"Objects must support compare: %@ %@", obj1, obj2); return [obj1 compare:obj2]; diff --git a/scripts/check_copyright.sh b/scripts/check_copyright.sh index 5cd8a18..cc83e29 100755 --- a/scripts/check_copyright.sh +++ b/scripts/check_copyright.sh @@ -22,7 +22,7 @@ options=( ) git grep "${options[@]}" \ - -- '*.'{c,cc,h,js,m,mm,py,sh,swift} \ + -- '*.'{c,cc,h,js,m,mm,py,rb,sh,swift} \ ':(exclude)**/third_party/**' if [[ $? == 0 ]]; then echo "ERROR: Missing copyright notices in the files above. Please fix." diff --git a/scripts/sync_project.rb b/scripts/sync_project.rb new file mode 100755 index 0000000..e34ae31 --- /dev/null +++ b/scripts/sync_project.rb @@ -0,0 +1,569 @@ +#!/usr/bin/ruby + +# 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. + +# Syncs Xcode project folder and target structure with the filesystem. This +# script finds all files on the filesystem that match the patterns supplied +# below and changes the project to match what it found. +# +# Run this script after adding/removing tests to keep the project in sync. + +require 'pathname' + +# Note that xcodeproj 1.5.8 appears to be broken +# https://github.com/CocoaPods/Xcodeproj/issues/572 +gem 'xcodeproj', '!= 1.5.8' +require 'xcodeproj' + + +def main() + # Make all filenames relative to the project root. + Dir.chdir(File.join(File.dirname(__FILE__), '..')) + + sync_firestore() +end + + +def sync_firestore() + project = Xcodeproj::Project.open('Firestore/Example/Firestore.xcodeproj') + + # Enable warnings after opening the project to avoid the warnings in + # xcodeproj itself + $VERBOSE = true + + s = Syncer.new(project, Dir.pwd) + + # Files on the filesystem that should be ignored. + s.ignore_files = [ + 'CMakeLists.txt', + 'InfoPlist.strings', + '*.plist', + + # b/79496027 + 'Firestore/core/test/firebase/firestore/remote/serializer_test.cc', + ] + + # Folder groups in the Xcode project that contain tests. + s.test_groups = [ + 'Tests', + 'CoreTests', + 'SwiftTests', + ] + + s.target 'Firestore_Tests_iOS' do |t| + t.source_files = [ + 'Firestore/Example/Tests/**', + 'Firestore/core/test/**', + 'Firestore/third_party/Immutable/Tests/**', + ] + t.exclude_files = [ + # needs to be in project but not in target + 'Firestore/Example/Tests/Tests-Info.plist', + + # These files are integration tests, handled below + 'Firestore/Example/Tests/Integration/**', + ] + end + + s.target 'Firestore_IntegrationTests_iOS' do |t| + t.source_files = [ + 'Firestore/Example/Tests/Integration/**', + 'Firestore/Example/Tests/Util/FSTEventAccumulator.mm', + 'Firestore/Example/Tests/Util/FSTHelpers.mm', + 'Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm', + 'Firestore/Example/Tests/Util/XCTestCase+Await.mm', + 'Firestore/Example/Tests/en.lproj/InfoPlist.strings', + ] + end + + s.sync() + sort_project(project) + if project.dirty? + project.save() + end +end + + +# The definition of a test target including the target name, its source_files +# and exclude_files. A file is considered part of a target if it matches a +# pattern in source_files but does not match a pattern in exclude_files. +class TargetDef + def initialize(name) + @name = name + @source_files = [] + @exclude_files = [] + end + + attr_accessor :name, :source_files, :exclude_files + + # Returns true if the given relative_path matches this target's source_files + # but not its exclude_files. + # + # Args: + # - relative_path: a Pathname instance with a path relative to the project + # root. + def matches?(relative_path) + return matches_patterns(relative_path, @source_files) && + !matches_patterns(relative_path, @exclude_files) + end + + private + # Evaluates the relative_path against the given list of fnmatch patterns. + def matches_patterns(relative_path, patterns) + patterns.each do |pattern| + if relative_path.fnmatch?(pattern) + return true + end + end + return false + end +end + + +class Syncer + def initialize(project, root_dir) + @project = project + @root_dir = Pathname.new(root_dir) + + @finder = DirectoryLister.new(@root_dir) + + @seen_groups = {} + + @test_groups = [] + @targets = [] + end + + # Considers the given fnmatch glob patterns to be ignored by the syncer. + # Patterns are matched both against the basename and project-relative + # qualified pathname. + def ignore_files=(patterns) + @finder.add_patterns(patterns) + end + + # Names the groups within the project that serve as roots for tests within + # the project. + def test_groups=(groups) + @test_groups = [] + groups.each do |group| + project_group = @project[group] + if project_group.nil? + raise "Project does not contain group #{group}" + end + @test_groups.push(@project[group]) + end + end + + # Starts a new target block. Creates a new TargetDef and yields it. + def target(name, &block) + t = TargetDef.new(name) + @targets.push(t) + + block.call(t) + end + + # Synchronizes the filesystem with the project. + # + # Generally there are three separate ways a file is referenced within a project: + # + # 1. The file must be in the global list of files, assigning it a UUID. + # 2. The file must be added to folder groups, describing where it is in the + # folder view of the Project Navigator. + # 3. The file must be added to a target descrbing how it's built. + # + # The Xcodeproj library handles (1) for us automatically if we do (2). + # + # Synchronization essentially proceeds in two steps: + # + # 1. Sync the filesystem structure with the folder group structure. This has + # the effect of bringing (1) and (2) into sync. + # 2. Sync the global list of files with the targets. + def sync() + group_differ = GroupDiffer.new(@finder) + group_diffs = group_differ.diff(@test_groups) + sync_groups(group_diffs) + + @targets.each do |target_def| + sync_target(target_def) + end + end + + private + def sync_groups(diff_entries) + diff_entries.each do |entry| + if !entry.in_source && entry.in_target + remove_from_project(entry.ref) + end + + if entry.in_source && !entry.in_target + add_to_project(entry.path) + end + end + end + + # Removes the given file reference from the project after the file is found + # missing but references to it still exist in the project. + def remove_from_project(file_ref) + group = file_ref.parents[-1] + + mark_change_in_group(relative_path(group)) + puts " #{basename(file_ref)} - removed" + + # If the file is gone, any build phase that refers to must also remove the + # file. Without this, the project will have build file references that + # contain no actual file. + @project.native_targets.each do |target| + target.build_phases.each do |phase| + if phase.include?(file_ref) + phase.remove_file_reference(file_ref) + end + end + end + + file_ref.remove_from_project + end + + # Adds the given file to the project, in a path starting from the test root + # that fully prefixes the file. + def add_to_project(path) + root_group = find_test_group_containing(path) + + # Find or create the group to contain the path. + dir_rel_path = path.relative_path_from(root_group.real_path).dirname + group = root_group.find_subpath(dir_rel_path.to_s, true) + + mark_change_in_group(relative_path(group)) + + file_ref = group.new_file(path.to_s) + + puts " #{basename(file_ref)} - added" + return file_ref + end + + # Finds a test group whose path prefixes the given entry. Starting from the + # project root may not work since not all test directories exist within the + # example app. + def find_test_group_containing(path) + @test_groups.each do |group| + rel = path.relative_path_from(group.real_path) + next if rel.to_s.start_with?('..') + + return group + end + + raise "Could not find an existing test group that's a parent of #{entry.path}" + end + + def mark_change_in_group(group) + path = group.to_s + if !@seen_groups.has_key?(path) + puts "#{path} ..." + @seen_groups[path] = true + end + end + + SOURCES = %w{.c .cc .m .mm} + + def sync_target(target_def) + target = @project.native_targets.find { |t| t.name == target_def.name } + if !target + raise "Missing target #{target_def.name}" + end + + files = find_files_for_target(target_def) + sources, resources = classify_files(files) + + sync_build_phase(target, target.source_build_phase, sources) + end + + def classify_files(files) + sources = {} + resources = {} + + files.each do |file| + path = file.real_path + ext = path.extname + if SOURCES.include?(ext) + sources[path] = file + end + end + + return sources, resources + end + + def sync_build_phase(target, phase, sources) + # buffer changes to the phase to avoid modifying the array we're iterating + # over. + to_remove = [] + phase.files.each do |build_file| + source_path = build_file.file_ref.real_path + if sources.has_key?(source_path) + # matches spec and existing target no action taken + sources.delete(source_path) + + else + # in the phase but now missing in the groups + to_remove.push(build_file) + end + end + + to_remove.each do |build_file| + mark_change_in_group(target.name) + + source_path = build_file.file_ref.real_path + puts " #{relative_path(source_path)} - removed" + phase.remove_build_file(build_file) + end + + sources.each do |path, file_ref| + mark_change_in_group(target.name) + + phase.add_file_reference(file_ref) + puts " #{relative_path(file_ref)} - added" + end + end + + def find_files_for_target(target_def) + result = [] + + @project.files.each do |file_ref| + next if file_ref.source_tree != '<group>' + + rel = relative_path(file_ref) + if target_def.matches?(rel) + result.push(file_ref) + end + end + return result + end + + def normalize_to_pathname(file_ref) + if !file_ref.is_a? Pathname + if file_ref.is_a? String + file_ref = Pathname.new(file_ref) + else + file_ref = file_ref.real_path + end + end + return file_ref + end + + def basename(file_ref) + return normalize_to_pathname(file_ref).basename + end + + def relative_path(file_ref) + file_ref = normalize_to_pathname(file_ref) + return file_ref.relative_path_from(@root_dir) + end +end + + +def sort_project(project) + project.groups.each do |group| + sort_group(group) + end + + project.targets.each do |target| + target.build_phases.each do |phase| + phase.files.sort! { |a, b| + a.file_ref.real_path.basename <=> b.file_ref.real_path.basename + } + end + end +end + + +def sort_group(group) + group.groups.each do |child| + sort_group(child) + end + + group.children.sort! do |a, b| + # Sort groups first + if a.isa == 'PBXGroup' && b.isa != 'PBXGroup' + -1 + elsif a.isa != 'PBXGroup' && b.isa == 'PBXGroup' + 1 + elsif a.display_name && b.display_name + File.basename(a.display_name) <=> File.basename(b.display_name) + else + 0 + end + end +end + + +# Tracks how a file is referenced: in the project file, on the filesystem, +# neither, or both. +class DiffEntry + def initialize(path) + @path = path + @in_source = false + @in_target = false + @ref = nil + end + + attr_reader :path + attr_accessor :in_source, :in_target, :ref +end + + +# Diffs folder groups against the filesystem directories referenced by those +# folder groups. +# +# This performs the diff starting from the directories referenced by the test +# groups in the project, finding files contained within them. When comparing +# the files it finds against the project this acts on absolute paths to avoid +# problems with arbitary additional groupings in project structure that are +# standard, e.g. "Supporting Files" or "en.lproj" which either act as aliases +# for the parent or are folders that are omitted from the project view. +# Processing the diff this way allows these warts to be tolerated, even if they +# won't necessarily be recreated if an artifact is added to the filesystem. +class GroupDiffer + def initialize(dir_lister) + @dir_lister = dir_lister + + @entries = {} + @dirs = {} + end + + # Finds all tests on the filesystem contained within the paths of the given + # test groups and computes a list of DiffEntries describing the state of the + # files. + # + # Args: + # - groups: A list of PBXGroup objects representing folder groups within the + # project that contain tests. + # + # Returns: + # A list of DiffEntry objects, one for each test found. If the test exists on + # the filesystem, :in_source will be true. If the test exists in the project + # :in_target will be true and :ref will be set to the PBXFileReference naming + # the file. + def diff(groups) groups.each do |group| diff_project_files(group) end + + return @entries.values.sort { |a, b| a.path.basename <=> b.path.basename } + end + + private + # Recursively traverses all the folder groups in the Xcode project and finds + # files both on the filesystem and the group file listing. + def diff_project_files(group) + find_fs_files(group.real_path) + + group.groups.each do |child| + diff_project_files(child) + end + + group.files.each do |file_ref| + path = file_ref.real_path + entry = track_file(path) + entry.in_target = true + entry.ref = file_ref + + if path.file? + entry.in_source = true + end + end + end + + def find_fs_files(parent_path) + # Avoid re-traversing the filesystem + if @dirs.has_key?(parent_path) + return + end + @dirs[parent_path] = true + + @dir_lister.entries(parent_path).each do |path| + if path.directory? + find_fs_files(path) + next + end + + entry = track_file(path) + entry.in_source = true + end + end + + def track_file(path) + if @entries.has_key?(path) + return @entries[path] + end + + entry = DiffEntry.new(path) + @entries[path] = entry + return entry + end +end + + +# Finds files on the filesystem while ignoring files that have been declared to +# be ignored. +class DirectoryLister + def initialize(root_dir) + @root_dir = root_dir + @ignore_basenames = ['.', '..'] + @ignore_pathnames = [] + end + + def add_patterns(patterns) + patterns.each do |pattern| + if File.basename(pattern) != pattern + @ignore_pathnames.push(File.join(@root_dir, pattern)) + else + @ignore_basenames.push(pattern) + end + end + end + + # Finds filesystem entries that are immediate children of the given Pathname, + # ignoring files that match the the global ignore_files patterns. + def entries(path) + result = [] + path.entries.each do |entry| + next if ignore_basename?(entry) + + file = path.join(entry) + next if ignore_pathname?(file) + + result.push(file) + end + return result + end + + private + def ignore_basename?(basename) + @ignore_basenames.each do |ignore| + if basename.fnmatch(ignore) + return true + end + end + return false + end + + def ignore_pathname?(file) + @ignore_pathnames.each do |ignore| + if file.fnmatch(ignore) + return true + end + end + return false + end +end + + +if __FILE__ == $0 + main() +end |