Skip to content
1 change: 1 addition & 0 deletions Example/tvOSSample/tvOSSample/AuthViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import UIKit
import FirebaseAuth

class AuthViewController: UIViewController {

// MARK: - User Interface

/// A stackview containing all of the buttons to providers (Email, OAuth, etc).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ protocol EmailLoginDelegate {
}

class EmailLoginViewController: UIViewController {

// MARK: - Public Properties

var delegate: EmailLoginDelegate?
Expand Down
4 changes: 4 additions & 0 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
C80B10E79CDD7EF7843C321E /* type_traits_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A0CF41BA5AED6049B0BEB2C /* type_traits_apple_test.mm */; };
C8D3CE2343E53223E6487F2C /* Pods_Firestore_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5918805E993304321A05E82B /* Pods_Firestore_Example_iOS.framework */; };
CA989C0E6020C372A62B7062 /* testutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54A0352820A3B3BD003E0143 /* testutil.cc */; };
D5B252EE3F4037405DB1ECE3 /* FIRNumericTransformTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = D5B25E7E7D6873CBA4571841 /* FIRNumericTransformTests.mm */; };
D5B25CBF07F65E885C9D68AB /* perf_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */; };
D94A1862B8FB778225DB54A1 /* filesystem_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F51859B394D01C0C507282F1 /* filesystem_test.cc */; };
DD5976A45071455FF3FE74B8 /* string_win_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 79507DF8378D3C42F5B36268 /* string_win_test.cc */; };
Expand Down Expand Up @@ -546,6 +547,7 @@
C8522DE226C467C54E6788D8 /* mutation_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = mutation_test.cc; sourceTree = "<group>"; };
D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = perf_spec_test.json; sourceTree = "<group>"; };
D5B25E7E7D6873CBA4571841 /* FIRNumericTransformTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRNumericTransformTests.mm; sourceTree = "<group>"; };
DE03B2E91F2149D600A30B9C /* Firestore_IntegrationTests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_IntegrationTests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DE03B3621F215E1600A30B9C /* CAcert.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = CAcert.pem; sourceTree = "<group>"; };
DE0761F61F2FE68D003233AF /* BasicCompileTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicCompileTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1262,6 +1264,7 @@
5492E071202154D600B64F25 /* FIRTypeTests.mm */,
5492E06D202154D600B64F25 /* FIRValidationTests.mm */,
5492E06F202154D600B64F25 /* FIRWriteBatchTests.mm */,
D5B25E7E7D6873CBA4571841 /* FIRNumericTransformTests.mm */,
);
path = API;
sourceTree = "<group>";
Expand Down Expand Up @@ -2046,6 +2049,7 @@
B67BF44A216EB43000CA9097 /* create_noop_connectivity_monitor.cc in Sources */,
EBFC611B1BF195D0EC710AF4 /* app_testing.mm in Sources */,
CA989C0E6020C372A62B7062 /* testutil.cc in Sources */,
D5B252EE3F4037405DB1ECE3 /* FIRNumericTransformTests.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
161 changes: 161 additions & 0 deletions Firestore/Example/Tests/Integration/API/FIRNumericTransformTests.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <FirebaseFirestore/FirebaseFirestore.h>

#import <XCTest/XCTest.h>

#import "Firestore/Source/API/FIRFieldValue+Internal.h"

#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"

@interface FIRNumericTransformTests : FSTIntegrationTestCase
@end

@implementation FIRNumericTransformTests {
// A document reference to read and write to.
FIRDocumentReference *_docRef;

// Accumulator used to capture events during the test.
FSTEventAccumulator<FIRDocumentSnapshot *> *_accumulator;

// Listener registration for a listener maintained during the course of the test.
id<FIRListenerRegistration> _listenerRegistration;
}

- (void)setUp {
[super setUp];

_docRef = [self documentRef];
_accumulator = [FSTEventAccumulator accumulatorForTest:self];
_listenerRegistration =
[_docRef addSnapshotListenerWithIncludeMetadataChanges:YES
listener:_accumulator.valueEventHandler];

// Wait for initial nil snapshot to avoid potential races.
FIRDocumentSnapshot *initialSnapshot = [_accumulator awaitEventWithName:@"initial event"];
XCTAssertFalse(initialSnapshot.exists);
}

- (void)tearDown {
[_listenerRegistration remove];

[super tearDown];
}

#pragma mark - Test Helpers

/** Writes some initial data and consumes the events generated. */
- (void)writeInitialData:(NSDictionary<NSString *, id> *)data {
[self writeDocumentRef:_docRef data:data];
XCTAssertEqualObjects([_accumulator awaitLocalEvent].data, data);
XCTAssertEqualObjects([_accumulator awaitRemoteEvent].data, data);
}

