From 7041066109b9493e434f9cd7bd393e4158fd5b3f Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Fri, 27 May 2022 05:03:05 +0300 Subject: [PATCH] Main: generate tests for printf format parser --- .gitignore | 2 + Makefile.am | 15 ++ common/printf_fmt.yml | 340 +++++++++++++++++++++++++++++++++++++ tests/printf_fmt_gen.jinja | 35 ++++ tests/printf_fmt_gen.py | 59 +++++++ 5 files changed, 451 insertions(+) create mode 100644 common/printf_fmt.yml create mode 100644 tests/printf_fmt_gen.jinja create mode 100644 tests/printf_fmt_gen.py diff --git a/.gitignore b/.gitignore index d9cd26d..8dc0557 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,8 @@ /tests/test_ntoa /tests/test_pfa /tests/test_pfa_assert +/tests/test_printf_fmt_gen +/tests/test_printf_fmt_gen.c /tests/test_printf_gen /tests/test_printf_gen.c /tests/test_units_human diff --git a/Makefile.am b/Makefile.am index 11ff0de..14d86e8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,6 +17,7 @@ libkernaux_a_SOURCES = \ src/libc.c CLEANFILES = \ + tests/test_printf_fmt_gen.c \ tests/test_printf_gen.c if ASM_I386 @@ -143,6 +144,9 @@ libkernaux_a_SOURCES += src/printf_fmt.c if ENABLE_TESTS TESTS += examples/printf_fmt endif +if ENABLE_TESTS_PYTHON +TESTS += tests/test_printf_fmt_gen +endif endif if WITH_UNITS @@ -278,6 +282,14 @@ tests_test_pfa_assert_SOURCES = \ $(libkernaux_a_SOURCES) \ tests/test_pfa_assert.c +tests_test_printf_fmt_gen_SOURCES = \ + $(libkernaux_a_SOURCES) \ + tests/test_printf_fmt_gen.c \ + tests/printf_fmt_gen.py \ + tests/printf_fmt_gen.jinja \ + common/printf.yml \ + common/printf_orig.yml + tests_test_printf_gen_SOURCES = \ $(libkernaux_a_SOURCES) \ tests/test_printf_gen.c \ @@ -290,5 +302,8 @@ tests_test_units_human_SOURCES = \ $(libkernaux_a_SOURCES) \ tests/test_units_human.c +tests/test_printf_fmt_gen.c: tests/printf_fmt_gen.py tests/printf_fmt_gen.jinja common/printf_fmt.yml + python3 tests/printf_fmt_gen.py + tests/test_printf_gen.c: tests/printf_gen.py tests/printf_gen.jinja common/printf.yml common/printf_orig.yml python3 tests/printf_gen.py diff --git a/common/printf_fmt.yml b/common/printf_fmt.yml new file mode 100644 index 0000000..fbd9cab --- /dev/null +++ b/common/printf_fmt.yml @@ -0,0 +1,340 @@ +- in: + format: 's' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: '-s' + width: null + precision: null + out: + flags: [left] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: '+s' + width: null + precision: null + out: + flags: [plus] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: ' s' + width: null + precision: null + out: + flags: [space] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: '#s' + width: null + precision: null + out: + flags: [hash] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: '0s' + width: null + precision: null + out: + flags: [zeropad] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: '123s' + width: null + precision: null + out: + flags: [] + width: 123 + precision: 0 + type: str + base: 0 + +- in: + format: '*s' + width: 123 + precision: null + out: + flags: [] + width: 123 + precision: 0 + type: str + base: 0 + +- in: + format: '.123s' + width: null + precision: null + out: + flags: [precision] + width: 0 + precision: 123 + type: str + base: 0 + +- in: + format: '.*s' + width: null + precision: 123 + out: + flags: [precision] + width: 0 + precision: 123 + type: str + base: 0 + +- in: + format: 'ls' + width: null + precision: null + out: + flags: [long] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: 'lls' + width: null + precision: null + out: + flags: [long, long_long] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: 'hs' + width: null + precision: null + out: + flags: [short] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: 'hhs' + width: null + precision: null + out: + flags: [short, char] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: 'd' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: int + base: 10 + +- in: + format: 'i' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: int + base: 10 + +- in: + format: 'u' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: uint + base: 10 + +- in: + format: 'x' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: uint + base: 16 + +- in: + format: 'X' + width: null + precision: null + out: + flags: [uppercase] + width: 0 + precision: 0 + type: uint + base: 16 + +- in: + format: 'o' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: uint + base: 8 + +- in: + format: 'b' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: uint + base: 2 + +- in: + format: 'f' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: float + base: 0 + +- in: + format: 'F' + width: null + precision: null + out: + flags: [uppercase] + width: 0 + precision: 0 + type: float + base: 0 + +- in: + format: 'e' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: exp + base: 0 + +- in: + format: 'E' + width: null + precision: null + out: + flags: [uppercase] + width: 0 + precision: 0 + type: exp + base: 0 + +- in: + format: 'g' + width: null + precision: null + out: + flags: [adapt_exp] + width: 0 + precision: 0 + type: exp + base: 0 + +- in: + format: 'G' + width: null + precision: null + out: + flags: [adapt_exp, uppercase] + width: 0 + precision: 0 + type: exp + base: 0 + +- in: + format: 'c' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: char + base: 0 + +- in: + format: 's' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: str + base: 0 + +- in: + format: '%' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: percent + base: 0 + +- in: + format: '_' + width: null + precision: null + out: + flags: [] + width: 0 + precision: 0 + type: none + base: 0 diff --git a/tests/printf_fmt_gen.jinja b/tests/printf_fmt_gen.jinja new file mode 100644 index 0000000..a1f1c50 --- /dev/null +++ b/tests/printf_fmt_gen.jinja @@ -0,0 +1,35 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +int main() +{ + {% for case in cases %} + { + const char *format = {{ escape_str(case.in.format) }}; + + struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create(); + KernAux_PrintfFmt_Spec_eval_flags(&spec, &format); + if (KernAux_PrintfFmt_Spec_eval_width1(&spec, &format)) { + KernAux_PrintfFmt_Spec_eval_width2(&spec, {{ none_to_zero(case.in.width) }}); + } + if (KernAux_PrintfFmt_Spec_eval_precision1(&spec, &format)) { + KernAux_PrintfFmt_Spec_eval_precision2(&spec, {{ none_to_zero(case.in.precision) }}); + } + KernAux_PrintfFmt_Spec_eval_length(&spec, &format); + KernAux_PrintfFmt_Spec_eval_type(&spec, &format); + + assert(spec.flags == {{ escape_flags(case.out.flags) }}); + assert(spec.width == {{ case.out.width }}); + assert(spec.precision == {{ case.out.precision }}); + assert(spec.type == {{ escape_type(case.out.type) }}); + assert(spec.base == {{ case.out.base }}); + } + {% endfor %} + + return 0; +} diff --git a/tests/printf_fmt_gen.py b/tests/printf_fmt_gen.py new file mode 100644 index 0000000..f6d092c --- /dev/null +++ b/tests/printf_fmt_gen.py @@ -0,0 +1,59 @@ +from jinja2 import Environment, FileSystemLoader +from os import path +from yaml import SafeLoader, safe_load + +CASES_FILENAME = 'printf_fmt.yml' +TEMPLATE_FILENAME = 'printf_fmt_gen.jinja' +TEST_FILENAME = 'test_printf_fmt_gen.c' + +ROOT_DIRPATH = path.dirname(path.dirname(path.join(path.abspath(__file__)))) + +COMMON_DIRPATH = path.join(ROOT_DIRPATH, 'common') +TESTS_DIRPATH = path.join(ROOT_DIRPATH, 'tests') + +CASES_FILEPATH = path.join(COMMON_DIRPATH, CASES_FILENAME) +TEST_FILEPATH = path.join(TESTS_DIRPATH, TEST_FILENAME) + +def main(): + cases = safe_load(open(CASES_FILEPATH)) + + jinja_env = Environment( + keep_trailing_newline=True, + loader=FileSystemLoader(TESTS_DIRPATH), + ) + jinja_template = jinja_env.get_template(TEMPLATE_FILENAME) + + result = jinja_template.render( + cases=cases, + escape_flags=escape_flags, + escape_str=escape_str, + escape_type=escape_type, + none_to_zero=none_to_zero, + ) + + with open(TEST_FILEPATH, 'w') as f: + f.write(result) + +def escape_flag(flag): + return 'KERNAUX_PRINTF_FMT_FLAGS_' + flag.upper() + +def escape_flags(flags): + if len(flags) == 0: + return '0' + + return '(' + ' | '.join(map(escape_flag, flags)) + ')' + +def escape_str(s): + return '"' + s + '"' + +def escape_type(type_): + return 'KERNAUX_PRINTF_FMT_TYPE_' + type_.upper() + +def none_to_zero(num): + if num is None: + return '0' + else: + return str(num) + +if __name__ == '__main__': + main()