Main: generate tests for cmdline

This commit is contained in:
Alex Kotov 2022-06-08 02:00:46 +03:00
parent b2341a5ca2
commit 619f7004e0
Signed by: kotovalexarian
GPG Key ID: 553C0EBBEB5D5F08
6 changed files with 310 additions and 51 deletions

2
.gitignore vendored
View File

@ -116,6 +116,8 @@
/tests/multiboot2_info_print1
/tests/multiboot2_info_print2
/tests/test_cmdline
/tests/test_cmdline_gen
/tests/test_cmdline_gen.c
/tests/test_elf
/tests/test_mbr
/tests/test_multiboot2_header_helpers

View File

@ -321,6 +321,27 @@ tests_test_cmdline_SOURCES = tests/test_cmdline.c
endif
endif
##########################
# tests/test_cmdline_gen #
##########################
if ENABLE_TESTS_PYTHON
if WITH_CMDLINE
TESTS += tests/test_cmdline_gen
tests_test_cmdline_gen_LDADD = libkernaux.a
tests_test_cmdline_gen_SOURCES = \
tests/test_cmdline_gen.c \
tests/cmdline_gen.py \
tests/cmdline_gen.jinja \
common/cmdline.yml
endif
endif
CLEANFILES += tests/test_cmdline_gen.c
tests/test_cmdline_gen.c: tests/cmdline_gen.py tests/cmdline_gen.jinja common/cmdline.yml
python3 tests/cmdline_gen.py
##################
# tests/test_elf #
##################

125
common/cmdline.yml Normal file
View File

@ -0,0 +1,125 @@
# TODO: move here test cases from tests/test_cmdline.c
- cmdline: ''
count: 0
result: []
- cmdline: ' '
count: 0
result: []
- cmdline: 'foo'
count: 1
result: ['foo']
- cmdline: 'foo bar'
count: 2
result: ['foo', 'bar']
- cmdline: 'foo bar '
count: 2
result: ['foo', 'bar']
- cmdline: ' foo bar '
count: 2
result: ['foo', 'bar']
- cmdline: 'foo bar'
count: 2
result: ['foo', 'bar']
- cmdline: ' foo bar'
count: 2
result: ['foo', 'bar']
- cmdline: 'foo bar '
count: 2
result: ['foo', 'bar']
- cmdline: ' foo bar '
count: 2
result: ['foo', 'bar']
- cmdline: 'foo bar car'
count: 3
result: ['foo', 'bar', 'car']
- cmdline: '\"\"'
count: 1
result: ['']
- cmdline: '\"\" \"\"'
count: 2
result: ['', '']
- cmdline: '\"\" \"\" \"\"'
count: 3
result: ['', '', '']
- cmdline: '\"foo\"'
count: 1
result: ['foo']
- cmdline: '\"foo\" \"bar\"'
count: 2
result: ['foo', 'bar']
- cmdline: ' \"foo\" \"bar\"'
count: 2
result: ['foo', 'bar']
- cmdline: '\"foo\" \"bar\" '
count: 2
result: ['foo', 'bar']
- cmdline: ' \"foo\" \"bar\" '
count: 2
result: ['foo', 'bar']
- cmdline: '\"foo\" \"bar\"'
count: 2
result: ['foo', 'bar']
- cmdline: '\"foo\" \"bar\" '
count: 2
result: ['foo', 'bar']
- cmdline: ' \"foo\" \"bar\"'
count: 2
result: ['foo', 'bar']
- cmdline: ' \"foo\" \"bar\" '
count: 2
result: ['foo', 'bar']
- cmdline: '\"foo\" \"bar\" \"car\"'
count: 3
result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car'
argv_count_max: 3
count: 3
result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car'
buffer_size: 12
count: 3
result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car'
argv_count_max: 3
buffer_size: 12
count: 3
result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car'
argv_count_max: 2
error: 'too many args'
- cmdline: 'foo bar car'
buffer_size: 11
error: 'buffer overflow'
- cmdline: 'foo bar car'
argv_count_max: 2
buffer_size: 11
error: 'too many args'
- cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 3
count: 3
result: ['foo', 'bar', 'car']
- cmdline: '\"foo\" \"bar\" \"car\"'
buffer_size: 12
count: 3
result: ['foo', 'bar', 'car']
- cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 3
buffer_size: 12
count: 3
result: ['foo', 'bar', 'car']
- cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 2
error: 'too many args'
- cmdline: '\"foo\" \"bar\" \"car\"'
buffer_size: 11
error: 'buffer overflow'
- cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 2
buffer_size: 11
error: 'too many args'

119
tests/cmdline_gen.jinja Normal file
View File

