mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
tests/sys/snprintf: Test format specifiers
This adds a simple test applications that runs snprintf on standard format specifiers and compares the output with the expected output. The assumption is that internally every stdio implementation uses the same formatting code for each member of the printf functions family, so testing snprintf only is sufficient.
This commit is contained in:
parent
326e9c35ac
commit
a8ffaeb67b
7
tests/sys/snprintf/Makefile
Normal file
7
tests/sys/snprintf/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
include ../Makefile.sys_common
|
||||
|
||||
# avrlibc's snprintf doesn't support uint64_t / int64_t and even fails
|
||||
# to compile due to PRI*64 macros not being defined
|
||||
FEATURES_BLACKLIST := arch_avr8
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
4
tests/sys/snprintf/Makefile.board.dep
Normal file
4
tests/sys/snprintf/Makefile.board.dep
Normal file
@ -0,0 +1,4 @@
|
||||
# newlib's printf is known to be incomplete, despite being bloated
|
||||
ifneq (,$(filter newlib,$(USEMODULE)))
|
||||
USEPKG += mpaland-printf
|
||||
endif
|
6
tests/sys/snprintf/README.md
Normal file
6
tests/sys/snprintf/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# snprintf
|
||||
|
||||
This test aims to test if the stdio implementations correctly implements
|
||||
standard format specifiers. Instead of relying on the transport of stdout to
|
||||
be fast and reliable, it will use snprintf to format in-memory and compare
|
||||
in the app with correctness.
|
291
tests/sys/snprintf/main.c
Normal file
291
tests/sys/snprintf/main.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Marian Buschsieweke
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief snprintf test (correctness of standard format specifier
|
||||
* implementation)
|
||||
*
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool failed = false;
|
||||
|
||||
static void check(const char *expected, const char *got, int retval)
|
||||
{
|
||||
if (retval != (int)strlen(expected)) {
|
||||
failed = true;
|
||||
printf("snprintf() returned %d, but expected %u\n",
|
||||
retval, (unsigned)strlen(expected));
|
||||
}
|
||||
|
||||
if (strcmp(expected, got) != 0) {
|
||||
printf("Expected: \"%s\"\n"
|
||||
"Got: \"%s\"\n",
|
||||
expected, got);
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_int8(void)
|
||||
{
|
||||
static uint8_t u8 = 10;
|
||||
static int8_t s8 = -3;
|
||||
|
||||
/* memory barrier to prevent the compiler from constant folding on the
|
||||
* snprintf calls */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIu8, u8);
|
||||
check("10", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIx8, u8);
|
||||
check("a", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIx8, u8);
|
||||
check("0xa", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIX8, u8);
|
||||
check("A", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIX8, u8);
|
||||
check("0XA", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIo8, u8);
|
||||
check("12", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIo8, u8);
|
||||
check("012", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRId8, s8);
|
||||
check("-3", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIi8, s8);
|
||||
check("-3", buf, len);
|
||||
}
|
||||
|
||||
static void test_int16(void)
|
||||
{
|
||||
static uint16_t u16 = 45054;
|
||||
static int16_t s16 = -1337;
|
||||
|
||||
/* memory barrier to prevent the compiler from constant folding on the
|
||||
* snprintf calls */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIu16, u16);
|
||||
check("45054", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIx16, u16);
|
||||
check("affe", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIx16, u16);
|
||||
check("0xaffe", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIX16, u16);
|
||||
check("AFFE", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIX16, u16);
|
||||
check("0XAFFE", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIo16, u16);
|
||||
check("127776", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIo16, u16);
|
||||
check("0127776", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRId16, s16);
|
||||
check("-1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIi16, s16);
|
||||
check("-1337", buf, len);
|
||||
}
|
||||
|
||||
static void test_int32(void)
|
||||
{
|
||||
static uint32_t u32 = 2952663863;
|
||||
static int32_t s32 = -2147483648;
|
||||
|
||||
/* memory barrier to prevent the compiler from constant folding on the
|
||||
* snprintf calls */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIu32, u32);
|
||||
check("2952663863", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIx32, u32);
|
||||
check("affe1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIx32, u32);
|
||||
check("0xaffe1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIX32, u32);
|
||||
check("AFFE1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIX32, u32);
|
||||
check("0XAFFE1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIo32, u32);
|
||||
check("25777411467", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIo32, u32);
|
||||
check("025777411467", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRId32, s32);
|
||||
check("-2147483648", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIi32, s32);
|
||||
check("-2147483648", buf, len);
|
||||
}
|
||||
|
||||
static void test_int64(void)
|
||||
{
|
||||
static uint64_t u64 = 16045690984050070327ULL;
|
||||
static int64_t s64 = -9223372036854775807LL;
|
||||
|
||||
/* memory barrier to prevent the compiler from constant folding on the
|
||||
* snprintf calls */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIu64, u64);
|
||||
check("16045690984050070327", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIx64, u64);
|
||||
check("deadbeefaffe1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIx64, u64);
|
||||
check("0xdeadbeefaffe1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIX64, u64);
|
||||
check("DEADBEEFAFFE1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIX64, u64);
|
||||
check("0XDEADBEEFAFFE1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIo64, u64);
|
||||
check("1572555756765777411467", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%#" PRIo64, u64);
|
||||
check("01572555756765777411467", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRId64, s64);
|
||||
check("-9223372036854775807", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%" PRIi64, s64);
|
||||
check("-9223372036854775807", buf, len);
|
||||
}
|
||||
|
||||
static void test_size(void)
|
||||
{
|
||||
static size_t s = 42;
|
||||
static ssize_t ss = -1;
|
||||
static ptrdiff_t p = 1337;
|
||||
|
||||
/* memory barrier to prevent the compiler from constant folding on the
|
||||
* snprintf calls */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%zu", s);
|
||||
check("42", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%zd", ss);
|
||||
check("-1", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%td", p);
|
||||
check("1337", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%tu", p);
|
||||
check("1337", buf, len);
|
||||
}
|
||||
|
||||
static void test_flags_widths(void)
|
||||
{
|
||||
static uint16_t u16 = 42;
|
||||
static int16_t s16 = -42;
|
||||
|
||||
/* memory barrier to prevent the compiler from constant folding on the
|
||||
* snprintf calls */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%03" PRIu16, u16);
|
||||
check("042", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%3" PRIu16, u16);
|
||||
check(" 42", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%-3" PRIu16, u16);
|
||||
check("42 ", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%*" PRIu16, 8, u16);
|
||||
check(" 42", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%-*" PRIu16, 8, u16);
|
||||
check("42 ", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%+" PRId16, (int16_t)u16);
|
||||
check("+42", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%04" PRId16, s16);
|
||||
check("-042", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%4" PRId16, s16);
|
||||
check(" -42", buf, len);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%-4" PRId16, s16);
|
||||
check("-42 ", buf, len);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Testing snprintf() implementation...");
|
||||
test_int8();
|
||||
test_int16();
|
||||
test_int32();
|
||||
test_int64();
|
||||
test_size();
|
||||
test_flags_widths();
|
||||
|
||||
if (failed) {
|
||||
puts("TEST FAILED!");
|
||||
}
|
||||
else {
|
||||
puts("Test succeeded");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
21
tests/sys/snprintf/tests/01-run.py
Executable file
21
tests/sys/snprintf/tests/01-run.py
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2024 Marian Buschsieweke
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
|
||||
# @author Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
child.expect_exact("Testing snprintf() implementation...")
|
||||
child.expect_exact("Test succeeded")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
Loading…
Reference in New Issue
Block a user