- (void)expectLocalAndRemoteValue:(int64_t)expectedSum {
FIRDocumentSnapshot *snap = [_accumulator awaitLocalEvent];
XCTAssertEqual(@(expectedSum), snap[@"sum"]);
snap = [_accumulator awaitRemoteEvent];
XCTAssertEqual(@(expectedSum), snap[@"sum"]);
}

- (void)expectApproximateLocalAndRemoteValue:(double)expectedSum {
FIRDocumentSnapshot *snap = [_accumulator awaitLocalEvent];
XCTAssertEqual(@(expectedSum), snap[@"sum"]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be XCTAssertEqualWithAccuracy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Fixed.

I should have probably asked you not to review these tests until I was able to run them.

snap = [_accumulator awaitRemoteEvent];
XCTAssertEqual(@(expectedSum), snap[@"sum"]);
}

#pragma mark - Test Cases

- (void)testCreateDocumentWithIncrement {
[self writeDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForIntegerIncrement:1337]}];
[self expectLocalAndRemoteValue:1337];
}

- (void)testMergeOnNonExistingDocumentWithIncrement {
[self mergeDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForIntegerIncrement:1337]}];
[self expectLocalAndRemoteValue:1337];
}

- (void)testIntegerIncrementWithExistingInteger {
[self writeInitialData:@{@"sum" : @1337}];
[self updateDocumentRef:_docRef data:@{@"sum" : [FIRFieldValue fieldValueForIntegerIncrement:1]}];
[self expectLocalAndRemoteValue:13378];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/13378/1338

}

- (void)testDoubleIncrementWithExistingDouble {
[self writeInitialData:@{@"sum" : @13.37}];
[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForDoubleIncrement:0.1]}];
[self expectApproximateLocalAndRemoteValue:13.47];
}

- (void)testIntegerIncrementWithExistingDouble {
[self writeInitialData:@{@"sum" : @13.37}];
[self updateDocumentRef:_docRef data:@{@"sum" : [FIRFieldValue fieldValueForIntegerIncrement:1]}];
[self expectApproximateLocalAndRemoteValue:14.37];
}

- (void)testDoubleIncrementWithExistingInteger {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe replace "double" in test name with "float", "floating point", or "real"? "DoubleIncrement" reads like "IncrementTwice", not "IncrementByADouble".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to push back on this suggestions purely out of laziness. I want these tests names to match across all platforms, and changing one name here requires me to port this change to Android and Web. Thanks for flagging this though.

[self writeInitialData:@{@"sum" : @1337}];
[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForDoubleIncrement:0.1]}];
[self expectApproximateLocalAndRemoteValue:1337.1];
}

- (void)testIntegerIncrementWithExistingString {
[self writeInitialData:@{@"sum" : @"overwrite"}];
[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForIntegerIncrement:1337]}];
[self expectLocalAndRemoteValue:1337];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this PR: why was it decided to overwrite instead of reject in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend semantics for NUMERIC_ADD follow those of ARRA_UNION and coerce to the expected type first. This ensures consistency between all document transforms.

}

- (void)testDoubleIncrementWithExistingString {
[self writeInitialData:@{@"sum" : @"overwrite"}];
[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForDoubleIncrement:13.37]}];
[self expectApproximateLocalAndRemoteValue:13.37];
}

- (void)testMultipleDoubleIncrements {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: test for overflow/interesting floating point values (NaN/infinity/etc.)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests here test the integration with the backend, and as such am I inclined to not add too much edge case testing. I am testing the internal logic that deals with NaN and Infinity in the unit tests.

[self writeInitialData:@{@"sum" : @"0.0"}];

[self disableNetwork];

[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForDoubleIncrement:0.1]}];
[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForDoubleIncrement:0.01]}];
[self updateDocumentRef:_docRef
data:@{@"sum" : [FIRFieldValue fieldValueForDoubleIncrement:0.01]}];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this should be 0.001 (one thousandth, not one hundredth).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct. Fixed.