@ -0,0 +1,119 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <kernaux/cmdline.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#define ARGV_COUNT_MAX 100
#define BUFFER_SIZE 4096
static void test(
const char *cmdline,
size_t argv_count_max,
size_t buffer_size,
bool expected_result,
const char *expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
);
int main()
{
{% for case in cases %}
{
{% if not case.error %}
const char *const expected_argv[{{ escape_int(len(case.result) or 1) }}] = {
{% if len(case.result) %}
{% for item in case.result %}
{{ escape_str(item) }},
{% endfor %}
{% else %}
NULL,
{% endif %}
};
{% endif %}
test(
{{ escape_str(case.cmdline) }},
{{ escape_int(case.argv_count_max or 0) }},
{{ escape_int(case.buffer_size or 0) }},
{% if not case.error %}
true,
"",
{{ escape_int(case.count) }},
expected_argv
{% else %}
false,
{{ escape_str(case.error) }},
0,
NULL
{% endif %}
);
}
{% endfor %}
return 0;
}
void test(
const char *const cmdline,
size_t argv_count_max,
size_t buffer_size,
const bool expected_result,
const char *const expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
) {
if (argv_count_max == 0) argv_count_max = ARGV_COUNT_MAX;
if (buffer_size == 0) buffer_size = BUFFER_SIZE;
char *error_msg = malloc(KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
size_t argc = 1234;
char **const argv = malloc(sizeof(char*) * argv_count_max);
char *const buffer = malloc(buffer_size);
assert(error_msg);
assert(argv);
assert(buffer);
memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
memset(argv, 'x', sizeof(char*) * argv_count_max);
memset(buffer, 'x', buffer_size);
assert(
kernaux_cmdline(
cmdline,
error_msg,
&argc,
argv,
buffer,
argv_count_max,
buffer_size
) == !!expected_result
);
assert(strcmp(error_msg, expected_error_msg) == 0);
assert(argc == expected_argc);
if (expected_argv) {
for (size_t index = 0; index < argc; ++index) {
assert(strcmp(argv[index], expected_argv[index]) == 0);
}
}
for (size_t index = argc; index < argv_count_max; ++index) {
assert(argv[index] == NULL);
}
free(error_msg);
free(argv);
free(buffer);
}

43
tests/cmdline_gen.py Normal file
View File

@ -0,0 +1,43 @@
from jinja2 import Environment, FileSystemLoader
from os import path
from yaml import SafeLoader, safe_load
CASES_FILENAME = 'cmdline.yml'
TEMPLATE_FILENAME = 'cmdline_gen.jinja'
TEST_FILENAME = 'test_cmdline_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_str=escape_str,
escape_int=escape_int,
len=len,
)
with open(TEST_FILEPATH, 'w') as f:
f.write(result)
def escape_int(n):
return str(n)
def escape_str(s):
return '"' + s + '"'
if __name__ == '__main__':
main()

View File

@ -24,14 +24,6 @@ static void test(
const char *const *const expected_argv
);
static const char *const argv_empty[] = {""};
static const char *const argv_empty_X2[] = {"", ""};
static const char *const argv_empty_X3[] = {"", "", ""};
static const char *const argv_foo[] = {"foo"};
static const char *const argv_foo_bar[] = {"foo", "bar"};
static const char *const argv_foo_bar_car[] = {"foo", "bar", "car"};
static const char *const argv_spaceX3_X3[] = {" ", " ", " "};
static const char *const argv_backslashX3_X3[] = {"\\\\\\", "\\\\\\", "\\\\\\"};
static const char *const argv_quotmarkX3_X3[] = {"\"\"\"", "\"\"\"", "\"\"\""};
@ -86,49 +78,6 @@ static const char *const argv_a_X6[] = { "a", "a", "a", "a", "a", "a" };
int main()
{
test("", 0, 0, true, "", 0, NULL);
test(" ", 0, 0, true, "", 0, NULL);
test("foo", 0, 0, true, "", 1, argv_foo);
test("foo bar", 0, 0, true, "", 2, argv_foo_bar);
test(" foo bar", 0, 0, true, "", 2, argv_foo_bar);
test("foo bar ", 0, 0, true, "", 2, argv_foo_bar);
test(" foo bar ", 0, 0, true, "", 2, argv_foo_bar);
test("foo bar", 0, 0, true, "", 2, argv_foo_bar);
test(" foo bar", 0, 0, true, "", 2, argv_foo_bar);
test("foo bar ", 0, 0, true, "", 2, argv_foo_bar);
test(" foo bar ", 0, 0, true, "", 2, argv_foo_bar);
test("foo bar car", 0, 0, true, "", 3, argv_foo_bar_car);
test("\"\"", 0, 0, true, "", 1, argv_empty);
test("\"\" \"\"", 0, 0, true, "", 2, argv_empty_X2);
test("\"\" \"\" \"\"", 0, 0, true, "", 3, argv_empty_X3);
test("\"foo\"", 0, 0, true, "", 1, argv_foo);
test("\"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
test(" \"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
test("\"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
test(" \"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
test("\"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
test("\"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
test(" \"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
test(" \"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
test("\"foo\" \"bar\" \"car\"", 0, 0, true, "", 3, argv_foo_bar_car);
test("foo bar car", 3, 0, true, "", 3, argv_foo_bar_car);
test("foo bar car", 0, 12, true, "", 3, argv_foo_bar_car);
test("foo bar car", 3, 12, true, "", 3, argv_foo_bar_car);
test("foo bar car", 2, 0, false, "too many args", 0, NULL);
test("foo bar car", 0, 11, false, "buffer overflow", 0, NULL);
test("foo bar car", 2, 11, false, "too many args", 0, NULL);
test("\"foo\" \"bar\" \"car\"", 3, 0, true, "", 3, argv_foo_bar_car);
test("\"foo\" \"bar\" \"car\"", 0, 12, true, "", 3, argv_foo_bar_car);
test("\"foo\" \"bar\" \"car\"", 3, 12, true, "", 3, argv_foo_bar_car);
test("\"foo\" \"bar\" \"car\"", 2, 0, false, "too many args", 0, NULL);
test("\"foo\" \"bar\" \"car\"", 0, 11, false, "buffer overflow", 0, NULL);
test("\"foo\" \"bar\" \"car\"", 2, 11, false, "too many args", 0, NULL);
test("\\ ", 0, 0, true, "", 1, argv_space);
test("\"\\ \"", 0, 0, true, "", 1, argv_space);
test("\\\\", 0, 0, true, "", 1, argv_backslash);