From bfa0e40795ba676fd02d616794cce1c9b2d6a95f Mon Sep 17 00:00:00 2001 From: zxu Date: Thu, 25 Jan 2018 09:14:19 -0500 Subject: Implement the rest of FieldValue types for C++ (#687) * implement FieldValue for null and boolean. * Implement number and string FieldValue. * Implement object FieldValue. * implement timestamp FieldValue. * Implement number and string FieldValue. * implement public type `Blob` and `GeoPoint` * implement Blob FieldValue * Implement GeoPoint FieldValue * refactoring `Blob` --- .../test/firebase/firestore/model/CMakeLists.txt | 1 + .../firebase/firestore/model/field_value_test.cc | 300 ++++++++++++++++++++- .../firebase/firestore/model/timestamp_test.cc | 49 ++++ 3 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 Firestore/core/test/firebase/firestore/model/timestamp_test.cc (limited to 'Firestore/core/test/firebase/firestore/model') diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt index 31fe040..9153a57 100644 --- a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt @@ -16,6 +16,7 @@ cc_test( firebase_firestore_model_test SOURCES field_value_test.cc + timestamp_test.cc DEPENDS 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 index 1194e63..a006d46 100644 --- a/Firestore/core/test/firebase/firestore/model/field_value_test.cc +++ b/Firestore/core/test/firebase/firestore/model/field_value_test.cc @@ -26,6 +26,14 @@ namespace model { using Type = FieldValue::Type; +namespace { + +const uint8_t* Bytes(const char* value) { + return reinterpret_cast(value); +} + +} // namespace + TEST(FieldValue, NullType) { const FieldValue value = FieldValue::NullValue(); EXPECT_EQ(Type::Null, value.type()); @@ -42,6 +50,107 @@ TEST(FieldValue, BooleanType) { EXPECT_TRUE(false_value < true_value); } +TEST(FieldValue, NumberType) { + const FieldValue nan_value = FieldValue::NanValue(); + const FieldValue integer_value = FieldValue::IntegerValue(10L); + const FieldValue double_value = FieldValue::DoubleValue(10.1); + EXPECT_EQ(Type::Double, nan_value.type()); + EXPECT_EQ(Type::Long, integer_value.type()); + EXPECT_EQ(Type::Double, double_value.type()); + EXPECT_TRUE(nan_value < integer_value); + EXPECT_TRUE(nan_value < double_value); + EXPECT_FALSE(nan_value < nan_value); + EXPECT_FALSE(integer_value < nan_value); + EXPECT_FALSE(integer_value < nan_value); + EXPECT_TRUE(integer_value < double_value); // 10 < 10.1 + EXPECT_FALSE(double_value < integer_value); + EXPECT_FALSE(integer_value < integer_value); + EXPECT_FALSE(double_value < double_value); + + // Number comparison craziness + // Integers + EXPECT_TRUE(FieldValue::IntegerValue(1L) < FieldValue::IntegerValue(2L)); + EXPECT_FALSE(FieldValue::IntegerValue(1L) < FieldValue::IntegerValue(1L)); + EXPECT_FALSE(FieldValue::IntegerValue(2L) < FieldValue::IntegerValue(1L)); + // Doubles + EXPECT_TRUE(FieldValue::DoubleValue(1.0) < FieldValue::DoubleValue(2.0)); + EXPECT_FALSE(FieldValue::DoubleValue(1.0) < FieldValue::DoubleValue(1.0)); + EXPECT_FALSE(FieldValue::DoubleValue(2.0) < FieldValue::DoubleValue(1.0)); + EXPECT_TRUE(FieldValue::NanValue() < FieldValue::DoubleValue(1.0)); + EXPECT_FALSE(FieldValue::NanValue() < FieldValue::NanValue()); + EXPECT_FALSE(FieldValue::DoubleValue(1.0) < FieldValue::NanValue()); + // Mixed + EXPECT_TRUE(FieldValue::DoubleValue(-1e20) < + FieldValue::IntegerValue(LLONG_MIN)); + EXPECT_FALSE(FieldValue::DoubleValue(1e20) < + FieldValue::IntegerValue(LLONG_MAX)); + EXPECT_TRUE(FieldValue::DoubleValue(1.234) < FieldValue::IntegerValue(2L)); + EXPECT_FALSE(FieldValue::DoubleValue(2.345) < FieldValue::IntegerValue(1L)); + EXPECT_FALSE(FieldValue::DoubleValue(1.0) < FieldValue::IntegerValue(1L)); + EXPECT_FALSE(FieldValue::DoubleValue(1.234) < FieldValue::IntegerValue(1L)); + EXPECT_FALSE(FieldValue::IntegerValue(LLONG_MIN) < + FieldValue::DoubleValue(-1e20)); + EXPECT_TRUE(FieldValue::IntegerValue(LLONG_MAX) < + FieldValue::DoubleValue(1e20)); + EXPECT_FALSE(FieldValue::IntegerValue(1) < FieldValue::DoubleValue(1.0)); + EXPECT_TRUE(FieldValue::IntegerValue(1) < FieldValue::DoubleValue(1.234)); +} + +TEST(FieldValue, TimestampType) { + const FieldValue o = FieldValue::TimestampValue(Timestamp()); + const FieldValue a = FieldValue::TimestampValue({100, 0}); + const FieldValue b = FieldValue::TimestampValue({200, 0}); + EXPECT_EQ(Type::Timestamp, a.type()); + EXPECT_TRUE(o < a); + EXPECT_TRUE(a < b); + EXPECT_FALSE(a < a); + const FieldValue c = FieldValue::ServerTimestampValue({100, 0}); + const FieldValue d = FieldValue::ServerTimestampValue({200, 0}, {300, 0}); + EXPECT_EQ(Type::ServerTimestamp, c.type()); + EXPECT_EQ(Type::ServerTimestamp, d.type()); + EXPECT_TRUE(c < d); + EXPECT_FALSE(c < c); + // Mixed + EXPECT_TRUE(o < c); + EXPECT_TRUE(a < c); + EXPECT_TRUE(b < c); + EXPECT_TRUE(b < d); + EXPECT_FALSE(c < o); + EXPECT_FALSE(c < a); + EXPECT_FALSE(c < b); + EXPECT_FALSE(d < b); +} + +TEST(FieldValue, StringType) { + const FieldValue a = FieldValue::StringValue("abc"); + std::string xyz("xyz"); + const FieldValue b = FieldValue::StringValue(xyz); + const FieldValue c = FieldValue::StringValue(std::move(xyz)); + EXPECT_EQ(Type::String, a.type()); + EXPECT_EQ(Type::String, b.type()); + EXPECT_EQ(Type::String, c.type()); + EXPECT_TRUE(a < b); + EXPECT_FALSE(a < a); +} + +TEST(FieldValue, BlobType) { + const FieldValue a = FieldValue::BlobValue(Bytes("abc"), 4); + const FieldValue b = FieldValue::BlobValue(Bytes("def"), 4); + EXPECT_EQ(Type::Blob, a.type()); + EXPECT_EQ(Type::Blob, b.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}); + EXPECT_EQ(Type::GeoPoint, a.type()); + EXPECT_EQ(Type::GeoPoint, b.type()); + EXPECT_TRUE(a < b); + EXPECT_FALSE(a < a); +} + TEST(FieldValue, ArrayType) { const FieldValue empty = FieldValue::ArrayValue(std::vector{}); @@ -64,6 +173,29 @@ TEST(FieldValue, ArrayType) { EXPECT_FALSE(large < small); } +TEST(FieldValue, ObjectType) { + const FieldValue empty = + FieldValue::ObjectValue(std::map{}); + std::map object{ + {"null", FieldValue::NullValue()}, + {"true", FieldValue::TrueValue()}, + {"false", FieldValue::FalseValue()}}; + // copy the map + const FieldValue small = FieldValue::ObjectValue(object); + std::map another_object{ + {"null", FieldValue::NullValue()}, {"true", FieldValue::FalseValue()}}; + // move the array + const FieldValue large = FieldValue::ObjectValue(std::move(another_object)); + EXPECT_EQ(Type::Object, empty.type()); + EXPECT_EQ(Type::Object, small.type()); + EXPECT_EQ(Type::Object, 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(); @@ -82,6 +214,80 @@ TEST(FieldValue, Copy) { clone = null_value; EXPECT_EQ(FieldValue::NullValue(), clone); + const FieldValue nan_value = FieldValue::NanValue(); + clone = nan_value; + EXPECT_EQ(FieldValue::NanValue(), clone); + EXPECT_EQ(FieldValue::NanValue(), nan_value); + clone = clone; + EXPECT_EQ(FieldValue::NanValue(), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue integer_value = FieldValue::IntegerValue(1L); + clone = integer_value; + EXPECT_EQ(FieldValue::IntegerValue(1L), clone); + EXPECT_EQ(FieldValue::IntegerValue(1L), integer_value); + clone = clone; + EXPECT_EQ(FieldValue::IntegerValue(1L), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue double_value = FieldValue::DoubleValue(1.0); + clone = double_value; + EXPECT_EQ(FieldValue::DoubleValue(1.0), clone); + EXPECT_EQ(FieldValue::DoubleValue(1.0), double_value); + clone = clone; + EXPECT_EQ(FieldValue::DoubleValue(1.0), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200}); + clone = timestamp_value; + EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone); + EXPECT_EQ(FieldValue::TimestampValue({100, 200}), timestamp_value); + clone = clone; + EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue server_timestamp_value = + FieldValue::ServerTimestampValue({1, 2}, {3, 4}); + clone = server_timestamp_value; + EXPECT_EQ(FieldValue::ServerTimestampValue({1, 2}, {3, 4}), clone); + EXPECT_EQ(FieldValue::ServerTimestampValue({1, 2}, {3, 4}), + server_timestamp_value); + clone = clone; + EXPECT_EQ(FieldValue::ServerTimestampValue({1, 2}, {3, 4}), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue string_value = FieldValue::StringValue("abc"); + clone = string_value; + EXPECT_EQ(FieldValue::StringValue("abc"), clone); + EXPECT_EQ(FieldValue::StringValue("abc"), string_value); + clone = clone; + EXPECT_EQ(FieldValue::StringValue("abc"), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue blob_value = FieldValue::BlobValue(Bytes("abc"), 4); + clone = blob_value; + EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), clone); + EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), blob_value); + clone = clone; + EXPECT_EQ(FieldValue::BlobValue(Bytes("abc"), 4), 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); + EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), geo_point_value); + clone = clone; + EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + const FieldValue array_value = FieldValue::ArrayValue(std::vector{ FieldValue::TrueValue(), FieldValue::FalseValue()}); @@ -98,6 +304,30 @@ TEST(FieldValue, Copy) { clone); clone = null_value; EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue object_value = + FieldValue::ObjectValue(std::map{ + {"true", FieldValue::TrueValue()}, + {"false", FieldValue::FalseValue()}}); + clone = object_value; + EXPECT_EQ( + FieldValue::ObjectValue(std::map{ + {"true", FieldValue::TrueValue()}, + {"false", FieldValue::FalseValue()}}), + clone); + EXPECT_EQ( + FieldValue::ObjectValue(std::map{ + {"true", FieldValue::TrueValue()}, + {"false", FieldValue::FalseValue()}}), + object_value); + clone = clone; + EXPECT_EQ( + FieldValue::ObjectValue(std::map{ + {"true", FieldValue::TrueValue()}, + {"false", FieldValue::FalseValue()}}), + clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); } TEST(FieldValue, Move) { @@ -113,6 +343,48 @@ TEST(FieldValue, Move) { clone = FieldValue::NullValue(); EXPECT_EQ(FieldValue::NullValue(), clone); + FieldValue nan_value = FieldValue::NanValue(); + clone = std::move(nan_value); + EXPECT_EQ(FieldValue::NanValue(), clone); + clone = FieldValue::NullValue(); + EXPECT_EQ(FieldValue::NullValue(), clone); + + FieldValue integer_value = FieldValue::IntegerValue(1L); + clone = std::move(integer_value); + EXPECT_EQ(FieldValue::IntegerValue(1L), clone); + clone = FieldValue::NullValue(); + EXPECT_EQ(FieldValue::NullValue(), clone); + + FieldValue double_value = FieldValue::DoubleValue(1.0); + clone = std::move(double_value); + EXPECT_EQ(FieldValue::DoubleValue(1.0), clone); + clone = FieldValue::NullValue(); + EXPECT_EQ(FieldValue::NullValue(), clone); + + const FieldValue timestamp_value = FieldValue::TimestampValue({100, 200}); + clone = std::move(timestamp_value); + EXPECT_EQ(FieldValue::TimestampValue({100, 200}), clone); + clone = FieldValue::NullValue(); + EXPECT_EQ(FieldValue::NullValue(), clone); + + FieldValue string_value = FieldValue::StringValue("abc"); + clone = std::move(string_value); + EXPECT_EQ(FieldValue::StringValue("abc"), clone); + clone = FieldValue::NullValue(); + EXPECT_EQ(FieldValue::NullValue(), clone); + + const 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}); + clone = std::move(geo_point_value); + EXPECT_EQ(FieldValue::GeoPointValue({1, 2}), clone); + clone = null_value; + EXPECT_EQ(FieldValue::NullValue(), clone); + FieldValue array_value = FieldValue::ArrayValue(std::vector{ FieldValue::TrueValue(), FieldValue::FalseValue()}); clone = std::move(array_value); @@ -121,15 +393,41 @@ TEST(FieldValue, Move) { clone); clone = FieldValue::NullValue(); EXPECT_EQ(FieldValue::NullValue(), clone); + + FieldValue object_value = + FieldValue::ObjectValue(std::map{ + {"true", FieldValue::TrueValue()}, + {"false", FieldValue::FalseValue()}}); + clone = std::move(object_value); + EXPECT_EQ( + FieldValue::ObjectValue(std::map{ + {"true", FieldValue::TrueValue()}, + {"false", 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 number_value = FieldValue::NanValue(); + 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 FieldValue geo_point_value = FieldValue::GeoPointValue({1, 2}); const FieldValue array_value = FieldValue::ArrayValue(std::vector()); + const FieldValue object_value = + FieldValue::ObjectValue(std::map()); EXPECT_TRUE(null_value < true_value); - EXPECT_TRUE(true_value < array_value); + EXPECT_TRUE(true_value < number_value); + 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(geo_point_value < array_value); + EXPECT_TRUE(array_value < object_value); } TEST(FieldValue, CompareWithOperator) { diff --git a/Firestore/core/test/firebase/firestore/model/timestamp_test.cc b/Firestore/core/test/firebase/firestore/model/timestamp_test.cc new file mode 100644 index 0000000..55ee378 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/timestamp_test.cc @@ -0,0 +1,49 @@ +/* + * 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/timestamp.h" + +#include + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +TEST(Timestamp, Getter) { + const Timestamp timestamp_zero; + EXPECT_EQ(0, timestamp_zero.seconds()); + EXPECT_EQ(0, timestamp_zero.nanos()); + + const Timestamp timestamp(100, 200); + EXPECT_EQ(100, timestamp.seconds()); + EXPECT_EQ(200, timestamp.nanos()); + + const Timestamp timestamp_now = Timestamp::Now(); + EXPECT_LT(0, timestamp_now.seconds()); + EXPECT_LE(0, timestamp_now.nanos()); +} + +TEST(Timestamp, Comparison) { + EXPECT_TRUE(Timestamp() < Timestamp(1, 2)); + EXPECT_TRUE(Timestamp(1, 2) < Timestamp(2, 1)); + EXPECT_TRUE(Timestamp(2, 1) < Timestamp(2, 2)); +} + +} // namespace model +} // namespace firestore +} // namespace firebase -- cgit v1.2.3