FIRDocumentSnapshot *snap = [_accumulator awaitLocalEvent];
XCTAssertEqual(@(0.1), snap[@"sum"]);
snap = [_accumulator awaitLocalEvent];
XCTAssertEqual(@(0.11), snap[@"sum"]);
snap = [_accumulator awaitLocalEvent];
XCTAssertEqual(@(0.111), snap[@"sum"]);

[self enableNetwork];
snap = [_accumulator awaitRemoteEvent];
XCTAssertEqual(@(0.111), snap[@"sum"]);
}

@end
1 change: 1 addition & 0 deletions Firestore/Example/Tests/Integration/FSTDatastoreTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ - (void)testStreamingWrite {
FSTSetMutation *mutation = [self setMutation];
FSTMutationBatch *batch = [[FSTMutationBatch alloc] initWithBatchID:23
localWriteTime:[FIRTimestamp timestamp]
baseMutations:@[]
mutations:@[ mutation ]];
[_testWorkerQueue dispatchAsync:^{
[_remoteStore addBatchToWritePipeline:batch];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ - (void)testRemoveOrphanedDocuments {
// serve to keep the mutated documents from being GC'd while the mutations are outstanding.
_persistence.run("actually register the mutations", [&]() {
FIRTimestamp *writeTime = [FIRTimestamp timestamp];
[_mutationQueue addMutationBatchWithWriteTime:writeTime mutations:mutations];
[_mutationQueue addMutationBatchWithWriteTime:writeTime baseMutations:@[] mutations:mutations];
});

// Mark 5 documents eligible for GC. This simulates documents that were mutated then ack'd.
Expand Down
15 changes: 15 additions & 0 deletions Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ - (void)setUp {
}

- (void)testEncodesMutationBatch {
FSTMutation *base = [[FSTPatchMutation alloc] initWithKey:FSTTestDocKey(@"bar/baz")
fieldMask:FieldMask{testutil::Field("a")}
value:FSTTestObjectValue(@{@"a" : @"b"})
precondition:Precondition::Exists(true)];
FSTMutation *set = FSTTestSetMutation(@"foo/bar", @{@"a" : @"b", @"num" : @1});
FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:FSTTestDocKey(@"bar/baz")
fieldMask:FieldMask{testutil::Field("a")}
Expand All @@ -91,8 +95,17 @@ - (void)testEncodesMutationBatch {
FIRTimestamp *writeTime = [FIRTimestamp timestamp];
FSTMutationBatch *model = [[FSTMutationBatch alloc] initWithBatchID:42
localWriteTime:writeTime
baseMutations:@[ base ]
mutations:@[ set, patch, del ]];

GCFSWrite *baseProto = [GCFSWrite message];
baseProto.update.name = @"projects/p/databases/d/documents/bar/baz";
[baseProto.update.fields addEntriesFromDictionary:@{
@"a" : [self.remoteSerializer encodedString:@"b"],
}];
[baseProto.updateMask.fieldPathsArray addObjectsFromArray:@[ @"a" ]];
baseProto.currentDocument.exists = YES;

GCFSWrite *setProto = [GCFSWrite message];
setProto.update.name = @"projects/p/databases/d/documents/foo/bar";
[setProto.update.fields addEntriesFromDictionary:@{
Expand All @@ -118,13 +131,15 @@ - (void)testEncodesMutationBatch {

FSTPBWriteBatch *batchProto = [FSTPBWriteBatch message];
batchProto.batchId = 42;
[batchProto.baseWritesArray addObject:baseProto];
[batchProto.writesArray addObjectsFromArray:@[ setProto, patchProto, delProto ]];
batchProto.localWriteTime = writeTimeProto;

XCTAssertEqualObjects([self.serializer encodedMutationBatch:model], batchProto);
FSTMutationBatch *decoded = [self.serializer decodedMutationBatch:batchProto];
XCTAssertEqual(decoded.batchID, model.batchID);
XCTAssertEqualObjects(decoded.localWriteTime, model.localWriteTime);
XCTAssertEqualObjects(decoded.baseMutations, model.baseMutations);
XCTAssertEqualObjects(decoded.mutations, model.mutations);
XCTAssertEqual([decoded keys], [model keys]);
}
Expand Down
Loading