diff options
| author | Charles <sircharlesaze@gmail.com> | 2019-11-05 05:23:48 +0100 |
|---|---|---|
| committer | Charles <sircharlesaze@gmail.com> | 2019-11-05 05:23:48 +0100 |
| commit | f4e039e5c23d5aea7a45dd8f81d573902681ec99 (patch) | |
| tree | bed21b5b73a91a8e0a31f854b9c921f1f16fb769 | |
| parent | a4969e7e47b27b47fc06ceeebfb826d73ea78c52 (diff) | |
| download | ft_printf_test-f4e039e5c23d5aea7a45dd8f81d573902681ec99.tar.gz ft_printf_test-f4e039e5c23d5aea7a45dd8f81d573902681ec99.tar.bz2 ft_printf_test-f4e039e5c23d5aea7a45dd8f81d573902681ec99.zip | |
Generator doesnt generate -Wformat incompatible tests
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | README.md | 17 | ||||
| -rw-r--r-- | generate.py | 89 |
3 files changed, 70 insertions, 39 deletions
@@ -31,6 +31,9 @@ interactive: all raw: all ./$(NAME) +generate: + $(PYTHON) generate.py -n 100 + all: $(NAME) $(NAME): ft_printf_all $(OBJ) header.h tests/tests.h @@ -2,6 +2,8 @@ Unit test for the ft_printf project of 42 school. + + ## Usage Clone this repo such that: @@ -19,7 +21,18 @@ or modify the `FT_PRINTF_PATH` variable in the Makefile - `> make quiet`: to show a more quiet output - `> make raw`: run the tests in a ugly but parsable format - `> python3 prettier -h`: show prettier options +- `> make generate`: generate 100 random test -## Example - +## Random Test Generator + +It will generate random test according to the `-Wformat` flag of gcc. + +- `> python3 generate.py -n [number of tests]`: generate n test +- `> python3 generate.py -h`: show all available options + +## Pro tips + +This doesnt handle timeout, so if your `ft_printf` goes in an infinite loop, +this test will too. +`Ctrl-C` is your best friend. diff --git a/generate.py b/generate.py index 22051c4..a015471 100644 --- a/generate.py +++ b/generate.py @@ -22,21 +22,25 @@ CHARS.extend([r"\t", r"\n", r"\r", r"\v", r"\f", "\\\\"]) def parse_args(): - parser = argparse.ArgumentParser( - prog="ft_printf_test generator", description="A random test generator") - parser.add_argument("-n", type=int, default=100, - help="number of tests to generate") + parser = argparse.ArgumentParser(prog="ft_printf_test generator", description="A random test generator") + parser.add_argument("-n", "--tests", type=int, default=100, help="number of tests to generate") + parser.add_argument("-c", "--check-gcc", action="store_true", help="check generated test is valid with gcc (slow)") + parser.add_argument("-o", "--output", default="generated.c", help="output file") + parser.add_argument("-a", "--args-max", default=5, type=int, help="maximum number of argument") + parser.add_argument("-f", "--flags-max", default=3, type=int, help="maximum number of flags") + parser.add_argument("-s", "--str-max", default=30, type=int, help="maximum length of string") return vars(parser.parse_args(sys.argv[1:])) class Generator: def __init__(self, options): - self.test_nb = options["n"] - self.output_filename = "generated.c" + self.test_nb = options["tests"] + self.check_valid = options["check_gcc"] + self.output_filename = options["output"] self.output_file = None self.tmp_filename = "tmp.c" - self.str_max_len = 10 - self.args_max = 10 - self.flags_max = 2 + self.args_max = options["args_max"] + self.flags_max = options["flags_max"] + self.str_max_len = options["str_max"] self.width_max = 200 self.width_wildcard_rate = 10 self.width_empty_rate = 2 @@ -50,22 +54,21 @@ class Generator: self.pool = [] def run(self): + if self.check_valid: + os.system(f"touch {self.tmp_filename}") with open(self.output_filename, "w") as self.output_file: self._write_header() while self.test_nb > 0: assert_printf = self._random_printf() - print(assert_printf) - # self.test_nb -= 1 - if self._compile(assert_printf): - self.output_file.write(assert_printf + "\n\t") - self.test_nb -= 1 - print("generated") + if self.check_valid and not self._compile(assert_printf): + print("Failed to generate:", assert_printf) + continue + self.test_nb -= 1 + self.output_file.write(assert_printf + "\n\t") + print("Generated", self.test_nb) self._write_footer() - os.system(f"rm {self.tmp_filename}") - - def quit(self): - pass - + if self.check_valid: + os.system(f"rm {self.tmp_filename}") def _compile(self, assert_printf): with open(self.tmp_filename, "w") as tmp_file: @@ -85,13 +88,13 @@ class Generator: conv = self.possible_conv[randrange(self.possible_conv_len)] f = self._random_fmt(conv) for _ in range(f.count("*")): - args.append(randrange(-100, 100)) + args.append(randrange(-200, 200)) formats.append(f) args.append(self._random_arg(conv)) return formats, args def _random_fmt(self, conv): - return f"%{self._random_flags()}{self._random_width()}{self._random_precision()}{conv}" + return "%" + self._random_flags(conv) + self._random_width() + self._random_precision(conv) + conv def _random_arg(self, conv): return { @@ -99,17 +102,32 @@ class Generator: 's': "\"" + self._random_string() + "\"", 'd': randrange(INT_MIN, INT_MAX + 1), 'i': randrange(INT_MIN, INT_MAX + 1), - 'u': randrange(UINT_MAX), - 'x': randrange(UINT_MAX), - 'X': randrange(UINT_MAX), - 'p': str(randrange(ULONG_INT_MAX)) + "lu" - # '%': None + 'u': str(randrange(UINT_MAX)) + "u", + 'x': str(randrange(UINT_MAX)) + "u", + 'X': str(randrange(UINT_MAX)) + "u", + 'p': "(void*)" + str(randrange(ULONG_INT_MAX)) + "lu" }[conv] - def _random_flags(self): + def _random_flags(self, conv): if self.flags_max <= 0: return "" - return "".join([choice(self.possible_conv) for _ in range(randrange(self.flags_max))]) + + flags = "".join([choice(self.possible_flags) for _ in range(randrange(self.flags_max))]) + + if "+" in flags and conv in "psxXcu": + flags = flags.replace("+", "") + if " " in flags and conv in "pcsuxX": + flags = flags.replace(" ", "") + if "0" in flags and conv in "pcs": + flags = flags.replace("0", "") + if "#" in flags and conv in "upcsdi": + flags = flags.replace("#", "") + + if "0" in flags and "-" in flags: + flags = flags.replace("0", "") + if " " in flags and "+" in flags: + flags = flags.replace(" ", "") + return flags def _random_width(self): p = randrange(100) @@ -118,9 +136,11 @@ class Generator: p -= self.width_wildcard_rate if p < self.width_empty_rate: return "" - return str(randrange(self.width_max)) + return str(randrange(1, self.width_max)) - def _random_precision(self): + def _random_precision(self, conv): + if conv == "p" or conv == "c": + return "" p = randrange(100) if p < self.precision_wildcard_rate: return ".*" @@ -144,9 +164,4 @@ class Generator: if __name__ == "__main__": options = parse_args() g = Generator(options) - try: - g.run() - except KeyboardInterrupt: - pass - finally: - g.quit() + g.run() |
