Просмотр исходного кода

stdio: add tests for FP printf formats

Test %[aAeEfFgG] with various flags/width/precision settings.
Separate tests for %[aA] support for which is optional from the
remaining formats.
Don't dump the formatted output by default because it's huge, only
calculate CRC32 of it and print it as a test result. Build the test with
the `DEBUG` macro defined to see the full output.

Included *.out.good files correspond to the uClibc-ng version with
applied fixes for the %a.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Max Filippov 2 дней назад
Родитель
Сommit
e05666807a

+ 2 - 0
test/stdio/Makefile.in

@@ -6,3 +6,5 @@ DODIFF_64bit := 1
 ifeq ($(UCLIBC_HAS_GLIBC_CUSTOM_STREAMS),)
 TESTS_DISABLED += tst-fmemopen
 endif
+
+TESTS_DISABLED += printf_fp

+ 25 - 0
test/stdio/printf_a.c

@@ -0,0 +1,25 @@
+#include "printf_fp.c"
+
+int main()
+{
+	const double v[] = {
+		-NAN,
+		-INFINITY,
+		-0x1.1p40,
+		-2.75,
+		-1,
+		-9 / 1024.,
+		0,
+		9 / 1024.,
+		1,
+		0x1.23456789abcdep0,
+		0x1.f8p0,
+		2.75,
+		0x1.1p40,
+		INFINITY,
+		NAN,
+	};
+
+	test_float("aA", v, ARRAY_SIZE(v));
+	return 0;
+}

+ 1 - 0
test/stdio/printf_a.out.good

@@ -0,0 +1 @@
+CRC = 0x5797c255

+ 24 - 0
test/stdio/printf_efg.c

@@ -0,0 +1,24 @@
+#include "printf_fp.c"
+
+int main()
+{
+	const double v[] = {
+		-NAN,
+		-INFINITY,
+		-0x1.1p29,
+		-2.75,
+		-1,
+		-7 / 64.,
+		0,
+		7 / 64.,
+		1,
+		0x1.f8p0,
+		2.75,
+		0x1.1p29,
+		INFINITY,
+		NAN,
+	};
+
+	test_float("eEfFgG", v, ARRAY_SIZE(v));
+	return 0;
+}

+ 1 - 0
test/stdio/printf_efg.out.good

@@ -0,0 +1 @@
+CRC = 0x52f6dd6b

+ 127 - 0
test/stdio/printf_fp.c

@@ -0,0 +1,127 @@
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#define ARRAY_SIZE(A) (sizeof(A) / sizeof(*(A)))
+#define FIELD(B, code) (((code) / BASE_##B) % VARS_##B)
+
+#define BASE_0 1
+#define VARS_0 2
+
+#define BASE_1 (BASE_0 * VARS_0)
+#define VARS_1 2
+
+#define BASE_2 (BASE_1 * VARS_1)
+#define VARS_2 2
+
+#define BASE_3 (BASE_2 * VARS_2)
+#define VARS_3 2
+
+#define BASE_4 (BASE_3 * VARS_3)
+#define VARS_4 2
+
+#define BASE_5 (BASE_4 * VARS_4)
+#define VARS_5 3
+
+#define BASE_6 (BASE_5 * VARS_5)
+#define VARS_6 5
+
+#define N_CODES (BASE_6 * VARS_6)
+
+
+/*
+ *   0  1  2  3  4  5      6          7
+ * %[#][0][-][ ][+][width][.precision]conversion
+ *
+ * 0, 1, 2, 3, 4: bit flags
+ * 5: absent/narrow/wide
+ * 6: absent/'.' is present, precision is absent/zero/small/big
+ */
+static void make_format(char *fmt, int code, char conv)
+{
+	*fmt++ = '%';
+	if (FIELD(0, code))
+		*fmt++ = '#';
+	if (FIELD(1, code))
+		*fmt++ = '0';
+	if (FIELD(2, code))
+		*fmt++ = '-';
+	if (FIELD(3, code))
+		*fmt++ = ' ';
+	if (FIELD(4, code))
+		*fmt++ = '+';
+	switch (FIELD(5, code)) {
+	case 0:
+		break;
+	case 1:
+		*fmt++ = '1';
+		break;
+	case 2:
+		*fmt++ = '4';
+		*fmt++ = '0';
+		break;
+	}
+	if (FIELD(6, code))
+		*fmt++ = '.';
+	switch (FIELD(6, code)) {
+	case 0:
+	case 1:
+		break;
+	case 2:
+		*fmt++ = '0';
+		break;
+	case 3:
+		*fmt++ = '1';
+		break;
+	case 4:
+		*fmt++ = '2';
+		*fmt++ = '0';
+		break;
+	}
+	*fmt++ = conv;
+	*fmt++ = 0;
+}
+
+
+#define CRC32_POLY 0xedb88320
+
+static inline uint32_t crc32(uint32_t crc, const void *p, size_t sz)
+{
+	const uint8_t *data = p;
+
+	while (sz --> 0) {
+		crc ^= *data++;
+		for (int i = 0; i < 8; ++i) {
+			if (crc & 1)
+				crc = (crc >> 1) ^ CRC32_POLY;
+			else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+static void test_float(const char *conv, const double v[], int n)
+{
+	uint32_t crc = 0xffffffff;
+
+	for (int i = 0; conv[i]; ++i) {
+		for (int code = 0; code < N_CODES; ++code) {
+			char fmt[20];
+			char out[256];
+
+			make_format(fmt, code, conv[i]);
+			crc = crc32(crc, fmt, strlen(fmt));
+			for (int j = 0; j < n; ++j) {
+				snprintf(out, sizeof(out), fmt, v[j]);
+				crc = crc32(crc, out, strlen(out));
+#ifdef DEBUG
+				printf("%-20s -> %s\n", fmt, out);
+#endif
+			}
+		}
+	}
+	printf("CRC = %#010" PRIx32 "\n", crc);
+}