aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore
diff options
context:
space:
mode:
Diffstat (limited to 'Firestore')
-rw-r--r--Firestore/CHANGELOG.md5
-rw-r--r--Firestore/Example/App/iOS/Base.lproj/LaunchScreen.storyboard (renamed from Firestore/Example/Firestore/Base.lproj/LaunchScreen.storyboard)0
-rw-r--r--Firestore/Example/App/iOS/Base.lproj/Main.storyboard (renamed from Firestore/Example/Firestore/Base.lproj/Main.storyboard)0
-rw-r--r--Firestore/Example/App/iOS/FIRAppDelegate.h (renamed from Firestore/Example/Firestore/FIRAppDelegate.h)0
-rw-r--r--Firestore/Example/App/iOS/FIRAppDelegate.m (renamed from Firestore/Example/Firestore/FIRAppDelegate.m)0
-rw-r--r--Firestore/Example/App/iOS/FIRViewController.h (renamed from Firestore/Example/Firestore/FIRViewController.h)0
-rw-r--r--Firestore/Example/App/iOS/FIRViewController.m (renamed from Firestore/Example/Firestore/FIRViewController.m)0
-rw-r--r--Firestore/Example/App/iOS/Firestore-Info.plist (renamed from Firestore/Example/Firestore/Firestore-Info.plist)0
-rw-r--r--Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json (renamed from Firestore/Example/Firestore/Images.xcassets/AppIcon.appiconset/Contents.json)0
-rw-r--r--Firestore/Example/App/iOS/en.lproj/InfoPlist.strings (renamed from Firestore/Example/Firestore/en.lproj/InfoPlist.strings)0
-rw-r--r--Firestore/Example/App/iOS/main.m (renamed from Firestore/Example/Firestore/main.m)0
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj543
-rw-r--r--Firestore/Example/GoogleTest.podspec (renamed from Firestore/Example/Tests/GoogleTest/GoogleTest.podspec)17
-rw-r--r--Firestore/Example/Podfile76
-rw-r--r--Firestore/Example/Tests/Core/FSTQueryListenerTests.mm33
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRValidationTests.mm7
-rw-r--r--Firestore/Example/Tests/Model/field_transform_test.mm (renamed from Firestore/core/test/firebase/firestore/model/field_transform_test.cc)5
-rw-r--r--Firestore/Example/Tests/Model/transform_operations_test.mm (renamed from Firestore/core/test/firebase/firestore/model/transform_operations_test.cc)16
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm6
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTSpecTests.mm4
-rw-r--r--Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm10
-rw-r--r--Firestore/Example/Tests/Util/FSTDispatchQueueTests.mm46
-rw-r--r--Firestore/Example/Tests/Util/FSTHelpers.mm2
-rw-r--r--Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm8
-rw-r--r--Firestore/Source/API/FIRDocumentReference.mm4
-rw-r--r--Firestore/Source/API/FIRDocumentSnapshot.mm2
-rw-r--r--Firestore/Source/API/FIRFieldPath.mm2
-rw-r--r--Firestore/Source/API/FIRFirestore.mm70
-rw-r--r--Firestore/Source/API/FIRQuery+Internal.h4
-rw-r--r--Firestore/Source/API/FIRQuery.mm9
-rw-r--r--Firestore/Source/API/FSTUserDataConverter.mm12
-rw-r--r--Firestore/Source/Core/FSTFirestoreClient.h19
-rw-r--r--Firestore/Source/Core/FSTFirestoreClient.mm66
-rw-r--r--Firestore/Source/Core/FSTQuery.h3
-rw-r--r--Firestore/Source/Core/FSTQuery.mm10
-rw-r--r--Firestore/Source/Core/FSTSnapshotVersion.h43
-rw-r--r--Firestore/Source/Core/FSTSnapshotVersion.mm80
-rw-r--r--Firestore/Source/Core/FSTSyncEngine.mm6
-rw-r--r--Firestore/Source/Local/FSTLevelDB.mm1
-rw-r--r--Firestore/Source/Local/FSTLevelDBKey.mm2
-rw-r--r--Firestore/Source/Local/FSTLocalSerializer.mm1
-rw-r--r--Firestore/Source/Local/FSTLocalStore.mm12
-rw-r--r--Firestore/Source/Local/FSTQueryData.mm2
-rw-r--r--Firestore/Source/Model/FSTDocument.mm10
-rw-r--r--Firestore/Source/Model/FSTMutation.mm4
-rw-r--r--Firestore/Source/Public/FIRDocumentReference.h3
-rw-r--r--Firestore/Source/Public/FIRQuery.h3
-rw-r--r--Firestore/Source/Remote/FSTDatastore.mm12
-rw-r--r--Firestore/Source/Remote/FSTExponentialBackoff.mm9
-rw-r--r--Firestore/Source/Remote/FSTOnlineStateTracker.mm12
-rw-r--r--Firestore/Source/Remote/FSTRemoteEvent.mm5
-rw-r--r--Firestore/Source/Remote/FSTRemoteStore.mm15
-rw-r--r--Firestore/Source/Remote/FSTSerializerBeta.mm4
-rw-r--r--Firestore/Source/Remote/FSTStream.mm36
-rw-r--r--Firestore/Source/Util/FSTAsyncQueryListener.h7
-rw-r--r--Firestore/Source/Util/FSTAsyncQueryListener.mm14
-rw-r--r--Firestore/Source/Util/FSTDispatchQueue.mm277
-rw-r--r--Firestore/Source/Util/FSTLogger.h26
-rw-r--r--Firestore/Source/Util/FSTLogger.mm41
-rw-r--r--Firestore/core/CMakeLists.txt1
-rw-r--r--Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm16
-rw-r--r--Firestore/core/src/firebase/firestore/auth/token.h4
-rw-r--r--Firestore/core/src/firebase/firestore/auth/user.cc4
-rw-r--r--Firestore/core/src/firebase/firestore/geo_point.cc16
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h6
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h6
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/sorted_map.h26
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h4
-rw-r--r--Firestore/core/src/firebase/firestore/immutable/sorted_set.h2
-rw-r--r--Firestore/core/src/firebase/firestore/local/leveldb_key.cc2
-rw-r--r--Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc32
-rw-r--r--Firestore/core/src/firebase/firestore/model/base_path.h16
-rw-r--r--Firestore/core/src/firebase/firestore/model/database_id.cc6
-rw-r--r--Firestore/core/src/firebase/firestore/model/document.cc4
-rw-r--r--Firestore/core/src/firebase/firestore/model/document_key.cc7
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_path.cc27
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.cc28
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.h12
-rw-r--r--Firestore/core/src/firebase/firestore/model/maybe_document.cc2
-rw-r--r--Firestore/core/src/firebase/firestore/model/precondition.cc4
-rw-r--r--Firestore/core/src/firebase/firestore/model/precondition.h9
-rw-r--r--Firestore/core/src/firebase/firestore/model/resource_path.cc8
-rw-r--r--Firestore/core/src/firebase/firestore/model/snapshot_version.h33
-rw-r--r--Firestore/core/src/firebase/firestore/model/transform_operations.h107
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/CMakeLists.txt27
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/reader.cc141
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/reader.h175
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/tag.h43
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/writer.cc163
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/writer.h140
-rw-r--r--Firestore/core/src/firebase/firestore/remote/CMakeLists.txt2
-rw-r--r--Firestore/core/src/firebase/firestore/remote/serializer.cc879
-rw-r--r--Firestore/core/src/firebase/firestore/remote/serializer.h58
-rw-r--r--Firestore/core/src/firebase/firestore/timestamp.cc22
-rw-r--r--Firestore/core/src/firebase/firestore/util/CMakeLists.txt14
-rw-r--r--Firestore/core/src/firebase/firestore/util/async_queue.cc48
-rw-r--r--Firestore/core/src/firebase/firestore/util/bits.cc4
-rw-r--r--Firestore/core/src/firebase/firestore/util/executor_libdispatch.h12
-rw-r--r--Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm86
-rw-r--r--Firestore/core/src/firebase/firestore/util/executor_std.cc3
-rw-r--r--Firestore/core/src/firebase/firestore/util/executor_std.h9
-rw-r--r--Firestore/core/src/firebase/firestore/util/firebase_assert.h119
-rw-r--r--Firestore/core/src/firebase/firestore/util/hard_assert.h88
-rw-r--r--Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm (renamed from Firestore/core/src/firebase/firestore/util/assert_apple.mm)41
-rw-r--r--Firestore/core/src/firebase/firestore/util/hard_assert_stdio.cc (renamed from Firestore/core/src/firebase/firestore/util/assert_stdio.cc)43
-rw-r--r--Firestore/core/src/firebase/firestore/util/log.h71
-rw-r--r--Firestore/core/src/firebase/firestore/util/log_apple.mm77
-rw-r--r--Firestore/core/src/firebase/firestore/util/log_stdio.cc63
-rw-r--r--Firestore/core/src/firebase/firestore/util/ordered_code.cc43
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.cc8
-rw-r--r--Firestore/core/src/firebase/firestore/util/status.h13
-rw-r--r--Firestore/core/src/firebase/firestore/util/statusor.cc8
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_format.cc94
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_format.h156
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_printf.cc102
-rw-r--r--Firestore/core/src/firebase/firestore/util/string_printf.h46
-rw-r--r--Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm (renamed from Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm)191
-rw-r--r--Firestore/core/test/firebase/firestore/model/CMakeLists.txt2
-rw-r--r--Firestore/core/test/firebase/firestore/remote/serializer_test.cc262
-rw-r--r--Firestore/core/test/firebase/firestore/util/CMakeLists.txt6
-rw-r--r--Firestore/core/test/firebase/firestore/util/async_queue_libdispatch_test.mm2
-rw-r--r--Firestore/core/test/firebase/firestore/util/async_queue_test.cc8
-rw-r--r--Firestore/core/test/firebase/firestore/util/comparison_test.cc73
-rw-r--r--Firestore/core/test/firebase/firestore/util/executor_libdispatch_test.mm33
-rw-r--r--Firestore/core/test/firebase/firestore/util/executor_std_test.cc8
-rw-r--r--Firestore/core/test/firebase/firestore/util/executor_test.cc112
-rw-r--r--Firestore/core/test/firebase/firestore/util/hard_assert_test.cc (renamed from Firestore/core/test/firebase/firestore/util/assert_test.cc)27
-rw-r--r--Firestore/core/test/firebase/firestore/util/log_test.cc20
-rw-r--r--Firestore/core/test/firebase/firestore/util/string_format_test.cc110
-rw-r--r--Firestore/core/test/firebase/firestore/util/string_printf_test.cc78
130 files changed, 3133 insertions, 2583 deletions
diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md
index c97aa23..70bab4e 100644
--- a/Firestore/CHANGELOG.md
+++ b/Firestore/CHANGELOG.md
@@ -1,4 +1,9 @@
# Unreleased
+- [fixed] Fixed an issue where `FirestoreSettings` would accept a concurrent
+ dispatch queue, but this configuration would trigger an assertion failure.
+ Passing a concurrent dispatch queue should now work correctly (#988).
+
+# v0.12.0
- [changed] Replaced the `DocumentListenOptions` object with a simple boolean.
Instead of calling
`addSnapshotListener(options: DocumentListenOptions.includeMetadataChanges(true))`
diff --git a/Firestore/Example/Firestore/Base.lproj/LaunchScreen.storyboard b/Firestore/Example/App/iOS/Base.lproj/LaunchScreen.storyboard
index 66a7681..66a7681 100644
--- a/Firestore/Example/Firestore/Base.lproj/LaunchScreen.storyboard
+++ b/Firestore/Example/App/iOS/Base.lproj/LaunchScreen.storyboard
diff --git a/Firestore/Example/Firestore/Base.lproj/Main.storyboard b/Firestore/Example/App/iOS/Base.lproj/Main.storyboard
index d164a23..d164a23 100644
--- a/Firestore/Example/Firestore/Base.lproj/Main.storyboard
+++ b/Firestore/Example/App/iOS/Base.lproj/Main.storyboard
diff --git a/Firestore/Example/Firestore/FIRAppDelegate.h b/Firestore/Example/App/iOS/FIRAppDelegate.h
index 1eb5040..1eb5040 100644
--- a/Firestore/Example/Firestore/FIRAppDelegate.h
+++ b/Firestore/Example/App/iOS/FIRAppDelegate.h
diff --git a/Firestore/Example/Firestore/FIRAppDelegate.m b/Firestore/Example/App/iOS/FIRAppDelegate.m
index 12ca249..12ca249 100644
--- a/Firestore/Example/Firestore/FIRAppDelegate.m
+++ b/Firestore/Example/App/iOS/FIRAppDelegate.m
diff --git a/Firestore/Example/Firestore/FIRViewController.h b/Firestore/Example/App/iOS/FIRViewController.h
index 64b4b74..64b4b74 100644
--- a/Firestore/Example/Firestore/FIRViewController.h
+++ b/Firestore/Example/App/iOS/FIRViewController.h
diff --git a/Firestore/Example/Firestore/FIRViewController.m b/Firestore/Example/App/iOS/FIRViewController.m
index cdad545..cdad545 100644
--- a/Firestore/Example/Firestore/FIRViewController.m
+++ b/Firestore/Example/App/iOS/FIRViewController.m
diff --git a/Firestore/Example/Firestore/Firestore-Info.plist b/Firestore/Example/App/iOS/Firestore-Info.plist
index 7576a0d..7576a0d 100644
--- a/Firestore/Example/Firestore/Firestore-Info.plist
+++ b/Firestore/Example/App/iOS/Firestore-Info.plist
diff --git a/Firestore/Example/Firestore/Images.xcassets/AppIcon.appiconset/Contents.json b/Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json
index d7070bc..d7070bc 100644
--- a/Firestore/Example/Firestore/Images.xcassets/AppIcon.appiconset/Contents.json
+++ b/Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json
diff --git a/Firestore/Example/Firestore/en.lproj/InfoPlist.strings b/Firestore/Example/App/iOS/en.lproj/InfoPlist.strings
index 477b28f..477b28f 100644
--- a/Firestore/Example/Firestore/en.lproj/InfoPlist.strings
+++ b/Firestore/Example/App/iOS/en.lproj/InfoPlist.strings
diff --git a/Firestore/Example/Firestore/main.m b/Firestore/Example/App/iOS/main.m
index 724fccf..724fccf 100644
--- a/Firestore/Example/Firestore/main.m
+++ b/Firestore/Example/App/iOS/main.m
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index ba7a59a..fd6d9ba 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -25,17 +25,15 @@
/* Begin PBXBuildFile section */
132E3E53179DE287D875F3F2 /* FSTLevelDBTransactionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 132E36BB104830BD806351AC /* FSTLevelDBTransactionTests.mm */; };
- 347FDC6AA737A754541F7C8A /* Pods_Firestore_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8525646842C83F703237BAA4 /* Pods_Firestore_Tests_iOS.framework */; };
3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; };
- 3DE7ABABD726C80991971BE1 /* Pods_Firestore_SwiftTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 44B1394B81D5FCA818943A06 /* Pods_Firestore_SwiftTests_iOS.framework */; };
- 5436F32420008FAD006E51E3 /* string_printf_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5436F32320008FAD006E51E3 /* string_printf_test.cc */; };
+ 54131E9720ADE679001DF3FF /* string_format_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54131E9620ADE678001DF3FF /* string_format_test.cc */; };
54511E8E209805F8005BD28F /* hashing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54511E8D209805F8005BD28F /* hashing_test.cc */; };
5467FB01203E5717009C9584 /* FIRFirestoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5467FAFF203E56F8009C9584 /* FIRFirestoreTests.mm */; };
5467FB08203E6A44009C9584 /* app_testing.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5467FB07203E6A44009C9584 /* app_testing.mm */; };
+ 546854AA20A36867004BDBD5 /* datastore_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 546854A820A36867004BDBD5 /* datastore_test.cc */; };
54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A531FC913E500713A1A /* secure_random_test.cc */; };
54740A581FC914F000713A1A /* autoid_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54740A521FC913E500713A1A /* autoid_test.cc */; };
54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */; };
- 548DB927200D590300E00ABC /* assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 548DB926200D590300E00ABC /* assert_test.cc */; };
548DB929200D59F600E00ABC /* comparison_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 548DB928200D59F600E00ABC /* comparison_test.cc */; };
5491BC721FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */; };
5491BC731FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */; };
@@ -110,6 +108,17 @@
5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */; };
5495EB032040E90200EBA509 /* CodableGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */; };
54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */; };
+ 549CCA5020A36DBC00BCEB75 /* sorted_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4C20A36DBB00BCEB75 /* sorted_set_test.cc */; };
+ 549CCA5120A36DBC00BCEB75 /* tree_sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4D20A36DBB00BCEB75 /* tree_sorted_map_test.cc */; };
+ 549CCA5220A36DBC00BCEB75 /* sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4E20A36DBB00BCEB75 /* sorted_map_test.cc */; };
+ 549CCA5720A36E1F00BCEB75 /* field_mask_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5320A36E1F00BCEB75 /* field_mask_test.cc */; };
+ 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5520A36E1F00BCEB75 /* precondition_test.cc */; };
+ 54A0352620A3AED0003E0143 /* field_transform_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352320A3AEC3003E0143 /* field_transform_test.mm */; };
+ 54A0352720A3AED0003E0143 /* transform_operations_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352220A3AEC3003E0143 /* transform_operations_test.mm */; };
+ 54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352820A3B3BD003E0143 /* testutil.cc */; };
+ 54A0352F20A3B3D8003E0143 /* status_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352C20A3B3D7003E0143 /* status_test.cc */; };
+ 54A0353020A3B3D8003E0143 /* statusor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352D20A3B3D7003E0143 /* statusor_test.cc */; };
+ 54A0353520A3D8CB003E0143 /* iterator_adaptors_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */; };
54C2294F1FECABAE007D065B /* log_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54C2294E1FECABAE007D065B /* log_test.cc */; };
54DA12A61F315EE100DD57A1 /* collection_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129C1F315EE100DD57A1 /* collection_spec_test.json */; };
54DA12A71F315EE100DD57A1 /* existence_filter_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */; };
@@ -122,6 +131,7 @@
54DA12AE1F315EE100DD57A1 /* resume_token_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A41F315EE100DD57A1 /* resume_token_spec_test.json */; };
54DA12AF1F315EE100DD57A1 /* write_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA12A51F315EE100DD57A1 /* write_spec_test.json */; };
54EB764D202277B30088B8F3 /* array_sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */; };
+ 5D405BE298CE4692CB00790A /* Pods_Firestore_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B50B3A0DF77100EEE887891 /* Pods_Firestore_Tests_iOS.framework */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
@@ -139,6 +149,7 @@
7346E61D20325C6900FD6CEF /* FSTDispatchQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */; };
73866AA12082B0A5009BB4FF /* FIRArrayTransformTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 73866A9F2082B069009BB4FF /* FIRArrayTransformTests.mm */; };
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 */; };
AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CF82019382300D97691 /* target_id_generator_test.cc */; };
AB380CFE201A2F4500D97691 /* string_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CFC201A2EE200D97691 /* string_util_test.cc */; };
@@ -167,8 +178,9 @@
B6FB468E208F9BAB00554BA2 /* executor_libdispatch_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */; };
B6FB468F208F9BAE00554BA2 /* executor_std_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4687208F9B9100554BA2 /* executor_std_test.cc */; };
B6FB4690208F9BB300554BA2 /* executor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4688208F9B9100554BA2 /* executor_test.cc */; };
- C4E749275AD0FBDF9F4716A8 /* Pods_SwiftBuildTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32AD40BF6B0E849B07FFD05E /* Pods_SwiftBuildTest.framework */; };
- CF08376B68945A0BB332D0C8 /* Pods_Firestore_IntegrationTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B4EEE10E8E59CC91309335CA /* Pods_Firestore_IntegrationTests_iOS.framework */; };
+ BF219E98F1C5A1DAEB5EEC86 /* Pods_Firestore_Example_iOS_SwiftBuildTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 379B34A1536045869826D82A /* Pods_Firestore_Example_iOS_SwiftBuildTest.framework */; };
+ C1AA536F90A0A576CA2816EB /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB92EB03E3F92485023F64ED /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework */; };
+ C8D3CE2343E53223E6487F2C /* Pods_Firestore_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5918805E993304321A05E82B /* Pods_Firestore_Example_iOS.framework */; };
DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
DE03B2D61F2149D600A30B9C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
@@ -179,7 +191,6 @@
DE2EF0861F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF0801F3D0B6E003D0CDC /* FSTImmutableSortedDictionary+Testing.m */; };
DE2EF0871F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF0821F3D0B6E003D0CDC /* FSTImmutableSortedSet+Testing.m */; };
DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE2EF0841F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m */; };
- F06EE8EB234BBE8B7898D5EE /* Pods_Firestore_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24A6BEC38BF31BC4BF0E9DA7 /* Pods_Firestore_Example_iOS.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -235,30 +246,26 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- 04DF37A117F88A9891379ED6 /* Pods-Firestore_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests/Pods-Firestore_Tests.release.xcconfig"; sourceTree = "<group>"; };
- 0E5F50EF80014608B1868944 /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 05C3D82261C3BE976889FF09 /* Pods-Firestore_Example_iOS-SwiftBuildTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-SwiftBuildTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-SwiftBuildTest/Pods-Firestore_Example_iOS-SwiftBuildTest.debug.xcconfig"; sourceTree = "<group>"; };
+ 11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 1277F98C20D2DF0867496976 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
12F4357299652983A615F886 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
132E36BB104830BD806351AC /* FSTLevelDBTransactionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBTransactionTests.mm; sourceTree = "<group>"; };
- 245812330F6A31632BB4B623 /* Pods_Firestore_Example_Firestore_SwiftTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_Firestore_SwiftTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 24A6BEC38BF31BC4BF0E9DA7 /* Pods_Firestore_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 32AD40BF6B0E849B07FFD05E /* Pods_SwiftBuildTest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftBuildTest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 39F1102E452A53A1F93AAA1F /* Pods-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_SwiftTests_iOS/Pods-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 2B50B3A0DF77100EEE887891 /* Pods_Firestore_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 379B34A1536045869826D82A /* Pods_Firestore_Example_iOS_SwiftBuildTest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS_SwiftBuildTest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = "<group>"; };
- 3C7CE22C50805C4A854C73A1 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 3F422FFBDA6E79396E2FB594 /* Pods-Firestore_Example-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example-Firestore_SwiftTests_iOS/Pods-Firestore_Example-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 42491D7DC8C8CD245CC22B93 /* Pods-SwiftBuildTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftBuildTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest.debug.xcconfig"; sourceTree = "<group>"; };
- 44B1394B81D5FCA818943A06 /* Pods_Firestore_SwiftTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_SwiftTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 4EBC5F5ABE1FD097EFE5E224 /* Pods-Firestore_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.release.xcconfig"; sourceTree = "<group>"; };
- 5436F32320008FAD006E51E3 /* string_printf_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_printf_test.cc; path = ../../core/test/firebase/firestore/util/string_printf_test.cc; sourceTree = "<group>"; };
- 54511E8D209805F8005BD28F /* hashing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = hashing_test.cc; path = ../../core/test/firebase/firestore/util/hashing_test.cc; 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>"; };
+ 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>"; };
- 5467FB06203E6A44009C9584 /* app_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = app_testing.h; path = ../../core/test/firebase/firestore/testutil/app_testing.h; sourceTree = "<group>"; };
- 5467FB07203E6A44009C9584 /* app_testing.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = app_testing.mm; path = ../../core/test/firebase/firestore/testutil/app_testing.mm; sourceTree = "<group>"; };
- 54740A521FC913E500713A1A /* autoid_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = autoid_test.cc; path = ../../core/test/firebase/firestore/util/autoid_test.cc; sourceTree = "<group>"; };
- 54740A531FC913E500713A1A /* secure_random_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = secure_random_test.cc; path = ../../core/test/firebase/firestore/util/secure_random_test.cc; sourceTree = "<group>"; };
- 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = FSTGoogleTestTests.mm; path = GoogleTest/FSTGoogleTestTests.mm; sourceTree = "<group>"; };
- 548DB926200D590300E00ABC /* assert_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = assert_test.cc; path = ../../core/test/firebase/firestore/util/assert_test.cc; sourceTree = "<group>"; };
- 548DB928200D59F600E00ABC /* comparison_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = comparison_test.cc; path = ../../core/test/firebase/firestore/util/comparison_test.cc; sourceTree = "<group>"; };
+ 5467FB06203E6A44009C9584 /* app_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = app_testing.h; sourceTree = "<group>"; };
+ 5467FB07203E6A44009C9584 /* app_testing.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = app_testing.mm; sourceTree = "<group>"; };
+ 546854A820A36867004BDBD5 /* datastore_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = datastore_test.cc; sourceTree = "<group>"; };
+ 54740A521FC913E500713A1A /* autoid_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = autoid_test.cc; sourceTree = "<group>"; };
+ 54740A531FC913E500713A1A /* secure_random_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = secure_random_test.cc; sourceTree = "<group>"; };
+ 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTGoogleTestTests.mm; sourceTree = "<group>"; };
+ 548DB928200D59F600E00ABC /* comparison_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = comparison_test.cc; sourceTree = "<group>"; };
5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTIntegrationTestCase.mm; sourceTree = "<group>"; };
5492E02C20213FFB00B64F25 /* FSTLevelDBSpecTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBSpecTests.mm; sourceTree = "<group>"; };
5492E02D20213FFC00B64F25 /* FSTMockDatastore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMockDatastore.mm; sourceTree = "<group>"; };
@@ -335,8 +342,22 @@
5492E0C42021557E00B64F25 /* FSTWatchChange+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FSTWatchChange+Testing.h"; sourceTree = "<group>"; };
5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWatchChangeTests.mm; sourceTree = "<group>"; };
5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodableGeoPointTests.swift; sourceTree = "<group>"; };
- 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = leveldb_key_test.cc; path = ../../core/test/firebase/firestore/local/leveldb_key_test.cc; sourceTree = "<group>"; };
- 54C2294E1FECABAE007D065B /* log_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = log_test.cc; path = ../../core/test/firebase/firestore/util/log_test.cc; sourceTree = "<group>"; };
+ 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_key_test.cc; sourceTree = "<group>"; };
+ 549CCA4C20A36DBB00BCEB75 /* sorted_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sorted_set_test.cc; sourceTree = "<group>"; };
+ 549CCA4D20A36DBB00BCEB75 /* tree_sorted_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tree_sorted_map_test.cc; sourceTree = "<group>"; };
+ 549CCA4E20A36DBB00BCEB75 /* sorted_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sorted_map_test.cc; sourceTree = "<group>"; };
+ 549CCA4F20A36DBC00BCEB75 /* testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testing.h; sourceTree = "<group>"; };
+ 549CCA5320A36E1F00BCEB75 /* field_mask_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = field_mask_test.cc; sourceTree = "<group>"; };
+ 549CCA5520A36E1F00BCEB75 /* precondition_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = precondition_test.cc; sourceTree = "<group>"; };
+ 54A0352220A3AEC3003E0143 /* transform_operations_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = transform_operations_test.mm; sourceTree = "<group>"; };
+ 54A0352320A3AEC3003E0143 /* field_transform_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = field_transform_test.mm; sourceTree = "<group>"; };
+ 54A0352820A3B3BD003E0143 /* testutil.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testutil.cc; sourceTree = "<group>"; };
+ 54A0352920A3B3BD003E0143 /* testutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testutil.h; sourceTree = "<group>"; };
+ 54A0352B20A3B3D7003E0143 /* status_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status_test_util.h; sourceTree = "<group>"; };
+ 54A0352C20A3B3D7003E0143 /* status_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status_test.cc; sourceTree = "<group>"; };
+ 54A0352D20A3B3D7003E0143 /* statusor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statusor_test.cc; sourceTree = "<group>"; };
+ 54A0353420A3D8CB003E0143 /* iterator_adaptors_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iterator_adaptors_test.cc; sourceTree = "<group>"; };
+ 54C2294E1FECABAE007D065B /* log_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_test.cc; sourceTree = "<group>"; };
54C9EDF12040E16300A969CD /* Firestore_SwiftTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_SwiftTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
54C9EDF52040E16300A969CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
54DA129C1F315EE100DD57A1 /* collection_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = collection_spec_test.json; sourceTree = "<group>"; };
@@ -352,9 +373,8 @@
54E9281C1F33950B00C1953E /* FSTEventAccumulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTEventAccumulator.h; sourceTree = "<group>"; };
54E9281E1F33950B00C1953E /* FSTIntegrationTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTIntegrationTestCase.h; sourceTree = "<group>"; };
54E9282A1F339CAD00C1953E /* XCTestCase+Await.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "XCTestCase+Await.h"; sourceTree = "<group>"; };
- 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = array_sorted_map_test.cc; path = ../../immutable/array_sorted_map_test.cc; sourceTree = "<group>"; };
- 555ACD6970390DC825A8F141 /* 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>"; };
- 5A3E3BE5F322D66EE3D6CB65 /* Pods-Firestore_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
+ 54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = array_sorted_map_test.cc; sourceTree = "<group>"; };
+ 5918805E993304321A05E82B /* Pods_Firestore_Example_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58A195388D20070C39A /* Firestore_Example_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Firestore_Example_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -372,25 +392,18 @@
6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRFirestoreSourceTests.mm; sourceTree = "<group>"; };
- 618AC3C38A174084B9420162 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 635C1D9B5E36BC4C12A35E70 /* Pods-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_SwiftTests_iOS/Pods-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 69E6C311558EC77729A16CF1 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
7346E61C20325C6900FD6CEF /* FSTDispatchQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDispatchQueueTests.mm; sourceTree = "<group>"; };
73866A9F2082B069009BB4FF /* FIRArrayTransformTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRArrayTransformTests.mm; sourceTree = "<group>"; };
- 75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 80025E2E892B94823962D11D /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 8525646842C83F703237BAA4 /* Pods_Firestore_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 74ACEC3603BE58B57A7E8D4C /* Pods-Firestore_Example_iOS-SwiftBuildTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-SwiftBuildTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-SwiftBuildTest/Pods-Firestore_Example_iOS-SwiftBuildTest.release.xcconfig"; sourceTree = "<group>"; };
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
8E002F4AD5D9B6197C940847 /* Firestore.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Firestore.podspec; path = ../Firestore.podspec; sourceTree = "<group>"; };
- 9837221D251B8D40E7D7B454 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- 9D52E67EE96AA7E5D6F69748 /* Pods-Firestore_IntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests/Pods-Firestore_IntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
- 9EF477AD4B2B643FD320867A /* Pods-Firestore_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.debug.xcconfig"; sourceTree = "<group>"; };
AB356EF6200EA5EB0089B766 /* field_value_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = field_value_test.cc; sourceTree = "<group>"; };
AB380CF82019382300D97691 /* target_id_generator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = target_id_generator_test.cc; sourceTree = "<group>"; };
- AB380CFC201A2EE200D97691 /* string_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_util_test.cc; path = ../../core/test/firebase/firestore/util/string_util_test.cc; sourceTree = "<group>"; };
- AB380D01201BC69F00D97691 /* bits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bits_test.cc; path = ../../core/test/firebase/firestore/util/bits_test.cc; sourceTree = "<group>"; };
- AB380D03201BC6E400D97691 /* ordered_code_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ordered_code_test.cc; path = ../../core/test/firebase/firestore/util/ordered_code_test.cc; sourceTree = "<group>"; };
+ AB380CFC201A2EE200D97691 /* string_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_util_test.cc; sourceTree = "<group>"; };
+ AB380D01201BC69F00D97691 /* bits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bits_test.cc; sourceTree = "<group>"; };
+ AB380D03201BC6E400D97691 /* ordered_code_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ordered_code_test.cc; sourceTree = "<group>"; };
AB38D92E20235D22000A432D /* database_info_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = database_info_test.cc; sourceTree = "<group>"; };
AB38D93220239654000A432D /* user_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = user_test.cc; sourceTree = "<group>"; };
AB38D9342023966E000A432D /* credentials_provider_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = credentials_provider_test.cc; sourceTree = "<group>"; };
@@ -399,32 +412,27 @@
AB6B908520322E6D00CC290A /* maybe_document_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = maybe_document_test.cc; sourceTree = "<group>"; };
AB6B908720322E8800CC290A /* no_document_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = no_document_test.cc; sourceTree = "<group>"; };
AB71064B201FA60300344F18 /* database_id_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = database_id_test.cc; sourceTree = "<group>"; };
- AB7BAB332012B519001E0872 /* geo_point_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = geo_point_test.cc; path = ../../core/test/firebase/firestore/geo_point_test.cc; sourceTree = "<group>"; };
+ AB7BAB332012B519001E0872 /* geo_point_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = geo_point_test.cc; sourceTree = "<group>"; };
ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = snapshot_version_test.cc; sourceTree = "<group>"; };
ABC1D7DF2023A3EF00BA84F0 /* token_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = token_test.cc; sourceTree = "<group>"; };
ABC1D7E22023CDC500BA84F0 /* firebase_credentials_provider_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = firebase_credentials_provider_test.mm; sourceTree = "<group>"; };
- ABF6506B201131F8005F2C74 /* timestamp_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = timestamp_test.cc; path = ../../core/test/firebase/firestore/timestamp_test.cc; sourceTree = "<group>"; };
- B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- B4EEE10E8E59CC91309335CA /* Pods_Firestore_IntegrationTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ ABF6506B201131F8005F2C74 /* timestamp_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = timestamp_test.cc; sourceTree = "<group>"; };
+ B3F5B3AAE791A5911B9EAA82 /* Pods-Firestore_Tests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS.release.xcconfig"; sourceTree = "<group>"; };
B6152AD5202A5385000E5744 /* document_key_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = document_key_test.cc; sourceTree = "<group>"; };
B65D34A7203C99090076A5E1 /* FIRTimestampTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRTimestampTest.m; sourceTree = "<group>"; };
B686F2AD2023DDB20028D6BE /* field_path_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = field_path_test.cc; sourceTree = "<group>"; };
B686F2B02024FFD70028D6BE /* resource_path_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resource_path_test.cc; sourceTree = "<group>"; };
- B6FB467A208E9A8200554BA2 /* async_queue_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = async_queue_test.h; path = ../../core/test/firebase/firestore/util/async_queue_test.h; sourceTree = "<group>"; };
- B6FB467B208E9A8200554BA2 /* async_queue_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = async_queue_test.cc; path = ../../core/test/firebase/firestore/util/async_queue_test.cc; sourceTree = "<group>"; };
- B6FB4680208EA0BE00554BA2 /* async_queue_libdispatch_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = async_queue_libdispatch_test.mm; path = ../../core/test/firebase/firestore/util/async_queue_libdispatch_test.mm; sourceTree = "<group>"; };
- B6FB4681208EA0BE00554BA2 /* async_queue_std_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = async_queue_std_test.cc; path = ../../core/test/firebase/firestore/util/async_queue_std_test.cc; sourceTree = "<group>"; };
- B6FB4686208F9B9100554BA2 /* async_tests_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = async_tests_util.h; path = ../../core/test/firebase/firestore/util/async_tests_util.h; sourceTree = "<group>"; };
- B6FB4687208F9B9100554BA2 /* executor_std_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = executor_std_test.cc; path = ../../core/test/firebase/firestore/util/executor_std_test.cc; sourceTree = "<group>"; };
- B6FB4688208F9B9100554BA2 /* executor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = executor_test.cc; path = ../../core/test/firebase/firestore/util/executor_test.cc; sourceTree = "<group>"; };
- B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = executor_libdispatch_test.mm; path = ../../core/test/firebase/firestore/util/executor_libdispatch_test.mm; sourceTree = "<group>"; };
- B6FB468A208F9B9100554BA2 /* executor_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = executor_test.h; path = ../../core/test/firebase/firestore/util/executor_test.h; sourceTree = "<group>"; };
- BE88081EE627C46349C918EF /* Pods-Firestore_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
- C1D89E5405935366C88CC3E5 /* Pods-Firestore_Example-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example-Firestore_SwiftTests_iOS/Pods-Firestore_Example-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
- CE00BABB5A3AAB44A4C209E2 /* Pods-Firestore_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests/Pods-Firestore_Tests.debug.xcconfig"; sourceTree = "<group>"; };
+ B6FB467A208E9A8200554BA2 /* async_queue_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = async_queue_test.h; sourceTree = "<group>"; };
+ B6FB467B208E9A8200554BA2 /* async_queue_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = async_queue_test.cc; sourceTree = "<group>"; };
+ B6FB4680208EA0BE00554BA2 /* async_queue_libdispatch_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = async_queue_libdispatch_test.mm; sourceTree = "<group>"; };
+ B6FB4681208EA0BE00554BA2 /* async_queue_std_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = async_queue_std_test.cc; sourceTree = "<group>"; };
+ B6FB4686208F9B9100554BA2 /* async_tests_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = async_tests_util.h; sourceTree = "<group>"; };
+ B6FB4687208F9B9100554BA2 /* executor_std_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = executor_std_test.cc; sourceTree = "<group>"; };
+ B6FB4688208F9B9100554BA2 /* executor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = executor_test.cc; sourceTree = "<group>"; };
+ B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = executor_libdispatch_test.mm; sourceTree = "<group>"; };
+ B6FB468A208F9B9100554BA2 /* executor_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = executor_test.h; sourceTree = "<group>"; };
+ BB92EB03E3F92485023F64ED /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
- D8CA124A5F9A704EA0E12785 /* 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>"; };
- DB17FEDFB80770611A935A60 /* Pods-Firestore_IntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests/Pods-Firestore_IntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
DE03B2E91F2149D600A30B9C /* Firestore_IntegrationTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_IntegrationTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DE03B3621F215E1600A30B9C /* CAcert.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = CAcert.pem; sourceTree = "<group>"; };
DE0761E41F2FE611003233AF /* SwiftBuildTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftBuildTest.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -441,7 +449,9 @@
DE51B1981F0D48AC0013853F /* FSTSpecTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTSpecTests.h; sourceTree = "<group>"; };
DE51B19A1F0D48AC0013853F /* FSTSyncEngineTestDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSTSyncEngineTestDriver.h; sourceTree = "<group>"; };
DE51B1A71F0D48AC0013853F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
- F23325524BEAF8D24F78AC88 /* Pods-SwiftBuildTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftBuildTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest.release.xcconfig"; sourceTree = "<group>"; };
+ E592181BFD7C53C305123739 /* Pods-Firestore_Tests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
+ ECEBABC7E7B693BE808A1052 /* Pods_Firestore_IntegrationTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ F354C0FE92645B56A6C6FD44 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -449,7 +459,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 3DE7ABABD726C80991971BE1 /* Pods_Firestore_SwiftTests_iOS.framework in Frameworks */,
+ C1AA536F90A0A576CA2816EB /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -460,7 +470,7 @@
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
- F06EE8EB234BBE8B7898D5EE /* Pods_Firestore_Example_iOS.framework in Frameworks */,
+ C8D3CE2343E53223E6487F2C /* Pods_Firestore_Example_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -471,7 +481,7 @@
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */,
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */,
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */,
- 347FDC6AA737A754541F7C8A /* Pods_Firestore_Tests_iOS.framework in Frameworks */,
+ 5D405BE298CE4692CB00790A /* Pods_Firestore_Tests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -482,7 +492,7 @@
DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */,
DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */,
DE03B2D61F2149D600A30B9C /* Foundation.framework in Frameworks */,
- CF08376B68945A0BB332D0C8 /* Pods_Firestore_IntegrationTests_iOS.framework in Frameworks */,
+ 8C82D4D3F9AB63E79CC52DC8 /* Pods_Firestore_IntegrationTests_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -490,49 +500,71 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- C4E749275AD0FBDF9F4716A8 /* Pods_SwiftBuildTest.framework in Frameworks */,
+ BF219E98F1C5A1DAEB5EEC86 /* Pods_Firestore_Example_iOS_SwiftBuildTest.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 543B4F0520A91E4B001F506D /* App */ = {
+ isa = PBXGroup;
+ children = (
+ 6003F593195388D20070C39A /* iOS */,
+ );
+ path = App;
+ sourceTree = "<group>";
+ };
5467FB05203E652F009C9584 /* testutil */ = {
isa = PBXGroup;
children = (
5467FB06203E6A44009C9584 /* app_testing.h */,
5467FB07203E6A44009C9584 /* app_testing.mm */,
+ 54A0352820A3B3BD003E0143 /* testutil.cc */,
+ 54A0352920A3B3BD003E0143 /* testutil.h */,
+ );
+ path = testutil;
+ sourceTree = "<group>";
+ };
+ 546854A720A3681B004BDBD5 /* remote */ = {
+ isa = PBXGroup;
+ children = (
+ 546854A820A36867004BDBD5 /* datastore_test.cc */,
);
- name = testutil;
+ path = remote;
sourceTree = "<group>";
};
54740A561FC913EB00713A1A /* util */ = {
isa = PBXGroup;
children = (
- B6FB4686208F9B9100554BA2 /* async_tests_util.h */,
- B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */,
- B6FB4687208F9B9100554BA2 /* executor_std_test.cc */,
- B6FB4688208F9B9100554BA2 /* executor_test.cc */,
- B6FB468A208F9B9100554BA2 /* executor_test.h */,
B6FB4680208EA0BE00554BA2 /* async_queue_libdispatch_test.mm */,
B6FB4681208EA0BE00554BA2 /* async_queue_std_test.cc */,
B6FB467B208E9A8200554BA2 /* async_queue_test.cc */,
B6FB467A208E9A8200554BA2 /* async_queue_test.h */,
- 548DB926200D590300E00ABC /* assert_test.cc */,
+ B6FB4686208F9B9100554BA2 /* async_tests_util.h */,
54740A521FC913E500713A1A /* autoid_test.cc */,
AB380D01201BC69F00D97691 /* bits_test.cc */,
548DB928200D59F600E00ABC /* comparison_test.cc */,
+ B6FB4689208F9B9100554BA2 /* executor_libdispatch_test.mm */,
+ B6FB4687208F9B9100554BA2 /* executor_std_test.cc */,
+ B6FB4688208F9B9100554BA2 /* executor_test.cc */,
+ B6FB468A208F9B9100554BA2 /* executor_test.h */,
+ 54131E9820AE076C001DF3FF /* 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 */,
- 5436F32320008FAD006E51E3 /* string_printf_test.cc */,
+ 54A0352B20A3B3D7003E0143 /* status_test_util.h */,
+ 54A0352C20A3B3D7003E0143 /* status_test.cc */,
+ 54A0352D20A3B3D7003E0143 /* statusor_test.cc */,
+ 54131E9620ADE678001DF3FF /* string_format_test.cc */,
AB380CFC201A2EE200D97691 /* string_util_test.cc */,
);
- name = util;
+ path = util;
sourceTree = "<group>";
};
- 54764FAC1FAA0C390085E60A /* GoogleTests */ = {
+ 54764FAC1FAA0C390085E60A /* CoreTests */ = {
isa = PBXGroup;
children = (
AB38D9312023962A000A432D /* auth */,
@@ -540,13 +572,15 @@
54EB764B202277970088B8F3 /* immutable */,
54995F70205B6E1A004EFFA0 /* local */,
AB356EF5200E9D1A0089B766 /* model */,
+ 546854A720A3681B004BDBD5 /* remote */,
5467FB05203E652F009C9584 /* testutil */,
54740A561FC913EB00713A1A /* util */,
54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */,
AB7BAB332012B519001E0872 /* geo_point_test.cc */,
ABF6506B201131F8005F2C74 /* timestamp_test.cc */,
);
- name = GoogleTests;
+ name = CoreTests;
+ path = ../core/test/firebase/firestore;
sourceTree = "<group>";
};
5495EB012040E90200EBA509 /* Codable */ = {
@@ -562,7 +596,7 @@
children = (
54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */,
);
- name = local;
+ path = local;
sourceTree = "<group>";
};
54C9EDF22040E16300A969CD /* SwiftTests */ = {
@@ -579,22 +613,26 @@
isa = PBXGroup;
children = (
54EB764C202277B30088B8F3 /* array_sorted_map_test.cc */,
+ 549CCA4E20A36DBB00BCEB75 /* sorted_map_test.cc */,
+ 549CCA4C20A36DBB00BCEB75 /* sorted_set_test.cc */,
+ 549CCA4F20A36DBC00BCEB75 /* testing.h */,
+ 549CCA4D20A36DBB00BCEB75 /* tree_sorted_map_test.cc */,
);
- name = immutable;
- path = ../../core/test/firebase/firestore/core/immutable;
+ path = immutable;
sourceTree = "<group>";
};
6003F581195388D10070C39A = {
isa = PBXGroup;
children = (
+ 543B4F0520A91E4B001F506D /* App */,
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */,
- 6003F593195388D20070C39A /* Example for Firestore */,
6003F5B5195388D20070C39A /* Tests */,
+ 54764FAC1FAA0C390085E60A /* CoreTests */,
54C9EDF22040E16300A969CD /* SwiftTests */,
DE0761E51F2FE611003233AF /* SwiftBuildTest */,
6003F58C195388D20070C39A /* Frameworks */,
6003F58B195388D20070C39A /* Products */,
- A47A1BF74A48BCAEAFBCBF1E /* Pods */,
+ AAEA2A72CFD1FA5AD34462F7 /* Pods */,
);
sourceTree = "<group>";
};
@@ -617,21 +655,16 @@
6003F58F195388D20070C39A /* CoreGraphics.framework */,
6003F591195388D20070C39A /* UIKit.framework */,
6003F5AF195388D20070C39A /* XCTest.framework */,
- 75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */,
- 69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */,
- B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */,
- 32AD40BF6B0E849B07FFD05E /* Pods_SwiftBuildTest.framework */,
- 245812330F6A31632BB4B623 /* Pods_Firestore_Example_Firestore_SwiftTests_iOS.framework */,
- 24A6BEC38BF31BC4BF0E9DA7 /* Pods_Firestore_Example_iOS.framework */,
- 0E5F50EF80014608B1868944 /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework */,
- 8525646842C83F703237BAA4 /* Pods_Firestore_Tests_iOS.framework */,
- B4EEE10E8E59CC91309335CA /* Pods_Firestore_IntegrationTests_iOS.framework */,
- 44B1394B81D5FCA818943A06 /* Pods_Firestore_SwiftTests_iOS.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 */,
);
name = Frameworks;
sourceTree = "<group>";
};
- 6003F593195388D20070C39A /* Example for Firestore */ = {
+ 6003F593195388D20070C39A /* iOS */ = {
isa = PBXGroup;
children = (
6003F59C195388D20070C39A /* FIRAppDelegate.h */,
@@ -643,8 +676,7 @@
6003F5A8195388D20070C39A /* Images.xcassets */,
6003F594195388D20070C39A /* Supporting Files */,
);
- name = "Example for Firestore";
- path = Firestore;
+ path = iOS;
sourceTree = "<group>";
};
6003F594195388D20070C39A /* Supporting Files */ = {
@@ -662,7 +694,6 @@
children = (
DE51B1831F0D48AC0013853F /* API */,
DE51B1A81F0D48AC0013853F /* Core */,
- 54764FAC1FAA0C390085E60A /* GoogleTests */,
DE2EF06E1F3D07D7003D0CDC /* Immutable */,
DE51B1BB1F0D48AC0013853F /* Integration */,
DE51B1621F0D48AC0013853F /* Local */,
@@ -694,29 +725,19 @@
name = "Podspec Metadata";
sourceTree = "<group>";
};
- A47A1BF74A48BCAEAFBCBF1E /* Pods */ = {
+ AAEA2A72CFD1FA5AD34462F7 /* Pods */ = {
isa = PBXGroup;
children = (
- 9EF477AD4B2B643FD320867A /* Pods-Firestore_Example.debug.xcconfig */,
- 4EBC5F5ABE1FD097EFE5E224 /* Pods-Firestore_Example.release.xcconfig */,
- 9D52E67EE96AA7E5D6F69748 /* Pods-Firestore_IntegrationTests.debug.xcconfig */,
- DB17FEDFB80770611A935A60 /* Pods-Firestore_IntegrationTests.release.xcconfig */,
- CE00BABB5A3AAB44A4C209E2 /* Pods-Firestore_Tests.debug.xcconfig */,
- 04DF37A117F88A9891379ED6 /* Pods-Firestore_Tests.release.xcconfig */,
- 42491D7DC8C8CD245CC22B93 /* Pods-SwiftBuildTest.debug.xcconfig */,
- F23325524BEAF8D24F78AC88 /* Pods-SwiftBuildTest.release.xcconfig */,
- 3F422FFBDA6E79396E2FB594 /* Pods-Firestore_Example-Firestore_SwiftTests_iOS.debug.xcconfig */,
- C1D89E5405935366C88CC3E5 /* Pods-Firestore_Example-Firestore_SwiftTests_iOS.release.xcconfig */,
- 555ACD6970390DC825A8F141 /* Pods-Firestore_Example_iOS.debug.xcconfig */,
- D8CA124A5F9A704EA0E12785 /* Pods-Firestore_Example_iOS.release.xcconfig */,
- 9837221D251B8D40E7D7B454 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */,
- 80025E2E892B94823962D11D /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */,
- BE88081EE627C46349C918EF /* Pods-Firestore_Tests_iOS.debug.xcconfig */,
- 5A3E3BE5F322D66EE3D6CB65 /* Pods-Firestore_Tests_iOS.release.xcconfig */,
- 3C7CE22C50805C4A854C73A1 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */,
- 618AC3C38A174084B9420162 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */,
- 635C1D9B5E36BC4C12A35E70 /* Pods-Firestore_SwiftTests_iOS.debug.xcconfig */,
- 39F1102E452A53A1F93AAA1F /* Pods-Firestore_SwiftTests_iOS.release.xcconfig */,
+ 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 */,
+ 1277F98C20D2DF0867496976 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */,
+ F354C0FE92645B56A6C6FD44 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */,
+ E592181BFD7C53C305123739 /* Pods-Firestore_Tests_iOS.debug.xcconfig */,
+ B3F5B3AAE791A5911B9EAA82 /* Pods-Firestore_Tests_iOS.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@@ -724,28 +745,28 @@
AB356EF5200E9D1A0089B766 /* model */ = {
isa = PBXGroup;
children = (
+ AB71064B201FA60300344F18 /* database_id_test.cc */,
B6152AD5202A5385000E5744 /* document_key_test.cc */,
AB6B908320322E4D00CC290A /* document_test.cc */,
- B686F2B02024FFD70028D6BE /* resource_path_test.cc */,
+ 549CCA5320A36E1F00BCEB75 /* field_mask_test.cc */,
B686F2AD2023DDB20028D6BE /* field_path_test.cc */,
- AB71064B201FA60300344F18 /* database_id_test.cc */,
AB356EF6200EA5EB0089B766 /* field_value_test.cc */,
AB6B908520322E6D00CC290A /* maybe_document_test.cc */,
AB6B908720322E8800CC290A /* no_document_test.cc */,
+ 549CCA5520A36E1F00BCEB75 /* precondition_test.cc */,
+ B686F2B02024FFD70028D6BE /* resource_path_test.cc */,
ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */,
);
- name = model;
- path = ../../core/test/firebase/firestore/model;
+ path = model;
sourceTree = "<group>";
};
AB380CF7201937B800D97691 /* core */ = {
isa = PBXGroup;
children = (
- AB380CF82019382300D97691 /* target_id_generator_test.cc */,
AB38D92E20235D22000A432D /* database_info_test.cc */,
+ AB380CF82019382300D97691 /* target_id_generator_test.cc */,
);
- name = core;
- path = ../../core/test/firebase/firestore/core;
+ path = core;
sourceTree = "<group>";
};
AB38D9312023962A000A432D /* auth */ = {
@@ -757,8 +778,7 @@
ABC1D7DF2023A3EF00BA84F0 /* token_test.cc */,
AB38D93220239654000A432D /* user_test.cc */,
);
- name = auth;
- path = ../../core/test/firebase/firestore/auth;
+ path = auth;
sourceTree = "<group>";
};
DE0761E51F2FE611003233AF /* SwiftBuildTest */ = {
@@ -818,11 +838,13 @@
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 */,
+ 54A0352220A3AEC3003E0143 /* transform_operations_test.mm */,
);
path = Model;
sourceTree = "<group>";
@@ -963,11 +985,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 54C9EDFA2040E16300A969CD /* Build configuration list for PBXNativeTarget "Firestore_SwiftTests_iOS" */;
buildPhases = (
- 6FB7F3A6D6ADAC64E4972A29 /* [CP] Check Pods Manifest.lock */,
+ D2D94DFA64939EF6DECDF908 /* [CP] Check Pods Manifest.lock */,
54C9EDED2040E16300A969CD /* Sources */,
54C9EDEE2040E16300A969CD /* Frameworks */,
54C9EDEF2040E16300A969CD /* Resources */,
- 9E2D564AC55ADE2D52B7E951 /* [CP] Embed Pods Frameworks */,
+ EA424838F4A5DD7B337F57AB /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -983,10 +1005,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "Firestore_Example_iOS" */;
buildPhases = (
- FAB3416C6DD87D45081EC3E8 /* [CP] Check Pods Manifest.lock */,
+ 83F2AB95D08093BB076EE521 /* [CP] Check Pods Manifest.lock */,
6003F586195388D20070C39A /* Sources */,
6003F587195388D20070C39A /* Frameworks */,
6003F588195388D20070C39A /* Resources */,
+ 1EE692C7509A98D7EB03CA51 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -1001,11 +1024,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Firestore_Tests_iOS" */;
buildPhases = (
- 8D94B6319191CD7344A4D1B9 /* [CP] Check Pods Manifest.lock */,
+ 8B469EB6DA9E6404589402E2 /* [CP] Check Pods Manifest.lock */,
6003F5AA195388D20070C39A /* Sources */,
6003F5AB195388D20070C39A /* Frameworks */,
6003F5AC195388D20070C39A /* Resources */,
- BB3FE78ABF533BFC38839A0E /* [CP] Embed Pods Frameworks */,
+ 329C25E418360CEF62F6CB2B /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -1021,11 +1044,11 @@
isa = PBXNativeTarget;
buildConfigurationList = DE03B2E61F2149D600A30B9C /* Build configuration list for PBXNativeTarget "Firestore_IntegrationTests_iOS" */;
buildPhases = (
- DE03B2971F2149D600A30B9C /* [CP] Check Pods Manifest.lock */,
+ A827A009A65B69DC1B80EAD4 /* [CP] Check Pods Manifest.lock */,
DE03B2981F2149D600A30B9C /* Sources */,
DE03B2D31F2149D600A30B9C /* Frameworks */,
DE03B2D81F2149D600A30B9C /* Resources */,
- A677B831B09F9BD04DC6DF32 /* [CP] Embed Pods Frameworks */,
+ B7923D95031DB0DA112AAE9B /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -1041,11 +1064,11 @@
isa = PBXNativeTarget;
buildConfigurationList = DE0761F51F2FE611003233AF /* Build configuration list for PBXNativeTarget "SwiftBuildTest" */;
buildPhases = (
- 8F34C5E63ACEBD784CF82A45 /* [CP] Check Pods Manifest.lock */,
+ 5504F81EEBBEF943CA61D32C /* [CP] Check Pods Manifest.lock */,
DE0761E01F2FE611003233AF /* Sources */,
DE0761E11F2FE611003233AF /* Frameworks */,
DE0761E21F2FE611003233AF /* Resources */,
- 125BDFEB177CFD41D7A40928 /* [CP] Embed Pods Frameworks */,
+ 04404E0DCBB886A40E3C7175 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -1170,13 +1193,13 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 125BDFEB177CFD41D7A40928 /* [CP] Embed Pods Frameworks */ = {
+ 04404E0DCBB886A40E3C7175 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest-frameworks.sh",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Example_iOS-SwiftBuildTest/Pods-Firestore_Example_iOS-SwiftBuildTest-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
"${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
@@ -1203,28 +1226,68 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Example_iOS-SwiftBuildTest/Pods-Firestore_Example_iOS-SwiftBuildTest-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 6FB7F3A6D6ADAC64E4972A29 /* [CP] Check Pods Manifest.lock */ = {
+ 1EE692C7509A98D7EB03CA51 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC-ProtoRPC/ProtoRPC.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC-RxLibrary/RxLibrary.framework",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProtoRPC.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxLibrary.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 329C25E418360CEF62F6CB2B /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleTest/GoogleTest.framework",
+ "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Firestore_SwiftTests_iOS-checkManifestLockResult.txt",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleTest.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 8D94B6319191CD7344A4D1B9 /* [CP] Check Pods Manifest.lock */ = {
+ 5504F81EEBBEF943CA61D32C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -1235,14 +1298,14 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Firestore_Tests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Firestore_Example_iOS-SwiftBuildTest-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 8F34C5E63ACEBD784CF82A45 /* [CP] Check Pods Manifest.lock */ = {
+ 83F2AB95D08093BB076EE521 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -1253,126 +1316,68 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-SwiftBuildTest-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Firestore_Example_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 9E2D564AC55ADE2D52B7E951 /* [CP] Embed Pods Frameworks */ = {
+ 8B469EB6DA9E6404589402E2 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_SwiftTests_iOS/Pods-Firestore_SwiftTests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-ProtoRPC/ProtoRPC.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-RxLibrary/RxLibrary.framework",
- "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProtoRPC.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxLibrary.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "$(DERIVED_FILE_DIR)/Pods-Firestore_Tests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_SwiftTests_iOS/Pods-Firestore_SwiftTests_iOS-frameworks.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- A677B831B09F9BD04DC6DF32 /* [CP] Embed Pods Frameworks */ = {
+ A827A009A65B69DC1B80EAD4 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-ProtoRPC/ProtoRPC.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-RxLibrary/RxLibrary.framework",
- "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
- name = "[CP] Embed Pods Frameworks";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProtoRPC.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxLibrary.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "$(DERIVED_FILE_DIR)/Pods-Firestore_IntegrationTests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS-frameworks.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- BB3FE78ABF533BFC38839A0E /* [CP] Embed Pods Frameworks */ = {
+ B7923D95031DB0DA112AAE9B /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS-frameworks.sh",
- "${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
- "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
- "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
- "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-ProtoRPC/ProtoRPC.framework",
- "${BUILT_PRODUCTS_DIR}/gRPC-RxLibrary/RxLibrary.framework",
- "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
- "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
- "${BUILT_PRODUCTS_DIR}/GoogleTest/GoogleTest.framework",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProtoRPC.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxLibrary.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleTest.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Tests_iOS/Pods-Firestore_Tests_iOS-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- DE03B2971F2149D600A30B9C /* [CP] Check Pods Manifest.lock */ = {
+ D2D94DFA64939EF6DECDF908 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -1383,29 +1388,47 @@
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Firestore_IntegrationTests_iOS-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- FAB3416C6DD87D45081EC3E8 /* [CP] Check Pods Manifest.lock */ = {
+ EA424838F4A5DD7B337F57AB /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
+ "${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
+ "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
+ "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC-ProtoRPC/ProtoRPC.framework",
+ "${BUILT_PRODUCTS_DIR}/gRPC-RxLibrary/RxLibrary.framework",
+ "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
);
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Firestore_Example_iOS-checkManifestLockResult.txt",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProtoRPC.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxLibrary.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -1437,6 +1460,7 @@
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 */,
@@ -1448,36 +1472,41 @@
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 */,
5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */,
54740A581FC914F000713A1A /* autoid_test.cc in Sources */,
- 548DB927200D590300E00ABC /* assert_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 */,
- 5436F32420008FAD006E51E3 /* string_printf_test.cc 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 */,
@@ -1485,6 +1514,7 @@
5492E054202154AB00B64F25 /* FIRFieldValueTests.mm in Sources */,
AB6B908620322E6D00CC290A /* maybe_document_test.cc in Sources */,
5492E09F2021552D00B64F25 /* FSTLevelDBMigrationsTests.mm in Sources */,
+ 546854AA20A36867004BDBD5 /* datastore_test.cc in Sources */,
5492E053202154AB00B64F25 /* FIRDocumentReferenceTests.mm in Sources */,
5492E09D2021552D00B64F25 /* FSTLocalStoreTests.mm in Sources */,
5492E0A32021552D00B64F25 /* FSTLocalSerializerTests.mm in Sources */,
@@ -1500,12 +1530,14 @@
54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */,
5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */,
B6FB467D208E9D3C00554BA2 /* async_queue_test.cc in Sources */,
+ 54A0352F20A3B3D8003E0143 /* status_test.cc 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 */,
@@ -1520,9 +1552,11 @@
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 */,
AB380D02201BC69F00D97691 /* bits_test.cc in Sources */,
548DB929200D59F600E00ABC /* comparison_test.cc in Sources */,
+ 549CCA5720A36E1F00BCEB75 /* field_mask_test.cc in Sources */,
5492E03D2021401F00B64F25 /* FSTAssertTests.mm in Sources */,
AB38D93020236E21000A432D /* database_info_test.cc in Sources */,
5492E052202154AB00B64F25 /* FIRGeoPointTests.mm in Sources */,
@@ -1531,6 +1565,7 @@
5492E03520213FFC00B64F25 /* FSTSpecTests.mm in Sources */,
5492E057202154AB00B64F25 /* FIRSnapshotMetadataTests.mm in Sources */,
54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */,
+ 549CCA5020A36DBC00BCEB75 /* sorted_set_test.cc in Sources */,
5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */,
132E3E53179DE287D875F3F2 /* FSTLevelDBTransactionTests.mm in Sources */,
);
@@ -1640,7 +1675,7 @@
/* Begin XCBuildConfiguration section */
54C9EDF82040E16300A969CD /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 635C1D9B5E36BC4C12A35E70 /* Pods-Firestore_SwiftTests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 69E6C311558EC77729A16CF1 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -1679,7 +1714,7 @@
};
54C9EDF92040E16300A969CD /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 39F1102E452A53A1F93AAA1F /* Pods-Firestore_SwiftTests_iOS.release.xcconfig */;
+ baseConfigurationReference = 11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -1793,7 +1828,7 @@
};
6003F5C0195388D20070C39A /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 555ACD6970390DC825A8F141 /* Pods-Firestore_Example_iOS.debug.xcconfig */;
+ baseConfigurationReference = 3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -1803,8 +1838,12 @@
"\"${PODS_ROOT}/Firebase/Firebase/Firebase\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
);
- INFOPLIST_FILE = "Firestore/Firestore-Info.plist";
+ INFOPLIST_FILE = "App/iOS/Firestore-Info.plist";
MODULE_NAME = ExampleApp;
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-all_load",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
@@ -1813,7 +1852,7 @@
};
6003F5C1195388D20070C39A /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = D8CA124A5F9A704EA0E12785 /* Pods-Firestore_Example_iOS.release.xcconfig */;
+ baseConfigurationReference = 3F0992A4B83C60841C52E960 /* Pods-Firestore_Example_iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -1823,8 +1862,12 @@
"\"${PODS_ROOT}/Firebase/Firebase/Firebase\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
);
- INFOPLIST_FILE = "Firestore/Firestore-Info.plist";
+ INFOPLIST_FILE = "App/iOS/Firestore-Info.plist";
MODULE_NAME = ExampleApp;
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-all_load",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
@@ -1833,7 +1876,7 @@
};
6003F5C3195388D20070C39A /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = BE88081EE627C46349C918EF /* Pods-Firestore_Tests_iOS.debug.xcconfig */;
+ baseConfigurationReference = E592181BFD7C53C305123739 /* Pods-Firestore_Tests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1853,8 +1896,9 @@
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
"\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
- "\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/GoogleTest/googlemock/include\"",
"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
+ "\"${PODS_ROOT}/leveldb-library/include\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
@@ -1866,7 +1910,7 @@
};
6003F5C4195388D20070C39A /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 5A3E3BE5F322D66EE3D6CB65 /* Pods-Firestore_Tests_iOS.release.xcconfig */;
+ baseConfigurationReference = B3F5B3AAE791A5911B9EAA82 /* Pods-Firestore_Tests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1886,8 +1930,9 @@
"$(inherited)",
"\"${PODS_ROOT}/../../..\"",
"\"${PODS_ROOT}/../../../Firestore/third_party/abseil-cpp\"",
- "\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/GoogleTest/googlemock/include\"",
"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
+ "\"${PODS_ROOT}/leveldb-library/include\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
@@ -1899,7 +1944,7 @@
};
DE03B2E71F2149D600A30B9C /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 3C7CE22C50805C4A854C73A1 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */;
+ baseConfigurationReference = 1277F98C20D2DF0867496976 /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1936,7 +1981,7 @@
};
DE03B2E81F2149D600A30B9C /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 618AC3C38A174084B9420162 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */;
+ baseConfigurationReference = F354C0FE92645B56A6C6FD44 /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1973,7 +2018,7 @@
};
DE0761F31F2FE611003233AF /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 42491D7DC8C8CD245CC22B93 /* Pods-SwiftBuildTest.debug.xcconfig */;
+ baseConfigurationReference = 05C3D82261C3BE976889FF09 /* Pods-Firestore_Example_iOS-SwiftBuildTest.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -1986,7 +2031,7 @@
DEVELOPMENT_TEAM = EQHXZ8M8AV;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
- INFOPLIST_FILE = "Firestore/Firestore-Info.plist";
+ INFOPLIST_FILE = "App/iOS/Firestore-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
@@ -2000,7 +2045,7 @@
};
DE0761F41F2FE611003233AF /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = F23325524BEAF8D24F78AC88 /* Pods-SwiftBuildTest.release.xcconfig */;
+ baseConfigurationReference = 74ACEC3603BE58B57A7E8D4C /* Pods-Firestore_Example_iOS-SwiftBuildTest.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
@@ -2014,7 +2059,7 @@
DEVELOPMENT_TEAM = EQHXZ8M8AV;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
- INFOPLIST_FILE = "Firestore/Firestore-Info.plist";
+ INFOPLIST_FILE = "App/iOS/Firestore-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
diff --git a/Firestore/Example/Tests/GoogleTest/GoogleTest.podspec b/Firestore/Example/GoogleTest.podspec
index 064fc59..0ecba3d 100644
--- a/Firestore/Example/Tests/GoogleTest/GoogleTest.podspec
+++ b/Firestore/Example/GoogleTest.podspec
@@ -41,6 +41,8 @@ Google's C++ test framework.
# (e.g. gtest.h). We don't need them because they're effectively empty:
# they're compile-time hooks for third-party customization that we don't use.
s.public_header_files = [
+ 'googlemock/include/gmock/*.h',
+ 'googlemock/include/gmock/internal/*.h',
'googletest/include/gtest/*.h',
'googletest/include/gtest/internal/*.h'
]
@@ -54,6 +56,9 @@ Google's C++ test framework.
]
s.source_files = [
+ 'googlemock/src/*.cc',
+ 'googlemock/include/gmock/*.h',
+ 'googlemock/include/gmock/internal/*.h',
'googletest/src/*.cc',
'googletest/include/gtest/*.h',
'googletest/include/gtest/internal/*.h'
@@ -61,8 +66,11 @@ Google's C++ test framework.
s.exclude_files = [
# A convenience wrapper for a simple command-line build. If included in
- # this build, results in duplicate symbols
+ # this build, results in duplicate symbols.
+ 'googlemock/src/gmock-all.cc',
'googletest/src/gtest-all.cc',
+ # Both gmock and gtest define a main function but we only need one.
+ 'googletest/src/gtest_main.cc',
]
s.library = 'c++'
@@ -70,12 +78,17 @@ Google's C++ test framework.
# When building this pod there are headers in googletest/src.
s.pod_target_xcconfig = {
'HEADER_SEARCH_PATHS' =>
- '"${PODS_ROOT}/GoogleTest/googletest/include" "${PODS_ROOT}/GoogleTest/googletest"'
+ '"${PODS_ROOT}/GoogleTest/googlemock/include" ' +
+ '"${PODS_ROOT}/GoogleTest/googletest/include" ' +
+ '"${PODS_ROOT}/GoogleTest/googletest"'
}
s.prepare_command = <<-'CMD'
# Remove includes of files in internal/custom
sed -i.bak -e '/include.*internal\/custom/ d' \
+ googlemock/include/gmock/gmock-matchers.h \
+ googlemock/include/gmock/gmock-generated-actions.h \
+ googlemock/include/gmock/internal/gmock-port.h \
googletest/include/gtest/gtest-printers.h \
googletest/include/gtest/internal/gtest-port.h \
googletest/src/gtest-death-test.cc \
diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile
index c1e02c8..26af4cd 100644
--- a/Firestore/Example/Podfile
+++ b/Firestore/Example/Podfile
@@ -2,71 +2,39 @@
#source 'sso://cpdc-internal/spec'
#source 'https://github.com/CocoaPods/Specs.git'
-# The next line is the forcing function for the Firebase pod. The Firebase
-# version's subspecs should depend on the component versions in their
-# corresponding podspec's.
-
-pod 'Firebase/Core', '5.0.0'
-
use_frameworks!
-pod 'FirebaseAuth', :path => '../../'
-pod 'FirebaseCore', :path => '../../'
-pod 'FirebaseFirestore', :path => '../../'
-
target 'Firestore_Example_iOS' do
platform :ios, '8.0'
- # Test targets are below to avoid problems with duplicate symbols when
- # building as a static library (see comments below).
-end
+ # The next line is the forcing function for the Firebase pod. The Firebase
+ # version's subspecs should depend on the component versions in their
+ # corresponding podspec's.
+ pod 'Firebase/Core', '5.0.1'
-target 'Firestore_Tests_iOS' do
- platform :ios, '8.0'
+ pod 'FirebaseAuth', :path => '../../'
+ pod 'FirebaseCore', :path => '../../'
+ pod 'FirebaseFirestore', :path => '../../'
- pod 'leveldb-library'
- pod 'OCMock'
- pod 'GoogleTest', :podspec => 'Tests/GoogleTest/GoogleTest.podspec'
-end
+ target 'Firestore_Tests_iOS' do
+ inherit! :search_paths
-target 'Firestore_IntegrationTests_iOS' do
- platform :ios, '8.0'
-end
+ pod 'leveldb-library'
+ pod 'OCMock'
+ pod 'GoogleTest', :podspec => 'GoogleTest.podspec'
+ end
-target 'Firestore_SwiftTests_iOS' do
- platform :ios, '8.0'
- pod 'FirebaseFirestoreSwift', :path => '../../'
-end
+ target 'Firestore_IntegrationTests_iOS' do
+ inherit! :search_paths
-target 'SwiftBuildTest' do
- platform :ios, '8.0'
-end
+ pod 'OCMock'
+ end
-# Firestore includes both Objective-C and C++ code, and the Firestore tests
-# consist of both XCTest-based tests in Objective-C and GoogleTest-based tests
-# in C++. The C++ tests must resolve the classes under test at link time, so
-# CocoaPods usual strategy linking Frameworks to the app and then resolving
-# those classes through run-time loading does not work in all cases.
-#
-# If use_frameworks! is disabled above, the project will encounter a ton of
-# duplicate Objective-C class warnings during test runs. Some of the tests will
-# fail too because duplicate classes also get duplicate static data and this
-# violates the expectations of code we depend upon.
-#
-# The workaround is to strip duplicate dependencies out of the example app,
-# which does not need them since it doesn't do anything other than act as a
-# host to the tests. This is based on the workaround posted here:
-#
-# https://github.com/CocoaPods/CocoaPods/issues/7155
-#
-# TODO(wilhuff): Reevaluate if this is needed once we require CocoaPods 1.5.1
-# which may address this.
-pre_install do |installer|
- test_target = installer.aggregate_targets.find do |target|
- target.name == 'Pods-Firestore_Tests_iOS'
+ target 'Firestore_SwiftTests_iOS' do
+ pod 'FirebaseFirestoreSwift', :path => '../../'
end
- app_target = installer.aggregate_targets.find do |target|
- target.name == 'Pods-Firestore_Example_iOS'
+
+ target 'SwiftBuildTest' do
+ platform :ios, '8.0'
end
- app_target.pod_targets = app_target.pod_targets - test_target.pod_targets
end
diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm
index 7ae9704..5629075 100644
--- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm
+++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm
@@ -15,6 +15,7 @@
*/
#import <XCTest/XCTest.h>
+#include <memory>
#import "Firestore/Source/Core/FSTEventManager.h"
#import "Firestore/Source/Core/FSTQuery.h"
@@ -23,23 +24,29 @@
#import "Firestore/Source/Model/FSTDocumentSet.h"
#import "Firestore/Source/Remote/FSTRemoteEvent.h"
#import "Firestore/Source/Util/FSTAsyncQueryListener.h"
-#import "Firestore/Source/Util/FSTDispatchQueue.h"
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
+#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h"
+#include "absl/memory/memory.h"
+
+using firebase::firestore::util::internal::ExecutorLibdispatch;
using firebase::firestore::model::DocumentKeySet;
NS_ASSUME_NONNULL_BEGIN
@interface FSTQueryListenerTests : XCTestCase
-@property(nonatomic, strong, readonly) FSTDispatchQueue *asyncQueue;
@end
-@implementation FSTQueryListenerTests
+@implementation FSTQueryListenerTests {
+ std::unique_ptr<ExecutorLibdispatch> _executor;
+}
- (void)setUp {
- _asyncQueue = [FSTDispatchQueue
- queueWith:dispatch_queue_create("FSTQueryListenerTests Queue", DISPATCH_QUEUE_SERIAL)];
+ // TODO(varconst): moving this test to C++, it should be possible to store Executor as a value,
+ // not a pointer, and initialize it in the constructor.
+ _executor = absl::make_unique<ExecutorLibdispatch>(
+ dispatch_queue_create("FSTQueryListenerTests Queue", DISPATCH_QUEUE_SERIAL));
}
- (void)testRaisesCollectionEvents {
@@ -131,12 +138,12 @@ NS_ASSUME_NONNULL_BEGIN
FSTDocument *doc1 = FSTTestDoc("rooms/Eros", 3, @{@"name" : @"Eros"}, NO);
FSTDocument *doc2 = FSTTestDoc("rooms/Eros", 4, @{@"name" : @"Eros2"}, NO);
- __block FSTAsyncQueryListener *listener = [[FSTAsyncQueryListener alloc]
- initWithDispatchQueue:self.asyncQueue
- snapshotHandler:^(FSTViewSnapshot *snapshot, NSError *error) {
- [accum addObject:snapshot];
- [listener mute];
- }];
+ __block FSTAsyncQueryListener *listener =
+ [[FSTAsyncQueryListener alloc] initWithExecutor:_executor.get()
+ snapshotHandler:^(FSTViewSnapshot *snapshot, NSError *error) {
+ [accum addObject:snapshot];
+ [listener mute];
+ }];
FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}];
FSTViewSnapshot *viewSnapshot1 = FSTTestApplyChanges(view, @[ doc1 ], nil);
@@ -148,9 +155,7 @@ NS_ASSUME_NONNULL_BEGIN
// Drain queue
XCTestExpectation *expectation = [self expectationWithDescription:@"Queue drained"];
- [self.asyncQueue dispatchAsync:^{
- [expectation fulfill];
- }];
+ _executor->Execute([=] { [expectation fulfill]; });
[self waitForExpectationsWithTimeout:4.0
handler:^(NSError *_Nullable expectationError) {
diff --git a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
index 8af8d15..599f1b2 100644
--- a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
+++ b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
@@ -557,6 +557,13 @@
@"array_contains different than orderBy works.");
}
+- (void)testQueryMustNotHaveMultipleArrayContainsFilters {
+ FIRCollectionReference *coll = [self.db collectionWithPath:@"collection"];
+ FSTAssertThrows(
+ [[coll queryWhereField:@"foo" arrayContains:@1] queryWhereField:@"foo" arrayContains:@2],
+ @"Invalid Query. Queries only support a single arrayContains filter.");
+}
+
#pragma mark - GeoPoint Validation
- (void)testInvalidGeoPointParameters {
diff --git a/Firestore/core/test/firebase/firestore/model/field_transform_test.cc b/Firestore/Example/Tests/Model/field_transform_test.mm
index b66aeef..a22a0f3 100644
--- a/Firestore/core/test/firebase/firestore/model/field_transform_test.cc
+++ b/Firestore/Example/Tests/Model/field_transform_test.mm
@@ -26,9 +26,8 @@ namespace firestore {
namespace model {
TEST(FieldTransform, Getter) {
- FieldTransform transform(testutil::Field("foo"),
- absl::make_unique<ServerTimestampTransform>(
- ServerTimestampTransform::Get()));
+ FieldTransform transform{testutil::Field("foo"), absl::make_unique<ServerTimestampTransform>(
+ ServerTimestampTransform::Get())};
EXPECT_EQ(testutil::Field("foo"), transform.path());
EXPECT_EQ(ServerTimestampTransform::Get(), transform.transformation());
diff --git a/Firestore/core/test/firebase/firestore/model/transform_operations_test.cc b/Firestore/Example/Tests/Model/transform_operations_test.mm
index ec0882a..247ea13 100644
--- a/Firestore/core/test/firebase/firestore/model/transform_operations_test.cc
+++ b/Firestore/Example/Tests/Model/transform_operations_test.mm
@@ -31,9 +31,25 @@ class DummyOperation : public TransformOperation {
return Type::Test;
}
+ FSTFieldValue* ApplyToLocalView(FSTFieldValue* /* previousValue */,
+ FIRTimestamp* /* localWriteTime */) const override {
+ return nil;
+ }
+
+ FSTFieldValue* ApplyToRemoteDocument(FSTFieldValue* /* previousValue */,
+ FSTFieldValue* /* transformResult */) const override {
+ return nil;
+ }
+
bool operator==(const TransformOperation& other) const override {
return this == &other;
}
+
+ NSUInteger Hash() const override {
+ // arbitrary number, the same as used in ObjC implementation, since all
+ // instances are equal.
+ return 37;
+ }
};
TEST(TransformOperations, ServerTimestamp) {
diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm
index dd34556..c846ec5 100644
--- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm
+++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm
@@ -21,7 +21,6 @@
#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;
@@ -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)];
}
diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm
index 5a7cb72..7b10bd4 100644
--- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm
+++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm
@@ -37,7 +37,6 @@
#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 +45,7 @@
#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/log.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
#include "Firestore/core/test/firebase/firestore/testutil/testutil.h"
@@ -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..40ebfb9 100644
--- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm
+++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm
@@ -31,7 +31,6 @@
#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 +40,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/document_key.h"
+#include "Firestore/core/src/firebase/firestore/util/log.h"
using firebase::firestore::auth::EmptyCredentialsProvider;
using firebase::firestore::auth::HashUser;
@@ -202,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN
FSTAssert([actualWrite isEqual:expectedWrite],
@"Mock datastore received write %@ but first outstanding mutation was %@", actualWrite,
expectedWrite);
- FSTLog(@"A write was sent: %@", actualWrite);
+ 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;
}];
diff --git a/Firestore/Example/Tests/Util/FSTDispatchQueueTests.mm b/Firestore/Example/Tests/Util/FSTDispatchQueueTests.mm
index 811fa34..1f49aa4 100644
--- a/Firestore/Example/Tests/Util/FSTDispatchQueueTests.mm
+++ b/Firestore/Example/Tests/Util/FSTDispatchQueueTests.mm
@@ -66,9 +66,10 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
XCTAssertNotNil(caught);
XCTAssertEqualObjects(caught.name, NSInternalInconsistencyException);
- XCTAssertTrue(
- [caught.reason hasPrefix:@"FIRESTORE INTERNAL ASSERTION FAILED: "
- @"dispatchAsync called when we are already running on target"]);
+ XCTAssertTrue([caught.reason
+ hasPrefix:
+ @"FIRESTORE INTERNAL ASSERTION FAILED: "
+ @"Enqueue methods cannot be called when we are already running on target executor"]);
}
- (void)testDispatchAsyncAllowingSameQueueActuallyAllowsSameQueue {
@@ -133,9 +134,10 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
XCTAssertNotNil(caught);
XCTAssertEqualObjects(caught.name, NSInternalInconsistencyException);
- XCTAssertTrue(
- [caught.reason hasPrefix:@"FIRESTORE INTERNAL ASSERTION FAILED: "
- @"dispatchSync called when we are already running on target"]);
+ XCTAssertTrue([caught.reason
+ hasPrefix:
+ @"FIRESTORE INTERNAL ASSERTION FAILED: "
+ @"Enqueue methods cannot be called when we are already running on target executor"]);
}
- (void)testVerifyIsCurrentQueueActuallyRequiresCurrentQueue {
@@ -150,7 +152,8 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
}
XCTAssertNotNil(caught);
XCTAssertTrue([caught.reason hasPrefix:@"FIRESTORE INTERNAL ASSERTION FAILED: "
- @"We are running on the wrong dispatch queue"]);
+ @"Expected to be called by the executor "
+ @"associated with this queue"]);
}
- (void)testVerifyIsCurrentQueueRequiresOperationIsInProgress {
@@ -165,7 +168,7 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
XCTAssertNotNil(caught);
XCTAssertTrue(
[caught.reason hasPrefix:@"FIRESTORE INTERNAL ASSERTION FAILED: "
- @"verifyIsCurrentQueue called outside enterCheckedOperation"]);
+ @"VerifyIsCurrentQueue called when no operation is executing"]);
}
- (void)testVerifyIsCurrentQueueWorksWithOperationIsInProgress {
@@ -194,9 +197,10 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
}];
XCTAssertNil(problem);
XCTAssertNotNil(caught);
- XCTAssertTrue([caught.reason
- hasPrefix:@"FIRESTORE INTERNAL ASSERTION FAILED: "
- @"enterCheckedOperation may not be called when an operation is in progress"]);
+ XCTAssertTrue(
+ [caught.reason hasPrefix:@"FIRESTORE INTERNAL ASSERTION FAILED: "
+ @"ExecuteBlocking may not be called before the previous operation "
+ @"finishes executing"]);
}
/**
@@ -217,8 +221,10 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
_expectation = [self expectationWithDescription:@"Expected steps"];
_expectedSteps = @[ @1, @2, @3, @4 ];
[_queue dispatchAsync:[self blockForStep:1]];
- [_queue dispatchAfterDelay:0.005 timerID:timerID1 block:[self blockForStep:4]];
- [_queue dispatchAfterDelay:0.001 timerID:timerID2 block:[self blockForStep:3]];
+ [_queue dispatchAsync:^{
+ [_queue dispatchAfterDelay:0.005 timerID:timerID1 block:[self blockForStep:4]];
+ [_queue dispatchAfterDelay:0.001 timerID:timerID2 block:[self blockForStep:3]];
+ }];
[_queue dispatchAsync:[self blockForStep:2]];
[self awaitExpectations];
@@ -244,8 +250,10 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
- (void)testCanManuallyDrainAllDelayedCallbacksForTesting {
[_queue dispatchAsync:[self blockForStep:1]];
- [_queue dispatchAfterDelay:20 timerID:timerID1 block:[self blockForStep:4]];
- [_queue dispatchAfterDelay:10 timerID:timerID2 block:[self blockForStep:3]];
+ [_queue dispatchAsync:^{
+ [_queue dispatchAfterDelay:20 timerID:timerID1 block:[self blockForStep:4]];
+ [_queue dispatchAfterDelay:10 timerID:timerID2 block:[self blockForStep:3]];
+ }];
[_queue dispatchAsync:[self blockForStep:2]];
[_queue runDelayedCallbacksUntil:FSTTimerIDAll];
@@ -254,9 +262,11 @@ static const FSTTimerID timerID3 = FSTTimerIDWriteStreamConnectionBackoff;
- (void)testCanManuallyDrainSpecificDelayedCallbacksForTesting {
[_queue dispatchAsync:[self blockForStep:1]];
- [_queue dispatchAfterDelay:20 timerID:timerID1 block:[self blockForStep:5]];
- [_queue dispatchAfterDelay:10 timerID:timerID2 block:[self blockForStep:3]];
- [_queue dispatchAfterDelay:15 timerID:timerID3 block:[self blockForStep:4]];
+ [_queue dispatchAsync:^{
+ [_queue dispatchAfterDelay:20 timerID:timerID1 block:[self blockForStep:5]];
+ [_queue dispatchAfterDelay:10 timerID:timerID2 block:[self blockForStep:3]];
+ [_queue dispatchAfterDelay:15 timerID:timerID3 block:[self blockForStep:4]];
+ }];
[_queue dispatchAsync:[self blockForStep:2]];
[_queue runDelayedCallbacksUntil:timerID3];
diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm
index dbd19aa..bc2f005 100644
--- a/Firestore/Example/Tests/Util/FSTHelpers.mm
+++ b/Firestore/Example/Tests/Util/FSTHelpers.mm
@@ -250,7 +250,7 @@ FSTPatchMutation *FSTTestPatchMutation(const absl::string_view path,
BOOL merge = !updateMask.empty();
__block FSTObjectValue *objectValue = [FSTObjectValue objectValue];
- __block std::vector<FieldPath> fieldMaskPaths{};
+ __block std::vector<FieldPath> fieldMaskPaths;
[values enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
const FieldPath path = testutil::Field(util::MakeStringView(key));
fieldMaskPaths.push_back(path);
diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
index 1817015..434b77b 100644
--- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
+++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
@@ -17,7 +17,13 @@
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
#import <FirebaseCore/FIRLogger.h>
-#import <FirebaseFirestore/FirebaseFirestore-umbrella.h>
+#import <FirebaseFirestore/FIRCollectionReference.h>
+#import <FirebaseFirestore/FIRDocumentChange.h>
+#import <FirebaseFirestore/FIRDocumentReference.h>
+#import <FirebaseFirestore/FIRDocumentSnapshot.h>
+#import <FirebaseFirestore/FIRFirestoreSettings.h>
+#import <FirebaseFirestore/FIRQuerySnapshot.h>
+#import <FirebaseFirestore/FIRSnapshotMetadata.h>
#import <GRPCClient/GRPCCall+ChannelArg.h>
#import <GRPCClient/GRPCCall+Tests.h>
diff --git a/Firestore/Source/API/FIRDocumentReference.mm b/Firestore/Source/API/FIRDocumentReference.mm
index da67a5b..5ad606c 100644
--- a/Firestore/Source/API/FIRDocumentReference.mm
+++ b/Firestore/Source/API/FIRDocumentReference.mm
@@ -280,8 +280,8 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
};
FSTAsyncQueryListener *asyncListener =
- [[FSTAsyncQueryListener alloc] initWithDispatchQueue:self.firestore.client.userDispatchQueue
- snapshotHandler:snapshotHandler];
+ [[FSTAsyncQueryListener alloc] initWithExecutor:self.firestore.client.userExecutor
+ snapshotHandler:snapshotHandler];
FSTQueryListener *internalListener =
[firestore.client listenToQuery:query
diff --git a/Firestore/Source/API/FIRDocumentSnapshot.mm b/Firestore/Source/API/FIRDocumentSnapshot.mm
index 614982b..388b3b3 100644
--- a/Firestore/Source/API/FIRDocumentSnapshot.mm
+++ b/Firestore/Source/API/FIRDocumentSnapshot.mm
@@ -50,7 +50,7 @@ static FSTServerTimestampBehavior InternalServerTimestampBehavor(
case FIRServerTimestampBehaviorPrevious:
return FSTServerTimestampBehaviorPrevious;
default:
- FIREBASE_ASSERT_MESSAGE(false, "Unexpected server timestamp option: %ld", (long)behavior);
+ HARD_FAIL("Unexpected server timestamp option: %s", behavior);
}
}
diff --git a/Firestore/Source/API/FIRFieldPath.mm b/Firestore/Source/API/FIRFieldPath.mm
index 4fd0022..68f3de1 100644
--- a/Firestore/Source/API/FIRFieldPath.mm
+++ b/Firestore/Source/API/FIRFieldPath.mm
@@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN
FSTThrowInvalidArgument(@"Invalid field path. Provided names must not be empty.");
}
- std::vector<std::string> field_names{};
+ std::vector<std::string> field_names;
field_names.reserve(fieldNames.count);
for (int i = 0; i < fieldNames.count; ++i) {
if (fieldNames[i].length == 0) {
diff --git a/Firestore/Source/API/FIRFirestore.mm b/Firestore/Source/API/FIRFirestore.mm
index fe461d6..0ed9082 100644
--- a/Firestore/Source/API/FIRFirestore.mm
+++ b/Firestore/Source/API/FIRFirestore.mm
@@ -34,7 +34,6 @@
#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,15 +41,20 @@
#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/log.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
#include "absl/memory/memory.h"
+#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h"
+
namespace util = firebase::firestore::util;
using firebase::firestore::auth::CredentialsProvider;
using firebase::firestore::auth::FirebaseCredentialsProvider;
using firebase::firestore::core::DatabaseInfo;
using firebase::firestore::model::DatabaseId;
using firebase::firestore::model::ResourcePath;
+using util::internal::Executor;
+using util::internal::ExecutorLibdispatch;
NS_ASSUME_NONNULL_BEGIN
@@ -242,42 +246,43 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
FSTAssert(_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),
util::MakeStringView(_settings.host), _settings.sslEnabled);
- FSTDispatchQueue *userDispatchQueue = [FSTDispatchQueue queueWith:_settings.dispatchQueue];
+ std::unique_ptr<Executor> userExecutor =
+ absl::make_unique<ExecutorLibdispatch>(_settings.dispatchQueue);
_client = [FSTFirestoreClient clientWithDatabaseInfo:database_info
usePersistence:_settings.persistenceEnabled
credentialsProvider:_credentialsProvider.get()
- userDispatchQueue:userDispatchQueue
+ userExecutor:std::move(userExecutor)
workerDispatchQueue:_workerDispatchQueue];
}
}
@@ -287,6 +292,11 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
if (!collectionPath) {
FSTThrowInvalidArgument(@"Collection path cannot be nil.");
}
+ if ([collectionPath containsString:@"//"]) {
+ FSTThrowInvalidArgument(@"Invalid path (%@). Paths must not contain // in them.",
+ collectionPath);
+ }
+
[self ensureClientConfigured];
const ResourcePath path = ResourcePath::FromString(util::MakeStringView(collectionPath));
return [FIRCollectionReference referenceWithPath:path firestore:self];
@@ -296,6 +306,10 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain";
if (!documentPath) {
FSTThrowInvalidArgument(@"Document path cannot be nil.");
}
+ if ([documentPath containsString:@"//"]) {
+ FSTThrowInvalidArgument(@"Invalid path (%@). Paths must not contain // in them.", documentPath);
+ }
+
[self ensureClientConfigured];
const ResourcePath path = ResourcePath::FromString(util::MakeStringView(documentPath));
return [FIRDocumentReference referenceWithPath:path firestore:self];
diff --git a/Firestore/Source/API/FIRQuery+Internal.h b/Firestore/Source/API/FIRQuery+Internal.h
index c4f9f23..e207837 100644
--- a/Firestore/Source/API/FIRQuery+Internal.h
+++ b/Firestore/Source/API/FIRQuery+Internal.h
@@ -35,6 +35,8 @@ NS_ASSUME_NONNULL_BEGIN
* Creates and returns a new `FIRQuery` with the additional filter that documents must contain
* the specified field, it must be an array, and the array must contain the provided value.
*
+ * A query can have only one arrayContains filter.
+ *
* @param field The name of the field containing an array to search
* @param value The value that must be contained in the array
*
@@ -49,6 +51,8 @@ NS_ASSUME_NONNULL_BEGIN
* Creates and returns a new `FIRQuery` with the additional filter that documents must contain
* the specified field, it must be an array, and the array must contain the provided value.
*
+ * A query can have only one arrayContains filter.
+ *
* @param path The path of the field containing an array to search
* @param value The value that must be contained in the array
*
diff --git a/Firestore/Source/API/FIRQuery.mm b/Firestore/Source/API/FIRQuery.mm
index c83af9c..ad4d2aa 100644
--- a/Firestore/Source/API/FIRQuery.mm
+++ b/Firestore/Source/API/FIRQuery.mm
@@ -183,8 +183,8 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
};
FSTAsyncQueryListener *asyncListener =
- [[FSTAsyncQueryListener alloc] initWithDispatchQueue:self.firestore.client.userDispatchQueue
- snapshotHandler:snapshotHandler];
+ [[FSTAsyncQueryListener alloc] initWithExecutor:self.firestore.client.userExecutor
+ snapshotHandler:snapshotHandler];
FSTQueryListener *internalListener =
[firestore.client listenToQuery:query
@@ -527,6 +527,11 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
if (firstOrderByField) {
[self validateOrderByField:*firstOrderByField matchesInequalityField:filter.field];
}
+ } else if (filter.filterOperator == FSTRelationFilterOperatorArrayContains) {
+ if ([self.query hasArrayContainsFilter]) {
+ FSTThrowInvalidUsage(@"InvalidQueryException",
+ @"Invalid Query. Queries only support a single arrayContains filter.");
+ }
}
}
diff --git a/Firestore/Source/API/FSTUserDataConverter.mm b/Firestore/Source/API/FSTUserDataConverter.mm
index 6d01c75..3484539 100644
--- a/Firestore/Source/API/FSTUserDataConverter.mm
+++ b/Firestore/Source/API/FSTUserDataConverter.mm
@@ -268,7 +268,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) {
}
- (instancetype)contextForField:(NSString *)fieldName {
- std::unique_ptr<FieldPath> path{};
+ std::unique_ptr<FieldPath> path;
if (_path) {
path = absl::make_unique<FieldPath>(_path->Append(util::MakeString(fieldName)));
}
@@ -282,7 +282,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) {
}
- (instancetype)contextForFieldPath:(const FieldPath &)fieldPath {
- std::unique_ptr<FieldPath> path{};
+ std::unique_ptr<FieldPath> path;
if (_path) {
path = absl::make_unique<FieldPath>(_path->Append(fieldPath));
}
@@ -428,9 +428,9 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) {
std::vector<FieldTransform> convertedFieldTransform;
if (fieldMask) {
- __block std::vector<FieldPath> fieldMaskPaths{};
+ __block std::vector<FieldPath> fieldMaskPaths;
[fieldMask enumerateObjectsUsingBlock:^(id fieldPath, NSUInteger idx, BOOL *stop) {
- FieldPath path{};
+ FieldPath path;
if ([fieldPath isKindOfClass:[NSString class]]) {
path = [FIRFieldPath pathWithDotSeparatedString:fieldPath].internalValue;
@@ -490,14 +490,14 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) {
NSDictionary *dict = input;
- __block std::vector<FieldPath> fieldMaskPaths{};
+ __block std::vector<FieldPath> fieldMaskPaths;
__block FSTObjectValue *updateData = [FSTObjectValue objectValue];
FSTParseContext *context =
[FSTParseContext contextWithSource:FSTUserDataSourceUpdate
path:absl::make_unique<FieldPath>(FieldPath::EmptyPath())];
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
- FieldPath path{};
+ FieldPath path;
if ([key isKindOfClass:[NSString class]]) {
path = [FIRFieldPath pathWithDotSeparatedString:key].internalValue;
diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h
index 7285e65..94c2284 100644
--- a/Firestore/Source/Core/FSTFirestoreClient.h
+++ b/Firestore/Source/Core/FSTFirestoreClient.h
@@ -15,6 +15,7 @@
*/
#import <Foundation/Foundation.h>
+#include <memory>
#import "Firestore/Source/Core/FSTTypes.h"
#import "Firestore/Source/Core/FSTViewSnapshot.h"
@@ -23,6 +24,7 @@
#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/executor.h"
@class FIRDocumentReference;
@class FIRDocumentSnapshot;
@@ -50,14 +52,15 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Creates and returns a FSTFirestoreClient with the given parameters.
*
- * All callbacks and events will be triggered on the provided userDispatchQueue.
+ * All callbacks and events will be triggered on the provided userExecutor.
*/
-+ (instancetype)clientWithDatabaseInfo:(const firebase::firestore::core::DatabaseInfo &)databaseInfo
- usePersistence:(BOOL)usePersistence
- credentialsProvider:(firebase::firestore::auth::CredentialsProvider *)
- credentialsProvider // no passing ownership
- userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue
- workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue;
++ (instancetype)
+clientWithDatabaseInfo:(const firebase::firestore::core::DatabaseInfo &)databaseInfo
+ usePersistence:(BOOL)usePersistence
+ credentialsProvider:(firebase::firestore::auth::CredentialsProvider *)
+ credentialsProvider // no passing ownership
+ userExecutor:(std::unique_ptr<firebase::firestore::util::internal::Executor>)userExecutor
+ workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue;
- (instancetype)init __attribute__((unavailable("Use static constructor method.")));
@@ -111,7 +114,7 @@ NS_ASSUME_NONNULL_BEGIN
* Dispatch queue for user callbacks / events. This will often be the "Main Dispatch Queue" of the
* app but the developer can configure it to a different queue if they so choose.
*/
-@property(nonatomic, strong, readonly) FSTDispatchQueue *userDispatchQueue;
+- (firebase::firestore::util::internal::Executor *)userExecutor;
@end
diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm
index 658cf57..da19960 100644
--- a/Firestore/Source/Core/FSTFirestoreClient.mm
+++ b/Firestore/Source/Core/FSTFirestoreClient.mm
@@ -18,6 +18,7 @@
#include <future> // NOLINT(build/c++11)
#include <memory>
+#include <utility>
#import "FIRFirestoreErrors.h"
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
@@ -44,11 +45,11 @@
#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/log.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
namespace util = firebase::firestore::util;
@@ -58,6 +59,8 @@ using firebase::firestore::core::DatabaseInfo;
using firebase::firestore::model::DatabaseId;
using firebase::firestore::model::DocumentKeySet;
+using firebase::firestore::util::internal::Executor;
+
NS_ASSUME_NONNULL_BEGIN
@interface FSTFirestoreClient () {
@@ -68,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN
usePersistence:(BOOL)usePersistence
credentialsProvider:
(CredentialsProvider *)credentialsProvider // no passing ownership
- userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue
+ userExecutor:(std::unique_ptr<Executor>)userExecutor
workerDispatchQueue:(FSTDispatchQueue *)queue NS_DESIGNATED_INITIALIZER;
@property(nonatomic, assign, readonly) const DatabaseInfo *databaseInfo;
@@ -91,18 +94,24 @@ NS_ASSUME_NONNULL_BEGIN
@end
-@implementation FSTFirestoreClient
+@implementation FSTFirestoreClient {
+ std::unique_ptr<Executor> _userExecutor;
+}
+
+- (Executor *)userExecutor {
+ return _userExecutor.get();
+}
+ (instancetype)clientWithDatabaseInfo:(const DatabaseInfo &)databaseInfo
usePersistence:(BOOL)usePersistence
credentialsProvider:
(CredentialsProvider *)credentialsProvider // no passing ownership
- userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue
+ userExecutor:(std::unique_ptr<Executor>)userExecutor
workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue {
return [[FSTFirestoreClient alloc] initWithDatabaseInfo:databaseInfo
usePersistence:usePersistence
credentialsProvider:credentialsProvider
- userDispatchQueue:userDispatchQueue
+ userExecutor:std::move(userExecutor)
workerDispatchQueue:workerDispatchQueue];
}
@@ -110,12 +119,12 @@ NS_ASSUME_NONNULL_BEGIN
usePersistence:(BOOL)usePersistence
credentialsProvider:
(CredentialsProvider *)credentialsProvider // no passing ownership
- userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue
+ userExecutor:(std::unique_ptr<Executor>)userExecutor
workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue {
if (self = [super init]) {
_databaseInfo = databaseInfo;
_credentialsProvider = credentialsProvider;
- _userDispatchQueue = userDispatchQueue;
+ _userExecutor = std::move(userExecutor);
_workerDispatchQueue = workerDispatchQueue;
auto userPromise = std::make_shared<std::promise<User>>();
@@ -217,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];
}
@@ -230,9 +239,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.workerDispatchQueue dispatchAsync:^{
[self.remoteStore disableNetwork];
if (completion) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(nil);
- }];
+ self->_userExecutor->Execute([=] { completion(nil); });
}
}];
}
@@ -241,9 +248,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.workerDispatchQueue dispatchAsync:^{
[self.remoteStore enableNetwork];
if (completion) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(nil);
- }];
+ self->_userExecutor->Execute([=] { completion(nil); });
}
}];
}
@@ -255,9 +260,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.remoteStore shutdown];
[self.persistence shutdown];
if (completion) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(nil);
- }];
+ self->_userExecutor->Execute([=] { completion(nil); });
}
}];
}
@@ -338,18 +341,14 @@ NS_ASSUME_NONNULL_BEGIN
[self.workerDispatchQueue dispatchAsync:^{
if (mutations.count == 0) {
if (completion) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(nil);
- }];
+ self->_userExecutor->Execute([=] { completion(nil); });
}
} else {
[self.syncEngine writeMutations:mutations
completion:^(NSError *error) {
// Dispatch the result back onto the user dispatch queue.
if (completion) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(error);
- }];
+ self->_userExecutor->Execute([=] { completion(error); });
}
}];
}
@@ -360,17 +359,16 @@ NS_ASSUME_NONNULL_BEGIN
updateBlock:(FSTTransactionBlock)updateBlock
completion:(FSTVoidIDErrorBlock)completion {
[self.workerDispatchQueue dispatchAsync:^{
- [self.syncEngine transactionWithRetries:retries
- workerDispatchQueue:self.workerDispatchQueue
- updateBlock:updateBlock
- completion:^(id _Nullable result, NSError *_Nullable error) {
- // Dispatch the result back onto the user dispatch queue.
- if (completion) {
- [self.userDispatchQueue dispatchAsync:^{
- completion(result, error);
- }];
- }
- }];
+ [self.syncEngine
+ transactionWithRetries:retries
+ workerDispatchQueue:self.workerDispatchQueue
+ updateBlock:updateBlock
+ completion:^(id _Nullable result, NSError *_Nullable error) {
+ // Dispatch the result back onto the user dispatch queue.
+ if (completion) {
+ self->_userExecutor->Execute([=] { completion(result, error); });
+ }
+ }];
}];
}
diff --git a/Firestore/Source/Core/FSTQuery.h b/Firestore/Source/Core/FSTQuery.h
index 572fabb..e38d3dd 100644
--- a/Firestore/Source/Core/FSTQuery.h
+++ b/Firestore/Source/Core/FSTQuery.h
@@ -245,6 +245,9 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
*/
- (const firebase::firestore::model::FieldPath *)inequalityFilterField;
+/** Returns YES if the query has an arrayContains filter already. */
+- (BOOL)hasArrayContainsFilter;
+
/** Returns the first field in an order-by constraint, or nullptr if none. */
- (const firebase::firestore::model::FieldPath *)firstSortOrderField;
diff --git a/Firestore/Source/Core/FSTQuery.mm b/Firestore/Source/Core/FSTQuery.mm
index d3961e8..13ebadb 100644
--- a/Firestore/Source/Core/FSTQuery.mm
+++ b/Firestore/Source/Core/FSTQuery.mm
@@ -724,6 +724,16 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
return nullptr;
}
+- (BOOL)hasArrayContainsFilter {
+ for (id<FSTFilter> filter in self.filters) {
+ if ([filter isKindOfClass:[FSTRelationFilter class]] &&
+ ((FSTRelationFilter *)filter).filterOperator == FSTRelationFilterOperatorArrayContains) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
- (const FieldPath *)firstSortOrderField {
if (self.explicitSortOrders.count > 0) {
return &self.explicitSortOrders.firstObject.field;
diff --git a/Firestore/Source/Core/FSTSnapshotVersion.h b/Firestore/Source/Core/FSTSnapshotVersion.h
deleted file mode 100644
index 8649d40..0000000
--- a/Firestore/Source/Core/FSTSnapshotVersion.h
+++ /dev/null
@@ -1,43 +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
-
-@class FIRTimestamp;
-
-/**
- * A version of a document in Firestore. This corresponds to the version timestamp, such as
- * update_time or read_time.
- */
-@interface FSTSnapshotVersion : NSObject <NSCopying>
-
-/** Creates a new version that is smaller than all other versions. */
-+ (instancetype)noVersion;
-
-/** Creates a new version representing the given timestamp. */
-+ (instancetype)versionWithTimestamp:(FIRTimestamp *)timestamp;
-
-- (instancetype)init NS_UNAVAILABLE;
-
-- (NSComparisonResult)compare:(FSTSnapshotVersion *)other;
-
-@property(nonatomic, strong, readonly) FIRTimestamp *timestamp;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTSnapshotVersion.mm b/Firestore/Source/Core/FSTSnapshotVersion.mm
deleted file mode 100644
index 58b2be4..0000000
--- a/Firestore/Source/Core/FSTSnapshotVersion.mm
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import "Firestore/Source/Core/FSTSnapshotVersion.h"
-
-#import "FIRTimestamp.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@implementation FSTSnapshotVersion
-
-+ (instancetype)noVersion {
- static FSTSnapshotVersion *min;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- FIRTimestamp *timestamp = [[FIRTimestamp alloc] initWithSeconds:0 nanoseconds:0];
- min = [FSTSnapshotVersion versionWithTimestamp:timestamp];
- });
- return min;
-}
-
-+ (instancetype)versionWithTimestamp:(FIRTimestamp *)timestamp {
- return [[FSTSnapshotVersion alloc] initWithTimestamp:timestamp];
-}
-
-- (instancetype)initWithTimestamp:(FIRTimestamp *)timestamp {
- self = [super init];
- if (self) {
- _timestamp = timestamp;
- }
- return self;
-}
-
-#pragma mark - NSObject methods
-
-- (BOOL)isEqual:(id)object {
- if (self == object) {
- return YES;
- }
- if (![object isKindOfClass:[FSTSnapshotVersion class]]) {
- return NO;
- }
- return [self.timestamp isEqual:((FSTSnapshotVersion *)object).timestamp];
-}
-
-- (NSUInteger)hash {
- return self.timestamp.hash;
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:@"<FSTSnapshotVersion: %@>", self.timestamp];
-}
-
-- (id)copyWithZone:(NSZone *_Nullable)zone {
- // Implements NSCopying without actually copying because timestamps are immutable.
- return self;
-}
-
-#pragma mark - Public methods
-
-- (NSComparisonResult)compare:(FSTSnapshotVersion *)other {
- return [self.timestamp compare:other.timestamp];
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm
index ed97d6c..9d9e526 100644
--- a/Firestore/Source/Core/FSTSyncEngine.mm
+++ b/Firestore/Source/Core/FSTSyncEngine.mm
@@ -40,12 +40,12 @@
#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/log.h"
using firebase::firestore::auth::HashUser;
using firebase::firestore::auth::User;
@@ -470,7 +470,7 @@ 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;
@@ -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/Local/FSTLevelDB.mm b/Firestore/Source/Local/FSTLevelDB.mm
index bc2f2eb..6d0f8af 100644
--- a/Firestore/Source/Local/FSTLevelDB.mm
+++ b/Firestore/Source/Local/FSTLevelDB.mm
@@ -25,7 +25,6 @@
#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"
diff --git a/Firestore/Source/Local/FSTLevelDBKey.mm b/Firestore/Source/Local/FSTLevelDBKey.mm
index e23f5b7..1fe0396 100644
--- a/Firestore/Source/Local/FSTLevelDBKey.mm
+++ b/Firestore/Source/Local/FSTLevelDBKey.mm
@@ -280,7 +280,7 @@ BOOL ReadDocumentKey(Slice *contents, FSTDocumentKey *__strong *result) {
Slice completeSegments = *contents;
std::string segment;
- std::vector<std::string> path_segments{};
+ std::vector<std::string> path_segments;
for (;;) {
// Advance a temporary slice to avoid advancing contents into the next key component which may
// not be a path segment.
diff --git a/Firestore/Source/Local/FSTLocalSerializer.mm b/Firestore/Source/Local/FSTLocalSerializer.mm
index 8fa1278..2c5ab4d 100644
--- a/Firestore/Source/Local/FSTLocalSerializer.mm
+++ b/Firestore/Source/Local/FSTLocalSerializer.mm
@@ -18,6 +18,7 @@
#include <cinttypes>
+#import "FIRTimestamp.h"
#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h"
#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm
index 0d6a785..245dd62 100644
--- a/Firestore/Source/Local/FSTLocalStore.mm
+++ b/Firestore/Source/Local/FSTLocalStore.mm
@@ -37,12 +37,12 @@
#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/log.h"
using firebase::firestore::auth::User;
using firebase::firestore::core::TargetIdGenerator;
@@ -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.
diff --git a/Firestore/Source/Local/FSTQueryData.mm b/Firestore/Source/Local/FSTQueryData.mm
index 5087dfc..16c3b2e 100644
--- a/Firestore/Source/Local/FSTQueryData.mm
+++ b/Firestore/Source/Local/FSTQueryData.mm
@@ -82,7 +82,7 @@ NS_ASSUME_NONNULL_BEGIN
NSUInteger result = [self.query hash];
result = result * 31 + self.targetID;
result = result * 31 + self.purpose;
- result = result * 31 + [self.snapshotVersion hash];
+ result = result * 31 + self.snapshotVersion.Hash();
result = result * 31 + [self.resumeToken hash];
return result;
}
diff --git a/Firestore/Source/Model/FSTDocument.mm b/Firestore/Source/Model/FSTDocument.mm
index 8ebc9ab..8c4c801 100644
--- a/Firestore/Source/Model/FSTDocument.mm
+++ b/Firestore/Source/Model/FSTDocument.mm
@@ -23,6 +23,7 @@
#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/hashing.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
namespace util = firebase::firestore::util;
@@ -45,7 +46,6 @@ NS_ASSUME_NONNULL_BEGIN
}
- (instancetype)initWithKey:(DocumentKey)key version:(SnapshotVersion)version {
- FSTAssert(!!version, @"Version must not be nil.");
self = [super init];
if (self) {
_key = std::move(key);
@@ -102,13 +102,13 @@ NS_ASSUME_NONNULL_BEGIN
}
FSTDocument *otherDoc = other;
- return [self.key isEqual:otherDoc.key] && [self.version isEqual:otherDoc.version] &&
+ return [self.key isEqual:otherDoc.key] && self.version == otherDoc.version &&
[self.data isEqual:otherDoc.data] && self.hasLocalMutations == otherDoc.hasLocalMutations;
}
- (NSUInteger)hash {
NSUInteger result = [self.key hash];
- result = result * 31 + [self.version hash];
+ result = result * 31 + self.version.Hash();
result = result * 31 + [self.data hash];
result = result * 31 + (self.hasLocalMutations ? 1 : 0);
return result;
@@ -142,12 +142,12 @@ NS_ASSUME_NONNULL_BEGIN
}
FSTDocument *otherDoc = other;
- return [self.key isEqual:otherDoc.key] && [self.version isEqual:otherDoc.version];
+ return [self.key isEqual:otherDoc.key] && self.version == otherDoc.version;
}
- (NSUInteger)hash {
NSUInteger result = [self.key hash];
- result = result * 31 + [self.version hash];
+ result = result * 31 + self.version.Hash();
return result;
}
diff --git a/Firestore/Source/Model/FSTMutation.mm b/Firestore/Source/Model/FSTMutation.mm
index ee6ef9c..82a535e 100644
--- a/Firestore/Source/Model/FSTMutation.mm
+++ b/Firestore/Source/Model/FSTMutation.mm
@@ -400,7 +400,7 @@ serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument
}
[transformResults
- addObject:transform.applyToRemoteDocument(previousValue, serverTransformResults[i])];
+ addObject:transform.ApplyToRemoteDocument(previousValue, serverTransformResults[i])];
}
return transformResults;
}
@@ -426,7 +426,7 @@ serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument
previousValue = [((FSTDocument *)baseDocument) fieldForPath:fieldTransform.path()];
}
- [transformResults addObject:transform.applyToLocalView(previousValue, localWriteTime)];
+ [transformResults addObject:transform.ApplyToLocalView(previousValue, localWriteTime)];
}
return transformResults;
}
diff --git a/Firestore/Source/Public/FIRDocumentReference.h b/Firestore/Source/Public/FIRDocumentReference.h
index 7baa30a..216a8dc 100644
--- a/Firestore/Source/Public/FIRDocumentReference.h
+++ b/Firestore/Source/Public/FIRDocumentReference.h
@@ -225,7 +225,8 @@ NS_SWIFT_NAME(DocumentReference)
* @param completion a block to execute once the document has been successfully read.
*/
// clang-format off
-- (void)getDocumentWithSource:(FIRFirestoreSource)source completion:(FIRDocumentSnapshotBlock)completion
+- (void)getDocumentWithSource:(FIRFirestoreSource)source
+ completion:(FIRDocumentSnapshotBlock)completion
NS_SWIFT_NAME(getDocument(source:completion:));
// clang-format on
diff --git a/Firestore/Source/Public/FIRQuery.h b/Firestore/Source/Public/FIRQuery.h
index 946cf06..799abcc 100644
--- a/Firestore/Source/Public/FIRQuery.h
+++ b/Firestore/Source/Public/FIRQuery.h
@@ -66,7 +66,8 @@ NS_SWIFT_NAME(Query)
* documentSet will be `nil` only if error is `non-nil`.
*/
// clang-format off
-- (void)getDocumentsWithSource:(FIRFirestoreSource)source completion:(FIRQuerySnapshotBlock)completion
+- (void)getDocumentsWithSource:(FIRFirestoreSource)source
+ completion:(FIRQuerySnapshotBlock)completion
NS_SWIFT_NAME(getDocuments(source:completion:));
// clang-format on
diff --git a/Firestore/Source/Remote/FSTDatastore.mm b/Firestore/Source/Remote/FSTDatastore.mm
index f0852fe..d45af6b 100644
--- a/Firestore/Source/Remote/FSTDatastore.mm
+++ b/Firestore/Source/Remote/FSTDatastore.mm
@@ -33,7 +33,6 @@
#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 +42,7 @@
#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/log.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
namespace util = firebase::firestore::util;
@@ -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,7 +285,7 @@ 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.");
NSMutableArray<FSTMaybeDocument *> *docs =
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..e512a3c 100644
--- a/Firestore/Source/Remote/FSTOnlineStateTracker.mm
+++ b/Firestore/Source/Remote/FSTOnlineStateTracker.mm
@@ -18,7 +18,8 @@
#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/log.h"
NS_ASSUME_NONNULL_BEGIN
@@ -83,10 +84,9 @@ static const NSTimeInterval kOnlineStateTimeout = 10;
FSTAssert(
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.",
+ LOG_DEBUG(
+ "Watch stream didn't reach Online or Offline within %s seconds. "
+ "Considering client offline.",
kOnlineStateTimeout);
[self logClientOfflineWarningIfNecessary];
[self setAndBroadcastState:FSTOnlineStateOffline];
@@ -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..ebd9b93 100644
--- a/Firestore/Source/Remote/FSTRemoteEvent.mm
+++ b/Firestore/Source/Remote/FSTRemoteEvent.mm
@@ -24,9 +24,10 @@
#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/hashing.h"
+#include "Firestore/core/src/firebase/firestore/util/log.h"
using firebase::firestore::model::DocumentKey;
using firebase::firestore::model::SnapshotVersion;
@@ -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..e0adb4e 100644
--- a/Firestore/Source/Remote/FSTRemoteStore.mm
+++ b/Firestore/Source/Remote/FSTRemoteStore.mm
@@ -32,11 +32,11 @@
#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/log.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
namespace util = firebase::firestore::util;
@@ -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
@@ -408,7 +408,7 @@ static const int kMaxPendingWrites = 10;
}
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];
@@ -490,8 +490,7 @@ static const int kMaxPendingWrites = 10;
- (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];
}
@@ -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 782e54c..f862ec3 100644
--- a/Firestore/Source/Remote/FSTSerializerBeta.mm
+++ b/Firestore/Source/Remote/FSTSerializerBeta.mm
@@ -683,8 +683,8 @@ NS_ASSUME_NONNULL_BEGIN
[transformResults addObject:[self decodedFieldValue:result]];
}
}
- return [[FSTMutationResult alloc]
- initWithVersion:(version ? version.value() : nil)transformResults:transformResults];
+ return [[FSTMutationResult alloc] initWithVersion:std::move(version)
+ transformResults:transformResults];
}
#pragma mark - FSTQueryData => GCFSTarget proto
diff --git a/Firestore/Source/Remote/FSTStream.mm b/Firestore/Source/Remote/FSTStream.mm
index f4ec675..0e45418 100644
--- a/Firestore/Source/Remote/FSTStream.mm
+++ b/Firestore/Source/Remote/FSTStream.mm
@@ -29,7 +29,6 @@
#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 +37,7 @@
#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/log.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
namespace util = firebase::firestore::util;
@@ -258,7 +258,7 @@ static const NSTimeInterval kIdleTimeout = 60.0;
return;
}
- FSTLog(@"%@ %p start", NSStringFromClass([self class]), (__bridge void *)self);
+ LOG_DEBUG("%s %s start", NSStringFromClass([self class]), (__bridge void *)self);
FSTAssert(self.state == FSTStreamStateInitial, @"Already started");
self.state = FSTStreamStateAuth;
@@ -311,7 +311,7 @@ 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");
@@ -381,13 +381,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 +395,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,7 +426,7 @@ 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];
}
@@ -550,7 +550,7 @@ 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);
+ LOG_DEBUG("%s %s close: %s", NSStringFromClass([self class]), (__bridge void *)self, error);
FSTAssert([self isStarted], @"handleStreamClose: called for non-started stream.");
// In theory the stream could close cleanly, however, in our current model we never expect this
@@ -577,9 +577,9 @@ static const NSTimeInterval kIdleTimeout = 60.0;
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;
@@ -665,7 +665,7 @@ 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];
}
@@ -677,7 +677,7 @@ static const NSTimeInterval kIdleTimeout = 60.0;
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 +686,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.
@@ -765,7 +765,7 @@ 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];
}
@@ -783,7 +783,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 +792,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/FSTAsyncQueryListener.h b/Firestore/Source/Util/FSTAsyncQueryListener.h
index 4888268..06471d8 100644
--- a/Firestore/Source/Util/FSTAsyncQueryListener.h
+++ b/Firestore/Source/Util/FSTAsyncQueryListener.h
@@ -18,6 +18,8 @@
#import "Firestore/Source/Core/FSTViewSnapshot.h"
+#include "Firestore/core/src/firebase/firestore/util/executor.h"
+
NS_ASSUME_NONNULL_BEGIN
@class FSTDispatchQueue;
@@ -28,9 +30,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface FSTAsyncQueryListener : NSObject
-- (instancetype)initWithDispatchQueue:(FSTDispatchQueue *)dispatchQueue
- snapshotHandler:(FSTViewSnapshotHandler)snapshotHandler
- NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithExecutor:(firebase::firestore::util::internal::Executor*)executor
+ snapshotHandler:(FSTViewSnapshotHandler)snapshotHandler NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
diff --git a/Firestore/Source/Util/FSTAsyncQueryListener.mm b/Firestore/Source/Util/FSTAsyncQueryListener.mm
index b72ac57..81dd41f 100644
--- a/Firestore/Source/Util/FSTAsyncQueryListener.mm
+++ b/Firestore/Source/Util/FSTAsyncQueryListener.mm
@@ -18,16 +18,18 @@
#import "Firestore/Source/Util/FSTDispatchQueue.h"
+using firebase::firestore::util::internal::Executor;
+
@implementation FSTAsyncQueryListener {
volatile BOOL _muted;
FSTViewSnapshotHandler _snapshotHandler;
- FSTDispatchQueue *_dispatchQueue;
+ Executor *_executor;
}
-- (instancetype)initWithDispatchQueue:(FSTDispatchQueue *)dispatchQueue
- snapshotHandler:(FSTViewSnapshotHandler)snapshotHandler {
+- (instancetype)initWithExecutor:(Executor *)executor
+ snapshotHandler:(FSTViewSnapshotHandler)snapshotHandler {
if (self = [super init]) {
- _dispatchQueue = dispatchQueue;
+ _executor = executor;
_snapshotHandler = snapshotHandler;
}
return self;
@@ -40,11 +42,11 @@
// users just want to turn on notifications "forever" and don't want to have
// to keep track of our handle to keep them going.
return ^(FSTViewSnapshot *_Nullable snapshot, NSError *_Nullable error) {
- [self->_dispatchQueue dispatchAsync:^{
+ self->_executor->Execute([self, snapshot, error] {
if (!self->_muted) {
self->_snapshotHandler(snapshot, error);
}
- }];
+ });
};
}
diff --git a/Firestore/Source/Util/FSTDispatchQueue.mm b/Firestore/Source/Util/FSTDispatchQueue.mm
index 0974359..01b2732 100644
--- a/Firestore/Source/Util/FSTDispatchQueue.mm
+++ b/Firestore/Source/Util/FSTDispatchQueue.mm
@@ -16,154 +16,66 @@
#import <Foundation/Foundation.h>
-#include <atomic>
+#include <memory>
+#include <utility>
#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTDispatchQueue.h"
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- * removeDelayedCallback is used by FSTDelayedCallback and so we pre-declare it before the rest of
- * the FSTDispatchQueue private interface.
- */
-@interface FSTDispatchQueue ()
-- (void)removeDelayedCallback:(FSTDelayedCallback *)callback;
-@end
+#include "Firestore/core/src/firebase/firestore/util/async_queue.h"
+#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h"
+#include "absl/memory/memory.h"
-#pragma mark - FSTDelayedCallback
-
-/**
- * Represents a callback scheduled to be run in the future on an FSTDispatchQueue.
- *
- * It is created via [FSTDelayedCallback createAndScheduleWithQueue].
- *
- * Supports cancellation (via cancel) and early execution (via skipDelay).
- */
-@interface FSTDelayedCallback ()
+using firebase::firestore::util::AsyncQueue;
+using firebase::firestore::util::DelayedOperation;
+using firebase::firestore::util::TimerId;
+using firebase::firestore::util::internal::Executor;
+using firebase::firestore::util::internal::ExecutorLibdispatch;
-@property(nonatomic, strong, readonly) FSTDispatchQueue *queue;
-@property(nonatomic, assign, readonly) FSTTimerID timerID;
-@property(nonatomic, assign, readonly) NSTimeInterval targetTime;
-@property(nonatomic, copy) void (^callback)();
-/** YES if the callback has been run or canceled. */
-@property(nonatomic, getter=isDone) BOOL done;
+NS_ASSUME_NONNULL_BEGIN
-/**
- * Creates and returns an FSTDelayedCallback that has been scheduled on the provided queue with the
- * provided delay.
- *
- * @param queue The FSTDispatchQueue to run the callback on.
- * @param timerID A FSTTimerID identifying the type of the delayed callback.
- * @param delay The delay before the callback should be scheduled.
- * @param callback The callback block to run.
- * @return The created FSTDelayedCallback instance.
- */
-+ (instancetype)createAndScheduleWithQueue:(FSTDispatchQueue *)queue
- timerID:(FSTTimerID)timerID
- delay:(NSTimeInterval)delay
- callback:(void (^)(void))callback;
+#pragma mark - FSTDelayedCallback
-/**
- * Queues the callback to run immediately (if it hasn't already been run or canceled).
- */
-- (void)skipDelay;
+@interface FSTDelayedCallback () {
+ DelayedOperation _impl;
+}
@end
@implementation FSTDelayedCallback
-- (instancetype)initWithQueue:(FSTDispatchQueue *)queue
- timerID:(FSTTimerID)timerID
- targetTime:(NSTimeInterval)targetTime
- callback:(void (^)(void))callback {
+- (instancetype)initWithImpl:(DelayedOperation &&)impl {
if (self = [super init]) {
- _queue = queue;
- _timerID = timerID;
- _targetTime = targetTime;
- _callback = callback;
- _done = NO;
+ _impl = std::move(impl);
}
return self;
}
-+ (instancetype)createAndScheduleWithQueue:(FSTDispatchQueue *)queue
- timerID:(FSTTimerID)timerID
- delay:(NSTimeInterval)delay
- callback:(void (^)(void))callback {
- NSTimeInterval targetTime = [[NSDate date] timeIntervalSince1970] + delay;
- FSTDelayedCallback *delayedCallback = [[FSTDelayedCallback alloc] initWithQueue:queue
- timerID:timerID
- targetTime:targetTime
- callback:callback];
- [delayedCallback startWithDelay:delay];
- return delayedCallback;
-}
-
-/**
- * Starts the timer. This is called immediately after construction by createAndScheduleWithQueue.
- */
-- (void)startWithDelay:(NSTimeInterval)delay {
- dispatch_time_t delayNs = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
- dispatch_after(delayNs, self.queue.queue, ^{
- [self.queue enterCheckedOperation:^{
- [self delayDidElapse];
- }];
- });
-}
-
-- (void)skipDelay {
- [self.queue dispatchAsyncAllowingSameQueue:^{
- [self delayDidElapse];
- }];
-}
-
- (void)cancel {
- [self.queue verifyIsCurrentQueue];
- if (!self.isDone) {
- // PORTING NOTE: There's no way to actually cancel the dispatched callback, but it'll be a no-op
- // since we set done to YES.
- [self markDone];
- }
-}
-
-- (void)delayDidElapse {
- [self.queue verifyIsCurrentQueue];
- if (!self.isDone) {
- [self markDone];
- self.callback();
- }
-}
-
-/**
- * Marks this delayed callback as done, and notifies the FSTDispatchQueue that it should be removed.
- */
-- (void)markDone {
- self.done = YES;
- [self.queue removeDelayedCallback:self];
+ _impl.Cancel();
}
@end
#pragma mark - FSTDispatchQueue
-@interface FSTDispatchQueue ()
-/**
- * Callbacks scheduled to be queued in the future. Callbacks are automatically removed after they
- * are run or canceled.
- */
-@property(nonatomic, strong, readonly) NSMutableArray<FSTDelayedCallback *> *delayedCallbacks;
-
-- (instancetype)initWithQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;
-
-@end
-
@implementation FSTDispatchQueue {
- /**
- * Flag set while an FSTDispatchQueue operation is currently executing. Used for assertion
- * sanity-checks.
- */
- std::atomic<bool> _operationInProgress;
+ std::unique_ptr<AsyncQueue> _impl;
+}
+
++ (TimerId)convertTimerId:(FSTTimerID)objcTimerID {
+ const TimerId converted = static_cast<TimerId>(objcTimerID);
+ switch (converted) {
+ case TimerId::All:
+ case TimerId::ListenStreamIdle:
+ case TimerId::ListenStreamConnectionBackoff:
+ case TimerId::WriteStreamIdle:
+ case TimerId::WriteStreamConnectionBackoff:
+ case TimerId::OnlineStateTimeout:
+ return converted;
+ default:
+ FSTAssert(false, @"Unknown value of enum FSTTimerID.");
+ }
}
+ (instancetype)queueWith:(dispatch_queue_t)dispatchQueue {
@@ -172,141 +84,50 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithQueue:(dispatch_queue_t)queue {
if (self = [super init]) {
- _operationInProgress = false;
_queue = queue;
- _delayedCallbacks = [NSMutableArray array];
+ auto executor = absl::make_unique<ExecutorLibdispatch>(queue);
+ _impl = absl::make_unique<AsyncQueue>(std::move(executor));
}
return self;
}
- (void)verifyIsCurrentQueue {
- FSTAssert([self onTargetQueue],
- @"We are running on the wrong dispatch queue. Expected '%@' Actual: '%@'",
- [self targetQueueLabel], [self currentQueueLabel]);
- FSTAssert(_operationInProgress,
- @"verifyIsCurrentQueue called outside enterCheckedOperation on queue '%@'",
- [self currentQueueLabel]);
+ _impl->VerifyIsCurrentQueue();
}
- (void)enterCheckedOperation:(void (^)(void))block {
- FSTAssert(!_operationInProgress,
- @"enterCheckedOperation may not be called when an operation is in progress");
- @try {
- _operationInProgress = true;
- [self verifyIsCurrentQueue];
- block();
- } @finally {
- _operationInProgress = false;
- }
+ _impl->ExecuteBlocking([block] { block(); });
}
- (void)dispatchAsync:(void (^)(void))block {
- FSTAssert(![self onTargetQueue] || !_operationInProgress,
- @"dispatchAsync called when we are already running on target dispatch queue '%@'",
- [self targetQueueLabel]);
-
- dispatch_async(self.queue, ^{
- [self enterCheckedOperation:block];
- });
+ _impl->Enqueue([block] { block(); });
}
- (void)dispatchAsyncAllowingSameQueue:(void (^)(void))block {
- dispatch_async(self.queue, ^{
- [self enterCheckedOperation:block];
- });
+ _impl->EnqueueRelaxed([block] { block(); });
}
- (void)dispatchSync:(void (^)(void))block {
- FSTAssert(![self onTargetQueue] || !_operationInProgress,
- @"dispatchSync called when we are already running on target dispatch queue '%@'",
- [self targetQueueLabel]);
-
- dispatch_sync(self.queue, ^{
- [self enterCheckedOperation:block];
- });
+ _impl->EnqueueBlocking([block] { block(); });
}
- (FSTDelayedCallback *)dispatchAfterDelay:(NSTimeInterval)delay
timerID:(FSTTimerID)timerID
block:(void (^)(void))block {
- // While not necessarily harmful, we currently don't expect to have multiple callbacks with the
- // same timerID in the queue, so defensively reject them.
- FSTAssert(![self containsDelayedCallbackWithTimerID:timerID],
- @"Attempted to schedule multiple callbacks with id %ld", (unsigned long)timerID);
- FSTDelayedCallback *delayedCallback = [FSTDelayedCallback createAndScheduleWithQueue:self
- timerID:timerID
- delay:delay
- callback:block];
- [self.delayedCallbacks addObject:delayedCallback];
- return delayedCallback;
+ const AsyncQueue::Milliseconds delayMs =
+ std::chrono::milliseconds(static_cast<long long>(delay * 1000));
+ const TimerId convertedTimerId = [FSTDispatchQueue convertTimerId:timerID];
+ DelayedOperation delayed_operation =
+ _impl->EnqueueAfterDelay(delayMs, convertedTimerId, [block] { block(); });
+ return [[FSTDelayedCallback alloc] initWithImpl:std::move(delayed_operation)];
}
- (BOOL)containsDelayedCallbackWithTimerID:(FSTTimerID)timerID {
- NSUInteger matchIndex = [self.delayedCallbacks
- indexOfObjectPassingTest:^BOOL(FSTDelayedCallback *obj, NSUInteger idx, BOOL *stop) {
- return obj.timerID == timerID;
- }];
- return matchIndex != NSNotFound;
+ return _impl->IsScheduled([FSTDispatchQueue convertTimerId:timerID]);
}
- (void)runDelayedCallbacksUntil:(FSTTimerID)lastTimerID {
- dispatch_semaphore_t doneSemaphore = dispatch_semaphore_create(0);
-
- [self dispatchAsync:^{
- FSTAssert(lastTimerID == FSTTimerIDAll || [self containsDelayedCallbackWithTimerID:lastTimerID],
- @"Attempted to run callbacks until missing timer ID: %ld",
- (unsigned long)lastTimerID);
-
- [self sortDelayedCallbacks];
- for (FSTDelayedCallback *callback in self.delayedCallbacks) {
- [callback skipDelay];
- if (lastTimerID != FSTTimerIDAll && callback.timerID == lastTimerID) {
- break;
- }
- }
-
- // Now that the callbacks are queued, we want to enqueue an additional item to release the
- // 'done' semaphore.
- [self dispatchAsyncAllowingSameQueue:^{
- dispatch_semaphore_signal(doneSemaphore);
- }];
- }];
-
- dispatch_semaphore_wait(doneSemaphore, DISPATCH_TIME_FOREVER);
-}
-
-// NOTE: For performance we could store the callbacks sorted (e.g. using std::priority_queue),
-// but this sort only happens in tests (if runDelayedCallbacksUntil: is called), and the size
-// is guaranteed to be small since we don't allow duplicate TimerIds (of which there are only 4).
-- (void)sortDelayedCallbacks {
- // We want to run callbacks in the same order they'd run if they ran naturally.
- [self.delayedCallbacks
- sortUsingComparator:^NSComparisonResult(FSTDelayedCallback *a, FSTDelayedCallback *b) {
- return a.targetTime < b.targetTime
- ? NSOrderedAscending
- : a.targetTime > b.targetTime ? NSOrderedDescending : NSOrderedSame;
- }];
-}
-
-/** Called by FSTDelayedCallback when a callback is run or canceled. */
-- (void)removeDelayedCallback:(FSTDelayedCallback *)callback {
- NSUInteger index = [self.delayedCallbacks indexOfObject:callback];
- FSTAssert(index != NSNotFound, @"Delayed callback not found.");
- [self.delayedCallbacks removeObjectAtIndex:index];
-}
-
-#pragma mark - Private Methods
-
-- (NSString *)currentQueueLabel {
- return [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)];
-}
-
-- (NSString *)targetQueueLabel {
- return [NSString stringWithUTF8String:dispatch_queue_get_label(self.queue)];
-}
-
-- (BOOL)onTargetQueue {
- return [[self currentQueueLabel] isEqualToString:[self targetQueueLabel]];
+ _impl->RunScheduledOperationsUntil([FSTDispatchQueue convertTimerId:lastTimerID]);
}
@end
diff --git a/Firestore/Source/Util/FSTLogger.h b/Firestore/Source/Util/FSTLogger.h
deleted file mode 100644
index c4e2b85..0000000
--- a/Firestore/Source/Util/FSTLogger.h
+++ /dev/null
@@ -1,26 +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
-
-/** Logs to NSLog if [FIRFirestore isLoggingEnabled] is YES. */
-void FSTLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
-
-void FSTWarn(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
-
-NS_ASSUME_NONNULL_END
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/core/CMakeLists.txt b/Firestore/core/CMakeLists.txt
index 1a0c936..c6ae0f5 100644
--- a/Firestore/core/CMakeLists.txt
+++ b/Firestore/core/CMakeLists.txt
@@ -20,6 +20,7 @@ add_subdirectory(src/firebase/firestore/core)
add_subdirectory(src/firebase/firestore/immutable)
add_subdirectory(src/firebase/firestore/local)
add_subdirectory(src/firebase/firestore/model)
+add_subdirectory(src/firebase/firestore/nanopb)
add_subdirectory(src/firebase/firestore/remote)
add_subdirectory(src/firebase/firestore/util)
diff --git a/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm b/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm
index ff2d5f7..9d5b89e 100644
--- a/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm
+++ b/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm
@@ -20,7 +20,7 @@
#import <FirebaseCore/FIRAppInternal.h>
#import <FirebaseCore/FIROptionsInternal.h>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
// NB: This is also defined in Firestore/Source/Public/FIRFirestoreErrors.h
@@ -80,8 +80,8 @@ FirebaseCredentialsProvider::~FirebaseCredentialsProvider() {
void FirebaseCredentialsProvider::GetToken(bool force_refresh,
TokenListener completion) {
- FIREBASE_ASSERT_MESSAGE(auth_listener_handle_,
- "GetToken cannot be called after listener removed.");
+ HARD_ASSERT(auth_listener_handle_,
+ "GetToken cannot be called after listener removed.");
// Take note of the current value of the userCounter so that this method can
// fail if there is a user change while the request is outstanding.
@@ -129,15 +129,13 @@ void FirebaseCredentialsProvider::SetUserChangeListener(
UserChangeListener listener) {
std::unique_lock<std::mutex> lock(contents_->mutex);
if (listener) {
- FIREBASE_ASSERT_MESSAGE(!user_change_listener_,
- "set user_change_listener twice!");
+ HARD_ASSERT(!user_change_listener_, "set user_change_listener twice!");
// Fire initial event.
listener(contents_->current_user);
} else {
- FIREBASE_ASSERT_MESSAGE(auth_listener_handle_,
- "removed user_change_listener twice!");
- FIREBASE_ASSERT_MESSAGE(user_change_listener_,
- "user_change_listener removed without being set!");
+ HARD_ASSERT(auth_listener_handle_, "removed user_change_listener twice!");
+ HARD_ASSERT(user_change_listener_,
+ "user_change_listener removed without being set!");
[[NSNotificationCenter defaultCenter] removeObserver:auth_listener_handle_];
auth_listener_handle_ = nil;
}
diff --git a/Firestore/core/src/firebase/firestore/auth/token.h b/Firestore/core/src/firebase/firestore/auth/token.h
index 56084f8..b0d7075 100644
--- a/Firestore/core/src/firebase/firestore/auth/token.h
+++ b/Firestore/core/src/firebase/firestore/auth/token.h
@@ -20,7 +20,7 @@
#include <string>
#include "Firestore/core/src/firebase/firestore/auth/user.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/strings/string_view.h"
namespace firebase {
@@ -46,7 +46,7 @@ class Token {
/** The actual raw token. */
const std::string& token() const {
- FIREBASE_ASSERT(user_.is_authenticated());
+ HARD_ASSERT(user_.is_authenticated());
return token_;
}
diff --git a/Firestore/core/src/firebase/firestore/auth/user.cc b/Firestore/core/src/firebase/firestore/auth/user.cc
index 4793fed..4fc10f6 100644
--- a/Firestore/core/src/firebase/firestore/auth/user.cc
+++ b/Firestore/core/src/firebase/firestore/auth/user.cc
@@ -16,7 +16,7 @@
#include "Firestore/core/src/firebase/firestore/auth/user.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -26,7 +26,7 @@ User::User() : is_authenticated_(false) {
}
User::User(const absl::string_view uid) : uid_(uid), is_authenticated_(true) {
- FIREBASE_ASSERT(!uid.empty());
+ HARD_ASSERT(!uid.empty());
}
const User& User::Unauthenticated() {
diff --git a/Firestore/core/src/firebase/firestore/geo_point.cc b/Firestore/core/src/firebase/firestore/geo_point.cc
index 1ed5126..393b8f2 100644
--- a/Firestore/core/src/firebase/firestore/geo_point.cc
+++ b/Firestore/core/src/firebase/firestore/geo_point.cc
@@ -18,9 +18,7 @@
#include <cmath>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
-
-using std::isnan;
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -30,14 +28,10 @@ GeoPoint::GeoPoint() : GeoPoint(0, 0) {
GeoPoint::GeoPoint(double latitude, double longitude)
: latitude_(latitude), longitude_(longitude) {
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
- !isnan(latitude) && -90 <= latitude && latitude <= 90,
- -90 <= latitude && latitude <= 90,
- "Latitude must be in the range of [-90, 90]");
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
- !isnan(longitude) && -180 <= longitude && longitude <= 180,
- -180 <= longitude && longitude <= 180,
- "Latitude must be in the range of [-180, 180]");
+ HARD_ASSERT(!std::isnan(latitude) && -90 <= latitude && latitude <= 90,
+ "Latitude must be in the range of [-90, 90]");
+ HARD_ASSERT(!std::isnan(longitude) && -180 <= longitude && longitude <= 180,
+ "Latitude must be in the range of [-180, 180]");
}
bool operator<(const GeoPoint& lhs, const GeoPoint& rhs) {
diff --git a/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h b/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h
index db53969..b1c9398 100644
--- a/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h
+++ b/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h
@@ -28,7 +28,7 @@
#include "Firestore/core/src/firebase/firestore/immutable/map_entry.h"
#include "Firestore/core/src/firebase/firestore/immutable/sorted_map_base.h"
#include "Firestore/core/src/firebase/firestore/util/comparison.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "Firestore/core/src/firebase/firestore/util/range.h"
namespace firebase {
@@ -74,7 +74,7 @@ class FixedArray {
void append(SourceIterator src_begin, SourceIterator src_end) {
auto appending = static_cast<size_type>(src_end - src_begin);
auto new_size = size_ + appending;
- FIREBASE_ASSERT(new_size <= SortedMapBase::kFixedSize);
+ HARD_ASSERT(new_size <= SortedMapBase::kFixedSize);
std::copy(src_begin, src_end, end());
size_ = new_size;
@@ -85,7 +85,7 @@ class FixedArray {
*/
void append(T&& value) {
size_type new_size = size_ + 1;
- FIREBASE_ASSERT(new_size <= SortedMapBase::kFixedSize);
+ HARD_ASSERT(new_size <= SortedMapBase::kFixedSize);
*end() = std::move(value);
size_ = new_size;
diff --git a/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h b/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h
index 5011947..3092678 100644
--- a/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h
+++ b/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h
@@ -23,7 +23,7 @@
#include "Firestore/core/src/firebase/firestore/immutable/llrb_node.h"
#include "Firestore/core/src/firebase/firestore/util/comparison.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -149,7 +149,7 @@ class LlrbNodeIterator {
* This can only be called if `end()` is false.
*/
pointer get() const {
- FIREBASE_ASSERT(!is_end());
+ HARD_ASSERT(!is_end());
return &(stack_.top()->entry());
}
@@ -162,7 +162,7 @@ class LlrbNodeIterator {
}
LlrbNodeIterator& operator++() {
- FIREBASE_ASSERT(!is_end());
+ HARD_ASSERT(!is_end());
// Pop the stack, moving the currently pointed to node to the parent.
const node_type* node = stack_.top();
diff --git a/Firestore/core/src/firebase/firestore/immutable/sorted_map.h b/Firestore/core/src/firebase/firestore/immutable/sorted_map.h
index 647bab0..3a50020 100644
--- a/Firestore/core/src/firebase/firestore/immutable/sorted_map.h
+++ b/Firestore/core/src/firebase/firestore/immutable/sorted_map.h
@@ -144,7 +144,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return tree_.empty();
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/** Returns the number of items in this map. */
@@ -155,7 +155,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return tree_.size();
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -184,7 +184,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return SortedMap{tree_.insert(key, value)};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -205,7 +205,7 @@ class SortedMap : public impl::SortedMapBase {
}
return SortedMap{std::move(result)};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
bool contains(const K& key) const {
@@ -215,7 +215,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return tree_.contains(key);
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -232,7 +232,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return const_iterator{tree_.find(key)};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -248,7 +248,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return tree_.find_index(key);
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -267,7 +267,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return const_iterator{tree_.lower_bound(key)};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
const_iterator min() const {
@@ -277,7 +277,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return const_iterator{tree_.min()};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
const_iterator max() const {
@@ -287,7 +287,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return const_iterator{tree_.max()};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -301,7 +301,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return const_iterator{tree_.begin()};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -314,7 +314,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return const_iterator{tree_.end()};
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
/**
@@ -359,7 +359,7 @@ class SortedMap : public impl::SortedMapBase {
case Tag::Tree:
return tree_.comparator();
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
enum class Tag {
diff --git a/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h b/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h
index a79f9f5..960e3f6 100644
--- a/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h
+++ b/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h
@@ -123,7 +123,7 @@ class SortedMapIterator {
case Tag::Tree:
return tree_iter_.get();
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
reference operator*() const {
@@ -164,7 +164,7 @@ class SortedMapIterator {
case Tag::Tree:
return a.tree_iter_ == b.tree_iter_;
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
bool operator!=(const SortedMapIterator& b) const {
diff --git a/Firestore/core/src/firebase/firestore/immutable/sorted_set.h b/Firestore/core/src/firebase/firestore/immutable/sorted_set.h
index d78fd61..1fe91bd 100644
--- a/Firestore/core/src/firebase/firestore/immutable/sorted_set.h
+++ b/Firestore/core/src/firebase/firestore/immutable/sorted_set.h
@@ -23,7 +23,7 @@
#include "Firestore/core/src/firebase/firestore/immutable/sorted_map.h"
#include "Firestore/core/src/firebase/firestore/immutable/sorted_map_base.h"
#include "Firestore/core/src/firebase/firestore/util/comparison.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "Firestore/core/src/firebase/firestore/util/hashing.h"
namespace firebase {
diff --git a/Firestore/core/src/firebase/firestore/local/leveldb_key.cc b/Firestore/core/src/firebase/firestore/local/leveldb_key.cc
index 7febe71..3a4e512 100644
--- a/Firestore/core/src/firebase/firestore/local/leveldb_key.cc
+++ b/Firestore/core/src/firebase/firestore/local/leveldb_key.cc
@@ -534,7 +534,7 @@ class Writer {
OrderedCode::WriteString(&dest_, value);
}
- std::string dest_{};
+ std::string dest_;
};
} // namespace
diff --git a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc
index 561d1e2..da9f004 100644
--- a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc
+++ b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc
@@ -17,7 +17,7 @@
#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "Firestore/core/src/firebase/firestore/util/log.h"
#include "absl/memory/memory.h"
#include "leveldb/write_batch.h"
@@ -71,26 +71,24 @@ void LevelDbTransaction::Iterator::UpdateCurrent() {
void LevelDbTransaction::Iterator::Seek(const std::string& key) {
db_iter_->Seek(key);
- FIREBASE_ASSERT_MESSAGE(db_iter_->status().ok(),
- "leveldb iterator reported an error: %s",
- db_iter_->status().ToString().c_str());
+ HARD_ASSERT(db_iter_->status().ok(), "leveldb iterator reported an error: %s",
+ db_iter_->status().ToString());
for (; db_iter_->Valid() && IsDeleted(db_iter_->key()); db_iter_->Next()) {
}
- FIREBASE_ASSERT_MESSAGE(db_iter_->status().ok(),
- "leveldb iterator reported an error: %s",
- db_iter_->status().ToString().c_str());
+ HARD_ASSERT(db_iter_->status().ok(), "leveldb iterator reported an error: %s",
+ db_iter_->status().ToString());
mutations_iter_ = txn_->mutations_.lower_bound(key);
UpdateCurrent();
last_version_ = txn_->version_;
}
absl::string_view LevelDbTransaction::Iterator::key() {
- FIREBASE_ASSERT_MESSAGE(Valid(), "key() called on invalid iterator");
+ HARD_ASSERT(Valid(), "key() called on invalid iterator");
return current_.first;
}
absl::string_view LevelDbTransaction::Iterator::value() {
- FIREBASE_ASSERT_MESSAGE(Valid(), "value() called on invalid iterator");
+ HARD_ASSERT(Valid(), "value() called on invalid iterator");
return current_.second;
}
@@ -115,13 +113,12 @@ void LevelDbTransaction::Iterator::AdvanceLDB() {
do {
db_iter_->Next();
} while (db_iter_->Valid() && IsDeleted(db_iter_->key()));
- FIREBASE_ASSERT_MESSAGE(db_iter_->status().ok(),
- "leveldb iterator reported an error: %s",
- db_iter_->status().ToString().c_str());
+ HARD_ASSERT(db_iter_->status().ok(), "leveldb iterator reported an error: %s",
+ db_iter_->status().ToString());
}
void LevelDbTransaction::Iterator::Next() {
- FIREBASE_ASSERT_MESSAGE(Valid(), "Next() called on invalid iterator");
+ HARD_ASSERT(Valid(), "Next() called on invalid iterator");
bool advanced = SyncToTransaction();
if (!advanced && is_valid_) {
if (is_mutation_) {
@@ -215,14 +212,11 @@ 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);
- FIREBASE_ASSERT_MESSAGE(status.ok(),
- "Failed to commit transaction:\n%s\n Failed: %s",
- ToString().c_str(), status.ToString().c_str());
+ HARD_ASSERT(status.ok(), "Failed to commit transaction:\n%s\n Failed: %s",
+ ToString(), status.ToString());
}
std::string LevelDbTransaction::ToString() {
diff --git a/Firestore/core/src/firebase/firestore/model/base_path.h b/Firestore/core/src/firebase/firestore/model/base_path.h
index 58df6f0..7608829 100644
--- a/Firestore/core/src/firebase/firestore/model/base_path.h
+++ b/Firestore/core/src/firebase/firestore/model/base_path.h
@@ -24,7 +24,7 @@
#include <utility>
#include <vector>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "Firestore/core/src/firebase/firestore/util/hashing.h"
namespace firebase {
@@ -57,19 +57,18 @@ class BasePath {
/** Returns i-th segment of the path. */
const std::string& operator[](const size_t i) const {
- FIREBASE_ASSERT_MESSAGE(i < segments_.size(), "index %u out of range", i);
+ HARD_ASSERT(i < segments_.size(), "index %s out of range", i);
return segments_[i];
}
/** Returns the first segment of the path. */
const std::string& first_segment() const {
- FIREBASE_ASSERT_MESSAGE(!empty(),
- "Cannot call first_segment on empty path");
+ HARD_ASSERT(!empty(), "Cannot call first_segment on empty path");
return segments_[0];
}
/** Returns the last segment of the path. */
const std::string& last_segment() const {
- FIREBASE_ASSERT_MESSAGE(!empty(), "Cannot call last_segment on empty path");
+ HARD_ASSERT(!empty(), "Cannot call last_segment on empty path");
return segments_[size() - 1];
}
@@ -117,9 +116,8 @@ class BasePath {
* this path.
*/
T PopFirst(const size_t n = 1) const {
- FIREBASE_ASSERT_MESSAGE(n <= size(),
- "Cannot call PopFirst(%u) on path of length %u", n,
- size());
+ HARD_ASSERT(n <= size(), "Cannot call PopFirst(%s) on path of length %s", n,
+ size());
return T{begin() + n, end()};
}
@@ -128,7 +126,7 @@ class BasePath {
* this path.
*/
T PopLast() const {
- FIREBASE_ASSERT_MESSAGE(!empty(), "Cannot call PopLast() on empty path");
+ HARD_ASSERT(!empty(), "Cannot call PopLast() on empty path");
return T{begin(), end() - 1};
}
diff --git a/Firestore/core/src/firebase/firestore/model/database_id.cc b/Firestore/core/src/firebase/firestore/model/database_id.cc
index a756ea7..97e7d92 100644
--- a/Firestore/core/src/firebase/firestore/model/database_id.cc
+++ b/Firestore/core/src/firebase/firestore/model/database_id.cc
@@ -16,7 +16,7 @@
#include "Firestore/core/src/firebase/firestore/model/database_id.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -27,8 +27,8 @@ constexpr const char* DatabaseId::kDefault;
DatabaseId::DatabaseId(const absl::string_view project_id,
const absl::string_view database_id)
: project_id_(project_id), database_id_(database_id) {
- FIREBASE_ASSERT(!project_id.empty());
- FIREBASE_ASSERT(!database_id.empty());
+ HARD_ASSERT(!project_id.empty());
+ HARD_ASSERT(!database_id.empty());
}
} // namespace model
diff --git a/Firestore/core/src/firebase/firestore/model/document.cc b/Firestore/core/src/firebase/firestore/model/document.cc
index ae59d15..7adf684 100644
--- a/Firestore/core/src/firebase/firestore/model/document.cc
+++ b/Firestore/core/src/firebase/firestore/model/document.cc
@@ -18,7 +18,7 @@
#include <utility>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -32,7 +32,7 @@ Document::Document(FieldValue&& data,
data_(std::move(data)),
has_local_mutations_(has_local_mutations) {
set_type(Type::Document);
- FIREBASE_ASSERT(FieldValue::Type::Object == data.type());
+ HARD_ASSERT(FieldValue::Type::Object == data.type());
}
bool Document::Equals(const MaybeDocument& other) const {
diff --git a/Firestore/core/src/firebase/firestore/model/document_key.cc b/Firestore/core/src/firebase/firestore/model/document_key.cc
index ddda4c9..7dae412 100644
--- a/Firestore/core/src/firebase/firestore/model/document_key.cc
+++ b/Firestore/core/src/firebase/firestore/model/document_key.cc
@@ -18,7 +18,7 @@
#include <utility>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -27,9 +27,8 @@ namespace model {
namespace {
void AssertValidPath(const ResourcePath& path) {
- FIREBASE_ASSERT_MESSAGE(DocumentKey::IsDocumentKey(path),
- "invalid document key path: %s",
- path.CanonicalString().c_str());
+ HARD_ASSERT(DocumentKey::IsDocumentKey(path), "invalid document key path: %s",
+ path.CanonicalString());
}
} // namespace
diff --git a/Firestore/core/src/firebase/firestore/model/field_path.cc b/Firestore/core/src/firebase/firestore/model/field_path.cc
index bc0e97c..5636b53 100644
--- a/Firestore/core/src/firebase/firestore/model/field_path.cc
+++ b/Firestore/core/src/firebase/firestore/model/field_path.cc
@@ -19,7 +19,7 @@
#include <algorithm>
#include <utility>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
@@ -71,18 +71,11 @@ FieldPath FieldPath::FromServerFormat(const absl::string_view path) {
std::string segment;
segment.reserve(path.size());
- // string_view doesn't have a c_str() method, because it might not be
- // null-terminated. Assertions expect C strings, so construct std::string on
- // the fly, so that c_str() might be called on it.
- const auto to_string = [](const absl::string_view view) {
- return std::string{view.data(), view.data() + view.size()};
- };
- const auto finish_segment = [&segments, &segment, &path, &to_string] {
- FIREBASE_ASSERT_MESSAGE(
- !segment.empty(),
- "Invalid field path (%s). Paths must not be empty, begin with "
- "'.', end with '.', or contain '..'",
- to_string(path).c_str());
+ const auto finish_segment = [&segments, &segment, &path] {
+ HARD_ASSERT(!segment.empty(),
+ "Invalid field path (%s). Paths must not be empty, begin with "
+ "'.', end with '.', or contain '..'",
+ path);
// Move operation will clear segment, but capacity will remain the same
// (not, strictly speaking, required by the standard, but true in practice).
segments.push_back(std::move(segment));
@@ -116,9 +109,8 @@ FieldPath FieldPath::FromServerFormat(const absl::string_view path) {
case '\\':
// TODO(b/37244157): Make this a user-facing exception once we
// finalize field escaping.
- FIREBASE_ASSERT_MESSAGE(i + 1 != path.size(),
- "Trailing escape characters not allowed in %s",
- to_string(path).c_str());
+ HARD_ASSERT(i + 1 != path.size(),
+ "Trailing escape characters not allowed in %s", path);
++i;
segment += path[i];
break;
@@ -131,8 +123,7 @@ FieldPath FieldPath::FromServerFormat(const absl::string_view path) {
}
finish_segment();
- FIREBASE_ASSERT_MESSAGE(!inside_backticks, "Unterminated ` in path %s",
- to_string(path).c_str());
+ HARD_ASSERT(!inside_backticks, "Unterminated ` in path %s", path);
return FieldPath{std::move(segments)};
}
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.cc b/Firestore/core/src/firebase/firestore/model/field_value.cc
index 35253c8..4f92c8b 100644
--- a/Firestore/core/src/firebase/firestore/model/field_value.cc
+++ b/Firestore/core/src/firebase/firestore/model/field_value.cc
@@ -23,7 +23,7 @@
#include <vector>
#include "Firestore/core/src/firebase/firestore/util/comparison.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
using firebase::firestore::util::Comparator;
@@ -130,8 +130,7 @@ FieldValue& FieldValue::operator=(const FieldValue& value) {
break;
}
default:
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
- false, lhs.type(), "Unsupported type %d", value.type());
+ HARD_FAIL("Unsupported type %s", value.type());
}
return *this;
}
@@ -168,10 +167,10 @@ FieldValue& FieldValue::operator=(FieldValue&& value) {
FieldValue FieldValue::Set(const FieldPath& field_path,
FieldValue value) const {
- FIREBASE_ASSERT_MESSAGE(type() == Type::Object,
- "Cannot set field for non-object FieldValue");
- FIREBASE_ASSERT_MESSAGE(!field_path.empty(),
- "Cannot set field for empty path on FieldValue");
+ HARD_ASSERT(type() == Type::Object,
+ "Cannot set field for non-object FieldValue");
+ HARD_ASSERT(!field_path.empty(),
+ "Cannot set field for empty path on FieldValue");
// Set the value by recursively calling on child object.
const std::string& child_name = field_path.first_segment();
const ObjectValue::Map& object_map = object_value_.internal_value;
@@ -195,10 +194,10 @@ FieldValue FieldValue::Set(const FieldPath& field_path,
}
FieldValue FieldValue::Delete(const FieldPath& field_path) const {
- FIREBASE_ASSERT_MESSAGE(type() == Type::Object,
- "Cannot delete field for non-object FieldValue");
- FIREBASE_ASSERT_MESSAGE(!field_path.empty(),
- "Cannot delete field for empty path on FieldValue");
+ HARD_ASSERT(type() == Type::Object,
+ "Cannot delete field for non-object FieldValue");
+ HARD_ASSERT(!field_path.empty(),
+ "Cannot delete field for empty path on FieldValue");
// Delete the value by recursively calling on child object.
const std::string& child_name = field_path.first_segment();
const ObjectValue::Map& object_map = object_value_.internal_value;
@@ -223,8 +222,8 @@ FieldValue FieldValue::Delete(const FieldPath& field_path) const {
}
absl::optional<FieldValue> FieldValue::Get(const FieldPath& field_path) const {
- FIREBASE_ASSERT_MESSAGE(type() == Type::Object,
- "Cannot get field for non-object FieldValue");
+ HARD_ASSERT(type() == Type::Object,
+ "Cannot get field for non-object FieldValue");
const FieldValue* current = this;
for (const auto& path : field_path) {
if (current->type() != Type::Object) {
@@ -435,8 +434,7 @@ bool operator<(const FieldValue& lhs, const FieldValue& rhs) {
case Type::Object:
return lhs.object_value_ < rhs.object_value_;
default:
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
- false, lhs.type(), "Unsupported type %d", lhs.type());
+ HARD_FAIL("Unsupported type %s", lhs.type());
// return false if assertion does not abort the program. We will say
// each unsupported type takes only one value thus everything is equal.
return false;
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.h b/Firestore/core/src/firebase/firestore/model/field_value.h
index 0f7dfc4..09c8531 100644
--- a/Firestore/core/src/firebase/firestore/model/field_value.h
+++ b/Firestore/core/src/firebase/firestore/model/field_value.h
@@ -28,7 +28,7 @@
#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/model/field_path.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/types/optional.h"
namespace firebase {
@@ -109,27 +109,27 @@ class FieldValue {
}
bool boolean_value() const {
- FIREBASE_ASSERT(tag_ == Type::Boolean);
+ HARD_ASSERT(tag_ == Type::Boolean);
return boolean_value_;
}
int64_t integer_value() const {
- FIREBASE_ASSERT(tag_ == Type::Integer);
+ HARD_ASSERT(tag_ == Type::Integer);
return integer_value_;
}
Timestamp timestamp_value() const {
- FIREBASE_ASSERT(tag_ == Type::Timestamp);
+ HARD_ASSERT(tag_ == Type::Timestamp);
return timestamp_value_;
}
const std::string& string_value() const {
- FIREBASE_ASSERT(tag_ == Type::String);
+ HARD_ASSERT(tag_ == Type::String);
return string_value_;
}
ObjectValue object_value() const {
- FIREBASE_ASSERT(tag_ == Type::Object);
+ HARD_ASSERT(tag_ == Type::Object);
return ObjectValue{object_value_};
}
diff --git a/Firestore/core/src/firebase/firestore/model/maybe_document.cc b/Firestore/core/src/firebase/firestore/model/maybe_document.cc
index 4f3be1d..aa5e15a 100644
--- a/Firestore/core/src/firebase/firestore/model/maybe_document.cc
+++ b/Firestore/core/src/firebase/firestore/model/maybe_document.cc
@@ -18,8 +18,6 @@
#include <utility>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
-
namespace firebase {
namespace firestore {
namespace model {
diff --git a/Firestore/core/src/firebase/firestore/model/precondition.cc b/Firestore/core/src/firebase/firestore/model/precondition.cc
index 423d5a2..179b313 100644
--- a/Firestore/core/src/firebase/firestore/model/precondition.cc
+++ b/Firestore/core/src/firebase/firestore/model/precondition.cc
@@ -18,7 +18,7 @@
#include "Firestore/core/src/firebase/firestore/model/maybe_document.h"
#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -59,7 +59,7 @@ bool Precondition::IsValidFor(const MaybeDocument& maybe_doc) const {
case Type::None:
return true;
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
} // namespace model
diff --git a/Firestore/core/src/firebase/firestore/model/precondition.h b/Firestore/core/src/firebase/firestore/model/precondition.h
index b98bb45..b015100 100644
--- a/Firestore/core/src/firebase/firestore/model/precondition.h
+++ b/Firestore/core/src/firebase/firestore/model/precondition.h
@@ -27,7 +27,7 @@
#include "Firestore/core/src/firebase/firestore/model/maybe_document.h"
#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -104,7 +104,7 @@ class Precondition {
case Type::None:
return true;
}
- FIREBASE_UNREACHABLE();
+ UNREACHABLE();
}
// For Objective-C++ hash; to be removed after migration.
@@ -131,10 +131,7 @@ class Precondition {
stringWithFormat:@"<Precondition update_time=%s>",
update_time_.timestamp().ToString().c_str()];
}
- // We only raise dev assertion here. This function is mainly used in
- // logging.
- FIREBASE_DEV_ASSERT_MESSAGE(false, "precondition invalid");
- return @"<Precondition invalid>";
+ UNREACHABLE();
}
#endif // defined(__OBJC__)
diff --git a/Firestore/core/src/firebase/firestore/model/resource_path.cc b/Firestore/core/src/firebase/firestore/model/resource_path.cc
index c95aa63..cdd795f 100644
--- a/Firestore/core/src/firebase/firestore/model/resource_path.cc
+++ b/Firestore/core/src/firebase/firestore/model/resource_path.cc
@@ -20,7 +20,7 @@
#include <utility>
#include <vector>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
@@ -33,10 +33,8 @@ ResourcePath ResourcePath::FromString(const absl::string_view path) {
// sequences (e.g. __id123__) and just passes them through raw (they exist
// for legacy reasons and should not be used frequently).
- FIREBASE_ASSERT_MESSAGE(
- path.find("//") == std::string::npos,
- "Invalid path (%s). Paths must not contain // in them.",
- std::string{path.data(), path.data() + path.size()}.c_str());
+ HARD_ASSERT(path.find("//") == std::string::npos,
+ "Invalid path (%s). Paths must not contain // in them.", path);
// SkipEmpty because we may still have an empty segment at the beginning or
// end if they had a leading or trailing slash (which we allow).
diff --git a/Firestore/core/src/firebase/firestore/model/snapshot_version.h b/Firestore/core/src/firebase/firestore/model/snapshot_version.h
index 7ce0985..dbecea1 100644
--- a/Firestore/core/src/firebase/firestore/model/snapshot_version.h
+++ b/Firestore/core/src/firebase/firestore/model/snapshot_version.h
@@ -19,11 +19,6 @@
#include "Firestore/core/include/firebase/firestore/timestamp.h"
-#if defined(__OBJC__)
-#import "FIRTimestamp.h"
-#import "Firestore/Source/Core/FSTSnapshotVersion.h"
-#endif // defined(__OBJC__)
-
namespace firebase {
namespace firestore {
namespace model {
@@ -34,6 +29,11 @@ namespace model {
*/
class SnapshotVersion {
public:
+#if __OBJC__
+ SnapshotVersion() {
+ }
+#endif // __OBJC__
+
explicit SnapshotVersion(const Timestamp& timestamp);
const Timestamp& timestamp() const {
@@ -43,26 +43,11 @@ class SnapshotVersion {
/** Creates a new version that is smaller than all other versions. */
static const SnapshotVersion& None();
-#if defined(__OBJC__)
- SnapshotVersion() {
- }
-
- SnapshotVersion(FSTSnapshotVersion* version) // NOLINT(runtime/explicit)
- : timestamp_{version.timestamp.seconds, version.timestamp.nanoseconds} {
- }
-
- operator FSTSnapshotVersion*() const {
- if (timestamp_ == Timestamp{}) {
- return [FSTSnapshotVersion noVersion];
- } else {
- return [FSTSnapshotVersion
- versionWithTimestamp:[FIRTimestamp
- timestampWithSeconds:timestamp_.seconds()
- nanoseconds:timestamp_
- .nanoseconds()]];
- }
+#if __OBJC__
+ size_t Hash() const {
+ return std::hash<Timestamp>{}(timestamp_);
}
-#endif // defined(__OBJC__)
+#endif // __OBJC__
private:
Timestamp timestamp_;
diff --git a/Firestore/core/src/firebase/firestore/model/transform_operations.h b/Firestore/core/src/firebase/firestore/model/transform_operations.h
index abc8d1b..a5c5f82 100644
--- a/Firestore/core/src/firebase/firestore/model/transform_operations.h
+++ b/Firestore/core/src/firebase/firestore/model/transform_operations.h
@@ -17,14 +17,16 @@
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATIONS_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATIONS_H_
+#if !defined(__OBJC__)
+#error "This header only supports Objective-C++."
+#endif // !defined(__OBJC__)
+
#include <utility>
#include <vector>
-#include "Firestore/core/include/firebase/firestore/timestamp.h"
-
-#if defined(__OBJC__)
#import "Firestore/Source/Model/FSTFieldValue.h"
-#endif
+
+#include "Firestore/core/include/firebase/firestore/timestamp.h"
namespace firebase {
namespace firestore {
@@ -51,36 +53,31 @@ class TransformOperation {
/** Returns the actual type. */
virtual Type type() const = 0;
-// TODO(mikelehen): apply methods require FSTFieldValue which is Obj-C only.
-#if defined(__OBJC__)
/**
* Computes the local transform result against the provided `previousValue`,
* optionally using the provided localWriteTime.
*/
- virtual FSTFieldValue *applyToLocalView(
- FSTFieldValue *previousValue, FIRTimestamp *localWriteTime) const = 0;
+ virtual FSTFieldValue* ApplyToLocalView(
+ FSTFieldValue* previousValue, FIRTimestamp* localWriteTime) const = 0;
/**
* Computes a final transform result after the transform has been acknowledged
* by the server, potentially using the server-provided transformResult.
*/
- virtual FSTFieldValue *applyToRemoteDocument(
- FSTFieldValue *previousValue, FSTFieldValue *transformResult) const = 0;
-#endif
+ virtual FSTFieldValue* ApplyToRemoteDocument(
+ FSTFieldValue* previousValue, FSTFieldValue* transformResult) const = 0;
/** Returns whether the two are equal. */
- virtual bool operator==(const TransformOperation &other) const = 0;
+ virtual bool operator==(const TransformOperation& other) const = 0;
/** Returns whether the two are not equal. */
- bool operator!=(const TransformOperation &other) const {
+ bool operator!=(const TransformOperation& other) const {
return !operator==(other);
}
-#if defined(__OBJC__)
// For Objective-C++ hash; to be removed after migration.
// Do NOT use in C++ code.
virtual NSUInteger Hash() const = 0;
-#endif // defined(__OBJC__)
};
/** Transforms a value into a server-generated timestamp. */
@@ -93,33 +90,29 @@ class ServerTimestampTransform : public TransformOperation {
return Type::ServerTimestamp;
}
-// TODO(mikelehen): apply methods require FSTFieldValue which is Obj-C only.
-#if defined(__OBJC__)
- FSTFieldValue *applyToLocalView(FSTFieldValue *previousValue,
- FIRTimestamp *localWriteTime) const override {
+ FSTFieldValue* ApplyToLocalView(FSTFieldValue* previousValue,
+ FIRTimestamp* localWriteTime) const override {
return [FSTServerTimestampValue
serverTimestampValueWithLocalWriteTime:localWriteTime
previousValue:previousValue];
}
- FSTFieldValue *applyToRemoteDocument(
- FSTFieldValue *previousValue,
- FSTFieldValue *transformResult) const override {
+ FSTFieldValue* ApplyToRemoteDocument(
+ FSTFieldValue* /* previousValue */,
+ FSTFieldValue* transformResult) const override {
return transformResult;
}
-#endif
- bool operator==(const TransformOperation &other) const override {
+ bool operator==(const TransformOperation& other) const override {
// All ServerTimestampTransform objects are equal.
return other.type() == Type::ServerTimestamp;
}
- static const ServerTimestampTransform &Get() {
+ static const ServerTimestampTransform& Get() {
static ServerTimestampTransform shared_instance;
return shared_instance;
}
-#if defined(__OBJC__)
// For Objective-C++ hash; to be removed after migration.
// Do NOT use in C++ code.
NSUInteger Hash() const override {
@@ -127,24 +120,19 @@ class ServerTimestampTransform : public TransformOperation {
// instances are equal.
return 37;
}
-#endif // defined(__OBJC__)
private:
ServerTimestampTransform() {
}
};
-// TODO(mikelehen): ArrayTransform can only be used from Obj-C until we switch
-// to using FieldValue instead of FSTFieldValue.
-#if defined(__OBJC__)
-
/**
* Transforms an array via a union or remove operation (for convenience, we use
* this class for both Type::ArrayUnion and Type::ArrayRemove).
*/
class ArrayTransform : public TransformOperation {
public:
- ArrayTransform(Type type, std::vector<FSTFieldValue *> elements)
+ ArrayTransform(Type type, std::vector<FSTFieldValue*> elements)
: type_(type), elements_(std::move(elements)) {
}
@@ -155,33 +143,34 @@ class ArrayTransform : public TransformOperation {
return type_;
}
- FSTFieldValue *applyToLocalView(FSTFieldValue *previousValue,
- FIRTimestamp *localWriteTime) const override {
- return apply(previousValue);
+ FSTFieldValue* ApplyToLocalView(
+ FSTFieldValue* previousValue,
+ FIRTimestamp* /* localWriteTime */) const override {
+ return Apply(previousValue);
}
- FSTFieldValue *applyToRemoteDocument(
- FSTFieldValue *previousValue,
- FSTFieldValue *transformResult) const override {
+ FSTFieldValue* ApplyToRemoteDocument(
+ FSTFieldValue* previousValue,
+ FSTFieldValue* /* transformResult */) const override {
// The server just sends null as the transform result for array operations,
// so we have to calculate a result the same as we do for local
// applications.
- return apply(previousValue);
+ return Apply(previousValue);
}
- const std::vector<FSTFieldValue *> &elements() const {
+ const std::vector<FSTFieldValue*>& elements() const {
return elements_;
}
- bool operator==(const TransformOperation &other) const override {
+ bool operator==(const TransformOperation& other) const override {
if (other.type() != type()) {
return false;
}
- auto array_transform = static_cast<const ArrayTransform &>(other);
+ auto array_transform = static_cast<const ArrayTransform&>(other);
if (array_transform.elements_.size() != elements_.size()) {
return false;
}
- for (int i = 0; i < elements_.size(); i++) {
+ for (size_t i = 0; i < elements_.size(); i++) {
if (![array_transform.elements_[i] isEqual:elements_[i]]) {
return false;
}
@@ -189,64 +178,60 @@ class ArrayTransform : public TransformOperation {
return true;
}
-#if defined(__OBJC__)
// For Objective-C++ hash; to be removed after migration.
// Do NOT use in C++ code.
NSUInteger Hash() const override {
NSUInteger result = 37;
result = 31 * result + (type() == Type::ArrayUnion ? 1231 : 1237);
- for (FSTFieldValue *element : elements_) {
+ for (FSTFieldValue* element : elements_) {
result = 31 * result + [element hash];
}
return result;
}
-#endif // defined(__OBJC__)
- static const std::vector<FSTFieldValue *> &Elements(
- const TransformOperation &op) {
- FIREBASE_ASSERT(op.type() == Type::ArrayUnion ||
- op.type() == Type::ArrayRemove);
- return static_cast<const ArrayTransform &>(op).elements();
+ static const std::vector<FSTFieldValue*>& Elements(
+ const TransformOperation& op) {
+ HARD_ASSERT(op.type() == Type::ArrayUnion ||
+ op.type() == Type::ArrayRemove);
+ return static_cast<const ArrayTransform&>(op).elements();
}
private:
Type type_;
- std::vector<FSTFieldValue *> elements_;
+ std::vector<FSTFieldValue*> elements_;
/**
* Inspects the provided value, returning a mutable copy of the internal array
* if it's an FSTArrayValue and an empty mutable array if it's nil or any
* other type of FSTFieldValue.
*/
- static NSMutableArray<FSTFieldValue *> *CoercedFieldValuesArray(
- FSTFieldValue *value) {
+ static NSMutableArray<FSTFieldValue*>* CoercedFieldValuesArray(
+ FSTFieldValue* value) {
if ([value isMemberOfClass:[FSTArrayValue class]]) {
return [NSMutableArray
- arrayWithArray:reinterpret_cast<FSTArrayValue *>(value)
- .internalValue];
+ arrayWithArray:reinterpret_cast<FSTArrayValue*>(value).internalValue];
} else {
// coerce to empty array.
return [NSMutableArray array];
}
}
- FSTFieldValue *apply(FSTFieldValue *previousValue) const {
- NSMutableArray<FSTFieldValue *> *result =
+ FSTFieldValue* Apply(FSTFieldValue* previousValue) const {
+ NSMutableArray<FSTFieldValue*>* result =
ArrayTransform::CoercedFieldValuesArray(previousValue);
- for (FSTFieldValue *element : elements_) {
+ for (FSTFieldValue* element : elements_) {
if (type_ == Type::ArrayUnion) {
if (![result containsObject:element]) {
[result addObject:element];
}
} else {
- FIREBASE_ASSERT(type_ == Type::ArrayRemove);
+ HARD_ASSERT(type_ == Type::ArrayRemove);
[result removeObject:element];
}
}
return [[FSTArrayValue alloc] initWithValueNoCopy:result];
}
};
-#endif
} // namespace model
} // namespace firestore
diff --git a/Firestore/core/src/firebase/firestore/nanopb/CMakeLists.txt b/Firestore/core/src/firebase/firestore/nanopb/CMakeLists.txt
new file mode 100644
index 0000000..82ffb65
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/nanopb/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright 2018 Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+cc_library(
+ firebase_firestore_nanopb
+ SOURCES
+ tag.h
+ reader.h
+ reader.cc
+ writer.h
+ writer.cc
+ DEPENDS
+ firebase_firestore_util
+ firebase_firestore_protos_nanopb
+ nanopb
+)
diff --git a/Firestore/core/src/firebase/firestore/nanopb/reader.cc b/Firestore/core/src/firebase/firestore/nanopb/reader.cc
new file mode 100644
index 0000000..7a12900
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/nanopb/reader.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/src/firebase/firestore/nanopb/reader.h"
+
+#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h"
+
+namespace firebase {
+namespace firestore {
+namespace nanopb {
+
+using firebase::firestore::util::Status;
+using std::int64_t;
+using std::uint64_t;
+
+Reader Reader::Wrap(const uint8_t* bytes, size_t length) {
+ return Reader{pb_istream_from_buffer(bytes, length)};
+}
+
+Tag Reader::ReadTag() {
+ Tag tag;
+ if (!status_.ok()) return tag;
+
+ bool eof;
+ if (!pb_decode_tag(&stream_, &tag.wire_type, &tag.field_number, &eof)) {
+ status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
+ return tag;
+ }
+
+ // nanopb code always returns a false status when setting eof.
+ HARD_ASSERT(!eof, "nanopb set both ok status and eof to true");
+
+ return tag;
+}
+
+void Reader::ReadNanopbMessage(const pb_field_t fields[], void* dest_struct) {
+ if (!status_.ok()) return;
+
+ if (!pb_decode(&stream_, fields, dest_struct)) {
+ status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
+ }
+}
+
+/**
+ * Note that (despite the return type) this works for bool, enum, int32, int64,
+ * uint32 and uint64 proto field types.
+ *
+ * Note: This is not expected to be called directly, but rather only via the
+ * other Decode* methods (i.e. DecodeBool, DecodeLong, etc)
+ *
+ * @return The decoded varint as a uint64_t.
+ */
+uint64_t Reader::ReadVarint() {
+ if (!status_.ok()) return 0;
+
+ uint64_t varint_value = 0;
+ if (!pb_decode_varint(&stream_, &varint_value)) {
+ status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
+ }
+ return varint_value;
+}
+
+void Reader::ReadNull() {
+ uint64_t varint = ReadVarint();
+ if (!status_.ok()) return;
+
+ if (varint != google_protobuf_NullValue_NULL_VALUE) {
+ status_ = Status(FirestoreErrorCode::DataLoss,
+ "Input proto bytes cannot be parsed (invalid null value)");
+ }
+}
+
+bool Reader::ReadBool() {
+ uint64_t varint = ReadVarint();
+ if (!status_.ok()) return false;
+
+ switch (varint) {
+ case 0:
+ return false;
+ case 1:
+ return true;
+ default:
+ status_ =
+ Status(FirestoreErrorCode::DataLoss,
+ "Input proto bytes cannot be parsed (invalid bool value)");
+ return false;
+ }
+}
+
+int64_t Reader::ReadInteger() {
+ return ReadVarint();
+}
+
+std::string Reader::ReadString() {
+ if (!status_.ok()) return "";
+
+ pb_istream_t substream;
+ if (!pb_make_string_substream(&stream_, &substream)) {
+ status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
+ pb_close_string_substream(&stream_, &substream);
+ return "";
+ }
+
+ std::string result(substream.bytes_left, '\0');
+ if (!pb_read(&substream, reinterpret_cast<pb_byte_t*>(&result[0]),
+ substream.bytes_left)) {
+ status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
+ pb_close_string_substream(&stream_, &substream);
+ return "";
+ }
+
+ // NB: future versions of nanopb read the remaining characters out of the
+ // substream (and return false if that fails) as an additional safety
+ // check within pb_close_string_substream. Unfortunately, that's not present
+ // in the current version (0.38). We'll make a stronger assertion and check
+ // to make sure there *are* no remaining characters in the substream.
+ HARD_ASSERT(
+ substream.bytes_left == 0,
+ "Bytes remaining in substream after supposedly reading all of them.");
+
+ pb_close_string_substream(&stream_, &substream);
+
+ return result;
+}
+
+} // namespace nanopb
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/nanopb/reader.h b/Firestore/core/src/firebase/firestore/nanopb/reader.h
new file mode 100644
index 0000000..930211a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/nanopb/reader.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_READER_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_READER_H_
+
+#include <pb.h>
+#include <pb_decode.h>
+
+#include <cstdint>
+#include <functional>
+#include <string>
+
+#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
+#include "Firestore/core/src/firebase/firestore/nanopb/tag.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+
+namespace firebase {
+namespace firestore {
+namespace nanopb {
+
+/**
+ * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb
+ * pb_istream_t.
+ */
+class Reader {
+ public:
+ /**
+ * Creates an input stream that reads from the specified bytes. Note that
+ * this reference must remain valid for the lifetime of this Reader.
+ *
+ * (This is roughly equivalent to the nanopb function
+ * pb_istream_from_buffer())
+ *
+ * @param bytes where the input should be deserialized from.
+ */
+ static Reader Wrap(const uint8_t* bytes, size_t length);
+
+ /**
+ * Reads a message type from the input stream.
+ *
+ * This essentially wraps calls to nanopb's pb_decode_tag() method.
+ */
+ Tag ReadTag();
+
+ /**
+ * Reads a nanopb message from the input stream.
+ *
+ * This essentially wraps calls to nanopb's pb_decode() method. If we didn't
+ * use `oneof`s in our protos, this would be the primary way of decoding
+ * messages.
+ */
+ void ReadNanopbMessage(const pb_field_t fields[], void* dest_struct);
+
+ void ReadNull();
+ bool ReadBool();
+ std::int64_t ReadInteger();
+
+ std::string ReadString();
+
+ /**
+ * Reads a message and its length.
+ *
+ * Analog to Writer::WriteNestedMessage(). See that methods docs for further
+ * details.
+ *
+ * Call this method when reading a nested message. Provide a function to read
+ * the message itself.
+ *
+ * @param read_message_fn Function to read the submessage. Note that this
+ * function is expected to check the Reader's status (via
+ * Reader::status().ok()) and if not ok, to return a placeholder/invalid
+ * value.
+ */
+ template <typename T>
+ T ReadNestedMessage(const std::function<T(Reader*)>& read_message_fn);
+
+ size_t bytes_left() const {
+ return stream_.bytes_left;
+ }
+
+ util::Status status() const {
+ return status_;
+ }
+
+ void set_status(util::Status status) {
+ status_ = status;
+ }
+
+ private:
+ /**
+ * Creates a new Reader, based on the given nanopb pb_istream_t. Note that
+ * a shallow copy will be taken. (Non-null pointers within this struct must
+ * remain valid for the lifetime of this Reader.)
+ */
+ explicit Reader(pb_istream_t stream) : stream_(stream) {
+ }
+
+ /**
+ * Reads a "varint" from the input stream.
+ *
+ * This essentially wraps calls to nanopb's pb_decode_varint() method.
+ *
+ * Note that (despite the return type) this works for bool, enum, int32,
+ * int64, uint32 and uint64 proto field types.
+ *
+ * Note: This is not expected to be called direclty, but rather only via the
+ * other Decode* methods (i.e. DecodeBool, DecodeLong, etc)
+ *
+ * @return The decoded varint as a uint64_t.
+ */
+ std::uint64_t ReadVarint();
+
+ util::Status status_ = util::Status::OK();
+
+ pb_istream_t stream_;
+};
+
+template <typename T>
+T Reader::ReadNestedMessage(const std::function<T(Reader*)>& read_message_fn) {
+ // Implementation note: This is roughly modeled on pb_decode_delimited,
+ // adjusted to account for the oneof in FieldValue.
+
+ if (!status_.ok()) return read_message_fn(this);
+
+ pb_istream_t raw_substream;
+ if (!pb_make_string_substream(&stream_, &raw_substream)) {
+ status_ =
+ util::Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
+ pb_close_string_substream(&stream_, &raw_substream);
+ return read_message_fn(this);
+ }
+ Reader substream(raw_substream);
+
+ // If this fails, we *won't* return right away so that we can cleanup the
+ // substream (although technically, that turns out not to matter; no resource
+ // leaks occur if we don't do this.)
+ // TODO(rsgowman): Consider RAII here. (Watch out for Reader class which also
+ // wraps streams.)
+ T message = read_message_fn(&substream);
+ status_ = substream.status();
+
+ // NB: future versions of nanopb read the remaining characters out of the
+ // substream (and return false if that fails) as an additional safety
+ // check within pb_close_string_substream. Unfortunately, that's not present
+ // in the current version (0.38). We'll make a stronger assertion and check
+ // to make sure there *are* no remaining characters in the substream.
+ HARD_ASSERT(
+ substream.bytes_left() == 0,
+ "Bytes remaining in substream after supposedly reading all of them.");
+
+ pb_close_string_substream(&stream_, &substream.stream_);
+
+ return message;
+}
+
+} // namespace nanopb
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_READER_H_
diff --git a/Firestore/core/src/firebase/firestore/nanopb/tag.h b/Firestore/core/src/firebase/firestore/nanopb/tag.h
new file mode 100644
index 0000000..455ef0c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/nanopb/tag.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_TAG_H__
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_TAG_H__
+
+#include <pb.h>
+
+namespace firebase {
+namespace firestore {
+namespace nanopb {
+
+/**
+ * Represents a nanopb tag.
+ *
+ * field_number is one of the field tags that nanopb generates based off of
+ * the proto messages. They're typically named in the format:
+ * <parentNameSpace>_<childNameSpace>_<message>_<field>_tag, e.g.
+ * google_firestore_v1beta1_Document_name_tag.
+ */
+struct Tag {
+ pb_wire_type_t wire_type;
+ uint32_t field_number;
+};
+
+} // namespace nanopb
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_TAG_H_
diff --git a/Firestore/core/src/firebase/firestore/nanopb/writer.cc b/Firestore/core/src/firebase/firestore/nanopb/writer.cc
new file mode 100644
index 0000000..c3ffaac
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/nanopb/writer.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/src/firebase/firestore/nanopb/writer.h"
+
+#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h"
+
+namespace firebase {
+namespace firestore {
+namespace nanopb {
+
+using firebase::firestore::util::Status;
+using std::int64_t;
+using std::int8_t;
+using std::uint64_t;
+
+Writer Writer::Wrap(std::vector<uint8_t>* out_bytes) {
+ // TODO(rsgowman): find a better home for this constant.
+ // A document is defined to have a max size of 1MiB - 4 bytes.
+ static const size_t kMaxDocumentSize = 1 * 1024 * 1024 - 4;
+
+ // Construct a nanopb output stream.
+ //
+ // Set the max_size to be the max document size (as an upper bound; one would
+ // expect individual FieldValue's to be smaller than this).
+ //
+ // bytes_written is (always) initialized to 0. (NB: nanopb does not know or
+ // care about the underlying output vector, so where we are in the vector
+ // itself is irrelevant. i.e. don't use out_bytes->size())
+ pb_ostream_t raw_stream = {
+ /*callback=*/[](pb_ostream_t* stream, const pb_byte_t* buf,
+ size_t count) -> bool {
+ auto* out_bytes = static_cast<std::vector<uint8_t>*>(stream->state);
+ out_bytes->insert(out_bytes->end(), buf, buf + count);
+ return true;
+ },
+ /*state=*/out_bytes,
+ /*max_size=*/kMaxDocumentSize,
+ /*bytes_written=*/0,
+ /*errmsg=*/nullptr};
+ return Writer(raw_stream);
+}
+
+void Writer::WriteTag(Tag tag) {
+ if (!status_.ok()) return;
+
+ if (!pb_encode_tag(&stream_, tag.wire_type, tag.field_number)) {
+ HARD_FAIL(PB_GET_ERROR(&stream_));
+ }
+}
+
+void Writer::WriteNanopbMessage(const pb_field_t fields[],
+ const void* src_struct) {
+ if (!status_.ok()) return;
+
+ if (!pb_encode(&stream_, fields, src_struct)) {
+ HARD_FAIL(PB_GET_ERROR(&stream_));
+ }
+}
+
+void Writer::WriteSize(size_t size) {
+ return WriteVarint(size);
+}
+
+void Writer::WriteVarint(uint64_t value) {
+ if (!status_.ok()) return;
+
+ if (!pb_encode_varint(&stream_, value)) {
+ HARD_FAIL(PB_GET_ERROR(&stream_));
+ }
+}
+
+void Writer::WriteNull() {
+ return WriteVarint(google_protobuf_NullValue_NULL_VALUE);
+}
+
+void Writer::WriteBool(bool bool_value) {
+ return WriteVarint(bool_value);
+}
+
+void Writer::WriteInteger(int64_t integer_value) {
+ return WriteVarint(integer_value);
+}
+
+void Writer::WriteString(const std::string& string_value) {
+ if (!status_.ok()) return;
+
+ if (!pb_encode_string(
+ &stream_, reinterpret_cast<const pb_byte_t*>(string_value.c_str()),
+ string_value.length())) {
+ HARD_FAIL(PB_GET_ERROR(&stream_));
+ }
+}
+
+void Writer::WriteNestedMessage(
+ const std::function<void(Writer*)>& write_message_fn) {
+ if (!status_.ok()) return;
+
+ // First calculate the message size using a non-writing substream.
+ Writer sizer = Writer::Sizing();
+ write_message_fn(&sizer);
+ status_ = sizer.status();
+ if (!status_.ok()) return;
+ size_t size = sizer.bytes_written();
+
+ // Write out the size to the output writer.
+ WriteSize(size);
+ if (!status_.ok()) return;
+
+ // If this stream is itself a sizing stream, then we don't need to actually
+ // parse field_value a second time; just update the bytes_written via a call
+ // to pb_write. (If we try to write the contents into a sizing stream, it'll
+ // fail since sizing streams don't actually have any buffer space.)
+ if (stream_.callback == nullptr) {
+ if (!pb_write(&stream_, nullptr, size)) {
+ HARD_FAIL(PB_GET_ERROR(&stream_));
+ }
+ return;
+ }
+
+ // Ensure the output stream has enough space
+ if (stream_.bytes_written + size > stream_.max_size) {
+ HARD_FAIL(
+ "Insufficient space in the output stream to write the given message");
+ }
+
+ // Use a substream to verify that a callback doesn't write more than what it
+ // did the first time. (Use an initializer rather than setting fields
+ // individually like nanopb does. This gives us a *chance* of noticing if
+ // nanopb adds new fields.)
+ Writer writer({stream_.callback, stream_.state,
+ /*max_size=*/size, /*bytes_written=*/0,
+ /*errmsg=*/nullptr});
+ write_message_fn(&writer);
+ status_ = writer.status();
+ if (!status_.ok()) return;
+
+ stream_.bytes_written += writer.stream_.bytes_written;
+ stream_.state = writer.stream_.state;
+ stream_.errmsg = writer.stream_.errmsg;
+
+ if (writer.bytes_written() != size) {
+ // submsg size changed
+ HARD_FAIL("Parsing the nested message twice yielded different sizes");
+ }
+}
+
+} // namespace nanopb
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/nanopb/writer.h b/Firestore/core/src/firebase/firestore/nanopb/writer.h
new file mode 100644
index 0000000..e428826
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/nanopb/writer.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_WRITER_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_WRITER_H_
+
+#include <pb.h>
+#include <pb_encode.h>
+
+#include <cstdint>
+#include <functional>
+#include <string>
+#include <vector>
+
+#include "Firestore/core/src/firebase/firestore/nanopb/tag.h"
+#include "Firestore/core/src/firebase/firestore/util/status.h"
+
+namespace firebase {
+namespace firestore {
+namespace nanopb {
+
+/**
+ * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb
+ * pb_ostream_t. Also doc how to check status.
+ */
+class Writer {
+ public:
+ /**
+ * Creates an output stream that writes to the specified vector. Note that
+ * this vector pointer must remain valid for the lifetime of this Writer.
+ *
+ * (This is roughly equivalent to the nanopb function
+ * pb_ostream_from_buffer())
+ *
+ * @param out_bytes where the output should be serialized to.
+ */
+ static Writer Wrap(std::vector<std::uint8_t>* out_bytes);
+
+ /**
+ * Creates a non-writing output stream used to calculate the size of
+ * the serialized output.
+ */
+ static Writer Sizing() {
+ return Writer(PB_OSTREAM_SIZING);
+ }
+
+ /**
+ * Writes a message type to the output stream.
+ *
+ * This essentially wraps calls to nanopb's pb_encode_tag() method.
+ */
+ void WriteTag(Tag tag);
+
+ /**
+ * Writes a nanopb message to the output stream.
+ *
+ * This essentially wraps calls to nanopb's `pb_encode()` method. If we didn't
+ * use `oneof`s in our protos, this would be the primary way of encoding
+ * messages.
+ */
+ void WriteNanopbMessage(const pb_field_t fields[], const void* src_struct);
+
+ void WriteSize(size_t size);
+ void WriteNull();
+ void WriteBool(bool bool_value);
+ void WriteInteger(std::int64_t integer_value);
+
+ void WriteString(const std::string& string_value);
+
+ /**
+ * Writes a message and its length.
+ *
+ * When writing a top level message, protobuf doesn't include the length
+ * (since you can get that already from the length of the binary output.) But
+ * when writing a sub/nested message, you must include the length in the
+ * serialization.
+ *
+ * Call this method when writing a nested message. Provide a function to
+ * write the message itself. This method will calculate the size of the
+ * written message (using the provided function with a non-writing sizing
+ * stream), write out the size (and perform sanity checks), and then serialize
+ * the message by calling the provided function a second time.
+ */
+ void WriteNestedMessage(const std::function<void(Writer*)>& write_message_fn);
+
+ size_t bytes_written() const {
+ return stream_.bytes_written;
+ }
+
+ util::Status status() const {
+ return status_;
+ }
+
+ private:
+ util::Status status_ = util::Status::OK();
+
+ /**
+ * Creates a new Writer, based on the given nanopb pb_ostream_t. Note that
+ * a shallow copy will be taken. (Non-null pointers within this struct must
+ * remain valid for the lifetime of this Writer.)
+ */
+ explicit Writer(const pb_ostream_t& stream) : stream_(stream) {
+ }
+
+ /**
+ * Writes a "varint" to the output stream.
+ *
+ * This essentially wraps calls to nanopb's pb_encode_varint() method.
+ *
+ * Note that (despite the value parameter type) this works for bool, enum,
+ * int32, int64, uint32 and uint64 proto field types.
+ *
+ * Note: This is not expected to be called directly, but rather only
+ * via the other Write* methods (i.e. WriteBool, WriteLong, etc)
+ *
+ * @param value The value to write, represented as a uint64_t.
+ */
+ void WriteVarint(std::uint64_t value);
+
+ pb_ostream_t stream_;
+};
+
+} // namespace nanopb
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_WRITER_H_
diff --git a/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt b/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
index 7f528fb..fc51b37 100644
--- a/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
@@ -21,7 +21,9 @@ cc_library(
serializer.cc
DEPENDS
firebase_firestore_model
+ firebase_firestore_nanopb
firebase_firestore_protos_nanopb
+ firebase_firestore_util
grpc::grpc
nanopb
)
diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.cc b/Firestore/core/src/firebase/firestore/remote/serializer.cc
index 209f2b1..6ea5844 100644
--- a/Firestore/core/src/firebase/firestore/remote/serializer.cc
+++ b/Firestore/core/src/firebase/firestore/remote/serializer.cc
@@ -25,10 +25,19 @@
#include <utility>
#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h"
+#include "Firestore/Protos/nanopb/google/firestore/v1beta1/firestore.pb.h"
+#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
#include "Firestore/core/include/firebase/firestore/timestamp.h"
+#include "Firestore/core/src/firebase/firestore/model/document.h"
+#include "Firestore/core/src/firebase/firestore/model/no_document.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/nanopb/reader.h"
+#include "Firestore/core/src/firebase/firestore/nanopb/tag.h"
+#include "Firestore/core/src/firebase/firestore/nanopb/writer.h"
#include "Firestore/core/src/firebase/firestore/timestamp_internal.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
+#include "absl/memory/memory.h"
namespace firebase {
namespace firestore {
@@ -37,422 +46,30 @@ namespace remote {
using firebase::Timestamp;
using firebase::TimestampInternal;
using firebase::firestore::model::DatabaseId;
+using firebase::firestore::model::Document;
using firebase::firestore::model::DocumentKey;
using firebase::firestore::model::FieldValue;
+using firebase::firestore::model::MaybeDocument;
+using firebase::firestore::model::NoDocument;
using firebase::firestore::model::ObjectValue;
using firebase::firestore::model::ResourcePath;
+using firebase::firestore::model::SnapshotVersion;
+using firebase::firestore::nanopb::Reader;
+using firebase::firestore::nanopb::Tag;
+using firebase::firestore::nanopb::Writer;
using firebase::firestore::util::Status;
using firebase::firestore::util::StatusOr;
namespace {
-class Writer;
+void EncodeMapValue(Writer* writer, const ObjectValue& object_value);
+void EncodeObjectMap(Writer* writer,
+ const ObjectValue::Map& object_value_map,
+ uint32_t map_tag,
+ uint32_t key_tag,
+ uint32_t value_tag);
-class Reader;
-
-void EncodeObject(Writer* writer, const ObjectValue& object_value);
-
-ObjectValue::Map DecodeObject(Reader* reader);
-
-/**
- * Represents a nanopb tag.
- *
- * field_number is one of the field tags that nanopb generates based off of
- * the proto messages. They're typically named in the format:
- * <parentNameSpace>_<childNameSpace>_<message>_<field>_tag, e.g.
- * google_firestore_v1beta1_Document_name_tag.
- */
-struct Tag {
- pb_wire_type_t wire_type;
- uint32_t field_number;
-};
-
-/**
- * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb
- * pb_ostream_t. Also doc how to check status.
- */
-class Writer {
- public:
- /**
- * Creates an output stream that writes to the specified vector. Note that
- * this vector pointer must remain valid for the lifetime of this Writer.
- *
- * (This is roughly equivalent to the nanopb function
- * pb_ostream_from_buffer())
- *
- * @param out_bytes where the output should be serialized to.
- */
- static Writer Wrap(std::vector<uint8_t>* out_bytes);
-
- /**
- * Creates a non-writing output stream used to calculate the size of
- * the serialized output.
- */
- static Writer Sizing() {
- return Writer(PB_OSTREAM_SIZING);
- }
-
- /**
- * Writes a message type to the output stream.
- *
- * This essentially wraps calls to nanopb's pb_encode_tag() method.
- */
- void WriteTag(Tag tag);
-
- /**
- * Writes a nanopb message to the output stream.
- *
- * This essentially wraps calls to nanopb's `pb_encode()` method. If we didn't
- * use `oneof`s in our protos, this would be the primary way of encoding
- * messages.
- */
- void WriteNanopbMessage(const pb_field_t fields[], const void* src_struct);
-
- void WriteSize(size_t size);
- void WriteNull();
- void WriteBool(bool bool_value);
- void WriteInteger(int64_t integer_value);
-
- void WriteString(const std::string& string_value);
-
- /**
- * Writes a message and its length.
- *
- * When writing a top level message, protobuf doesn't include the length
- * (since you can get that already from the length of the binary output.) But
- * when writing a sub/nested message, you must include the length in the
- * serialization.
- *
- * Call this method when writing a nested message. Provide a function to
- * write the message itself. This method will calculate the size of the
- * written message (using the provided function with a non-writing sizing
- * stream), write out the size (and perform sanity checks), and then serialize
- * the message by calling the provided function a second time.
- */
- void WriteNestedMessage(const std::function<void(Writer*)>& write_message_fn);
-
- size_t bytes_written() const {
- return stream_.bytes_written;
- }
-
- Status status() const {
- return status_;
- }
-
- private:
- Status status_ = Status::OK();
-
- /**
- * Creates a new Writer, based on the given nanopb pb_ostream_t. Note that
- * a shallow copy will be taken. (Non-null pointers within this struct must
- * remain valid for the lifetime of this Writer.)
- */
- explicit Writer(const pb_ostream_t& stream) : stream_(stream) {
- }
-
- /**
- * Writes a "varint" to the output stream.
- *
- * This essentially wraps calls to nanopb's pb_encode_varint() method.
- *
- * Note that (despite the value parameter type) this works for bool, enum,
- * int32, int64, uint32 and uint64 proto field types.
- *
- * Note: This is not expected to be called directly, but rather only
- * via the other Write* methods (i.e. WriteBool, WriteLong, etc)
- *
- * @param value The value to write, represented as a uint64_t.
- */
- void WriteVarint(uint64_t value);
-
- pb_ostream_t stream_;
-};
-
-/**
- * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb
- * pb_istream_t.
- */
-class Reader {
- public:
- /**
- * Creates an input stream that reads from the specified bytes. Note that
- * this reference must remain valid for the lifetime of this Reader.
- *
- * (This is roughly equivalent to the nanopb function
- * pb_istream_from_buffer())
- *
- * @param bytes where the input should be deserialized from.
- */
- static Reader Wrap(const uint8_t* bytes, size_t length);
-
- /**
- * Reads a message type from the input stream.
- *
- * This essentially wraps calls to nanopb's pb_decode_tag() method.
- */
- Tag ReadTag();
-
- /**
- * Reads a nanopb message from the input stream.
- *
- * This essentially wraps calls to nanopb's pb_decode() method. If we didn't
- * use `oneof`s in our protos, this would be the primary way of decoding
- * messages.
- */
- void ReadNanopbMessage(const pb_field_t fields[], void* dest_struct);
-
- void ReadNull();
- bool ReadBool();
- int64_t ReadInteger();
-
- std::string ReadString();
-
- /**
- * Reads a message and its length.
- *
- * Analog to Writer::WriteNestedMessage(). See that methods docs for further
- * details.
- *
- * Call this method when reading a nested message. Provide a function to read
- * the message itself.
- */
- template <typename T>
- T ReadNestedMessage(const std::function<T(Reader*)>& read_message_fn);
-
- size_t bytes_left() const {
- return stream_.bytes_left;
- }
-
- Status status() const {
- return status_;
- }
-
- void set_status(Status status) {
- status_ = status;
- }
-
- private:
- /**
- * Creates a new Reader, based on the given nanopb pb_istream_t. Note that
- * a shallow copy will be taken. (Non-null pointers within this struct must
- * remain valid for the lifetime of this Reader.)
- */
- explicit Reader(pb_istream_t stream) : stream_(stream) {
- }
-
- /**
- * Reads a "varint" from the input stream.
- *
- * This essentially wraps calls to nanopb's pb_decode_varint() method.
- *
- * Note that (despite the return type) this works for bool, enum, int32,
- * int64, uint32 and uint64 proto field types.
- *
- * Note: This is not expected to be called direclty, but rather only via the
- * other Decode* methods (i.e. DecodeBool, DecodeLong, etc)
- *
- * @return The decoded varint as a uint64_t.
- */
- uint64_t ReadVarint();
-
- Status status_ = Status::OK();
-
- pb_istream_t stream_;
-};
-
-Writer Writer::Wrap(std::vector<uint8_t>* out_bytes) {
- // TODO(rsgowman): find a better home for this constant.
- // A document is defined to have a max size of 1MiB - 4 bytes.
- static const size_t kMaxDocumentSize = 1 * 1024 * 1024 - 4;
-
- // Construct a nanopb output stream.
- //
- // Set the max_size to be the max document size (as an upper bound; one would
- // expect individual FieldValue's to be smaller than this).
- //
- // bytes_written is (always) initialized to 0. (NB: nanopb does not know or
- // care about the underlying output vector, so where we are in the vector
- // itself is irrelevant. i.e. don't use out_bytes->size())
- pb_ostream_t raw_stream = {
- /*callback=*/[](pb_ostream_t* stream, const pb_byte_t* buf,
- size_t count) -> bool {
- auto* out_bytes = static_cast<std::vector<uint8_t>*>(stream->state);
- out_bytes->insert(out_bytes->end(), buf, buf + count);
- return true;
- },
- /*state=*/out_bytes,
- /*max_size=*/kMaxDocumentSize,
- /*bytes_written=*/0,
- /*errmsg=*/nullptr};
- return Writer(raw_stream);
-}
-
-Reader Reader::Wrap(const uint8_t* bytes, size_t length) {
- return Reader{pb_istream_from_buffer(bytes, length)};
-}
-
-// TODO(rsgowman): I've left the methods as near as possible to where they were
-// before, which implies that the Writer methods are interspersed with the
-// Reader methods. This should make it a bit easier to review. Refactor these to
-// group the related methods together (probably within their own file rather
-// than here).
-
-void Writer::WriteTag(Tag tag) {
- if (!status_.ok()) return;
-
- if (!pb_encode_tag(&stream_, tag.wire_type, tag.field_number)) {
- FIREBASE_ASSERT_MESSAGE(false, PB_GET_ERROR(&stream_));
- }
-}
-
-Tag Reader::ReadTag() {
- Tag tag;
- if (!status_.ok()) return tag;
-
- bool eof;
- if (!pb_decode_tag(&stream_, &tag.wire_type, &tag.field_number, &eof)) {
- status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
- return tag;
- }
-
- // nanopb code always returns a false status when setting eof.
- FIREBASE_ASSERT_MESSAGE(!eof, "nanopb set both ok status and eof to true");
-
- return tag;
-}
-
-void Writer::WriteNanopbMessage(const pb_field_t fields[],
- const void* src_struct) {
- if (!status_.ok()) return;
-
- if (!pb_encode(&stream_, fields, src_struct)) {
- FIREBASE_ASSERT_MESSAGE(false, PB_GET_ERROR(&stream_));
- }
-}
-
-void Reader::ReadNanopbMessage(const pb_field_t fields[], void* dest_struct) {
- if (!status_.ok()) return;
-
- if (!pb_decode(&stream_, fields, dest_struct)) {
- status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
- }
-}
-
-void Writer::WriteSize(size_t size) {
- return WriteVarint(size);
-}
-
-void Writer::WriteVarint(uint64_t value) {
- if (!status_.ok()) return;
-
- if (!pb_encode_varint(&stream_, value)) {
- FIREBASE_ASSERT_MESSAGE(false, PB_GET_ERROR(&stream_));
- }
-}
-
-/**
- * Note that (despite the return type) this works for bool, enum, int32, int64,
- * uint32 and uint64 proto field types.
- *
- * Note: This is not expected to be called directly, but rather only via the
- * other Decode* methods (i.e. DecodeBool, DecodeLong, etc)
- *
- * @return The decoded varint as a uint64_t.
- */
-uint64_t Reader::ReadVarint() {
- if (!status_.ok()) return 0;
-
- uint64_t varint_value = 0;
- if (!pb_decode_varint(&stream_, &varint_value)) {
- status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
- }
- return varint_value;
-}
-
-void Writer::WriteNull() {
- return WriteVarint(google_protobuf_NullValue_NULL_VALUE);
-}
-
-void Reader::ReadNull() {
- uint64_t varint = ReadVarint();
- if (!status_.ok()) return;
-
- if (varint != google_protobuf_NullValue_NULL_VALUE) {
- status_ = Status(FirestoreErrorCode::DataLoss,
- "Input proto bytes cannot be parsed (invalid null value)");
- }
-}
-
-void Writer::WriteBool(bool bool_value) {
- return WriteVarint(bool_value);
-}
-
-bool Reader::ReadBool() {
- uint64_t varint = ReadVarint();
- if (!status_.ok()) return false;
-
- switch (varint) {
- case 0:
- return false;
- case 1:
- return true;
- default:
- status_ =
- Status(FirestoreErrorCode::DataLoss,
- "Input proto bytes cannot be parsed (invalid bool value)");
- return false;
- }
-}
-
-void Writer::WriteInteger(int64_t integer_value) {
- return WriteVarint(integer_value);
-}
-
-int64_t Reader::ReadInteger() {
- return ReadVarint();
-}
-
-void Writer::WriteString(const std::string& string_value) {
- if (!status_.ok()) return;
-
- if (!pb_encode_string(
- &stream_, reinterpret_cast<const pb_byte_t*>(string_value.c_str()),
- string_value.length())) {
- FIREBASE_ASSERT_MESSAGE(false, PB_GET_ERROR(&stream_));
- }
-}
-
-std::string Reader::ReadString() {
- if (!status_.ok()) return "";
-
- pb_istream_t substream;
- if (!pb_make_string_substream(&stream_, &substream)) {
- status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
- pb_close_string_substream(&stream_, &substream);
- return "";
- }
-
- std::string result(substream.bytes_left, '\0');
- if (!pb_read(&substream, reinterpret_cast<pb_byte_t*>(&result[0]),
- substream.bytes_left)) {
- status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
- pb_close_string_substream(&stream_, &substream);
- return "";
- }
-
- // NB: future versions of nanopb read the remaining characters out of the
- // substream (and return false if that fails) as an additional safety
- // check within pb_close_string_substream. Unfortunately, that's not present
- // in the current version (0.38). We'll make a stronger assertion and check
- // to make sure there *are* no remaining characters in the substream.
- FIREBASE_ASSERT_MESSAGE(
- substream.bytes_left == 0,
- "Bytes remaining in substream after supposedly reading all of them.");
-
- pb_close_string_substream(&stream_, &substream);
-
- return result;
-}
+ObjectValue::Map DecodeMapValue(Reader* reader);
void EncodeTimestamp(Writer* writer, const Timestamp& timestamp_value) {
google_protobuf_Timestamp timestamp_proto =
@@ -464,6 +81,8 @@ void EncodeTimestamp(Writer* writer, const Timestamp& timestamp_value) {
}
Timestamp DecodeTimestamp(Reader* reader) {
+ if (!reader->status().ok()) return {};
+
google_protobuf_Timestamp timestamp_proto =
google_protobuf_Timestamp_init_zero;
reader->ReadNanopbMessage(google_protobuf_Timestamp_fields, &timestamp_proto);
@@ -534,7 +153,9 @@ void EncodeFieldValueImpl(Writer* writer, const FieldValue& field_value) {
case FieldValue::Type::Object:
writer->WriteTag(
{PB_WT_STRING, google_firestore_v1beta1_Value_map_value_tag});
- EncodeObject(writer, field_value.object_value());
+ writer->WriteNestedMessage([&field_value](Writer* writer) {
+ EncodeMapValue(writer, field_value.object_value());
+ });
break;
default:
@@ -544,6 +165,8 @@ void EncodeFieldValueImpl(Writer* writer, const FieldValue& field_value) {
}
FieldValue DecodeFieldValueImpl(Reader* reader) {
+ if (!reader->status().ok()) return FieldValue::NullValue();
+
Tag tag = reader->ReadTag();
if (!reader->status().ok()) return FieldValue::NullValue();
@@ -580,9 +203,8 @@ FieldValue DecodeFieldValueImpl(Reader* reader) {
// TODO(rsgowman): While still in development, we'll contradict the above
// and assume the latter. Remove the following assertion when we're
// confident that we're handling all the tags in the protos.
- FIREBASE_ASSERT_MESSAGE(
- false,
- "Unhandled message field number (tag): %i. (Or possibly "
+ HARD_FAIL(
+ "Unhandled message field number (tag): %s. (Or possibly "
"corrupt input bytes)",
tag.field_number);
reader->set_status(Status(
@@ -606,110 +228,18 @@ FieldValue DecodeFieldValueImpl(Reader* reader) {
return FieldValue::TimestampValue(
reader->ReadNestedMessage<Timestamp>(DecodeTimestamp));
case google_firestore_v1beta1_Value_map_value_tag:
- return FieldValue::ObjectValueFromMap(DecodeObject(reader));
+ return FieldValue::ObjectValueFromMap(
+ reader->ReadNestedMessage<ObjectValue::Map>(DecodeMapValue));
default:
// This indicates an internal error as we've already ensured that this is
// a valid field_number.
- FIREBASE_ASSERT_MESSAGE(
- false,
+ HARD_FAIL(
"Somehow got an unexpected field number (tag) after verifying that "
"the field number was expected.");
}
}
-void Writer::WriteNestedMessage(
- const std::function<void(Writer*)>& write_message_fn) {
- if (!status_.ok()) return;
-
- // First calculate the message size using a non-writing substream.
- Writer sizer = Writer::Sizing();
- write_message_fn(&sizer);
- status_ = sizer.status();
- if (!status_.ok()) return;
- size_t size = sizer.bytes_written();
-
- // Write out the size to the output writer.
- WriteSize(size);
- if (!status_.ok()) return;
-
- // If this stream is itself a sizing stream, then we don't need to actually
- // parse field_value a second time; just update the bytes_written via a call
- // to pb_write. (If we try to write the contents into a sizing stream, it'll
- // fail since sizing streams don't actually have any buffer space.)
- if (stream_.callback == nullptr) {
- if (!pb_write(&stream_, nullptr, size)) {
- FIREBASE_ASSERT_MESSAGE(false, PB_GET_ERROR(&stream_));
- }
- return;
- }
-
- // Ensure the output stream has enough space
- if (stream_.bytes_written + size > stream_.max_size) {
- FIREBASE_ASSERT_MESSAGE(
- false,
- "Insufficient space in the output stream to write the given message");
- }
-
- // Use a substream to verify that a callback doesn't write more than what it
- // did the first time. (Use an initializer rather than setting fields
- // individually like nanopb does. This gives us a *chance* of noticing if
- // nanopb adds new fields.)
- Writer writer({stream_.callback, stream_.state,
- /*max_size=*/size, /*bytes_written=*/0,
- /*errmsg=*/nullptr});
- write_message_fn(&writer);
- status_ = writer.status();
- if (!status_.ok()) return;
-
- stream_.bytes_written += writer.stream_.bytes_written;
- stream_.state = writer.stream_.state;
- stream_.errmsg = writer.stream_.errmsg;
-
- if (writer.bytes_written() != size) {
- // submsg size changed
- FIREBASE_ASSERT_MESSAGE(
- false, "Parsing the nested message twice yielded different sizes");
- }
-}
-
-template <typename T>
-T Reader::ReadNestedMessage(const std::function<T(Reader*)>& read_message_fn) {
- // Implementation note: This is roughly modeled on pb_decode_delimited,
- // adjusted to account for the oneof in FieldValue.
-
- if (!status_.ok()) return T();
-
- pb_istream_t raw_substream;
- if (!pb_make_string_substream(&stream_, &raw_substream)) {
- status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&stream_));
- pb_close_string_substream(&stream_, &raw_substream);
- return T();
- }
- Reader substream(raw_substream);
-
- // If this fails, we *won't* return right away so that we can cleanup the
- // substream (although technically, that turns out not to matter; no resource
- // leaks occur if we don't do this.)
- // TODO(rsgowman): Consider RAII here. (Watch out for Reader class which also
- // wraps streams.)
- T message = read_message_fn(&substream);
- status_ = substream.status();
-
- // NB: future versions of nanopb read the remaining characters out of the
- // substream (and return false if that fails) as an additional safety
- // check within pb_close_string_substream. Unfortunately, that's not present
- // in the current version (0.38). We'll make a stronger assertion and check
- // to make sure there *are* no remaining characters in the substream.
- FIREBASE_ASSERT_MESSAGE(
- substream.bytes_left() == 0,
- "Bytes remaining in substream after supposedly reading all of them.");
-
- pb_close_string_substream(&stream_, &substream.stream_);
-
- return message;
-}
-
/**
* Encodes a 'FieldsEntry' object, within a FieldValue's map_value type.
*
@@ -730,35 +260,38 @@ T Reader::ReadNestedMessage(const std::function<T(Reader*)>& read_message_fn) {
*
* @param kv The individual key/value pair to write.
*/
-void EncodeFieldsEntry(Writer* writer, const ObjectValue::Map::value_type& kv) {
+void EncodeFieldsEntry(Writer* writer,
+ const ObjectValue::Map::value_type& kv,
+ uint32_t key_tag,
+ uint32_t value_tag) {
// Write the key (string)
- writer->WriteTag(
- {PB_WT_STRING, google_firestore_v1beta1_MapValue_FieldsEntry_key_tag});
+ writer->WriteTag({PB_WT_STRING, key_tag});
writer->WriteString(kv.first);
// Write the value (FieldValue)
- writer->WriteTag(
- {PB_WT_STRING, google_firestore_v1beta1_MapValue_FieldsEntry_value_tag});
+ writer->WriteTag({PB_WT_STRING, value_tag});
writer->WriteNestedMessage(
[&kv](Writer* writer) { EncodeFieldValueImpl(writer, kv.second); });
}
-ObjectValue::Map::value_type DecodeFieldsEntry(Reader* reader) {
+ObjectValue::Map::value_type DecodeFieldsEntry(Reader* reader,
+ uint32_t key_tag,
+ uint32_t value_tag) {
+ if (!reader->status().ok()) return {};
+
Tag tag = reader->ReadTag();
if (!reader->status().ok()) return {};
// TODO(rsgowman): figure out error handling: We can do better than a failed
// assertion.
- FIREBASE_ASSERT(tag.field_number ==
- google_firestore_v1beta1_MapValue_FieldsEntry_key_tag);
- FIREBASE_ASSERT(tag.wire_type == PB_WT_STRING);
+ HARD_ASSERT(tag.field_number == key_tag);
+ HARD_ASSERT(tag.wire_type == PB_WT_STRING);
std::string key = reader->ReadString();
tag = reader->ReadTag();
if (!reader->status().ok()) return {};
- FIREBASE_ASSERT(tag.field_number ==
- google_firestore_v1beta1_MapValue_FieldsEntry_value_tag);
- FIREBASE_ASSERT(tag.wire_type == PB_WT_STRING);
+ HARD_ASSERT(tag.field_number == value_tag);
+ HARD_ASSERT(tag.wire_type == PB_WT_STRING);
FieldValue value =
reader->ReadNestedMessage<FieldValue>(DecodeFieldValueImpl);
@@ -766,49 +299,72 @@ ObjectValue::Map::value_type DecodeFieldsEntry(Reader* reader) {
return ObjectValue::Map::value_type{key, value};
}
-void EncodeObject(Writer* writer, const ObjectValue& object_value) {
- return writer->WriteNestedMessage([&object_value](Writer* writer) {
- // Write each FieldsEntry (i.e. key-value pair.)
- for (const auto& kv : object_value.internal_value) {
- writer->WriteTag({PB_WT_STRING,
- google_firestore_v1beta1_MapValue_FieldsEntry_key_tag});
- writer->WriteNestedMessage(
- [&kv](Writer* writer) { return EncodeFieldsEntry(writer, kv); });
- }
- });
+ObjectValue::Map::value_type DecodeMapValueFieldsEntry(Reader* reader) {
+ return DecodeFieldsEntry(
+ reader, google_firestore_v1beta1_MapValue_FieldsEntry_key_tag,
+ google_firestore_v1beta1_MapValue_FieldsEntry_value_tag);
}
-ObjectValue::Map DecodeObject(Reader* reader) {
- if (!reader->status().ok()) return ObjectValue::Map();
-
- return reader->ReadNestedMessage<ObjectValue::Map>(
- [](Reader* reader) -> ObjectValue::Map {
- ObjectValue::Map result;
- if (!reader->status().ok()) return result;
-
- while (reader->bytes_left()) {
- Tag tag = reader->ReadTag();
- if (!reader->status().ok()) return result;
- FIREBASE_ASSERT(tag.field_number ==
- google_firestore_v1beta1_MapValue_fields_tag);
- FIREBASE_ASSERT(tag.wire_type == PB_WT_STRING);
-
- ObjectValue::Map::value_type fv =
- reader->ReadNestedMessage<ObjectValue::Map::value_type>(
- DecodeFieldsEntry);
-
- // Sanity check: ensure that this key doesn't already exist in the
- // map.
- // TODO(rsgowman): figure out error handling: We can do better than a
- // failed assertion.
- if (!reader->status().ok()) return result;
- FIREBASE_ASSERT(result.find(fv.first) == result.end());
-
- // Add this key,fieldvalue to the results map.
- result.emplace(std::move(fv));
- }
- return result;
- });
+ObjectValue::Map::value_type DecodeDocumentFieldsEntry(Reader* reader) {
+ return DecodeFieldsEntry(
+ reader, google_firestore_v1beta1_Document_FieldsEntry_key_tag,
+ google_firestore_v1beta1_Document_FieldsEntry_value_tag);
+}
+
+void EncodeObjectMap(Writer* writer,
+ const ObjectValue::Map& object_value_map,
+ uint32_t map_tag,
+ uint32_t key_tag,
+ uint32_t value_tag) {
+ // Write each FieldsEntry (i.e. key-value pair.)
+ for (const auto& kv : object_value_map) {
+ writer->WriteTag({PB_WT_STRING, map_tag});
+ writer->WriteNestedMessage([&kv, &key_tag, &value_tag](Writer* writer) {
+ return EncodeFieldsEntry(writer, kv, key_tag, value_tag);
+ });
+ }
+}
+
+void EncodeMapValue(Writer* writer, const ObjectValue& object_value) {
+ EncodeObjectMap(writer, object_value.internal_value,
+ google_firestore_v1beta1_MapValue_fields_tag,
+ google_firestore_v1beta1_MapValue_FieldsEntry_key_tag,
+ google_firestore_v1beta1_MapValue_FieldsEntry_value_tag);
+}
+
+ObjectValue::Map DecodeMapValue(Reader* reader) {
+ ObjectValue::Map result;
+ if (!reader->status().ok()) return result;
+
+ while (reader->bytes_left()) {
+ Tag tag = reader->ReadTag();
+ if (!reader->status().ok()) return result;
+ // The MapValue message only has a single valid tag.
+ // TODO(rsgowman): figure out error handling: We can do better than a
+ // failed assertion.
+ HARD_ASSERT(tag.field_number ==
+ google_firestore_v1beta1_MapValue_fields_tag);
+ HARD_ASSERT(tag.wire_type == PB_WT_STRING);
+
+ ObjectValue::Map::value_type fv =
+ reader->ReadNestedMessage<ObjectValue::Map::value_type>(
+ DecodeMapValueFieldsEntry);
+
+ if (!reader->status().ok()) return result;
+
+ // Assumption: If we parse two entries for the map that have the same key,
+ // then the latter should overwrite the former. This does not appear to be
+ // explicitly called out by the docs, but seems to be in the spirit of how
+ // things work. (i.e. non-repeated fields explicitly follow this behaviour.)
+ // In any case, well behaved proto emitters shouldn't create encodings like
+ // this, but well behaved parsers are expected to handle these cases.
+ //
+ // https://developers.google.com/protocol-buffers/docs/encoding#optional
+
+ // Add this key,fieldvalue to the results map.
+ result[fv.first] = fv.second;
+ }
+ return result;
}
/**
@@ -849,9 +405,9 @@ bool IsValidResourceName(const ResourcePath& path) {
*/
ResourcePath DecodeResourceName(absl::string_view encoded) {
ResourcePath resource = ResourcePath::FromString(encoded);
- FIREBASE_ASSERT_MESSAGE(IsValidResourceName(resource),
- "Tried to deserialize invalid key %s",
- resource.CanonicalString().c_str());
+ HARD_ASSERT(IsValidResourceName(resource),
+ "Tried to deserialize invalid key %s",
+ resource.CanonicalString());
return resource;
}
@@ -862,10 +418,9 @@ ResourcePath DecodeResourceName(absl::string_view encoded) {
*/
ResourcePath ExtractLocalPathFromResourceName(
const ResourcePath& resource_name) {
- FIREBASE_ASSERT_MESSAGE(
- resource_name.size() > 4 && resource_name[4] == "documents",
- "Tried to deserialize invalid key %s",
- resource_name.CanonicalString().c_str());
+ HARD_ASSERT(resource_name.size() > 4 && resource_name[4] == "documents",
+ "Tried to deserialize invalid key %s",
+ resource_name.CanonicalString());
return resource_name.PopFirst(5);
}
@@ -895,13 +450,197 @@ std::string Serializer::EncodeKey(const DocumentKey& key) const {
DocumentKey Serializer::DecodeKey(absl::string_view name) const {
ResourcePath resource = DecodeResourceName(name);
- FIREBASE_ASSERT_MESSAGE(resource[1] == database_id_.project_id(),
- "Tried to deserialize key from different project.");
- FIREBASE_ASSERT_MESSAGE(resource[3] == database_id_.database_id(),
- "Tried to deserialize key from different database.");
+ HARD_ASSERT(resource[1] == database_id_.project_id(),
+ "Tried to deserialize key from different project.");
+ HARD_ASSERT(resource[3] == database_id_.database_id(),
+ "Tried to deserialize key from different database.");
return DocumentKey{ExtractLocalPathFromResourceName(resource)};
}
+util::Status Serializer::EncodeDocument(const DocumentKey& key,
+ const ObjectValue& value,
+ std::vector<uint8_t>* out_bytes) const {
+ Writer writer = Writer::Wrap(out_bytes);
+ EncodeDocument(&writer, key, value);
+ return writer.status();
+}
+
+void Serializer::EncodeDocument(Writer* writer,
+ const DocumentKey& key,
+ const ObjectValue& object_value) const {
+ // Encode Document.name
+ writer->WriteTag({PB_WT_STRING, google_firestore_v1beta1_Document_name_tag});
+ writer->WriteString(EncodeKey(key));
+
+ // Encode Document.fields (unless it's empty)
+ if (!object_value.internal_value.empty()) {
+ EncodeObjectMap(writer, object_value.internal_value,
+ google_firestore_v1beta1_Document_fields_tag,
+ google_firestore_v1beta1_Document_FieldsEntry_key_tag,
+ google_firestore_v1beta1_Document_FieldsEntry_value_tag);
+ }
+
+ // Skip Document.create_time and Document.update_time, since they're
+ // output-only fields.
+}
+
+util::StatusOr<std::unique_ptr<model::MaybeDocument>>
+Serializer::DecodeMaybeDocument(const uint8_t* bytes, size_t length) const {
+ Reader reader = Reader::Wrap(bytes, length);
+ std::unique_ptr<MaybeDocument> maybeDoc =
+ DecodeBatchGetDocumentsResponse(&reader);
+
+ if (reader.status().ok()) {
+ return std::move(maybeDoc);
+ } else {
+ return reader.status();
+ }
+}
+
+std::unique_ptr<MaybeDocument> Serializer::DecodeBatchGetDocumentsResponse(
+ Reader* reader) const {
+ if (!reader->status().ok()) return nullptr;
+
+ // Initialize BatchGetDocumentsResponse fields to their default values
+ std::unique_ptr<MaybeDocument> found;
+ std::string missing;
+ // TODO(rsgowman): transaction
+ SnapshotVersion read_time = SnapshotVersion::None();
+
+ while (reader->bytes_left()) {
+ 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:
+ 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;
+
+ case google_firestore_v1beta1_BatchGetDocumentsResponse_transaction_tag:
+ // TODO(rsgowman)
+ abort();
+
+ 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:
+ // TODO(rsgowman)
+ abort();
+
+ 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 {
+ // Neither 'found' nor 'missing' fields were set.
+ // TODO(rsgowman): Handle the error case.
+ abort();
+ }
+}
+
+std::unique_ptr<Document> Serializer::DecodeDocument(Reader* reader) const {
+ if (!reader->status().ok()) return nullptr;
+
+ std::string name;
+ ObjectValue::Map fields_internal;
+ SnapshotVersion version = SnapshotVersion::None();
+
+ while (reader->bytes_left()) {
+ Tag tag = reader->ReadTag();
+ if (!reader->status().ok()) return nullptr;
+ HARD_ASSERT(tag.wire_type == PB_WT_STRING);
+ switch (tag.field_number) {
+ case google_firestore_v1beta1_Document_name_tag:
+ name = reader->ReadString();
+ break;
+ case google_firestore_v1beta1_Document_fields_tag: {
+ ObjectValue::Map::value_type fv =
+ reader->ReadNestedMessage<ObjectValue::Map::value_type>(
+ DecodeDocumentFieldsEntry);
+
+ if (!reader->status().ok()) return nullptr;
+
+ // Assumption: For duplicates, the latter overrides the former, see
+ // comment on writing object map for details (DecodeMapValue).
+
+ // Add fieldvalue to the results map.
+ fields_internal[fv.first] = fv.second;
+ break;
+ }
+ case google_firestore_v1beta1_Document_create_time_tag:
+ // This field is ignored by the client sdk, but we still need to extract
+ // it.
+ reader->ReadNestedMessage<Timestamp>(DecodeTimestamp);
+ break;
+ case google_firestore_v1beta1_Document_update_time_tag:
+ // TODO(rsgowman): Rather than overwriting, we should instead merge with
+ // the existing SnapshotVersion (if any). Less relevant here, since it's
+ // just two numbers which are both expected to be present, but if the
+ // proto evolves that might change.
+ version = SnapshotVersion{
+ reader->ReadNestedMessage<Timestamp>(DecodeTimestamp)};
+ break;
+ default:
+ // TODO(rsgowman): Error handling. (Invalid tags should fail to decode,
+ // but shouldn't cause a crash.)
+ abort();
+ }
+ }
+
+ return absl::make_unique<Document>(
+ FieldValue::ObjectValueFromMap(fields_internal), DecodeKey(name), version,
+ /*has_local_modifications=*/false);
+}
+
} // namespace remote
} // namespace firestore
} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.h b/Firestore/core/src/firebase/firestore/remote/serializer.h
index 86aa6e2..379069c 100644
--- a/Firestore/core/src/firebase/firestore/remote/serializer.h
+++ b/Firestore/core/src/firebase/firestore/remote/serializer.h
@@ -19,13 +19,18 @@
#include <cstdint>
#include <cstdlib>
+#include <memory>
#include <string>
#include <vector>
#include "Firestore/core/src/firebase/firestore/model/database_id.h"
+#include "Firestore/core/src/firebase/firestore/model/document.h"
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
#include "Firestore/core/src/firebase/firestore/model/field_value.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/model/maybe_document.h"
+#include "Firestore/core/src/firebase/firestore/nanopb/reader.h"
+#include "Firestore/core/src/firebase/firestore/nanopb/writer.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "Firestore/core/src/firebase/firestore/util/status.h"
#include "Firestore/core/src/firebase/firestore/util/statusor.h"
#include "absl/base/attributes.h"
@@ -59,7 +64,7 @@ class Serializer {
}
/**
- * Converts the FieldValue model passed into bytes.
+ * @brief Converts the FieldValue model passed into bytes.
*
* @param field_value the model to convert.
* @param[out] out_bytes A buffer to place the output. The bytes will be
@@ -111,7 +116,56 @@ class Serializer {
firebase::firestore::model::DocumentKey DecodeKey(
absl::string_view name) const;
+ /**
+ * @brief Converts the Document (i.e. key/value) into bytes.
+ *
+ * @param[out] out_bytes A buffer to place the output. The bytes will be
+ * appended to this vector.
+ * @return A Status, which if not ok(), indicates what went wrong. Note that
+ * errors during encoding generally indicate a serious/fatal error.
+ */
+ // TODO(rsgowman): Similar to above, if we never support any output except to
+ // a vector, it may make sense to have Serializer own the vector and provide
+ // an accessor rather than asking the user to create it first.
+ util::Status EncodeDocument(
+ const firebase::firestore::model::DocumentKey& key,
+ const firebase::firestore::model::ObjectValue& value,
+ std::vector<uint8_t>* out_bytes) const;
+
+ /**
+ * @brief Converts from bytes to the model Document format.
+ *
+ * @param bytes The bytes to convert. These bytes must represent a
+ * BatchGetDocumentsResponse. It's assumed that exactly all of the bytes will
+ * be used by this conversion.
+ * @return The model equivalent of the bytes or a Status indicating
+ * what went wrong.
+ */
+ util::StatusOr<std::unique_ptr<model::MaybeDocument>> DecodeMaybeDocument(
+ const uint8_t* bytes, size_t length) const;
+
+ /**
+ * @brief Converts from bytes to the model Document format.
+ *
+ * @param bytes The bytes to convert. These bytes must represent a
+ * BatchGetDocumentsResponse. It's assumed that exactly all of the bytes will
+ * be used by this conversion.
+ * @return The model equivalent of the bytes or a Status indicating
+ * what went wrong.
+ */
+ util::StatusOr<std::unique_ptr<model::MaybeDocument>> DecodeMaybeDocument(
+ const std::vector<uint8_t>& bytes) const {
+ return DecodeMaybeDocument(bytes.data(), bytes.size());
+ }
+
private:
+ void EncodeDocument(nanopb::Writer* writer,
+ const model::DocumentKey& key,
+ const model::ObjectValue& object_value) const;
+ std::unique_ptr<model::MaybeDocument> DecodeBatchGetDocumentsResponse(
+ nanopb::Reader* reader) const;
+ std::unique_ptr<model::Document> DecodeDocument(nanopb::Reader* reader) const;
+
const firebase::firestore::model::DatabaseId& database_id_;
};
diff --git a/Firestore/core/src/firebase/firestore/timestamp.cc b/Firestore/core/src/firebase/firestore/timestamp.cc
index a5f0121..c35fca1 100644
--- a/Firestore/core/src/firebase/firestore/timestamp.cc
+++ b/Firestore/core/src/firebase/firestore/timestamp.cc
@@ -16,7 +16,7 @@
#include "Firestore/core/include/firebase/firestore/timestamp.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
@@ -58,7 +58,7 @@ Timestamp Timestamp::FromTimePoint(
const auto epoch_time = time_point.time_since_epoch();
auto seconds = chr::duration_cast<chr::duration<int64_t>>(epoch_time);
auto nanoseconds = chr::duration_cast<chr::nanoseconds>(epoch_time - seconds);
- FIREBASE_DEV_ASSERT(nanoseconds.count() < 1 * 1000 * 1000 * 1000);
+ HARD_ASSERT(nanoseconds.count() < 1 * 1000 * 1000 * 1000);
if (nanoseconds.count() < 0) {
// Timestamp format always has a positive number of nanoseconds that is
@@ -89,19 +89,17 @@ std::string Timestamp::ToString() const {
}
void Timestamp::ValidateBounds() const {
- FIREBASE_ASSERT_MESSAGE(nanoseconds_ >= 0,
- "Timestamp nanoseconds out of range: %d",
- nanoseconds_);
- FIREBASE_ASSERT_MESSAGE(nanoseconds_ < 1e9,
- "Timestamp nanoseconds out of range: %d",
- nanoseconds_);
+ HARD_ASSERT(nanoseconds_ >= 0, "Timestamp nanoseconds out of range: %s",
+ nanoseconds_);
+ HARD_ASSERT(nanoseconds_ < 1e9, "Timestamp nanoseconds out of range: %s",
+ nanoseconds_);
// Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore
// supports.
- FIREBASE_ASSERT_MESSAGE(seconds_ >= -62135596800L,
- "Timestamp seconds out of range: %lld", seconds_);
+ HARD_ASSERT(seconds_ >= -62135596800L, "Timestamp seconds out of range: %s",
+ seconds_);
// This will break in the year 10,000.
- FIREBASE_ASSERT_MESSAGE(seconds_ < 253402300800L,
- "Timestamp seconds out of range: %lld", seconds_);
+ HARD_ASSERT(seconds_ < 253402300800L, "Timestamp seconds out of range: %s",
+ seconds_);
}
} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
index b2b015b..043713f 100644
--- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt
@@ -22,10 +22,11 @@ include(CheckIncludeFiles)
cc_library(
firebase_firestore_util_base
SOURCES
- string_printf.cc
- string_printf.h
+ string_format.cc
+ string_format.h
DEPENDS
absl_base
+ absl_strings
)
## assert and log
@@ -33,8 +34,8 @@ cc_library(
cc_library(
firebase_firestore_util_log_stdio
SOURCES
- firebase_assert.h
- assert_stdio.cc
+ hard_assert_stdio.cc
+ hard_assert.h
log.h
log_stdio.cc
DEPENDS
@@ -46,14 +47,15 @@ cc_library(
cc_library(
firebase_firestore_util_log_apple
SOURCES
- firebase_assert.h
- assert_apple.mm
+ hard_assert.h
+ hard_assert_apple.mm
log.h
log_apple.mm
string_apple.h
DEPENDS
FirebaseCore
absl_strings
+ firebase_firestore_util_base
EXCLUDE_FROM_ALL
)
diff --git a/Firestore/core/src/firebase/firestore/util/async_queue.cc b/Firestore/core/src/firebase/firestore/util/async_queue.cc
index 71f5cc5..b42dec3 100644
--- a/Firestore/core/src/firebase/firestore/util/async_queue.cc
+++ b/Firestore/core/src/firebase/firestore/util/async_queue.cc
@@ -18,7 +18,7 @@
#include <utility>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/memory/memory.h"
namespace firebase {
@@ -32,28 +32,29 @@ AsyncQueue::AsyncQueue(std::unique_ptr<Executor> executor)
is_operation_in_progress_ = false;
}
+// TODO(varconst): assert in destructor that the queue is empty.
+
void AsyncQueue::VerifyIsCurrentExecutor() const {
- FIREBASE_ASSERT_MESSAGE(
+ HARD_ASSERT(
executor_->IsCurrentExecutor(),
"Expected to be called by the executor associated with this queue "
"(expected executor: '%s', actual executor: '%s')",
- executor_->Name().c_str(), executor_->CurrentExecutorName().c_str());
+ executor_->Name(), executor_->CurrentExecutorName());
}
void AsyncQueue::VerifyIsCurrentQueue() const {
VerifyIsCurrentExecutor();
- FIREBASE_ASSERT_MESSAGE(
- is_operation_in_progress_,
- "VerifyIsCurrentQueue called when no operation is executing "
- "(expected executor: '%s', actual executor: '%s')",
- executor_->Name().c_str(), executor_->CurrentExecutorName().c_str());
+ HARD_ASSERT(is_operation_in_progress_,
+ "VerifyIsCurrentQueue called when no operation is executing "
+ "(expected executor: '%s', actual executor: '%s')",
+ executor_->Name(), executor_->CurrentExecutorName());
}
void AsyncQueue::ExecuteBlocking(const Operation& operation) {
VerifyIsCurrentExecutor();
- FIREBASE_ASSERT_MESSAGE(!is_operation_in_progress_,
- "ExecuteBlocking may not be called "
- "before the previous operation finishes executing");
+ HARD_ASSERT(!is_operation_in_progress_,
+ "ExecuteBlocking may not be called "
+ "before the previous operation finishes executing");
is_operation_in_progress_ = true;
operation();
@@ -77,9 +78,8 @@ DelayedOperation AsyncQueue::EnqueueAfterDelay(const Milliseconds delay,
// While not necessarily harmful, we currently don't expect to have multiple
// callbacks with the same timer_id in the queue, so defensively reject
// them.
- FIREBASE_ASSERT_MESSAGE(
- !IsScheduled(timer_id),
- "Attempted to schedule multiple operations with id %d", timer_id);
+ HARD_ASSERT(!IsScheduled(timer_id),
+ "Attempted to schedule multiple operations with id %s", timer_id);
Executor::TaggedOperation tagged{static_cast<int>(timer_id), Wrap(operation)};
return executor_->Schedule(delay, std::move(tagged));
@@ -95,12 +95,11 @@ AsyncQueue::Operation AsyncQueue::Wrap(const Operation& operation) {
void AsyncQueue::VerifySequentialOrder() const {
// This is the inverse of `VerifyIsCurrentQueue`.
- FIREBASE_ASSERT_MESSAGE(
- !is_operation_in_progress_ || !executor_->IsCurrentExecutor(),
- "Enforcing sequential order failed: currently executing operations "
- "cannot enqueue more operations "
- "(this queue's executor: '%s', current executor: '%s')",
- executor_->Name().c_str(), executor_->CurrentExecutorName().c_str());
+ HARD_ASSERT(!is_operation_in_progress_ || !executor_->IsCurrentExecutor(),
+ "Enqueue methods cannot be called when we are already running on "
+ "target executor "
+ "(this queue's executor: '%s', current executor: '%s')",
+ executor_->Name(), executor_->CurrentExecutorName());
}
// Test-only functions
@@ -115,14 +114,13 @@ bool AsyncQueue::IsScheduled(const TimerId timer_id) const {
}
void AsyncQueue::RunScheduledOperationsUntil(const TimerId last_timer_id) {
- FIREBASE_ASSERT_MESSAGE(
- !executor_->IsCurrentExecutor(),
- "RunScheduledOperationsUntil must not be called on the queue");
+ HARD_ASSERT(!executor_->IsCurrentExecutor(),
+ "RunScheduledOperationsUntil must not be called on the queue");
executor_->ExecuteBlocking([this, last_timer_id] {
- FIREBASE_ASSERT_MESSAGE(
+ HARD_ASSERT(
last_timer_id == TimerId::All || IsScheduled(last_timer_id),
- "Attempted to run scheduled operations until missing timer id: %d",
+ "Attempted to run scheduled operations until missing timer id: %s",
last_timer_id);
for (auto next = executor_->PopFromSchedule(); next.has_value();
diff --git a/Firestore/core/src/firebase/firestore/util/bits.cc b/Firestore/core/src/firebase/firestore/util/bits.cc
index 0bfe4c3..03d9b77 100644
--- a/Firestore/core/src/firebase/firestore/util/bits.cc
+++ b/Firestore/core/src/firebase/firestore/util/bits.cc
@@ -16,7 +16,7 @@
#include "Firestore/core/src/firebase/firestore/util/bits.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -34,7 +34,7 @@ int Bits::Log2Floor_Portable(uint32_t n) {
log += shift;
}
}
- FIREBASE_ASSERT(value == 1);
+ HARD_ASSERT(value == 1);
return log;
}
diff --git a/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h b/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h
index 85c34f8..d356a74 100644
--- a/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h
+++ b/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h
@@ -26,7 +26,6 @@
#include "dispatch/dispatch.h"
#include "Firestore/core/src/firebase/firestore/util/executor.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
#include "absl/strings/string_view.h"
#if !defined(__OBJC__)
@@ -45,10 +44,10 @@ namespace internal {
// Generic wrapper over `dispatch_async_f`, providing `dispatch_async`-like
// interface: accepts an arbitrary invocable object in place of an Objective-C
// block.
-void DispatchAsync(const dispatch_queue_t queue, std::function<void()>&& work);
+void DispatchAsync(dispatch_queue_t queue, std::function<void()>&& work);
// Similar to `DispatchAsync` but wraps `dispatch_sync_f`.
-void DispatchSync(const dispatch_queue_t queue, std::function<void()> work);
+void DispatchSync(dispatch_queue_t queue, std::function<void()> work);
class TimeSlot;
@@ -56,9 +55,7 @@ class TimeSlot;
// a dedicated serial dispatch queue.
class ExecutorLibdispatch : public Executor {
public:
- ExecutorLibdispatch();
explicit ExecutorLibdispatch(dispatch_queue_t dispatch_queue);
- ~ExecutorLibdispatch();
bool IsCurrentExecutor() const override;
std::string CurrentExecutorName() const override;
@@ -79,11 +76,6 @@ class ExecutorLibdispatch : public Executor {
}
private:
- // GetLabel functions are guaranteed to never return a "null" string_view
- // (i.e. data() != nullptr).
- absl::string_view GetCurrentQueueLabel() const;
- absl::string_view GetTargetQueueLabel() const;
-
dispatch_queue_t dispatch_queue_;
// Stores non-owned pointers to `TimeSlot`s.
// Invariant: if a `TimeSlot` is in `schedule_`, it's a valid pointer.
diff --git a/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm b/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm
index 5491fec..70d0b3a 100644
--- a/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm
+++ b/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm
@@ -16,6 +16,8 @@
#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
+
namespace firebase {
namespace firestore {
namespace util {
@@ -28,13 +30,16 @@ absl::string_view StringViewFromDispatchLabel(const char* const label) {
return label ? absl::string_view{label} : absl::string_view{""};
}
-void RunSynchronized(const ExecutorLibdispatch* const executor,
- std::function<void()>&& work) {
- if (executor->IsCurrentExecutor()) {
- work();
- } else {
- DispatchSync(executor->dispatch_queue(), std::move(work));
- }
+// GetLabel functions are guaranteed to never return a "null" string_view
+// (i.e. data() != nullptr).
+absl::string_view GetQueueLabel(const dispatch_queue_t queue) {
+ return StringViewFromDispatchLabel(dispatch_queue_get_label(queue));
+}
+absl::string_view GetCurrentQueueLabel() {
+ // Note: dispatch_queue_get_label may return nullptr if the queue wasn't
+ // initialized with a label.
+ return StringViewFromDispatchLabel(
+ dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
}
} // namespace
@@ -51,15 +56,32 @@ void DispatchAsync(const dispatch_queue_t queue, std::function<void()>&& work) {
});
}
-void DispatchSync(const dispatch_queue_t queue, Executor::Operation work) {
+void DispatchSync(const dispatch_queue_t queue, std::function<void()> work) {
+ HARD_ASSERT(
+ GetCurrentQueueLabel() != GetQueueLabel(queue),
+ "Calling DispatchSync on the current queue will lead to a deadlock.");
+
// Unlike dispatch_async_f, dispatch_sync_f blocks until the work passed to it
// is done, so passing a reference to a local variable is okay.
dispatch_sync_f(queue, &work, [](void* const raw_work) {
- const auto unwrap = static_cast<const Executor::Operation*>(raw_work);
+ const auto unwrap = static_cast<std::function<void()>*>(raw_work);
(*unwrap)();
});
}
+namespace {
+
+template <typename Work>
+void RunSynchronized(const ExecutorLibdispatch* const executor, Work&& work) {
+ if (executor->IsCurrentExecutor()) {
+ work();
+ } else {
+ DispatchSync(executor->dispatch_queue(), std::forward<Work>(work));
+ }
+}
+
+} // namespace
+
// Represents a "busy" time slot on the schedule.
//
// Since libdispatch doesn't provide a way to cancel a scheduled operation, once
@@ -156,8 +178,8 @@ void TimeSlot::Execute() {
RemoveFromSchedule();
- FIREBASE_ASSERT_MESSAGE(tagged_.operation,
- "TimeSlot contains an invalid function object");
+ HARD_ASSERT(tagged_.operation,
+ "TimeSlot contains an invalid function object");
tagged_.operation();
}
@@ -170,32 +192,15 @@ void TimeSlot::RemoveFromSchedule() {
ExecutorLibdispatch::ExecutorLibdispatch(const dispatch_queue_t dispatch_queue)
: dispatch_queue_{dispatch_queue} {
}
-ExecutorLibdispatch::ExecutorLibdispatch()
- : ExecutorLibdispatch{dispatch_queue_create("com.google.firebase.firestore",
- DISPATCH_QUEUE_SERIAL)} {
-}
-
-ExecutorLibdispatch::~ExecutorLibdispatch() {
- // Turn any operations that might still be in the queue into no-ops, lest
- // they try to access `ExecutorLibdispatch` after it gets destroyed. Because
- // the queue is serial, by the time libdispatch gets to the newly-enqueued
- // work, the pending operations that might have been in progress would have
- // already finished.
- RunSynchronized(this, [this] {
- for (auto slot : schedule_) {
- slot->MarkDone();
- }
- });
-}
bool ExecutorLibdispatch::IsCurrentExecutor() const {
- return GetCurrentQueueLabel().data() == GetTargetQueueLabel().data();
+ return GetCurrentQueueLabel() == GetQueueLabel(dispatch_queue());
}
std::string ExecutorLibdispatch::CurrentExecutorName() const {
return GetCurrentQueueLabel().data();
}
std::string ExecutorLibdispatch::Name() const {
- return GetTargetQueueLabel().data();
+ return GetQueueLabel(dispatch_queue()).data();
}
void ExecutorLibdispatch::Execute(Operation&& operation) {
@@ -243,29 +248,14 @@ void ExecutorLibdispatch::RemoveFromSchedule(const TimeSlot* const to_remove) {
});
}
-// GetLabel functions are guaranteed to never return a "null" string_view
-// (i.e. data() != nullptr).
-absl::string_view ExecutorLibdispatch::GetCurrentQueueLabel() const {
- // Note: dispatch_queue_get_label may return nullptr if the queue wasn't
- // initialized with a label.
- return StringViewFromDispatchLabel(
- dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
-}
-
-absl::string_view ExecutorLibdispatch::GetTargetQueueLabel() const {
- return StringViewFromDispatchLabel(
- dispatch_queue_get_label(dispatch_queue()));
-}
-
// Test-only methods
bool ExecutorLibdispatch::IsScheduled(const Tag tag) const {
bool result = false;
RunSynchronized(this, [this, tag, &result] {
- result = std::find_if(schedule_.begin(), schedule_.end(),
- [&tag](const TimeSlot* const operation) {
- return *operation == tag;
- }) != schedule_.end();
+ result = std::any_of(
+ schedule_.begin(), schedule_.end(),
+ [&tag](const TimeSlot* const operation) { return *operation == tag; });
});
return result;
}
diff --git a/Firestore/core/src/firebase/firestore/util/executor_std.cc b/Firestore/core/src/firebase/firestore/util/executor_std.cc
index f03a712..a87ec20 100644
--- a/Firestore/core/src/firebase/firestore/util/executor_std.cc
+++ b/Firestore/core/src/firebase/firestore/util/executor_std.cc
@@ -64,8 +64,7 @@ DelayedOperation ExecutorStd::Schedule(const Milliseconds delay,
// While negative delay can be interpreted as a request for immediate
// execution, supporting it would provide a hacky way to modify FIFO ordering
// of immediate operations.
- FIREBASE_ASSERT_MESSAGE(delay.count() >= 0,
- "Schedule: delay cannot be negative");
+ HARD_ASSERT(delay.count() >= 0, "Schedule: delay cannot be negative");
namespace chr = std::chrono;
const auto now = chr::time_point_cast<Milliseconds>(chr::steady_clock::now());
diff --git a/Firestore/core/src/firebase/firestore/util/executor_std.h b/Firestore/core/src/firebase/firestore/util/executor_std.h
index 58ef96f..efe60db 100644
--- a/Firestore/core/src/firebase/firestore/util/executor_std.h
+++ b/Firestore/core/src/firebase/firestore/util/executor_std.h
@@ -27,7 +27,7 @@
#include <utility>
#include "Firestore/core/src/firebase/firestore/util/executor.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/types/optional.h"
namespace firebase {
@@ -41,7 +41,7 @@ namespace async {
// the exact same time are prioritized in FIFO order.
//
// The main function of `Schedule` is `PopBlocking`, which sleeps until an entry
-// becomes available. It correctly handles entries being asynchonously added or
+// becomes available. It correctly handles entries being asynchronously added or
// removed from the schedule.
//
// The details of time management are completely concealed within the class.
@@ -181,8 +181,8 @@ class Schedule {
// This function expects the mutex to be already locked.
T ExtractLocked(const Iterator where) {
- FIREBASE_ASSERT_MESSAGE(!scheduled_.empty(),
- "Trying to pop an entry from an empty queue.");
+ HARD_ASSERT(!scheduled_.empty(),
+ "Trying to pop an entry from an empty queue.");
T result = std::move(where->value);
scheduled_.erase(where);
@@ -220,7 +220,6 @@ class ExecutorStd : public Executor {
bool IsScheduled(Tag tag) const override;
absl::optional<TaggedOperation> PopFromSchedule() override;
- private:
using TimePoint = async::Schedule<Operation>::TimePoint;
// To allow canceling operations, each scheduled operation is assigned
// a monotonically increasing identifier.
diff --git a/Firestore/core/src/firebase/firestore/util/firebase_assert.h b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
deleted file mode 100644
index 6a9c2eb..0000000
--- a/Firestore/core/src/firebase/firestore/util/firebase_assert.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2018 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// To avoid naming-collision, this header is called firebase_assert.h instead
-// of assert.h.
-
-#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_
-#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_
-
-#include <cstdlib>
-
-#include "Firestore/core/src/firebase/firestore/util/log.h"
-#include "absl/base/attributes.h"
-
-#define FIREBASE_EXPAND_STRINGIFY_(X) #X
-#define FIREBASE_EXPAND_STRINGIFY(X) FIREBASE_EXPAND_STRINGIFY_(X)
-
-// FIREBASE_ASSERT_* macros are not compiled out of release builds. They should
-// be used for assertions that need to be propagated to end-users of SDKs.
-// FIREBASE_DEV_ASSERT_* macros are compiled out of release builds, similar to
-// the C assert() macro. They should be used for internal assertions that are
-// only shown to SDK developers.
-
-// Assert condition is true, if it's false log an assert with the specified
-// expression as a string.
-#define FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression) \
- do { \
- if (!(condition)) { \
- firebase::firestore::util::FailAssert( \
- __FILE__, __PRETTY_FUNCTION__, __LINE__, \
- FIREBASE_EXPAND_STRINGIFY(expression)); \
- } \
- } while (0)
-
-// Assert condition is true, if it's false log an assert with the specified
-// expression as a string. Compiled out of release builds.
-#if defined(NDEBUG)
-#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \
- { (void)(condition); }
-#else
-#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \
- FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression)
-#endif // defined(NDEBUG)
-
-// Custom assert() implementation that is not compiled out in release builds.
-#define FIREBASE_ASSERT(expression) \
- FIREBASE_ASSERT_WITH_EXPRESSION(expression, expression)
-
-// Custom assert() implementation that is compiled out in release builds.
-// Compiled out of release builds.
-#define FIREBASE_DEV_ASSERT(expression) \
- FIREBASE_DEV_ASSERT_WITH_EXPRESSION(expression, expression)
-
-// Assert condition is true otherwise display the specified expression,
-// message and abort.
-#define FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, ...) \
- do { \
- if (!(condition)) { \
- firebase::firestore::util::LogError( \
- FIREBASE_EXPAND_STRINGIFY(expression)); \
- firebase::firestore::util::FailAssert(__FILE__, __PRETTY_FUNCTION__, \
- __LINE__, __VA_ARGS__); \
- } \
- } while (0)
-
-// Assert condition is true otherwise display the specified expression,
-// message and abort. Compiled out of release builds.
-#if defined(NDEBUG)
-#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \
- ...) \
- { (void)(condition); }
-#else
-#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \
- ...) \
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, __VA_ARGS__)
-#endif // defined(NDEBUG)
-
-// Assert expression is true otherwise display the specified message and
-// abort.
-#define FIREBASE_ASSERT_MESSAGE(expression, ...) \
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(expression, expression, __VA_ARGS__)
-
-// Assert expression is true otherwise display the specified message and
-// abort. Compiled out of release builds.
-#define FIREBASE_DEV_ASSERT_MESSAGE(expression, ...) \
- FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(expression, expression, \
- __VA_ARGS__)
-
-// Indicates an area of the code that cannot be reached (except possibly due to
-// undefined behaviour or other similar badness). The only reasonable thing to
-// do in these cases is to immediately abort.
-#define FIREBASE_UNREACHABLE() abort()
-
-namespace firebase {
-namespace firestore {
-namespace util {
-
-// A no-return helper function. To raise an assertion, use Macro instead.
-ABSL_ATTRIBUTE_NORETURN void FailAssert(
- const char* file, const char* func, int line, const char* format, ...);
-
-} // namespace util
-} // namespace firestore
-} // namespace firebase
-
-#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_
diff --git a/Firestore/core/src/firebase/firestore/util/hard_assert.h b/Firestore/core/src/firebase/firestore/util/hard_assert.h
new file mode 100644
index 0000000..e60d71a
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/hard_assert.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HARD_ASSERT_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HARD_ASSERT_H_
+
+#include <string>
+
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
+
+/**
+ * Fails the current function if the given condition is false.
+ *
+ * Unlike assert(3) or NSAssert, this macro is never compiled out.
+ *
+ * @param condition The condition to test.
+ * @param format (optional) A format string suitable for util::StringFormat.
+ * @param ... format arguments to pass to util::StringFormat.
+ */
+#define HARD_ASSERT(condition, ...) \
+ do { \
+ if (!(condition)) { \
+ std::string _message = \
+ firebase::firestore::util::StringFormat(__VA_ARGS__); \
+ firebase::firestore::util::internal::Fail( \
+ __FILE__, __PRETTY_FUNCTION__, __LINE__, _message, #condition); \
+ } \
+ } while (0)
+
+/**
+ * Unconditionally fails the current function.
+ *
+ * Unlike assert(3) or NSAssert, this macro is never compiled out.
+ *
+ * @param format A format string suitable for util::StringFormat.
+ * @param ... format arguments to pass to util::StringFormat.
+ */
+#define HARD_FAIL(...) \
+ do { \
+ std::string _failure = \
+ firebase::firestore::util::StringFormat(__VA_ARGS__); \
+ firebase::firestore::util::internal::Fail(__FILE__, __PRETTY_FUNCTION__, \
+ __LINE__, _failure); \
+ } while (0)
+
+/**
+ * Indicates an area of the code that cannot be reached (except possibly due to
+ * undefined behaviour or other similar badness). The only reasonable thing to
+ * do in these cases is to immediately abort.
+ */
+#define UNREACHABLE() abort()
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace internal {
+
+// A no-return helper function. To raise an assertion, use Macro instead.
+ABSL_ATTRIBUTE_NORETURN void Fail(const char* file,
+ const char* func,
+ int line,
+ const std::string& message);
+
+ABSL_ATTRIBUTE_NORETURN void Fail(const char* file,
+ const char* func,
+ int line,
+ const std::string& message,
+ const char* condition);
+
+} // namespace internal
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HARD_ASSERT_H_
diff --git a/Firestore/core/src/firebase/firestore/util/assert_apple.mm b/Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm
index 9b6a651..3324fe8 100644
--- a/Firestore/core/src/firebase/firestore/util/assert_apple.mm
+++ b/Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm
@@ -14,36 +14,47 @@
* limitations under the License.
*/
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
+
#import <Foundation/Foundation.h>
-// TODO(wilhuff): match basenames so this can move up top
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include <string>
+
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
namespace firebase {
namespace firestore {
namespace util {
+namespace internal {
-void FailAssert(const char* file,
- const char* func,
- const int line,
- const char* format,
- ...) {
- va_list args;
- va_start(args, format);
- NSString* description =
- [[NSString alloc] initWithFormat:WrapNSStringNoCopy(format)
- arguments:args];
- va_end(args);
+void Fail(const char* file,
+ const char* func,
+ const int line,
+ const std::string& message) {
[[NSAssertionHandler currentHandler]
handleFailureInFunction:WrapNSStringNoCopy(func)
file:WrapNSStringNoCopy(file)
lineNumber:line
- description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@",
- description];
+ description:@"FIRESTORE INTERNAL ASSERTION FAILED: %s",
+ message.c_str()];
abort();
}
+void Fail(const char* file,
+ const char* func,
+ const int line,
+ const std::string& message,
+ const char* condition) {
+ std::string failure;
+ if (message.empty()) {
+ failure = condition;
+ } else {
+ failure = StringFormat("%s (expected %s)", message, condition);
+ }
+ Fail(file, func, line, failure);
+}
+
+} // namespace internal
} // namespace util
} // namespace firestore
} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/assert_stdio.cc b/Firestore/core/src/firebase/firestore/util/hard_assert_stdio.cc
index e01e564..6c50eb7 100644
--- a/Firestore/core/src/firebase/firestore/util/assert_stdio.cc
+++ b/Firestore/core/src/firebase/firestore/util/hard_assert_stdio.cc
@@ -14,40 +14,51 @@
* limitations under the License.
*/
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
+
#include <cstdarg>
#include <stdexcept>
#include <string>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
-#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
#include "absl/base/config.h"
namespace firebase {
namespace firestore {
namespace util {
+namespace internal {
-void FailAssert(const char* file,
- const char* func,
- const int line,
- const char* format,
- ...) {
- std::string message;
- StringAppendF(&message, "ASSERT: %s(%d) %s: ", file, line, func);
-
- va_list args;
- va_start(args, format);
- StringAppendV(&message, format, args);
- va_end(args);
+void Fail(const char* file,
+ const char* func,
+ const int line,
+ const std::string& message) {
+ std::string failure =
+ StringFormat("ASSERT: %s(%s) %s: %s", file, line, func, message);
#if ABSL_HAVE_EXCEPTIONS
- throw std::logic_error(message);
+ throw std::logic_error(failure);
#else
- fprintf(stderr, "%s\n", message.c_str());
+ fprintf(stderr, "%s\n", failure.c_str());
std::terminate();
#endif
}
+void Fail(const char* file,
+ const char* func,
+ const int line,
+ const std::string& message,
+ const char* condition) {
+ std::string failure;
+ if (message.empty()) {
+ failure = condition;
+ } else {
+ failure = StringFormat("%s (expected %s)", message, condition);
+ }
+ Fail(file, func, line, failure);
+}
+
+} // namespace internal
} // namespace util
} // namespace firestore
} // namespace firebase
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/ordered_code.cc b/Firestore/core/src/firebase/firestore/util/ordered_code.cc
index cb53b09..03da08d 100644
--- a/Firestore/core/src/firebase/firestore/util/ordered_code.cc
+++ b/Firestore/core/src/firebase/firestore/util/ordered_code.cc
@@ -17,7 +17,7 @@
#include "Firestore/core/src/firebase/firestore/util/ordered_code.h"
#include "Firestore/core/src/firebase/firestore/util/bits.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/base/internal/endian.h"
#include "absl/base/internal/unaligned_access.h"
#include "absl/base/port.h"
@@ -99,20 +99,20 @@ inline static bool IsSpecialByte(char c) {
* assertion checking).
*/
inline static int AdvanceIfNoSpecialBytes(uint32_t v_32, const char* p) {
- FIREBASE_DEV_ASSERT(UNALIGNED_LOAD32(p) == v_32);
+ HARD_ASSERT(UNALIGNED_LOAD32(p) == v_32);
// See comments in SkipToNextSpecialByte if you wish to
// understand this expression (which checks for the occurrence
// of the special byte values 0 or 255 in any of the bytes of v_32).
if ((v_32 - 0x01010101u) & ~(v_32 + 0x01010101u) & 0x80808080u) {
// Special byte is in p[0..3]
- FIREBASE_DEV_ASSERT(IsSpecialByte(p[0]) || IsSpecialByte(p[1]) ||
- IsSpecialByte(p[2]) || IsSpecialByte(p[3]));
+ HARD_ASSERT(IsSpecialByte(p[0]) || IsSpecialByte(p[1]) ||
+ IsSpecialByte(p[2]) || IsSpecialByte(p[3]));
return 0;
} else {
- FIREBASE_DEV_ASSERT(!IsSpecialByte(p[0]));
- FIREBASE_DEV_ASSERT(!IsSpecialByte(p[1]));
- FIREBASE_DEV_ASSERT(!IsSpecialByte(p[2]));
- FIREBASE_DEV_ASSERT(!IsSpecialByte(p[3]));
+ HARD_ASSERT(!IsSpecialByte(p[0]));
+ HARD_ASSERT(!IsSpecialByte(p[1]));
+ HARD_ASSERT(!IsSpecialByte(p[2]));
+ HARD_ASSERT(!IsSpecialByte(p[3]));
return 4;
}
}
@@ -125,8 +125,8 @@ inline static int AdvanceIfNoSpecialBytes(uint32_t v_32, const char* p) {
inline static const char* SkipToNextSpecialByte(const char* start,
const char* limit) {
// If these constants were ever changed, this routine needs to change
- FIREBASE_DEV_ASSERT(kEscape1 == 0);
- FIREBASE_DEV_ASSERT((kEscape2 & 0xff) == 255);
+ HARD_ASSERT(kEscape1 == 0);
+ HARD_ASSERT((kEscape2 & 0xff) == 255);
const char* p = start;
while (p + 8 <= limit) {
// Find out if any of the next 8 bytes are either 0 or 255 (our
@@ -164,8 +164,7 @@ inline static const char* SkipToNextSpecialByte(const char* start,
if (IsSpecialByte(p[0])) return p;
if (IsSpecialByte(p[1])) return p + 1;
if (IsSpecialByte(p[2])) return p + 2;
- FIREBASE_DEV_ASSERT(
- IsSpecialByte(p[3])); // Last byte must be the special one
+ HARD_ASSERT(IsSpecialByte(p[3])); // Last byte must be the special one
return p + 3;
}
}
@@ -198,14 +197,14 @@ inline static void EncodeStringFragment(std::string* dest,
p = SkipToNextSpecialByte(p, limit);
if (p >= limit) break; // No more special characters that need escaping
char c = *(p++);
- FIREBASE_DEV_ASSERT(IsSpecialByte(c));
+ HARD_ASSERT(IsSpecialByte(c));
if (c == kEscape1) {
AppendBytes(dest, copy_start, static_cast<size_t>(p - copy_start) - 1);
dest->push_back(kEscape1);
dest->push_back(kNullCharacter);
copy_start = p;
} else {
- FIREBASE_DEV_ASSERT(c == kEscape2);
+ HARD_ASSERT(c == kEscape2);
AppendBytes(dest, copy_start, static_cast<size_t>(p - copy_start) - 1);
dest->push_back(kEscape2);
dest->push_back(kFFCharacter);
@@ -302,7 +301,7 @@ inline static bool ReadStringInternal(absl::string_view* src,
// If inversion is required, instead of inverting 'c', we invert the
// character constants to which 'c' is compared. We get the same
// behavior but save the runtime cost of inverting 'c'.
- FIREBASE_DEV_ASSERT(IsSpecialByte(c));
+ HARD_ASSERT(IsSpecialByte(c));
if (c == kEscape1) {
if (result) {
AppendBytes(result, copy_start,
@@ -323,7 +322,7 @@ inline static bool ReadStringInternal(absl::string_view* src,
}
copy_start = start;
} else {
- FIREBASE_DEV_ASSERT(c == kEscape2);
+ HARD_ASSERT(c == kEscape2);
if (result) {
AppendBytes(result, copy_start,
static_cast<size_t>(start - copy_start) - 1);
@@ -359,7 +358,7 @@ bool OrderedCode::ReadNumIncreasing(absl::string_view* src, uint64_t* result) {
// If len > 0 and src is longer than 1, the first byte of "payload"
// must be non-zero (otherwise the encoding is not minimal).
// In opt mode, we don't enforce that encodings must be minimal.
- FIREBASE_DEV_ASSERT(0 == len || src->size() == 1 || (*src)[1] != '\0');
+ HARD_ASSERT(0 == len || src->size() == 1 || (*src)[1] != '\0');
if (len + 1 > src->size() || len > 8) {
return false; // Not enough bytes or too many bytes
@@ -557,11 +556,9 @@ void OrderedCode::WriteSignedNumIncreasing(std::string* dest, int64_t val) {
};
UNALIGNED_STORE64(buf + 2, absl::ghtonll(static_cast<uint64_t>(val)));
- FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(sizeof(buf) == kMaxSigned64Length,
- sizeof(buf) == kMaxSigned64Length,
- "max length size mismatch");
+ HARD_ASSERT(sizeof(buf) == kMaxSigned64Length, "max length size mismatch");
const size_t len = static_cast<size_t>(SignedEncodingLengthPositive(x));
- FIREBASE_DEV_ASSERT(len >= 2);
+ HARD_ASSERT(len >= 2);
char* const begin = buf + sizeof(buf) - len;
begin[0] ^= kLengthToHeaderBits[len][0];
begin[1] ^= kLengthToHeaderBits[len][1]; // ok because len >= 2
@@ -608,8 +605,8 @@ bool OrderedCode::ReadSignedNumIncreasing(absl::string_view* src,
x ^= kLengthToMask[len]; // remove spurious header bits
- FIREBASE_DEV_ASSERT(len == static_cast<size_t>(SignedEncodingLength(
- static_cast<int64_t>(x))));
+ HARD_ASSERT(len == static_cast<size_t>(
+ SignedEncodingLength(static_cast<int64_t>(x))));
if (result) *result = static_cast<int64_t>(x);
src->remove_prefix(static_cast<size_t>(len));
diff --git a/Firestore/core/src/firebase/firestore/util/status.cc b/Firestore/core/src/firebase/firestore/util/status.cc
index 662fa5d..46f3ce6 100644
--- a/Firestore/core/src/firebase/firestore/util/status.cc
+++ b/Firestore/core/src/firebase/firestore/util/status.cc
@@ -16,14 +16,14 @@
#include "Firestore/core/src/firebase/firestore/util/status.h"
-#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
namespace firebase {
namespace firestore {
namespace util {
Status::Status(FirestoreErrorCode code, absl::string_view msg) {
- FIREBASE_ASSERT(code != FirestoreErrorCode::Ok);
+ HARD_ASSERT(code != FirestoreErrorCode::Ok);
state_ = std::unique_ptr<State>(new State);
state_->code = code;
state_->msg = static_cast<std::string>(msg);
@@ -103,7 +103,7 @@ std::string Status::ToString() const {
result = "Data loss";
break;
default:
- result = StringPrintf("Unknown code(%d)", static_cast<int>(code()));
+ result = StringFormat("Unknown code(%s)", code());
break;
}
result += ": ";
@@ -117,7 +117,7 @@ void Status::IgnoreError() const {
}
std::string StatusCheckOpHelperOutOfLine(const Status& v, const char* msg) {
- FIREBASE_ASSERT(!v.ok());
+ HARD_ASSERT(!v.ok());
std::string r("Non-OK-status: ");
r += msg;
r += " status: ";
diff --git a/Firestore/core/src/firebase/firestore/util/status.h b/Firestore/core/src/firebase/firestore/util/status.h
index 13bf320..9121b36 100644
--- a/Firestore/core/src/firebase/firestore/util/status.h
+++ b/Firestore/core/src/firebase/firestore/util/status.h
@@ -23,7 +23,7 @@
#include <string>
#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "absl/base/attributes.h"
#include "absl/strings/string_view.h"
@@ -124,15 +124,8 @@ typedef std::function<void(const Status&)> StatusCallback;
extern std::string StatusCheckOpHelperOutOfLine(const Status& v,
const char* msg);
-#define STATUS_CHECK_OK(val) \
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION( \
- val.ok(), val.ok(), StatusCheckOpHelperOutOfLine(val, #val).c_str())
-
-// DEBUG only version of STATUS_CHECK_OK. Compiler still parses 'val' even in
-// opt mode.
-#define STATUS_DCHECK_OK(val) \
- FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION( \
- val.ok(), val.ok(), StatusCheckOpHelperOutOfLine(val, #val).c_str())
+#define STATUS_CHECK_OK(val) \
+ HARD_ASSERT(val.ok(), "%s", StatusCheckOpHelperOutOfLine(val, #val))
} // namespace util
} // namespace firestore
diff --git a/Firestore/core/src/firebase/firestore/util/statusor.cc b/Firestore/core/src/firebase/firestore/util/statusor.cc
index be1e03a..bbd5781 100644
--- a/Firestore/core/src/firebase/firestore/util/statusor.cc
+++ b/Firestore/core/src/firebase/firestore/util/statusor.cc
@@ -15,6 +15,7 @@
*/
#include "Firestore/core/src/firebase/firestore/util/statusor.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -24,15 +25,14 @@ namespace internal_statusor {
void Helper::HandleInvalidStatusCtorArg(Status* status) {
const char* kMessage =
"An OK status is not a valid constructor argument to StatusOr<T>";
- FIREBASE_DEV_ASSERT_MESSAGE(false, kMessage);
+ HARD_FAIL("%s", kMessage);
// Fall back to Internal for non-debug builds
*status = Status(FirestoreErrorCode::Internal, kMessage);
}
void Helper::Crash(const Status& status) {
- FIREBASE_ASSERT_MESSAGE(
- false, "Attempting to fetch value instead of handling error ",
- status.ToString().c_str());
+ HARD_FAIL("Attempting to fetch value instead of handling error %s",
+ status.ToString());
}
} // namespace internal_statusor
diff --git a/Firestore/core/src/firebase/firestore/util/string_format.cc b/Firestore/core/src/firebase/firestore/util/string_format.cc
new file mode 100644
index 0000000..bafdac2
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_format.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+namespace internal {
+
+static const char* kMissing = "<missing>";
+static const char* kInvalid = "<invalid>";
+
+std::string StringFormatPieces(
+ const char* format, std::initializer_list<absl::string_view> pieces) {
+ std::string result;
+
+ const char* format_iter = format;
+ const char* format_end = format + strlen(format);
+
+ auto pieces_iter = pieces.begin();
+ auto pieces_end = pieces.end();
+ auto append_next_piece = [&](std::string* dest) {
+ if (pieces_iter == pieces_end) {
+ dest->append(kMissing);
+ } else {
+ // Pass a piece through
+ dest->append(pieces_iter->data(), pieces_iter->size());
+ ++pieces_iter;
+ }
+ };
+
+ auto append_specifier = [&](char spec) {
+ switch (spec) {
+ case '%':
+ // Pass through literal %.
+ result.push_back('%');
+ break;
+
+ case 's': {
+ append_next_piece(&result);
+ break;
+ }
+
+ default:
+ result.append(kInvalid);
+ break;
+ }
+ };
+
+ // Iterate through the format string, advancing `format_iter` as we go.
+ while (true) {
+ const char* percent_ptr = std::find(format_iter, format_end, '%');
+
+ // percent either points to the next format specifier or the end of the
+ // format string. Either is safe to append here:
+ result.append(format_iter, percent_ptr);
+ if (percent_ptr == format_end) {
+ // No further pieces to format
+ break;
+ }
+
+ // Examine the specifier:
+ const char* spec_ptr = percent_ptr + 1;
+ if (spec_ptr == format_end) {
+ // Incomplete specifier, treat as a literal "%" and be done.
+ append_specifier('%');
+ break;
+ }
+ append_specifier(*spec_ptr);
+
+ format_iter = spec_ptr + 1;
+ }
+
+ return result;
+}
+
+} // namespace internal
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/string_format.h b/Firestore/core/src/firebase/firestore/util/string_format.h
new file mode 100644
index 0000000..f8da785
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/util/string_format.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_
+
+#include <initializer_list>
+#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"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+namespace internal {
+
+std::string StringFormatPieces(const char* format,
+ std::initializer_list<absl::string_view> pieces);
+
+/**
+ * Explicit ranking for formatting choices. Only useful as an implementation
+ * detail of `FormatArg`.
+ */
+template <int I>
+struct FormatChoice : FormatChoice<I + 1> {};
+
+template <>
+struct FormatChoice<4> {};
+
+} // namespace internal
+
+/**
+ * Acts as the main value parameter to StringFormat and related functions.
+ *
+ * Chooses a conversion to a text form in this order:
+ * * If the value is exactly of `bool` type (without implicit conversions)
+ * the text will the "true" or "false".
+ * * If the value is of type `const char*`, the text will be the value
+ * interpreted as a C string. To show the address of a single char or to
+ * show the `const char*` as an address, cast to `void*`.
+ * * If the value is any other pointer type, the text will be the hexidecimal
+ * formatting of the value as an unsigned integer.
+ * * Otherwise the value is interpreted as anything absl::AlphaNum accepts.
+ */
+class FormatArg : public absl::AlphaNum {
+ public:
+ template <typename T>
+ FormatArg(T&& value) // NOLINT(runtime/explicit)
+ : FormatArg{std::forward<T>(value), internal::FormatChoice<0>{}} {
+ }
+
+#if __OBJC__
+ FormatArg(NSObject* object) // NOLINT(runtime/explicit)
+ : AlphaNum{MakeStringView([object description])} {
+ }
+#endif
+
+ private:
+ /**
+ * Creates a FormatArg from a boolean value, representing the string
+ * "true" or "false".
+ *
+ * This overload only applies if the type of the argument is exactly `bool`.
+ * No implicit conversions to bool are accepted.
+ */
+ template <typename T,
+ typename = typename std::enable_if<std::is_same<bool, T>{}>::type>
+ FormatArg(T bool_value, internal::FormatChoice<0>)
+ : AlphaNum{bool_value ? "true" : "false"} {
+ }
+
+ /**
+ * Creates a FormatArg from a character string literal. This is
+ * handled specially to avoid ambiguity with generic pointers, which are
+ * handled differently.
+ */
+ FormatArg(std::nullptr_t, internal::FormatChoice<1>) : AlphaNum{"null"} {
+ }
+
+ /**
+ * Creates a FormatArg from a character string literal. This is
+ * handled specially to avoid ambiguity with generic pointers, which are
+ * handled differently.
+ */
+ FormatArg(const char* string_value, internal::FormatChoice<2>)
+ : AlphaNum{string_value == nullptr ? "null" : string_value} {
+ }
+
+ /**
+ * Creates a FormatArg from an arbitrary pointer, represented as a
+ * hexidecimal integer literal.
+ */
+ template <typename T>
+ FormatArg(T* pointer_value, internal::FormatChoice<3>)
+ : AlphaNum{absl::Hex{reinterpret_cast<uintptr_t>(pointer_value)}} {
+ }
+
+ /**
+ * As a final fallback, creates a FormatArg from any type of value that
+ * absl::AlphaNum accepts.
+ */
+ template <typename T>
+ FormatArg(T&& value, internal::FormatChoice<4>)
+ : AlphaNum{std::forward<T>(value)} {
+ }
+};
+
+/**
+ * Formats a string using a simplified printf-like formatting mechanism that
+ * does not rely on C varargs.
+ *
+ * The following format specifiers are recognized:
+ * * "%%" - A literal "%"
+ * * "%s" - The next parameter is copied through
+ *
+ * Note:
+ * * If you pass fewer arguments than the format requires, StringFormat will
+ * insert "<missing>".
+ * * If you pass more arguments than the format requires, any excess arguments
+ * are ignored.
+ * * If you use an invalid format specifier, StringFormat will insert
+ * <invalid>.
+ */
+template <typename... FA>
+std::string StringFormat(const char* format, const FA&... args) {
+ return internal::StringFormatPieces(
+ format, {static_cast<const FormatArg&>(args).Piece()...});
+}
+
+inline std::string StringFormat() {
+ return {};
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_
diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.cc b/Firestore/core/src/firebase/firestore/util/string_printf.cc
deleted file mode 100644
index c5483f4..0000000
--- a/Firestore/core/src/firebase/firestore/util/string_printf.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2018 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
-
-#include <cstdio>
-
-namespace firebase {
-namespace firestore {
-namespace util {
-
-void StringAppendV(std::string* dst, const char* format, va_list ap) {
- // First try with a small fixed size buffer
- static const int kSpaceLength = 1024;
- char space[kSpaceLength];
-
- // It's possible for methods that use a va_list to invalidate
- // the data in it upon use. The fix is to make a copy
- // of the structure before using it and use that copy instead.
- va_list backup_ap;
- va_copy(backup_ap, ap);
- int result = vsnprintf(space, kSpaceLength, format, backup_ap);
- va_end(backup_ap);
-
- if (result < kSpaceLength) {
- if (result >= 0) {
- // Normal case -- everything fit.
- dst->append(space, static_cast<size_t>(result));
- return;
- }
-
-#ifdef _MSC_VER
- // Error or MSVC running out of space. MSVC 8.0 and higher
- // can be asked about space needed with the special idiom below:
- va_copy(backup_ap, ap);
- result = vsnprintf(nullptr, 0, format, backup_ap);
- va_end(backup_ap);
-#endif
- }
-
- if (result < 0) {
- // Just an error.
- return;
- }
- size_t result_size = static_cast<size_t>(result);
-
- // Increase the buffer size to the size requested by vsnprintf,
- // plus one for the closing \0.
- size_t initial_size = dst->size();
- size_t target_size = initial_size + result_size;
-
- dst->resize(target_size + 1);
- char* buf = &(*dst)[initial_size];
- size_t buf_remain = result_size + 1;
-
- // Restore the va_list before we use it again
- va_copy(backup_ap, ap);
- result = vsnprintf(buf, buf_remain, format, backup_ap);
- va_end(backup_ap);
-
- if (result >= 0 && static_cast<size_t>(result) < buf_remain) {
- // It fit and vsnprintf copied in directly. Resize down one to
- // remove the trailing \0.
- dst->resize(target_size);
- } else {
- // Didn't fit. Leave the original string unchanged.
- dst->resize(initial_size);
- }
-}
-
-std::string StringPrintf(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- std::string result;
- StringAppendV(&result, format, ap);
- va_end(ap);
- return result;
-}
-
-void StringAppendF(std::string* dst, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- StringAppendV(dst, format, ap);
- va_end(ap);
-}
-
-} // namespace util
-} // namespace firestore
-} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.h b/Firestore/core/src/firebase/firestore/util/string_printf.h
deleted file mode 100644
index 553af66..0000000
--- a/Firestore/core/src/firebase/firestore/util/string_printf.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
-#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
-
-#include <cstdarg>
-#include <string>
-
-#include "absl/base/attributes.h"
-
-namespace firebase {
-namespace firestore {
-namespace util {
-
-/** Return a C++ string. */
-std::string StringPrintf(const char* format, ...) ABSL_PRINTF_ATTRIBUTE(1, 2);
-
-/** Append result to a supplied string. */
-void StringAppendF(std::string* dst, const char* format, ...)
- ABSL_PRINTF_ATTRIBUTE(2, 3);
-
-/**
- * Lower-level routine that takes a va_list and appends to a specified
- * string. All other routines are just convenience wrappers around it.
- */
-void StringAppendV(std::string* dst, const char* format, va_list ap);
-
-} // namespace util
-} // namespace firestore
-} // namespace firebase
-
-#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_
diff --git a/Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm b/Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm
index ec14880..c87949a 100644
--- a/Firestore/Example/Tests/GoogleTest/FSTGoogleTestTests.mm
+++ b/Firestore/core/test/firebase/firestore/FSTGoogleTestTests.mm
@@ -22,53 +22,60 @@
#include "gtest/gtest.h"
/**
- * An XCTest test case that finds C++ test cases written in the GoogleTest framework, runs them, and
- * reports the results back to Xcode. This allows tests written in C++ that don't rely on XCTest to
- * coexist in this project.
+ * An XCTest test case that finds C++ test cases written in the GoogleTest
+ * framework, runs them, and reports the results back to Xcode. This allows
+ * tests written in C++ that don't rely on XCTest to coexist in this project.
*
- * As an extra feature, you can run all C++ tests by focusing on the GoogleTests class.
+ * As an extra feature, you can run all C++ tests by focusing on the GoogleTests
+ * class.
*
- * Each GoogleTest TestCase is mapped to a dynamically generated XCTestCase class. Each GoogleTest
- * TEST() is mapped to a test method on that XCTestCase.
+ * Each GoogleTest TestCase is mapped to a dynamically generated XCTestCase
+ * class. Each GoogleTest TEST() is mapped to a test method on that XCTestCase.
*/
@interface GoogleTests : XCTestCase
@end
namespace {
-// A testing::TestCase named "Foo" corresponds to an XCTestCase named "FooTests".
+// A testing::TestCase named "Foo" corresponds to an XCTestCase named
+// "FooTests".
NSString *const kTestCaseSuffix = @"Tests";
// A testing::TestInfo named "Foo" corresponds to test method named "testFoo".
NSString *const kTestMethodPrefix = @"test";
-// A map of keys created by TestInfoKey to the corresponding testing::TestInfo (wrapped in an
-// NSValue). The generated XCTestCase classes are discovered and instantiated by XCTest so this is
-// the only means of plumbing per-test-method state into these methods.
+// A map of keys created by TestInfoKey to the corresponding testing::TestInfo
+// (wrapped in an NSValue). The generated XCTestCase classes are discovered and
+// instantiated by XCTest so this is the only means of plumbing per-test-method
+// state into these methods.
NSDictionary<NSString *, NSValue *> *testInfosByKey;
-// If the user focuses on GoogleTests itself, this means force all C++ tests to run.
+// If the user focuses on GoogleTests itself, this means force all C++ tests to
+// run.
BOOL forceAllTests = NO;
/**
- * Loads this XCTest runner's configuration file and figures out which tests to run based on the
- * contents of that configuration file.
+ * Loads this XCTest runner's configuration file and figures out which tests to
+ * run based on the contents of that configuration file.
*
- * @return the set of tests to run, or nil if the user asked for all tests or if there's any
- * problem loading or parsing the configuration.
+ * @return the set of tests to run, or nil if the user asked for all tests or if
+ * there's any problem loading or parsing the configuration.
*/
NSSet<NSString *> *_Nullable LoadXCTestConfigurationTestsToRun() {
- // Xcode invokes the test runner with an XCTestConfigurationFilePath environment variable set to
- // the path of a configuration file containing, among other things, the set of tests to run. The
- // configuration file deserializes to a non-public XCTestConfiguration class.
+ // Xcode invokes the test runner with an XCTestConfigurationFilePath
+ // environment variable set to the path of a configuration file containing,
+ // among other things, the set of tests to run. The configuration file
+ // deserializes to a non-public XCTestConfiguration class.
//
- // This loads that file and then reflectively pulls out the testsToRun set. Just in case any of
- // these private details should change in the future and something should fail here, the mechanism
- // complains but fails open. This way the worst that can happen is that users end up running more
- // tests than they intend, but we never accidentally show a green run that wasn't.
+ // This loads that file and then reflectively pulls out the testsToRun set.
+ // Just in case any of these private details should change in the future and
+ // something should fail here, the mechanism complains but fails open. This
+ // way the worst that can happen is that users end up running more tests than
+ // they intend, but we never accidentally show a green run that wasn't.
static NSString *const configEnvVar = @"XCTestConfigurationFilePath";
- NSDictionary<NSString *, NSString *> *env = [[NSProcessInfo processInfo] environment];
+ NSDictionary<NSString *, NSString *> *env =
+ [[NSProcessInfo processInfo] environment];
NSString *filePath = [env objectForKey:configEnvVar];
if (!filePath) {
NSLog(@"Missing %@ environment variable; assuming all tests", configEnvVar);
@@ -77,27 +84,32 @@ NSSet<NSString *> *_Nullable LoadXCTestConfigurationTestsToRun() {
id config = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
if (!config) {
- NSLog(@"Failed to load any configuaration from %@=%@", configEnvVar, filePath);
+ NSLog(@"Failed to load any configuaration from %@=%@", configEnvVar,
+ filePath);
return nil;
}
SEL testsToRunSelector = NSSelectorFromString(@"testsToRun");
if (![config respondsToSelector:testsToRunSelector]) {
- NSLog(@"Invalid configuaration from %@=%@: missing testsToRun", configEnvVar, filePath);
+ NSLog(@"Invalid configuaration from %@=%@: missing testsToRun",
+ configEnvVar, filePath);
return nil;
}
- // Invoke the testsToRun selector safely. This indirection is required because just calling
- // -performSelector: fails to properly retain the NSSet under ARC.
+ // Invoke the testsToRun selector safely. This indirection is required because
+ // just calling -performSelector: fails to properly retain the NSSet under
+ // ARC.
typedef NSSet<NSString *> *(*TestsToRunFunction)(id, SEL);
IMP testsToRunMethod = [config methodForSelector:testsToRunSelector];
- auto testsToRunFunction = reinterpret_cast<TestsToRunFunction>(testsToRunMethod);
+ auto testsToRunFunction =
+ reinterpret_cast<TestsToRunFunction>(testsToRunMethod);
return testsToRunFunction(config, testsToRunSelector);
}
/**
- * Creates a GoogleTest filter specification, suitable for passing to the --gtest_filter flag,
- * that limits GoogleTest to running the same set of tests that Xcode requested.
+ * Creates a GoogleTest filter specification, suitable for passing to the
+ * --gtest_filter flag, that limits GoogleTest to running the same set of tests
+ * that Xcode requested.
*
* Each member of the testsToRun set is mapped as follows:
*
@@ -106,7 +118,8 @@ NSSet<NSString *> *_Nullable LoadXCTestConfigurationTestsToRun() {
*
* These members are then joined with a ":" as googletest requires.
*
- * @see https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md
+ * @see
+ * https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md
*/
NSString *CreateTestFiltersFromTestsToRun(NSSet<NSString *> *testsToRun) {
NSMutableString *result = [[NSMutableString alloc] init];
@@ -117,7 +130,8 @@ NSString *CreateTestFiltersFromTestsToRun(NSSet<NSString *> *testsToRun) {
if (parts.count > 0) {
NSString *className = parts[0];
if ([className hasSuffix:kTestCaseSuffix]) {
- gtestCaseName = [className substringToIndex:className.length - kTestCaseSuffix.length];
+ gtestCaseName = [className
+ substringToIndex:className.length - kTestCaseSuffix.length];
}
}
@@ -125,7 +139,8 @@ NSString *CreateTestFiltersFromTestsToRun(NSSet<NSString *> *testsToRun) {
if (parts.count > 1) {
NSString *methodName = parts[1];
if ([methodName hasPrefix:kTestMethodPrefix]) {
- gtestMethodName = [methodName substringFromIndex:kTestMethodPrefix.length];
+ gtestMethodName =
+ [methodName substringFromIndex:kTestMethodPrefix.length];
}
}
@@ -142,9 +157,11 @@ NSString *CreateTestFiltersFromTestsToRun(NSSet<NSString *> *testsToRun) {
return result;
}
-/** Returns the name of the selector for the test method representing this specific test. */
+/** Returns the name of the selector for the test method representing this
+ * specific test. */
NSString *SelectorNameForTestInfo(const testing::TestInfo *testInfo) {
- return [NSString stringWithFormat:@"%@%s", kTestMethodPrefix, testInfo->name()];
+ return
+ [NSString stringWithFormat:@"%@%s", kTestMethodPrefix, testInfo->name()];
}
/** Returns the name of the class representing the given testing::TestCase. */
@@ -153,21 +170,22 @@ NSString *ClassNameForTestCase(const testing::TestCase *testCase) {
}
/**
- * Returns a key name for the testInfosByKey dictionary. Each (class, selector) pair corresponds
- * to a unique GoogleTest result.
+ * Returns a key name for the testInfosByKey dictionary. Each (class, selector)
+ * pair corresponds to a unique GoogleTest result.
*/
NSString *TestInfoKey(Class testClass, SEL testSelector) {
- return [NSString
- stringWithFormat:@"%@.%@", NSStringFromClass(testClass), NSStringFromSelector(testSelector)];
+ return [NSString stringWithFormat:@"%@.%@", NSStringFromClass(testClass),
+ NSStringFromSelector(testSelector)];
}
/**
- * Looks up the testing::TestInfo for this test method and reports on the outcome to XCTest, as if
- * the test actually ran in this method.
+ * Looks up the testing::TestInfo for this test method and reports on the
+ * outcome to XCTest, as if the test actually ran in this method.
*
- * Note: this function is the implementation for each generated test method. It shouldn't be used
- * directly. The parameter names of self and _cmd match up with the implicit parameters passed to
- * any Objective-C method. Naming them this way here allows XCTAssert and friends to work.
+ * Note: this function is the implementation for each generated test method. It
+ * shouldn't be used directly. The parameter names of self and _cmd match up
+ * with the implicit parameters passed to any Objective-C method. Naming them
+ * this way here allows XCTAssert and friends to work.
*/
void ReportTestResult(XCTestCase *self, SEL _cmd) {
NSString *testInfoKey = TestInfoKey([self class], _cmd);
@@ -189,31 +207,38 @@ void ReportTestResult(XCTestCase *self, SEL _cmd) {
return;
}
- // Test failed :-(. Record the failure such that XCode will navigate directly to the file:line.
+ // Test failed :-(. Record the failure such that XCode will navigate directly
+ // to the file:line.
int parts = result->total_part_count();
for (int i = 0; i < parts; i++) {
const testing::TestPartResult &part = result->GetTestPartResult(i);
- [self recordFailureWithDescription:@(part.message())
- inFile:@(part.file_name() ? part.file_name() : "")
- atLine:(part.line_number() > 0 ? part.line_number() : 0)
- expected:YES];
+ [self
+ recordFailureWithDescription:@(part.message())
+ inFile:@(part.file_name() ? part.file_name() : "")
+ atLine:(part.line_number() > 0
+ ? part.line_number()
+ : 0)
+ expected:YES];
}
}
/**
- * Generates a new subclass of XCTestCase for the given GoogleTest TestCase. Each TestInfo (which
- * represents an indivudal test method execution) is translated into a method on the test case.
+ * Generates a new subclass of XCTestCase for the given GoogleTest TestCase.
+ * Each TestInfo (which represents an indivudal test method execution) is
+ * translated into a method on the test case.
*
* @param The testing::TestCase of interest to translate.
* @param A map of TestInfoKeys to testing::TestInfos, populated by this method.
*
- * @return A new Class that's a subclass of XCTestCase, that's been registered with the Objective-C
- * runtime.
+ * @return A new Class that's a subclass of XCTestCase, that's been registered
+ * with the Objective-C runtime.
*/
-Class CreateXCTestCaseClass(const testing::TestCase *testCase,
- NSMutableDictionary<NSString *, NSValue *> *infoMap) {
+Class CreateXCTestCaseClass(
+ const testing::TestCase *testCase,
+ NSMutableDictionary<NSString *, NSValue *> *infoMap) {
NSString *testCaseName = ClassNameForTestCase(testCase);
- Class testClass = objc_allocateClassPair([XCTestCase class], [testCaseName UTF8String], 0);
+ Class testClass =
+ objc_allocateClassPair([XCTestCase class], [testCaseName UTF8String], 0);
// Create a method for each TestInfo.
int testInfos = testCase->total_test_count();
@@ -223,8 +248,9 @@ Class CreateXCTestCaseClass(const testing::TestCase *testCase,
NSString *selectorName = SelectorNameForTestInfo(testInfo);
SEL selector = sel_registerName([selectorName UTF8String]);
- // Use the ReportTestResult function as the method implementation. The v@: indicates it is a
- // void objective-C method; this must continue to match the signature of ReportTestResult.
+ // Use the ReportTestResult function as the method implementation. The v@:
+ // indicates it is a void objective-C method; this must continue to match
+ // the signature of ReportTestResult.
IMP method = reinterpret_cast<IMP>(ReportTestResult);
class_addMethod(testClass, selector, method, "v@:");
@@ -238,16 +264,20 @@ Class CreateXCTestCaseClass(const testing::TestCase *testCase,
}
/**
- * Creates a test suite containing all C++ tests, used when the user starts the GoogleTests class.
+ * Creates a test suite containing all C++ tests, used when the user starts the
+ * GoogleTests class.
*
- * Note: normally XCTest finds all the XCTestCase classes that are registered with the run time
- * and asks them to create suites for themselves. When a user focuses on the GoogleTests class,
- * XCTest no longer does this so we have to force XCTest to see more tests than it would normally
- * look at so that the indicators in the test navigator update properly.
+ * Note: normally XCTest finds all the XCTestCase classes that are registered
+ * with the run time and asks them to create suites for themselves. When a user
+ * focuses on the GoogleTests class, XCTest no longer does this so we have to
+ * force XCTest to see more tests than it would normally look at so that the
+ * indicators in the test navigator update properly.
*/
XCTestSuite *CreateAllTestsTestSuite() {
- XCTestSuite *allTestsSuite = [[XCTestSuite alloc] initWithName:@"All GoogleTest Tests"];
- [allTestsSuite addTest:[XCTestSuite testSuiteForTestCaseClass:[GoogleTests class]]];
+ XCTestSuite *allTestsSuite =
+ [[XCTestSuite alloc] initWithName:@"All GoogleTest Tests"];
+ [allTestsSuite
+ addTest:[XCTestSuite testSuiteForTestCaseClass:[GoogleTests class]]];
const testing::UnitTest *master = testing::UnitTest::GetInstance();
@@ -263,8 +293,8 @@ XCTestSuite *CreateAllTestsTestSuite() {
}
/**
- * Finds and runs googletest-based tests based on the XCTestConfiguration of the current test
- * invocation.
+ * Finds and runs googletest-based tests based on the XCTestConfiguration of the
+ * current test invocation.
*/
void RunGoogleTestTests() {
NSString *masterTestCaseName = NSStringFromClass([GoogleTests class]);
@@ -276,8 +306,9 @@ void RunGoogleTestTests() {
// Convert XCTest's testToRun set to the equivalent --gtest_filter flag.
//
- // Note that we only set forceAllTests to YES if the user specifically focused on GoogleTests.
- // This prevents XCTest double-counting test cases (and failures) when a user asks for all tests.
+ // Note that we only set forceAllTests to YES if the user specifically focused
+ // on GoogleTests. This prevents XCTest double-counting test cases (and
+ // failures) when a user asks for all tests.
NSSet<NSString *> *allTests = [NSSet setWithObject:masterTestCaseName];
NSSet<NSString *> *testsToRun = LoadXCTestConfigurationTestsToRun();
if (testsToRun) {
@@ -307,10 +338,11 @@ void RunGoogleTestTests() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-result"
- // RUN_ALL_TESTS by default doesn't want you to ignore its result, but it's safe here. Test
- // failures are already logged by GoogleTest itself (and then again by XCTest). Test failures are
- // reported via -recordFailureWithDescription:inFile:atLine:expected: which then causes XCTest
- // itself to fail the run.
+ // RUN_ALL_TESTS by default doesn't want you to ignore its result, but it's
+ // safe here. Test failures are already logged by GoogleTest itself (and then
+ // again by XCTest). Test failures are reported via
+ // -recordFailureWithDescription:inFile:atLine:expected: which then causes
+ // XCTest itself to fail the run.
RUN_ALL_TESTS();
#pragma clang diagnostic pop
}
@@ -320,7 +352,8 @@ void RunGoogleTestTests() {
@implementation GoogleTests
+ (XCTestSuite *)defaultTestSuite {
- // Only return all tests beyond GoogleTests if the user is focusing on GoogleTests.
+ // Only return all tests beyond GoogleTests if the user is focusing on
+ // GoogleTests.
if (forceAllTests) {
return CreateAllTestsTestSuite();
} else {
@@ -330,8 +363,8 @@ void RunGoogleTestTests() {
}
- (void)testGoogleTestsActuallyRun {
- // This whole mechanism is sufficiently tricky that we should verify that the build actually
- // plumbed this together correctly.
+ // This whole mechanism is sufficiently tricky that we should verify that the
+ // build actually plumbed this together correctly.
const testing::UnitTest *master = testing::UnitTest::GetInstance();
XCTAssertGreaterThan(master->total_test_case_count(), 0);
}
@@ -339,9 +372,9 @@ void RunGoogleTestTests() {
@end
/**
- * This class is registered as the NSPrincipalClass in the Firestore_Tests bundle's Info.plist.
- * XCTest instantiates this class to perform one-time setup for the test bundle, as documented
- * here:
+ * This class is registered as the NSPrincipalClass in the Firestore_Tests
+ * bundle's Info.plist. XCTest instantiates this class to perform one-time setup
+ * for the test bundle, as documented here:
*
* https://developer.apple.com/documentation/xctest/xctestobservationcenter
*/
diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
index 9c94677..b38d658 100644
--- a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
+++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
@@ -20,14 +20,12 @@ cc_test(
document_test.cc
field_mask_test.cc
field_path_test.cc
- field_transform_test.cc
field_value_test.cc
maybe_document_test.cc
no_document_test.cc
precondition_test.cc
resource_path_test.cc
snapshot_version_test.cc
- transform_operations_test.cc
DEPENDS
firebase_firestore_model
)
diff --git a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
index 38277e2..ba9ea47 100644
--- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
+++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
@@ -33,23 +33,32 @@
#include <vector>
#include "Firestore/Protos/cpp/google/firestore/v1beta1/document.pb.h"
+#include "Firestore/Protos/cpp/google/firestore/v1beta1/firestore.pb.h"
#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
#include "Firestore/core/include/firebase/firestore/timestamp.h"
#include "Firestore/core/src/firebase/firestore/model/field_value.h"
+#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
#include "Firestore/core/src/firebase/firestore/timestamp_internal.h"
#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"
+namespace v1beta1 = google::firestore::v1beta1;
using firebase::Timestamp;
using firebase::TimestampInternal;
using firebase::firestore::FirestoreErrorCode;
using firebase::firestore::model::DatabaseId;
+using firebase::firestore::model::Document;
+using firebase::firestore::model::DocumentKey;
using firebase::firestore::model::FieldValue;
+using firebase::firestore::model::MaybeDocument;
+using firebase::firestore::model::NoDocument;
using firebase::firestore::model::ObjectValue;
+using firebase::firestore::model::SnapshotVersion;
using firebase::firestore::remote::Serializer;
using firebase::firestore::testutil::Key;
using firebase::firestore::util::Status;
@@ -73,13 +82,14 @@ TEST(Serializer, CanLinkToNanopb) {
class SerializerTest : public ::testing::Test {
public:
SerializerTest() : serializer(kDatabaseId) {
+ msg_diff.ReportDifferencesToString(&message_differences);
}
const DatabaseId kDatabaseId{"p", "d"};
Serializer serializer;
void ExpectRoundTrip(const FieldValue& model,
- const google::firestore::v1beta1::Value& proto,
+ const v1beta1::Value& proto,
FieldValue::Type type) {
// First, serialize model with our (nanopb based) serializer, then
// deserialize the resulting bytes with libprotobuf and ensure the result is
@@ -92,6 +102,21 @@ class SerializerTest : public ::testing::Test {
ExpectDeserializationRoundTrip(model, proto, type);
}
+ void ExpectRoundTrip(const DocumentKey& key,
+ const FieldValue& value,
+ const SnapshotVersion& update_time,
+ const v1beta1::BatchGetDocumentsResponse& proto) {
+ ExpectSerializationRoundTrip(key, value, update_time, proto);
+ 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:
@@ -128,10 +153,10 @@ class SerializerTest : public ::testing::Test {
EXPECT_EQ(status.code(), bad_status.status().code());
}
- google::firestore::v1beta1::Value ValueProto(nullptr_t) {
+ v1beta1::Value ValueProto(nullptr_t) {
std::vector<uint8_t> bytes =
EncodeFieldValue(&serializer, FieldValue::NullValue());
- google::firestore::v1beta1::Value proto;
+ v1beta1::Value proto;
bool ok = proto.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(ok);
return proto;
@@ -145,6 +170,16 @@ class SerializerTest : public ::testing::Test {
return bytes;
}
+ std::vector<uint8_t> EncodeDocument(Serializer* serializer,
+ const DocumentKey& key,
+ const FieldValue& value) {
+ std::vector<uint8_t> bytes;
+ Status status =
+ serializer->EncodeDocument(key, value.object_value(), &bytes);
+ EXPECT_OK(status);
+ return bytes;
+ }
+
void Mutate(uint8_t* byte,
uint8_t expected_initial_value,
uint8_t new_value) {
@@ -152,63 +187,84 @@ class SerializerTest : public ::testing::Test {
*byte = new_value;
}
- google::firestore::v1beta1::Value ValueProto(bool b) {
+ v1beta1::Value ValueProto(bool b) {
std::vector<uint8_t> bytes =
EncodeFieldValue(&serializer, FieldValue::BooleanValue(b));
- google::firestore::v1beta1::Value proto;
+ v1beta1::Value proto;
bool ok = proto.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(ok);
return proto;
}
- google::firestore::v1beta1::Value ValueProto(int64_t i) {
+ v1beta1::Value ValueProto(int64_t i) {
std::vector<uint8_t> bytes =
EncodeFieldValue(&serializer, FieldValue::IntegerValue(i));
- google::firestore::v1beta1::Value proto;
+ v1beta1::Value proto;
bool ok = proto.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(ok);
return proto;
}
- google::firestore::v1beta1::Value ValueProto(const char* s) {
+ v1beta1::Value ValueProto(const char* s) {
return ValueProto(std::string(s));
}
- google::firestore::v1beta1::Value ValueProto(const std::string& s) {
+ v1beta1::Value ValueProto(const std::string& s) {
std::vector<uint8_t> bytes =
EncodeFieldValue(&serializer, FieldValue::StringValue(s));
- google::firestore::v1beta1::Value proto;
+ v1beta1::Value proto;
bool ok = proto.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(ok);
return proto;
}
- google::firestore::v1beta1::Value ValueProto(const Timestamp& ts) {
+ v1beta1::Value ValueProto(const Timestamp& ts) {
std::vector<uint8_t> bytes =
EncodeFieldValue(&serializer, FieldValue::TimestampValue(ts));
- google::firestore::v1beta1::Value proto;
+ v1beta1::Value proto;
bool ok = proto.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(ok);
return proto;
}
+ /**
+ * 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.
+ *
+ * This method adds these ignored fields to the proto.
+ */
+ void TouchIgnoredBatchGetDocumentsResponseFields(
+ v1beta1::BatchGetDocumentsResponse* proto) {
+ // 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);
+ create_time_proto->set_nanos(4321);
+ }
+
private:
- void ExpectSerializationRoundTrip(
- const FieldValue& model,
- const google::firestore::v1beta1::Value& proto,
- FieldValue::Type type) {
+ void ExpectSerializationRoundTrip(const FieldValue& model,
+ const v1beta1::Value& proto,
+ FieldValue::Type type) {
EXPECT_EQ(type, model.type());
std::vector<uint8_t> bytes = EncodeFieldValue(&serializer, model);
- google::firestore::v1beta1::Value actual_proto;
+ v1beta1::Value actual_proto;
bool ok = actual_proto.ParseFromArray(bytes.data(), bytes.size());
EXPECT_TRUE(ok);
- EXPECT_TRUE(MessageDifferencer::Equals(proto, actual_proto));
+ EXPECT_TRUE(msg_diff.Compare(proto, actual_proto)) << message_differences;
}
- void ExpectDeserializationRoundTrip(
- const FieldValue& model,
- const google::firestore::v1beta1::Value& proto,
- FieldValue::Type type) {
+ void ExpectDeserializationRoundTrip(const FieldValue& model,
+ const v1beta1::Value& proto,
+ FieldValue::Type type) {
size_t size = proto.ByteSizeLong();
std::vector<uint8_t> bytes(size);
bool status = proto.SerializeToArray(bytes.data(), size);
@@ -220,6 +276,72 @@ class SerializerTest : public ::testing::Test {
EXPECT_EQ(type, actual_model.type());
EXPECT_EQ(model, actual_model);
}
+
+ void ExpectSerializationRoundTrip(
+ const DocumentKey& key,
+ const FieldValue& value,
+ const SnapshotVersion& update_time,
+ const v1beta1::BatchGetDocumentsResponse& proto) {
+ std::vector<uint8_t> bytes = EncodeDocument(&serializer, key, value);
+ v1beta1::Document actual_proto;
+ bool ok = actual_proto.ParseFromArray(bytes.data(), bytes.size());
+ EXPECT_TRUE(ok);
+
+ // 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
+ // backend, we don't encode the update_time (or create_time). But when we
+ // *decode* a document, we *do* decode the update_time (though we still
+ // ignore the create_time). Therefore, we'll verify the update_time
+ // independently, and then strip it out before comparing the rest.
+ EXPECT_FALSE(actual_proto.has_create_time());
+ EXPECT_EQ(update_time.timestamp().seconds(),
+ proto.found().update_time().seconds());
+ EXPECT_EQ(update_time.timestamp().nanoseconds(),
+ proto.found().update_time().nanos());
+ v1beta1::BatchGetDocumentsResponse proto_copy{proto};
+ proto_copy.mutable_found()->clear_update_time();
+ proto_copy.mutable_found()->clear_create_time();
+
+ EXPECT_TRUE(msg_diff.Compare(proto_copy.found(), actual_proto))
+ << message_differences;
+ }
+
+ void ExpectDeserializationRoundTrip(
+ const DocumentKey& key,
+ 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);
+ bool status = proto.SerializeToArray(bytes.data(), size);
+ EXPECT_TRUE(status);
+ StatusOr<std::unique_ptr<MaybeDocument>> actual_model_status =
+ serializer.DecodeMaybeDocument(bytes);
+ EXPECT_OK(actual_model_status);
+ std::unique_ptr<MaybeDocument> actual_model =
+ std::move(actual_model_status).ValueOrDie();
+
+ EXPECT_EQ(key, actual_model->key());
+ 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;
+ MessageDifferencer msg_diff;
};
TEST_F(SerializerTest, EncodesNull) {
@@ -292,7 +414,7 @@ TEST_F(SerializerTest, EncodesTimestamps) {
TEST_F(SerializerTest, EncodesEmptyMap) {
FieldValue model = FieldValue::ObjectValueFromMap({});
- google::firestore::v1beta1::Value proto;
+ v1beta1::Value proto;
proto.mutable_map_value();
ExpectRoundTrip(model, proto, FieldValue::Type::Object);
@@ -320,20 +442,20 @@ TEST_F(SerializerTest, EncodesNestedObjects) {
})},
});
- google::firestore::v1beta1::Value inner_proto;
- google::protobuf::Map<std::string, google::firestore::v1beta1::Value>*
- inner_fields = inner_proto.mutable_map_value()->mutable_fields();
+ v1beta1::Value inner_proto;
+ google::protobuf::Map<std::string, v1beta1::Value>* inner_fields =
+ inner_proto.mutable_map_value()->mutable_fields();
(*inner_fields)["e"] = ValueProto(std::numeric_limits<int64_t>::max());
- google::firestore::v1beta1::Value middle_proto;
- google::protobuf::Map<std::string, google::firestore::v1beta1::Value>*
- middle_fields = middle_proto.mutable_map_value()->mutable_fields();
+ v1beta1::Value middle_proto;
+ google::protobuf::Map<std::string, v1beta1::Value>* middle_fields =
+ middle_proto.mutable_map_value()->mutable_fields();
(*middle_fields)["d"] = ValueProto(int64_t{100});
(*middle_fields)["nested"] = inner_proto;
- google::firestore::v1beta1::Value proto;
- google::protobuf::Map<std::string, google::firestore::v1beta1::Value>*
- fields = proto.mutable_map_value()->mutable_fields();
+ v1beta1::Value proto;
+ google::protobuf::Map<std::string, v1beta1::Value>* fields =
+ proto.mutable_map_value()->mutable_fields();
(*fields)["b"] = ValueProto(true);
(*fields)["i"] = ValueProto(int64_t{1});
(*fields)["n"] = ValueProto(nullptr);
@@ -422,7 +544,7 @@ TEST_F(SerializerTest, BadTag) {
std::vector<uint8_t> bytes =
EncodeFieldValue(&serializer, FieldValue::NullValue());
- // The google::firestore::v1beta1::Value value_type oneof currently has tags
+ // The v1beta1::Value value_type oneof currently has tags
// up to 18. For this test, we'll pick a tag that's unlikely to be added in
// the near term but still fits within a uint8_t even when encoded.
// Specifically 31. 0xf8 represents field number 31 encoded as a varint.
@@ -517,5 +639,79 @@ TEST_F(SerializerTest, BadKey) {
}
}
+TEST_F(SerializerTest, EncodesEmptyDocument) {
+ DocumentKey key = DocumentKey::FromPathString("path/to/the/doc");
+ FieldValue empty_value = FieldValue::ObjectValueFromMap({});
+ SnapshotVersion update_time = SnapshotVersion{{1234, 5678}};
+
+ v1beta1::BatchGetDocumentsResponse proto;
+ v1beta1::Document* doc_proto = proto.mutable_found();
+ doc_proto->set_name(serializer.EncodeKey(key));
+ doc_proto->mutable_fields();
+
+ google::protobuf::Timestamp* update_time_proto =
+ doc_proto->mutable_update_time();
+ update_time_proto->set_seconds(1234);
+ update_time_proto->set_nanos(5678);
+
+ TouchIgnoredBatchGetDocumentsResponseFields(&proto);
+
+ ExpectRoundTrip(key, empty_value, update_time, proto);
+}
+
+TEST_F(SerializerTest, EncodesNonEmptyDocument) {
+ DocumentKey key = DocumentKey::FromPathString("path/to/the/doc");
+ FieldValue fields = FieldValue::ObjectValueFromMap({
+ {"foo", FieldValue::StringValue("bar")},
+ {"two", FieldValue::IntegerValue(2)},
+ {"nested", FieldValue::ObjectValueFromMap({
+ {"fourty-two", FieldValue::IntegerValue(42)},
+ })},
+ });
+ SnapshotVersion update_time = SnapshotVersion{{1234, 5678}};
+
+ v1beta1::Value inner_proto;
+ google::protobuf::Map<std::string, v1beta1::Value>& inner_fields =
+ *inner_proto.mutable_map_value()->mutable_fields();
+ inner_fields["fourty-two"] = ValueProto(int64_t{42});
+
+ v1beta1::BatchGetDocumentsResponse proto;
+ v1beta1::Document* doc_proto = proto.mutable_found();
+ doc_proto->set_name(serializer.EncodeKey(key));
+ google::protobuf::Map<std::string, v1beta1::Value>& m =
+ *doc_proto->mutable_fields();
+ m["foo"] = ValueProto("bar");
+ m["two"] = ValueProto(int64_t{2});
+ m["nested"] = inner_proto;
+
+ google::protobuf::Timestamp* update_time_proto =
+ doc_proto->mutable_update_time();
+ update_time_proto->set_seconds(1234);
+ update_time_proto->set_nanos(5678);
+
+ TouchIgnoredBatchGetDocumentsResponseFields(&proto);
+
+ 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);
+}
+
// TODO(rsgowman): Test [en|de]coding multiple protos into the same output
// vector.
diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
index ea80ea2..bcb1c84 100644
--- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
+++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt
@@ -23,7 +23,7 @@ if(APPLE)
cc_test(
firebase_firestore_util_log_apple_test
SOURCES
- assert_test.cc
+ hard_assert_test.cc
log_test.cc
DEPENDS
firebase_firestore_util_log_apple
@@ -33,7 +33,7 @@ endif(APPLE)
cc_test(
firebase_firestore_util_log_stdio_test
SOURCES
- assert_test.cc
+ hard_assert_test.cc
log_test.cc
DEPENDS
firebase_firestore_util_log_stdio
@@ -129,7 +129,7 @@ cc_test(
status_test.cc
status_test_util.h
statusor_test.cc
- string_printf_test.cc
+ string_format_test.cc
string_util_test.cc
DEPENDS
absl_base
diff --git a/Firestore/core/test/firebase/firestore/util/async_queue_libdispatch_test.mm b/Firestore/core/test/firebase/firestore/util/async_queue_libdispatch_test.mm
index 5452266..f1ff394 100644
--- a/Firestore/core/test/firebase/firestore/util/async_queue_libdispatch_test.mm
+++ b/Firestore/core/test/firebase/firestore/util/async_queue_libdispatch_test.mm
@@ -77,7 +77,7 @@ TEST_F(AsyncQueueTestLibdispatchOnly,
}
TEST_F(AsyncQueueTestLibdispatchOnly,
- VerifyIsCurrentQueueRequiresBeingCalledAsync) {
+ VerifyIsCurrentQueueRequiresBeingCalledOnTheQueue) {
ASSERT_NE(underlying_queue, dispatch_get_main_queue());
EXPECT_ANY_THROW(queue.VerifyIsCurrentQueue());
}
diff --git a/Firestore/core/test/firebase/firestore/util/async_queue_test.cc b/Firestore/core/test/firebase/firestore/util/async_queue_test.cc
index bcee2e3..4247584 100644
--- a/Firestore/core/test/firebase/firestore/util/async_queue_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/async_queue_test.cc
@@ -83,16 +83,20 @@ TEST_P(AsyncQueueTest, VerifyIsCurrentQueueWorksWithOperationInProgress) {
queue.EnqueueBlocking([&] { EXPECT_NO_THROW(queue.VerifyIsCurrentQueue()); });
}
+// TODO(varconst): this test is inherently flaky because it can't be guaranteed
+// that the enqueued asynchronous operation didn't finish before the code has
+// a chance to even enqueue the next operation. Delays are chosen so that the
+// test is unlikely to fail in practice. Need to revisit this.
TEST_P(AsyncQueueTest, CanScheduleOperationsInTheFuture) {
std::string steps;
queue.Enqueue([&steps] { steps += '1'; });
queue.Enqueue([&] {
- queue.EnqueueAfterDelay(AsyncQueue::Milliseconds(5), kTimerId1, [&] {
+ queue.EnqueueAfterDelay(AsyncQueue::Milliseconds(20), kTimerId1, [&] {
steps += '4';
signal_finished();
});
- queue.EnqueueAfterDelay(AsyncQueue::Milliseconds(1), kTimerId2,
+ queue.EnqueueAfterDelay(AsyncQueue::Milliseconds(10), kTimerId2,
[&steps] { steps += '3'; });
queue.EnqueueRelaxed([&steps] { steps += '2'; });
});
diff --git a/Firestore/core/test/firebase/firestore/util/comparison_test.cc b/Firestore/core/test/firebase/firestore/util/comparison_test.cc
index a03aec8..317a830 100644
--- a/Firestore/core/test/firebase/firestore/util/comparison_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/comparison_test.cc
@@ -16,11 +16,10 @@
#include "Firestore/core/src/firebase/firestore/util/comparison.h"
-#include <cinttypes>
#include <cmath>
#include <limits>
-#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
#include "gtest/gtest.h"
namespace firebase {
@@ -84,47 +83,47 @@ TEST(Comparison, DoubleCompare) {
ASSERT_SAME(Compare<double>(-0, 0));
}
-#define ASSERT_BIT_EQUALS(expected, actual) \
- do { \
- uint64_t expectedBits = DoubleBits(expected); \
- uint64_t actualBits = DoubleBits(actual); \
- if (expectedBits != actualBits) { \
- std::string message = StringPrintf( \
- "Expected <%f> to compare equal to <%f> " \
- "with bits <%" PRIu64 "> equal to <%" PRIu64 ">", \
- actual, expected, actualBits, expectedBits); \
- FAIL() << message; \
- } \
+#define ASSERT_BIT_EQUALS(expected, actual) \
+ do { \
+ uint64_t expectedBits = DoubleBits(expected); \
+ uint64_t actualBits = DoubleBits(actual); \
+ if (expectedBits != actualBits) { \
+ std::string message = StringFormat( \
+ "Expected <%s> to compare equal to <%s> " \
+ "with bits <%s> equal to <%s>", \
+ actual, expected, actualBits, expectedBits); \
+ FAIL() << message; \
+ } \
} while (0);
-#define ASSERT_MIXED_SAME(doubleValue, longValue) \
- do { \
- ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
- if (result != ComparisonResult::Same) { \
- std::string message = StringPrintf( \
- "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
- FAIL() << message; \
- } \
+#define ASSERT_MIXED_SAME(doubleValue, longValue) \
+ do { \
+ ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
+ if (result != ComparisonResult::Same) { \
+ std::string message = StringFormat( \
+ "Expected <%s> to compare equal to <%s>", doubleValue, longValue); \
+ FAIL() << message; \
+ } \
} while (0);
-#define ASSERT_MIXED_DESCENDING(doubleValue, longValue) \
- do { \
- ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
- if (result != ComparisonResult::Descending) { \
- std::string message = StringPrintf( \
- "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
- FAIL() << message; \
- } \
+#define ASSERT_MIXED_DESCENDING(doubleValue, longValue) \
+ do { \
+ ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
+ if (result != ComparisonResult::Descending) { \
+ std::string message = StringFormat( \
+ "Expected <%s> to compare equal to <%s>", doubleValue, longValue); \
+ FAIL() << message; \
+ } \
} while (0);
-#define ASSERT_MIXED_ASCENDING(doubleValue, longValue) \
- do { \
- ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
- if (result != ComparisonResult::Ascending) { \
- std::string message = StringPrintf( \
- "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \
- FAIL() << message; \
- } \
+#define ASSERT_MIXED_ASCENDING(doubleValue, longValue) \
+ do { \
+ ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \
+ if (result != ComparisonResult::Ascending) { \
+ std::string message = StringFormat( \
+ "Expected <%s> to compare equal to <%s>", doubleValue, longValue); \
+ FAIL() << message; \
+ } \
} while (0);
TEST(Comparison, MixedNumberCompare) {
diff --git a/Firestore/core/test/firebase/firestore/util/executor_libdispatch_test.mm b/Firestore/core/test/firebase/firestore/util/executor_libdispatch_test.mm
index 0167c83..330c8fc 100644
--- a/Firestore/core/test/firebase/firestore/util/executor_libdispatch_test.mm
+++ b/Firestore/core/test/firebase/firestore/util/executor_libdispatch_test.mm
@@ -29,7 +29,8 @@ namespace util {
namespace {
std::unique_ptr<internal::Executor> ExecutorFactory() {
- return absl::make_unique<internal::ExecutorLibdispatch>();
+ return absl::make_unique<internal::ExecutorLibdispatch>(
+ dispatch_queue_create("ExecutorLibdispatchTests", DISPATCH_QUEUE_SERIAL));
}
} // namespace
@@ -38,6 +39,36 @@ INSTANTIATE_TEST_CASE_P(ExecutorTestLibdispatch,
ExecutorTest,
::testing::Values(ExecutorFactory));
+namespace internal {
+class ExecutorLibdispatchOnlyTests : public TestWithTimeoutMixin,
+ public ::testing::Test {
+ public:
+ ExecutorLibdispatchOnlyTests() : executor{ExecutorFactory()} {
+ }
+
+ std::unique_ptr<Executor> executor;
+};
+
+TEST_F(ExecutorLibdispatchOnlyTests, NameReturnsLabelOfTheQueue) {
+ EXPECT_EQ(executor->Name(), "ExecutorLibdispatchTests");
+ executor->Execute([&] {
+ EXPECT_EQ(executor->CurrentExecutorName(), "ExecutorLibdispatchTests");
+ signal_finished();
+ });
+ EXPECT_TRUE(WaitForTestToFinish());
+}
+
+TEST_F(ExecutorLibdispatchOnlyTests,
+ ExecuteBlockingOnTheCurrentQueueIsNotAllowed) {
+ EXPECT_NO_THROW(executor->ExecuteBlocking([] {}));
+ executor->Execute([&] {
+ EXPECT_ANY_THROW(executor->ExecuteBlocking([] {}));
+ signal_finished();
+ });
+ EXPECT_TRUE(WaitForTestToFinish());
+}
+
+} // namespace internal
} // namespace util
} // namespace firestore
} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/executor_std_test.cc b/Firestore/core/test/firebase/firestore/util/executor_std_test.cc
index 43cad60..59c3c32 100644
--- a/Firestore/core/test/firebase/firestore/util/executor_std_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/executor_std_test.cc
@@ -70,7 +70,6 @@ TEST_F(ScheduleTest, PopIfDue_Delayed) {
schedule.Push(2, start_time + chr::milliseconds(3));
schedule.Push(3, start_time + chr::milliseconds(1));
- EXPECT_FALSE(schedule.PopIfDue().has_value());
std::this_thread::sleep_for(chr::milliseconds(5));
EXPECT_EQ(schedule.PopIfDue().value(), 3);
@@ -212,11 +211,16 @@ TEST_F(ScheduleTest, PopBlockingIsNotAffectedByIrrelevantRemovals) {
EXPECT_EQ(schedule.PopBlocking(), 1);
});
- while (schedule.empty()) {
+ // Wait (with timeout) for both values to appear in the schedule.
+ while (schedule.size() != 2) {
+ if (now() - start_time >= kTimeout) {
+ Abort();
+ }
std::this_thread::sleep_for(chr::milliseconds(1));
}
const auto maybe_removed =
schedule.RemoveIf([](const int v) { return v == 2; });
+ ASSERT_TRUE(maybe_removed.has_value());
EXPECT_EQ(maybe_removed.value(), 2);
ABORT_ON_TIMEOUT(future);
}
diff --git a/Firestore/core/test/firebase/firestore/util/executor_test.cc b/Firestore/core/test/firebase/firestore/util/executor_test.cc
index 5cf389b..99bddce 100644
--- a/Firestore/core/test/firebase/firestore/util/executor_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/executor_test.cc
@@ -49,6 +49,12 @@ TEST_P(ExecutorTest, Execute) {
EXPECT_TRUE(WaitForTestToFinish());
}
+TEST_P(ExecutorTest, ExecuteBlocking) {
+ bool finished = false;
+ executor->ExecuteBlocking([&] { finished = true; });
+ EXPECT_TRUE(finished);
+}
+
TEST_P(ExecutorTest, DestructorDoesNotBlockIfThereArePendingTasks) {
const auto future = std::async(std::launch::async, [&] {
auto another_executor = GetParam()();
@@ -60,15 +66,19 @@ TEST_P(ExecutorTest, DestructorDoesNotBlockIfThereArePendingTasks) {
ABORT_ON_TIMEOUT(future);
}
+// TODO(varconst): this test is inherently flaky because it can't be guaranteed
+// that the enqueued asynchronous operation didn't finish before the code has
+// a chance to even enqueue the next operation. Delays are chosen so that the
+// test is unlikely to fail in practice. Need to revisit this.
TEST_P(ExecutorTest, CanScheduleOperationsInTheFuture) {
std::string steps;
executor->Execute([&steps] { steps += '1'; });
- Schedule(executor.get(), Executor::Milliseconds(5), [&] {
+ Schedule(executor.get(), Executor::Milliseconds(20), [&] {
steps += '4';
signal_finished();
});
- Schedule(executor.get(), Executor::Milliseconds(1),
+ Schedule(executor.get(), Executor::Milliseconds(10),
[&steps] { steps += '3'; });
executor->Execute([&steps] { steps += '2'; });
@@ -105,6 +115,104 @@ TEST_P(ExecutorTest, DelayedOperationIsValidAfterTheOperationHasRun) {
EXPECT_NO_THROW(delayed_operation.Cancel());
}
+TEST_P(ExecutorTest, IsCurrentExecutor) {
+ EXPECT_FALSE(executor->IsCurrentExecutor());
+ EXPECT_NE(executor->Name(), executor->CurrentExecutorName());
+
+ executor->ExecuteBlocking([&] {
+ EXPECT_TRUE(executor->IsCurrentExecutor());
+ EXPECT_EQ(executor->Name(), executor->CurrentExecutorName());
+ });
+
+ executor->Execute([&] {
+ EXPECT_TRUE(executor->IsCurrentExecutor());
+ EXPECT_EQ(executor->Name(), executor->CurrentExecutorName());
+ });
+
+ Schedule(executor.get(), Executor::Milliseconds(1), [&] {
+ EXPECT_TRUE(executor->IsCurrentExecutor());
+ EXPECT_EQ(executor->Name(), executor->CurrentExecutorName());
+ signal_finished();
+ });
+
+ EXPECT_TRUE(WaitForTestToFinish());
+}
+
+TEST_P(ExecutorTest, OperationsCanBeRemovedFromScheduleBeforeTheyRun) {
+ const Executor::Tag tag_foo = 1;
+ const Executor::Tag tag_bar = 2;
+
+ // Make sure the schedule is empty.
+ EXPECT_FALSE(executor->IsScheduled(tag_foo));
+ EXPECT_FALSE(executor->IsScheduled(tag_bar));
+ EXPECT_FALSE(executor->PopFromSchedule().has_value());
+
+ // Add two operations to the schedule with different tags.
+
+ // The exact delay doesn't matter as long as it's too far away to be executed
+ // during the test.
+ const auto far_away = chr::seconds(1);
+ executor->Schedule(far_away, {tag_foo, [] {}});
+ // Scheduled operations can be distinguished by their tag.
+ EXPECT_TRUE(executor->IsScheduled(tag_foo));
+ EXPECT_FALSE(executor->IsScheduled(tag_bar));
+
+ // This operation will be scheduled after the previous one (operations
+ // scheduled with the same delay are FIFO ordered).
+ executor->Schedule(far_away, {tag_bar, [] {}});
+ EXPECT_TRUE(executor->IsScheduled(tag_foo));
+ EXPECT_TRUE(executor->IsScheduled(tag_bar));
+
+ // Now pop the operations one by one without waiting for them to be executed,
+ // check that operations are popped in the order they are scheduled and
+ // preserve tags. Schedule should become empty as a result.
+
+ auto maybe_operation = executor->PopFromSchedule();
+ ASSERT_TRUE(maybe_operation.has_value());
+ EXPECT_EQ(maybe_operation->tag, tag_foo);
+ EXPECT_FALSE(executor->IsScheduled(tag_foo));
+ EXPECT_TRUE(executor->IsScheduled(tag_bar));
+
+ maybe_operation = executor->PopFromSchedule();
+ ASSERT_TRUE(maybe_operation.has_value());
+ EXPECT_EQ(maybe_operation->tag, tag_bar);
+ EXPECT_FALSE(executor->IsScheduled(tag_bar));
+
+ // Schedule should now be empty.
+ EXPECT_FALSE(executor->PopFromSchedule().has_value());
+}
+
+TEST_P(ExecutorTest, DuplicateTagsOnOperationsAreAllowed) {
+ const Executor::Tag tag_foo = 1;
+ std::string steps;
+
+ // Add two operations with the same tag to the schedule to verify that
+ // duplicate tags are allowed.
+
+ const auto far_away = chr::seconds(1);
+ executor->Schedule(far_away, {tag_foo, [&steps] { steps += '1'; }});
+ executor->Schedule(far_away, {tag_foo, [&steps] { steps += '2'; }});
+ EXPECT_TRUE(executor->IsScheduled(tag_foo));
+
+ auto maybe_operation = executor->PopFromSchedule();
+ ASSERT_TRUE(maybe_operation.has_value());
+ EXPECT_EQ(maybe_operation->tag, tag_foo);
+ // There's still another operation with the same tag in the schedule.
+ EXPECT_TRUE(executor->IsScheduled(tag_foo));
+
+ maybe_operation->operation();
+
+ maybe_operation = executor->PopFromSchedule();
+ ASSERT_TRUE(maybe_operation.has_value());
+ EXPECT_EQ(maybe_operation->tag, tag_foo);
+ EXPECT_FALSE(executor->IsScheduled(tag_foo));
+
+ maybe_operation->operation();
+ // Despite having the same tag, the operations should have been ordered
+ // according to their scheduled time and preserved their identity.
+ EXPECT_EQ(steps, "12");
+}
+
} // namespace util
} // namespace firestore
} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/assert_test.cc b/Firestore/core/test/firebase/firestore/util/hard_assert_test.cc
index fb15e61..fab6475 100644
--- a/Firestore/core/test/firebase/firestore/util/assert_test.cc
+++ b/Firestore/core/test/firebase/firestore/util/hard_assert_test.cc
@@ -16,7 +16,7 @@
#include <exception>
-#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
#include "gtest/gtest.h"
namespace firebase {
@@ -25,37 +25,26 @@ namespace util {
namespace {
-void AssertWithExpression(bool condition) {
- FIREBASE_ASSERT_WITH_EXPRESSION(condition, 1 + 2 + 3);
-}
-
void Assert(bool condition) {
- FIREBASE_ASSERT(condition == true);
+ HARD_ASSERT(condition == true);
}
-void AssertMessageWithExpression(bool condition) {
- FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, 1 + 2 + 3, "connection %s",
- condition ? "succeeded" : "failed");
+void AssertWithMessage(bool condition) {
+ HARD_ASSERT(condition, "condition %s", condition ? "succeeded" : "failed");
}
} // namespace
-TEST(Assert, WithExpression) {
- AssertWithExpression(true);
-
- EXPECT_ANY_THROW(AssertWithExpression(false));
-}
-
-TEST(Assert, Vanilla) {
+TEST(HardAssertTest, Vanilla) {
Assert(true);
EXPECT_ANY_THROW(Assert(false));
}
-TEST(Assert, WithMessageAndExpression) {
- AssertMessageWithExpression(true);
+TEST(HardAssertTest, WithMessage) {
+ AssertWithMessage(true);
- EXPECT_ANY_THROW(AssertMessageWithExpression(false));
+ EXPECT_ANY_THROW(AssertWithMessage(false));
}
} // namespace util
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/core/test/firebase/firestore/util/string_format_test.cc b/Firestore/core/test/firebase/firestore/util/string_format_test.cc
new file mode 100644
index 0000000..f0ec20d
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/util/string_format_test.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/src/firebase/firestore/util/string_format.h"
+
+#include "absl/strings/string_view.h"
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace util {
+
+TEST(StringFormatTest, Empty) {
+ EXPECT_EQ("", StringFormat(""));
+ EXPECT_EQ("", StringFormat("%s", std::string().c_str()));
+ EXPECT_EQ("", StringFormat("%s", ""));
+}
+
+TEST(StringFormatTest, CString) {
+ EXPECT_EQ("Hello World", StringFormat("Hello %s", "World"));
+ EXPECT_EQ("Hello World", StringFormat("%s World", "Hello"));
+ EXPECT_EQ("Hello World", StringFormat("Hello%sWorld", " "));
+
+ const char* value = "World";
+ EXPECT_EQ("Hello World", StringFormat("Hello %s", value));
+
+ value = nullptr;
+ EXPECT_EQ("Hello null", StringFormat("Hello %s", value));
+}
+
+TEST(StringFormatTest, String) {
+ EXPECT_EQ("Hello World", StringFormat("Hello %s", std::string{"World"}));
+
+ std::string value{"World"};
+ EXPECT_EQ("Hello World", StringFormat("Hello %s", value));
+}
+
+TEST(StringFormatTest, StringView) {
+ EXPECT_EQ("Hello World",
+ StringFormat("Hello %s", absl::string_view{"World"}));
+ EXPECT_EQ("Hello World",
+ StringFormat("%s World", absl::string_view{"Hello"}));
+ EXPECT_EQ("Hello World",
+ StringFormat("Hello%sWorld", absl::string_view{" "}));
+}
+
+TEST(StringFormatTest, Int) {
+ std::string value = StringFormat("Hello %s", 123);
+ EXPECT_EQ("Hello 123", value);
+}
+
+TEST(StringFormatTest, Float) {
+ std::string value = StringFormat("Hello %s", 1.5);
+ EXPECT_EQ("Hello 1.5", value);
+}
+
+TEST(StringFormatTest, Bool) {
+ EXPECT_EQ("Hello true", StringFormat("Hello %s", true));
+ EXPECT_EQ("Hello false", StringFormat("Hello %s", false));
+}
+
+TEST(StringFormatTest, Pointer) {
+ // pointers implicitly convert to bool. Make sure this doesn't happen in
+ // this API.
+ int value = 4;
+ EXPECT_NE("Hello true", StringFormat("Hello %s", &value));
+ EXPECT_EQ("Hello null", StringFormat("Hello %s", nullptr));
+}
+
+TEST(StringFormatTest, Mixed) {
+ EXPECT_EQ("string=World, bool=true, int=42, float=1.5",
+ StringFormat("string=%s, bool=%s, int=%s, float=%s", "World", true,
+ 42, 1.5));
+ EXPECT_EQ("World%true%42%1.5",
+ StringFormat("%s%%%s%%%s%%%s", "World", true, 42, 1.5));
+}
+
+TEST(StringFormatTest, Literal) {
+ EXPECT_EQ("Hello %", StringFormat("Hello %%"));
+ EXPECT_EQ("% World", StringFormat("%% World"));
+}
+
+TEST(StringFormatTest, Invalid) {
+ EXPECT_EQ("Hello <invalid>", StringFormat("Hello %@", 42));
+}
+
+TEST(StringFormatTest, Missing) {
+ EXPECT_EQ("Hello <missing>", StringFormat("Hello %s"));
+}
+
+TEST(StringFormatTest, Excess) {
+ EXPECT_EQ("Hello World", StringFormat("Hello %s", "World", 42));
+}
+
+} // namespace util
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/util/string_printf_test.cc b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc
deleted file mode 100644
index 14cc9c8..0000000
--- a/Firestore/core/test/firebase/firestore/util/string_printf_test.cc
+++ /dev/null
@@ -1,78 +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.
- */
-
-#include "Firestore/core/src/firebase/firestore/util/string_printf.h"
-
-#include "gtest/gtest.h"
-
-namespace firebase {
-namespace firestore {
-namespace util {
-
-TEST(StringPrintf, Empty) {
- EXPECT_EQ("", StringPrintf(""));
- EXPECT_EQ("", StringPrintf("%s", std::string().c_str()));
- EXPECT_EQ("", StringPrintf("%s", ""));
-}
-
-TEST(StringAppendFTest, Empty) {
- std::string value("Hello");
- const char* empty = "";
- StringAppendF(&value, "%s", empty);
- EXPECT_EQ("Hello", value);
-}
-
-TEST(StringAppendFTest, EmptyString) {
- std::string value("Hello");
- StringAppendF(&value, "%s", "");
- EXPECT_EQ("Hello", value);
-}
-
-TEST(StringAppendFTest, String) {
- std::string value("Hello");
- StringAppendF(&value, " %s", "World");
- EXPECT_EQ("Hello World", value);
-}
-
-TEST(StringAppendFTest, Int) {
- std::string value("Hello");
- StringAppendF(&value, " %d", 123);
- EXPECT_EQ("Hello 123", value);
-}
-
-TEST(StringPrintf, DontOverwriteErrno) {
- // Check that errno isn't overwritten unless we're printing
- // something significantly larger than what people are normally
- // printing in their badly written PLOG() statements.
- errno = ECHILD;
- std::string value = StringPrintf("Hello, %s!", "World");
- EXPECT_EQ(ECHILD, errno);
-}
-
-TEST(StringPrintf, LargeBuf) {
- // Check that the large buffer is handled correctly.
- size_t n = 2048;
- char* buf = new char[n + 1];
- memset(buf, ' ', n);
- buf[n] = 0;
- std::string value = StringPrintf("%s", buf);
- EXPECT_EQ(buf, value);
- delete[] buf;
-}
-
-} // namespace util
-} // namespace firestore
-} // namespace firebase