Bug 1686831 - Hook glibc printf tests in TestPrintf.cpp. r=nika,mhoye

It is worth noting that some of these tests fail on Windows for rounding
difference reasons (see later commit from this bug for more details),
and on both Windows and mac for differences in formatting for INFINITY
and NAN. All the tests pass on Linux (since the underlying printf is
currently glibc's).

Differential Revision: https://phabricator.services.mozilla.com/D103133
This commit is contained in:
Mike Hommey 2021-01-27 23:10:02 +00:00
parent c776e2a4de
commit ba38386d81

View File

@ -7,8 +7,31 @@
#include "mozilla/Printf.h" #include "mozilla/Printf.h"
#include <cfloat> #include <cfloat>
#include <cmath>
#include <stdarg.h> #include <stdarg.h>
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wc++11-narrowing"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnarrowing"
#endif
namespace tiformat {
#include "glibc_printf_tests/tiformat.c"
}
namespace tllformat {
#include "glibc_printf_tests/tllformat.c"
}
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
namespace tfformat {
#include "glibc_printf_tests/tfformat.c"
}
// A simple implementation of PrintfTarget, just for testing // A simple implementation of PrintfTarget, just for testing
// PrintfTarget::print. // PrintfTarget::print.
class TestPrintfTarget : public mozilla::PrintfTarget { class TestPrintfTarget : public mozilla::PrintfTarget {
@ -42,16 +65,17 @@ static void TestPrintfTargetPrint() {
checker.print("test string"); checker.print("test string");
} }
static bool MOZ_FORMAT_PRINTF(4, 5) static bool MOZ_FORMAT_PRINTF(5, 6)
check_print(const char* file, int line, const char* expect, const char* fmt, check_print(const char* file, int line,
...) { bool (*cmp)(const char* a, const char* b), const char* expect,
const char* fmt, ...) {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
mozilla::SmprintfPointer output = mozilla::Vsmprintf(fmt, ap); mozilla::SmprintfPointer output = mozilla::Vsmprintf(fmt, ap);
va_end(ap); va_end(ap);
bool ret = output && !strcmp(output.get(), expect); bool ret = output && cmp(output.get(), expect);
if (!ret && strcmp(expect, "ignore") != 0) { if (!ret && strcmp(expect, "ignore") != 0) {
printf("(actual) \"%s\" != (expected) \"%s\" (%s:%d)\n", output.get(), printf("(actual) \"%s\" != (expected) \"%s\" (%s:%d)\n", output.get(),
expect, file, line); expect, file, line);
@ -59,7 +83,13 @@ static bool MOZ_FORMAT_PRINTF(4, 5)
return ret; return ret;
} }
#define print_one(...) check_print(__FILE__, __LINE__, __VA_ARGS__) bool str_match(const char* a, const char* b) { return !strcmp(a, b); }
bool approx_match(const char* a, const char* b) {
return tfformat::matches(const_cast<char*>(a), b);
}
#define print_one(...) check_print(__FILE__, __LINE__, str_match, __VA_ARGS__)
static const char* zero() { return nullptr; } static const char* zero() { return nullptr; }
@ -159,6 +189,49 @@ static void TestPrintfFormats() {
print_one("7799 9977", "%2$zu %1$zu", (size_t)9977, (size_t)7799)); print_one("7799 9977", "%2$zu %1$zu", (size_t)9977, (size_t)7799));
} }
template <typename T, size_t N>
static void TestGlibcPrintf(T (&test_cases)[N], const char* file,
bool (*cmp)(const char* a, const char* b)) {
bool ok = true;
char fmt2[40];
for (auto& line : test_cases) {
// mozilla::PrintfTarget doesn't support the `#` flag character or the
// `a` conversion specifier.
if (!line.line || strchr(line.format_string, '#') ||
strchr(line.format_string, 'a')) {
continue;
}
// Derive the format string in the test case to add "2$" in the specifier
// (transforming e.g. "%f" into "%2$f"), and append "%1$.0d".
// The former will make the format string take the `line.value` as the
// second argument, and the latter will make the first argument formatted
// with no precision. We'll pass 0 as the first argument, such that the
// formatted value for it is "", which means the expected result string
// is still the same.
MOZ_RELEASE_ASSERT(sizeof(fmt2) > strlen(line.format_string) + 8);
const char* percent = strchr(line.format_string, '%');
MOZ_RELEASE_ASSERT(percent);
size_t percent_off = percent - line.format_string;
memcpy(fmt2, line.format_string, percent_off + 1);
memcpy(fmt2 + percent_off + 1, "2$", 2);
strcpy(fmt2 + percent_off + 3, percent + 1);
strcat(fmt2, "%1$.0d");
int l = line.line;
const char* res = line.result;
const char* fmt = line.format_string;
if (strchr(line.format_string, 'I')) {
ok = check_print(file, l, cmp, res, fmt, (size_t)line.value) && ok;
ok = check_print(file, l, cmp, res, fmt2, 0, (size_t)line.value) && ok;
} else {
ok = check_print(file, l, cmp, res, fmt, line.value) && ok;
ok = check_print(file, l, cmp, res, fmt2, 0, line.value) && ok;
}
}
MOZ_RELEASE_ASSERT(ok);
}
#if defined(XP_WIN) #if defined(XP_WIN)
int wmain() int wmain()
#else #else
@ -167,6 +240,9 @@ int main()
{ {
TestPrintfFormats(); TestPrintfFormats();
TestPrintfTargetPrint(); TestPrintfTargetPrint();
TestGlibcPrintf(tiformat::sprint_ints, "tiformat.c", str_match);
TestGlibcPrintf(tllformat::sprint_ints, "tllformat.c", str_match);
TestGlibcPrintf(tfformat::sprint_doubles, "tfformat.c", approx_match);
return 0; return 0;
} }