mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-11 22:55:59 +05:45
* Suppress warning from boringssl * Try out target exclusion * Skip a failed tsan test * Add todo
1451 lines
54 KiB
Plaintext
1451 lines
54 KiB
Plaintext
/*
|
|
* Copyright 2023 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#import <FirebaseFirestore/FIRFieldPath.h>
|
|
#import <FirebaseFirestore/FirebaseFirestore.h>
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
// TODO(sum/avg) update these imports with public imports when sum/avg is public
|
|
#import "Firestore/Source/API/FIRAggregateField.h"
|
|
#import "Firestore/Source/API/FIRAggregateQuerySnapshot+Internal.h"
|
|
#import "Firestore/Source/API/FIRQuery+Internal.h"
|
|
|
|
#include "Firestore/core/src/util/sanitizers.h"
|
|
|
|
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
|
|
|
|
@interface FIRAggregateTests : FSTIntegrationTestCase
|
|
@end
|
|
|
|
@implementation FIRAggregateTests
|
|
|
|
- (void)testCountAggregateFieldQueryEquals {
|
|
FIRCollectionReference* coll1 = [self collectionRefWithDocuments:@{}];
|
|
FIRCollectionReference* coll1Same = [[coll1 firestore] collectionWithPath:[coll1 path]];
|
|
|
|
FIRAggregateQuery* query1 = [coll1 aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
FIRAggregateQuery* query1Same =
|
|
[coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
FIRAggregateQuery* query1DiffAgg =
|
|
[coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
|
|
FIRCollectionReference* sub = [[coll1 documentWithPath:@"bar"] collectionWithPath:@"baz"];
|
|
|
|
FIRAggregateQuery* query2 = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
FIRAggregateQuery* query2Same = [[[sub queryWhereField:@"a"
|
|
isEqualTo:@1] queryLimitedTo:100] count];
|
|
|
|
FIRAggregateQuery* query3 = [[[sub queryWhereField:@"b" isEqualTo:@1] queryOrderedByField:@"c"]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
FIRAggregateQuery* query3Same = [[[sub queryWhereField:@"b"
|
|
isEqualTo:@1] queryOrderedByField:@"c"] count];
|
|
|
|
XCTAssertEqualObjects(query1, query1Same);
|
|
XCTAssertEqualObjects(query2, query2Same);
|
|
XCTAssertEqualObjects(query3, query3Same);
|
|
|
|
XCTAssertEqual([query1 hash], [query1Same hash]);
|
|
XCTAssertEqual([query2 hash], [query2Same hash]);
|
|
XCTAssertEqual([query3 hash], [query3Same hash]);
|
|
|
|
XCTAssertFalse([query1 isEqual:nil]);
|
|
XCTAssertFalse([query1 isEqual:@"string"]);
|
|
XCTAssertFalse([query1 isEqual:query2]);
|
|
XCTAssertFalse([query2 isEqual:query3]);
|
|
|
|
XCTAssertNotEqual([query1 hash], [query1DiffAgg hash]);
|
|
XCTAssertNotEqual([query1 hash], [query2 hash]);
|
|
XCTAssertNotEqual([query2 hash], [query3 hash]);
|
|
}
|
|
|
|
- (void)testSumAggregateFieldQueryEquals {
|
|
FIRCollectionReference* coll1 = [self collectionRefWithDocuments:@{}];
|
|
FIRCollectionReference* coll1Same = [[coll1 firestore] collectionWithPath:[coll1 path]];
|
|
|
|
FIRAggregateQuery* query1 =
|
|
[coll1 aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query1Same =
|
|
[coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query1WithFieldPath =
|
|
[coll1Same aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfFieldPath:[[FIRFieldPath alloc]
|
|
initWithFields:@[ @"baz" ]]] ]];
|
|
FIRAggregateQuery* query1DiffAgg =
|
|
[coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
|
|
FIRCollectionReference* sub = [[coll1 documentWithPath:@"bar"] collectionWithPath:@"baz"];
|
|
FIRAggregateQuery* query2 = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query2Same = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query3 = [[[sub queryWhereField:@"b" isEqualTo:@1] queryOrderedByField:@"c"]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query3Same = [[[sub queryWhereField:@"b"
|
|
isEqualTo:@1] queryOrderedByField:@"c"]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
|
|
XCTAssertEqualObjects(query1, query1Same);
|
|
XCTAssertEqualObjects(query1, query1WithFieldPath);
|
|
XCTAssertEqualObjects(query2, query2Same);
|
|
XCTAssertEqualObjects(query3, query3Same);
|
|
|
|
XCTAssertEqual([query1 hash], [query1Same hash]);
|
|
XCTAssertEqual([query1 hash], [query1WithFieldPath hash]);
|
|
XCTAssertEqual([query2 hash], [query2Same hash]);
|
|
XCTAssertEqual([query3 hash], [query3Same hash]);
|
|
|
|
XCTAssertFalse([query1 isEqual:nil]);
|
|
XCTAssertFalse([query1 isEqual:@"string"]);
|
|
XCTAssertFalse([query1 isEqual:query2]);
|
|
XCTAssertFalse([query2 isEqual:query3]);
|
|
|
|
XCTAssertNotEqual([query1 hash], [query1DiffAgg hash]);
|
|
XCTAssertNotEqual([query1 hash], [query2 hash]);
|
|
XCTAssertNotEqual([query2 hash], [query3 hash]);
|
|
}
|
|
|
|
- (void)testAverageAggregateFieldQueryEquals {
|
|
FIRCollectionReference* coll1 = [self collectionRefWithDocuments:@{}];
|
|
FIRCollectionReference* coll1Same = [[coll1 firestore] collectionWithPath:[coll1 path]];
|
|
|
|
FIRAggregateQuery* query1 =
|
|
[coll1 aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query1Same =
|
|
[coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query1WithFieldPath = [coll1Same aggregate:@[
|
|
[FIRAggregateField
|
|
aggregateFieldForAverageOfFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"baz" ]]]
|
|
]];
|
|
FIRAggregateQuery* query1DiffAgg =
|
|
[coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
|
|
FIRCollectionReference* sub = [[coll1 documentWithPath:@"bar"] collectionWithPath:@"baz"];
|
|
|
|
FIRAggregateQuery* query2 = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query2Same = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
|
|
FIRAggregateQuery* query3 = [[[sub queryWhereField:@"b" isEqualTo:@1] queryOrderedByField:@"c"]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query3Same = [[[sub queryWhereField:@"b"
|
|
isEqualTo:@1] queryOrderedByField:@"c"]
|
|
aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
|
|
XCTAssertEqualObjects(query1, query1Same);
|
|
XCTAssertEqualObjects(query1, query1WithFieldPath);
|
|
XCTAssertEqualObjects(query2, query2Same);
|
|
XCTAssertEqualObjects(query3, query3Same);
|
|
|
|
XCTAssertEqual([query1 hash], [query1Same hash]);
|
|
XCTAssertEqual([query1 hash], [query1WithFieldPath hash]);
|
|
XCTAssertEqual([query2 hash], [query2Same hash]);
|
|
XCTAssertEqual([query3 hash], [query3Same hash]);
|
|
|
|
XCTAssertFalse([query1 isEqual:nil]);
|
|
XCTAssertFalse([query1 isEqual:@"string"]);
|
|
XCTAssertFalse([query1 isEqual:query2]);
|
|
XCTAssertFalse([query2 isEqual:query3]);
|
|
|
|
XCTAssertNotEqual([query1 hash], [query1DiffAgg hash]);
|
|
XCTAssertNotEqual([query1 hash], [query2 hash]);
|
|
XCTAssertNotEqual([query2 hash], [query3 hash]);
|
|
}
|
|
|
|
- (void)testAggregateFieldQueryNotEquals {
|
|
FIRCollectionReference* coll = [self collectionRefWithDocuments:@{}];
|
|
|
|
FIRAggregateQuery* query1 = [coll aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
FIRAggregateQuery* query2 =
|
|
[coll aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query3 =
|
|
[coll aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
|
|
XCTAssertNotEqualObjects(query1, query2);
|
|
XCTAssertNotEqualObjects(query2, query3);
|
|
XCTAssertNotEqualObjects(query3, query1);
|
|
|
|
XCTAssertNotEqual([query1 hash], [query2 hash]);
|
|
XCTAssertNotEqual([query2 hash], [query3 hash]);
|
|
XCTAssertNotEqual([query3 hash], [query1 hash]);
|
|
|
|
FIRQuery* baseQuery = [[[[coll documentWithPath:@"bar"] collectionWithPath:@"baz"]
|
|
queryWhereField:@"a"
|
|
isEqualTo:@1] queryLimitedTo:100];
|
|
|
|
FIRAggregateQuery* query4 = [baseQuery aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
|
|
FIRAggregateQuery* query5 =
|
|
[baseQuery aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
|
|
FIRAggregateQuery* query6 =
|
|
[baseQuery aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
|
|
|
|
XCTAssertNotEqualObjects(query4, query5);
|
|
XCTAssertNotEqualObjects(query5, query6);
|
|
XCTAssertNotEqualObjects(query6, query4);
|
|
|
|
XCTAssertNotEqual([query4 hash], [query5 hash]);
|
|
XCTAssertNotEqual([query5 hash], [query6 hash]);
|
|
XCTAssertNotEqual([query6 hash], [query4 hash]);
|
|
}
|
|
|
|
- (void)testCanRunAggregateQuery {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"weight"]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual([snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]],
|
|
[NSNumber numberWithLong:2L]);
|
|
XCTAssertEqual([snapshot count], [NSNumber numberWithLong:2L]);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
|
|
[NSNumber numberWithLong:150L], );
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"weight"]]
|
|
doubleValue],
|
|
99.6);
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]],
|
|
[NSNumber numberWithDouble:75.0]);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"weight"]]
|
|
doubleValue],
|
|
49.8);
|
|
}
|
|
|
|
- (void)testCanRunEmptyAggregateQuery {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuery* emptyQuery = [testCollection aggregate:@[]];
|
|
|
|
__block NSError* result;
|
|
XCTestExpectation* expectation = [self expectationWithDescription:@"aggregate result"];
|
|
|
|
[emptyQuery aggregationWithSource:FIRAggregateSourceServer
|
|
completion:^(FIRAggregateQuerySnapshot* snapshot, NSError* error) {
|
|
XCTAssertNil(snapshot);
|
|
result = error;
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
[self awaitExpectation:expectation];
|
|
|
|
XCTAssertNotNil(result);
|
|
XCTAssertTrue([[result localizedDescription] containsString:@"Aggregations can not be empty"]);
|
|
}
|
|
|
|
// (TODO:b/283101111): Try thread sanitizer to see if timeout on Github Actions is gone.
|
|
#if !defined(THREAD_SANITIZER)
|
|
- (void)testAggregateFieldQuerySnapshotEquality {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot1 =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"weight"]
|
|
]]];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot2 =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"weight"]
|
|
]]];
|
|
|
|
// different aggregates
|
|
FIRAggregateQuerySnapshot* snapshot3 =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]
|
|
]]];
|
|
|
|
// different data set
|
|
FIRAggregateQuerySnapshot* snapshot4 = [self
|
|
readSnapshotForAggregate:[[testCollection queryWhereField:@"pages" isGreaterThan:@50]
|
|
aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField
|
|
aggregateFieldForAverageOfField:@"weight"]
|
|
]]];
|
|
|
|
XCTAssertEqualObjects(snapshot1, snapshot2);
|
|
XCTAssertNotEqualObjects(snapshot1, snapshot3);
|
|
XCTAssertNotEqualObjects(snapshot1, snapshot4);
|
|
XCTAssertNotEqualObjects(snapshot3, snapshot4);
|
|
|
|
XCTAssertEqual([snapshot1 hash], [snapshot2 hash]);
|
|
XCTAssertNotEqual([snapshot1 hash], [snapshot3 hash]);
|
|
XCTAssertNotEqual([snapshot1 hash], [snapshot4 hash]);
|
|
XCTAssertNotEqual([snapshot3 hash], [snapshot4 hash]);
|
|
}
|
|
#endif // #if !defined(THREAD_SANITIZER)
|
|
|
|
- (void)testAllowsAliasesLongerThan1500Bytes {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
// The longest field name allowed is 1500. The alias chosen by the client is <op>_<fieldName>.
|
|
// If the field name is
|
|
// 1500 bytes, the alias will be longer than 1500, which is the limit for aliases. This is to
|
|
// make sure the client
|
|
// can handle this corner case correctly.
|
|
NSString* longField = [@"" stringByPaddingToLength:1499
|
|
withString:@"0123456789"
|
|
startingAtIndex:0];
|
|
|
|
FIRCollectionReference* testCollection =
|
|
[self collectionRefWithDocuments:@{@"a" : @{longField : @1}, @"b" : @{longField : @2}}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:longField] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:longField]],
|
|
[NSNumber numberWithLong:3], );
|
|
}
|
|
|
|
- (void)testCanGetDuplicateAggregations {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual([snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]],
|
|
[NSNumber numberWithLong:2L]);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
|
|
[NSNumber numberWithLong:150L], );
|
|
}
|
|
|
|
- (void)testTerminateDoesNotCrashWithFlyingAggregateQuery {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuery* aggQuery = [testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]
|
|
]];
|
|
|
|
__block FIRAggregateQuerySnapshot* result;
|
|
XCTestExpectation* expectation = [self expectationWithDescription:@"aggregate result"];
|
|
[aggQuery aggregationWithSource:FIRAggregateSourceServer
|
|
completion:^(FIRAggregateQuerySnapshot* snapshot, NSError* error) {
|
|
XCTAssertNil(error);
|
|
result = snapshot;
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
[self awaitExpectation:expectation];
|
|
|
|
// Count
|
|
XCTAssertEqual([result valueForAggregation:[FIRAggregateField aggregateFieldForCount]],
|
|
[NSNumber numberWithLong:2L]);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[result valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
|
|
[NSNumber numberWithLong:150L], );
|
|
}
|
|
|
|
- (void)testCanPerformMaxAggregations {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
// Max is 5, do not exceed
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"weight"]
|
|
]]];
|
|
|
|
// Assert
|
|
XCTAssertEqual([snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]],
|
|
[NSNumber numberWithLong:2L]);
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
|
|
[NSNumber numberWithLong:150L], );
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"weight"]]
|
|
doubleValue],
|
|
99.6);
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]],
|
|
[NSNumber numberWithDouble:75.0]);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"weight"]]
|
|
doubleValue],
|
|
49.8);
|
|
}
|
|
|
|
- (void)testCannotPerformMoreThanMaxAggregations {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
// Max is 5, we're attempting 6. I also like to live dangerously.
|
|
FIRAggregateQuery* query = [testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"weight"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"foo"]
|
|
]];
|
|
|
|
__block NSError* result;
|
|
XCTestExpectation* expectation = [self expectationWithDescription:@"aggregate result"];
|
|
|
|
[query aggregationWithSource:FIRAggregateSourceServer
|
|
completion:^(FIRAggregateQuerySnapshot* snapshot, NSError* error) {
|
|
XCTAssertNil(snapshot);
|
|
result = error;
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
[self awaitExpectation:expectation];
|
|
|
|
XCTAssertNotNil(result);
|
|
XCTAssertTrue([[result localizedDescription] containsString:@"maximum number of aggregations"]);
|
|
}
|
|
|
|
- (void)testCanRunAggregateCollectionGroupQuery {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
NSString* collectionGroup =
|
|
[NSString stringWithFormat:@"%@%@", @"b",
|
|
[self.db collectionWithPath:@"foo"].documentWithAutoID.documentID];
|
|
NSArray* docPathFormats = @[
|
|
@"abc/123/%@/cg-doc1", @"abc/123/%@/cg-doc2", @"%@/cg-doc3", @"%@/cg-doc4",
|
|
@"def/456/%@/cg-doc5", @"%@/virtual-doc/nested-coll/not-cg-doc", @"x%@/not-cg-doc",
|
|
@"%@x/not-cg-doc", @"abc/123/%@x/not-cg-doc", @"abc/123/x%@/not-cg-doc", @"abc/%@"
|
|
];
|
|
|
|
FIRWriteBatch* batch = self.db.batch;
|
|
for (NSString* format in docPathFormats) {
|
|
NSString* path = [NSString stringWithFormat:format, collectionGroup];
|
|
[batch setData:@{@"x" : @2} forDocument:[self.db documentWithPath:path]];
|
|
}
|
|
|
|
XCTestExpectation* expectation = [self expectationWithDescription:@"commit"];
|
|
[batch commitWithCompletion:^(NSError* error) {
|
|
XCTAssertNil(error);
|
|
[expectation fulfill];
|
|
}];
|
|
[self awaitExpectation:expectation];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[[self.db collectionGroupWithID:collectionGroup] aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"x"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"x"]
|
|
]]];
|
|
// "cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5",
|
|
XCTAssertEqual([snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]],
|
|
[NSNumber numberWithLong:5L]);
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"x"]],
|
|
[NSNumber numberWithLong:10L]);
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"x"]],
|
|
[NSNumber numberWithDouble:2.0]);
|
|
}
|
|
|
|
- (void)testPerformsAggregationsWhenNaNExistsForSomeFieldValues {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"year" : @1980,
|
|
@"rating" : @5
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"year" : @2020,
|
|
@"rating" : @4
|
|
},
|
|
@"c" : @{
|
|
@"author" : @"authorC",
|
|
@"title" : @"titleC",
|
|
@"pages" : @100,
|
|
@"year" : @1980,
|
|
@"rating" : [NSNumber numberWithFloat:NAN]
|
|
},
|
|
@"d" : @{
|
|
@"author" : @"authorD",
|
|
@"title" : @"titleD",
|
|
@"pages" : @50,
|
|
@"year" : @2020,
|
|
@"rating" : @0
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"rating"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"year"]
|
|
]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]],
|
|
[NSNumber numberWithDouble:NAN]);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]]
|
|
longValue],
|
|
300L);
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]],
|
|
[NSNumber numberWithDouble:NAN]);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"year"]]
|
|
doubleValue],
|
|
2000.0);
|
|
}
|
|
|
|
- (void)testThrowsAnErrorWhenGettingTheResultOfAnUnrequestedAggregation {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"pages"] ]]];
|
|
|
|
@try {
|
|
[snapshot count];
|
|
XCTAssertTrue(false, "Exception expected");
|
|
} @catch (NSException* exception) {
|
|
XCTAssertEqualObjects(exception.name, @"FIRInvalidArgumentException");
|
|
XCTAssertEqualObjects(exception.reason,
|
|
@"'count()' was not requested in the aggregation query.");
|
|
}
|
|
|
|
@
|
|
try {
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"foo"]];
|
|
XCTAssertTrue(false, "Exception expected");
|
|
} @catch (NSException* exception) {
|
|
XCTAssertEqualObjects(exception.name, @"FIRInvalidArgumentException");
|
|
XCTAssertEqualObjects(exception.reason,
|
|
@"'sum(foo)' was not requested in the aggregation query.");
|
|
}
|
|
|
|
@
|
|
try {
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]];
|
|
XCTAssertTrue(false, "Exception expected");
|
|
} @catch (NSException* exception) {
|
|
XCTAssertEqualObjects(exception.name, @"FIRInvalidArgumentException");
|
|
XCTAssertEqualObjects(exception.reason,
|
|
@"'avg(pages)' was not requested in the aggregation query.");
|
|
}
|
|
}
|
|
|
|
- (void)testPerformsAggregationWhenUsingInOperator {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"year" : @1980,
|
|
@"rating" : @5
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"year" : @2020,
|
|
@"rating" : @4
|
|
},
|
|
@"c" : @{
|
|
@"author" : @"authorC",
|
|
@"title" : @"titleC",
|
|
@"pages" : @100,
|
|
@"year" : @1980,
|
|
@"rating" : @3
|
|
},
|
|
@"d" : @{
|
|
@"author" : @"authorD",
|
|
@"title" : @"titleD",
|
|
@"pages" : @50,
|
|
@"year" : @2020,
|
|
@"rating" : @0
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot = [self
|
|
readSnapshotForAggregate:[[testCollection queryWhereField:@"rating" in:@[ @5, @3 ]]
|
|
aggregate:@[
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"rating"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForCount]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]] longValue], 2L);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
longValue],
|
|
8L);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]]
|
|
longValue],
|
|
200L);
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]]
|
|
doubleValue],
|
|
4.0);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]]
|
|
doubleValue],
|
|
100.0);
|
|
}
|
|
|
|
- (void)testPerformsAggregationWhenUsingArrayContainsAnyOperator {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"year" : @1980,
|
|
@"rating" : @[ @5, @1000 ]
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"year" : @2020,
|
|
@"rating" : @[ @4 ]
|
|
},
|
|
@"c" : @{
|
|
@"author" : @"authorC",
|
|
@"title" : @"titleC",
|
|
@"pages" : @100,
|
|
@"year" : @1980,
|
|
@"rating" : @[ @2222, @3 ]
|
|
},
|
|
@"d" : @{
|
|
@"author" : @"authorD",
|
|
@"title" : @"titleD",
|
|
@"pages" : @50,
|
|
@"year" : @2020,
|
|
@"rating" : @[ @0 ]
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot = [self
|
|
readSnapshotForAggregate:[[testCollection queryWhereField:@"rating"
|
|
arrayContainsAny:@[ @5, @3 ]]
|
|
aggregate:@[
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"rating"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
|
|
[FIRAggregateField aggregateFieldForCount]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]] longValue], 2L);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
longValue],
|
|
0L);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]]
|
|
longValue],
|
|
200L);
|
|
|
|
// Average
|
|
XCTAssertEqualObjects(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]],
|
|
[NSNull null]);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]]
|
|
doubleValue],
|
|
100.0);
|
|
}
|
|
|
|
- (void)testPerformsAggregationsOnNestedMapValues {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"metadata" : @{@"pages" : @100, @"rating" : @{@"critic" : @2, @"user" : @5}}
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"metadata" : @{@"pages" : @50, @"rating" : @{@"critic" : @4, @"user" : @4}}
|
|
},
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"metadata.pages"],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"metadata.rating.user"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"metadata.pages"],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"metadata.rating.critic"],
|
|
[FIRAggregateField aggregateFieldForCount]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]] longValue], 2L);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField
|
|
aggregateFieldForSumOfField:@"metadata.pages"]] longValue],
|
|
150L);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField
|
|
aggregateFieldForSumOfField:@"metadata.rating.user"]]
|
|
longValue],
|
|
9);
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[[snapshot
|
|
valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"metadata.pages"]]
|
|
doubleValue],
|
|
75.0);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField
|
|
aggregateFieldForAverageOfField:@"metadata.rating.critic"]]
|
|
doubleValue],
|
|
3.0);
|
|
}
|
|
|
|
- (void)testPerformsSumThatOverflowsMaxLong {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"rating" : [NSNumber numberWithLong:LLONG_MAX]
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"rating" : [NSNumber numberWithLong:LLONG_MAX]
|
|
},
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithLong:LLONG_MAX] doubleValue] +
|
|
[[NSNumber numberWithLong:LLONG_MAX] doubleValue]);
|
|
}
|
|
|
|
- (void)testPerformsSumThatCanOverflowLongValuesDuringAccumulation {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"rating" : [NSNumber numberWithLong:LLONG_MAX]
|
|
},
|
|
@"b" : @{@"author" : @"authorB", @"title" : @"titleB", @"rating" : [NSNumber numberWithLong:1]},
|
|
@"c" :
|
|
@{@"author" : @"authorC", @"title" : @"titleC", @"rating" : [NSNumber numberWithLong:-101]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
longLongValue],
|
|
[[NSNumber numberWithLong:LLONG_MAX - 100] longLongValue]);
|
|
}
|
|
|
|
- (void)testPerformsSumThatIsNegative {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"rating" : [NSNumber numberWithLong:LLONG_MAX]
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"rating" : [NSNumber numberWithLong:-LLONG_MAX]
|
|
},
|
|
@"c" :
|
|
@{@"author" : @"authorC", @"title" : @"titleC", @"rating" : [NSNumber numberWithLong:-101]},
|
|
@"d" : @{
|
|
@"author" : @"authorD",
|
|
@"title" : @"titleD",
|
|
@"rating" : [NSNumber numberWithLong:-10000]
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
longLongValue],
|
|
[[NSNumber numberWithLong:-10101] longLongValue]);
|
|
}
|
|
|
|
- (void)testPerformsSumThatIsPositiveInfinity {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"rating" : [NSNumber numberWithDouble:DBL_MAX]
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"rating" : [NSNumber numberWithDouble:DBL_MAX]
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]],
|
|
[NSNumber numberWithDouble:INFINITY]);
|
|
}
|
|
|
|
- (void)testPerformsSumThatIsNegativeInfinity {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"rating" : [NSNumber numberWithDouble:-DBL_MAX]
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"rating" : [NSNumber numberWithDouble:-DBL_MAX]
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]],
|
|
[NSNumber numberWithDouble:-INFINITY]);
|
|
}
|
|
|
|
- (void)testPerformsSumThatIsValidButCouldOverflowDuringAggregation {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
|
|
@"b" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
|
|
@"c" : @{@"rating" : [NSNumber numberWithDouble:-DBL_MAX]},
|
|
@"d" : @{@"rating" : [NSNumber numberWithDouble:-DBL_MAX]},
|
|
@"e" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
|
|
@"f" : @{@"rating" : [NSNumber numberWithDouble:-DBL_MAX]},
|
|
@"g" : @{@"rating" : [NSNumber numberWithDouble:-DBL_MAX]},
|
|
@"h" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
longLongValue],
|
|
[[NSNumber numberWithLong:0] longLongValue]);
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithLong:0] doubleValue]);
|
|
}
|
|
|
|
- (void)testPerformsSumOverResultSetOfZeroDocuments {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[[testCollection queryWhereField:@"pages" isGreaterThan:@200]
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"pages"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
|
|
[NSNumber numberWithLong:0L]);
|
|
}
|
|
|
|
- (void)testPerformsSumOnlyOnNumericFields {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithLong:5]},
|
|
@"b" : @{@"rating" : [NSNumber numberWithLong:4]},
|
|
@"c" : @{@"rating" : @"3"},
|
|
@"d" : @{@"rating" : [NSNumber numberWithLong:1]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForSumOfField:@"rating"]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]] longValue], 4L);
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
longLongValue],
|
|
[[NSNumber numberWithLong:10] longLongValue]);
|
|
}
|
|
|
|
- (void)testPerformsSumOfMinIEEE754 {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithDouble:__DBL_DENORM_MIN__]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForSumOfField:@"rating"] ]]];
|
|
|
|
// Sum
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithDouble:__DBL_DENORM_MIN__] doubleValue]);
|
|
}
|
|
|
|
- (void)testPerformsAverageOfVariousNumericTypes {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"x" : @1,
|
|
@"intToInt" : [NSNumber numberWithLong:10],
|
|
@"floatToInt" : [NSNumber numberWithDouble:10.5],
|
|
@"mixedToInt" : [NSNumber numberWithLong:10],
|
|
@"floatToFloat" : [NSNumber numberWithDouble:5.5],
|
|
@"mixedToFloat" : [NSNumber numberWithDouble:8.6],
|
|
@"intToFloat" : [NSNumber numberWithLong:10]
|
|
},
|
|
@"b" : @{
|
|
@"intToInt" : [NSNumber numberWithLong:5],
|
|
@"floatToInt" : [NSNumber numberWithDouble:9.5],
|
|
@"mixedToInt" : [NSNumber numberWithDouble:9.5],
|
|
@"floatToFloat" : [NSNumber numberWithDouble:4.5],
|
|
@"mixedToFloat" : [NSNumber numberWithLong:9],
|
|
@"intToFloat" : [NSNumber numberWithLong:9]
|
|
},
|
|
@"c" : @{
|
|
@"intToInt" : [NSNumber numberWithLong:0],
|
|
@"floatToInt" : @"ignore",
|
|
@"mixedToInt" : [NSNumber numberWithDouble:10.5],
|
|
@"floatToFloat" : [NSNumber numberWithDouble:3.5],
|
|
@"mixedToFloat" : [NSNumber numberWithLong:10],
|
|
@"intToFloat" : @"ignore"
|
|
}
|
|
}];
|
|
|
|
NSArray* testCases = @[
|
|
@{
|
|
@"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"intToInt"],
|
|
@"expected" : [NSNumber numberWithLong:5]
|
|
},
|
|
@{
|
|
@"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"floatToInt"],
|
|
@"expected" : [NSNumber numberWithLong:10]
|
|
},
|
|
@{
|
|
@"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"mixedToInt"],
|
|
@"expected" : [NSNumber numberWithLong:10]
|
|
},
|
|
@{
|
|
@"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"floatToFloat"],
|
|
@"expected" : [NSNumber numberWithDouble:4.5]
|
|
},
|
|
@{
|
|
@"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"mixedToFloat"],
|
|
@"expected" : [NSNumber numberWithDouble:9.2]
|
|
},
|
|
@{
|
|
@"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"intToFloat"],
|
|
@"expected" : [NSNumber numberWithDouble:9.5]
|
|
}
|
|
];
|
|
|
|
for (NSDictionary* testCase in testCases) {
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[ testCase[@"agg"] ]]];
|
|
|
|
// Average
|
|
XCTAssertEqual([[snapshot valueForAggregation:testCase[@"agg"]] longValue],
|
|
[testCase[@"expected"] longLongValue]);
|
|
XCTAssertEqualWithAccuracy([[snapshot valueForAggregation:testCase[@"agg"]] doubleValue],
|
|
[testCase[@"expected"] doubleValue], 0.00000000000001);
|
|
}
|
|
}
|
|
|
|
- (void)testPerformsAverageCausingUnderflow {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithDouble:__DBL_DENORM_MIN__]},
|
|
@"b" : @{@"rating" : [NSNumber numberWithDouble:0]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
|
|
]]];
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithDouble:0] doubleValue]);
|
|
}
|
|
|
|
- (void)testPerformsAverageOfMinIEEE754 {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithDouble:__DBL_DENORM_MIN__]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
|
|
]]];
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithDouble:__DBL_DENORM_MIN__] doubleValue]);
|
|
}
|
|
|
|
- (void)testPerformsAverageOverflowIEEE754DuringAccumulation {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
|
|
@"b" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
|
|
]]];
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithDouble:INFINITY] doubleValue]);
|
|
}
|
|
|
|
- (void)testPerformsAverageOverResultSetOfZeroDocuments {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{
|
|
@"author" : @"authorA",
|
|
@"title" : @"titleA",
|
|
@"pages" : @100,
|
|
@"height" : @24.5,
|
|
@"weight" : @24.1,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
},
|
|
@"b" : @{
|
|
@"author" : @"authorB",
|
|
@"title" : @"titleB",
|
|
@"pages" : @50,
|
|
@"height" : @25.5,
|
|
@"weight" : @75.5,
|
|
@"foo" : @1,
|
|
@"bar" : @2,
|
|
@"baz" : @3
|
|
}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot = [self
|
|
readSnapshotForAggregate:[[testCollection queryWhereField:@"pages" isGreaterThan:@200]
|
|
aggregate:@[ [FIRAggregateField
|
|
aggregateFieldForAverageOfField:@"pages"] ]]];
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]],
|
|
[NSNull null]);
|
|
}
|
|
|
|
- (void)testPerformsAverageOnlyOnNumericFields {
|
|
// TODO(sum/avg) remove the check below when sum and avg are supported in production
|
|
XCTSkipIf(![FSTIntegrationTestCase isRunningAgainstEmulator], @"only tested against emulator");
|
|
|
|
FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
|
|
@"a" : @{@"rating" : [NSNumber numberWithLong:5]},
|
|
@"b" : @{@"rating" : [NSNumber numberWithLong:4]},
|
|
@"c" : @{@"rating" : @"3"},
|
|
@"d" : @{@"rating" : [NSNumber numberWithLong:6]}
|
|
}];
|
|
|
|
FIRAggregateQuerySnapshot* snapshot =
|
|
[self readSnapshotForAggregate:[testCollection aggregate:@[
|
|
[FIRAggregateField aggregateFieldForCount],
|
|
[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
|
|
]]];
|
|
|
|
// Count
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForCount]] longValue], 4L);
|
|
|
|
// Average
|
|
XCTAssertEqual(
|
|
[[snapshot valueForAggregation:[FIRAggregateField aggregateFieldForAverageOfField:@"rating"]]
|
|
doubleValue],
|
|
[[NSNumber numberWithDouble:5] doubleValue]);
|
|
}
|
|
|
|
@end
|