diff --git a/.gitignore b/.gitignore index 609430f4ea..0ad1525e37 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ gcs_key_file.json # Folders for cmake/test output *_build/ -*cmake-build-debug/ +cmake-build-*/ testing/test_framework/external/ # XCode user specific folders diff --git a/firestore/integration_test_internal/CMakeLists.txt b/firestore/integration_test_internal/CMakeLists.txt index 0205e5b164..f6e22bd8b1 100644 --- a/firestore/integration_test_internal/CMakeLists.txt +++ b/firestore/integration_test_internal/CMakeLists.txt @@ -91,6 +91,8 @@ set(FIREBASE_INTEGRATION_TEST_PORTABLE_TEST_SRCS # public API are performed. src/integration_test.cc # Internal tests below. + src/aggregate_query_snapshot_test.cc + src/aggregate_query_test.cc src/bundle_test.cc src/collection_reference_test.cc src/cursor_test.cc diff --git a/firestore/integration_test_internal/src/aggregate_query_snapshot_test.cc b/firestore/integration_test_internal/src/aggregate_query_snapshot_test.cc new file mode 100644 index 0000000000..101811ef46 --- /dev/null +++ b/firestore/integration_test_internal/src/aggregate_query_snapshot_test.cc @@ -0,0 +1,555 @@ +/* + * 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. + */ + +#include "firebase/firestore.h" +#include "firestore_integration_test.h" + +#include "gtest/gtest.h" + +#if defined(__ANDROID__) +#include "firestore/src/android/converter_android.h" +#else +#include "firestore/src/main/aggregate_query_snapshot_main.h" +#include "firestore/src/main/converter_main.h" +#endif // defined(__ANDROID__) + +namespace firebase { +namespace firestore { + +class AggregateQuerySnapshotTest : public FirestoreIntegrationTest { + protected: + static AggregateQuerySnapshot TestAggregateQuerySnapshot( + AggregateQuery aggregate_query, const int count) { + api::AggregateQuery aggregateQuery = + GetInternal(&aggregate_query)->aggregate_query_; + return MakePublic( + AggregateQuerySnapshotInternal(std::move(aggregateQuery), count)); + } +}; + +std::size_t AggregateQuerySnapshotHash(const AggregateQuerySnapshot& snapshot) { + return snapshot.Hash(); +} + +namespace { + +TEST_F(AggregateQuerySnapshotTest, DefaultConstructorReturnsInvalidObject) { + AggregateQuerySnapshot snapshot; + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_EQ(snapshot.count(), 0); + EXPECT_FALSE(snapshot.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + CopyConstructorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuerySnapshot snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + AggregateQuerySnapshot copied_snapshot(snapshot); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(copied_snapshot.count(), 0); + EXPECT_EQ(copied_snapshot.query(), AggregateQuery()); + EXPECT_FALSE(copied_snapshot.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + CopyConstructorAppliedToValidObjectReturnsEqualObject) { + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query, 5); + + EXPECT_EQ(snapshot.count(), 5); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + AggregateQuerySnapshot copied_snapshot(snapshot); + + EXPECT_EQ(snapshot.count(), 5); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + EXPECT_EQ(copied_snapshot.count(), 5); + EXPECT_EQ(copied_snapshot.query(), aggregate_query); + EXPECT_TRUE(copied_snapshot.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + DefaultObjectCopyAssignmentOperatorAppliedToValidObjectReturnsEqualObject) { + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + const AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query, 7); + + AggregateQuerySnapshot snapshot_copy_dest; + + EXPECT_EQ(snapshot_copy_dest.count(), 0); + EXPECT_EQ(snapshot_copy_dest.query(), AggregateQuery()); + EXPECT_FALSE(snapshot_copy_dest.is_valid()); + + snapshot_copy_dest = snapshot; + + EXPECT_EQ(snapshot.count(), 7); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_copy_dest.count(), 7); + EXPECT_EQ(snapshot_copy_dest.query(), aggregate_query); + EXPECT_TRUE(snapshot_copy_dest.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + DefaultObjectCopyAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + const AggregateQuerySnapshot snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + AggregateQuerySnapshot snapshot_copy_dest; + + EXPECT_EQ(snapshot_copy_dest.count(), 0); + EXPECT_EQ(snapshot_copy_dest.query(), AggregateQuery()); + EXPECT_FALSE(snapshot_copy_dest.is_valid()); + + snapshot_copy_dest; + + EXPECT_EQ(snapshot_copy_dest.count(), 0); + EXPECT_EQ(snapshot_copy_dest.query(), AggregateQuery()); + EXPECT_FALSE(snapshot_copy_dest.is_valid()); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + ValidObjectCopyAssignmentOperatorAppliedToValidObjectReturnsEqualObject) { + const AggregateQuerySnapshot snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot_copy_dest = + TestAggregateQuerySnapshot(aggregate_query, 7); + + EXPECT_EQ(snapshot_copy_dest.count(), 7); + EXPECT_EQ(snapshot_copy_dest.query(), aggregate_query); + EXPECT_TRUE(snapshot_copy_dest.is_valid()); + + snapshot_copy_dest = snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_copy_dest.count(), 0); + EXPECT_EQ(snapshot_copy_dest.query(), AggregateQuery()); + EXPECT_FALSE(snapshot_copy_dest.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + ValidObjectCopyAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + const AggregateQuery aggregate_query1 = + TestFirestore()->Collection("foo").Limit(10).Count(); + const AggregateQuery aggregate_query2 = + TestFirestore()->Collection("bar").Limit(20).Count(); + + const AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query1, 1); + + EXPECT_EQ(snapshot.count(), 1); + EXPECT_EQ(snapshot.query(), aggregate_query1); + EXPECT_TRUE(snapshot.is_valid()); + + AggregateQuerySnapshot snapshot_copy_dest = + TestAggregateQuerySnapshot(aggregate_query2, 2); + + EXPECT_EQ(snapshot_copy_dest.count(), 2); + EXPECT_EQ(snapshot_copy_dest.query(), aggregate_query2); + EXPECT_TRUE(snapshot_copy_dest.is_valid()); + + snapshot_copy_dest = snapshot; + + EXPECT_EQ(snapshot.count(), 1); + EXPECT_EQ(snapshot.query(), aggregate_query1); + EXPECT_TRUE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_copy_dest.count(), 1); + EXPECT_EQ(snapshot_copy_dest.query(), aggregate_query1); + EXPECT_TRUE(snapshot_copy_dest.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + CopyAssignmentAppliedSelfReturnsEqualObject) { + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query, 7); + + EXPECT_EQ(snapshot.count(), 7); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + snapshot = snapshot; + + EXPECT_EQ(snapshot.count(), 7); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + MoveConstructorAppliedToValidObjectReturnsEqualObject) { + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query, 11); + + EXPECT_EQ(snapshot.count(), 11); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + AggregateQuerySnapshot moved_snapshot_dest(std::move(snapshot)); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(moved_snapshot_dest.count(), 11); + EXPECT_EQ(moved_snapshot_dest.query(), aggregate_query); + EXPECT_TRUE(moved_snapshot_dest.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + MoveConstructorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuerySnapshot snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + AggregateQuerySnapshot moved_snapshot_dest(std::move(snapshot)); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + DefaultObjectMoveAssignmentOperatorAppliedToValidObjectReturnsEqualObject) { + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query, 3); + + EXPECT_EQ(snapshot.count(), 3); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + AggregateQuerySnapshot snapshot_move_dest = std::move(snapshot); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_move_dest.count(), 3); + EXPECT_EQ(snapshot_move_dest.query(), aggregate_query); + EXPECT_TRUE(snapshot_move_dest.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + DefaultObjectMoveAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuerySnapshot snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + AggregateQuerySnapshot snapshot_move_dest = std::move(snapshot); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_move_dest.count(), 0); + EXPECT_EQ(snapshot_move_dest.query(), AggregateQuery()); + EXPECT_FALSE(snapshot_move_dest.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + ValidObjectMoveAssignmentOperatorAppliedToValidObjectReturnsEqualObject) { + const AggregateQuery aggregate_query1 = + TestFirestore()->Collection("foo").Limit(10).Count(); + const AggregateQuery aggregate_query2 = + TestFirestore()->Collection("bar").Limit(20).Count(); + + AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query1, 3); + + EXPECT_EQ(snapshot.count(), 3); + EXPECT_EQ(snapshot.query(), aggregate_query1); + EXPECT_TRUE(snapshot.is_valid()); + + AggregateQuerySnapshot snapshot_move_dest = + TestAggregateQuerySnapshot(aggregate_query2, 6); + + EXPECT_EQ(snapshot_move_dest.count(), 6); + EXPECT_EQ(snapshot_move_dest.query(), aggregate_query2); + EXPECT_TRUE(snapshot_move_dest.is_valid()); + + snapshot_move_dest = std::move(snapshot); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_move_dest.count(), 3); + EXPECT_EQ(snapshot_move_dest.query(), aggregate_query1); + EXPECT_TRUE(snapshot_move_dest.is_valid()); +} + +TEST_F( + AggregateQuerySnapshotTest, + ValidObjectMoveAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuerySnapshot snapshot; + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot_move_dest = + TestAggregateQuerySnapshot(aggregate_query, 99); + + EXPECT_EQ(snapshot_move_dest.count(), 99); + EXPECT_EQ(snapshot_move_dest.query(), aggregate_query); + EXPECT_TRUE(snapshot_move_dest.is_valid()); + + snapshot_move_dest = std::move(snapshot); + + EXPECT_EQ(snapshot.count(), 0); + EXPECT_EQ(snapshot.query(), AggregateQuery()); + EXPECT_FALSE(snapshot.is_valid()); + + EXPECT_EQ(snapshot_move_dest.count(), 0); + EXPECT_EQ(snapshot_move_dest.query(), AggregateQuery()); + EXPECT_FALSE(snapshot_move_dest.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + MoveAssignmentOperatorAppliedToSelfReturnsEqualObject) { + const AggregateQuery aggregate_query = + TestFirestore()->Collection("foo").Limit(10).Count(); + + AggregateQuerySnapshot snapshot = + TestAggregateQuerySnapshot(aggregate_query, 99); + + EXPECT_EQ(snapshot.count(), 99); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); + + snapshot = std::move(snapshot); + + EXPECT_EQ(snapshot.count(), 99); + EXPECT_EQ(snapshot.query(), aggregate_query); + EXPECT_TRUE(snapshot.is_valid()); +} + +TEST_F(AggregateQuerySnapshotTest, + IdenticalSnapshotFromCollectionQueriesWithLimitShouldBeEqual) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + AggregateQuerySnapshot snapshot1 = ReadAggregate(collection.Limit(1).Count()); + AggregateQuerySnapshot snapshot2 = ReadAggregate(collection.Limit(1).Count()); + + EXPECT_TRUE(snapshot1 == snapshot1); + EXPECT_TRUE(snapshot1 == snapshot2); + + EXPECT_FALSE(snapshot1 != snapshot1); + EXPECT_FALSE(snapshot1 != snapshot2); +} + +TEST_F(AggregateQuerySnapshotTest, + IdenticalSnapshotFromCollectionQueriesShouldBeEqual) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + AggregateQuerySnapshot snapshot1 = ReadAggregate(collection.Count()); + AggregateQuerySnapshot snapshot2 = ReadAggregate(collection.Count()); + + EXPECT_TRUE(snapshot1 == snapshot1); + EXPECT_TRUE(snapshot1 == snapshot2); + + EXPECT_FALSE(snapshot1 != snapshot1); + EXPECT_FALSE(snapshot1 != snapshot2); +} + +TEST_F(AggregateQuerySnapshotTest, + IdenticalDefaultAggregateSnapshotShouldBeEqual) { + AggregateQuerySnapshot snapshot1; + AggregateQuerySnapshot snapshot2; + + EXPECT_TRUE(snapshot1 == snapshot1); + EXPECT_TRUE(snapshot1 == snapshot2); + + EXPECT_FALSE(snapshot1 != snapshot1); + EXPECT_FALSE(snapshot1 != snapshot2); +} + +TEST_F(AggregateQuerySnapshotTest, NonEquality) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + AggregateQuerySnapshot snapshot1 = ReadAggregate( + collection.WhereEqualTo("k", FieldValue::String("d")).Count()); + AggregateQuerySnapshot snapshot2 = ReadAggregate(collection.Limit(1).Count()); + AggregateQuerySnapshot snapshot3 = ReadAggregate(collection.Limit(3).Count()); + AggregateQuerySnapshot snapshot4 = ReadAggregate(collection.Count()); + AggregateQuerySnapshot snapshot5; + + EXPECT_TRUE(snapshot1 == snapshot1); + EXPECT_TRUE(snapshot2 == snapshot2); + EXPECT_TRUE(snapshot3 == snapshot3); + EXPECT_TRUE(snapshot4 == snapshot4); + EXPECT_TRUE(snapshot5 == snapshot5); + + EXPECT_TRUE(snapshot1 != snapshot2); + EXPECT_TRUE(snapshot1 != snapshot3); + EXPECT_TRUE(snapshot1 != snapshot4); + EXPECT_TRUE(snapshot1 != snapshot5); + EXPECT_TRUE(snapshot2 != snapshot3); + EXPECT_TRUE(snapshot2 != snapshot4); + EXPECT_TRUE(snapshot2 != snapshot5); + EXPECT_TRUE(snapshot3 != snapshot4); + EXPECT_TRUE(snapshot3 != snapshot5); + EXPECT_TRUE(snapshot4 != snapshot5); + + EXPECT_FALSE(snapshot1 != snapshot1); + EXPECT_FALSE(snapshot2 != snapshot2); + EXPECT_FALSE(snapshot3 != snapshot3); + EXPECT_FALSE(snapshot4 != snapshot4); + EXPECT_FALSE(snapshot5 != snapshot5); + + EXPECT_FALSE(snapshot1 == snapshot2); + EXPECT_FALSE(snapshot1 == snapshot3); + EXPECT_FALSE(snapshot1 == snapshot4); + EXPECT_FALSE(snapshot1 == snapshot5); + EXPECT_FALSE(snapshot2 == snapshot3); + EXPECT_FALSE(snapshot2 == snapshot4); + EXPECT_FALSE(snapshot2 == snapshot5); + EXPECT_FALSE(snapshot3 == snapshot4); + EXPECT_FALSE(snapshot3 == snapshot5); + EXPECT_FALSE(snapshot4 == snapshot5); +} + +TEST_F(AggregateQuerySnapshotTest, + IdenticalSnapshotFromCollectionQueriesWithLimitShouldHaveSameHash) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + AggregateQuerySnapshot snapshot1 = ReadAggregate(collection.Limit(1).Count()); + AggregateQuerySnapshot snapshot2 = ReadAggregate(collection.Limit(1).Count()); + + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot1)); + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot2)); +} + +TEST_F(AggregateQuerySnapshotTest, + IdenticalSnapshotFromCollectionQueriesShouldHaveSameHash) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + AggregateQuerySnapshot snapshot1 = ReadAggregate(collection.Count()); + AggregateQuerySnapshot snapshot2 = ReadAggregate(collection.Count()); + + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot1)); + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot2)); +} + +TEST_F(AggregateQuerySnapshotTest, TestHashCode) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + AggregateQuerySnapshot snapshot1 = ReadAggregate( + collection.WhereEqualTo("k", FieldValue::String("d")).Count()); + AggregateQuerySnapshot snapshot2 = ReadAggregate(collection.Limit(1).Count()); + AggregateQuerySnapshot snapshot3 = ReadAggregate(collection.Limit(3).Count()); + AggregateQuerySnapshot snapshot4 = ReadAggregate(collection.Count()); + + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot1)); + EXPECT_NE(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot2)); + EXPECT_NE(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot3)); + EXPECT_NE(AggregateQuerySnapshotHash(snapshot1), + AggregateQuerySnapshotHash(snapshot4)); + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot2), + AggregateQuerySnapshotHash(snapshot2)); + EXPECT_NE(AggregateQuerySnapshotHash(snapshot2), + AggregateQuerySnapshotHash(snapshot3)); + EXPECT_NE(AggregateQuerySnapshotHash(snapshot2), + AggregateQuerySnapshotHash(snapshot4)); + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot3), + AggregateQuerySnapshotHash(snapshot3)); + EXPECT_NE(AggregateQuerySnapshotHash(snapshot3), + AggregateQuerySnapshotHash(snapshot4)); + EXPECT_EQ(AggregateQuerySnapshotHash(snapshot4), + AggregateQuerySnapshotHash(snapshot4)); +} + +} // namespace +} // namespace firestore +} // namespace firebase diff --git a/firestore/integration_test_internal/src/aggregate_query_test.cc b/firestore/integration_test_internal/src/aggregate_query_test.cc new file mode 100644 index 0000000000..7320be516f --- /dev/null +++ b/firestore/integration_test_internal/src/aggregate_query_test.cc @@ -0,0 +1,338 @@ +/* + * 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. + */ + +#include "firebase/firestore.h" +#include "firestore_integration_test.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { + +size_t AggregateQueryHash(const AggregateQuery& aggregate_query) { + return aggregate_query.Hash(); +} + +namespace { + +using AggregateQueryTest = FirestoreIntegrationTest; + +TEST_F(AggregateQueryTest, DefaultConstructorReturnsInvalidObject) { + AggregateQuery aggregate_query; + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, + CopyConstructorAppliedToValidObjectReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + const AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery copied_aggregate_query(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + EXPECT_EQ(copied_aggregate_query.query(), query); + EXPECT_TRUE(copied_aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, CopyConstructorAppliedToDefaultReturnsEqualObject) { + const AggregateQuery aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + AggregateQuery copied_aggregate_query(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(copied_aggregate_query.query(), Query()); + EXPECT_FALSE(copied_aggregate_query.is_valid()); +} + +TEST_F( + AggregateQueryTest, + DefaultObjectCopyAssignmentOperatorAppliedToValidObjectOperatorReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + const AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery copied_aggregate_query; + + EXPECT_EQ(copied_aggregate_query.query(), Query()); + EXPECT_FALSE(copied_aggregate_query.is_valid()); + + copied_aggregate_query = aggregate_query; + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + EXPECT_EQ(copied_aggregate_query.query(), query); + EXPECT_TRUE(copied_aggregate_query.is_valid()); +} + +TEST_F( + AggregateQueryTest, + DefaultObjectCopyAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + const AggregateQuery aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + AggregateQuery copied_aggregate_query; + + EXPECT_EQ(copied_aggregate_query.query(), Query()); + EXPECT_FALSE(copied_aggregate_query.is_valid()); + + copied_aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(copied_aggregate_query.query(), Query()); + EXPECT_FALSE(copied_aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, + ValidObjectCopyAssignmentAppliedToValidObjectReturnsEqualObject) { + const Query query1 = TestFirestore()->Collection("foo").Limit(10); + const Query query2 = TestFirestore()->Collection("bar").Limit(20); + const AggregateQuery aggregate_query = query1.Count(); + + EXPECT_EQ(aggregate_query.query(), query1); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery copied_aggregate_query = query2.Count(); + + EXPECT_EQ(copied_aggregate_query.query(), query2); + EXPECT_TRUE(copied_aggregate_query.is_valid()); + + copied_aggregate_query = aggregate_query; + + EXPECT_EQ(aggregate_query.query(), query1); + EXPECT_TRUE(aggregate_query.is_valid()); + + EXPECT_EQ(copied_aggregate_query.query(), query1); + EXPECT_TRUE(copied_aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, + ValidObjectCopyAssignmentAppliedToDefaultReturnsEqualObject) { + const AggregateQuery aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + const Query query = TestFirestore()->Collection("foo").Limit(10); + AggregateQuery copied_aggregate_query = query.Count(); + + EXPECT_EQ(copied_aggregate_query.query(), query); + EXPECT_TRUE(copied_aggregate_query.is_valid()); + + copied_aggregate_query = aggregate_query; + + EXPECT_EQ(copied_aggregate_query.query(), Query()); + EXPECT_FALSE(copied_aggregate_query.is_valid()); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, CopyAssignmentAppliedSelfReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + + AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + aggregate_query = aggregate_query; + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, + CopyAssignmentAppliedToValidObjectReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + const AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery copied_aggregate_query = aggregate_query; + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + EXPECT_EQ(copied_aggregate_query.query(), query); + EXPECT_TRUE(copied_aggregate_query.is_valid()); +} + +TEST_F(AggregateQueryTest, + MoveConstructorAppliedToValidObjectReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery moved_snapshot_dest(std::move(aggregate_query)); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(moved_snapshot_dest.query(), query); + EXPECT_TRUE(moved_snapshot_dest.is_valid()); +} + +TEST_F(AggregateQueryTest, + MoveConstructorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuery aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + AggregateQuery moved_snapshot_dest(std::move(aggregate_query)); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(moved_snapshot_dest.query(), Query()); + EXPECT_FALSE(moved_snapshot_dest.is_valid()); +} + +TEST_F( + AggregateQueryTest, + DefaultObjectMoveAssignmentOperatorAppliedToValidObjectReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery snapshot_move_dest = std::move(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(snapshot_move_dest.query(), query); + EXPECT_TRUE(snapshot_move_dest.is_valid()); +} + +TEST_F( + AggregateQueryTest, + DefaultObjectMoveAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuery aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + AggregateQuery snapshot_move_dest = std::move(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(snapshot_move_dest.query(), Query()); + EXPECT_FALSE(snapshot_move_dest.is_valid()); +} + +TEST_F( + AggregateQueryTest, + ValidObjectMoveAssignmentOperatorAppliedToValidObjectReturnsEqualObject) { + const Query query1 = TestFirestore()->Collection("foo").Limit(10); + const Query query2 = TestFirestore()->Collection("bar").Limit(20); + AggregateQuery aggregate_query = query1.Count(); + + EXPECT_EQ(aggregate_query.query(), query1); + EXPECT_TRUE(aggregate_query.is_valid()); + + AggregateQuery snapshot_move_dest = query2.Count(); + + EXPECT_EQ(snapshot_move_dest.query(), query2); + EXPECT_TRUE(snapshot_move_dest.is_valid()); + + snapshot_move_dest = std::move(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(snapshot_move_dest.query(), query1); + EXPECT_TRUE(snapshot_move_dest.is_valid()); +} + +TEST_F(AggregateQueryTest, + MoveAssignmentOperatorAppliedToSelfReturnsEqualObject) { + const Query query = TestFirestore()->Collection("foo").Limit(10); + + AggregateQuery aggregate_query = query.Count(); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); + + aggregate_query = std::move(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), query); + EXPECT_TRUE(aggregate_query.is_valid()); +} + +TEST_F( + AggregateQueryTest, + ValidObjectMoveAssignmentOperatorAppliedToDefaultObjectReturnsEqualObject) { + AggregateQuery aggregate_query; + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + const Query query = TestFirestore()->Collection("foo").Limit(10); + AggregateQuery snapshot_move_dest = query.Count(); + + EXPECT_EQ(snapshot_move_dest.query(), query); + EXPECT_TRUE(snapshot_move_dest.is_valid()); + + snapshot_move_dest = std::move(aggregate_query); + + EXPECT_EQ(aggregate_query.query(), Query()); + EXPECT_FALSE(aggregate_query.is_valid()); + + EXPECT_EQ(snapshot_move_dest.query(), Query()); + EXPECT_FALSE(snapshot_move_dest.is_valid()); +} + +TEST_F(AggregateQueryTest, TestHashCode) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}}); + Query query1 = + collection.Limit(2).OrderBy("sort", Query::Direction::kAscending); + Query query2 = + collection.Limit(2).OrderBy("sort", Query::Direction::kDescending); + EXPECT_NE(AggregateQueryHash(query1.Count()), + AggregateQueryHash(query2.Count())); + EXPECT_EQ(AggregateQueryHash(query1.Count()), + AggregateQueryHash(query1.Count())); +} + +} // namespace +} // namespace firestore +} // namespace firebase diff --git a/firestore/integration_test_internal/src/firestore_integration_test.cc b/firestore/integration_test_internal/src/firestore_integration_test.cc index ed6f2df358..df1854044f 100644 --- a/firestore/integration_test_internal/src/firestore_integration_test.cc +++ b/firestore/integration_test_internal/src/firestore_integration_test.cc @@ -255,6 +255,21 @@ QuerySnapshot FirestoreIntegrationTest::ReadDocuments( } } +AggregateQuerySnapshot FirestoreIntegrationTest::ReadAggregate( + const AggregateQuery& aggregate_query) const { + SCOPED_TRACE("FirestoreIntegrationTest::ReadAggregate()"); + Future future = + aggregate_query.Get(AggregateSource::kServer); + Stopwatch stopwatch; + const AggregateQuerySnapshot* result = Await(future); + stopwatch.stop(); + if (FailIfUnsuccessful("ReadAggregate", future, stopwatch)) { + return {}; + } else { + return *result; + } +} + void FirestoreIntegrationTest::DeleteDocument( DocumentReference reference) const { SCOPED_TRACE("FirestoreIntegrationTest::DeleteDocument(" + reference.path() + diff --git a/firestore/integration_test_internal/src/firestore_integration_test.h b/firestore/integration_test_internal/src/firestore_integration_test.h index af590fceea..249fbe3b0d 100644 --- a/firestore/integration_test_internal/src/firestore_integration_test.h +++ b/firestore/integration_test_internal/src/firestore_integration_test.h @@ -333,6 +333,10 @@ class FirestoreIntegrationTest : public testing::Test { // Read documents in the specified collection / query. QuerySnapshot ReadDocuments(const Query& reference) const; + // Read the aggregate. + AggregateQuerySnapshot ReadAggregate( + const AggregateQuery& aggregate_query) const; + // Delete the specified document. void DeleteDocument(DocumentReference reference) const; diff --git a/firestore/integration_test_internal/src/query_snapshot_test.cc b/firestore/integration_test_internal/src/query_snapshot_test.cc index 5c12235153..f1c93126b3 100644 --- a/firestore/integration_test_internal/src/query_snapshot_test.cc +++ b/firestore/integration_test_internal/src/query_snapshot_test.cc @@ -23,7 +23,6 @@ #include "firestore/src/android/query_snapshot_android.h" #endif // defined(__ANDROID__) -#include "gmock/gmock.h" #include "gtest/gtest.h" namespace firebase { @@ -49,94 +48,141 @@ TEST_F(QuerySnapshotTest, Assignment) { #endif // defined(__ANDROID__) -TEST_F(QuerySnapshotTest, Equality) { +TEST_F(QuerySnapshotTest, + IdenticalSnapshotFromCollectionQueriesWithLimitShouldBeEqual) { CollectionReference collection = Collection({{"a", {{"k", FieldValue::String("a")}}}, {"b", {{"k", FieldValue::String("b")}}}, {"c", {{"k", FieldValue::String("c")}}}}); QuerySnapshot snapshot1 = ReadDocuments(collection.Limit(2)); QuerySnapshot snapshot2 = ReadDocuments(collection.Limit(2)); - QuerySnapshot snapshot3 = ReadDocuments(collection.Limit(1)); - QuerySnapshot snapshot4 = ReadDocuments(collection); - QuerySnapshot snapshot5 = + + EXPECT_TRUE(snapshot1 == snapshot1); + EXPECT_TRUE(snapshot1 == snapshot2); + EXPECT_FALSE(snapshot1 != snapshot1); + EXPECT_FALSE(snapshot1 != snapshot2); +} + +TEST_F(QuerySnapshotTest, IdenticalDefaultSnapshotShouldBeEqual) { + QuerySnapshot snapshot1 = QuerySnapshot(); + QuerySnapshot snapshot2 = QuerySnapshot(); + + EXPECT_TRUE(snapshot1 == snapshot1); + EXPECT_TRUE(snapshot1 == snapshot2); + EXPECT_FALSE(snapshot1 != snapshot1); + EXPECT_FALSE(snapshot1 != snapshot2); +} + +TEST_F(QuerySnapshotTest, NonEquality) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + QuerySnapshot snapshot1 = ReadDocuments(collection.Limit(2)); + QuerySnapshot snapshot2 = ReadDocuments(collection.Limit(1)); + QuerySnapshot snapshot3 = ReadDocuments(collection); + QuerySnapshot snapshot4 = ReadDocuments(collection.OrderBy("k", Query::Direction::kAscending)); - QuerySnapshot snapshot6 = + QuerySnapshot snapshot5 = ReadDocuments(collection.OrderBy("k", Query::Direction::kDescending)); - QuerySnapshot snapshot7 = QuerySnapshot(); - QuerySnapshot snapshot8 = QuerySnapshot(); + QuerySnapshot snapshot6 = QuerySnapshot(); EXPECT_TRUE(snapshot1 == snapshot1); - EXPECT_TRUE(snapshot1 == snapshot2); + EXPECT_TRUE(snapshot2 == snapshot2); + EXPECT_TRUE(snapshot3 == snapshot3); + EXPECT_TRUE(snapshot4 == snapshot4); + EXPECT_TRUE(snapshot5 == snapshot5); + + EXPECT_TRUE(snapshot1 != snapshot2); EXPECT_TRUE(snapshot1 != snapshot3); EXPECT_TRUE(snapshot1 != snapshot4); EXPECT_TRUE(snapshot1 != snapshot5); EXPECT_TRUE(snapshot1 != snapshot6); + EXPECT_TRUE(snapshot2 != snapshot3); + EXPECT_TRUE(snapshot2 != snapshot4); + EXPECT_TRUE(snapshot2 != snapshot5); + EXPECT_TRUE(snapshot2 != snapshot6); EXPECT_TRUE(snapshot3 != snapshot4); EXPECT_TRUE(snapshot3 != snapshot5); EXPECT_TRUE(snapshot3 != snapshot6); + EXPECT_TRUE(snapshot4 != snapshot5); + EXPECT_TRUE(snapshot4 != snapshot6); EXPECT_TRUE(snapshot5 != snapshot6); - EXPECT_TRUE(snapshot1 != snapshot7); - EXPECT_TRUE(snapshot2 != snapshot7); - EXPECT_TRUE(snapshot3 != snapshot7); - EXPECT_TRUE(snapshot4 != snapshot7); - EXPECT_TRUE(snapshot5 != snapshot7); - EXPECT_TRUE(snapshot6 != snapshot7); - EXPECT_TRUE(snapshot7 == snapshot8); EXPECT_FALSE(snapshot1 != snapshot1); - EXPECT_FALSE(snapshot1 != snapshot2); + EXPECT_FALSE(snapshot2 != snapshot2); + EXPECT_FALSE(snapshot3 != snapshot3); + EXPECT_FALSE(snapshot4 != snapshot4); + EXPECT_FALSE(snapshot5 != snapshot5); + + EXPECT_FALSE(snapshot1 == snapshot2); EXPECT_FALSE(snapshot1 == snapshot3); EXPECT_FALSE(snapshot1 == snapshot4); EXPECT_FALSE(snapshot1 == snapshot5); EXPECT_FALSE(snapshot1 == snapshot6); + EXPECT_FALSE(snapshot2 == snapshot3); + EXPECT_FALSE(snapshot2 == snapshot4); + EXPECT_FALSE(snapshot2 == snapshot5); + EXPECT_FALSE(snapshot2 == snapshot6); EXPECT_FALSE(snapshot3 == snapshot4); EXPECT_FALSE(snapshot3 == snapshot5); EXPECT_FALSE(snapshot3 == snapshot6); + EXPECT_FALSE(snapshot4 == snapshot5); + EXPECT_FALSE(snapshot4 == snapshot6); EXPECT_FALSE(snapshot5 == snapshot6); - EXPECT_FALSE(snapshot1 == snapshot7); - EXPECT_FALSE(snapshot2 == snapshot7); - EXPECT_FALSE(snapshot3 == snapshot7); - EXPECT_FALSE(snapshot4 == snapshot7); - EXPECT_FALSE(snapshot5 == snapshot7); - EXPECT_FALSE(snapshot6 == snapshot7); - EXPECT_FALSE(snapshot7 != snapshot8); } -TEST_F(QuerySnapshotTest, TestHashCode) { +TEST_F(QuerySnapshotTest, + IdenticalSnapshotFromCollectionQueriesWithLimitShouldHaveSameHash) { CollectionReference collection = Collection({{"a", {{"k", FieldValue::String("a")}}}, {"b", {{"k", FieldValue::String("b")}}}, {"c", {{"k", FieldValue::String("c")}}}}); QuerySnapshot snapshot1 = ReadDocuments(collection.Limit(2)); QuerySnapshot snapshot2 = ReadDocuments(collection.Limit(2)); - QuerySnapshot snapshot3 = ReadDocuments(collection.Limit(1)); - QuerySnapshot snapshot4 = ReadDocuments(collection); - QuerySnapshot snapshot5 = - ReadDocuments(collection.OrderBy("k", Query::Direction::kAscending)); - QuerySnapshot snapshot6 = - ReadDocuments(collection.OrderBy("k", Query::Direction::kDescending)); - QuerySnapshot snapshot7 = QuerySnapshot(); - QuerySnapshot snapshot8 = QuerySnapshot(); + EXPECT_EQ(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot1)); + EXPECT_EQ(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot2)); +} + +TEST_F(QuerySnapshotTest, IdenticalDefaultSnapshotShouldHaveSameHash) { + QuerySnapshot snapshot1 = QuerySnapshot(); + QuerySnapshot snapshot2 = QuerySnapshot(); EXPECT_EQ(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot1)); EXPECT_EQ(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot2)); +} + +TEST_F(QuerySnapshotTest, TestHashCodeNonEquality) { + CollectionReference collection = + Collection({{"a", {{"k", FieldValue::String("a")}}}, + {"b", {{"k", FieldValue::String("b")}}}, + {"c", {{"k", FieldValue::String("c")}}}}); + QuerySnapshot snapshot1 = ReadDocuments(collection.Limit(2)); + QuerySnapshot snapshot2 = ReadDocuments(collection.Limit(1)); + QuerySnapshot snapshot3 = ReadDocuments(collection); + QuerySnapshot snapshot4 = + ReadDocuments(collection.OrderBy("k", Query::Direction::kAscending)); + QuerySnapshot snapshot5 = + ReadDocuments(collection.OrderBy("k", Query::Direction::kDescending)); + QuerySnapshot snapshot6 = QuerySnapshot(); + + EXPECT_NE(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot2)); EXPECT_NE(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot3)); EXPECT_NE(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot4)); EXPECT_NE(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot5)); EXPECT_NE(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot6)); + EXPECT_NE(QuerySnapshotHash(snapshot2), QuerySnapshotHash(snapshot3)); + EXPECT_NE(QuerySnapshotHash(snapshot2), QuerySnapshotHash(snapshot4)); + EXPECT_NE(QuerySnapshotHash(snapshot2), QuerySnapshotHash(snapshot5)); + EXPECT_NE(QuerySnapshotHash(snapshot2), QuerySnapshotHash(snapshot6)); EXPECT_NE(QuerySnapshotHash(snapshot3), QuerySnapshotHash(snapshot4)); EXPECT_NE(QuerySnapshotHash(snapshot3), QuerySnapshotHash(snapshot5)); EXPECT_NE(QuerySnapshotHash(snapshot3), QuerySnapshotHash(snapshot6)); + EXPECT_NE(QuerySnapshotHash(snapshot4), QuerySnapshotHash(snapshot5)); + EXPECT_NE(QuerySnapshotHash(snapshot4), QuerySnapshotHash(snapshot6)); EXPECT_NE(QuerySnapshotHash(snapshot5), QuerySnapshotHash(snapshot6)); - EXPECT_NE(QuerySnapshotHash(snapshot1), QuerySnapshotHash(snapshot7)); - EXPECT_NE(QuerySnapshotHash(snapshot2), QuerySnapshotHash(snapshot7)); - EXPECT_NE(QuerySnapshotHash(snapshot3), QuerySnapshotHash(snapshot7)); - EXPECT_NE(QuerySnapshotHash(snapshot4), QuerySnapshotHash(snapshot7)); - EXPECT_NE(QuerySnapshotHash(snapshot5), QuerySnapshotHash(snapshot7)); - EXPECT_NE(QuerySnapshotHash(snapshot6), QuerySnapshotHash(snapshot7)); - EXPECT_EQ(QuerySnapshotHash(snapshot7), QuerySnapshotHash(snapshot8)); } } // namespace firestore diff --git a/firestore/integration_test_internal/src/query_test.cc b/firestore/integration_test_internal/src/query_test.cc index f1702f6702..21949e72ca 100644 --- a/firestore/integration_test_internal/src/query_test.cc +++ b/firestore/integration_test_internal/src/query_test.cc @@ -236,11 +236,17 @@ TEST_F(QueryTest, TestKeyOrderIsDescendingForDescendingInequality) { {"e", {{"foo", FieldValue::Double(21.0)}}}, {"f", {{"foo", FieldValue::Integer(66)}}}, {"g", {{"foo", FieldValue::Double(66.0)}}}}); - QuerySnapshot snapshot = ReadDocuments( + const Query& query = collection.WhereGreaterThan("foo", FieldValue::Integer(21)) - .OrderBy(FieldPath({"foo"}), Query::Direction::kDescending)); + .OrderBy(FieldPath({"foo"}), Query::Direction::kDescending); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({"g", "f", "c", "b", "a"}), QuerySnapshotToIds(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(5, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestUnaryFilterQueries) { @@ -250,12 +256,17 @@ TEST_F(QueryTest, TestUnaryFilterQueries) { {"c", {{"null", FieldValue::Boolean(false)}, {"nan", FieldValue::Double(NAN)}}}}); - QuerySnapshot snapshot = - ReadDocuments(collection.WhereEqualTo("null", FieldValue::Null()) - .WhereEqualTo("nan", FieldValue::Double(NAN))); + const Query& query = collection.WhereEqualTo("null", FieldValue::Null()) + .WhereEqualTo("nan", FieldValue::Double(NAN)); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({{{"null", FieldValue::Null()}, {"nan", FieldValue::Double(NAN)}}}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(1, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueryWithFieldPaths) { @@ -263,21 +274,33 @@ TEST_F(QueryTest, TestQueryWithFieldPaths) { Collection({{"a", {{"a", FieldValue::Integer(1)}}}, {"b", {{"a", FieldValue::Integer(2)}}}, {"c", {{"a", FieldValue::Integer(3)}}}}); - QuerySnapshot snapshot = ReadDocuments( + const Query& query = collection.WhereLessThan(FieldPath({"a"}), FieldValue::Integer(3)) - .OrderBy(FieldPath({"a"}), Query::Direction::kDescending)); + .OrderBy(FieldPath({"a"}), Query::Direction::kDescending); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({"b", "a"}), QuerySnapshotToIds(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(2, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestFilterOnInfinity) { CollectionReference collection = Collection({{"a", {{"inf", FieldValue::Double(INFINITY)}}}, {"b", {{"inf", FieldValue::Double(-INFINITY)}}}}); - QuerySnapshot snapshot = ReadDocuments( - collection.WhereEqualTo("inf", FieldValue::Double(INFINITY))); + const Query& query = + collection.WhereEqualTo("inf", FieldValue::Double(INFINITY)); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ( std::vector({{{"inf", FieldValue::Double(INFINITY)}}}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(1, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestWillNotGetMetadataOnlyUpdates) { @@ -448,18 +471,30 @@ TEST_F(QueryTest, TestCanQueryByDocumentId) { {"bb", {{"key", FieldValue::String("bb")}}}}); // Query by Document Id. - QuerySnapshot snapshot1 = ReadDocuments(collection.WhereEqualTo( - FieldPath::DocumentId(), FieldValue::String("ab"))); + const Query& query1 = collection.WhereEqualTo(FieldPath::DocumentId(), + FieldValue::String("ab")); + QuerySnapshot snapshot1 = ReadDocuments(query1); EXPECT_EQ(std::vector({"ab"}), QuerySnapshotToIds(snapshot1)); + const AggregateQuery& aggregate_query1 = query1.Count(); + AggregateQuerySnapshot aggregate_snapshot1 = ReadAggregate(aggregate_query1); + EXPECT_EQ(1, aggregate_snapshot1.count()); + EXPECT_EQ(aggregate_query1, aggregate_snapshot1.query()); + // Query by Document Ids. - QuerySnapshot snapshot2 = ReadDocuments( + const Query& query2 = collection .WhereGreaterThan(FieldPath::DocumentId(), FieldValue::String("aa")) .WhereLessThanOrEqualTo(FieldPath::DocumentId(), - FieldValue::String("ba"))); + FieldValue::String("ba")); + QuerySnapshot snapshot2 = ReadDocuments(query2); EXPECT_EQ(std::vector({"ab", "ba"}), QuerySnapshotToIds(snapshot2)); + + const AggregateQuery& aggregate_query2 = query2.Count(); + AggregateQuerySnapshot aggregate_snapshot2 = ReadAggregate(aggregate_query2); + EXPECT_EQ(2, aggregate_snapshot2.count()); + EXPECT_EQ(aggregate_query2, aggregate_snapshot2.query()); } TEST_F(QueryTest, TestCanQueryByDocumentIdUsingRefs) { @@ -470,21 +505,33 @@ TEST_F(QueryTest, TestCanQueryByDocumentIdUsingRefs) { {"bb", {{"key", FieldValue::String("bb")}}}}); // Query by Document Id. - QuerySnapshot snapshot1 = ReadDocuments(collection.WhereEqualTo( - FieldPath::DocumentId(), - FieldValue::Reference(collection.Document("ab")))); + const Query& query1 = + collection.WhereEqualTo(FieldPath::DocumentId(), + FieldValue::Reference(collection.Document("ab"))); + QuerySnapshot snapshot1 = ReadDocuments(query1); EXPECT_EQ(std::vector({"ab"}), QuerySnapshotToIds(snapshot1)); + const AggregateQuery& aggregate_query1 = query1.Count(); + AggregateQuerySnapshot aggregate_snapshot1 = ReadAggregate(aggregate_query1); + EXPECT_EQ(1, aggregate_snapshot1.count()); + EXPECT_EQ(aggregate_query1, aggregate_snapshot1.query()); + // Query by Document Ids. - QuerySnapshot snapshot2 = ReadDocuments( + const Query& query2 = collection .WhereGreaterThan(FieldPath::DocumentId(), FieldValue::Reference(collection.Document("aa"))) .WhereLessThanOrEqualTo( FieldPath::DocumentId(), - FieldValue::Reference(collection.Document("ba")))); + FieldValue::Reference(collection.Document("ba"))); + QuerySnapshot snapshot2 = ReadDocuments(query2); EXPECT_EQ(std::vector({"ab", "ba"}), QuerySnapshotToIds(snapshot2)); + + const AggregateQuery& aggregate_query2 = query2.Count(); + AggregateQuerySnapshot aggregate_snapshot2 = ReadAggregate(aggregate_query2); + EXPECT_EQ(2, aggregate_snapshot2.count()); + EXPECT_EQ(aggregate_query2, aggregate_snapshot2.query()); } TEST_F(QueryTest, TestCanQueryWithAndWithoutDocumentKey) { @@ -520,10 +567,16 @@ TEST_F(QueryTest, TestQueriesCanUseNotEqualFilters) { CollectionReference collection = Collection(docs); // Search for zips not matching 98101. - QuerySnapshot snapshot = ReadDocuments( - collection.WhereNotEqualTo("zip", FieldValue::Integer(98101))); + const Query& query = + collection.WhereNotEqualTo("zip", FieldValue::Integer(98101)); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"c", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(7, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithObject) { @@ -548,10 +601,16 @@ TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithObject) { }; CollectionReference collection = Collection(docs); - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotEqualTo( - "zip", FieldValue::Map({{"code", FieldValue::Integer(500)}}))); + const Query& query = collection.WhereNotEqualTo( + "zip", FieldValue::Map({{"code", FieldValue::Integer(500)}})); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"h", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(7, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithNull) { @@ -577,10 +636,16 @@ TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithNull) { CollectionReference collection = Collection(docs); // With Null. - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotEqualTo( - "zip", FieldValue::Map({{"code", FieldValue::Null()}}))); + const Query& query = collection.WhereNotEqualTo( + "zip", FieldValue::Map({{"code", FieldValue::Null()}})); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(8, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithNan) { @@ -605,10 +670,16 @@ TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithNan) { }; CollectionReference collection = Collection(docs); - QuerySnapshot snapshot = - ReadDocuments(collection.WhereNotEqualTo("zip", FieldValue::Double(NAN))); + const Query& query = + collection.WhereNotEqualTo("zip", FieldValue::Double(NAN)); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"a", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(7, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithDocIds) { @@ -620,10 +691,16 @@ TEST_F(QueryTest, TestQueriesCanUseNotEqualFiltersWithDocIds) { CollectionReference collection = Collection({{"aa", doc_a}, {"ab", doc_b}, {"ba", doc_c}, {"bb", doc_d}}); - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotEqualTo( - FieldPath::DocumentId(), FieldValue::String("aa"))); + const Query& query = collection.WhereNotEqualTo(FieldPath::DocumentId(), + FieldValue::String("aa")); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({doc_b, doc_c, doc_d}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(3, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseArrayContainsFilters) { @@ -643,8 +720,9 @@ TEST_F(QueryTest, TestQueriesCanUseArrayContainsFilters) { {{"array", FieldValue::Array({FieldValue::Integer(42)})}, {"array2", FieldValue::Array({FieldValue::String("bingo")})}}}}); // Search for 42 - QuerySnapshot snapshot = ReadDocuments( - collection.WhereArrayContains("array", FieldValue::Integer(42))); + const Query& query = + collection.WhereArrayContains("array", FieldValue::Integer(42)); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ( std::vector( {{{"array", FieldValue::Array({FieldValue::Integer(42)})}}, @@ -655,6 +733,11 @@ TEST_F(QueryTest, TestQueriesCanUseArrayContainsFilters) { {"array2", FieldValue::Array({FieldValue::String("bingo")})}}}), QuerySnapshotToValues(snapshot)); + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(3, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); + // NOTE: The backend doesn't currently support null, NaN, objects, or arrays, // so there isn't much of anything else interesting to test. } @@ -675,10 +758,11 @@ TEST_F(QueryTest, TestQueriesCanUseInFilters) { {{"zip", FieldValue::Array({FieldValue::Integer(98101), FieldValue::Integer(98102)})}}}}); // Search for zips matching 98101, 98103, or [98101, 98102]. - QuerySnapshot snapshot = ReadDocuments(collection.WhereIn( + const Query& query1 = collection.WhereIn( "zip", {FieldValue::Integer(98101), FieldValue::Integer(98103), FieldValue::Array( - {FieldValue::Integer(98101), FieldValue::Integer(98102)})})); + {FieldValue::Integer(98101), FieldValue::Integer(98102)})}); + QuerySnapshot snapshot = ReadDocuments(query1); EXPECT_EQ(std::vector( {{{"zip", FieldValue::Integer(98101)}}, {{"zip", FieldValue::Integer(98103)}}, @@ -686,13 +770,24 @@ TEST_F(QueryTest, TestQueriesCanUseInFilters) { FieldValue::Integer(98102)})}}}), QuerySnapshotToValues(snapshot)); + const AggregateQuery& aggregate_query1 = query1.Count(); + AggregateQuerySnapshot aggregate_snapshot1 = ReadAggregate(aggregate_query1); + EXPECT_EQ(3, aggregate_snapshot1.count()); + EXPECT_EQ(aggregate_query1, aggregate_snapshot1.query()); + // With objects. - snapshot = ReadDocuments(collection.WhereIn( - "zip", {FieldValue::Map({{"code", FieldValue::Integer(500)}})})); + const Query& query2 = collection.WhereIn( + "zip", {FieldValue::Map({{"code", FieldValue::Integer(500)}})}); + snapshot = ReadDocuments(query2); EXPECT_EQ( std::vector( {{{"zip", FieldValue::Map({{"code", FieldValue::Integer(500)}})}}}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query2 = query2.Count(); + AggregateQuerySnapshot aggregate_snapshot2 = ReadAggregate(aggregate_query2); + EXPECT_EQ(1, aggregate_snapshot2.count()); + EXPECT_EQ(aggregate_query2, aggregate_snapshot2.query()); } TEST_F(QueryTest, TestQueriesCanUseInFiltersWithDocIds) { @@ -702,12 +797,18 @@ TEST_F(QueryTest, TestQueriesCanUseInFiltersWithDocIds) { {"ba", {{"key", FieldValue::String("ba")}}}, {"bb", {{"key", FieldValue::String("bb")}}}}); - QuerySnapshot snapshot = ReadDocuments( + const Query& query = collection.WhereIn(FieldPath::DocumentId(), - {FieldValue::String("aa"), FieldValue::String("ab")})); + {FieldValue::String("aa"), FieldValue::String("ab")}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({{{"key", FieldValue::String("aa")}}, {{"key", FieldValue::String("ab")}}}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(2, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotInFilters) { @@ -733,12 +834,18 @@ TEST_F(QueryTest, TestQueriesCanUseNotInFilters) { CollectionReference collection = Collection(docs); // Search for zips not matching 98101, 98103 or [98101, 98102]. - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotIn( + const Query& query = collection.WhereNotIn( "zip", {{FieldValue::Integer(98101), FieldValue::Integer(98103), FieldValue::Array({{FieldValue::Integer(98101), - FieldValue::Integer(98102)}})}})); + FieldValue::Integer(98102)}})}}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"c", "d", "f", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(5, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithObject) { @@ -763,10 +870,16 @@ TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithObject) { }; CollectionReference collection = Collection(docs); - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotIn( - "zip", {{FieldValue::Map({{"code", FieldValue::Integer(500)}})}})); + const Query& query = collection.WhereNotIn( + "zip", {{FieldValue::Map({{"code", FieldValue::Integer(500)}})}}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"h", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(7, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithNull) { @@ -792,9 +905,14 @@ TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithNull) { CollectionReference collection = Collection(docs); // With Null, this leads to no result. - QuerySnapshot snapshot = - ReadDocuments(collection.WhereNotIn("zip", {{FieldValue::Null()}})); + const Query& query = collection.WhereNotIn("zip", {{FieldValue::Null()}}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), IsEmpty()); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(0, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithNan) { @@ -820,10 +938,18 @@ TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithNan) { CollectionReference collection = Collection(docs); // With NAN. - QuerySnapshot snapshot = - ReadDocuments(collection.WhereNotIn("zip", {{FieldValue::Double(NAN)}})); + const Query& query = + collection.WhereNotIn("zip", {{FieldValue::Double(NAN)}}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"a", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + // TODO(tomandersen) WhereNotIn does not filter NaN on aggregates. Fix to be + // discussed. EXPECT_EQ(7, aggregate_snapshot.count()); + EXPECT_EQ(8, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithNanAndNumber) { @@ -848,10 +974,18 @@ TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithNanAndNumber) { }; CollectionReference collection = Collection(docs); - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotIn( - "zip", {{FieldValue::Double(NAN), FieldValue::Integer(98101)}})); + const Query& query = collection.WhereNotIn( + "zip", {{FieldValue::Double(NAN), FieldValue::Integer(98101)}}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_THAT(QuerySnapshotToValues(snapshot), ElementsAreArray(AllDocsExcept(docs, {"a", "c", "i", "j"}))); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + // TODO(tomandersen) WhereNotIn does not filter NaN on aggregates. Fix to be + // discussed. EXPECT_EQ(6, aggregate_snapshot.count()); + EXPECT_EQ(7, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithDocIds) { @@ -863,11 +997,17 @@ TEST_F(QueryTest, TestQueriesCanUseNotInFiltersWithDocIds) { CollectionReference collection = Collection({{"aa", doc_a}, {"ab", doc_b}, {"ba", doc_c}, {"bb", doc_d}}); - QuerySnapshot snapshot = ReadDocuments(collection.WhereNotIn( + const Query& query = collection.WhereNotIn( FieldPath::DocumentId(), - {{FieldValue::String("aa"), FieldValue::String("ab")}})); + {{FieldValue::String("aa"), FieldValue::String("ab")}}); + QuerySnapshot snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({doc_c, doc_d}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(2, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, TestQueriesCanUseArrayContainsAnyFilters) { @@ -893,8 +1033,9 @@ TEST_F(QueryTest, TestQueriesCanUseArrayContainsAnyFilters) { {"g", {{"array", FieldValue::Integer(42)}}}}); // Search for "array" to contain [42, 43] - QuerySnapshot snapshot = ReadDocuments(collection.WhereArrayContainsAny( - "array", {FieldValue::Integer(42), FieldValue::Integer(43)})); + const Query& query1 = collection.WhereArrayContainsAny( + "array", {FieldValue::Integer(42), FieldValue::Integer(43)}); + QuerySnapshot snapshot = ReadDocuments(query1); EXPECT_EQ(std::vector( {{{"array", FieldValue::Array({FieldValue::Integer(42)})}}, {{"array", FieldValue::Array({FieldValue::String("a"), @@ -905,13 +1046,24 @@ TEST_F(QueryTest, TestQueriesCanUseArrayContainsAnyFilters) { {{"array", FieldValue::Array({FieldValue::Integer(43)})}}}), QuerySnapshotToValues(snapshot)); + const AggregateQuery& aggregate_query1 = query1.Count(); + AggregateQuerySnapshot aggregate_snapshot1 = ReadAggregate(aggregate_query1); + EXPECT_EQ(4, aggregate_snapshot1.count()); + EXPECT_EQ(aggregate_query1, aggregate_snapshot1.query()); + // With objects - snapshot = ReadDocuments(collection.WhereArrayContainsAny( - "array", {FieldValue::Map({{"a", FieldValue::Integer(42)}})})); + const Query& query2 = collection.WhereArrayContainsAny( + "array", {FieldValue::Map({{"a", FieldValue::Integer(42)}})}); + snapshot = ReadDocuments(query2); EXPECT_EQ(std::vector( {{{"array", FieldValue::Array({FieldValue::Map( {{"a", FieldValue::Integer(42)}})})}}}), QuerySnapshotToValues(snapshot)); + + const AggregateQuery& aggregate_query2 = query2.Count(); + AggregateQuerySnapshot aggregate_snapshot2 = ReadAggregate(aggregate_query2); + EXPECT_EQ(1, aggregate_snapshot2.count()); + EXPECT_EQ(aggregate_query2, aggregate_snapshot2.query()); } TEST_F(QueryTest, TestCollectionGroupQueries) { @@ -940,11 +1092,16 @@ TEST_F(QueryTest, TestCollectionGroupQueries) { } Await(batch.Commit()); - QuerySnapshot query_snapshot = - ReadDocuments(db->CollectionGroup(collection_group)); + const Query& query = db->CollectionGroup(collection_group); + QuerySnapshot query_snapshot = ReadDocuments(query); EXPECT_EQ(std::vector( {"cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5"}), QuerySnapshotToIds(query_snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(5, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, @@ -970,13 +1127,18 @@ TEST_F(QueryTest, } Await(batch.Commit()); - QuerySnapshot query_snapshot = - ReadDocuments(db->CollectionGroup(collection_group) - .OrderBy(FieldPath::DocumentId()) - .StartAt({FieldValue::String("a/b")}) - .EndAt({FieldValue::String("a/b0")})); + const Query& query = db->CollectionGroup(collection_group) + .OrderBy(FieldPath::DocumentId()) + .StartAt({FieldValue::String("a/b")}) + .EndAt({FieldValue::String("a/b0")}); + QuerySnapshot query_snapshot = ReadDocuments(query); EXPECT_EQ(std::vector({"cg-doc2", "cg-doc3", "cg-doc4"}), QuerySnapshotToIds(query_snapshot)); + + const AggregateQuery& aggregate_query = query.Count(); + AggregateQuerySnapshot aggregate_snapshot = ReadAggregate(aggregate_query); + EXPECT_EQ(3, aggregate_snapshot.count()); + EXPECT_EQ(aggregate_query, aggregate_snapshot.query()); } TEST_F(QueryTest, @@ -1002,23 +1164,35 @@ TEST_F(QueryTest, } Await(batch.Commit()); - QuerySnapshot query_snapshot = - ReadDocuments(db->CollectionGroup(collection_group) - .WhereGreaterThanOrEqualTo(FieldPath::DocumentId(), - FieldValue::String("a/b")) - .WhereLessThanOrEqualTo(FieldPath::DocumentId(), - FieldValue::String("a/b0"))); + const Query& query1 = + db->CollectionGroup(collection_group) + .WhereGreaterThanOrEqualTo(FieldPath::DocumentId(), + FieldValue::String("a/b")) + .WhereLessThanOrEqualTo(FieldPath::DocumentId(), + FieldValue::String("a/b0")); + QuerySnapshot query_snapshot = ReadDocuments(query1); EXPECT_EQ(std::vector({"cg-doc2", "cg-doc3", "cg-doc4"}), QuerySnapshotToIds(query_snapshot)); - query_snapshot = ReadDocuments( + const AggregateQuery& aggregate_query1 = query1.Count(); + AggregateQuerySnapshot aggregate_snapshot1 = ReadAggregate(aggregate_query1); + EXPECT_EQ(3, aggregate_snapshot1.count()); + EXPECT_EQ(aggregate_query1, aggregate_snapshot1.query()); + + const Query& query2 = db->CollectionGroup(collection_group) .WhereGreaterThan(FieldPath::DocumentId(), FieldValue::String("a/b")) .WhereLessThan( FieldPath::DocumentId(), - FieldValue::String("a/b/" + collection_group + "/cg-doc3"))); + FieldValue::String("a/b/" + collection_group + "/cg-doc3")); + query_snapshot = ReadDocuments(query2); EXPECT_EQ(std::vector({"cg-doc2"}), QuerySnapshotToIds(query_snapshot)); + + const AggregateQuery& aggregate_query2 = query2.Count(); + AggregateQuerySnapshot aggregate_snapshot2 = ReadAggregate(aggregate_query2); + EXPECT_EQ(1, aggregate_snapshot2.count()); + EXPECT_EQ(aggregate_query2, aggregate_snapshot2.query()); } #if defined(__ANDROID__) diff --git a/firestore/src/include/firebase/firestore/aggregate_query_snapshot.h b/firestore/src/include/firebase/firestore/aggregate_query_snapshot.h index 103d9c431d..abeb0a2ccb 100644 --- a/firestore/src/include/firebase/firestore/aggregate_query_snapshot.h +++ b/firestore/src/include/firebase/firestore/aggregate_query_snapshot.h @@ -119,7 +119,7 @@ class AggregateQuerySnapshot { * @return true if this `AggregateQuery` is valid, false if this * `AggregateQuerySnapshot` is invalid. */ - bool is_valid() const; + bool is_valid() const { return internal_ != nullptr; } private: std::size_t Hash() const; @@ -129,6 +129,7 @@ class AggregateQuerySnapshot { friend std::size_t AggregateQuerySnapshotHash( const AggregateQuerySnapshot& snapshot); friend struct ConverterImpl; + friend class AggregateQuerySnapshotTest; template friend struct CleanupFn; diff --git a/firestore/src/main/aggregate_query_main.h b/firestore/src/main/aggregate_query_main.h index defe03a06f..84f62dee67 100644 --- a/firestore/src/main/aggregate_query_main.h +++ b/firestore/src/main/aggregate_query_main.h @@ -50,6 +50,8 @@ class AggregateQueryInternal { kCount, }; + friend class AggregateQuerySnapshotTest; + api::AggregateQuery aggregate_query_; PromiseFactory promise_factory_; }; diff --git a/firestore/src/main/aggregate_query_snapshot_main.h b/firestore/src/main/aggregate_query_snapshot_main.h index 336903d1ec..222c6b4e39 100644 --- a/firestore/src/main/aggregate_query_snapshot_main.h +++ b/firestore/src/main/aggregate_query_snapshot_main.h @@ -51,7 +51,7 @@ class AggregateQuerySnapshotInternal { private: api::AggregateQuery aggregate_query_; - int64_t count_result_; + int64_t count_result_ = 0; }; inline bool operator!=(const AggregateQuerySnapshotInternal& lhs,