From b1fa08a975b326b59e9a511aff062e34a456f236 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 29 Mar 2018 18:27:11 -0400 Subject: C++ migration: fix some Timestamp tests failing on Linux. (#999) Some Timestamp tests check that constructor fails if given values beyond the supported (pretty wide) range. In case Timestamp is created from chrono::time_point, the time_point's underlying duration is implementation-defined and may overflow when tests try to set it to a value beyond Timestamp supported range. To work around this, make these tests not run if time_point cannot represent boundary values on this platform. For example, on OS X, time_point has microseconds precision, so the tests may run, but on Linux, time_point has nanoseconds precision, which would overflow. --- .../core/test/firebase/firestore/timestamp_test.cc | 41 ++++++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'Firestore/core/test') diff --git a/Firestore/core/test/firebase/firestore/timestamp_test.cc b/Firestore/core/test/firebase/firestore/timestamp_test.cc index a4edcdf..e7e8587 100644 --- a/Firestore/core/test/firebase/firestore/timestamp_test.cc +++ b/Firestore/core/test/firebase/firestore/timestamp_test.cc @@ -33,6 +33,23 @@ using Ms = std::chrono::milliseconds; const auto kUpperBound = 253402300800L - 1; const auto kLowerBound = -62135596800L; +// For near-bounds tests that use , it's important to only run them if +// system_clock::duration can represent values this large (e.g., on Linux, it's +// system_clock::duration uses nanoseconds precision and thus would overflow +// trying to represent very large numbers). +bool CanSystemClockDurationHold(const Sec seconds) { + namespace chr = std::chrono; + if (seconds.count() >= 0) { + const auto max_seconds = + chr::duration_cast(TimePoint::duration::max()).count(); + return max_seconds >= seconds.count(); + } else { + const auto min_seconds = + chr::duration_cast(TimePoint::duration::min()).count(); + return min_seconds <= seconds.count(); + } +} + } // namespace TEST(Timestamp, Constructors) { @@ -128,10 +145,12 @@ TEST(Timestamp, FromChronoNegativeTime) { EXPECT_EQ(0, positive_time_negative_fraction.seconds()); EXPECT_EQ(456000000, positive_time_negative_fraction.nanoseconds()); - const auto near_bounds = - Timestamp::FromTimePoint(TimePoint{Sec(kUpperBound + 1) + Ms(-544)}); - EXPECT_EQ(kUpperBound, near_bounds.seconds()); - EXPECT_EQ(456000000, near_bounds.nanoseconds()); + if (CanSystemClockDurationHold(Sec(kUpperBound + 1))) { + const auto near_bounds = + Timestamp::FromTimePoint(TimePoint{Sec(kUpperBound + 1) + Ms(-544)}); + EXPECT_EQ(kUpperBound, near_bounds.seconds()); + EXPECT_EQ(456000000, near_bounds.nanoseconds()); + } } TEST(Timestamp, ToChrono) { @@ -255,10 +274,18 @@ TEST(Timestamp, InvalidArguments) { // Seconds beyond supported range. ASSERT_ANY_THROW(Timestamp(kLowerBound - 1, 0)); ASSERT_ANY_THROW(Timestamp(kUpperBound + 1, 0)); +} - // Using chrono. - ASSERT_ANY_THROW(Timestamp::FromTimePoint(TimePoint{Sec(kLowerBound - 1)})); - ASSERT_ANY_THROW(Timestamp::FromTimePoint(TimePoint{Sec(kUpperBound + 1)})); +TEST(Timestamp, InvalidArgumentsChrono) { + // Make sure Timestamp doesn't accept values beyond the supported range, if + // system clock-based time_point on this platform can represent values this + // large. + if (CanSystemClockDurationHold(Sec(kUpperBound + 1))) { + ASSERT_ANY_THROW(Timestamp::FromTimePoint(TimePoint{Sec(kUpperBound + 1)})); + } + if (CanSystemClockDurationHold(Sec(kLowerBound - 1))) { + ASSERT_ANY_THROW(Timestamp::FromTimePoint(TimePoint{Sec(kLowerBound - 1)})); + } } TEST(Timestamp, ToString) { -- cgit v1.2.3