diff options
Diffstat (limited to 'Firestore/core/test')
16 files changed, 879 insertions, 36 deletions
diff --git a/Firestore/core/test/firebase/firestore/auth/CMakeLists.txt b/Firestore/core/test/firebase/firestore/auth/CMakeLists.txt new file mode 100644 index 0000000..f470bd7 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/auth/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright 2018 Google +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cc_test( + firebase_firestore_auth_test + SOURCES + credentials_provider_test.cc + empty_credentials_provider_test.cc + token_test.cc + user_test.cc + DEPENDS + firebase_firestore_auth +) + +if(APPLE) + cc_test( + firebase_firestore_auth_apple_test + SOURCES + firebase_credentials_provider_test.mm + DEPENDS + firebase_firestore_auth_apple + ) +endif(APPLE) diff --git a/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc b/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc new file mode 100644 index 0000000..1748422 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace auth { + +#define UNUSED(x) (void)(x) + +TEST(CredentialsProvider, Typedef) { + TokenListener token_listener = [](const Token& token, + const absl::string_view error) { + UNUSED(token); + UNUSED(error); + }; + EXPECT_NE(nullptr, token_listener); + EXPECT_TRUE(token_listener); + + token_listener = nullptr; + EXPECT_EQ(nullptr, token_listener); + EXPECT_FALSE(token_listener); + + UserChangeListener user_change_listener = [](const User& user) { + UNUSED(user); + }; + EXPECT_NE(nullptr, user_change_listener); + EXPECT_TRUE(user_change_listener); + + user_change_listener = nullptr; + EXPECT_EQ(nullptr, user_change_listener); + EXPECT_FALSE(user_change_listener); +} + +} // namespace auth +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc b/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc new file mode 100644 index 0000000..123f952 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace auth { + +TEST(EmptyCredentialsProvider, GetToken) { + EmptyCredentialsProvider credentials_provider; + credentials_provider.GetToken( + /*force_refresh=*/true, + [](const Token& token, const absl::string_view error) { + EXPECT_EQ("", token.token()); + const User& user = token.user(); + EXPECT_EQ("", user.uid()); + EXPECT_FALSE(user.is_authenticated()); + EXPECT_EQ("", error); + }); +} + +TEST(EmptyCredentialsProvider, SetListener) { + EmptyCredentialsProvider credentials_provider; + credentials_provider.SetUserChangeListener([](const User& user) { + EXPECT_EQ("", user.uid()); + EXPECT_FALSE(user.is_authenticated()); + }); + + credentials_provider.SetUserChangeListener(nullptr); +} + +} // namespace auth +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm b/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm new file mode 100644 index 0000000..8d2b361 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm @@ -0,0 +1,98 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h" + +#import <FirebaseCore/FIRApp.h> +#import <FirebaseCore/FIRAppInternal.h> +#import <FirebaseCore/FIROptionsInternal.h> + +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace auth { + +// TODO(zxu123): Make this an integration test and get infos from environment. +// Set a .plist file here to enable the test-case. +static NSString* const kPlist = @""; + +class FirebaseCredentialsProviderTest : public ::testing::Test { + protected: + void SetUp() override { + app_ready_ = false; + if (![kPlist hasSuffix:@".plist"]) { + return; + } + + static dispatch_once_t once_token; + dispatch_once(&once_token, ^{ + FIROptions* options = [[FIROptions alloc] initWithContentsOfFile:kPlist]; + [FIRApp configureWithOptions:options]; + }); + + // Set getUID implementation. + FIRApp* default_app = [FIRApp defaultApp]; + default_app.getUIDImplementation = ^NSString* { + return @"I'm a fake uid."; + }; + app_ready_ = true; + } + + bool app_ready_; +}; + +// Set kPlist above before enable. +TEST_F(FirebaseCredentialsProviderTest, GetToken) { + if (!app_ready_) { + return; + } + + FirebaseCredentialsProvider credentials_provider([FIRApp defaultApp]); + credentials_provider.GetToken( + /*force_refresh=*/true, + [](const Token& token, const absl::string_view error) { + EXPECT_EQ("", token.token()); + const User& user = token.user(); + EXPECT_EQ("I'm a fake uid.", user.uid()); + EXPECT_TRUE(user.is_authenticated()); + EXPECT_EQ("", error) << error; + }); +} + +// Set kPlist above before enable. +TEST_F(FirebaseCredentialsProviderTest, SetListener) { + if (!app_ready_) { + return; + } + + FirebaseCredentialsProvider credentials_provider([FIRApp defaultApp]); + credentials_provider.SetUserChangeListener([](const User& user) { + EXPECT_EQ("I'm a fake uid.", user.uid()); + EXPECT_TRUE(user.is_authenticated()); + }); + + // TODO(wilhuff): We should wait for the above expectations to actually happen + // before continuing. + + credentials_provider.SetUserChangeListener(nullptr); +} + +} // namespace auth +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/auth/token_test.cc b/Firestore/core/test/firebase/firestore/auth/token_test.cc new file mode 100644 index 0000000..a0f2c48 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/auth/token_test.cc @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/auth/token.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace auth { + +TEST(Token, Getter) { + Token token("token", User("abc")); + EXPECT_EQ("token", token.token()); + EXPECT_EQ(User("abc"), token.user()); +} + +} // namespace auth +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/auth/user_test.cc b/Firestore/core/test/firebase/firestore/auth/user_test.cc new file mode 100644 index 0000000..a9f764d --- /dev/null +++ b/Firestore/core/test/firebase/firestore/auth/user_test.cc @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/auth/user.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace auth { + +TEST(User, Getter) { + User anonymous; + EXPECT_EQ("", anonymous.uid()); + EXPECT_FALSE(anonymous.is_authenticated()); + + User signin("abc"); + EXPECT_EQ("abc", signin.uid()); + EXPECT_TRUE(signin.is_authenticated()); + + User copy; + copy = signin; + EXPECT_EQ(signin, copy); +} + +TEST(User, Unauthenticated) { + User unauthenticated = User::Unauthenticated(); + EXPECT_EQ("", unauthenticated.uid()); + EXPECT_FALSE(unauthenticated.is_authenticated()); +} + +TEST(User, Comparison) { + EXPECT_EQ(User(), User()); + EXPECT_EQ(User("abc"), User("abc")); + EXPECT_NE(User(), User("abc")); + EXPECT_NE(User("abc"), User("xyz")); +} + +} // namespace auth +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt index 63ed813..0d581bc 100644 --- a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt @@ -16,10 +16,15 @@ cc_test( firebase_firestore_model_test SOURCES database_id_test.cc + document_key_test.cc + document_test.cc field_path_test.cc field_value_test.cc - timestamp_test.cc + maybe_document_test.cc + no_document_test.cc resource_path_test.cc + snapshot_version_test.cc + timestamp_test.cc DEPENDS firebase_firestore_model ) diff --git a/Firestore/core/test/firebase/firestore/model/document_key_test.cc b/Firestore/core/test/firebase/firestore/model/document_key_test.cc new file mode 100644 index 0000000..0e0df2d --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/document_key_test.cc @@ -0,0 +1,153 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <initializer_list> +#include <string> +#include <utility> +#include <vector> + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +TEST(DocumentKey, Constructor_Empty) { + const DocumentKey default_key; + EXPECT_TRUE(default_key.path().empty()); + + const auto& empty_key = DocumentKey::Empty(); + const auto& another_empty_key = DocumentKey::Empty(); + EXPECT_EQ(default_key, empty_key); + EXPECT_EQ(empty_key, another_empty_key); + EXPECT_EQ(&empty_key, &another_empty_key); +} + +TEST(DocumentKey, Constructor_FromPath) { + ResourcePath path{"rooms", "firestore", "messages", "1"}; + const DocumentKey key_from_path_copy{path}; + // path shouldn't have been moved from. + EXPECT_FALSE(path.empty()); + EXPECT_EQ(key_from_path_copy.path(), path); + + const DocumentKey key_from_moved_path{std::move(path)}; + EXPECT_TRUE(path.empty()); + EXPECT_FALSE(key_from_moved_path.path().empty()); + EXPECT_EQ(key_from_path_copy.path(), key_from_moved_path.path()); +} + +TEST(DocumentKey, CopyAndMove) { + DocumentKey key({"rooms", "firestore", "messages", "1"}); + const std::string path_string = "rooms/firestore/messages/1"; + EXPECT_EQ(path_string, key.path().CanonicalString()); + + DocumentKey copied = key; + EXPECT_EQ(path_string, copied.path().CanonicalString()); + EXPECT_EQ(key, copied); + + const DocumentKey moved = std::move(key); + EXPECT_EQ(path_string, moved.path().CanonicalString()); + EXPECT_NE(key, moved); + EXPECT_TRUE(key.path().empty()); + + // Reassignment. + + key = copied; + EXPECT_EQ(copied, key); + EXPECT_EQ(path_string, key.path().CanonicalString()); + + key = {}; + EXPECT_TRUE(key.path().empty()); + key = std::move(copied); + EXPECT_NE(copied, key); + EXPECT_TRUE(copied.path().empty()); + EXPECT_EQ(path_string, key.path().CanonicalString()); +} + +TEST(DocumentKey, Constructor_StaticFactory) { + const auto key_from_segments = + DocumentKey::FromSegments({"rooms", "firestore", "messages", "1"}); + const std::string path_string = "rooms/firestore/messages/1"; + const auto key_from_string = DocumentKey::FromPathString(path_string); + EXPECT_EQ(path_string, key_from_string.path().CanonicalString()); + EXPECT_EQ(path_string, key_from_segments.path().CanonicalString()); + EXPECT_EQ(key_from_segments, key_from_string); + + const auto from_empty_path = DocumentKey::FromPathString(""); + EXPECT_EQ(from_empty_path, DocumentKey{}); +} + +TEST(DocumentKey, Constructor_BadArguments) { + ASSERT_ANY_THROW(DocumentKey(ResourcePath{"foo"})); + ASSERT_ANY_THROW(DocumentKey(ResourcePath{"foo", "bar", "baz"})); + + ASSERT_ANY_THROW(DocumentKey::FromSegments({"foo"})); + ASSERT_ANY_THROW(DocumentKey::FromSegments({"foo", "bar", "baz"})); + + ASSERT_ANY_THROW(DocumentKey::FromPathString("invalid")); + ASSERT_ANY_THROW(DocumentKey::FromPathString("invalid//string")); + ASSERT_ANY_THROW(DocumentKey::FromPathString("invalid/key/path")); +} + +TEST(DocumentKey, IsDocumentKey) { + EXPECT_TRUE(DocumentKey::IsDocumentKey({})); + EXPECT_FALSE(DocumentKey::IsDocumentKey({"foo"})); + EXPECT_TRUE(DocumentKey::IsDocumentKey({"foo", "bar"})); + EXPECT_FALSE(DocumentKey::IsDocumentKey({"foo", "bar", "baz"})); +} + +TEST(DocumentKey, Comparison) { + const DocumentKey abcd({"a", "b", "c", "d"}); + const DocumentKey abcd_too({"a", "b", "c", "d"}); + const DocumentKey xyzw({"x", "y", "z", "w"}); + EXPECT_EQ(abcd, abcd_too); + EXPECT_NE(abcd, xyzw); + + const DocumentKey empty; + const DocumentKey a({"a", "a"}); + const DocumentKey b({"b", "b"}); + const DocumentKey ab({"a", "a", "b", "b"}); + + EXPECT_FALSE(empty < empty); + EXPECT_TRUE(empty <= empty); + EXPECT_TRUE(empty < a); + EXPECT_TRUE(empty <= a); + EXPECT_TRUE(a > empty); + EXPECT_TRUE(a >= empty); + + EXPECT_FALSE(a < a); + EXPECT_TRUE(a <= a); + EXPECT_FALSE(a > a); + EXPECT_TRUE(a >= a); + EXPECT_TRUE(a == a); + EXPECT_FALSE(a != a); + + EXPECT_TRUE(a < b); + EXPECT_TRUE(a <= b); + EXPECT_TRUE(b > a); + EXPECT_TRUE(b >= a); + + EXPECT_TRUE(a < ab); + EXPECT_TRUE(a <= ab); + EXPECT_TRUE(ab > a); + EXPECT_TRUE(ab >= a); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/model/document_test.cc b/Firestore/core/test/firebase/firestore/model/document_test.cc new file mode 100644 index 0000000..6b72360 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/document_test.cc @@ -0,0 +1,76 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/model/document.h" + +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +namespace { + +inline Document MakeDocument(const absl::string_view data, + const absl::string_view path, + const Timestamp& timestamp, + bool has_local_mutations) { + return Document(FieldValue::ObjectValue( + {{"field", FieldValue::StringValue(data.data())}}), + DocumentKey::FromPathString(path.data()), + SnapshotVersion(timestamp), has_local_mutations); +} + +} // anonymous namespace + +TEST(Document, Getter) { + const Document& doc = + MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true); + EXPECT_EQ(MaybeDocument::Type::Document, doc.type()); + EXPECT_EQ( + FieldValue::ObjectValue({{"field", FieldValue::StringValue("foo")}}), + doc.data()); + EXPECT_EQ(DocumentKey::FromPathString("i/am/a/path"), doc.key()); + EXPECT_EQ(SnapshotVersion(Timestamp(123, 456)), doc.version()); + EXPECT_TRUE(doc.has_local_mutations()); +} + +TEST(Document, Comparison) { + EXPECT_EQ(MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true), + MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true)); + EXPECT_NE(MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true), + MakeDocument("bar", "i/am/a/path", Timestamp(123, 456), true)); + EXPECT_NE( + MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true), + MakeDocument("foo", "i/am/another/path", Timestamp(123, 456), true)); + EXPECT_NE(MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true), + MakeDocument("foo", "i/am/a/path", Timestamp(456, 123), true)); + EXPECT_NE(MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), true), + MakeDocument("foo", "i/am/a/path", Timestamp(123, 456), false)); + + // Document and MaybeDocument will not equal. In particular, Document and + // NoDocument will not equal, which I won't test here. + EXPECT_NE(Document(FieldValue::ObjectValue({}), + DocumentKey::FromPathString("same/path"), + SnapshotVersion(Timestamp()), false), + MaybeDocument(DocumentKey::FromPathString("same/path"), + SnapshotVersion(Timestamp()))); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/model/field_path_test.cc b/Firestore/core/test/firebase/firestore/model/field_path_test.cc index 7c7e0a3..a5ae3b2 100644 --- a/Firestore/core/test/firebase/firestore/model/field_path_test.cc +++ b/Firestore/core/test/firebase/firestore/model/field_path_test.cc @@ -29,18 +29,18 @@ namespace model { TEST(FieldPath, Constructors) { const FieldPath empty_path; EXPECT_TRUE(empty_path.empty()); - EXPECT_EQ(0, empty_path.size()); + EXPECT_EQ(0u, empty_path.size()); EXPECT_TRUE(empty_path.begin() == empty_path.end()); const FieldPath path_from_list = {"rooms", "Eros", "messages"}; EXPECT_FALSE(path_from_list.empty()); - EXPECT_EQ(3, path_from_list.size()); + EXPECT_EQ(3u, path_from_list.size()); EXPECT_TRUE(path_from_list.begin() + 3 == path_from_list.end()); std::vector<std::string> segments{"rooms", "Eros", "messages"}; const FieldPath path_from_segments{segments.begin(), segments.end()}; EXPECT_FALSE(path_from_segments.empty()); - EXPECT_EQ(3, path_from_segments.size()); + EXPECT_EQ(3u, path_from_segments.size()); EXPECT_TRUE(path_from_segments.begin() + 3 == path_from_segments.end()); FieldPath copied = path_from_list; @@ -168,13 +168,13 @@ TEST(FieldPath, IsPrefixOf) { TEST(FieldPath, AccessFailures) { const FieldPath path; - ASSERT_DEATH_IF_SUPPORTED(path.first_segment(), ""); - ASSERT_DEATH_IF_SUPPORTED(path.last_segment(), ""); - ASSERT_DEATH_IF_SUPPORTED(path[0], ""); - ASSERT_DEATH_IF_SUPPORTED(path[1], ""); - ASSERT_DEATH_IF_SUPPORTED(path.PopFirst(), ""); - ASSERT_DEATH_IF_SUPPORTED(path.PopFirst(2), ""); - ASSERT_DEATH_IF_SUPPORTED(path.PopLast(), ""); + ASSERT_ANY_THROW(path.first_segment()); + ASSERT_ANY_THROW(path.last_segment()); + ASSERT_ANY_THROW(path[0]); + ASSERT_ANY_THROW(path[1]); + ASSERT_ANY_THROW(path.PopFirst()); + ASSERT_ANY_THROW(path.PopFirst(2)); + ASSERT_ANY_THROW(path.PopLast()); } TEST(FieldPath, Parsing) { @@ -201,7 +201,7 @@ TEST(FieldPath, Parsing) { const auto path_with_dot = FieldPath::FromServerFormat(R"(foo\.bar)"); EXPECT_EQ(path_with_dot.CanonicalString(), "`foo.bar`"); - EXPECT_EQ(path_with_dot.size(), 1); + EXPECT_EQ(path_with_dot.size(), 1u); } // This is a special case in C++: std::string may contain embedded nulls. To @@ -213,22 +213,22 @@ TEST(FieldPath, ParseEmbeddedNull) { str += ".bar"; const auto path = FieldPath::FromServerFormat(str); - EXPECT_EQ(path.size(), 1); + EXPECT_EQ(path.size(), 1u); EXPECT_EQ(path.CanonicalString(), "foo"); } TEST(FieldPath, ParseFailures) { - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat(""), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat("."), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat(".."), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat("foo."), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat(".bar"), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat("foo..bar"), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat(R"(foo\)"), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat(R"(foo.\)"), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat("foo`"), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat("foo```"), ""); - ASSERT_DEATH_IF_SUPPORTED(FieldPath::FromServerFormat("`foo"), ""); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat(".")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("..")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("foo.")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat(".bar")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("foo..bar")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat(R"(foo\)")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat(R"(foo.\)")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("foo`")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("foo```")); + ASSERT_ANY_THROW(FieldPath::FromServerFormat("`foo")); } TEST(FieldPath, CanonicalStringOfSubstring) { diff --git a/Firestore/core/test/firebase/firestore/model/field_value_test.cc b/Firestore/core/test/firebase/firestore/model/field_value_test.cc index 702c0f6..86eb804 100644 --- a/Firestore/core/test/firebase/firestore/model/field_value_test.cc +++ b/Firestore/core/test/firebase/firestore/model/field_value_test.cc @@ -144,6 +144,20 @@ TEST(FieldValue, BlobType) { EXPECT_FALSE(a < a); } +TEST(FieldValue, ReferenceType) { + const DatabaseId id("project", "database"); + const FieldValue a = + FieldValue::ReferenceValue(DocumentKey::FromPathString("root/abc"), &id); + DocumentKey key = DocumentKey::FromPathString("root/def"); + const FieldValue b = FieldValue::ReferenceValue(key, &id); + const FieldValue c = FieldValue::ReferenceValue(std::move(key), &id); + EXPECT_EQ(Type::Reference, a.type()); + EXPECT_EQ(Type::Reference, b.type()); + EXPECT_EQ(Type::Reference, c.type()); + EXPECT_TRUE(a < b); + EXPECT_FALSE(a < a); +} + TEST(FieldValue, GeoPointType) { const FieldValue a = FieldValue::GeoPointValue({1, 2}); const FieldValue b = FieldValue::GeoPointValue({3, 4}); @@ -280,6 +294,23 @@ TEST(FieldValue, Copy) { clone = null_value; EXPECT_EQ(FieldValue::NullValue(), clone); + const DatabaseId database_id("project", "database"); + const FieldValue reference_value = FieldValue::ReferenceValue( + DocumentKey::FromPathString("root/abc"), &database_id); + clone = reference_value; + EXPECT_EQ(FieldValue::ReferenceValue(DocumentKey::FromPathString("root/abc"), + &database_id), + clone); + EXPECT_EQ(FieldValue::ReferenceValue(DocumentKey::FromPathString("root/abc"), + &database_id), + reference_value); + clone = clone; + EXPECT_EQ(FieldValue::ReferenceValue(DocumentKey::FromPathString("root/abc"), + &database_id), + clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + const FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2}); clone = geo_point_value; EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone); @@ -361,7 +392,7 @@ TEST(FieldValue, Move) { clone = FieldValue::NullValue(); EXPECT_EQ(FieldValue::NullValue(), clone); - const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200}); + FieldValue timestamp_value = FieldValue::TimestampValue({100, 200}); clone = std::move(timestamp_value); EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone); clone = FieldValue::NullValue(); @@ -373,13 +404,23 @@ TEST(FieldValue, Move) { clone = FieldValue::NullValue(); EXPECT_EQ(FieldValue::NullValue(), clone); - const FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4); + FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4); clone = std::move(blob_value); EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), clone); clone = FieldValue::NullValue(); EXPECT_EQ(FieldValue::NullValue(), clone); - const FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2}); + const DatabaseId database_id("project", "database"); + FieldValue reference_value = FieldValue::ReferenceValue( + DocumentKey::FromPathString("root/abc"), &database_id); + clone = std::move(reference_value); + EXPECT_EQ(FieldValue::ReferenceValue(DocumentKey::FromPathString("root/abc"), + &database_id), + clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2}); clone = std::move(geo_point_value); EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone); clone = null_value; @@ -415,6 +456,9 @@ TEST(FieldValue, CompareMixedType) { const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200}); const FieldValue string_value = FieldValue::StringValue("abc"); const FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4); + const DatabaseId database_id("project", "database"); + const FieldValue reference_value = FieldValue::ReferenceValue( + DocumentKey::FromPathString("root/abc"), &database_id); const FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2}); const FieldValue array_value = FieldValue::ArrayValue(std::vector<FieldValue>()); @@ -425,7 +469,8 @@ TEST(FieldValue, CompareMixedType) { EXPECT_TRUE(number_value < timestamp_value); EXPECT_TRUE(timestamp_value < string_value); EXPECT_TRUE(string_value < blob_value); - EXPECT_TRUE(blob_value < geo_point_value); + EXPECT_TRUE(blob_value < reference_value); + EXPECT_TRUE(reference_value < geo_point_value); EXPECT_TRUE(geo_point_value < array_value); EXPECT_TRUE(array_value < object_value); } diff --git a/Firestore/core/test/firebase/firestore/model/maybe_document_test.cc b/Firestore/core/test/firebase/firestore/model/maybe_document_test.cc new file mode 100644 index 0000000..005798a --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/maybe_document_test.cc @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" + +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +namespace { + +inline MaybeDocument MakeMaybeDocument(const absl::string_view path, + const Timestamp& timestamp) { + return MaybeDocument(DocumentKey::FromPathString(path.data()), + SnapshotVersion(timestamp)); +} + +inline bool operator<(const MaybeDocument& lhs, const MaybeDocument& rhs) { + static const DocumentKeyComparator less; + return less(lhs, rhs); +} + +} // anonymous namespace + +TEST(MaybeDocument, Getter) { + const MaybeDocument& doc = + MakeMaybeDocument("i/am/a/path", Timestamp(123, 456)); + EXPECT_EQ(MaybeDocument::Type::Unknown, doc.type()); + EXPECT_EQ(DocumentKey::FromPathString("i/am/a/path"), doc.key()); + EXPECT_EQ(SnapshotVersion(Timestamp(123, 456)), doc.version()); +} + +TEST(MaybeDocument, Comparison) { + EXPECT_TRUE(MakeMaybeDocument("root/123", Timestamp(456, 123)) < + MakeMaybeDocument("root/456", Timestamp(123, 456))); + // MaybeDocument comparision is purely key-based. + EXPECT_FALSE(MakeMaybeDocument("root/123", Timestamp(111, 111)) < + MakeMaybeDocument("root/123", Timestamp(222, 222))); + + EXPECT_EQ(MakeMaybeDocument("root/123", Timestamp(456, 123)), + MakeMaybeDocument("root/123", Timestamp(456, 123))); + EXPECT_NE(MakeMaybeDocument("root/123", Timestamp(456, 123)), + MakeMaybeDocument("root/456", Timestamp(456, 123))); + EXPECT_NE(MakeMaybeDocument("root/123", Timestamp(456, 123)), + MakeMaybeDocument("root/123", Timestamp(123, 456))); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/model/no_document_test.cc b/Firestore/core/test/firebase/firestore/model/no_document_test.cc new file mode 100644 index 0000000..825820f --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/no_document_test.cc @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/model/no_document.h" + +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +namespace { + +inline NoDocument MakeNoDocument(const absl::string_view path, + const Timestamp& timestamp) { + return NoDocument(DocumentKey::FromPathString(path.data()), + SnapshotVersion(timestamp)); +} + +} // anonymous namespace + +TEST(NoDocument, Getter) { + const NoDocument& doc = MakeNoDocument("i/am/a/path", Timestamp(123, 456)); + EXPECT_EQ(MaybeDocument::Type::NoDocument, doc.type()); + EXPECT_EQ(DocumentKey::FromPathString("i/am/a/path"), doc.key()); + EXPECT_EQ(SnapshotVersion(Timestamp(123, 456)), doc.version()); + + // NoDocument and MaybeDocument will not equal. + EXPECT_NE(NoDocument(DocumentKey::FromPathString("same/path"), + SnapshotVersion(Timestamp())), + MaybeDocument(DocumentKey::FromPathString("same/path"), + SnapshotVersion(Timestamp()))); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/model/resource_path_test.cc b/Firestore/core/test/firebase/firestore/model/resource_path_test.cc index 317a1db..637e78e 100644 --- a/Firestore/core/test/firebase/firestore/model/resource_path_test.cc +++ b/Firestore/core/test/firebase/firestore/model/resource_path_test.cc @@ -29,18 +29,18 @@ namespace model { TEST(ResourcePath, Constructor) { const ResourcePath empty_path; EXPECT_TRUE(empty_path.empty()); - EXPECT_EQ(0, empty_path.size()); + EXPECT_EQ(0u, empty_path.size()); EXPECT_TRUE(empty_path.begin() == empty_path.end()); const ResourcePath path_from_list{{"rooms", "Eros", "messages"}}; EXPECT_FALSE(path_from_list.empty()); - EXPECT_EQ(3, path_from_list.size()); + EXPECT_EQ(3u, path_from_list.size()); EXPECT_TRUE(path_from_list.begin() + 3 == path_from_list.end()); std::vector<std::string> segments{"rooms", "Eros", "messages"}; const ResourcePath path_from_segments{segments.begin(), segments.end()}; EXPECT_FALSE(path_from_segments.empty()); - EXPECT_EQ(3, path_from_segments.size()); + EXPECT_EQ(3u, path_from_segments.size()); EXPECT_TRUE(path_from_segments.begin() + 3 == path_from_segments.end()); ResourcePath copied = path_from_list; @@ -74,7 +74,7 @@ TEST(ResourcePath, Comparison) { TEST(ResourcePath, Parsing) { const auto parse = [](const std::pair<std::string, size_t> expected) { - const auto path = ResourcePath::Parse(expected.first); + const auto path = ResourcePath::FromString(expected.first); return std::make_pair(path.CanonicalString(), path.size()); }; const auto make_expected = [](const std::string& str, const size_t size) { @@ -92,12 +92,12 @@ TEST(ResourcePath, Parsing) { expected = make_expected(R"(foo/__!?#@..`..\`/baz)", 3); EXPECT_EQ(expected, parse(expected)); - EXPECT_EQ(ResourcePath::Parse("/foo/").CanonicalString(), "foo"); + EXPECT_EQ(ResourcePath::FromString("/foo/").CanonicalString(), "foo"); } TEST(ResourcePath, ParseFailures) { - ASSERT_DEATH_IF_SUPPORTED(ResourcePath::Parse("//"), ""); - ASSERT_DEATH_IF_SUPPORTED(ResourcePath::Parse("foo//bar"), ""); + ASSERT_ANY_THROW(ResourcePath::FromString("//")); + ASSERT_ANY_THROW(ResourcePath::FromString("foo//bar")); } } // namespace model diff --git a/Firestore/core/test/firebase/firestore/model/snapshot_version_test.cc b/Firestore/core/test/firebase/firestore/model/snapshot_version_test.cc new file mode 100644 index 0000000..e359f84 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/snapshot_version_test.cc @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +TEST(SnapshotVersion, Getter) { + SnapshotVersion version(Timestamp(123, 456)); + EXPECT_EQ(Timestamp(123, 456), version.timestamp()); + + const SnapshotVersion& no_version = SnapshotVersion::None(); + EXPECT_EQ(Timestamp(), no_version.timestamp()); +} + +TEST(SnapshotVersion, Comparison) { + EXPECT_LT(SnapshotVersion::None(), SnapshotVersion(Timestamp(123, 456))); + + EXPECT_LT(SnapshotVersion(Timestamp(123, 456)), + SnapshotVersion(Timestamp(456, 123))); + EXPECT_GT(SnapshotVersion(Timestamp(456, 123)), + SnapshotVersion(Timestamp(123, 456))); + EXPECT_LE(SnapshotVersion(Timestamp(123, 456)), + SnapshotVersion(Timestamp(456, 123))); + EXPECT_LE(SnapshotVersion(Timestamp(123, 456)), + SnapshotVersion(Timestamp(123, 456))); + EXPECT_GE(SnapshotVersion(Timestamp(456, 123)), + SnapshotVersion(Timestamp(123, 456))); + EXPECT_GE(SnapshotVersion(Timestamp(123, 456)), + SnapshotVersion(Timestamp(123, 456))); + EXPECT_EQ(SnapshotVersion(Timestamp(123, 456)), + SnapshotVersion(Timestamp(123, 456))); + EXPECT_NE(SnapshotVersion(Timestamp(123, 456)), + SnapshotVersion(Timestamp(456, 123))); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc index 1be5a87..35f417e 100644 --- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc +++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc @@ -16,8 +16,15 @@ #include "Firestore/core/src/firebase/firestore/remote/serializer.h" -#include <gtest/gtest.h> +#include <pb.h> #include <pb_encode.h> +#include <vector> + +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "gtest/gtest.h" + +using firebase::firestore::model::FieldValue; +using firebase::firestore::remote::Serializer; TEST(Serializer, CanLinkToNanopb) { // This test doesn't actually do anything interesting as far as actually using @@ -26,3 +33,65 @@ TEST(Serializer, CanLinkToNanopb) { // the test. pb_ostream_from_buffer(NULL, 0); } + +// Fixture for running serializer tests. +class SerializerTest : public ::testing::Test { + public: + SerializerTest() : serializer(/*DatabaseId("p", "d")*/) { + } + Serializer serializer; + + void ExpectRoundTrip(const FieldValue& model, + const Serializer::TypedValue& proto, + FieldValue::Type type) { + EXPECT_EQ(type, model.type()); + EXPECT_EQ(type, proto.type); + Serializer::TypedValue actual_proto = serializer.EncodeFieldValue(model); + EXPECT_EQ(type, actual_proto.type); + EXPECT_EQ(proto, actual_proto); + EXPECT_EQ(model, serializer.DecodeFieldValue(proto)); + } + + void ExpectRoundTrip(const Serializer::TypedValue& proto, + std::vector<uint8_t> bytes, + FieldValue::Type type) { + EXPECT_EQ(type, proto.type); + std::vector<uint8_t> actual_bytes; + Serializer::EncodeTypedValue(proto, &actual_bytes); + EXPECT_EQ(bytes, actual_bytes); + Serializer::TypedValue actual_proto = Serializer::DecodeTypedValue(bytes); + EXPECT_EQ(type, actual_proto.type); + EXPECT_EQ(proto, actual_proto); + } +}; + +TEST_F(SerializerTest, EncodesNullModelToProto) { + FieldValue model = FieldValue::NullValue(); + Serializer::TypedValue proto{FieldValue::Type::Null, + google_firestore_v1beta1_Value_init_default}; + // sanity check (the _init_default above should set this to _NULL_VALUE) + EXPECT_EQ(google_protobuf_NullValue_NULL_VALUE, proto.value.null_value); + ExpectRoundTrip(model, proto, FieldValue::Type::Null); +} + +TEST_F(SerializerTest, EncodesNullProtoToBytes) { + Serializer::TypedValue proto{FieldValue::Type::Null, + google_firestore_v1beta1_Value_init_default}; + // sanity check (the _init_default above should set this to _NULL_VALUE) + EXPECT_EQ(google_protobuf_NullValue_NULL_VALUE, proto.value.null_value); + + /* NB: proto bytes were created via: + echo 'null_value: NULL_VALUE' \ + | ./build/external/protobuf/src/protobuf-build/src/protoc \ + -I./Firestore/Protos/protos \ + -I./build/external/protobuf/src/protobuf/src/ \ + --encode=google.firestore.v1beta1.Value \ + google/firestore/v1beta1/document.proto \ + > output.bin + */ + std::vector<uint8_t> bytes{0x58, 0x00}; + ExpectRoundTrip(proto, bytes, FieldValue::Type::Null); +} + +// TODO(rsgowman): Test [en|de]coding multiple protos into the same output +// vector. |