363 changes: 363 additions & 0 deletions libc/test/src/stdio/sscanf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/limits.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PlatformDefs.h"

#include "src/stdio/sscanf.h"

#include <stdio.h> // For EOF

#include "utils/UnitTest/FPMatcher.h"
#include "utils/UnitTest/Test.h"

TEST(LlvmLibcSScanfTest, SimpleStringConv) {
Expand Down Expand Up @@ -209,6 +213,365 @@ TEST(LlvmLibcSScanfTest, IntConvNoWriteTests) {
EXPECT_EQ(result, 0);
}

TEST(LlvmLibcSScanfTest, FloatConvSimple) {
int ret_val;
float result = 0;

float inf = __llvm_libc::fputil::FPBits<float>::inf().get_val();
float nan = __llvm_libc::fputil::FPBits<float>::build_nan(1);

ret_val = __llvm_libc::sscanf("123", "%f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 123.0);

ret_val = __llvm_libc::sscanf("456.1", "%a", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 456.1);

ret_val = __llvm_libc::sscanf("0x789.ap0", "%e", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0x789.ap0);

ret_val = __llvm_libc::sscanf("0x.8", "%e", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0x0.8p0);

ret_val = __llvm_libc::sscanf("0x8.", "%e", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0x8.0p0);

ret_val = __llvm_libc::sscanf("+12.0e1", "%g", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 12.0e1);

ret_val = __llvm_libc::sscanf("inf", "%F", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, inf);

ret_val = __llvm_libc::sscanf("NaN", "%A", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, nan);

ret_val = __llvm_libc::sscanf("-InFiNiTy", "%E", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, -inf);

ret_val = __llvm_libc::sscanf("1e10", "%G", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 1e10);

ret_val = __llvm_libc::sscanf(".1", "%G", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.1);

ret_val = __llvm_libc::sscanf("1.", "%G", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 1.0);

ret_val = __llvm_libc::sscanf("0", "%f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("Not a float", "%f", &result);
EXPECT_EQ(ret_val, 0);
}

TEST(LlvmLibcSScanfTest, FloatConvLengthModifier) {
int ret_val;
double d_result = 0;
long double ld_result = 0;

double d_inf = __llvm_libc::fputil::FPBits<double>::inf().get_val();
long double ld_nan = __llvm_libc::fputil::FPBits<long double>::build_nan(1);

ret_val = __llvm_libc::sscanf("123", "%lf", &d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(d_result, 123.0);

ret_val = __llvm_libc::sscanf("456.1", "%La", &ld_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(ld_result, 456.1L);

ret_val = __llvm_libc::sscanf("inf", "%le", &d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(d_result, d_inf);

ret_val = __llvm_libc::sscanf("nan", "%Lg", &ld_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(ld_result, ld_nan);

ret_val = __llvm_libc::sscanf("1e-300", "%lF", &d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(d_result, 1e-300);

ret_val = __llvm_libc::sscanf("1.0e600", "%LA", &ld_result);
EXPECT_EQ(ret_val, 1);
// 1e600 may be larger than the maximum long double (if long double is double).
// In that case both of these should be evaluated as inf.
#ifdef LONG_DOUBLE_IS_DOUBLE
EXPECT_FP_EQ(ld_result, d_inf);
#else
EXPECT_FP_EQ(ld_result, 1.0e600L);
#endif
}

TEST(LlvmLibcSScanfTest, FloatConvLongNumber) {
int ret_val;
float result = 0;
double d_result = 0;

// 32 characters
ret_val =
__llvm_libc::sscanf("123456789012345678901234567890.0", "%f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 123456789012345678901234567890.0f);

// 64 characters
ret_val = __llvm_libc::sscanf(
"123456789012345678901234567890123456789012345678901234567890.000", "%la",
&d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(
d_result,
123456789012345678901234567890123456789012345678901234567890.000);

// 128 characters
ret_val = __llvm_libc::sscanf(
"123456789012345678901234567890123456789012345678901234567890"
"123456789012345678901234567890123456789012345678901234567890.0000000",
"%le", &d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(
d_result,
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.0000000);

// 256 characters
ret_val = __llvm_libc::sscanf("10000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000",
"%lf", &d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(d_result, 1e255);

// 288 characters
ret_val = __llvm_libc::sscanf("10000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000"
"00000000000000000000000000000000",
"%lf", &d_result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(d_result, 1e287);
}

TEST(LlvmLibcSScanfTest, FloatConvComplexParsing) {
int ret_val;
float result = 0;

float inf = __llvm_libc::fputil::FPBits<float>::inf().get_val();
float nan = __llvm_libc::fputil::FPBits<float>::build_nan(1);

ret_val = __llvm_libc::sscanf("0x1.0e3", "%f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0x1.0e3p0);

ret_val = __llvm_libc::sscanf("", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("+", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("-", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("+.", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("-.e+10", "%a", &result);
EXPECT_EQ(ret_val, 0);

// This is a specific example from the standard. Its behavior diverges from
// other implementations that accept "100e" as being the same as "100e0"
ret_val = __llvm_libc::sscanf("100er", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("nah", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("indirection", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("infnan", "%a", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, inf);

ret_val = __llvm_libc::sscanf("naninf", "%a", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, nan);

ret_val = __llvm_libc::sscanf("infinityinfinity", "%a", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, inf);

// For %f to accept a string as representing it has to be either "inf" or
// "infinity" when it stops. It only stops when it encounters a character that
// isn't the next one in the string, so it accepts "infi" as the the longest
// prefix of a possibly valid floating-point number, but determines that it is
// not valid and returns a matching failure. This is because it can only unget
// one character so when it finds that the character after the second 'i' is
// not the next character in "infinity" it can't rewind to the point where it
// had just "inf".
ret_val = __llvm_libc::sscanf("infi", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("infinite", "%a", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("-.1e1", "%f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, -.1e1);

ret_val = __llvm_libc::sscanf("1.2.e1", "%f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 1.2);
}

/*
TODO:
Max width tests
*/

TEST(LlvmLibcSScanfTest, FloatConvMaxWidth) {
int ret_val;
float result = 0;

float inf = __llvm_libc::fputil::FPBits<float>::inf().get_val();

ret_val = __llvm_libc::sscanf("123", "%3f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 123.0);

ret_val = __llvm_libc::sscanf("123", "%5f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 123.0);

ret_val = __llvm_libc::sscanf("456", "%1f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 4.0);

ret_val = __llvm_libc::sscanf("-789", "%1f", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("-123", "%2f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, -1.0);

ret_val = __llvm_libc::sscanf("inf", "%2f", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("nan", "%1f", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("-inf", "%3f", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("-nan", "%3f", &result);
EXPECT_EQ(ret_val, 0);

// If the max length were not here this would fail as discussed above, but
// since the max length limits it to the 3 it succeeds.
ret_val = __llvm_libc::sscanf("infinite", "%3f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, inf);

ret_val = __llvm_libc::sscanf("-infinite", "%4f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, -inf);

ret_val = __llvm_libc::sscanf("01", "%1f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("0x1", "%2f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("100e", "%4f", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("100e+10", "%5f", &result);
EXPECT_EQ(ret_val, 0);

ret_val = __llvm_libc::sscanf("100e10", "%5f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 100e1);
}

TEST(LlvmLibcSScanfTest, FloatConvNoWrite) {
int ret_val;
float result = 0;

ret_val = __llvm_libc::sscanf("123", "%*f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("456.1", "%*a", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("0x789.ap0", "%*e", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("+12.0e1", "%*g", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("inf", "%*F", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("NaN", "%*A", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("-InFiNiTy", "%*E", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("1e10", "%*G", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf(".1", "%*G", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("123", "%*3f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("123", "%*5f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("456", "%*1f", &result);
EXPECT_EQ(ret_val, 1);
EXPECT_FP_EQ(result, 0.0);

ret_val = __llvm_libc::sscanf("Not a float", "%*f", &result);
EXPECT_EQ(ret_val, 0);
}

TEST(LlvmLibcSScanfTest, CombinedConv) {
int ret_val;
int result = 0;
Expand Down