aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore
diff options
context:
space:
mode:
authorGravatar zxu <zxu@google.com>2018-01-17 13:18:54 -0500
committerGravatar GitHub <noreply@github.com>2018-01-17 13:18:54 -0500
commitcac2c3ff7aa7b94e3776bb1282765ca78be977ae (patch)
tree6234d9795604c8eb362659e4aef9cbd26550619c /Firestore
parent128e9cb170b28bbff0284610276b0e4e517f576e (diff)
implement FieldValue for null, boolean, and array in C++. (#637)
* implement FieldValue for null and boolean. * refactoring to use union type instead of poly * refactor using union design intead of poly * refactoring to use anonymous union and fix styles * small fix * add field_value_test to the project * fix warning of cmake and fix style
Diffstat (limited to 'Firestore')
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj13
-rw-r--r--Firestore/core/CMakeLists.txt6
-rw-r--r--Firestore/core/src/firebase/firestore/model/CMakeLists.txt22
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.cc176
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.h130
-rw-r--r--Firestore/core/src/firebase/firestore/util/firebase_assert.h4
-rw-r--r--Firestore/core/test/firebase/firestore/model/CMakeLists.txt22
-rw-r--r--Firestore/core/test/firebase/firestore/model/field_value_test.cc164
8 files changed, 533 insertions, 4 deletions
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index 6f2bf5a..538758d 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -64,6 +64,7 @@
6ED54761B845349D43DB6B78 /* Pods_Firestore_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */; };
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
+ AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB356EF6200EA5EB0089B766 /* field_value_test.cc */; };
AB382F7C1FE02A1F007CA955 /* FIRDocumentReferenceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AB382F7B1FE02A1F007CA955 /* FIRDocumentReferenceTests.m */; };
AB382F7E1FE03059007CA955 /* FIRFieldPathTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AB382F7D1FE03059007CA955 /* FIRFieldPathTests.m */; };
AB9945261FE2D71100DFC1E6 /* FIRCollectionReferenceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AB9945251FE2D71100DFC1E6 /* FIRCollectionReferenceTests.m */; };
@@ -245,6 +246,7 @@
8E002F4AD5D9B6197C940847 /* Firestore.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Firestore.podspec; path = ../Firestore.podspec; sourceTree = "<group>"; };
9D52E67EE96AA7E5D6F69748 /* Pods-Firestore_IntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests/Pods-Firestore_IntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
9EF477AD4B2B643FD320867A /* Pods-Firestore_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.debug.xcconfig"; sourceTree = "<group>"; };
+ AB356EF6200EA5EB0089B766 /* field_value_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = field_value_test.cc; sourceTree = "<group>"; };
AB382F7B1FE02A1F007CA955 /* FIRDocumentReferenceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRDocumentReferenceTests.m; sourceTree = "<group>"; };
AB382F7D1FE03059007CA955 /* FIRFieldPathTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRFieldPathTests.m; sourceTree = "<group>"; };
AB9945251FE2D71100DFC1E6 /* FIRCollectionReferenceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIRCollectionReferenceTests.m; sourceTree = "<group>"; };
@@ -408,6 +410,7 @@
54764FAC1FAA0C390085E60A /* GoogleTests */ = {
isa = PBXGroup;
children = (
+ AB356EF5200E9D1A0089B766 /* model */,
54764FAD1FAA0C650085E60A /* Port */,
54740A561FC913EB00713A1A /* util */,
54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */,
@@ -540,6 +543,15 @@
name = Pods;
sourceTree = "<group>";
};
+ AB356EF5200E9D1A0089B766 /* model */ = {
+ isa = PBXGroup;
+ children = (
+ AB356EF6200EA5EB0089B766 /* field_value_test.cc */,
+ );
+ name = model;
+ path = ../../core/test/firebase/firestore/model;
+ sourceTree = "<group>";
+ };
DE0761E51F2FE611003233AF /* SwiftBuildTest */ = {
isa = PBXGroup;
children = (
@@ -1236,6 +1248,7 @@
DE51B1F11F0D49140013853F /* FSTMutationTests.m in Sources */,
DE51B1FB1F0D492C0013853F /* FSTMemorySpecTests.m in Sources */,
DE51B1DB1F0D490D0013853F /* FSTLevelDBQueryCacheTests.m in Sources */,
+ AB356EF7200EA5EB0089B766 /* field_value_test.cc in Sources */,
54764FAB1FAA0C320085E60A /* string_util_test.cc in Sources */,
54E9282C1F339CAD00C1953E /* XCTestCase+Await.m in Sources */,
AB99452E1FE30AC800DFC1E6 /* FIRFieldValueTests.m in Sources */,
diff --git a/Firestore/core/CMakeLists.txt b/Firestore/core/CMakeLists.txt
index 9291fbd..da08dfc 100644
--- a/Firestore/core/CMakeLists.txt
+++ b/Firestore/core/CMakeLists.txt
@@ -12,8 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-add_subdirectory(src/firebase/firestore/util)
+add_subdirectory(src/firebase/firestore/model)
add_subdirectory(src/firebase/firestore/remote)
+add_subdirectory(src/firebase/firestore/util)
-add_subdirectory(test/firebase/firestore/util)
+add_subdirectory(test/firebase/firestore/model)
add_subdirectory(test/firebase/firestore/remote)
+add_subdirectory(test/firebase/firestore/util)
diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
new file mode 100644
index 0000000..1beb3bb
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
@@ -0,0 +1,22 @@
+# 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.
+
+add_library(
+ firebase_firestore_model
+ field_value.cc
+)
+target_link_libraries(
+ firebase_firestore_model
+ firebase_firestore_util
+)
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.cc b/Firestore/core/src/firebase/firestore/model/field_value.cc
new file mode 100644
index 0000000..5a19549
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/field_value.cc
@@ -0,0 +1,176 @@
+/*
+ * 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/field_value.h"
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+using Type = FieldValue::Type;
+
+namespace {
+/**
+ * This deviates from the other platforms that define TypeOrder. Since
+ * we already define Type for union types, we use it together with this
+ * function to achive the equivalent order of types i.e.
+ * i) if two types are comparable, then they are of equal order;
+ * ii) otherwise, their order is the same as the order of their Type.
+ */
+bool Comparable(Type lhs, Type rhs) {
+ switch (lhs) {
+ case Type::Long:
+ case Type::Double:
+ return rhs == Type::Long || rhs == Type::Double;
+ case Type::Timestamp:
+ case Type::ServerTimestamp:
+ return rhs == Type::Timestamp || rhs == Type::ServerTimestamp;
+ default:
+ return lhs == rhs;
+ }
+}
+
+} // namespace
+
+FieldValue::FieldValue(const FieldValue& value) {
+ *this = value;
+}
+
+FieldValue::FieldValue(FieldValue&& value) {
+ *this = std::move(value);
+}
+
+FieldValue::~FieldValue() {
+ SwitchTo(Type::Null);
+}
+
+FieldValue& FieldValue::operator=(const FieldValue& value) {
+ SwitchTo(value.tag_);
+ switch (tag_) {
+ case Type::Null:
+ break;
+ case Type::Boolean:
+ boolean_value_ = value.boolean_value_;
+ break;
+ case Type::Array: {
+ // copy-and-swap
+ std::vector<const FieldValue> tmp = value.array_value_;
+ std::swap(array_value_, tmp);
+ break;
+ }
+ default:
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ false, lhs.type(), "Unsupported type %d", value.type());
+ }
+ return *this;
+}
+
+FieldValue& FieldValue::operator=(FieldValue&& value) {
+ switch (value.tag_) {
+ case Type::Array:
+ SwitchTo(Type::Array);
+ std::swap(array_value_, value.array_value_);
+ return *this;
+ default:
+ // We just copy over POD union types.
+ return *this = value;
+ }
+}
+
+const FieldValue& FieldValue::NullValue() {
+ static const FieldValue kNullInstance;
+ return kNullInstance;
+}
+
+const FieldValue& FieldValue::TrueValue() {
+ static const FieldValue kTrueInstance(true);
+ return kTrueInstance;
+}
+
+const FieldValue& FieldValue::FalseValue() {
+ static const FieldValue kFalseInstance(false);
+ return kFalseInstance;
+}
+
+const FieldValue& FieldValue::BooleanValue(bool value) {
+ return value ? TrueValue() : FalseValue();
+}
+
+FieldValue FieldValue::ArrayValue(const std::vector<const FieldValue>& value) {
+ std::vector<const FieldValue> copy(value);
+ return ArrayValue(std::move(copy));
+}
+
+FieldValue FieldValue::ArrayValue(std::vector<const FieldValue>&& value) {
+ FieldValue result;
+ result.SwitchTo(Type::Array);
+ std::swap(result.array_value_, value);
+ return result;
+}
+
+bool operator<(const FieldValue& lhs, const FieldValue& rhs) {
+ if (!Comparable(lhs.type(), rhs.type())) {
+ return lhs.type() < rhs.type();
+ }
+
+ switch (lhs.type()) {
+ case Type::Null:
+ return false;
+ case Type::Boolean:
+ // lhs < rhs iff lhs == false and rhs == true.
+ return !lhs.boolean_value_ && rhs.boolean_value_;
+ case Type::Array:
+ return lhs.array_value_ < rhs.array_value_;
+ default:
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ false, lhs.type(), "Unsupported type %d", lhs.type());
+ // return false if assertion does not abort the program. We will say
+ // each unsupported type takes only one value thus everything is equal.
+ return false;
+ }
+}
+
+void FieldValue::SwitchTo(const Type type) {
+ if (tag_ == type) {
+ return;
+ }
+ // Not same type. Destruct old type first and then initialize new type.
+ // Must call destructor explicitly for any non-POD type.
+ switch (tag_) {
+ case Type::Array:
+ array_value_.~vector();
+ break;
+ default:; // The other types where there is nothing to worry about.
+ }
+ tag_ = type;
+ // Must call constructor explicitly for any non-POD type to initialize.
+ switch (tag_) {
+ case Type::Array:
+ new (&array_value_) std::vector<const FieldValue>();
+ break;
+ default:; // The other types where there is nothing to worry about.
+ }
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.h b/Firestore/core/src/firebase/firestore/model/field_value.h
new file mode 100644
index 0000000..781e34f
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/field_value.h
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
+
+#include <memory>
+#include <vector>
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+/**
+ * tagged-union class representing an immutable data value as stored in
+ * Firestore. FieldValue represents all the different kinds of values
+ * that can be stored in fields in a document.
+ */
+class FieldValue {
+ public:
+ /**
+ * All the different kinds of values that can be stored in fields in
+ * a document. The types of the same comparison order should be defined
+ * together as a group. The order of each group is defined by the Firestore
+ * backend and is available at:
+ * https://firebase.google.com/docs/firestore/manage-data/data-types
+ */
+ enum class Type {
+ Null, // Null
+ Boolean, // Boolean
+ Long, // Number type starts here
+ Double,
+ Timestamp, // Timestamp type starts here
+ ServerTimestamp,
+ String, // String
+ Blob, // Blob
+ Reference, // Reference
+ GeoPoint, // GeoPoint
+ Array, // Array
+ Object, // Object
+ // New enum should not always been added at the tail. Add it to the correct
+ // position instead, see the doc comment above.
+ };
+
+ FieldValue() : tag_(Type::Null) {
+ }
+
+ // Do not inline these ctor/dtor below, which contain call to non-trivial
+ // operator=.
+ FieldValue(const FieldValue& value);
+ FieldValue(FieldValue&& value);
+
+ ~FieldValue();
+
+ FieldValue& operator=(const FieldValue& value);
+ FieldValue& operator=(FieldValue&& value);
+
+ /** Returns the true type for this value. */
+ Type type() const {
+ return tag_;
+ }
+
+ /** factory methods. */
+ static const FieldValue& NullValue();
+ static const FieldValue& TrueValue();
+ static const FieldValue& FalseValue();
+ static const FieldValue& BooleanValue(bool value);
+ static FieldValue ArrayValue(const std::vector<const FieldValue>& value);
+ static FieldValue ArrayValue(std::vector<const FieldValue>&& value);
+
+ friend bool operator<(const FieldValue& lhs, const FieldValue& rhs);
+
+ private:
+ explicit FieldValue(bool value) : tag_(Type::Boolean), boolean_value_(value) {
+ }
+
+ /**
+ * Switch to the specified type, if different from the current type.
+ */
+ void SwitchTo(const Type type);
+
+ Type tag_;
+ union {
+ // There is no null type as tag_ alone is enough for Null FieldValue.
+ bool boolean_value_;
+ std::vector<const FieldValue> array_value_;
+ };
+};
+
+/** Compares against another FieldValue. */
+bool operator<(const FieldValue& lhs, const FieldValue& rhs);
+
+inline bool operator>(const FieldValue& lhs, const FieldValue& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator>=(const FieldValue& lhs, const FieldValue& rhs) {
+ return !(lhs < rhs);
+}
+
+inline bool operator<=(const FieldValue& lhs, const FieldValue& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator!=(const FieldValue& lhs, const FieldValue& rhs) {
+ return lhs < rhs || lhs > rhs;
+}
+
+inline bool operator==(const FieldValue& lhs, const FieldValue& rhs) {
+ return !(lhs != rhs);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
diff --git a/Firestore/core/src/firebase/firestore/util/firebase_assert.h b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
index da01864..cff550a 100644
--- a/Firestore/core/src/firebase/firestore/util/firebase_assert.h
+++ b/Firestore/core/src/firebase/firestore/util/firebase_assert.h
@@ -52,7 +52,7 @@
#else
#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \
FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression)
-#endif // !defined(NDEBUG)
+#endif // defined(NDEBUG)
// Custom assert() implementation that is not compiled out in release builds.
#define FIREBASE_ASSERT(expression) \
@@ -85,7 +85,7 @@
#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \
...) \
FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, __VA_ARGS__)
-#endif // !defined(NDEBUG)
+#endif // defined(NDEBUG)
namespace firebase {
namespace firestore {
diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
new file mode 100644
index 0000000..f5d9c2c
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt
@@ -0,0 +1,22 @@
+# 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_model_test
+ field_value_test.cc
+)
+target_link_libraries(
+ firebase_firestore_model_test
+ firebase_firestore_model
+)
diff --git a/Firestore/core/test/firebase/firestore/model/field_value_test.cc b/Firestore/core/test/firebase/firestore/model/field_value_test.cc
new file mode 100644
index 0000000..1194e63
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/model/field_value_test.cc
@@ -0,0 +1,164 @@
+/*
+ * 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/field_value.h"
+
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+using Type = FieldValue::Type;
+
+TEST(FieldValue, NullType) {
+ const FieldValue value = FieldValue::NullValue();
+ EXPECT_EQ(Type::Null, value.type());
+ EXPECT_FALSE(value < value);
+}
+
+TEST(FieldValue, BooleanType) {
+ const FieldValue true_value = FieldValue::BooleanValue(true);
+ const FieldValue false_value = FieldValue::BooleanValue(false);
+ EXPECT_EQ(Type::Boolean, true_value.type());
+ EXPECT_FALSE(true_value < true_value);
+ EXPECT_FALSE(true_value < false_value);
+ EXPECT_FALSE(false_value < false_value);
+ EXPECT_TRUE(false_value < true_value);
+}
+
+TEST(FieldValue, ArrayType) {
+ const FieldValue empty =
+ FieldValue::ArrayValue(std::vector<const FieldValue>{});
+ std::vector<const FieldValue> array{FieldValue::NullValue(),
+ FieldValue::BooleanValue(true),
+ FieldValue::BooleanValue(false)};
+ // copy the array
+ const FieldValue small = FieldValue::ArrayValue(array);
+ std::vector<const FieldValue> another_array{FieldValue::BooleanValue(true),
+ FieldValue::BooleanValue(false)};
+ // move the array
+ const FieldValue large = FieldValue::ArrayValue(std::move(another_array));
+ EXPECT_EQ(Type::Array, empty.type());
+ EXPECT_EQ(Type::Array, small.type());
+ EXPECT_EQ(Type::Array, large.type());
+ EXPECT_TRUE(empty < small);
+ EXPECT_FALSE(small < empty);
+ EXPECT_FALSE(small < small);
+ EXPECT_TRUE(small < large);
+ EXPECT_FALSE(large < small);
+}
+
+TEST(FieldValue, Copy) {
+ FieldValue clone = FieldValue::TrueValue();
+ const FieldValue null_value = FieldValue::NullValue();
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+ EXPECT_EQ(FieldValue::NullValue(), null_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue true_value = FieldValue::TrueValue();
+ clone = true_value;
+ EXPECT_EQ(FieldValue::TrueValue(), clone);
+ EXPECT_EQ(FieldValue::TrueValue(), true_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::TrueValue(), clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ const FieldValue array_value =
+ FieldValue::ArrayValue(std::vector<const FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()});
+ clone = array_value;
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<const FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ clone);
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<const FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ array_value);
+ clone = clone;
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<const FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ clone);
+ clone = null_value;
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+}
+
+TEST(FieldValue, Move) {
+ FieldValue clone = FieldValue::TrueValue();
+
+ FieldValue null_value = FieldValue::NullValue();
+ clone = std::move(null_value);
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue true_value = FieldValue::TrueValue();
+ clone = std::move(true_value);
+ EXPECT_EQ(FieldValue::TrueValue(), clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+
+ FieldValue array_value = FieldValue::ArrayValue(std::vector<const FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()});
+ clone = std::move(array_value);
+ EXPECT_EQ(FieldValue::ArrayValue(std::vector<const FieldValue>{
+ FieldValue::TrueValue(), FieldValue::FalseValue()}),
+ clone);
+ clone = FieldValue::NullValue();
+ EXPECT_EQ(FieldValue::NullValue(), clone);
+}
+
+TEST(FieldValue, CompareMixedType) {
+ const FieldValue null_value = FieldValue::NullValue();
+ const FieldValue true_value = FieldValue::TrueValue();
+ const FieldValue array_value =
+ FieldValue::ArrayValue(std::vector<const FieldValue>());
+ EXPECT_TRUE(null_value < true_value);
+ EXPECT_TRUE(true_value < array_value);
+}
+
+TEST(FieldValue, CompareWithOperator) {
+ const FieldValue small = FieldValue::NullValue();
+ const FieldValue large = FieldValue::TrueValue();
+
+ EXPECT_TRUE(small < large);
+ EXPECT_FALSE(small < small);
+ EXPECT_FALSE(large < small);
+
+ EXPECT_TRUE(large > small);
+ EXPECT_FALSE(small > small);
+ EXPECT_FALSE(small > large);
+
+ EXPECT_TRUE(large >= small);
+ EXPECT_TRUE(small >= small);
+ EXPECT_FALSE(small >= large);
+
+ EXPECT_TRUE(small <= large);
+ EXPECT_TRUE(small <= small);
+ EXPECT_FALSE(large <= small);
+
+ EXPECT_TRUE(small != large);
+ EXPECT_FALSE(small != small);
+
+ EXPECT_TRUE(small == small);
+ EXPECT_FALSE(small == large);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase