aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Example/Auth/Tests/FIRUserTests.m172
-rw-r--r--Example/Core/Tests/FIRLoggerTest.m10
-rw-r--r--Example/Messaging/Tests/FIRMessagingPubSubTest.m9
-rw-r--r--Example/Messaging/Tests/FIRMessagingServiceTest.m180
-rw-r--r--Firebase/Auth/CHANGELOG.md4
-rw-r--r--Firebase/Auth/Source/FIRUser.m22
-rw-r--r--Firebase/Core/CHANGELOG.md4
-rw-r--r--Firebase/Core/FIRLogger.m4
-rw-r--r--Firebase/Messaging/FIRMessaging.m71
-rw-r--r--Firebase/Messaging/FIRMessagingPubSub.h9
-rw-r--r--Firebase/Messaging/FIRMessagingPubSub.m8
-rw-r--r--FirebaseFirestore.podspec12
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj257
-rw-r--r--Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme13
-rw-r--r--Firestore/Example/Podfile1
-rw-r--r--Firestore/Example/ProtobufCpp.podspec74
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm8
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm2
-rw-r--r--Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm2
-rw-r--r--Firestore/Source/Core/FSTSyncEngine.mm42
-rw-r--r--Firestore/Source/Local/FSTLevelDB.h2
-rw-r--r--Firestore/Source/Local/FSTLevelDB.mm6
-rw-r--r--Firestore/Source/Local/FSTLevelDBMutationQueue.h2
-rw-r--r--Firestore/Source/Local/FSTLevelDBMutationQueue.mm2
-rw-r--r--Firestore/Source/Local/FSTLevelDBQueryCache.h2
-rw-r--r--Firestore/Source/Local/FSTLevelDBQueryCache.mm2
-rw-r--r--Firestore/Source/Remote/FSTDatastore.mm4
-rw-r--r--Firestore/Source/Remote/FSTRemoteEvent.h3
-rw-r--r--Firestore/Source/Remote/FSTRemoteStore.mm4
-rw-r--r--Firestore/core/src/firebase/firestore/local/CMakeLists.txt2
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/reader.cc3
-rw-r--r--Firestore/core/src/firebase/firestore/nanopb/reader.h1
-rw-r--r--Firestore/core/test/firebase/firestore/remote/serializer_test.cc5
-rw-r--r--Releases/Manifests/5.3.0.json4
-rw-r--r--Releases/Manifests/README3
-rwxr-xr-xReleases/update-versions.py249
-rwxr-xr-xscripts/check_test_inclusion.py2
-rwxr-xr-xscripts/push-pods.sh41
-rwxr-xr-xscripts/sync_project.rb5
-rwxr-xr-xscripts/update-tags.sh61
40 files changed, 1015 insertions, 292 deletions
diff --git a/Example/Auth/Tests/FIRUserTests.m b/Example/Auth/Tests/FIRUserTests.m
index 7a6c165..8bb6786 100644
--- a/Example/Auth/Tests/FIRUserTests.m
+++ b/Example/Auth/Tests/FIRUserTests.m
@@ -26,9 +26,11 @@
#import "FIRAuthGlobalWorkQueue.h"
#import "FIRAuthOperationType.h"
#import "FIRAuthTokenResult.h"
+#import "FIREmailLinkSignInResponse.m"
#import "FIRSecureTokenService.h"
#import "FIRSecureTokenRequest.h"
#import "FIRSecureTokenResponse.h"
+#import "FIRSignUpNewUserResponse.h"
#import "FIRGetAccountInfoRequest.h"
#import "FIRGetAccountInfoResponse.h"
#import "FIRSetAccountInfoRequest.h"
@@ -583,6 +585,57 @@ static const NSTimeInterval kExpectationTimeout = 2;
OCMVerifyAll(_mockBackend);
}
+/** @fn testUpdateEmailWithAuthLinkAccountSuccess
+ @brief Tests a successful @c updateEmail:completion: call updates provider info.
+ */
+- (void)testUpdateEmailWithAuthLinkAccountSuccess {
+ id (^mockUserInfoWithDisplayName)(NSString *) = ^(NSString *displayName) {
+ id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
+ OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
+ OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
+ OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
+ OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
+ return mockGetAccountInfoResponseUser;
+ };
+ XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
+ id userInfoResponse = mockUserInfoWithDisplayName(kGoogleDisplayName);
+ [self signInWithEmailLinkWithMockUserInfoResponse:userInfoResponse
+ completion:^(FIRUser *user) {
+ // Pretend that the display name on the server has been changed since last request.
+ [self
+ expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoWithDisplayName(kNewDisplayName)];
+ OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
+ .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
+ FIRSetAccountInfoResponseCallback callback) {
+ XCTAssertEqualObjects(request.APIKey, kAPIKey);
+ XCTAssertEqualObjects(request.accessToken, kAccessToken);
+ XCTAssertEqualObjects(request.email, kNewEmail);
+ XCTAssertNil(request.localID);
+ XCTAssertNil(request.displayName);
+ XCTAssertNil(request.photoURL);
+ XCTAssertNil(request.password);
+ XCTAssertNil(request.providers);
+ XCTAssertNil(request.deleteAttributes);
+ XCTAssertNil(request.deleteProviders);
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
+ id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
+ OCMStub([mockSetAccountInfoResponse email]).andReturn(kNewEmail);
+ OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
+ callback(mockSetAccountInfoResponse, nil);
+ });
+ });
+ [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertEqualObjects(user.email, kNewEmail);
+ XCTAssertEqualObjects(user.displayName, kNewDisplayName);
+ XCTAssertFalse(user.isAnonymous);
+ [expectation fulfill];
+ }];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
+ OCMVerifyAll(_mockBackend);
+}
+
/** @fn testUpdateEmailFailure
@brief Tests the flow of a failed @c updateEmail:completion: call.
*/
@@ -1572,6 +1625,64 @@ static const NSTimeInterval kExpectationTimeout = 2;
OCMVerifyAll(_mockBackend);
}
+/** @fn testLinkingAnonymousAccountsUpdatesIsAnonymous
+ @brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
+ invocation for email credential.
+ */
+- (void)testLinkingAnonymousAccountsUpdatesIsAnonymous {
+ FIRAuthCredential *linkEmailCredential =
+ [FIREmailAuthProvider credentialWithEmail:kEmail
+ link:@"https://google.com?oobCode=aCode&mode=signIn"];
+
+ id (^mockUserInfoWithDisplayName)(NSString *, BOOL) = ^(NSString *displayName,
+ BOOL hasProviders) {
+ NSArray *providers = hasProviders ? @[ @{
+ @"providerId": FIREmailAuthProviderID,
+ @"email": kEmail
+ } ] : @[];
+ FIRGetAccountInfoResponseUser *responseUser =
+ [[FIRGetAccountInfoResponseUser alloc] initWithDictionary:@{
+ @"providerUserInfo": providers,
+ @"localId": kLocalID,
+ @"displayName": displayName,
+ @"email": kEmail
+ }];
+ return responseUser;
+ };
+ XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
+ id userInfoResponse = mockUserInfoWithDisplayName(kGoogleDisplayName, NO);
+
+ [self signInAnonymouslyWithMockGetAccountInfoResponse:userInfoResponse
+ completion:^(FIRUser *user) {
+ // Pretend that the display name and providers on the server have been updated.
+ // Get account info is expected to be invoked twice.
+ id updatedMockUser = mockUserInfoWithDisplayName(kNewDisplayName, YES);
+ [self expectGetAccountInfoWithMockUserInfoResponse:updatedMockUser];
+ [self expectGetAccountInfoWithMockUserInfoResponse:updatedMockUser];
+ OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
+ .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
+ FIRSetAccountInfoResponseCallback callback) {
+ id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
+ OCMStub([mockSetAccountInfoResponse email]).andReturn(kNewEmail);
+ OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
+ callback(mockSetAccountInfoResponse, nil);
+ });
+ XCTAssertTrue(user.isAnonymous);
+
+ [user linkAndRetrieveDataWithCredential:linkEmailCredential
+ completion:^(FIRAuthDataResult *_Nullable linkAuthResult,
+ NSError *_Nullable error) {
+ XCTAssertTrue([NSThread isMainThread]);
+ XCTAssertNil(error);
+ XCTAssertEqualObjects(user.email, kEmail);
+ XCTAssertFalse(user.isAnonymous);
+ [expectation fulfill];
+ }];
+ }];
+ [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
+ OCMVerifyAll(_mockBackend);
+}
+
/** @fn testlinkEmailAndRetrieveDataSuccess
@brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
invocation for email credential.
@@ -2222,6 +2333,34 @@ static const NSTimeInterval kExpectationTimeout = 2;
OCMVerifyAll(_mockBackend);
}
+/** @fn signInAnonymouslyWithMockGetAccountInfoResponse:completion:
+ @brief Signs in with an anonymous account with mocked backend end calls.
+ @param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
+ @param completion The completion block that takes the newly signed-in user as the only
+ parameter.
+ */
+- (void)signInAnonymouslyWithMockGetAccountInfoResponse:(id)mockUserInfoResponse
+ completion:(void (^)(FIRUser *user))completion {
+ OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
+ .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
+ FIRSignupNewUserCallback callback) {
+ id mockSignUpResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
+ OCMStub([mockSignUpResponse IDToken]).andReturn(kAccessToken);
+ OCMStub([mockSignUpResponse approximateExpirationDate])
+ .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
+ OCMStub([mockSignUpResponse refreshToken]).andReturn(kRefreshToken);
+ callback(mockSignUpResponse, nil);
+ });
+ [self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
+ [[FIRAuth auth] signOut:NULL];
+ [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
+ NSError *_Nullable error) {
+ XCTAssertNotNil(result.user);
+ XCTAssertNil(error);
+ completion(result.user);
+ }];
+}
+
/** @fn signInWithEmailPasswordWithMockGetAccountInfoResponse:completion:
@brief Signs in with an email and password account with mocked backend end calls.
@param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
@@ -2229,7 +2368,7 @@ static const NSTimeInterval kExpectationTimeout = 2;
parameter.
*/
- (void)signInWithEmailPasswordWithMockUserInfoResponse:(id)mockUserInfoResponse
- completion:(void (^)(FIRUser *user))completion {
+ completion:(void (^)(FIRUser *user))completion {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
FIRVerifyPasswordResponseCallback callback) {
@@ -2239,7 +2378,7 @@ static const NSTimeInterval kExpectationTimeout = 2;
OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
- callback(mockVeriyPasswordResponse, nil);
+ callback(mockVeriyPasswordResponse, nil);
});
});
[self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
@@ -2253,6 +2392,35 @@ static const NSTimeInterval kExpectationTimeout = 2;
}];
}
+/** @fn signInWithEmailLinkWithMockGetAccountInfoResponse:completion:
+ @brief Signs in with an email link auth account with mocked backend end calls.
+ @param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
+ @param completion The completion block that takes the newly signed-in user as the only
+ parameter.
+ */
+- (void)signInWithEmailLinkWithMockUserInfoResponse:(id)mockUserInfoResponse
+ completion:(void (^)(FIRUser *user))completion {
+ OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
+ .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
+ FIREmailLinkSigninResponseCallback callback) {
+ id mockVerifyLinkResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
+ OCMStub([mockVerifyLinkResponse IDToken]).andReturn(kAccessToken);
+ OCMStub([mockVerifyLinkResponse approximateExpirationDate])
+ .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
+ OCMStub([mockVerifyLinkResponse refreshToken]).andReturn(kRefreshToken);
+ callback(mockVerifyLinkResponse, nil);
+ });
+ [self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
+ [[FIRAuth auth] signOut:NULL];
+ [[FIRAuth auth] signInWithEmail:kEmail
+ link:@"https://www.google.com?oobCode=aCode&mode=signIn"
+ completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
+ XCTAssertNotNil(result.user);
+ XCTAssertNil(error);
+ completion(result.user);
+ }];
+}
+
/** @fn expectGetAccountInfoWithMockUserInfoResponse:
@brief Expects a GetAccountInfo request on the mock backend and calls back with provided
fake account data.
diff --git a/Example/Core/Tests/FIRLoggerTest.m b/Example/Core/Tests/FIRLoggerTest.m
index 0d6d4e2..c1ba37b 100644
--- a/Example/Core/Tests/FIRLoggerTest.m
+++ b/Example/Core/Tests/FIRLoggerTest.m
@@ -29,8 +29,6 @@ extern NSString *const kFIRPersistedDebugModeKey;
extern const char *kFIRLoggerASLClientFacilityName;
-extern const char *kFIRLoggerCustomASLMessageFormat;
-
extern void FIRResetLogger(void);
extern aslclient getFIRLoggerClient(void);
@@ -39,10 +37,6 @@ extern dispatch_queue_t getFIRClientQueue(void);
extern BOOL getFIRLoggerDebugMode(void);
-// Define the message format again to make sure the format doesn't accidentally change.
-static NSString *const kCorrectASLMessageFormat =
- @"$((Time)(J.3)) $(Sender)[$(PID)] <$((Level)(str))> $Message";
-
static NSString *const kMessageCode = @"I-COR000001";
@interface FIRLoggerTest : FIRTestCase
@@ -71,10 +65,6 @@ static NSString *const kMessageCode = @"I-COR000001";
// Test some stable variables to make sure they weren't accidently changed.
- (void)testStableVariables {
- // kFIRLoggerCustomASLMessageFormat.
- XCTAssertEqualObjects(kCorrectASLMessageFormat,
- [NSString stringWithUTF8String:kFIRLoggerCustomASLMessageFormat]);
-
// Strings of type FIRLoggerServices.
XCTAssertEqualObjects(kFIRLoggerABTesting, @"[Firebase/ABTesting]");
XCTAssertEqualObjects(kFIRLoggerAdMob, @"[Firebase/AdMob]");
diff --git a/Example/Messaging/Tests/FIRMessagingPubSubTest.m b/Example/Messaging/Tests/FIRMessagingPubSubTest.m
index 3af1402..e1260f5 100644
--- a/Example/Messaging/Tests/FIRMessagingPubSubTest.m
+++ b/Example/Messaging/Tests/FIRMessagingPubSubTest.m
@@ -78,4 +78,13 @@ static NSString *const kTopicName = @"topic-Name";
XCTAssertTrue([FIRMessagingPubSub isValidTopicWithPrefix:topic]);
}
+- (void)testRemoveTopicPrefix {
+ NSString *topic = [NSString stringWithFormat:@"/topics/%@", kTopicName];
+ topic = [FIRMessagingPubSub removePrefixFromTopic:topic];
+ XCTAssertEqualObjects(topic, kTopicName);
+ // if the topic doesn't have the prefix, should return topic itself.
+ topic = [FIRMessagingPubSub removePrefixFromTopic:kTopicName];
+ XCTAssertEqualObjects(topic, kTopicName);
+}
+
@end
diff --git a/Example/Messaging/Tests/FIRMessagingServiceTest.m b/Example/Messaging/Tests/FIRMessagingServiceTest.m
index 073adad..afbae46 100644
--- a/Example/Messaging/Tests/FIRMessagingServiceTest.m
+++ b/Example/Messaging/Tests/FIRMessagingServiceTest.m
@@ -26,6 +26,11 @@
#import "InternalHeaders/FIRMessagingInternalUtilities.h"
#import "NSError+FIRMessaging.h"
+static NSString *const kFakeToken =
+ @"fE1e1PZJFSQ:APA91bFAOjp1ahBWn9rTlbjArwBEm_"
+ @"yUTTzK6dhIvLqzqqCSabaa4TQVM0pGTmF6r7tmMHPe6VYiGMHuCwJFgj5v97xl78sUNMLwuPPhoci8z_"
+ @"QGlCrTbxCFGzEUfvA3fGpGgIVQU2W6";
+
@interface FIRMessaging () <FIRMessagingClientDelegate>
@property(nonatomic, readwrite, strong) FIRMessagingClient *client;
@@ -40,22 +45,35 @@
@end
-
-@interface FIRMessagingServiceTest : XCTestCase
+@interface FIRMessagingServiceTest : XCTestCase {
+ FIRMessaging *_messaging;
+ id _mockPubSub;
+}
@end
@implementation FIRMessagingServiceTest
+- (void)setUp {
+ _messaging = [FIRMessaging messaging];
+ _messaging.defaultFcmToken = kFakeToken;
+ _mockPubSub = OCMPartialMock(_messaging.pubsub);
+ [super setUp];
+}
+
+- (void)tearDown {
+ [_mockPubSub stopMocking];
+ [super tearDown];
+}
+
- (void)testSubscribe {
id mockClient = OCMClassMock([FIRMessagingClient class]);
- FIRMessaging *service = [FIRMessaging messaging];
- [service setClient:mockClient];
- [service.pubsub setClient:mockClient];
+ [_messaging setClient:mockClient];
+ [_mockPubSub setClient:mockClient];
XCTestExpectation *subscribeExpectation =
[self expectationWithDescription:@"Should call subscribe on FIRMessagingClient"];
- NSString *token = @"abcdefghijklmn";
+ NSString *token = kFakeToken;
NSString *topic = @"/topics/some-random-topic";
[[[mockClient stub]
@@ -68,12 +86,12 @@
shouldDelete:NO
handler:OCMOCK_ANY];
- [service.pubsub subscribeWithToken:token
- topic:topic
- options:nil
- handler:^(NSError *error){
- // not a nil block
- }];
+ [_mockPubSub subscribeWithToken:token
+ topic:topic
+ options:nil
+ handler:^(NSError *error){
+ // not a nil block
+ }];
// should call updateSubscription
[self waitForExpectationsWithTimeout:0.1
@@ -85,14 +103,13 @@
- (void)testUnsubscribe {
id mockClient = OCMClassMock([FIRMessagingClient class]);
- FIRMessaging *messaging = [FIRMessaging messaging];
- [messaging setClient:mockClient];
- [messaging.pubsub setClient:mockClient];
+ [_messaging setClient:mockClient];
+ [_mockPubSub setClient:mockClient];
XCTestExpectation *subscribeExpectation =
[self expectationWithDescription:@"Should call unsubscribe on FIRMessagingClient"];
- NSString *token = @"abcdefghijklmn";
+ NSString *token = kFakeToken;
NSString *topic = @"/topics/some-random-topic";
[[[mockClient stub] andDo:^(NSInvocation *invocation) {
@@ -109,12 +126,12 @@
shouldDelete:YES
handler:OCMOCK_ANY];
- [messaging.pubsub unsubscribeWithToken:token
- topic:topic
- options:nil
- handler:^(NSError *error){
+ [_mockPubSub unsubscribeWithToken:token
+ topic:topic
+ options:nil
+ handler:^(NSError *error){
- }];
+ }];
// should call updateSubscription
[self waitForExpectationsWithTimeout:0.1
@@ -128,8 +145,8 @@
* Test using PubSub without explicitly starting FIRMessagingService.
*/
- (void)testSubscribeWithoutStart {
- [[[FIRMessaging messaging] pubsub]
- subscribeWithToken:@"abcdef1234"
+ [_mockPubSub
+ subscribeWithToken:kFakeToken
topic:@"/topics/hello-world"
options:nil
handler:^(NSError *error) {
@@ -141,19 +158,18 @@
// TODO(chliangGoogle) Investigate why invalid token can't throw assertion but the rest can under
// release build.
- (void)testSubscribeWithInvalidTopic {
- FIRMessaging *messaging = [FIRMessaging messaging];
XCTestExpectation *exceptionExpectation =
[self expectationWithDescription:@"Should throw exception for invalid token"];
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
- [messaging.pubsub subscribeWithToken:@"abcdef1234"
- topic:nil
- options:nil
- handler:^(NSError *error) {
- XCTFail(@"Should not invoke the handler");
- }];
+ [_mockPubSub subscribeWithToken:kFakeToken
+ topic:nil
+ options:nil
+ handler:^(NSError *error) {
+ XCTFail(@"Should not invoke the handler");
+ }];
#pragma clang diagnostic pop
}
@catch (NSException *exception) {
@@ -167,19 +183,17 @@
}
- (void)testUnsubscribeWithInvalidTopic {
- FIRMessaging *messaging = [FIRMessaging messaging];
-
XCTestExpectation *exceptionExpectation =
[self expectationWithDescription:@"Should throw exception for invalid token"];
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
- [messaging.pubsub unsubscribeWithToken:@"abcdef1234"
- topic:nil
- options:nil
- handler:^(NSError *error) {
- XCTFail(@"Should not invoke the handler");
- }];
+ [_mockPubSub unsubscribeWithToken:kFakeToken
+ topic:nil
+ options:nil
+ handler:^(NSError *error) {
+ XCTFail(@"Should not invoke the handler");
+ }];
#pragma clang diagnostic pop
}
@catch (NSException *exception) {
@@ -193,68 +207,66 @@
}
- (void)testSubscribeWithNoTopicPrefix {
- FIRMessaging *messaging = [FIRMessaging messaging];
- FIRMessagingPubSub *pubSub = messaging.pubsub;
- id mockPubSub = OCMClassMock([FIRMessagingPubSub class]);
NSString *topicName = @"topicWithoutPrefix";
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
- messaging.pubsub = mockPubSub;
- messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub subscribeToTopic:[OCMArg isEqual:topicNameWithPrefix]
- handler:[OCMArg any]]);
- [messaging subscribeToTopic:topicName];
- OCMVerifyAll(mockPubSub);
- // Need to swap back since it's a singleton and hence will live beyond the scope of this test.
- messaging.pubsub = pubSub;
+ OCMExpect(
+ [_mockPubSub subscribeToTopic:[OCMArg isEqual:topicNameWithPrefix] handler:[OCMArg any]]);
+ [_messaging subscribeToTopic:topicName];
+ OCMVerifyAll(_mockPubSub);
}
- (void)testSubscribeWithTopicPrefix {
- FIRMessaging *messaging = [FIRMessaging messaging];
- FIRMessagingPubSub *pubSub = messaging.pubsub;
- id mockPubSub = OCMClassMock([FIRMessagingPubSub class]);
-
NSString *topicName = @"/topics/topicWithoutPrefix";
- messaging.pubsub = mockPubSub;
- messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub subscribeToTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
- [messaging subscribeToTopic:topicName];
- OCMVerifyAll(mockPubSub);
- // Need to swap back since it's a singleton and hence will live beyond the scope of this test.
- messaging.pubsub = pubSub;
+ OCMExpect([_mockPubSub subscribeToTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
+ [_messaging subscribeToTopic:topicName];
+ OCMVerifyAll(_mockPubSub);
}
- (void)testUnsubscribeWithNoTopicPrefix {
- FIRMessaging *messaging = [FIRMessaging messaging];
- FIRMessagingPubSub *pubSub = messaging.pubsub;
- id mockPubSub = OCMClassMock([FIRMessagingPubSub class]);
-
NSString *topicName = @"topicWithoutPrefix";
NSString *topicNameWithPrefix = [FIRMessagingPubSub addPrefixToTopic:topicName];
- messaging.pubsub = mockPubSub;
- messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub unsubscribeFromTopic:[OCMArg isEqual:topicNameWithPrefix]
- handler:[OCMArg any]]);
- [messaging unsubscribeFromTopic:topicName];
- OCMVerifyAll(mockPubSub);
- // Need to swap back since it's a singleton and hence will live beyond the scope of this test.
- messaging.pubsub = pubSub;
+ OCMExpect(
+ [_mockPubSub unsubscribeFromTopic:[OCMArg isEqual:topicNameWithPrefix] handler:[OCMArg any]]);
+ [_messaging unsubscribeFromTopic:topicName];
+ OCMVerifyAll(_mockPubSub);
}
- (void)testUnsubscribeWithTopicPrefix {
- FIRMessaging *messaging = [FIRMessaging messaging];
- FIRMessagingPubSub *pubSub = messaging.pubsub;
- id mockPubSub = OCMClassMock([FIRMessagingPubSub class]);
-
NSString *topicName = @"/topics/topicWithPrefix";
- messaging.pubsub = mockPubSub;
- messaging.defaultFcmToken = @"fake-default-token";
- OCMExpect([messaging.pubsub unsubscribeFromTopic:[OCMArg isEqual:topicName]
- handler:[OCMArg any]]);
- [messaging unsubscribeFromTopic:topicName];
- OCMVerifyAll(mockPubSub);
- // Need to swap back since it's a singleton and hence will live beyond the scope of this test.
- messaging.pubsub = pubSub;
+ OCMExpect([_mockPubSub unsubscribeFromTopic:[OCMArg isEqual:topicName] handler:[OCMArg any]]);
+ [_messaging unsubscribeFromTopic:topicName];
+ OCMVerifyAll(_mockPubSub);
+}
+
+- (void)testSubscriptionCompletionHandlerWithSuccess {
+ OCMStub([_mockPubSub subscribeToTopic:[OCMArg any]
+ handler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
+ XCTestExpectation *subscriptionCompletionExpectation =
+ [self expectationWithDescription:@"Subscription is complete"];
+ [_messaging subscribeToTopic:@"news"
+ completion:^(NSError *error) {
+ XCTAssertNil(error);
+ [subscriptionCompletionExpectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:0.2
+ handler:^(NSError *_Nullable error){
+ }];
+}
+
+- (void)testUnsubscribeCompletionHandlerWithSuccess {
+ OCMStub([_mockPubSub unsubscribeFromTopic:[OCMArg any]
+ handler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
+ XCTestExpectation *unsubscriptionCompletionExpectation =
+ [self expectationWithDescription:@"Unsubscription is complete"];
+ [_messaging unsubscribeFromTopic:@"news"
+ completion:^(NSError *_Nullable error) {
+ XCTAssertNil(error);
+ [unsubscriptionCompletionExpectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:0.2
+ handler:^(NSError *_Nullable error){
+ }];
}
- (void)testFIRMessagingSDKVersionInFIRMessagingService {
diff --git a/Firebase/Auth/CHANGELOG.md b/Firebase/Auth/CHANGELOG.md
index 292f8bd..2669fc0 100644
--- a/Firebase/Auth/CHANGELOG.md
+++ b/Firebase/Auth/CHANGELOG.md
@@ -1,3 +1,7 @@
+# v5.0.2
+- Fix an issue where anonymous accounts weren't correctly promoted to
+ non-anonymous when linked with passwordless email auth accounts.
+
# v5.0.1
- Restore 4.x level of support for extensions (#1357).
diff --git a/Firebase/Auth/Source/FIRUser.m b/Firebase/Auth/Source/FIRUser.m
index 04aa861..3f5bf35 100644
--- a/Firebase/Auth/Source/FIRUser.m
+++ b/Firebase/Auth/Source/FIRUser.m
@@ -541,7 +541,7 @@ static void callInMainThreadWithAuthDataResultAndError(
- (void)updateEmail:(nullable NSString *)email
password:(nullable NSString *)password
callback:(nonnull FIRUserProfileChangeCallback)callback {
- if (password && ![password length]){
+ if (password && ![password length]) {
callback([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]);
return;
}
@@ -561,11 +561,9 @@ static void callInMainThreadWithAuthDataResultAndError(
return;
}
if (email) {
- self->_email = email;
+ self->_email = [email copy];
}
- if (self->_email && password) {
- self->_anonymous = NO;
- self->_hasEmailPasswordCredential = YES;
+ if (self->_email) {
if (!hadEmailPasswordCredential) {
// The list of providers need to be updated for the newly added email-password provider.
[self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
@@ -586,6 +584,20 @@ static void callInMainThreadWithAuthDataResultAndError(
callback(error);
return;
}
+ for (FIRGetAccountInfoResponseUser *userAccountInfo in response.users) {
+ // Set the account to non-anonymous if there are any providers, even if
+ // they're not email/password ones.
+ if (userAccountInfo.providerUserInfo.count > 0) {
+ self->_anonymous = NO;
+ }
+ for (FIRGetAccountInfoResponseProviderUserInfo *providerUserInfo in
+ userAccountInfo.providerUserInfo) {
+ if ([providerUserInfo.providerID isEqualToString:FIREmailAuthProviderID]) {
+ self->_hasEmailPasswordCredential = YES;
+ break;
+ }
+ }
+ }
[self updateWithGetAccountInfoResponse:response];
if (![self updateKeychain:&error]) {
callback(error);
diff --git a/Firebase/Core/CHANGELOG.md b/Firebase/Core/CHANGELOG.md
index e1f157a..9a02cb4 100644
--- a/Firebase/Core/CHANGELOG.md
+++ b/Firebase/Core/CHANGELOG.md
@@ -1,5 +1,9 @@
# Unreleased
+# 2018-06-19 -- v5.0.4 -- M28
+- [fixed] Fixed a thread sanitizer error (#1390)
+- [fixed] Updated FirebaseCore.podspec so that it works with cocoapods-packager. (#1378)
+
# 2018-05-29 -- v5.0.2 -- M26
- [changed] Delayed library registration call from `+load` to `+initialize`. (#1305)
diff --git a/Firebase/Core/FIRLogger.m b/Firebase/Core/FIRLogger.m
index 03f8a79..ae14e9f 100644
--- a/Firebase/Core/FIRLogger.m
+++ b/Firebase/Core/FIRLogger.m
@@ -54,10 +54,6 @@ NSString *const kFIRPersistedDebugModeKey = @"/google/firebase/debug_mode";
/// ASL client facility name used by FIRLogger.
const char *kFIRLoggerASLClientFacilityName = "com.firebase.app.logger";
-/// Message format used by ASL client that matches format of NSLog.
-const char *kFIRLoggerCustomASLMessageFormat =
- "$((Time)(J.3)) $(Sender)[$(PID)] <$((Level)(str))> $Message";
-
/// Keys for the number of errors and warnings logged.
NSString *const kFIRLoggerErrorCountKey = @"/google/firebase/count_of_errors_logged";
NSString *const kFIRLoggerWarningCountKey = @"/google/firebase/count_of_warnings_logged";
diff --git a/Firebase/Messaging/FIRMessaging.m b/Firebase/Messaging/FIRMessaging.m
index 3c4d999..100c18a 100644
--- a/Firebase/Messaging/FIRMessaging.m
+++ b/Firebase/Messaging/FIRMessaging.m
@@ -680,6 +680,9 @@ NSString *const kFIRMessagingPlistAutoInitEnabled =
#pragma mark - Topics
+ (NSString *)normalizeTopic:(NSString *)topic {
+ if (!topic.length) {
+ return nil;
+ }
if (![FIRMessagingPubSub hasTopicsPrefix:topic]) {
topic = [FIRMessagingPubSub addPrefixToTopic:topic];
}
@@ -695,24 +698,24 @@ NSString *const kFIRMessagingPlistAutoInitEnabled =
- (void)subscribeToTopic:(NSString *)topic
completion:(nullable FIRMessagingTopicOperationCompletion)completion {
- if (self.defaultFcmToken.length && topic.length) {
- NSString *normalizeTopic = [[self class ] normalizeTopic:topic];
- if ([FIRMessagingPubSub hasTopicsPrefix:topic]) {
- FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated,
- @"Format '%@' is deprecated. Only '%@' should be used in "
- @"subscribeToTopic.", topic, normalizeTopic);
- }
- if (normalizeTopic.length) {
- [self.pubsub subscribeToTopic:normalizeTopic handler:completion];
- } else {
- FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
- @"Cannot parse topic name %@. Will not subscribe.", topic);
- }
- } else {
- FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging010,
- @"Cannot subscribe to topic: %@ with token: %@", topic,
- self.defaultFcmToken);
+ if ([FIRMessagingPubSub hasTopicsPrefix:topic]) {
+ FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated,
+ @"Format '%@' is deprecated. Only '%@' should be used in "
+ @"subscribeToTopic.",
+ topic, [FIRMessagingPubSub removePrefixFromTopic:topic]);
+ }
+ if (!self.defaultFcmToken.length) {
+ FIRMessagingLoggerWarn(kFIRMessagingMessageCodeMessaging010,
+ @"The subscription operation is suspended because you don't have a "
+ @"token. The operation will resume once you get an FCM token.");
+ }
+ NSString *normalizeTopic = [[self class] normalizeTopic:topic];
+ if (normalizeTopic.length) {
+ [self.pubsub subscribeToTopic:normalizeTopic handler:completion];
+ return;
}
+ FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009,
+ @"Cannot parse topic name %@. Will not subscribe.", topic);
}
- (void)unsubscribeFromTopic:(NSString *)topic {
@@ -721,24 +724,24 @@ NSString *const kFIRMessagingPlistAutoInitEnabled =
- (void)unsubscribeFromTopic:(NSString *)topic
completion:(nullable FIRMessagingTopicOperationCompletion)completion {
- if (self.defaultFcmToken.length && topic.length) {
- NSString *normalizeTopic = [[self class] normalizeTopic:topic];
- if ([FIRMessagingPubSub hasTopicsPrefix:topic]) {
- FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated,
- @"Format '%@' is deprecated. Only '%@' should be used in "
- @"unsubscribeFromTopic.", topic, normalizeTopic);
- }
- if (normalizeTopic.length) {
- [self.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
- } else {
- FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
- @"Cannot parse topic name %@. Will not unsubscribe.", topic);
- }
- } else {
- FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging012,
- @"Cannot unsubscribe to topic: %@ with token: %@", topic,
- self.defaultFcmToken);
+ if ([FIRMessagingPubSub hasTopicsPrefix:topic]) {
+ FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated,
+ @"Format '%@' is deprecated. Only '%@' should be used in "
+ @"unsubscribeFromTopic.",
+ topic, [FIRMessagingPubSub removePrefixFromTopic:topic]);
+ }
+ if (!self.defaultFcmToken.length) {
+ FIRMessagingLoggerWarn(kFIRMessagingMessageCodeMessaging012,
+ @"The unsubscription operation is suspended because you don't have a "
+ @"token. The operation will resume once you get an FCM token.");
+ }
+ NSString *normalizeTopic = [[self class] normalizeTopic:topic];
+ if (normalizeTopic.length) {
+ [self.pubsub unsubscribeFromTopic:normalizeTopic handler:completion];
+ return;
}
+ FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011,
+ @"Cannot parse topic name %@. Will not unsubscribe.", topic);
}
#pragma mark - Send
diff --git a/Firebase/Messaging/FIRMessagingPubSub.h b/Firebase/Messaging/FIRMessagingPubSub.h
index 1c615d1..ebb4ca8 100644
--- a/Firebase/Messaging/FIRMessagingPubSub.h
+++ b/Firebase/Messaging/FIRMessagingPubSub.h
@@ -139,6 +139,15 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)addPrefixToTopic:(NSString *)topic;
/**
+ * Removes the "/topics/" prefix from the topic.
+ *
+ * @param topic The topic to remove the prefix from.
+ *
+ * @return The new topic name with the "/topics/" prefix removed.
+ */
+
++ (NSString *)removePrefixFromTopic:(NSString *)topic;
+/**
* Check if the topic name has "/topics/" prefix.
*
* @param topic The topic name to verify.
diff --git a/Firebase/Messaging/FIRMessagingPubSub.m b/Firebase/Messaging/FIRMessagingPubSub.m
index 09491b4..3f954e8 100644
--- a/Firebase/Messaging/FIRMessagingPubSub.m
+++ b/Firebase/Messaging/FIRMessagingPubSub.m
@@ -231,6 +231,14 @@ static NSString *const kTopicRegexPattern = @"/topics/([a-zA-Z0-9-_.~%]+)";
}
}
++ (NSString *)removePrefixFromTopic:(NSString *)topic {
+ if ([self hasTopicsPrefix:topic]) {
+ return [topic substringFromIndex:kTopicsPrefix.length];
+ } else {
+ return [topic copy];
+ }
+}
+
+ (BOOL)hasTopicsPrefix:(NSString *)topic {
return [topic hasPrefix:kTopicsPrefix];
}
diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec
index 441cd34..068d562 100644
--- a/FirebaseFirestore.podspec
+++ b/FirebaseFirestore.podspec
@@ -51,17 +51,23 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
s.dependency 'gRPC-ProtoRPC', '~> 1.0'
s.dependency 'leveldb-library', '~> 1.18'
s.dependency 'Protobuf', '~> 3.1'
+ s.dependency 'nanopb', '~> 0.3.8'
s.frameworks = 'MobileCoreServices'
s.library = 'c++'
s.pod_target_xcconfig = {
- 'GCC_PREPROCESSOR_DEFINITIONS' => 'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 ' +
- 'FIRFirestore_VERSION=' + s.version.to_s + ' PB_FIELD_16BIT',
+ 'GCC_PREPROCESSOR_DEFINITIONS' =>
+ "FIRFirestore_VERSION=#{s.version} " +
+ 'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 ' +
+ # The nanopb pod sets these defs, so we must too. (We *do* require 16bit
+ # (or larger) fields, so we'd have to set at least PB_FIELD_16BIT
+ # anyways.)
+ 'PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1',
'HEADER_SEARCH_PATHS' =>
'"${PODS_TARGET_SRCROOT}" ' +
'"${PODS_TARGET_SRCROOT}/Firestore/third_party/abseil-cpp" ' +
'"${PODS_ROOT}/nanopb" ' +
- '"${PODS_TARGET_SRCROOT}/Firestore/Protos/nanopb"'
+ '"${PODS_TARGET_SRCROOT}/Firestore/Protos/nanopb"',
}
s.prepare_command = <<-CMD
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index 2441b65..68b3a55 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -147,6 +147,19 @@
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
6161B5032047140C00A99DBB /* FIRFirestoreSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6161B5012047140400A99DBB /* FIRFirestoreSourceTests.mm */; };
+ 618BBEA620B89AAC00B5BCE7 /* target.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE7D20B89AAC00B5BCE7 /* target.pb.cc */; };
+ 618BBEA720B89AAC00B5BCE7 /* maybe_document.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */; };
+ 618BBEA820B89AAC00B5BCE7 /* mutation.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8220B89AAC00B5BCE7 /* mutation.pb.cc */; };
+ 618BBEA920B89AAC00B5BCE7 /* common.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8820B89AAC00B5BCE7 /* common.pb.cc */; };
+ 618BBEAA20B89AAC00B5BCE7 /* firestore.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8A20B89AAC00B5BCE7 /* firestore.pb.cc */; };
+ 618BBEAB20B89AAC00B5BCE7 /* query.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8C20B89AAC00B5BCE7 /* query.pb.cc */; };
+ 618BBEAC20B89AAC00B5BCE7 /* document.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8E20B89AAC00B5BCE7 /* document.pb.cc */; };
+ 618BBEAD20B89AAC00B5BCE7 /* write.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8F20B89AAC00B5BCE7 /* write.pb.cc */; };
+ 618BBEAE20B89AAC00B5BCE7 /* latlng.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9220B89AAC00B5BCE7 /* latlng.pb.cc */; };
+ 618BBEAF20B89AAC00B5BCE7 /* annotations.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9520B89AAC00B5BCE7 /* annotations.pb.cc */; };
+ 618BBEB020B89AAC00B5BCE7 /* http.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */; };
+ 618BBEB120B89AAC00B5BCE7 /* status.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9920B89AAC00B5BCE7 /* status.pb.cc */; };
+ 61F72C5620BC48FD001A68CB /* serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 61F72C5520BC48FD001A68CB /* serializer_test.cc */; };
6EDD3B4620BF247500C33877 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6EDD3B4820BF247500C33877 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6EDD3B4920BF247500C33877 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
@@ -274,7 +287,7 @@
3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = "<group>"; };
3C81DE3772628FE297055662 /* Pods-Firestore_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.debug.xcconfig"; sourceTree = "<group>"; };
3F0992A4B83C60841C52E960 /* Pods-Firestore_Example_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.release.xcconfig"; sourceTree = "<group>"; };
- 403DBF6EFB541DFD01582AA3 /* path_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = path_test.cc; sourceTree = "<group>"; };
+ 403DBF6EFB541DFD01582AA3 /* path_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = path_test.cc; sourceTree = "<group>"; };
444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = hard_assert_test.cc; sourceTree = "<group>"; };
54131E9620ADE678001DF3FF /* string_format_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_format_test.cc; sourceTree = "<group>"; };
54511E8D209805F8005BD28F /* hashing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashing_test.cc; sourceTree = "<group>"; };
@@ -411,6 +424,31 @@
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>"; };
+ 618BBE7D20B89AAC00B5BCE7 /* target.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = target.pb.cc; sourceTree = "<group>"; };
+ 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maybe_document.pb.cc; sourceTree = "<group>"; };
+ 618BBE7F20B89AAC00B5BCE7 /* target.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = target.pb.h; sourceTree = "<group>"; };
+ 618BBE8020B89AAC00B5BCE7 /* maybe_document.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maybe_document.pb.h; sourceTree = "<group>"; };
+ 618BBE8120B89AAC00B5BCE7 /* mutation.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mutation.pb.h; sourceTree = "<group>"; };
+ 618BBE8220B89AAC00B5BCE7 /* mutation.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutation.pb.cc; sourceTree = "<group>"; };
+ 618BBE8620B89AAC00B5BCE7 /* query.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = query.pb.h; sourceTree = "<group>"; };
+ 618BBE8720B89AAC00B5BCE7 /* common.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.pb.h; sourceTree = "<group>"; };
+ 618BBE8820B89AAC00B5BCE7 /* common.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = common.pb.cc; sourceTree = "<group>"; };
+ 618BBE8920B89AAC00B5BCE7 /* firestore.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = firestore.pb.h; sourceTree = "<group>"; };
+ 618BBE8A20B89AAC00B5BCE7 /* firestore.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = firestore.pb.cc; sourceTree = "<group>"; };
+ 618BBE8B20B89AAC00B5BCE7 /* write.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = write.pb.h; sourceTree = "<group>"; };
+ 618BBE8C20B89AAC00B5BCE7 /* query.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = query.pb.cc; sourceTree = "<group>"; };
+ 618BBE8D20B89AAC00B5BCE7 /* document.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = document.pb.h; sourceTree = "<group>"; };
+ 618BBE8E20B89AAC00B5BCE7 /* document.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = document.pb.cc; sourceTree = "<group>"; };
+ 618BBE8F20B89AAC00B5BCE7 /* write.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = write.pb.cc; sourceTree = "<group>"; };
+ 618BBE9120B89AAC00B5BCE7 /* latlng.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latlng.pb.h; sourceTree = "<group>"; };
+ 618BBE9220B89AAC00B5BCE7 /* latlng.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = latlng.pb.cc; sourceTree = "<group>"; };
+ 618BBE9420B89AAC00B5BCE7 /* http.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http.pb.h; sourceTree = "<group>"; };
+ 618BBE9520B89AAC00B5BCE7 /* annotations.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = annotations.pb.cc; sourceTree = "<group>"; };
+ 618BBE9620B89AAC00B5BCE7 /* annotations.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = annotations.pb.h; sourceTree = "<group>"; };
+ 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http.pb.cc; sourceTree = "<group>"; };
+ 618BBE9920B89AAC00B5BCE7 /* status.pb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status.pb.cc; sourceTree = "<group>"; };
+ 618BBE9A20B89AAC00B5BCE7 /* status.pb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status.pb.h; sourceTree = "<group>"; };
+ 61F72C5520BC48FD001A68CB /* serializer_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serializer_test.cc; sourceTree = "<group>"; };
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>"; };
6EDD3B5B20BF247500C33877 /* Firestore_FuzzTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_FuzzTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6EDD3B5C20BF247500C33877 /* Firestore_FuzzTests_iOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Firestore_FuzzTests_iOS-Info.plist"; sourceTree = "<group>"; };
@@ -567,6 +605,7 @@
isa = PBXGroup;
children = (
546854A820A36867004BDBD5 /* datastore_test.cc */,
+ 61F72C5520BC48FD001A68CB /* serializer_test.cc */,
);
path = remote;
sourceTree = "<group>";
@@ -665,6 +704,7 @@
6003F581195388D10070C39A = {
isa = PBXGroup;
children = (
+ 618BBE7A20B89AAC00B5BCE7 /* CoreTestsProtos */,
6EDD3B5D20BF24A700C33877 /* FuzzTests */,
543B4F0520A91E4B001F506D /* App */,
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */,
@@ -769,6 +809,102 @@
name = "Podspec Metadata";
sourceTree = "<group>";
};
+ 618BBE7A20B89AAC00B5BCE7 /* CoreTestsProtos */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE7B20B89AAC00B5BCE7 /* firestore */,
+ 618BBE8320B89AAC00B5BCE7 /* google */,
+ );
+ name = CoreTestsProtos;
+ path = ../Protos/cpp;
+ sourceTree = "<group>";
+ };
+ 618BBE7B20B89AAC00B5BCE7 /* firestore */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE7C20B89AAC00B5BCE7 /* local */,
+ );
+ path = firestore;
+ sourceTree = "<group>";
+ };
+ 618BBE7C20B89AAC00B5BCE7 /* local */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */,
+ 618BBE8020B89AAC00B5BCE7 /* maybe_document.pb.h */,
+ 618BBE8220B89AAC00B5BCE7 /* mutation.pb.cc */,
+ 618BBE8120B89AAC00B5BCE7 /* mutation.pb.h */,
+ 618BBE7D20B89AAC00B5BCE7 /* target.pb.cc */,
+ 618BBE7F20B89AAC00B5BCE7 /* target.pb.h */,
+ );
+ path = local;
+ sourceTree = "<group>";
+ };
+ 618BBE8320B89AAC00B5BCE7 /* google */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE9320B89AAC00B5BCE7 /* api */,
+ 618BBE8420B89AAC00B5BCE7 /* firestore */,
+ 618BBE9820B89AAC00B5BCE7 /* rpc */,
+ 618BBE9020B89AAC00B5BCE7 /* type */,
+ );
+ path = google;
+ sourceTree = "<group>";
+ };
+ 618BBE8420B89AAC00B5BCE7 /* firestore */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE8520B89AAC00B5BCE7 /* v1beta1 */,
+ );
+ path = firestore;
+ sourceTree = "<group>";
+ };
+ 618BBE8520B89AAC00B5BCE7 /* v1beta1 */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE8820B89AAC00B5BCE7 /* common.pb.cc */,
+ 618BBE8720B89AAC00B5BCE7 /* common.pb.h */,
+ 618BBE8E20B89AAC00B5BCE7 /* document.pb.cc */,
+ 618BBE8D20B89AAC00B5BCE7 /* document.pb.h */,
+ 618BBE8A20B89AAC00B5BCE7 /* firestore.pb.cc */,
+ 618BBE8920B89AAC00B5BCE7 /* firestore.pb.h */,
+ 618BBE8C20B89AAC00B5BCE7 /* query.pb.cc */,
+ 618BBE8620B89AAC00B5BCE7 /* query.pb.h */,
+ 618BBE8F20B89AAC00B5BCE7 /* write.pb.cc */,
+ 618BBE8B20B89AAC00B5BCE7 /* write.pb.h */,
+ );
+ path = v1beta1;
+ sourceTree = "<group>";
+ };
+ 618BBE9020B89AAC00B5BCE7 /* type */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE9220B89AAC00B5BCE7 /* latlng.pb.cc */,
+ 618BBE9120B89AAC00B5BCE7 /* latlng.pb.h */,
+ );
+ path = type;
+ sourceTree = "<group>";
+ };
+ 618BBE9320B89AAC00B5BCE7 /* api */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE9520B89AAC00B5BCE7 /* annotations.pb.cc */,
+ 618BBE9620B89AAC00B5BCE7 /* annotations.pb.h */,
+ 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */,
+ 618BBE9420B89AAC00B5BCE7 /* http.pb.h */,
+ );
+ path = api;
+ sourceTree = "<group>";
+ };
+ 618BBE9820B89AAC00B5BCE7 /* rpc */ = {
+ isa = PBXGroup;
+ children = (
+ 618BBE9920B89AAC00B5BCE7 /* status.pb.cc */,
+ 618BBE9A20B89AAC00B5BCE7 /* status.pb.h */,
+ );
+ path = rpc;
+ sourceTree = "<group>";
+ };
6EDD3B5D20BF24A700C33877 /* FuzzTests */ = {
isa = PBXGroup;
children = (
@@ -1360,12 +1496,14 @@
"${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
"${BUILT_PRODUCTS_DIR}/GoogleTest/GoogleTest.framework",
"${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework",
+ "${BUILT_PRODUCTS_DIR}/ProtobufCpp/ProtobufCpp.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleTest.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProtobufCpp.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -1639,6 +1777,7 @@
5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */,
5492E0AB2021552D00B64F25 /* StringViewTests.mm in Sources */,
5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */,
+ 618BBEAF20B89AAC00B5BCE7 /* annotations.pb.cc in Sources */,
5467FB08203E6A44009C9584 /* app_testing.mm in Sources */,
54EB764D202277B30088B8F3 /* array_sorted_map_test.cc in Sources */,
B6FB4684208EA0EC00554BA2 /* async_queue_libdispatch_test.mm in Sources */,
@@ -1646,11 +1785,13 @@
B6FB467D208E9D3C00554BA2 /* async_queue_test.cc in Sources */,
54740A581FC914F000713A1A /* autoid_test.cc in Sources */,
AB380D02201BC69F00D97691 /* bits_test.cc in Sources */,
+ 618BBEA920B89AAC00B5BCE7 /* common.pb.cc in Sources */,
548DB929200D59F600E00ABC /* comparison_test.cc in Sources */,
ABC1D7DC2023A04B00BA84F0 /* credentials_provider_test.cc in Sources */,
ABE6637A201FA81900ED349A /* database_id_test.cc in Sources */,
AB38D93020236E21000A432D /* database_info_test.cc in Sources */,
546854AA20A36867004BDBD5 /* datastore_test.cc in Sources */,
+ 618BBEAC20B89AAC00B5BCE7 /* document.pb.cc in Sources */,
B6152AD7202A53CB000E5744 /* document_key_test.cc in Sources */,
AB6B908420322E4D00CC290A /* document_test.cc in Sources */,
ABC1D7DD2023A04F00BA84F0 /* empty_credentials_provider_test.cc in Sources */,
@@ -1662,28 +1803,37 @@
54A0352620A3AED0003E0143 /* field_transform_test.mm in Sources */,
AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */,
ABC1D7E42024AFDE00BA84F0 /* firebase_credentials_provider_test.mm in Sources */,
+ 618BBEAA20B89AAC00B5BCE7 /* firestore.pb.cc in Sources */,
AB7BAB342012B519001E0872 /* geo_point_test.cc in Sources */,
73FE5066020EF9B2892C86BF /* hard_assert_test.cc in Sources */,
54511E8E209805F8005BD28F /* hashing_test.cc in Sources */,
+ 618BBEB020B89AAC00B5BCE7 /* http.pb.cc in Sources */,
54A0353520A3D8CB003E0143 /* iterator_adaptors_test.cc in Sources */,
+ 618BBEAE20B89AAC00B5BCE7 /* latlng.pb.cc in Sources */,
54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */,
54C2294F1FECABAE007D065B /* log_test.cc in Sources */,
+ 618BBEA720B89AAC00B5BCE7 /* maybe_document.pb.cc in Sources */,
AB6B908620322E6D00CC290A /* maybe_document_test.cc in Sources */,
+ 618BBEA820B89AAC00B5BCE7 /* mutation.pb.cc in Sources */,
AB6B908820322E8800CC290A /* no_document_test.cc in Sources */,
AB380D04201BC6E400D97691 /* ordered_code_test.cc in Sources */,
5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */,
549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */,
+ 618BBEAB20B89AAC00B5BCE7 /* query.pb.cc in Sources */,
B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */,
54740A571FC914BA00713A1A /* secure_random_test.cc in Sources */,
+ 61F72C5620BC48FD001A68CB /* serializer_test.cc in Sources */,
ABA495BB202B7E80008A7851 /* snapshot_version_test.cc in Sources */,
549CCA5220A36DBC00BCEB75 /* sorted_map_test.cc in Sources */,
549CCA5020A36DBC00BCEB75 /* sorted_set_test.cc in Sources */,
+ 618BBEB120B89AAC00B5BCE7 /* status.pb.cc in Sources */,
54A0352F20A3B3D8003E0143 /* status_test.cc in Sources */,
54A0353020A3B3D8003E0143 /* statusor_test.cc in Sources */,
1CAA9012B25F975D445D5978 /* strerror_test.cc in Sources */,
0535C1B65DADAE1CE47FA3CA /* string_format_apple_test.mm in Sources */,
54131E9720ADE679001DF3FF /* string_format_test.cc in Sources */,
AB380CFE201A2F4500D97691 /* string_util_test.cc in Sources */,
+ 618BBEA620B89AAC00B5BCE7 /* target.pb.cc in Sources */,
AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */,
54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */,
ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */,
@@ -1692,6 +1842,7 @@
549CCA5120A36DBC00BCEB75 /* tree_sorted_map_test.cc in Sources */,
C80B10E79CDD7EF7843C321E /* type_traits_apple_test.mm in Sources */,
ABC1D7DE2023A05300BA84F0 /* user_test.cc in Sources */,
+ 618BBEAD20B89AAC00B5BCE7 /* write.pb.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1924,6 +2075,7 @@
HEADER_SEARCH_PATHS = "";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
ONLY_ACTIVE_ARCH = YES;
+ OTHER_CFLAGS = "";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -1957,6 +2109,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ OTHER_CFLAGS = "";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
@@ -2036,10 +2189,61 @@
"\"${PODS_ROOT}/GoogleTest/googlemock/include\"",
"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/../../../Firestore/Protos/cpp\"",
+ "\"${PODS_ROOT}/ProtobufCpp/src\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleTest/GoogleTest.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/OCMock/OCMock.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/ProtobufCpp/ProtobufCpp.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library/leveldb.framework/Headers\"",
+ "$(inherited)",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/BoringSSL/openssl.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth/FirebaseAuth.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseFirestore/FirebaseFirestore.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf/Protobuf.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core/grpc.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-ProtoRPC/ProtoRPC.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-RxLibrary/RxLibrary.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/GRPCClient.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library/leveldb.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public/Firebase\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public/FirebaseAnalytics\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public/FirebaseInstanceID\"",
+ "-DPB_FIELD_32BIT",
+ "-DPB_NO_PACKED_STRUCTS=1",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
+ SYSTEM_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/nanopb\"";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Firestore_Example_iOS.app/Firestore_Example_iOS";
WRAPPER_EXTENSION = xctest;
};
@@ -2070,10 +2274,61 @@
"\"${PODS_ROOT}/GoogleTest/googlemock/include\"",
"\"${PODS_ROOT}/GoogleTest/googletest/include\"",
"\"${PODS_ROOT}/leveldb-library/include\"",
+ "\"${PODS_ROOT}/../../../Firestore/Protos/cpp\"",
+ "\"${PODS_ROOT}/ProtobufCpp/src\"",
);
INFOPLIST_FILE = "Tests/Tests-Info.plist";
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleTest/GoogleTest.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/OCMock/OCMock.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/ProtobufCpp/ProtobufCpp.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library/leveldb.framework/Headers\"",
+ "$(inherited)",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/BoringSSL/openssl.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAuth/FirebaseAuth.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseFirestore/FirebaseFirestore.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf/Protobuf.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core/grpc.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-ProtoRPC/ProtoRPC.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-RxLibrary/RxLibrary.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/GRPCClient.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/leveldb-library/leveldb.framework/Headers\"",
+ "-iquote",
+ "\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public/Firebase\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public/FirebaseAnalytics\"",
+ "-isystem",
+ "\"${PODS_ROOT}/Headers/Public/FirebaseInstanceID\"",
+ "-DPB_FIELD_32BIT",
+ "-DPB_NO_PACKED_STRUCTS=1",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
+ SYSTEM_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/nanopb\"";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Firestore_Example_iOS.app/Firestore_Example_iOS";
WRAPPER_EXTENSION = xctest;
};
diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme
index 039273b..051b1a4 100644
--- a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme
+++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme
@@ -5,6 +5,19 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForRunning = "YES"
+ buildForTesting = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "6EDD3AD120BF247500C33877"
+ BuildableName = "Firestore_FuzzTests_iOS.xctest"
+ BlueprintName = "Firestore_FuzzTests_iOS"
+ ReferencedContainer = "container:Firestore.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile
index 8439260..881747a 100644
--- a/Firestore/Example/Podfile
+++ b/Firestore/Example/Podfile
@@ -22,6 +22,7 @@ target 'Firestore_Example_iOS' do
pod 'leveldb-library'
pod 'OCMock'
pod 'GoogleTest', :podspec => 'GoogleTest.podspec'
+ pod 'ProtobufCpp', :podspec => 'ProtobufCpp.podspec'
end
target 'Firestore_IntegrationTests_iOS' do
diff --git a/Firestore/Example/ProtobufCpp.podspec b/Firestore/Example/ProtobufCpp.podspec
new file mode 100644
index 0000000..c809c06
--- /dev/null
+++ b/Firestore/Example/ProtobufCpp.podspec
@@ -0,0 +1,74 @@
+# Copyright 2018 Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A Private podspec for Protobuf which exposes the C++ headers (rather than
+# only the Obj-C headers). Suitable only for use inside this source tree.
+
+Pod::Spec.new do |s|
+ s.name = 'ProtobufCpp'
+ s.version = '3.5.2'
+ s.summary = 'Protocol Buffers v.3 runtime library for C++.'
+ s.homepage = 'https://github.com/google/protobuf'
+ s.license = '3-Clause BSD License'
+ s.authors = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
+ s.cocoapods_version = '>= 1.0'
+
+ s.source = {
+ :git => 'https://github.com/google/protobuf.git',
+ :tag => "v#{s.version}"
+ }
+
+ s.source_files = 'src/**/*.{h,cc}'
+ s.exclude_files = # skip test files. (Yes, the test files are intermixed with
+ # the source. No there doesn't seem to be a common/simple
+ # pattern we could use to exclude them; 'test' appears in
+ # various places throughout the file names and also in a
+ # non-test file. So, we'll exclude all files that either
+ # start with 'test' or include test and have a previous
+ # character that isn't "y" (so that bytestream isn't
+ # matched.))
+ 'src/**/test*.*',
+ 'src/**/*[^y]test*.*',
+ 'src/**/testing/**',
+ 'src/**/mock*',
+ # skip the javascript handling code.
+ 'src/**/js/**',
+ # skip the protoc compiler
+ 'src/google/protobuf/compiler/**/*'
+
+ s.header_mappings_dir = 'src/'
+
+ # Set a CPP symbol so the code knows to use framework imports.
+ s.pod_target_xcconfig = {
+ 'GCC_PREPROCESSOR_DEFINITIONS' =>
+ '$(inherited) ' +
+ 'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 ' +
+ 'HAVE_PTHREAD=1',
+ 'HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/ProtobufCpp/src"',
+
+ # Cocoapods flattens header imports, leading to much anguish. The
+ # following two statements work around this.
+ # - https://github.com/CocoaPods/CocoaPods/issues/1437
+ 'USE_HEADERMAP' => 'NO',
+ 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
+ }
+
+ # Disable warnings that upstream does not concern itself with
+ s.compiler_flags = '$(inherited) ' +
+ '-Wno-comma ' +
+ '-Wno-shorten-64-to-32'
+
+ s.requires_arc = false
+ s.library = 'c++'
+end
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
index 3da8083..e6ab720 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
@@ -42,7 +42,7 @@ using leveldb::Status;
@end
@implementation FSTLevelDBMigrationsTests {
- std::shared_ptr<DB> _db;
+ std::unique_ptr<DB> _db;
}
- (void)setUp {
@@ -62,12 +62,12 @@ using leveldb::Status;
}
- (void)testAddsTargetGlobal {
- FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
+ FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db.get()];
XCTAssertNil(metadata, @"Not expecting metadata yet, we should have an empty db");
LevelDbTransaction transaction(_db.get(), "testAddsTargetGlobal");
[FSTLevelDBMigrations runMigrationsWithTransaction:&transaction];
transaction.Commit();
- metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
+ metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db.get()];
XCTAssertNotNil(metadata, @"Migrations should have added the metadata");
}
@@ -107,7 +107,7 @@ using leveldb::Status;
LevelDbTransaction transaction(_db.get(), "testCountsQueries");
[FSTLevelDBMigrations runMigrationsWithTransaction:&transaction];
transaction.Commit();
- FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
+ FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db.get()];
XCTAssertEqual(expected, metadata.targetCount, @"Failed to count all of the targets we added");
}
}
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
index 29f5d6c..5c2718b 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
@@ -46,7 +46,7 @@ using firebase::firestore::local::LevelDbTransaction;
@end
@implementation FSTLevelDBTransactionTests {
- std::shared_ptr<DB> _db;
+ std::unique_ptr<DB> _db;
}
- (void)setUp {
diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm
index c6936f7..715f09b 100644
--- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm
+++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm
@@ -93,8 +93,6 @@ NS_ASSUME_NONNULL_BEGIN
* Creates an aggregator initialized with the set of provided FSTWatchChanges. Tests can add further
* changes via `handleDocumentChange`, `handleTargetChange` and `handleExistenceFilterChange`.
*
- * @param snapshotVersion The version at which to create the remote event. This corresponds to the
- * snapshot version provided by a NO_CHANGE event.
* @param targetMap A map of query data for all active targets. The map must include an entry for
* every target referenced by any of the watch changes.
* @param outstandingResponses The number of outstanding ACKs a target has to receive before it is
diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm
index 89cb774..bf7b053 100644
--- a/Firestore/Source/Core/FSTSyncEngine.mm
+++ b/Firestore/Source/Core/FSTSyncEngine.mm
@@ -28,7 +28,6 @@
#import "Firestore/Source/Core/FSTTransaction.h"
#import "Firestore/Source/Core/FSTView.h"
#import "Firestore/Source/Core/FSTViewSnapshot.h"
-#import "Firestore/Source/Local/FSTEagerGarbageCollector.h"
#import "Firestore/Source/Local/FSTLocalStore.h"
#import "Firestore/Source/Local/FSTLocalViewChanges.h"
#import "Firestore/Source/Local/FSTLocalWriteResult.h"
@@ -136,9 +135,6 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
/** Used to track any documents that are currently in limbo. */
@property(nonatomic, strong, readonly) FSTReferenceSet *limboDocumentRefs;
-/** The garbage collector used to collect documents that are no longer in limbo. */
-@property(nonatomic, strong, readonly) FSTEagerGarbageCollector *limboCollector;
-
@end
@implementation FSTSyncEngine {
@@ -171,10 +167,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
_queryViewsByQuery = [NSMutableDictionary dictionary];
_queryViewsByTarget = [NSMutableDictionary dictionary];
- _limboCollector = [[FSTEagerGarbageCollector alloc] init];
_limboDocumentRefs = [[FSTReferenceSet alloc] init];
- [_limboCollector addGarbageSource:_limboDocumentRefs];
-
_targetIdGenerator = TargetIdGenerator::SyncEngineTargetIdGenerator(0);
_currentUser = initialUser;
}
@@ -399,8 +392,14 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
[self.queryViewsByQuery removeObjectForKey:queryView.query];
[self.queryViewsByTarget removeObjectForKey:@(queryView.targetID)];
+ DocumentKeySet limboKeys = [self.limboDocumentRefs referencedKeysForID:queryView.targetID];
[self.limboDocumentRefs removeReferencesForID:queryView.targetID];
- [self garbageCollectLimboDocuments];
+ for (const DocumentKey &key : limboKeys) {
+ if (![self.limboDocumentRefs containsKey:key]) {
+ // We removed the last reference for this key.
+ [self removeLimboTargetForKey:key];
+ }
+ }
}
/**
@@ -462,13 +461,16 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
case FSTLimboDocumentChangeTypeRemoved:
LOG_DEBUG("Document no longer in limbo: %s", limboChange.key.ToString());
[self.limboDocumentRefs removeReferenceToKey:limboChange.key forID:targetID];
+ if (![self.limboDocumentRefs containsKey:limboChange.key]) {
+ // We removed the last reference for this key
+ [self removeLimboTargetForKey:limboChange.key];
+ }
break;
default:
HARD_FAIL("Unknown limbo change type: %s", limboChange.type);
}
}
- [self garbageCollectLimboDocuments];
}
- (void)trackLimboChange:(FSTLimboDocumentChange *)limboChange {
@@ -488,20 +490,16 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
}
}
-/** Garbage collect the limbo documents that we no longer need to track. */
-- (void)garbageCollectLimboDocuments {
- const std::set<DocumentKey> garbage = [self.limboCollector collectGarbage];
- for (const DocumentKey &key : garbage) {
- const auto iter = _limboTargetsByKey.find(key);
- if (iter == _limboTargetsByKey.end()) {
- // This target already got removed, because the query failed.
- return;
- }
- TargetId limboTargetID = iter->second;
- [self.remoteStore stopListeningToTargetID:limboTargetID];
- _limboTargetsByKey.erase(key);
- _limboKeysByTarget.erase(limboTargetID);
+- (void)removeLimboTargetForKey:(const DocumentKey &)key {
+ const auto iter = _limboTargetsByKey.find(key);
+ if (iter == _limboTargetsByKey.end()) {
+ // This target already got removed, because the query failed.
+ return;
}
+ TargetId limboTargetID = iter->second;
+ [self.remoteStore stopListeningToTargetID:limboTargetID];
+ _limboTargetsByKey.erase(key);
+ _limboKeysByTarget.erase(limboTargetID);
}
// Used for testing
diff --git a/Firestore/Source/Local/FSTLevelDB.h b/Firestore/Source/Local/FSTLevelDB.h
index 95b80a6..a56c133 100644
--- a/Firestore/Source/Local/FSTLevelDB.h
+++ b/Firestore/Source/Local/FSTLevelDB.h
@@ -95,7 +95,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)descriptionOfStatus:(leveldb::Status)status;
/** The native db pointer, allocated during start. */
-@property(nonatomic, assign, readonly) std::shared_ptr<leveldb::DB> ptr;
+@property(nonatomic, assign, readonly) leveldb::DB *ptr;
@property(nonatomic, readonly) firebase::firestore::local::LevelDbTransaction *currentTransaction;
diff --git a/Firestore/Source/Local/FSTLevelDB.mm b/Firestore/Source/Local/FSTLevelDB.mm
index 9f75a3e..9dc50a2 100644
--- a/Firestore/Source/Local/FSTLevelDB.mm
+++ b/Firestore/Source/Local/FSTLevelDB.mm
@@ -17,6 +17,7 @@
#import "Firestore/Source/Local/FSTLevelDB.h"
#include <memory>
+#include <utility>
#import "FIRFirestoreErrors.h"
#import "Firestore/Source/Local/FSTLevelDBMigrations.h"
@@ -60,6 +61,7 @@ using leveldb::WriteOptions;
@implementation FSTLevelDB {
std::unique_ptr<LevelDbTransaction> _transaction;
+ std::unique_ptr<leveldb::DB> _ptr;
FSTTransactionRunner _transactionRunner;
}
@@ -82,6 +84,10 @@ using leveldb::WriteOptions;
return self;
}
+- (leveldb::DB *)ptr {
+ return _ptr.get();
+}
+
- (const FSTTransactionRunner &)run {
return _transactionRunner;
}
diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.h b/Firestore/Source/Local/FSTLevelDBMutationQueue.h
index 034738f..911fa37 100644
--- a/Firestore/Source/Local/FSTLevelDBMutationQueue.h
+++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.h
@@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
* Returns one larger than the largest batch ID that has been stored. If there are no mutations
* returns 0. Note that batch IDs are global.
*/
-+ (FSTBatchID)loadNextBatchIDFromDB:(std::shared_ptr<leveldb::DB>)db;
++ (FSTBatchID)loadNextBatchIDFromDB:(leveldb::DB *)db;
@end
diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
index 3b4687c..94ab8a5 100644
--- a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
+++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
@@ -132,7 +132,7 @@ using leveldb::WriteOptions;
self.metadata = metadata;
}
-+ (FSTBatchID)loadNextBatchIDFromDB:(std::shared_ptr<DB>)db {
++ (FSTBatchID)loadNextBatchIDFromDB:(DB *)db {
// TODO(gsoltis): implement Prev() and SeekToLast() on LevelDbTransaction::Iterator, then port
// this to a transaction.
std::unique_ptr<Iterator> it(db->NewIterator(LevelDbTransaction::DefaultReadOptions()));
diff --git a/Firestore/Source/Local/FSTLevelDBQueryCache.h b/Firestore/Source/Local/FSTLevelDBQueryCache.h
index 2cd6758..f756d9e 100644
--- a/Firestore/Source/Local/FSTLevelDBQueryCache.h
+++ b/Firestore/Source/Local/FSTLevelDBQueryCache.h
@@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
* Retrieves the global singleton metadata row from the given database, if it exists.
* TODO(gsoltis): remove this method once fully ported to transactions.
*/
-+ (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(std::shared_ptr<leveldb::DB>)db;
++ (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(leveldb::DB *)db;
/**
* Retrieves the global singleton metadata row using the given transaction, if it exists.
diff --git a/Firestore/Source/Local/FSTLevelDBQueryCache.mm b/Firestore/Source/Local/FSTLevelDBQueryCache.mm
index f28370a..31c2a2e 100644
--- a/Firestore/Source/Local/FSTLevelDBQueryCache.mm
+++ b/Firestore/Source/Local/FSTLevelDBQueryCache.mm
@@ -85,7 +85,7 @@ using firebase::firestore::model::DocumentKeySet;
return proto;
}
-+ (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(std::shared_ptr<DB>)db {
++ (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(DB *)db {
std::string key = [FSTLevelDBTargetGlobalKey key];
std::string value;
Status status = db->Get([FSTLevelDB standardReadOptions], key, &value);
diff --git a/Firestore/Source/Remote/FSTDatastore.mm b/Firestore/Source/Remote/FSTDatastore.mm
index fdbeea3..33d29e9 100644
--- a/Firestore/Source/Remote/FSTDatastore.mm
+++ b/Firestore/Source/Remote/FSTDatastore.mm
@@ -240,7 +240,7 @@ typedef GRPCProtoCall * (^RPCFactory)(void);
error = [FSTDatastore firestoreErrorForError:error];
[self.workerDispatchQueue dispatchAsync:^{
if (error != nil && error.code == FIRFirestoreErrorCodeUnauthenticated) {
- _credentials->InvalidateToken();
+ self->_credentials->InvalidateToken();
}
LOG_DEBUG("RPC CommitRequest completed. Error: %s", error);
[FSTDatastore logHeadersForRPC:rpc RPCName:@"CommitRequest"];
@@ -277,7 +277,7 @@ typedef GRPCProtoCall * (^RPCFactory)(void);
if (error) {
LOG_DEBUG("RPC BatchGetDocuments completed. Error: %s", error);
if (error.code == FIRFirestoreErrorCodeUnauthenticated) {
- _credentials->InvalidateToken();
+ self->_credentials->InvalidateToken();
}
[FSTDatastore logHeadersForRPC:rpc RPCName:@"BatchGetDocuments"];
completion(nil, error);
diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h
index 9ea0f9c..02a5289 100644
--- a/Firestore/Source/Remote/FSTRemoteEvent.h
+++ b/Firestore/Source/Remote/FSTRemoteEvent.h
@@ -176,6 +176,9 @@ initWithSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVer
/** Processes and adds the WatchTargetChange to the current set of changes. */
- (void)handleTargetChange:(FSTWatchTargetChange *)targetChange;
+/** Removes the in-memory state for the provided target. */
+- (void)removeTarget:(FSTTargetID)targetID;
+
/**
* Handles existence filters and synthesizes deletes for filter mismatches. Targets that are
* invalidated by filter mismatches are added to `targetMismatches`.
diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm
index 54d00c4..4309c74 100644
--- a/Firestore/Source/Remote/FSTRemoteStore.mm
+++ b/Firestore/Source/Remote/FSTRemoteStore.mm
@@ -405,8 +405,10 @@ static const int kMaxPendingWrites = 10;
// Ignore targets that have been removed already.
for (FSTBoxedTargetID *targetID in change.targetIDs) {
if (self.listenTargets[targetID]) {
+ int unboxedTargetId = targetID.intValue;
[self.listenTargets removeObjectForKey:targetID];
- [self.syncEngine rejectListenWithTargetID:[targetID intValue] error:change.cause];
+ [self.watchChangeAggregator removeTarget:unboxedTargetId];
+ [self.syncEngine rejectListenWithTargetID:unboxedTargetId error:change.cause];
}
}
}
diff --git a/Firestore/core/src/firebase/firestore/local/CMakeLists.txt b/Firestore/core/src/firebase/firestore/local/CMakeLists.txt
index 089d03c..4d39c3d 100644
--- a/Firestore/core/src/firebase/firestore/local/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/local/CMakeLists.txt
@@ -17,6 +17,8 @@ cc_library(
SOURCES
leveldb_key.h
leveldb_key.cc
+ leveldb_transaction.h
+ leveldb_transaction.cc
DEPENDS
LevelDB::LevelDB
absl_strings
diff --git a/Firestore/core/src/firebase/firestore/nanopb/reader.cc b/Firestore/core/src/firebase/firestore/nanopb/reader.cc
index 69e3d83..3b102f0 100644
--- a/Firestore/core/src/firebase/firestore/nanopb/reader.cc
+++ b/Firestore/core/src/firebase/firestore/nanopb/reader.cc
@@ -110,14 +110,13 @@ std::string Reader::ReadString() {
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_));
+ status_ = Status(FirestoreErrorCode::DataLoss, PB_GET_ERROR(&substream));
pb_close_string_substream(&stream_, &substream);
return "";
}
diff --git a/Firestore/core/src/firebase/firestore/nanopb/reader.h b/Firestore/core/src/firebase/firestore/nanopb/reader.h
index 2c16ec4..7dd7432 100644
--- a/Firestore/core/src/firebase/firestore/nanopb/reader.h
+++ b/Firestore/core/src/firebase/firestore/nanopb/reader.h
@@ -150,7 +150,6 @@ T Reader::ReadNestedMessage(const std::function<T(Reader*)>& read_message_fn) {
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);
diff --git a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
index f3773b9..1125fb4 100644
--- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
+++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
@@ -656,7 +656,7 @@ TEST_F(SerializerTest, BadFieldValueTagWithOtherValidTagsPresent) {
// Craft the bytes. boolean_value has a smaller tag, so it'll get encoded
// first, normally implying integer_value should "win". Except that
// integer_value isn't a valid tag, so it should be ignored here.
- google_firestore_v1beta1_Value_Fake crafty_value{false, int64_t{42}};
+ google_firestore_v1beta1_Value_Fake crafty_value{true, int64_t{42}};
std::vector<uint8_t> bytes(128);
pb_ostream_t stream = pb_ostream_from_buffer(bytes.data(), bytes.size());
pb_encode(&stream, google_firestore_v1beta1_Value_fields_Fake, &crafty_value);
@@ -664,11 +664,12 @@ TEST_F(SerializerTest, BadFieldValueTagWithOtherValidTagsPresent) {
// Decode the bytes into the model
StatusOr<FieldValue> actual_model_status = serializer.DecodeFieldValue(bytes);
+ Status s = actual_model_status.status();
EXPECT_OK(actual_model_status);
FieldValue actual_model = actual_model_status.ValueOrDie();
// Ensure the decoded model is as expected.
- FieldValue expected_model = FieldValue::BooleanValue(false);
+ FieldValue expected_model = FieldValue::BooleanValue(true);
EXPECT_EQ(FieldValue::Type::Boolean, actual_model.type());
EXPECT_EQ(expected_model, actual_model);
}
diff --git a/Releases/Manifests/5.3.0.json b/Releases/Manifests/5.3.0.json
new file mode 100644
index 0000000..ae18cfa
--- /dev/null
+++ b/Releases/Manifests/5.3.0.json
@@ -0,0 +1,4 @@
+{
+ "FirebaseCore":"5.0.4",
+ "FirebaseFirestore":"0.12.4"
+} \ No newline at end of file
diff --git a/Releases/Manifests/README b/Releases/Manifests/README
new file mode 100644
index 0000000..0c7a631
--- /dev/null
+++ b/Releases/Manifests/README
@@ -0,0 +1,3 @@
+Each file in this directory corresponds with a Firebase release. The file
+includes a list of the podspecs and versions from this repo that updated in the
+Firebase release version indicated by the filename.
diff --git a/Releases/update-versions.py b/Releases/update-versions.py
new file mode 100755
index 0000000..681f044
--- /dev/null
+++ b/Releases/update-versions.py
@@ -0,0 +1,249 @@
+#!/usr/bin/python
+
+# 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.
+
+"""update-versions.py creates a release branch and commit with version updates.
+
+With the required --version parameter, this script will update all files in
+the repo based on the versions in Releases/Manifests/{version}.json.
+
+It will create a release branch, push and tag the updates, and push the
+updated podspecs to cpdc-internal.
+"""
+
+import argparse
+import json
+import os
+import subprocess
+import sys
+import tempfile
+
+test_mode = False # Flag to disable external repo updates
+
+
+def SetupArguments():
+ """SetupArguments sets up the set of command-line arguments.
+
+ Returns:
+ Args: The set of command line arguments
+ """
+ parser = argparse.ArgumentParser(description='Update Pod Versions')
+
+ parser.add_argument('--version', required=True, help='Firebase version')
+
+ parser.add_argument(
+ '--test_mode',
+ dest='test_mode',
+ action='store_true',
+ help='Log commands instead of updating public repo')
+
+ parser.add_argument(
+ '--tag_update',
+ dest='tag_update',
+ action='store_true',
+ help='Update the tags only')
+
+ args = parser.parse_args()
+ return args
+
+
+def LogOrRun(command):
+ """Log or run a command depending on test_mode value.
+
+ Args:
+ command: command to log or run.
+ """
+ if test_mode:
+ print 'Log only: {}'.format(command)
+ else:
+ os.system(command)
+
+
+def GetVersionData(git_root, version):
+ """Update version specifier in FIROptions.m.
+
+ Args:
+ git_root: root of git checkout.
+ version: the next version to release.
+ Returns:
+ Dictionary with pod keys and version values.
+ """
+ json_file = os.path.join(git_root, 'Releases', 'Manifests',
+ '{}.json'.format(version))
+ if os.path.isfile(json_file):
+ return json.load(open(json_file))
+ else:
+ sys.exit('Missing version file:{}'.format(json_file))
+
+
+def CreateReleaseBranch(release_branch):
+ """Create and push the release branch.
+
+ Args:
+ release_branch: the name of the git release branch.
+ """
+ os.system('git checkout master')
+ os.system('git pull')
+ os.system('git checkout -b {}'.format(release_branch))
+ LogOrRun('git push origin {}'.format(release_branch))
+ LogOrRun('git branch --set-upstream-to=origin/{} {}'.format(release_branch,
+ release_branch))
+
+
+def UpdateFIROptions(git_root, version_data):
+ """Update version specifier in FIROptions.m.
+
+ Args:
+ git_root: root of git checkout.
+ version_data: dictionary of versions to be updated.
+ """
+ core_version = version_data['FirebaseCore']
+ major, minor, patch = core_version.split('.')
+ path = os.path.join(git_root, 'Firebase', 'Core', 'FIROptions.m')
+ os.system("sed -E -i.bak 's/[[:digit:]]+\"[[:space:]]*\\/\\/ Major/"
+ "{}\" \\/\\/ Major/' {}".format(major, path))
+ os.system("sed -E -i.bak 's/[[:digit:]]+\"[[:space:]]*\\/\\/ Minor/"
+ "{}\" \\/\\/ Minor/' {}".format(minor.zfill(2), path))
+ os.system("sed -E -i.bak 's/[[:digit:]]+\"[[:space:]]*\\/\\/ Build/"
+ "{}\" \\/\\/ Build/' {}".format(patch.zfill(2), path))
+
+
+def UpdatePodSpecs(git_root, version_data, firebase_version):
+ """Update the podspecs with the right version.
+
+ Args:
+ git_root: root of git checkout.
+ version_data: dictionary of versions to be updated.
+ firebase_version: the Firebase version.
+ """
+ core_podspec = os.path.join(git_root, 'FirebaseCore.podspec')
+ os.system("sed -i.bak -e \"s/\\(Firebase_VERSION=\\).*'/\\1{}'/\" {}".format(
+ firebase_version, core_podspec))
+ for pod, version in version_data.items():
+ podspec = os.path.join(git_root, '{}.podspec'.format(pod))
+ os.system("sed -i.bak -e \"s/\\(\\.version.*=[[:space:]]*'\\).*'/\\1{}'/\" "
+ '{}'.format(version, podspec))
+
+
+def UpdatePodfiles(git_root, version):
+ """Update Podfile's to reference the latest Firebase pod.
+
+ Args:
+ git_root: root of git checkout.
+ version: the next Firebase version to release.
+ """
+ firebase_podfile = os.path.join(git_root, 'Example', 'Podfile')
+ firestore_podfile = os.path.join(git_root, 'Firestore', 'Example', 'Podfile')
+
+ sed_command = ("sed -i.bak -e \"s#\\(pod "
+ "'Firebase/Core',[[:space:]]*'\\).*'#\\1{}'#\" {}")
+ os.system(sed_command.format(version, firebase_podfile))
+ os.system(sed_command.format(version, firestore_podfile))
+
+
+def UpdateTags(version_data, firebase_version, first=False):
+ """Update tags.
+
+ Args:
+ version_data: dictionary of versions to be updated.
+ firebase_version: the Firebase version.
+ first: set to true the first time the versions are set.
+ """
+ if not first:
+ LogOrRun("git push --delete origin '{}'".format(firebase_version))
+ LogOrRun("git tag --delete '{}'".format(firebase_version))
+ LogOrRun("git tag '{}'".format(firebase_version))
+ for pod, version in version_data.items():
+ name = pod[len('Firebase'):]
+ tag = '{}-{}'.format(name, version)
+ if not first:
+ LogOrRun("git push --delete origin '{}'".format(tag))
+ LogOrRun("git tag --delete '{}'".format(tag))
+ LogOrRun("git tag '{}'".format(tag))
+ LogOrRun('git push origin --tags')
+
+
+def GetCpdcInternal():
+ """Find the cpdc-internal repo.
+
+"""
+ tmp_file = tempfile.mktemp()
+ os.system('pod repo list | grep -B2 sso://cpdc-internal | head -1 > {}'
+ .format(tmp_file))
+ with open(tmp_file,'r') as o:
+ output_var = ''.join(o.readlines()).strip()
+ os.system('rm -rf {}'.format(tmp_file))
+ return output_var
+
+
+def PushPodspecs(version_data):
+ """Push podspecs to cpdc-internal.
+
+ Args:
+ version_data: dictionary of versions to be updated.
+ """
+ pods = version_data.keys()
+ pods.insert(0, pods.pop(pods.index('FirebaseCore'))) # Core should be first
+ tmp_dir = tempfile.mkdtemp()
+ for pod in pods:
+ LogOrRun('pod cache clean {} --all'.format(pod))
+ if pod == 'FirebaseFirestore':
+ warnings_ok = ' --allow-warnings'
+ else:
+ warnings_ok = ''
+
+ podspec = '{}.podspec'.format(pod)
+ json = os.path.join(tmp_dir, '{}.json'.format(podspec))
+ os.system('pod ipc spec {} > {}'.format(podspec, json))
+ LogOrRun('pod repo push {} {}{}'.format(GetCpdcInternal(), json,
+ warnings_ok))
+ os.system('rm -rf {}'.format(tmp_dir))
+
+
+def UpdateVersions():
+ """UpdateVersions is the main body to create the branch and change versions.
+ """
+ global test_mode
+ args = SetupArguments()
+ test_mode = args.test_mode
+ # Validate version is proper format
+ major, minor, patch = args.version.split('.')
+ if (not major.isdigit()) or (not minor.isdigit()) or (not patch.isdigit()):
+ sys.exit('Invalid version parameter')
+
+ git_root = subprocess.Popen(
+ ['git', 'rev-parse', '--show-toplevel'],
+ stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')
+
+ version_data = GetVersionData(git_root, args.version)
+ if args.tag_update:
+ UpdateTags(version_data, args.version)
+ return
+
+ release_branch = 'release-{}'.format(args.version)
+ CreateReleaseBranch(release_branch)
+ UpdateFIROptions(git_root, version_data)
+ UpdatePodSpecs(git_root, version_data, args.version)
+ UpdatePodfiles(git_root, args.version)
+
+ LogOrRun('git commit -am "Update versions for Release {}"'
+ .format(args.version))
+ LogOrRun('git push origin {}'.format(release_branch))
+ UpdateTags(version_data, args.version, True)
+ PushPodspecs(version_data)
+
+
+if __name__ == '__main__':
+ UpdateVersions()
diff --git a/scripts/check_test_inclusion.py b/scripts/check_test_inclusion.py
index 7f5f354..7f6e43c 100755
--- a/scripts/check_test_inclusion.py
+++ b/scripts/check_test_inclusion.py
@@ -26,8 +26,6 @@ import sys
# Tests that are known not to compile in Xcode and can't be added there.
EXCLUDED = frozenset([
- # b/79496027
- "Firestore/core/test/firebase/firestore/remote/serializer_test.cc",
])
diff --git a/scripts/push-pods.sh b/scripts/push-pods.sh
deleted file mode 100755
index 9f4c303..0000000
--- a/scripts/push-pods.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-# Push GitHub pods to cpdc-internal-spec.
-
-# When bootstrapping a repo, FirebaseCore must be pushed first, then
-# FirebaseInstanceID, then FirebaseAnalytics, then the rest
-# Most of the warnings are tvOS specific. The Firestore one needs
-# investigation.
-
-pod cache clean FirebaseCore --all
-#pod cache clean FirebaseAuth --all
-#pod cache clean FirebaseDatabase --all
-pod cache clean FirebaseFirestore --all
-#pod cache clean FirebaseFunctions --all
-#pod cache clean FirebaseMessaging --all
-#pod cache clean FirebaseStorage --all
-
-pod repo push cpdc-internal-spec FirebaseCore.podspec
-#pod repo push cpdc-internal-spec FirebaseAuth.podspec
-#pod repo push cpdc-internal-spec FirebaseDatabase.podspec
-pod repo push cpdc-internal-spec FirebaseFirestore.podspec --allow-warnings
-#pod repo push cpdc-internal-spec FirebaseFunctions.podspec
-#pod repo push cpdc-internal-spec FirebaseMessaging.podspec
-#pod repo push cpdc-internal-spec FirebaseStorage.podspec
-
-# FirebaseFirestore warning (no plan to fix)
-# https://github.com/firebase/firebase-ios-sdk/issues/1143
diff --git a/scripts/sync_project.rb b/scripts/sync_project.rb
index e34ae31..ba9f98b 100755
--- a/scripts/sync_project.rb
+++ b/scripts/sync_project.rb
@@ -50,15 +50,13 @@ def sync_firestore()
'CMakeLists.txt',
'InfoPlist.strings',
'*.plist',
-
- # b/79496027
- 'Firestore/core/test/firebase/firestore/remote/serializer_test.cc',
]
# Folder groups in the Xcode project that contain tests.
s.test_groups = [
'Tests',
'CoreTests',
+ 'CoreTestsProtos',
'SwiftTests',
]
@@ -66,6 +64,7 @@ def sync_firestore()
t.source_files = [
'Firestore/Example/Tests/**',
'Firestore/core/test/**',
+ 'Firestore/Protos/cpp/**',
'Firestore/third_party/Immutable/Tests/**',
]
t.exclude_files = [
diff --git a/scripts/update-tags.sh b/scripts/update-tags.sh
deleted file mode 100755
index 0e5bd8c..0000000
--- a/scripts/update-tags.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-# Update the tags for the Firebase 5.0.0 release process
-
-# Before running, make sure everything is pushed.
-
-# This script should be a spec for a more robust Python or Swift script that
-# does the following.
-# 1. Verify all files are committed
-# 2. Verify running on a release branch
-# 3. Read the versions from the podspec (or incorporate into even more
-# automated version management)
-
-# Delete any existing tags at origin
-
-git push --delete origin '5.3.0'
-git push --delete origin 'Core-5.0.4'
-#git push --delete origin 'Auth-5.0.1'
-#git push --delete origin 'Database-5.0.1'
-git push --delete origin 'Firestore-0.12.4'
-#git push --delete origin 'Functions-2.0.0'
-#git push --delete origin 'Messaging-3.0.2'
-#git push --delete origin 'Storage-3.0.0'
-
-# Delete local tags
-
-git tag --delete '5.3.0'
-git tag --delete 'Core-5.0.4'
-#git tag --delete 'Auth-5.0.1'
-#git tag --delete 'Database-5.0.1'
-git tag --delete 'Firestore-0.12.4'
-#git tag --delete 'Functions-2.0.0'
-#git tag --delete 'Messaging-3.0.2'
-#git tag --delete 'Storage-3.0.0'
-
-# Add and push the tags
-
-git tag '5.3.0'
-git tag 'Core-5.0.4'
-#git tag 'Auth-5.0.1'
-# git tag 'Database-5.0.1'
-git tag 'Firestore-0.12.4'
-#git tag 'Functions-2.0.0'
-#git tag 'Messaging-3.0.2'
-#git tag 'Storage-3.0.0'
-
-git push origin --tags