From 39d8252300015c26f1932cff42032613fdb36a09 Mon Sep 17 00:00:00 2001 From: Gil Date: Fri, 19 Jan 2018 12:27:11 -0800 Subject: Port comparison to C++ (#678) This reimplements our comparison functions as C++ Comparators and then provides compatibility shims for interoperating with existing Objective-C usage. A few specialized comparators aren't suitable for porting but only have a single usage (e.g. CompareBytes for comparing NSData * instances). In these cases I've moved them into the caller. * Use int32_t for typeof(ID) in FSTDocumentReference * Migrate callers of FSTComparison.h to Objective-C++ * Port comparison to C++ * Migrate usages of FSTComparison.h to C++ equivalents * Remove FSTComparison --- .../test/firebase/firestore/util/CMakeLists.txt | 1 + .../firebase/firestore/util/comparison_test.cc | 210 +++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 Firestore/core/test/firebase/firestore/util/comparison_test.cc (limited to 'Firestore/core/test/firebase/firestore/util') diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt index 468c62e..5e7612c 100644 --- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt @@ -36,6 +36,7 @@ cc_test( firebase_firestore_util_test SOURCES autoid_test.cc + comparison_test.cc string_printf_test.cc DEPENDS firebase_firestore_util diff --git a/Firestore/core/test/firebase/firestore/util/comparison_test.cc b/Firestore/core/test/firebase/firestore/util/comparison_test.cc new file mode 100644 index 0000000..ecbed4a --- /dev/null +++ b/Firestore/core/test/firebase/firestore/util/comparison_test.cc @@ -0,0 +1,210 @@ +/* + * 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/util/comparison.h" + +#include + +#include + +#include "Firestore/core/src/firebase/firestore/util/string_printf.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace util { + +#define ASSERT_SAME(comparison) \ + do { \ + ASSERT_EQ(ComparisonResult::Same, comparison); \ + } while (0) + +#define ASSERT_ASCENDING(comparison) \ + do { \ + ASSERT_EQ(ComparisonResult::Ascending, comparison); \ + } while (0) + +#define ASSERT_DESCENDING(comparison) \ + do { \ + ASSERT_EQ(ComparisonResult::Descending, comparison); \ + } while (0) + +TEST(Comparison, ReverseOrder) { + ASSERT_ASCENDING(ReverseOrder(ComparisonResult::Descending)); + ASSERT_DESCENDING(ReverseOrder(ComparisonResult::Ascending)); + ASSERT_SAME(ReverseOrder(ComparisonResult::Same)); +} + +TEST(Comparison, StringCompare) { + ASSERT_ASCENDING(Compare("", "a")); + ASSERT_ASCENDING(Compare("a", "b")); + ASSERT_ASCENDING(Compare("a", "aa")); + + ASSERT_DESCENDING(Compare("a", "")); + ASSERT_DESCENDING(Compare("b", "a")); + ASSERT_DESCENDING(Compare("aa", "a")); + + ASSERT_SAME(Compare("", "")); + ASSERT_SAME(Compare("", std::string())); + ASSERT_SAME(Compare("a", "a")); +} + +TEST(Comparison, BooleanCompare) { + ASSERT_SAME(Compare(false, false)); + ASSERT_SAME(Compare(true, true)); + ASSERT_ASCENDING(Compare(false, true)); + ASSERT_DESCENDING(Compare(true, false)); +} + +TEST(Comparison, DoubleCompare) { + ASSERT_SAME(Compare(NAN, NAN)); + ASSERT_ASCENDING(Compare(NAN, 0)); + ASSERT_DESCENDING(Compare(0, NAN)); + + ASSERT_SAME(Compare(-INFINITY, -INFINITY)); + ASSERT_SAME(Compare(INFINITY, INFINITY)); + ASSERT_ASCENDING(Compare(-INFINITY, INFINITY)); + ASSERT_DESCENDING(Compare(INFINITY, -INFINITY)); + + ASSERT_SAME(Compare(0, 0)); + ASSERT_SAME(Compare(-0, -0)); + ASSERT_SAME(Compare(-0, 0)); +} + +#define ASSERT_BIT_EQUALS(expected, actual) \ + do { \ + uint64_t expectedBits = DoubleBits(expected); \ + uint64_t actualBits = DoubleBits(actual); \ + if (expectedBits != actualBits) { \ + std::string message = StringPrintf( \ + "Expected <%f> to compare equal to <%f> " \ + "with bits <%llX> equal to <%llX>", \ + actual, expected, actualBits, expectedBits); \ + FAIL() << message; \ + } \ + } while (0); + +#define ASSERT_MIXED_SAME(doubleValue, longValue) \ + do { \ + ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \ + if (result != ComparisonResult::Same) { \ + std::string message = StringPrintf( \ + "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \ + FAIL() << message; \ + } \ + } while (0); + +#define ASSERT_MIXED_DESCENDING(doubleValue, longValue) \ + do { \ + ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \ + if (result != ComparisonResult::Descending) { \ + std::string message = StringPrintf( \ + "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \ + FAIL() << message; \ + } \ + } while (0); + +#define ASSERT_MIXED_ASCENDING(doubleValue, longValue) \ + do { \ + ComparisonResult result = CompareMixedNumber(doubleValue, longValue); \ + if (result != ComparisonResult::Ascending) { \ + std::string message = StringPrintf( \ + "Expected <%f> to compare equal to <%lld>", doubleValue, longValue); \ + FAIL() << message; \ + } \ + } while (0); + +TEST(Comparison, MixedNumberCompare) { + // Infinities + ASSERT_MIXED_ASCENDING(-INFINITY, LLONG_MIN); + ASSERT_MIXED_ASCENDING(-INFINITY, LLONG_MAX); + ASSERT_MIXED_ASCENDING(-INFINITY, 0LL); + + ASSERT_MIXED_DESCENDING(INFINITY, LLONG_MIN); + ASSERT_MIXED_DESCENDING(INFINITY, LLONG_MAX); + ASSERT_MIXED_DESCENDING(INFINITY, 0LL); + + // NaN + ASSERT_MIXED_ASCENDING(NAN, LLONG_MIN); + ASSERT_MIXED_ASCENDING(NAN, LLONG_MAX); + ASSERT_MIXED_ASCENDING(NAN, 0LL); + + // Large values (note DBL_MIN is positive and near zero). + ASSERT_MIXED_ASCENDING(-DBL_MAX, LLONG_MIN); + + // Tests around LLONG_MIN + ASSERT_BIT_EQUALS((double)LLONG_MIN, -0x1.0p63); + ASSERT_MIXED_SAME(-0x1.0p63, LLONG_MIN); + ASSERT_MIXED_ASCENDING(-0x1.0p63, LLONG_MIN + 1); + + ASSERT_LT(-0x1.0000000000001p63, -0x1.0p63); + ASSERT_MIXED_ASCENDING(-0x1.0000000000001p63, LLONG_MIN); + ASSERT_MIXED_DESCENDING(-0x1.FFFFFFFFFFFFFp62, LLONG_MIN); + + // Tests around LLONG_MAX + // Note LLONG_MAX cannot be exactly represented by a double, so the system + // rounds it to the nearest double, which is 2^63. This number, in turn is + // larger than the maximum representable as a long. + ASSERT_BIT_EQUALS(0x1.0p63, (double)LLONG_MAX); + ASSERT_MIXED_DESCENDING(0x1.0p63, LLONG_MAX); + + // The largest value with an exactly long representation + ASSERT_EQ((int64_t)0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC00LL); + ASSERT_MIXED_SAME(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC00LL); + + ASSERT_MIXED_DESCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFB00LL); + ASSERT_MIXED_DESCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFBFFLL); + ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFC01LL); + ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFFp62, 0x7FFFFFFFFFFFFD00LL); + + ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFEp62, 0x7FFFFFFFFFFFFC00LL); + + // Tests around MAX_SAFE_INTEGER + ASSERT_MIXED_SAME(0x1.FFFFFFFFFFFFFp52, 0x1FFFFFFFFFFFFFLL); + ASSERT_MIXED_DESCENDING(0x1.FFFFFFFFFFFFFp52, 0x1FFFFFFFFFFFFELL); + ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFEp52, 0x1FFFFFFFFFFFFFLL); + ASSERT_MIXED_ASCENDING(0x1.FFFFFFFFFFFFFp52, 0x20000000000000LL); + + // Tests around MIN_SAFE_INTEGER + ASSERT_MIXED_SAME(-0x1.FFFFFFFFFFFFFp52, -0x1FFFFFFFFFFFFFLL); + ASSERT_MIXED_ASCENDING(-0x1.FFFFFFFFFFFFFp52, -0x1FFFFFFFFFFFFELL); + ASSERT_MIXED_DESCENDING(-0x1.FFFFFFFFFFFFEp52, -0x1FFFFFFFFFFFFFLL); + ASSERT_MIXED_DESCENDING(-0x1.FFFFFFFFFFFFFp52, -0x20000000000000LL); + + // Tests around zero. + ASSERT_MIXED_SAME(-0.0, 0LL); + ASSERT_MIXED_SAME(0.0, 0LL); + + // The smallest representable positive value should be greater than zero + ASSERT_MIXED_DESCENDING(DBL_MIN, 0LL); + ASSERT_MIXED_ASCENDING(-DBL_MIN, 0LL); + + // Note that 0x1.0p-1074 is a hex floating point literal representing the + // minimum subnormal number: . + double minSubNormal = 0x1.0p-1074; + ASSERT_MIXED_DESCENDING(minSubNormal, 0LL); + ASSERT_MIXED_ASCENDING(-minSubNormal, 0LL); + + // Other sanity checks + ASSERT_MIXED_ASCENDING(0.5, 1LL); + ASSERT_MIXED_DESCENDING(0.5, 0LL); + ASSERT_MIXED_ASCENDING(1.5, 2LL); + ASSERT_MIXED_DESCENDING(1.5, 1LL); +} + +} // namespace util +} // namespace firestore +} // namespace firebase -- cgit v1.2.3