Fix sscanf/wcstod parsing of NaNs.

The parsefloat routines -- which let us pass NaNs and infinities on to
strto(f|d|ld) -- come from NetBSD.

Also fix LP64's strtold to return a NaN, and fix all the architectures
to return quiet NaNs.

Also fix wcstof/wcstod/wcstold to use parsefloat so they support hex
floats.

Lots of new tests.

Bug: http://b/31101647
Change-Id: Id7d46ac2d8acb8770b5e8c445e87cfabfde6f111
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 000dc98..db51c08 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -22,6 +22,8 @@
 #include <stdint.h>
 #include <wchar.h>
 
+#include "math_data_test.h"
+
 #define NUM_WCHARS(num_bytes) ((num_bytes)/sizeof(wchar_t))
 
 TEST(wchar, sizeof_wchar_t) {
@@ -389,14 +391,6 @@
   ASSERT_EQ('\x20', *invalid);
 }
 
-TEST(wchar, wcstod) {
-  ASSERT_DOUBLE_EQ(1.23, wcstod(L"1.23", NULL));
-}
-
-TEST(wchar, wcstof) {
-  ASSERT_FLOAT_EQ(1.23f, wcstof(L"1.23", NULL));
-}
-
 TEST(wchar, wcstol) {
   ASSERT_EQ(123L, wcstol(L"123", NULL, 0));
 }
@@ -405,10 +399,6 @@
   ASSERT_EQ(123LL, wcstol(L"123", NULL, 0));
 }
 
-TEST(wchar, wcstold) {
-  ASSERT_DOUBLE_EQ(1.23L, wcstold(L"1.23", NULL));
-}
-
 TEST(wchar, wcstoul) {
   ASSERT_EQ(123UL, wcstoul(L"123", NULL, 0));
 }
@@ -672,3 +662,64 @@
   wchar_t dst[6];
   ASSERT_EQ(&dst[4], wmempcpy(dst, L"hello", 4));
 }
+
+template <typename T>
+static void CheckWcsToFloat(T fn(const wchar_t* s, wchar_t** end)) {
+  FpUlpEq<0, T> pred;
+
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"9.0", nullptr));
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0.9e1", nullptr));
+  EXPECT_PRED_FORMAT2(pred, 9.0, fn(L"0x1.2p3", nullptr));
+
+  EXPECT_TRUE(isnan(fn(L"+nan", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"nan", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"-nan", nullptr)));
+
+  EXPECT_TRUE(isnan(fn(L"+nan(0xff)", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"nan(0xff)", nullptr)));
+  EXPECT_TRUE(isnan(fn(L"-nan(0xff)", nullptr)));
+
+  wchar_t* p;
+  EXPECT_TRUE(isnan(fn(L"+nanny", &p)));
+  EXPECT_STREQ(L"ny", p);
+  EXPECT_TRUE(isnan(fn(L"nanny", &p)));
+  EXPECT_STREQ(L"ny", p);
+  EXPECT_TRUE(isnan(fn(L"-nanny", &p)));
+  EXPECT_STREQ(L"ny", p);
+
+  EXPECT_EQ(0, fn(L"muppet", &p));
+  EXPECT_STREQ(L"muppet", p);
+  EXPECT_EQ(0, fn(L"  muppet", &p));
+  EXPECT_STREQ(L"  muppet", p);
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+inf", nullptr));
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"inf", nullptr));
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-inf", nullptr));
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+infinity", nullptr));
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"infinity", nullptr));
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-infinity", nullptr));
+
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"+infinitude", &p));
+  EXPECT_STREQ(L"initude", p);
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"infinitude", &p));
+  EXPECT_STREQ(L"initude", p);
+  EXPECT_EQ(-std::numeric_limits<T>::infinity(), fn(L"-infinitude", &p));
+  EXPECT_STREQ(L"initude", p);
+
+  // Check case-insensitivity.
+  EXPECT_EQ(std::numeric_limits<T>::infinity(), fn(L"InFiNiTy", nullptr));
+  EXPECT_TRUE(isnan(fn(L"NaN", nullptr)));
+}
+
+TEST(wchar, wcstod) {
+  CheckWcsToFloat(wcstod);
+}
+
+TEST(wchar, wcstof) {
+  CheckWcsToFloat(wcstof);
+}
+
+TEST(wchar, wcstold) {
+  CheckWcsToFloat(wcstold);
+}