[FXCRT] Add unit tests for FXSYS_round()

There were none before, now there can be some.  This exposes an issue at
the edges of the integer range, where a float larger than the maximum
value of a signed 32 bit integer returns a value of the maximum negative
integer.

Bug: chromium:611744
Change-Id: Iad8551a17cac69f2078943bbf80d1211883ae974
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/60450
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/fx_system_unittest.cpp b/core/fxcrt/fx_system_unittest.cpp
index d32c8e2..83ac625 100644
--- a/core/fxcrt/fx_system_unittest.cpp
+++ b/core/fxcrt/fx_system_unittest.cpp
@@ -74,6 +74,57 @@
 
 }  // namespace
 
+TEST(fxcrt, FXSYS_round) {
+  EXPECT_EQ(0, FXSYS_round(0.0f));
+  EXPECT_EQ(0, FXSYS_round(-0.0f));
+  EXPECT_EQ(0, FXSYS_round(0.00001f));
+  EXPECT_EQ(0, FXSYS_round(-0.00001f));
+  EXPECT_EQ(3, FXSYS_round(3.14159f));
+  EXPECT_EQ(4, FXSYS_round(3.5f));
+
+  // Check for smallest non-zero float values.
+  EXPECT_EQ(0, FXSYS_round(std::numeric_limits<float>::min()));
+  EXPECT_EQ(0, FXSYS_round(-std::numeric_limits<float>::min()));
+
+  // Function is a wrapper around standard C library function round(), so
+  // returns the integral value that is nearest to x, with halfway cases
+  // rounded away from zero.
+  EXPECT_EQ(-3, FXSYS_round(-3.14159f));
+  EXPECT_EQ(-4, FXSYS_round(-3.5f));
+
+  // Positive rounding stops at maximum int.
+  // MAX_INT=0x7FFFFFFF=2147483647=2.147483647e+9
+  // In IEEE-754 format, 2^31 yields exponent of 0x9E with mantissa of all
+  // zeroes which is 0x4f000000=2.14748365e+9, which is beyond max integer.
+  // Going to next smallest float by minus one from exponent and mantissa of
+  // all ones yields binary float representation of 0x4EFFFFFF=2.14748352e+9,
+  // which is 2147483520.
+  EXPECT_EQ(2147483520, FXSYS_round(2.14748352e+9f));
+
+  // Using a slightly larger value, expect to see it be capped at MAX_INT.
+  // Instead erroneously seeing a return of MIN_INT.  crbug.com/611744
+  EXPECT_EQ(-2147483648, FXSYS_round(2.14748365e+9f));
+
+  EXPECT_EQ(2147483647, FXSYS_round(2.14748365e+10f));
+  EXPECT_EQ(2147483647, FXSYS_round(std::numeric_limits<float>::max()));
+
+  // Negative rounding stops at minimum int.
+  // MIN_INT=0x80000000=-2147483648,=-2.147483648e+9
+  // In IEEE-754 format, 2^31 yields exponent of 0x9E with mantissa of all
+  // zeroes which is 0x4f000000=2.14748365e+9, and the sign bit set, which
+  // is 0xCF000000 and exactly matches the minimum integer.  Going to next
+  // smallest negative float by minus one from exponent and mantissa of all
+  // ones yields binary float representation of 0xCEFFFFFF=-2.14748352e+9,
+  // which is -2147483520.
+  EXPECT_EQ(-2147483648, FXSYS_round(-2.147483648e+10f));
+  EXPECT_EQ(-2147483648, FXSYS_round(-2.147483648e+9f));
+  EXPECT_EQ(-2147483520, FXSYS_round(-2.14748352e+9f));
+  EXPECT_EQ(-2147483648, FXSYS_round(-std::numeric_limits<float>::max()));
+
+  // NaN should give zero.
+  EXPECT_EQ(0, FXSYS_round(NAN));
+}
+
 TEST(fxcrt, FXSYS_itoa_InvalidRadix) {
   char buf[32];