FIRAggregateTests.mm 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. /*
  2. * Copyright 2023 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <FirebaseFirestore/FIRAggregateField.h>
  17. #import <FirebaseFirestore/FIRFieldPath.h>
  18. #import <FirebaseFirestore/FirebaseFirestore.h>
  19. #import <XCTest/XCTest.h>
  20. #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
  21. #import "Firestore/core/src/util/exception.h"
  22. @interface FIRAggregateTests : FSTIntegrationTestCase
  23. @end
  24. @implementation FIRAggregateTests
  25. - (void)testCountAggregateFieldQueryEquals {
  26. FIRCollectionReference* coll1 = [self collectionRefWithDocuments:@{}];
  27. FIRCollectionReference* coll1Same = [[coll1 firestore] collectionWithPath:[coll1 path]];
  28. FIRAggregateQuery* query1 = [coll1 aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  29. FIRAggregateQuery* query1Same =
  30. [coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  31. FIRAggregateQuery* query1DiffAgg =
  32. [coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  33. FIRCollectionReference* sub = [[coll1 documentWithPath:@"bar"] collectionWithPath:@"baz"];
  34. FIRAggregateQuery* query2 = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
  35. aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  36. FIRAggregateQuery* query2Same = [[[sub queryWhereField:@"a"
  37. isEqualTo:@1] queryLimitedTo:100] count];
  38. FIRAggregateQuery* query3 = [[[sub queryWhereField:@"b" isEqualTo:@1] queryOrderedByField:@"c"]
  39. aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  40. FIRAggregateQuery* query3Same = [[[sub queryWhereField:@"b"
  41. isEqualTo:@1] queryOrderedByField:@"c"] count];
  42. XCTAssertEqualObjects(query1, query1Same);
  43. XCTAssertEqualObjects(query2, query2Same);
  44. XCTAssertEqualObjects(query3, query3Same);
  45. XCTAssertEqual([query1 hash], [query1Same hash]);
  46. XCTAssertEqual([query2 hash], [query2Same hash]);
  47. XCTAssertEqual([query3 hash], [query3Same hash]);
  48. XCTAssertFalse([query1 isEqual:nil]);
  49. XCTAssertFalse([query1 isEqual:@"string"]);
  50. XCTAssertFalse([query1 isEqual:query2]);
  51. XCTAssertFalse([query2 isEqual:query3]);
  52. XCTAssertNotEqual([query1 hash], [query1DiffAgg hash]);
  53. XCTAssertNotEqual([query1 hash], [query2 hash]);
  54. XCTAssertNotEqual([query2 hash], [query3 hash]);
  55. }
  56. - (void)testSumAggregateFieldQueryEquals {
  57. FIRCollectionReference* coll1 = [self collectionRefWithDocuments:@{}];
  58. FIRCollectionReference* coll1Same = [[coll1 firestore] collectionWithPath:[coll1 path]];
  59. FIRAggregateQuery* query1 =
  60. [coll1 aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  61. FIRAggregateQuery* query1Same =
  62. [coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  63. FIRAggregateQuery* query1WithFieldPath =
  64. [coll1Same aggregate:@[ [FIRAggregateField
  65. aggregateFieldForSumOfFieldPath:[[FIRFieldPath alloc]
  66. initWithFields:@[ @"baz" ]]] ]];
  67. FIRAggregateQuery* query1DiffAgg =
  68. [coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  69. FIRCollectionReference* sub = [[coll1 documentWithPath:@"bar"] collectionWithPath:@"baz"];
  70. FIRAggregateQuery* query2 = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
  71. aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  72. FIRAggregateQuery* query2Same = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
  73. aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  74. FIRAggregateQuery* query3 = [[[sub queryWhereField:@"b" isEqualTo:@1] queryOrderedByField:@"c"]
  75. aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  76. FIRAggregateQuery* query3Same = [[[sub queryWhereField:@"b"
  77. isEqualTo:@1] queryOrderedByField:@"c"]
  78. aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  79. XCTAssertEqualObjects(query1, query1Same);
  80. XCTAssertEqualObjects(query1, query1WithFieldPath);
  81. XCTAssertEqualObjects(query2, query2Same);
  82. XCTAssertEqualObjects(query3, query3Same);
  83. XCTAssertEqual([query1 hash], [query1Same hash]);
  84. XCTAssertEqual([query1 hash], [query1WithFieldPath hash]);
  85. XCTAssertEqual([query2 hash], [query2Same hash]);
  86. XCTAssertEqual([query3 hash], [query3Same hash]);
  87. XCTAssertFalse([query1 isEqual:nil]);
  88. XCTAssertFalse([query1 isEqual:@"string"]);
  89. XCTAssertFalse([query1 isEqual:query2]);
  90. XCTAssertFalse([query2 isEqual:query3]);
  91. XCTAssertNotEqual([query1 hash], [query1DiffAgg hash]);
  92. XCTAssertNotEqual([query1 hash], [query2 hash]);
  93. XCTAssertNotEqual([query2 hash], [query3 hash]);
  94. }
  95. - (void)testAverageAggregateFieldQueryEquals {
  96. FIRCollectionReference* coll1 = [self collectionRefWithDocuments:@{}];
  97. FIRCollectionReference* coll1Same = [[coll1 firestore] collectionWithPath:[coll1 path]];
  98. FIRAggregateQuery* query1 =
  99. [coll1 aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  100. FIRAggregateQuery* query1Same =
  101. [coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  102. FIRAggregateQuery* query1WithFieldPath = [coll1Same aggregate:@[
  103. [FIRAggregateField
  104. aggregateFieldForAverageOfFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"baz" ]]]
  105. ]];
  106. FIRAggregateQuery* query1DiffAgg =
  107. [coll1Same aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  108. FIRCollectionReference* sub = [[coll1 documentWithPath:@"bar"] collectionWithPath:@"baz"];
  109. FIRAggregateQuery* query2 = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
  110. aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  111. FIRAggregateQuery* query2Same = [[[sub queryWhereField:@"a" isEqualTo:@1] queryLimitedTo:100]
  112. aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  113. FIRAggregateQuery* query3 = [[[sub queryWhereField:@"b" isEqualTo:@1] queryOrderedByField:@"c"]
  114. aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  115. FIRAggregateQuery* query3Same = [[[sub queryWhereField:@"b"
  116. isEqualTo:@1] queryOrderedByField:@"c"]
  117. aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  118. XCTAssertEqualObjects(query1, query1Same);
  119. XCTAssertEqualObjects(query1, query1WithFieldPath);
  120. XCTAssertEqualObjects(query2, query2Same);
  121. XCTAssertEqualObjects(query3, query3Same);
  122. XCTAssertEqual([query1 hash], [query1Same hash]);
  123. XCTAssertEqual([query1 hash], [query1WithFieldPath hash]);
  124. XCTAssertEqual([query2 hash], [query2Same hash]);
  125. XCTAssertEqual([query3 hash], [query3Same hash]);
  126. XCTAssertFalse([query1 isEqual:nil]);
  127. XCTAssertFalse([query1 isEqual:@"string"]);
  128. XCTAssertFalse([query1 isEqual:query2]);
  129. XCTAssertFalse([query2 isEqual:query3]);
  130. XCTAssertNotEqual([query1 hash], [query1DiffAgg hash]);
  131. XCTAssertNotEqual([query1 hash], [query2 hash]);
  132. XCTAssertNotEqual([query2 hash], [query3 hash]);
  133. }
  134. - (void)testAggregateFieldQueryNotEquals {
  135. FIRCollectionReference* coll = [self collectionRefWithDocuments:@{}];
  136. FIRAggregateQuery* query1 = [coll aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  137. FIRAggregateQuery* query2 =
  138. [coll aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  139. FIRAggregateQuery* query3 =
  140. [coll aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  141. XCTAssertNotEqualObjects(query1, query2);
  142. XCTAssertNotEqualObjects(query2, query3);
  143. XCTAssertNotEqualObjects(query3, query1);
  144. XCTAssertNotEqual([query1 hash], [query2 hash]);
  145. XCTAssertNotEqual([query2 hash], [query3 hash]);
  146. XCTAssertNotEqual([query3 hash], [query1 hash]);
  147. FIRQuery* baseQuery = [[[[coll documentWithPath:@"bar"] collectionWithPath:@"baz"]
  148. queryWhereField:@"a"
  149. isEqualTo:@1] queryLimitedTo:100];
  150. FIRAggregateQuery* query4 = [baseQuery aggregate:@[ [FIRAggregateField aggregateFieldForCount] ]];
  151. FIRAggregateQuery* query5 =
  152. [baseQuery aggregate:@[ [FIRAggregateField aggregateFieldForSumOfField:@"baz"] ]];
  153. FIRAggregateQuery* query6 =
  154. [baseQuery aggregate:@[ [FIRAggregateField aggregateFieldForAverageOfField:@"baz"] ]];
  155. XCTAssertNotEqualObjects(query4, query5);
  156. XCTAssertNotEqualObjects(query5, query6);
  157. XCTAssertNotEqualObjects(query6, query4);
  158. XCTAssertNotEqual([query4 hash], [query5 hash]);
  159. XCTAssertNotEqual([query5 hash], [query6 hash]);
  160. XCTAssertNotEqual([query6 hash], [query4 hash]);
  161. }
  162. - (void)testCanRunAggregateQuery {
  163. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  164. @"a" : @{
  165. @"author" : @"authorA",
  166. @"title" : @"titleA",
  167. @"pages" : @100,
  168. @"height" : @24.5,
  169. @"weight" : @24.1,
  170. @"foo" : @1,
  171. @"bar" : @2,
  172. @"baz" : @3
  173. },
  174. @"b" : @{
  175. @"author" : @"authorB",
  176. @"title" : @"titleB",
  177. @"pages" : @50,
  178. @"height" : @25.5,
  179. @"weight" : @75.5,
  180. @"foo" : @1,
  181. @"bar" : @2,
  182. @"baz" : @3
  183. }
  184. }];
  185. FIRAggregateQuerySnapshot* snapshot =
  186. [self readSnapshotForAggregate:[testCollection aggregate:@[
  187. [FIRAggregateField aggregateFieldForCount],
  188. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  189. [FIRAggregateField aggregateFieldForAverageOfField:@"pages"]
  190. ]]];
  191. // Count
  192. XCTAssertEqual([snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]],
  193. [NSNumber numberWithLong:2L]);
  194. XCTAssertEqual([snapshot count], [NSNumber numberWithLong:2L]);
  195. // Sum
  196. XCTAssertEqual(
  197. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
  198. [NSNumber numberWithLong:150L], );
  199. // Average
  200. XCTAssertEqual([snapshot valueForAggregateField:[FIRAggregateField
  201. aggregateFieldForAverageOfField:@"pages"]],
  202. [NSNumber numberWithDouble:75.0]);
  203. }
  204. - (void)testCanRunEmptyAggregateQuery {
  205. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  206. @"a" : @{
  207. @"author" : @"authorA",
  208. @"title" : @"titleA",
  209. @"pages" : @100,
  210. @"height" : @24.5,
  211. @"weight" : @24.1,
  212. @"foo" : @1,
  213. @"bar" : @2,
  214. @"baz" : @3
  215. },
  216. @"b" : @{
  217. @"author" : @"authorB",
  218. @"title" : @"titleB",
  219. @"pages" : @50,
  220. @"height" : @25.5,
  221. @"weight" : @75.5,
  222. @"foo" : @1,
  223. @"bar" : @2,
  224. @"baz" : @3
  225. }
  226. }];
  227. FIRAggregateQuery* emptyQuery = [testCollection aggregate:@[]];
  228. __block NSError* result;
  229. XCTestExpectation* expectation = [self expectationWithDescription:@"aggregate result"];
  230. [emptyQuery aggregationWithSource:FIRAggregateSourceServer
  231. completion:^(FIRAggregateQuerySnapshot* snapshot, NSError* error) {
  232. XCTAssertNil(snapshot);
  233. result = error;
  234. [expectation fulfill];
  235. }];
  236. [self awaitExpectation:expectation];
  237. XCTAssertNotNil(result);
  238. XCTAssertTrue([[result localizedDescription] containsString:@"Aggregations can not be empty"]);
  239. }
  240. // (TODO:b/283101111): Try thread sanitizer to see if timeout on Github Actions is gone.
  241. #if !defined(THREAD_SANITIZER)
  242. - (void)testAggregateFieldQuerySnapshotEquality {
  243. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  244. @"a" : @{
  245. @"author" : @"authorA",
  246. @"title" : @"titleA",
  247. @"pages" : @100,
  248. @"height" : @24.5,
  249. @"weight" : @24.1,
  250. @"foo" : @1,
  251. @"bar" : @2,
  252. @"baz" : @3
  253. },
  254. @"b" : @{
  255. @"author" : @"authorB",
  256. @"title" : @"titleB",
  257. @"pages" : @50,
  258. @"height" : @25.5,
  259. @"weight" : @75.5,
  260. @"foo" : @1,
  261. @"bar" : @2,
  262. @"baz" : @3
  263. }
  264. }];
  265. FIRAggregateQuerySnapshot* snapshot1 =
  266. [self readSnapshotForAggregate:[testCollection aggregate:@[
  267. [FIRAggregateField aggregateFieldForCount],
  268. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  269. [FIRAggregateField aggregateFieldForAverageOfField:@"pages"]
  270. ]]];
  271. FIRAggregateQuerySnapshot* snapshot2 =
  272. [self readSnapshotForAggregate:[testCollection aggregate:@[
  273. [FIRAggregateField aggregateFieldForCount],
  274. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  275. [FIRAggregateField aggregateFieldForAverageOfField:@"pages"]
  276. ]]];
  277. // different aggregates
  278. FIRAggregateQuerySnapshot* snapshot3 =
  279. [self readSnapshotForAggregate:[testCollection aggregate:@[
  280. [FIRAggregateField aggregateFieldForCount],
  281. [FIRAggregateField aggregateFieldForSumOfField:@"weight"],
  282. [FIRAggregateField aggregateFieldForAverageOfField:@"weight"]
  283. ]]];
  284. // different data set
  285. FIRAggregateQuerySnapshot* snapshot4 =
  286. [self readSnapshotForAggregate:[[testCollection queryWhereField:@"pages" isGreaterThan:@50]
  287. aggregate:@[
  288. [FIRAggregateField aggregateFieldForCount],
  289. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  290. [FIRAggregateField
  291. aggregateFieldForAverageOfField:@"pages"]
  292. ]]];
  293. XCTAssertEqualObjects(snapshot1, snapshot2);
  294. XCTAssertNotEqualObjects(snapshot1, snapshot3);
  295. XCTAssertNotEqualObjects(snapshot1, snapshot4);
  296. XCTAssertNotEqualObjects(snapshot3, snapshot4);
  297. XCTAssertEqual([snapshot1 hash], [snapshot2 hash]);
  298. XCTAssertNotEqual([snapshot1 hash], [snapshot3 hash]);
  299. XCTAssertNotEqual([snapshot1 hash], [snapshot4 hash]);
  300. XCTAssertNotEqual([snapshot3 hash], [snapshot4 hash]);
  301. }
  302. #endif // #if !defined(THREAD_SANITIZER)
  303. - (void)testAggregateOnFieldNameWithMaxLength {
  304. // The longest field name and alias allowed is 1500 bytes or 1499 characters.
  305. NSString* longField = [@"" stringByPaddingToLength:1499
  306. withString:@"0123456789"
  307. startingAtIndex:0];
  308. FIRCollectionReference* testCollection =
  309. [self collectionRefWithDocuments:@{@"a" : @{longField : @1}, @"b" : @{longField : @2}}];
  310. FIRAggregateQuerySnapshot* snapshot =
  311. [self readSnapshotForAggregate:[testCollection
  312. aggregate:@[ [FIRAggregateField
  313. aggregateFieldForSumOfField:longField] ]]];
  314. // Sum
  315. XCTAssertEqual(
  316. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:longField]],
  317. [NSNumber numberWithLong:3], );
  318. }
  319. - (void)testCanGetDuplicateAggregations {
  320. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  321. @"a" : @{
  322. @"author" : @"authorA",
  323. @"title" : @"titleA",
  324. @"pages" : @100,
  325. @"height" : @24.5,
  326. @"weight" : @24.1,
  327. @"foo" : @1,
  328. @"bar" : @2,
  329. @"baz" : @3
  330. },
  331. @"b" : @{
  332. @"author" : @"authorB",
  333. @"title" : @"titleB",
  334. @"pages" : @50,
  335. @"height" : @25.5,
  336. @"weight" : @75.5,
  337. @"foo" : @1,
  338. @"bar" : @2,
  339. @"baz" : @3
  340. }
  341. }];
  342. FIRAggregateQuerySnapshot* snapshot =
  343. [self readSnapshotForAggregate:[testCollection aggregate:@[
  344. [FIRAggregateField aggregateFieldForCount],
  345. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  346. [FIRAggregateField aggregateFieldForSumOfField:@"pages"]
  347. ]]];
  348. // Count
  349. XCTAssertEqual([snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]],
  350. [NSNumber numberWithLong:2L]);
  351. // Sum
  352. XCTAssertEqual(
  353. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
  354. [NSNumber numberWithLong:150L], );
  355. }
  356. - (void)testTerminateDoesNotCrashWithFlyingAggregateQuery {
  357. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  358. @"a" : @{
  359. @"author" : @"authorA",
  360. @"title" : @"titleA",
  361. @"pages" : @100,
  362. @"height" : @24.5,
  363. @"weight" : @24.1,
  364. @"foo" : @1,
  365. @"bar" : @2,
  366. @"baz" : @3
  367. },
  368. @"b" : @{
  369. @"author" : @"authorB",
  370. @"title" : @"titleB",
  371. @"pages" : @50,
  372. @"height" : @25.5,
  373. @"weight" : @75.5,
  374. @"foo" : @1,
  375. @"bar" : @2,
  376. @"baz" : @3
  377. }
  378. }];
  379. FIRAggregateQuery* aggQuery = [testCollection aggregate:@[
  380. [FIRAggregateField aggregateFieldForCount],
  381. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  382. [FIRAggregateField aggregateFieldForAverageOfField:@"pages"]
  383. ]];
  384. __block FIRAggregateQuerySnapshot* result;
  385. XCTestExpectation* expectation = [self expectationWithDescription:@"aggregate result"];
  386. [aggQuery aggregationWithSource:FIRAggregateSourceServer
  387. completion:^(FIRAggregateQuerySnapshot* snapshot, NSError* error) {
  388. XCTAssertNil(error);
  389. result = snapshot;
  390. [expectation fulfill];
  391. }];
  392. [self awaitExpectation:expectation];
  393. // Count
  394. XCTAssertEqual([result valueForAggregateField:[FIRAggregateField aggregateFieldForCount]],
  395. [NSNumber numberWithLong:2L]);
  396. // Sum
  397. XCTAssertEqual(
  398. [result valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
  399. [NSNumber numberWithLong:150L], );
  400. }
  401. - (void)testCannotPerformMoreThanMaxAggregations {
  402. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  403. @"a" : @{
  404. @"author" : @"authorA",
  405. @"title" : @"titleA",
  406. @"pages" : @100,
  407. @"height" : @24.5,
  408. @"weight" : @24.1,
  409. @"foo" : @1,
  410. @"bar" : @2,
  411. @"baz" : @3
  412. },
  413. @"b" : @{
  414. @"author" : @"authorB",
  415. @"title" : @"titleB",
  416. @"pages" : @50,
  417. @"height" : @25.5,
  418. @"weight" : @75.5,
  419. @"foo" : @1,
  420. @"bar" : @2,
  421. @"baz" : @3
  422. }
  423. }];
  424. // Max is 5, we're attempting 6. I also like to live dangerously.
  425. FIRAggregateQuery* query = [testCollection aggregate:@[
  426. [FIRAggregateField aggregateFieldForCount],
  427. [FIRAggregateField aggregateFieldForSumOfField:@"pages"],
  428. [FIRAggregateField aggregateFieldForSumOfField:@"weight"],
  429. [FIRAggregateField aggregateFieldForAverageOfField:@"pages"],
  430. [FIRAggregateField aggregateFieldForAverageOfField:@"weight"],
  431. [FIRAggregateField aggregateFieldForAverageOfField:@"foo"]
  432. ]];
  433. __block NSError* result;
  434. XCTestExpectation* expectation = [self expectationWithDescription:@"aggregate result"];
  435. [query aggregationWithSource:FIRAggregateSourceServer
  436. completion:^(FIRAggregateQuerySnapshot* snapshot, NSError* error) {
  437. XCTAssertNil(snapshot);
  438. result = error;
  439. [expectation fulfill];
  440. }];
  441. [self awaitExpectation:expectation];
  442. XCTAssertNotNil(result);
  443. XCTAssertTrue([[result localizedDescription] containsString:@"maximum number of aggregations"]);
  444. }
  445. - (void)testThrowsAnErrorWhenGettingTheResultOfAnUnrequestedAggregation {
  446. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  447. @"a" : @{
  448. @"author" : @"authorA",
  449. @"title" : @"titleA",
  450. @"pages" : @100,
  451. @"height" : @24.5,
  452. @"weight" : @24.1,
  453. @"foo" : @1,
  454. @"bar" : @2,
  455. @"baz" : @3
  456. },
  457. @"b" : @{
  458. @"author" : @"authorB",
  459. @"title" : @"titleB",
  460. @"pages" : @50,
  461. @"height" : @25.5,
  462. @"weight" : @75.5,
  463. @"foo" : @1,
  464. @"bar" : @2,
  465. @"baz" : @3
  466. }
  467. }];
  468. FIRAggregateQuerySnapshot* snapshot =
  469. [self readSnapshotForAggregate:[testCollection
  470. aggregate:@[ [FIRAggregateField
  471. aggregateFieldForSumOfField:@"pages"] ]]];
  472. @try {
  473. [snapshot count];
  474. XCTAssertTrue(false, "Exception expected");
  475. } @catch (NSException* exception) {
  476. XCTAssertEqualObjects(exception.name, @"FIRInvalidArgumentException");
  477. XCTAssertEqualObjects(exception.reason,
  478. @"'count()' was not requested in the aggregation query.");
  479. }
  480. @
  481. try {
  482. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"foo"]];
  483. XCTAssertTrue(false, "Exception expected");
  484. } @catch (NSException* exception) {
  485. XCTAssertEqualObjects(exception.name, @"FIRInvalidArgumentException");
  486. XCTAssertEqualObjects(exception.reason,
  487. @"'sum(foo)' was not requested in the aggregation query.");
  488. }
  489. @
  490. try {
  491. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForAverageOfField:@"pages"]];
  492. XCTAssertTrue(false, "Exception expected");
  493. } @catch (NSException* exception) {
  494. XCTAssertEqualObjects(exception.name, @"FIRInvalidArgumentException");
  495. XCTAssertEqualObjects(exception.reason,
  496. @"'avg(pages)' was not requested in the aggregation query.");
  497. }
  498. }
  499. - (void)testPerformsAggregationWhenUsingInOperator {
  500. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  501. @"a" : @{
  502. @"author" : @"authorA",
  503. @"title" : @"titleA",
  504. @"pages" : @100,
  505. @"year" : @1980,
  506. @"rating" : @5
  507. },
  508. @"b" : @{
  509. @"author" : @"authorB",
  510. @"title" : @"titleB",
  511. @"pages" : @50,
  512. @"year" : @2020,
  513. @"rating" : @4
  514. },
  515. @"c" : @{
  516. @"author" : @"authorC",
  517. @"title" : @"titleC",
  518. @"pages" : @100,
  519. @"year" : @1980,
  520. @"rating" : @3
  521. },
  522. @"d" : @{
  523. @"author" : @"authorD",
  524. @"title" : @"titleD",
  525. @"pages" : @50,
  526. @"year" : @2020,
  527. @"rating" : @0
  528. }
  529. }];
  530. FIRAggregateQuerySnapshot* snapshot = [self
  531. readSnapshotForAggregate:[[testCollection queryWhereField:@"rating" in:@[ @5, @3 ]]
  532. aggregate:@[
  533. [FIRAggregateField aggregateFieldForSumOfField:@"rating"],
  534. [FIRAggregateField aggregateFieldForAverageOfField:@"rating"],
  535. [FIRAggregateField aggregateFieldForCount]
  536. ]]];
  537. // Count
  538. XCTAssertEqual(
  539. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]] longValue], 2L);
  540. // Sum
  541. XCTAssertEqual(
  542. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  543. longValue],
  544. 8L);
  545. // Average
  546. XCTAssertEqual([[snapshot valueForAggregateField:[FIRAggregateField
  547. aggregateFieldForAverageOfField:@"rating"]]
  548. doubleValue],
  549. 4.0);
  550. }
  551. - (void)testPerformsAggregationsOnNestedMapValues {
  552. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  553. @"a" : @{
  554. @"author" : @"authorA",
  555. @"title" : @"titleA",
  556. @"metadata" : @{@"pages" : @100, @"rating" : @{@"critic" : @2, @"user" : @5}}
  557. },
  558. @"b" : @{
  559. @"author" : @"authorB",
  560. @"title" : @"titleB",
  561. @"metadata" : @{@"pages" : @50, @"rating" : @{@"critic" : @4, @"user" : @4}}
  562. },
  563. }];
  564. FIRAggregateQuerySnapshot* snapshot =
  565. [self readSnapshotForAggregate:[testCollection aggregate:@[
  566. [FIRAggregateField aggregateFieldForSumOfField:@"metadata.pages"],
  567. [FIRAggregateField aggregateFieldForAverageOfField:@"metadata.pages"],
  568. [FIRAggregateField aggregateFieldForCount]
  569. ]]];
  570. // Count
  571. XCTAssertEqual(
  572. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]] longValue], 2L);
  573. // Sum
  574. XCTAssertEqual(
  575. [[snapshot
  576. valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"metadata.pages"]]
  577. longValue],
  578. 150L);
  579. // Average
  580. XCTAssertEqual(
  581. [[snapshot valueForAggregateField:[FIRAggregateField
  582. aggregateFieldForAverageOfField:@"metadata.pages"]]
  583. doubleValue],
  584. 75.0);
  585. }
  586. - (void)testPerformsSumThatOverflowsMaxLong {
  587. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  588. @"a" : @{
  589. @"author" : @"authorA",
  590. @"title" : @"titleA",
  591. @"rating" : [NSNumber numberWithLong:LLONG_MAX]
  592. },
  593. @"b" : @{
  594. @"author" : @"authorB",
  595. @"title" : @"titleB",
  596. @"rating" : [NSNumber numberWithLong:LLONG_MAX]
  597. },
  598. }];
  599. FIRAggregateQuerySnapshot* snapshot =
  600. [self readSnapshotForAggregate:[testCollection
  601. aggregate:@[ [FIRAggregateField
  602. aggregateFieldForSumOfField:@"rating"] ]]];
  603. // Sum
  604. XCTAssertEqual(
  605. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  606. doubleValue],
  607. [[NSNumber numberWithLong:LLONG_MAX] doubleValue] +
  608. [[NSNumber numberWithLong:LLONG_MAX] doubleValue]);
  609. }
  610. - (void)testPerformsSumThatCanOverflowLongValuesDuringAccumulation {
  611. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  612. @"a" : @{
  613. @"author" : @"authorA",
  614. @"title" : @"titleA",
  615. @"rating" : [NSNumber numberWithLong:LLONG_MAX]
  616. },
  617. @"b" : @{@"author" : @"authorB", @"title" : @"titleB", @"rating" : [NSNumber numberWithLong:1]},
  618. @"c" :
  619. @{@"author" : @"authorC", @"title" : @"titleC", @"rating" : [NSNumber numberWithLong:-101]}
  620. }];
  621. FIRAggregateQuerySnapshot* snapshot =
  622. [self readSnapshotForAggregate:[testCollection
  623. aggregate:@[ [FIRAggregateField
  624. aggregateFieldForSumOfField:@"rating"] ]]];
  625. // Sum
  626. XCTAssertEqual(
  627. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  628. longLongValue],
  629. [[NSNumber numberWithLong:LLONG_MAX - 100] longLongValue]);
  630. }
  631. - (void)testPerformsSumThatIsNegative {
  632. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  633. @"a" : @{
  634. @"author" : @"authorA",
  635. @"title" : @"titleA",
  636. @"rating" : [NSNumber numberWithLong:LLONG_MAX]
  637. },
  638. @"b" : @{
  639. @"author" : @"authorB",
  640. @"title" : @"titleB",
  641. @"rating" : [NSNumber numberWithLong:-LLONG_MAX]
  642. },
  643. @"c" :
  644. @{@"author" : @"authorC", @"title" : @"titleC", @"rating" : [NSNumber numberWithLong:-101]},
  645. @"d" : @{
  646. @"author" : @"authorD",
  647. @"title" : @"titleD",
  648. @"rating" : [NSNumber numberWithLong:-10000]
  649. }
  650. }];
  651. FIRAggregateQuerySnapshot* snapshot =
  652. [self readSnapshotForAggregate:[testCollection
  653. aggregate:@[ [FIRAggregateField
  654. aggregateFieldForSumOfField:@"rating"] ]]];
  655. // Sum
  656. XCTAssertEqual(
  657. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  658. longLongValue],
  659. [[NSNumber numberWithLong:-10101] longLongValue]);
  660. }
  661. - (void)testPerformsSumThatIsPositiveInfinity {
  662. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  663. @"a" : @{
  664. @"author" : @"authorA",
  665. @"title" : @"titleA",
  666. @"rating" : [NSNumber numberWithDouble:DBL_MAX]
  667. },
  668. @"b" : @{
  669. @"author" : @"authorB",
  670. @"title" : @"titleB",
  671. @"rating" : [NSNumber numberWithDouble:DBL_MAX]
  672. }
  673. }];
  674. FIRAggregateQuerySnapshot* snapshot =
  675. [self readSnapshotForAggregate:[testCollection
  676. aggregate:@[ [FIRAggregateField
  677. aggregateFieldForSumOfField:@"rating"] ]]];
  678. // Sum
  679. XCTAssertEqual(
  680. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]],
  681. [NSNumber numberWithDouble:INFINITY]);
  682. }
  683. - (void)testPerformsSumThatIsNegativeInfinity {
  684. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  685. @"a" : @{
  686. @"author" : @"authorA",
  687. @"title" : @"titleA",
  688. @"rating" : [NSNumber numberWithDouble:-DBL_MAX]
  689. },
  690. @"b" : @{
  691. @"author" : @"authorB",
  692. @"title" : @"titleB",
  693. @"rating" : [NSNumber numberWithDouble:-DBL_MAX]
  694. }
  695. }];
  696. FIRAggregateQuerySnapshot* snapshot =
  697. [self readSnapshotForAggregate:[testCollection
  698. aggregate:@[ [FIRAggregateField
  699. aggregateFieldForSumOfField:@"rating"] ]]];
  700. // Sum
  701. XCTAssertEqual(
  702. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]],
  703. [NSNumber numberWithDouble:-INFINITY]);
  704. }
  705. - (void)testPerformsSumThatIsValidButCouldOverflowDuringAggregation {
  706. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  707. @"a" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
  708. @"b" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
  709. @"c" : @{@"rating" : [NSNumber numberWithDouble:-DBL_MAX]},
  710. @"d" : @{@"rating" : [NSNumber numberWithDouble:-DBL_MAX]}
  711. }];
  712. FIRAggregateQuerySnapshot* snapshot =
  713. [self readSnapshotForAggregate:[testCollection
  714. aggregate:@[ [FIRAggregateField
  715. aggregateFieldForSumOfField:@"rating"] ]]];
  716. // Sum
  717. long long ratingL =
  718. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  719. longLongValue];
  720. XCTAssertTrue(ratingL == [[NSNumber numberWithDouble:-INFINITY] longLongValue] || ratingL == 0 ||
  721. ratingL == [[NSNumber numberWithDouble:INFINITY] longLongValue]);
  722. double ratingD =
  723. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  724. doubleValue];
  725. XCTAssertTrue(ratingD == -INFINITY || ratingD == 0 || ratingD == INFINITY);
  726. }
  727. - (void)testPerformsSumOverResultSetOfZeroDocuments {
  728. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  729. @"a" : @{
  730. @"author" : @"authorA",
  731. @"title" : @"titleA",
  732. @"pages" : @100,
  733. @"height" : @24.5,
  734. @"weight" : @24.1,
  735. @"foo" : @1,
  736. @"bar" : @2,
  737. @"baz" : @3
  738. },
  739. @"b" : @{
  740. @"author" : @"authorB",
  741. @"title" : @"titleB",
  742. @"pages" : @50,
  743. @"height" : @25.5,
  744. @"weight" : @75.5,
  745. @"foo" : @1,
  746. @"bar" : @2,
  747. @"baz" : @3
  748. }
  749. }];
  750. FIRAggregateQuerySnapshot* snapshot =
  751. [self readSnapshotForAggregate:[[testCollection queryWhereField:@"pages" isGreaterThan:@200]
  752. aggregate:@[ [FIRAggregateField
  753. aggregateFieldForSumOfField:@"pages"] ]]];
  754. // Sum
  755. XCTAssertEqual(
  756. [snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"pages"]],
  757. [NSNumber numberWithLong:0L]);
  758. }
  759. - (void)testPerformsSumOnlyOnNumericFields {
  760. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  761. @"a" : @{@"rating" : [NSNumber numberWithLong:5]},
  762. @"b" : @{@"rating" : [NSNumber numberWithLong:4]},
  763. @"c" : @{@"rating" : @"3"},
  764. @"d" : @{@"rating" : [NSNumber numberWithLong:1]}
  765. }];
  766. FIRAggregateQuerySnapshot* snapshot =
  767. [self readSnapshotForAggregate:[testCollection aggregate:@[
  768. [FIRAggregateField aggregateFieldForCount],
  769. [FIRAggregateField aggregateFieldForSumOfField:@"rating"]
  770. ]]];
  771. // Count
  772. XCTAssertEqual(
  773. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]] longValue], 4L);
  774. // Sum
  775. XCTAssertEqual(
  776. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  777. longLongValue],
  778. [[NSNumber numberWithLong:10] longLongValue]);
  779. }
  780. - (void)testPerformsSumOfMinIEEE754 {
  781. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  782. @"a" : @{@"rating" : [NSNumber numberWithDouble:__DBL_DENORM_MIN__]}
  783. }];
  784. FIRAggregateQuerySnapshot* snapshot =
  785. [self readSnapshotForAggregate:[testCollection
  786. aggregate:@[ [FIRAggregateField
  787. aggregateFieldForSumOfField:@"rating"] ]]];
  788. // Sum
  789. XCTAssertEqual(
  790. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForSumOfField:@"rating"]]
  791. doubleValue],
  792. [[NSNumber numberWithDouble:__DBL_DENORM_MIN__] doubleValue]);
  793. }
  794. - (void)testPerformsAverageOfVariousNumericTypes {
  795. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  796. @"a" : @{
  797. @"x" : @1,
  798. @"intToInt" : [NSNumber numberWithLong:10],
  799. @"floatToInt" : [NSNumber numberWithDouble:10.5],
  800. @"mixedToInt" : [NSNumber numberWithLong:10],
  801. @"floatToFloat" : [NSNumber numberWithDouble:5.5],
  802. @"mixedToFloat" : [NSNumber numberWithDouble:8.6],
  803. @"intToFloat" : [NSNumber numberWithLong:10]
  804. },
  805. @"b" : @{
  806. @"intToInt" : [NSNumber numberWithLong:5],
  807. @"floatToInt" : [NSNumber numberWithDouble:9.5],
  808. @"mixedToInt" : [NSNumber numberWithDouble:9.5],
  809. @"floatToFloat" : [NSNumber numberWithDouble:4.5],
  810. @"mixedToFloat" : [NSNumber numberWithLong:9],
  811. @"intToFloat" : [NSNumber numberWithLong:9]
  812. },
  813. @"c" : @{
  814. @"intToInt" : [NSNumber numberWithLong:0],
  815. @"floatToInt" : @"ignore",
  816. @"mixedToInt" : [NSNumber numberWithDouble:10.5],
  817. @"floatToFloat" : [NSNumber numberWithDouble:3.5],
  818. @"mixedToFloat" : [NSNumber numberWithLong:10],
  819. @"intToFloat" : @"ignore"
  820. }
  821. }];
  822. NSArray* testCases = @[
  823. @{
  824. @"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"intToInt"],
  825. @"expected" : [NSNumber numberWithLong:5]
  826. },
  827. @{
  828. @"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"floatToInt"],
  829. @"expected" : [NSNumber numberWithLong:10]
  830. },
  831. @{
  832. @"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"mixedToInt"],
  833. @"expected" : [NSNumber numberWithLong:10]
  834. },
  835. @{
  836. @"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"floatToFloat"],
  837. @"expected" : [NSNumber numberWithDouble:4.5]
  838. },
  839. @{
  840. @"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"mixedToFloat"],
  841. @"expected" : [NSNumber numberWithDouble:9.2]
  842. },
  843. @{
  844. @"agg" : [FIRAggregateField aggregateFieldForAverageOfField:@"intToFloat"],
  845. @"expected" : [NSNumber numberWithDouble:9.5]
  846. }
  847. ];
  848. for (NSDictionary* testCase in testCases) {
  849. FIRAggregateQuerySnapshot* snapshot =
  850. [self readSnapshotForAggregate:[testCollection aggregate:@[ testCase[@"agg"] ]]];
  851. // Average
  852. XCTAssertEqual([[snapshot valueForAggregateField:testCase[@"agg"]] longValue],
  853. [testCase[@"expected"] longLongValue]);
  854. XCTAssertEqualWithAccuracy([[snapshot valueForAggregateField:testCase[@"agg"]] doubleValue],
  855. [testCase[@"expected"] doubleValue], 0.00000000000001);
  856. }
  857. }
  858. - (void)testPerformsAverageCausingUnderflow {
  859. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  860. @"a" : @{@"rating" : [NSNumber numberWithDouble:__DBL_DENORM_MIN__]},
  861. @"b" : @{@"rating" : [NSNumber numberWithDouble:0]}
  862. }];
  863. FIRAggregateQuerySnapshot* snapshot =
  864. [self readSnapshotForAggregate:[testCollection aggregate:@[
  865. [FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
  866. ]]];
  867. // Average
  868. XCTAssertEqual([[snapshot valueForAggregateField:[FIRAggregateField
  869. aggregateFieldForAverageOfField:@"rating"]]
  870. doubleValue],
  871. [[NSNumber numberWithDouble:0] doubleValue]);
  872. }
  873. - (void)testPerformsAverageOfMinIEEE754 {
  874. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  875. @"a" : @{@"rating" : [NSNumber numberWithDouble:__DBL_DENORM_MIN__]}
  876. }];
  877. FIRAggregateQuerySnapshot* snapshot =
  878. [self readSnapshotForAggregate:[testCollection aggregate:@[
  879. [FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
  880. ]]];
  881. // Average
  882. XCTAssertEqual([[snapshot valueForAggregateField:[FIRAggregateField
  883. aggregateFieldForAverageOfField:@"rating"]]
  884. doubleValue],
  885. [[NSNumber numberWithDouble:__DBL_DENORM_MIN__] doubleValue]);
  886. }
  887. - (void)testPerformsAverageOverflowIEEE754DuringAccumulation {
  888. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  889. @"a" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]},
  890. @"b" : @{@"rating" : [NSNumber numberWithDouble:DBL_MAX]}
  891. }];
  892. FIRAggregateQuerySnapshot* snapshot =
  893. [self readSnapshotForAggregate:[testCollection aggregate:@[
  894. [FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
  895. ]]];
  896. // Average
  897. XCTAssertEqual([[snapshot valueForAggregateField:[FIRAggregateField
  898. aggregateFieldForAverageOfField:@"rating"]]
  899. doubleValue],
  900. [[NSNumber numberWithDouble:INFINITY] doubleValue]);
  901. }
  902. - (void)testPerformsAverageOverResultSetOfZeroDocuments {
  903. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  904. @"a" : @{
  905. @"author" : @"authorA",
  906. @"title" : @"titleA",
  907. @"pages" : @100,
  908. @"height" : @24.5,
  909. @"weight" : @24.1,
  910. @"foo" : @1,
  911. @"bar" : @2,
  912. @"baz" : @3
  913. },
  914. @"b" : @{
  915. @"author" : @"authorB",
  916. @"title" : @"titleB",
  917. @"pages" : @50,
  918. @"height" : @25.5,
  919. @"weight" : @75.5,
  920. @"foo" : @1,
  921. @"bar" : @2,
  922. @"baz" : @3
  923. }
  924. }];
  925. FIRAggregateQuerySnapshot* snapshot = [self
  926. readSnapshotForAggregate:[[testCollection queryWhereField:@"pages" isGreaterThan:@200]
  927. aggregate:@[ [FIRAggregateField
  928. aggregateFieldForAverageOfField:@"pages"] ]]];
  929. // Average
  930. XCTAssertEqual([snapshot valueForAggregateField:[FIRAggregateField
  931. aggregateFieldForAverageOfField:@"pages"]],
  932. [NSNull null]);
  933. }
  934. - (void)testPerformsAverageOnlyOnNumericFields {
  935. FIRCollectionReference* testCollection = [self collectionRefWithDocuments:@{
  936. @"a" : @{@"rating" : [NSNumber numberWithLong:5]},
  937. @"b" : @{@"rating" : [NSNumber numberWithLong:4]},
  938. @"c" : @{@"rating" : @"3"},
  939. @"d" : @{@"rating" : [NSNumber numberWithLong:6]}
  940. }];
  941. FIRAggregateQuerySnapshot* snapshot =
  942. [self readSnapshotForAggregate:[testCollection aggregate:@[
  943. [FIRAggregateField aggregateFieldForCount],
  944. [FIRAggregateField aggregateFieldForAverageOfField:@"rating"]
  945. ]]];
  946. // Count
  947. XCTAssertEqual(
  948. [[snapshot valueForAggregateField:[FIRAggregateField aggregateFieldForCount]] longValue], 4L);
  949. // Average
  950. XCTAssertEqual([[snapshot valueForAggregateField:[FIRAggregateField
  951. aggregateFieldForAverageOfField:@"rating"]]
  952. doubleValue],
  953. [[NSNumber numberWithDouble:5] doubleValue]);
  954. }
  955. @end