├── .gitattributes ├── .gitignore ├── Makefile ├── README.md ├── inc ├── printf_unit_test.h └── source-generator.h ├── libprintf-test.c └── src ├── main.cpp ├── random_args.cpp └── source_generator.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | *.so filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *~ 4 | *.so 5 | obj/ 6 | *.dSYM/ 7 | *.out.* 8 | a.out 9 | assets/tmp 10 | run_test 11 | src_gen 12 | assets/.source-generator.lock 13 | libprintf-test.c 14 | result.log 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # **************************************************************************** # 2 | # # 3 | # ::: :::::::: # 4 | # Makefile :+: :+: :+: # 5 | # +:+ +:+ +:+ # 6 | # By: alelievr +#+ +:+ +#+ # 7 | # +#+#+#+#+#+ +#+ # 8 | # Created: 2014/07/15 15:13:38 by alelievr #+# #+# # 9 | # Updated: 2018/02/16 19:10:35 by alelievr ### ########.fr # 10 | # # 11 | # **************************************************************************** # 12 | 13 | ################# 14 | ## VARIABLES ## 15 | ################# 16 | 17 | # Sources 18 | SRCDIR = src 19 | SRC = main.cpp \ 20 | random_args.cpp \ 21 | source_generator.cpp \ 22 | 23 | # Objects 24 | OBJDIR = obj 25 | 26 | # Printf library directory 27 | PRINTFDIR = ../ft_printf/ 28 | 29 | # Variables 30 | LIBFT = 2 #1 or 0 to include the libft / 2 for autodetct 31 | DEBUGLEVEL = 0 #can be 0 for no debug 1 for or 2 for harder debug 32 | #Warrning: non null debuglevel will disable optlevel 33 | OPTLEVEL = 1 #same than debuglevel 34 | #Warrning: non null optlevel will disable debuglevel 35 | CPPVERSION = c++11 36 | #For simpler and faster use, use commnd line variables DEBUG and OPTI: 37 | #Example $> make DEBUG=2 will set debuglevel to 2 38 | 39 | # Includes 40 | INCDIRS = inc 41 | 42 | # Libraries 43 | LIBDIRS = 44 | LDLIBS = 45 | 46 | # Spec 47 | FINAL_PRINTF_LIB = printf-tests.so 48 | 49 | ASSETS_DIR = assets 50 | TMP_LIB_FTPRINTF = $(ASSETS_DIR)/tmp 51 | LIB_FTPRINTF_SO = libftprintf.so 52 | 53 | # Output 54 | NAME = run_test 55 | LIB_FTPRINTF= libftprintf.a 56 | 57 | # Compiler 58 | WERROR = #-Werror 59 | CFLAGS = -Wall -Wextra -ferror-limit=999 60 | CPROTECTION = -z execstack -fno-stack-protector 61 | 62 | DEBUGFLAGS1 = -O2 -ggdb 63 | DEBUGFLAGS2 = -fsanitize=address 64 | OPTFLAGS1 = -funroll-loops -O2 65 | OPTFLAGS2 = -pipe -funroll-loops -Ofast 66 | 67 | # Framework 68 | FRAMEWORK = 69 | 70 | ################# 71 | ## COLORS ## 72 | ################# 73 | CPREFIX = "\033[38;5;" 74 | BGPREFIX = "\033[48;5;" 75 | CCLEAR = "\033[0m" 76 | CLINK_T = $(CPREFIX)"129m" 77 | CLINK = $(CPREFIX)"93m" 78 | COBJ_T = $(CPREFIX)"119m" 79 | COBJ = $(CPREFIX)"113m" 80 | CCLEAN_T = $(CPREFIX)"9m" 81 | CCLEAN = $(CPREFIX)"166m" 82 | CRUN_T = $(CPREFIX)"198m" 83 | CRUN = $(CPREFIX)"163m" 84 | CNORM_T = "226m" 85 | CNORM_ERR = "196m" 86 | CNORM_WARN = "202m" 87 | CNORM_OK = "231m" 88 | 89 | ################# 90 | ## OS/PROC ## 91 | ################# 92 | 93 | OS := $(shell uname -s) 94 | PROC := $(shell uname -p) 95 | DEBUGFLAGS = 96 | LINKDEBUG = 97 | OPTFLAGS = 98 | #COMPILATION = 99 | 100 | ifeq "$(OS)" "Windows_NT" 101 | endif 102 | ifeq "$(OS)" "Linux" 103 | LDLIBS += 104 | DEBUGFLAGS += " -fsanitize=memory -fsanitize-memory-use-after-dtor -fsanitize=thread" 105 | endif 106 | ifeq "$(OS)" "Darwin" 107 | endif 108 | 109 | ################# 110 | ## AUTO ## 111 | ################# 112 | 113 | NASM = nasm 114 | OBJS = $(patsubst %.c,%.o, $(filter %.c, $(SRC))) \ 115 | $(patsubst %.cpp,%.o, $(filter %.cpp, $(SRC))) \ 116 | $(patsubst %.s,%.o, $(filter %.s, $(SRC))) 117 | OBJ = $(addprefix $(OBJDIR)/,$(notdir $(OBJS))) 118 | NORME = **/*.[ch] 119 | VPATH += $(dir $(addprefix $(SRCDIR)/,$(SRC))) 120 | VFRAME = $(addprefix -framework ,$(FRAMEWORK)) 121 | INCFILES = $(foreach inc, $(INCDIRS), $(wildcard $(inc)/*.h)) 122 | CPPFLAGS = $(addprefix -I,$(INCDIRS)) 123 | LDFLAGS = $(addprefix -L,$(LIBDIRS)) 124 | LINKER = $(CXX) 125 | 126 | disp_indent = for I in `seq 1 $(MAKELEVEL)`; do \ 127 | test "$(MAKELEVEL)" '!=' '0' && printf "\t"; \ 128 | done 129 | color_exec = $(call disp_indent); \ 130 | echo $(1)➤ $(3)$(2)"\n"'$(strip $(4))'$(CCLEAR);$(4) 131 | color_exec_t= $(call disp_indent); \ 132 | echo $(1)➤ '$(strip $(3))'$(2)$(CCLEAR);$(3) 133 | 134 | ifneq ($(filter 1,$(strip $(DEBUGLEVEL)) ${DEBUG}),) 135 | OPTLEVEL = 0 136 | OPTI = 0 137 | DEBUGFLAGS += $(DEBUGFLAGS1) 138 | endif 139 | ifneq ($(filter 2,$(strip $(DEBUGLEVEL)) ${DEBUG}),) 140 | OPTLEVEL = 0 141 | OPTI = 0 142 | DEBUGFLAGS += $(DEBUGFLAGS1) $(DEBUGFLAGS2) 143 | LINKDEBUG += $(DEBUGFLAGS1) $(DEBUGFLAGS2) 144 | export ASAN_OPTIONS=check_initialization_order=1 145 | endif 146 | 147 | ifneq ($(filter 1,$(strip $(OPTLEVEL)) ${OPTI}),) 148 | DEBUGFLAGS = 149 | OPTFLAGS = $(OPTFLAGS1) 150 | endif 151 | ifneq ($(filter 2,$(strip $(OPTLEVEL)) ${OPTI}),) 152 | DEBUGFLAGS = 153 | OPTFLAGS = $(OPTFLAGS1) $(OPTFLAGS2) 154 | endif 155 | 156 | ifndef $(CXX) 157 | CXX = clang++ 158 | endif 159 | 160 | ifneq ($(filter %.cpp,$(SRC)),) 161 | LINKER = $(CXX) 162 | endif 163 | 164 | ifdef ${NOWERROR} 165 | WERROR = 166 | endif 167 | 168 | ifeq "$(strip $(LIBFT))" "2" 169 | ifneq ($(wildcard ./libft),) 170 | LIBDIRS += "libft" 171 | LDLIBS += "-lft" 172 | INCDIRS += "libft" 173 | endif 174 | endif 175 | 176 | ################# 177 | ## TARGETS ## 178 | ################# 179 | 180 | # First target 181 | all: $(NAME) printf 182 | 183 | # Linking 184 | $(NAME): $(OBJ) 185 | @$(if $(findstring lft,$(LDLIBS)),$(call color_exec_t,$(CCLEAR),$(CCLEAR),\ 186 | make -j 4 -C libft)) 187 | @$(call color_exec,$(CLINK_T),$(CLINK),"Link of $(NAME):",\ 188 | $(LINKER) $(WERROR) $(CFLAGS) $(LDFLAGS) $(LDLIBS) $(OPTFLAGS) $(DEBUGFLAGS) $(LINKDEBUG) $(VFRAME) -o $@ $^) 189 | 190 | $(OBJDIR)/%.o: %.cpp $(INCFILES) 191 | @mkdir -p $(OBJDIR)/$(dir $<) 192 | @$(call color_exec,$(COBJ_T),$(COBJ),"Object: $@",\ 193 | $(CXX) -std=$(CPPVERSION) $(WERROR) $(CFLAGS) $(OPTFLAGS) $(DEBUGFLAGS) $(CPPFLAGS) -o $@ -c $<) 194 | 195 | # Objects compilation 196 | $(OBJDIR)/%.o: %.c $(INCFILES) 197 | @mkdir -p $(OBJDIR)/$(dir $<) 198 | @$(call color_exec,$(COBJ_T),$(COBJ),"Object: $@",\ 199 | $(CC) $(WERROR) $(CFLAGS) $(OPTFLAGS) $(DEBUGFLAGS) $(CPPFLAGS) -o $@ -c $<) 200 | 201 | $(OBJDIR)/%.o: %.s 202 | @mkdir -p $(OBJDIR)/$(dir $<) 203 | @$(call color_exec,$(COBJ_T),$(COBJ),"Object: $@",\ 204 | $(NASM) -f macho64 -o $@ $<) 205 | 206 | # Removing objects 207 | clean: 208 | @$(call color_exec,$(CCLEAN_T),$(CCLEAN),"Clean:",\ 209 | $(RM) $(OBJ)) 210 | @rm -rf $(OBJDIR) 211 | @rm -rf $(TMP_LIB_FTPRINTF) 212 | @rm -rf $(ASSETS_DIR)/libftprintf.a 213 | 214 | # Removing objects and exe 215 | fclean: clean 216 | @$(call color_exec,$(CCLEAN_T),$(CCLEAN),"Fclean:",\ 217 | $(RM) $(NAME) $(LIB_FTPRINTF_SO)) 218 | 219 | printf: 220 | @mkdir -p $(ASSETS_DIR) 221 | @make -C "$(PRINTFDIR)" 222 | @cp "$(PRINTFDIR)"/$(LIB_FTPRINTF) $(ASSETS_DIR) 223 | @rm -rf $(TMP_LIB_FTPRINTF) 224 | @mkdir -p $(TMP_LIB_FTPRINTF) 225 | @$(call color_exec,$(CLINK_T),$(CLINK),"Creating libftprintf.so lib",\ 226 | cd $(TMP_LIB_FTPRINTF) && ar -xv ../$(LIB_FTPRINTF) >/dev/null && $(CC) -shared -fPIC *.o -o $(LIB_FTPRINTF_SO) && cp $(LIB_FTPRINTF_SO) ../..) 227 | 228 | # All removing then compiling 229 | re: fclean all 230 | 231 | f: all printf run 232 | 233 | # Checking norme 234 | norme: 235 | @norminette $(NORME) | sed "s/Norme/[38;5;$(CNORM_T)➤ [38;5;$(CNORM_OK)Norme/g;s/Warning/[0;$(CNORM_WARN)Warning/g;s/Error/[0;$(CNORM_ERR)Error/g" 236 | 237 | run: $(NAME) 238 | @echo $(CRUN_T)"➤ "$(CRUN)"./$(NAME) ${ARGS}\033[0m" 239 | @./$(NAME) ${ARGS} 240 | 241 | codesize: 242 | @cat $(NORME) |grep -v '/\*' |wc -l 243 | 244 | functions: $(NAME) 245 | @nm $(NAME) | grep U 246 | 247 | coffee: 248 | @clear 249 | @echo "" 250 | @echo " (" 251 | @echo " ) (" 252 | @echo " ___...(-------)-....___" 253 | @echo ' .-"" ) ( ""-.' 254 | @echo " .-''''|-._ ) _.-|" 255 | @echo ' / .--.| `""---...........---""` |' 256 | @echo " / / | |" 257 | @echo " | | | |" 258 | @echo " \ \ | |" 259 | @echo " '\ '\ | |" 260 | @echo " '\ '| |" 261 | @echo " _/ /\ /" 262 | @echo " (__/ \ /" 263 | @echo ' _..---""` \ /`""---.._' 264 | @echo " .-' \ / '-." 265 | @echo ": '-.__ __.-' :" 266 | @echo ': ) ""---...---"" ( :' 267 | @echo "\'._ '"--...___...--"' _.'" 268 | @echo ' \""--..__ __..--""/' 269 | @echo " '._ """----.....______.....----""" _.'" 270 | @echo ' ""--..,,_____ _____,,..--"""''' 271 | @echo ' """------"""' 272 | @sleep 0.5 273 | @clear 274 | @echo "" 275 | @echo " (" 276 | @echo " ) (" 277 | @echo " ___..(.------)--....___" 278 | @echo ' .-"" ) ( ""-.' 279 | @echo " .-''''|-._ ( ) _.-|" 280 | @echo ' / .--.| `""---...........---""` |' 281 | @echo " / / | |" 282 | @echo " | | | |" 283 | @echo " \ \ | |" 284 | @echo " '\ '\ | |" 285 | @echo " '\ '| |" 286 | @echo " _/ /\ /" 287 | @echo " (__/ \ /" 288 | @echo ' _..---""` \ /`""---.._' 289 | @echo " .-' \ / '-." 290 | @echo ": '-.__ __.-' :" 291 | @echo ': ) ""---...---"" ( :' 292 | @echo "\'._ '"--...___...--"' _.'" 293 | @echo ' \""--..__ __..--""/' 294 | @echo " '._ """----.....______.....----""" _.'" 295 | @echo ' ""--..,,_____ _____,,..--"""''' 296 | @echo ' """------"""' 297 | @sleep 0.5 298 | @clear 299 | @echo "" 300 | @echo " (" 301 | @echo " ) (" 302 | @echo " ___..(.------)--....___" 303 | @echo ' .-"" ) ( ""-.' 304 | @echo " .-''''|-._ ( ) _.-|" 305 | @echo ' / .--.| `""---...........---""` |' 306 | @echo " / / | |" 307 | @echo " | | | |" 308 | @echo " \ \ | |" 309 | @echo " '\ '\ | |" 310 | @echo " '\ '| |" 311 | @echo " _/ /\ /" 312 | @echo " (__/ \ /" 313 | @echo ' _..---""` \ /`""---.._' 314 | @echo " .-' \ / '-." 315 | @echo ": '-.__ __.-' :" 316 | @echo ': ) ""---...---"" ( :' 317 | @echo "\'._ '"--...___...--"' _.'" 318 | @echo ' \""--..__ __..--""/' 319 | @echo " '._ """----.....______.....----""" _.'" 320 | @echo ' ""--..,,_____ _____,,..--"""''' 321 | @echo ' """------"""' 322 | @sleep 0.5 323 | @clear 324 | @echo "" 325 | @echo " ( ) " 326 | @echo " ) (" 327 | @echo " ___)...----)----....___" 328 | @echo ' .-"" ) ( ""-.' 329 | @echo " .-''''|-._ ( ) _.-|" 330 | @echo ' / .--.| `""---...........---""` |' 331 | @echo " / / | |" 332 | @echo " | | | |" 333 | @echo " \ \ | |" 334 | @echo " '\ '\ | |" 335 | @echo " '\ '| |" 336 | @echo " _/ /\ /" 337 | @echo " (__/ \ /" 338 | @echo ' _..---""` \ /`""---.._' 339 | @echo " .-' \ / '-." 340 | @echo ": '-.__ __.-' :" 341 | @echo ': ) ""---...---"" ( :' 342 | @echo "\'._ '"--...___...--"' _.'" 343 | @echo ' \""--..__ __..--""/' 344 | @echo " '._ """----.....______.....----""" _.'" 345 | @echo ' ""--..,,_____ _____,,..--"""''' 346 | @echo ' """------"""' 347 | 348 | .PHONY: all clean fclean re norme codesize 349 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # printf-unit-test 2 | 3 | > :warning: **Important note: this version targets the new 42 subject of `printf`, if you want to use the old one [you can access it on the old branch](https://github.com/alelievr/printf-unit-test/tree/old).** 4 | 5 | ## Install 6 | 7 | clone or download this repo and place it in the parent folder of your ft_printf dir. 8 | 9 | you can configure the path of your printf with the var PRINTFDIR in the Makefile 10 | 11 | ## Run 12 | 13 | `make f` or `./run_test` 14 | 15 | ## Usage 16 | ./run_test \ \ 17 | -e: stop to the first error / segfault 18 | -q: disable errer/segv/timeout output 19 | -r: disable speed test 20 | -d: debug mode 21 | -h: display help 22 | -f \: output in the specified file 23 | 24 | ## Test System 25 | 26 | this is a brute-force based test for printf, it will check all compilable (with -Wformat flag) printf converters and flags. 27 | supported converters: idDoOuUxXcCsSpaAeEfFgG 28 | supported modifiers: ".#0-+ " 29 | 30 | current number of tested formats: 3.4M (without float converters) 31 | 32 | -------------------------------------------------------------------------------- /inc/printf_unit_test.h: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* printf_unit_test.h :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alelievr +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2016/12/23 17:46:11 by alelievr #+# #+# */ 9 | /* Updated: 2019/11/19 14:50:57 by juligonz ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #pragma once 14 | #pragma clang diagnostic ignored "-Wformat-nonliteral" 15 | #pragma clang diagnostic ignored "-Wformat-non-iso" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | typedef char * string; 29 | typedef wchar_t * wstring; 30 | typedef void * ptr; 31 | 32 | #define LONGIFY(x) *(long long *)(void *)(&x) 33 | 34 | //#define SUPPORTED_CONVERTERS "idDoOuUxXcCsSpaAeEfFgG" 35 | //#define DEFAULT_CONVERTERS "idDoOuUxXcCsSp" 36 | 37 | #define SUPPORTED_CONVERTERS "cspdiuxX" 38 | #define DEFAULT_CONVERTERS "cspdiuxXfge" 39 | #define TEST_LIB_SO "./printf-tests.so" 40 | #define TEST_LIB_FLOATS_SO "./printf-tests-floats.so" 41 | #define FTPRINTF_LIB_SO "./libftprintf.so" 42 | #define LOG_FILE "./result.log" 43 | 44 | #define READ 0 45 | #define WRITE 1 46 | 47 | int generateRandArgs(char conv, const char *mods, long long *args); 48 | std::list< std::string > generateTestFormats(char conv); 49 | -------------------------------------------------------------------------------- /inc/source-generator.h: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* source-generator.h :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alelievr +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created 2016/12/22 19:07:07 by alelievr #+# #+# */ 9 | /* Updated 2016/12/23 17:41:49 by alelievr ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #pragma once 14 | 15 | #pragma clang diagnostic ignored "-Wc++98-compat" 16 | #pragma clang diagnostic ignored "-Wreserved-user-defined-literal" 17 | #pragma clang diagnostic ignored "-Wold-style-cast" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #define OUT_FOLDER "/tmp/print-unit-test/" 39 | #define LOCK_FILE ".source-generator.lock" 40 | #define NO_FLAG "\x98" 41 | #define PRINTF_FLAGS_BASIC NO_FLAG"#0-+ " 42 | #define NOALIGN INT_MIN 43 | #define NOPADD NOALIGN 44 | #define PRINTF_FLAGS_ADVANCED "" 45 | 46 | #define CHAR_MASK 0x0000000000000FF 47 | #define HOST_MASK 0x00000000000FFFF 48 | #define INT_MASK 0x00000000FFFFFFFF 49 | #define LONG_MASK 0xFFFFFFFFFFFFFFFF 50 | 51 | #define FILE_HEADER_TEMPLATE "#include \n#include \n#include \n#include \n#include \n#include \n#include \n\nextern int\t\tprintf(const char *, ...);\n" 52 | #define FILE_CONTENT_TEMPLATE "void printf_unit_test_%c_%.9i(char *b, int (*ft_printf)(const char *, ...), int *r1, %s arg, int fun)\n{\n\tif (!fun) {\n\t\tstrcpy(b, \"%s\");\n\t\t*r1 = printf(\"%s\", %sarg);\n\t\tfflush(stdout);\n\t\twrite(1, \"\\x99\\x98\\x97\\x96\", 4);\n\t} else {\n\t\t*r1 = ft_printf(\"%s\", %sarg);\n\t\tfflush(stdout);\n\t}\n}\n\n" 53 | 54 | #define FILE_TEMPLATE FILE_HEADER_TEMPLATE FILE_CONTENT_TEMPLATE 55 | 56 | static const char * rand_strings[] = {"!", "42", "\\\\!/", "^.^/", ">------------<"}; 57 | 58 | static const char flag_to_flag_incompatibilities[][2] = { 59 | {' ', '+'}, 60 | {'0', '-'}, 61 | }; 62 | 63 | static const char convertion_to_flag_incompatibilities[][2] = { 64 | {'i', '#'}, 65 | 66 | {'d', '#'}, 67 | 68 | {'o', '+'}, 69 | {'o', ' '}, 70 | 71 | {'u', '+'}, 72 | {'u', ' '}, 73 | {'u', '#'}, 74 | 75 | {'x', '+'}, 76 | {'x', ' '}, 77 | 78 | {'X', '+'}, 79 | {'X', ' '}, 80 | 81 | {'D', '#'}, 82 | 83 | {'O', '+'}, 84 | {'O', ' '}, 85 | 86 | {'U', '+'}, 87 | {'U', ' '}, 88 | {'U', '#'}, 89 | 90 | {'c', '0'}, 91 | {'c', '+'}, 92 | {'c', ' '}, 93 | {'c', '#'}, 94 | 95 | {'C', '0'}, 96 | {'C', '+'}, 97 | {'C', ' '}, 98 | {'C', '#'}, 99 | 100 | {'s', '0'}, 101 | {'s', '+'}, 102 | {'s', ' '}, 103 | {'s', '#'}, 104 | 105 | {'S', '0'}, 106 | {'S', '+'}, 107 | {'S', ' '}, 108 | {'S', '#'}, 109 | 110 | {'p', '0'}, 111 | {'p', '+'}, 112 | {'p', ' '}, 113 | {'p', '#'}, 114 | }; 115 | -------------------------------------------------------------------------------- /libprintf-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int ft_printf(const char *format, ...) 5 | { 6 | va_list ap; 7 | int ret; 8 | char buff[0xF0000]; 9 | 10 | va_start(ap, format); 11 | ret = vprintf(format, ap); 12 | return ret; 13 | } 14 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* main.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alelievr +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created 2016/12/23 17:42:25 by alelievr #+# #+# */ 9 | // Updated: 2019/11/19 15:03:57 by juligonz ### ########.fr // 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "printf_unit_test.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | const char * C_ERROR = "\033[38;5;196m"; 23 | const char * C_PASS = "\033[38;5;118m"; 24 | const char * C_CRASH = "\033[38;5;93m"; 25 | const char * C_TITLE = "\033[38;5;70m"; 26 | const char * C_CLEAR = "\033[0m"; 27 | 28 | static const char * current_format; 29 | static int current_index = 0; 30 | static char current_conv; 31 | static int failed_tests = 0; 32 | static int passed_tests = 0; 33 | static long long current_arg; 34 | static long last_time_update; 35 | static jmp_buf jmp_next_test; 36 | static int sig_counter = 0; 37 | static int g_current_test_index = 0; 38 | static bool stop_to_first_error = false; 39 | static double current_speed_percent = 1.; 40 | static bool quiet = false; 41 | static bool no_speed = false; 42 | static bool debug = false; 43 | static bool verbose = false; 44 | static bool disable_timeout = false; 45 | static int output_fd = -1; 46 | static int logfile_fd = -1; 47 | 48 | static void * runTestFuncs[128]; 49 | 50 | #define MAX(x, y) ((x > y) ? x : y) 51 | 52 | static void usage() __attribute__((noreturn)); 53 | static void usage() 54 | { 55 | printf("usage: ./run_test < options > < converters >\n" 56 | "options:\n" 57 | " -e: stop to the first error / segfault\n" 58 | " -q: disable errer/segv/timeout output\n" 59 | " -r: disable speed test\n" 60 | " -d: debug mode\n" 61 | " -v: verbose (debug mode but only for failed tests)\n" 62 | " -h: display help\n" 63 | " -f : output in the specified file\n"); 64 | printf("supported converters: \"" SUPPORTED_CONVERTERS "\"\n"); 65 | exit(-1); 66 | } 67 | 68 | static void cout(const char *f, ...) 69 | { 70 | va_list ap; 71 | 72 | if (output_fd == -1) 73 | output_fd = open("/dev/tty", O_RDWR); 74 | 75 | va_start(ap, f); 76 | vdprintf(output_fd, f, ap); 77 | va_end(ap); 78 | } 79 | 80 | static void coutl2(const char *color, const char *f, ...) 81 | { 82 | va_list ap; 83 | 84 | if (output_fd == -1) 85 | output_fd = open("/dev/tty", O_RDWR); 86 | 87 | va_start(ap, f); 88 | vdprintf(logfile_fd, f, ap); 89 | va_end(ap); 90 | va_start(ap, f); 91 | cout(color); 92 | vdprintf(output_fd, f, ap); 93 | cout(C_CLEAR); 94 | va_end(ap); 95 | } 96 | 97 | static char *arg_to_string(long long int arg) 98 | { 99 | static char buff[0xF000]; 100 | 101 | switch (current_conv) 102 | { 103 | case 'd': case 'D': case 'i': case 'o': case 'O': case 'u': case 'U': case 'x': case 'X': 104 | sprintf(buff, "%lli", arg); 105 | break ; 106 | case 'p': 107 | sprintf(buff, "%p", (void *)arg); 108 | break ; 109 | case 's': 110 | if (strchr(current_format, 'l') != NULL) 111 | sprintf(buff, "L\"%S\"", (wchar_t *)arg); 112 | else 113 | sprintf(buff, "\"%s\"", (char *)arg); 114 | break ; 115 | case 'S': 116 | sprintf(buff, "L\"%S\"", (wchar_t *)arg); 117 | break ; 118 | case 'c': 119 | if (isprint((char)arg)) 120 | sprintf(buff, "\'%c\'", (char)arg); 121 | else 122 | sprintf(buff, "(char)%i", (int)arg); 123 | break ; 124 | case 'C': 125 | if (arg != 0) 126 | sprintf(buff, "L\'%C\'(%i)", (wchar_t)arg, (int)arg); 127 | else 128 | sprintf(buff, "(wchar_t)%i", (int)arg); 129 | break ; 130 | case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': 131 | sprintf(buff, "%f", (float)arg); 132 | break ; 133 | } 134 | return buff; 135 | } 136 | 137 | static void sigh(int s) __attribute__((noreturn)); 138 | static void sigh(int s) 139 | { 140 | if (!quiet) 141 | cout("%scatched signal: %s when testing format: \"%s\" with arg: %s%s\n", C_CRASH, strsignal(s), current_format, arg_to_string(current_arg), C_CLEAR); 142 | if (stop_to_first_error) 143 | exit(0); 144 | if (sig_counter >= 500 && !quiet) 145 | cout("%sreceived too many crash signals, aborting test ...\n%s", C_CRASH, C_CLEAR), exit(-1); 146 | sig_counter++; 147 | g_current_test_index++; 148 | longjmp(jmp_next_test, 1); 149 | } 150 | 151 | void print_mem(char *mem, size_t size); 152 | void print_mem(char *mem, size_t size) 153 | { 154 | size_t i = 0; 155 | 156 | while (i < size) 157 | { 158 | if (isprint(mem[i])) 159 | cout("%c", mem[i]); 160 | else 161 | cout("\\x%hhx", mem[i]); 162 | i++; 163 | } 164 | } 165 | 166 | static char *escapeBuff(char *str, size_t len, int buffer) 167 | { 168 | static char tmp[2][0xF000]; 169 | size_t i = 0; 170 | size_t j = 0; 171 | 172 | for (i = 0; i < len; i++) 173 | { 174 | if (!isprint(str[i])) 175 | { 176 | char b1 = (str[i] & 0xF); 177 | char b2 = ((str[i] >> 4) & 0xF); 178 | 179 | tmp[buffer][j++] = '\\'; 180 | tmp[buffer][j++] = 'x'; 181 | tmp[buffer][j++] = (b1 > 9) ? b1 + '&' : b1 + '0'; 182 | tmp[buffer][j++] = (b2 > 9) ? b2 + '&' : b2 + '0'; 183 | } 184 | else 185 | tmp[buffer][j++] = str[i]; 186 | } 187 | tmp[buffer][j] = 0; 188 | return tmp[buffer]; 189 | } 190 | 191 | static long long longify(void *addr, size_t length) 192 | { 193 | long long ret = 0; 194 | 195 | memcpy(&ret, addr, length); 196 | 197 | return ret; 198 | } 199 | 200 | template< typename T > 201 | static void runTestSpec(const char *fmt, int (*ft_printf)(const char *f, ...), int fd[2], T arg) 202 | { 203 | char printf_buff[0xF00]; 204 | char ftprintf_buff[0xF00]; 205 | long r1 = 0, r2 = 0; 206 | int d1, d2; //d1 is the printf return and d2 ft_printf return. 207 | clock_t b, m, e; 208 | bool failed; 209 | 210 | current_arg = longify((void *)&arg, sizeof(T)); 211 | current_format = fmt; 212 | 213 | if (debug) 214 | cout("format: [%s], arg: %s\n", fmt, arg_to_string((long long)arg)); 215 | 216 | b = clock(); 217 | //true printf 218 | d1 = printf(fmt, arg); 219 | fflush(stdout); 220 | write(1, "", 1); 221 | 222 | last_time_update = time(NULL); //for timeout 223 | if ((r1 = read(fd[READ], printf_buff, sizeof(printf_buff) - 1)) < 0) 224 | perror("read"), exit(-1); 225 | printf_buff[r1] = 0; 226 | m = clock(); 227 | 228 | d2 = ft_printf(fmt, arg); 229 | write(1, "", 1); 230 | if ((r2 = read(fd[READ], ftprintf_buff, sizeof(ftprintf_buff) - 1)) < 0) 231 | perror("read"), exit(-1); 232 | ftprintf_buff[r2] = 0; 233 | 234 | e = clock(); 235 | 236 | long r = MAX(r1 - 1, d1); 237 | if (debug) 238 | { 239 | cout(" printf: ["); 240 | print_mem(printf_buff, r1); 241 | cout("]\nft_printf: ["); 242 | print_mem(ftprintf_buff, r2); 243 | cout("]\n\n"); 244 | cout("r = %li, r1 = %li, r2 = %li\n", r, r1, r2); 245 | } 246 | 247 | if (current_index == 0) 248 | current_speed_percent = (double)(e - m) / (double)(m - b); 249 | else if (m - b != 0) 250 | { 251 | double h = 1. / ((double)current_index + 1.); 252 | double w = h * (current_index); 253 | current_speed_percent = current_speed_percent * w + ((e - m) / (m - b) * h); 254 | } 255 | 256 | failed = false; 257 | if (d1 != d2) 258 | { 259 | if (!quiet) 260 | { 261 | cout("%sbad return value for format \"%s\" and arg: %s -> got: %i expected %i\n%s", C_ERROR, current_format, arg_to_string((long long)arg), d2, d1, C_CLEAR); 262 | } 263 | if (stop_to_first_error) 264 | exit(0); 265 | failed_tests++; 266 | failed = true; 267 | } 268 | if (memcmp(printf_buff, ftprintf_buff, r)) 269 | { 270 | if (!quiet) 271 | cout("%s[ERROR] diff on output for format \"%s\" and arg: %s\nexpected: [%s]\n got: [%s]\n%s", C_ERROR, current_format, arg_to_string((long long)arg), escapeBuff(printf_buff, r, 0), escapeBuff(ftprintf_buff, r, 1), C_CLEAR); 272 | if (stop_to_first_error) 273 | exit(0); 274 | if (!failed) 275 | failed_tests++; 276 | } 277 | else 278 | passed_tests++; 279 | 280 | if (verbose && failed) 281 | { 282 | cout(" printf: ["); 283 | print_mem(printf_buff, r1); 284 | cout("]\nft_printf: ["); 285 | print_mem(ftprintf_buff, r2); 286 | cout("]\n\n"); 287 | cout("r = %li, r1 = %li, r2 = %li\n", r, r1, r2); 288 | } 289 | 290 | //split and diff the results 291 | (void)index; 292 | } 293 | 294 | #define generateRunTest(type) static void runTest_##type(const char *fmt, int (*ft_printf)(const char *f, ...), int fd[2], type c) \ 295 | { \ 296 | runTestSpec< type >(fmt, ft_printf, fd, c); \ 297 | } 298 | 299 | generateRunTest(int) 300 | generateRunTest(long) 301 | generateRunTest(string) 302 | generateRunTest(wstring) 303 | generateRunTest(wchar_t) 304 | generateRunTest(char) 305 | generateRunTest(double) 306 | generateRunTest(ptr) 307 | 308 | static void run_tests(int (*ft_printf)(const char *, ...), const char *convs, const char *allowed_convs) 309 | { 310 | int fd[2]; 311 | int index; 312 | int total_test_count = 0; 313 | int test_count = 0; 314 | int old_failed_tests; 315 | long long args[0xF0]; 316 | int argc; 317 | 318 | if (*convs) 319 | printf("Starting tests ...\n"); 320 | if (pipe(fd) != 0) 321 | perror("pipe"), exit(-1); 322 | dup2(fd[WRITE], STDOUT_FILENO); 323 | close(fd[WRITE]); 324 | setbuf(stdout, NULL); 325 | setlocale(LC_ALL, ""); 326 | while (*convs) 327 | { 328 | if (!strchr(allowed_convs, *convs) && convs++) 329 | continue ; 330 | current_conv = *convs; 331 | old_failed_tests = failed_tests; 332 | cout("%stesting %%%c ...\n%s", C_TITLE, *convs, C_CLEAR); 333 | index = -1; 334 | test_count = 0; 335 | disable_timeout = true; 336 | auto formats = generateTestFormats(*convs); 337 | disable_timeout = false; 338 | for (auto fmt : formats) 339 | { 340 | index++; 341 | current_index = index; 342 | argc = generateRandArgs(*convs, fmt.c_str(), args); 343 | g_current_test_index = -1; 344 | setjmp(jmp_next_test); 345 | while (++g_current_test_index < argc) 346 | { 347 | int convIndex = (int)*convs; 348 | if (*convs == 'c' && fmt.find('l') != std::string::npos) 349 | convIndex = 'C'; 350 | if (*convs == 's' && fmt.find('l') != std::string::npos) 351 | convIndex = 'S'; 352 | ((void (*)(const char *, int (*)(const char *, ...), int[2], ...))runTestFuncs[convIndex])(fmt.c_str(), ft_printf, fd, args[g_current_test_index]); 353 | total_test_count++; 354 | test_count++; 355 | } 356 | } 357 | if (failed_tests == old_failed_tests) 358 | coutl2(C_PASS, "Passed all %'i tests for convertion %c\n", test_count, *convs); 359 | else 360 | coutl2(C_ERROR, "Failed %'i of %'i tests for convertion %c\n", failed_tests - old_failed_tests, test_count, *convs); 361 | if (!no_speed) 362 | { 363 | coutl2(C_PASS, "On %c convertion, your printf is %.2f times slower than system's\n", *convs, current_speed_percent); 364 | } 365 | convs++; 366 | } 367 | coutl2(C_CLEAR, "Total tested format count: %i\n", total_test_count); 368 | } 369 | 370 | static void *timeout_thread(void *t) 371 | { 372 | (void)t; 373 | while (42) 374 | { 375 | sleep(1); 376 | if (disable_timeout) 377 | last_time_update = time(NULL); 378 | if (time(NULL) - last_time_update > 3) //3sec passed on ftprintf function 379 | { 380 | cout("%sTimeout on format: \"%s\" with argument: %lli\n%s", C_ERROR, current_format, arg_to_string(current_arg), C_CLEAR); 381 | exit(0); 382 | } 383 | } 384 | } 385 | 386 | static void options(int ac, char **av) 387 | { 388 | int opt; 389 | 390 | while ((opt = getopt(ac, av, "vheqdrf:")) != -1) 391 | switch (opt) 392 | { 393 | case 'h': 394 | usage(); 395 | case 'e': 396 | stop_to_first_error = true; 397 | break ; 398 | case 'q': 399 | quiet = true; 400 | break ; 401 | case 'd': 402 | debug = true; 403 | break ; 404 | case 'r': 405 | no_speed = true; 406 | break ; 407 | case 'v': 408 | verbose = true; 409 | break ; 410 | case 'f': 411 | C_ERROR = ""; 412 | C_PASS = ""; 413 | C_CRASH = ""; 414 | C_TITLE = ""; 415 | C_CLEAR = ""; 416 | output_fd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 0644); 417 | break ; 418 | } 419 | } 420 | 421 | static void InitRunTest() 422 | { 423 | runTestFuncs[(int)'c'] = (void *)runTest_char; 424 | runTestFuncs[(int)'s'] = (void *)runTest_string; 425 | runTestFuncs[(int)'p'] = (void *)runTest_ptr; 426 | runTestFuncs[(int)'d'] = (void *)runTest_int; 427 | runTestFuncs[(int)'i'] = (void *)runTest_int; 428 | runTestFuncs[(int)'u'] = (void *)runTest_int; 429 | runTestFuncs[(int)'x'] = (void *)runTest_int; 430 | runTestFuncs[(int)'X'] = (void *)runTest_int; 431 | runTestFuncs[(int)'f'] = (void *)runTest_double; 432 | runTestFuncs[(int)'g'] = (void *)runTest_double; 433 | runTestFuncs[(int)'e'] = (void *)runTest_double; 434 | 435 | (void)runTest_long; 436 | (void)runTest_wchar_t; 437 | (void)runTest_wstring; 438 | // runTestFuncs[(int)'O'] = (void *)runTest_long; 439 | // runTestFuncs[(int)'D'] = (void *)runTest_long; 440 | // runTestFuncs[(int)'U'] = (void *)runTest_long; 441 | 442 | 443 | // runTestFuncs[(int)'E'] = (void *)runTest_double; 444 | // runTestFuncs[(int)'F'] = (void *)runTest_double; 445 | // runTestFuncs[(int)'G'] = (void *)runTest_double; 446 | // runTestFuncs[(int)'a'] = (void *)runTest_double; 447 | // runTestFuncs[(int)'A'] = (void *)runTest_double; 448 | 449 | // runTestFuncs[(int)'C'] = (void *)runTest_wchar_t; 450 | // runTestFuncs[(int)'S'] = (void *)runTest_wstring; 451 | // runTestFuncs[(int)'o'] = (void *)runTest_int; 452 | } 453 | 454 | int main(int ac, char **av) 455 | { 456 | void *ftprintf_handler; 457 | const char *testflags = DEFAULT_CONVERTERS; 458 | int (*ft_printf)(const char *, ...); 459 | pthread_t p; 460 | 461 | options(ac, av); 462 | ac -= optind; 463 | av += optind; 464 | if (ac == 1) 465 | testflags = av[0]; 466 | 467 | logfile_fd = open(LOG_FILE, O_WRONLY | O_TRUNC | O_CREAT, 0644); 468 | 469 | InitRunTest(); 470 | signal(SIGSEGV, sigh); 471 | signal(SIGBUS, sigh); 472 | signal(SIGPIPE, sigh); 473 | if (!(ftprintf_handler = dlopen(FTPRINTF_LIB_SO, RTLD_LAZY))) 474 | perror("dlopen"), exit(-1); 475 | if (!(ft_printf = (int (*)(const char *, ...))dlsym(ftprintf_handler, "ft_printf"))) 476 | perror("dlsym"), exit(-1); 477 | if ((pthread_create(&p, NULL, timeout_thread, NULL)) == -1) 478 | printf("%sthread init failed%s", C_ERROR, C_CLEAR), exit(-1); 479 | run_tests(ft_printf, testflags, SUPPORTED_CONVERTERS); 480 | return (0); 481 | } 482 | -------------------------------------------------------------------------------- /src/random_args.cpp: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* random_args.c :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alelievr +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created: 2017/01/08 16:04:18 by alelievr #+# #+# */ 9 | /* Updated: 2018/02/06 13:23:20 by alelievr ### ########.fr */ 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "printf_unit_test.h" 18 | 19 | static const char * randomStrings[] = { 20 | "#nyancat inside", 21 | "\x7f", 22 | "The Game.", 23 | "I know what you are doing.", 24 | "You should better not go to sleep.", 25 | "Drop the keyboard and RUN!", 26 | "Any invalid command will remove a random file from your home.", 27 | "You will die before this tests ends.", 28 | "I love the smell of bugs in the morning.", 29 | "What do you want to debug today?", 30 | "rm: /: Permission denied.", 31 | "Already up-to-date.", 32 | ":(){ :|:& };:", 33 | "Do you want to print 333.5K chars? (y/N)", 34 | "Try with ASAN, and be amazed", 35 | "Remember that word: C H A I R", 36 | "Good morning, pal *<:-)", 37 | "WASTED", 38 | "Too old to crash", 39 | "don’t feed the bugs! (except delicious stacktraces)!", 40 | "Beer in mind.", 41 | "3nl4r9e y0\\/r pr1ntf", 42 | "Don't do this.", 43 | "No fix, no sleep", 44 | "/dev/brain: No such file or directory." 45 | }; 46 | 47 | static int generateRandomInts(long long *args, int n) 48 | { 49 | intmax_t r; 50 | int ret = 1; 51 | 52 | *args++ = 0; 53 | for (int i = 0; i < n; i++) 54 | { 55 | r = ((intmax_t)rand() * (intmax_t)rand()); 56 | *args++ = LONGIFY(r); 57 | ret++; 58 | } 59 | return (ret); 60 | } 61 | 62 | static int generateRandomFloats(long long *args, int n) 63 | { 64 | float r; 65 | int ret = 3; 66 | 67 | *args++ = 0; 68 | r = NAN; 69 | *args++ = LONGIFY(r); 70 | r = INFINITY; 71 | *args++ = LONGIFY(r); 72 | for (int i = 0; i < n; i++) 73 | { 74 | if (rand() % 2) 75 | r = ((float)(int)rand() / (float)(int)rand()); 76 | else 77 | r = ((float)(int)rand() * (float)(int)rand()); 78 | *args++ = LONGIFY(r); 79 | ret++; 80 | } 81 | return (ret); 82 | } 83 | 84 | #include 85 | static int generateRandomStrings(long long *args, int n) 86 | { 87 | const char *r = ""; 88 | int ret = 2; 89 | 90 | *args++ = LONGIFY(r); 91 | r = NULL; 92 | *args++ = LONGIFY(r); 93 | for (int i = 0; i < n; i++) 94 | { 95 | r = randomStrings[rand() % (sizeof(randomStrings) / sizeof(char *))]; 96 | *args++ = LONGIFY(r); 97 | ret++; 98 | } 99 | return (ret); 100 | } 101 | 102 | static int generateRandomWStrings(long long *args, int n) 103 | { 104 | const wchar_t *r = L""; 105 | int ret = 2; 106 | 107 | *args++ = LONGIFY(r); 108 | r = NULL; 109 | *args++ = LONGIFY(r); 110 | for (int i = 0; i < n; i++) 111 | { 112 | r = (const wchar_t *[]){L"こんにちは、私はprintf単体テストです", 113 | L"いいえ", 114 | L"最終的なフラッシュ", 115 | L"(╯°□°)╯︵ ┻━┻ ", 116 | L"(╯°□°)╯︵ ┻━┻ ︵ ╯(°□° ╯)", 117 | L"┬─┬ ノ( ゜-゜ノ)", 118 | L"(╯°Д°)╯︵ /(.□ . \\)", 119 | L"(/ .□.)\\ ︵╰(゜Д゜)╯︵ /(.□. \\)", 120 | L"ʕノ•ᴥ•ʔノ ︵ ┻━┻ " 121 | }[rand() % 9]; 122 | *args++ = LONGIFY(r); 123 | ret++; 124 | } 125 | return (ret); 126 | } 127 | 128 | static int generateRandomChars(long long *args, int n) 129 | { 130 | char r = '\0'; 131 | int ret = 1; 132 | 133 | *args++ = LONGIFY(r); 134 | for (int i = 0; i < n; i++) 135 | { 136 | r = (char)(rand() % 256); 137 | if (r == '\x99') 138 | r = 42; 139 | *args++ = LONGIFY(r); 140 | ret++; 141 | } 142 | return (ret); 143 | } 144 | 145 | static int generateRandomWChars(long long *args, int n) 146 | { 147 | wchar_t r = '\0'; 148 | int ret = 1; 149 | 150 | *args++ = LONGIFY(r); 151 | for (int i = 0; i < n; i++) 152 | { 153 | r = (wchar_t []){L'⭐', L'💖', L'⚔', L'☕', L'☠', L'⚡', L'Ω', L'ø', L'π'}[rand() % 9]; 154 | *args++ = LONGIFY(r); 155 | ret++; 156 | } 157 | return (ret); 158 | } 159 | 160 | static int generateRandomPointers(long long *args, int n) 161 | { 162 | void *r = NULL; 163 | int ret = 1; 164 | 165 | *args++ = LONGIFY(r); 166 | for (int i = 0; i < n; i++) 167 | { 168 | r = (void *)(unsigned long)rand(); 169 | *args++ = LONGIFY(r); 170 | ret++; 171 | } 172 | return (ret); 173 | } 174 | 175 | int generateRandArgs(char conv, const char *mods, long long *args) 176 | { 177 | int n_rand_args = 5; 178 | 179 | if (strchr("idDoOuUxX", conv)) 180 | return generateRandomInts(args, n_rand_args); 181 | if (strchr("aAeEfFgG", conv)) 182 | return generateRandomFloats(args, n_rand_args); 183 | if (conv == 'S' || (conv == 's' && strchr(mods, 'l'))) 184 | return generateRandomWStrings(args, n_rand_args); 185 | if (conv == 's') 186 | return generateRandomStrings(args, n_rand_args); 187 | if (conv == 'C' || (conv == 'c' && strchr(mods, 'l'))) 188 | return generateRandomWChars(args, n_rand_args); 189 | if (conv == 'c') 190 | return generateRandomChars(args, n_rand_args); 191 | if (conv == 'p') 192 | return generateRandomPointers(args, n_rand_args); 193 | return (0); 194 | } 195 | 196 | -------------------------------------------------------------------------------- /src/source_generator.cpp: -------------------------------------------------------------------------------- 1 | /* ************************************************************************** */ 2 | /* */ 3 | /* ::: :::::::: */ 4 | /* source-generator.cpp :+: :+: :+: */ 5 | /* +:+ +:+ +:+ */ 6 | /* By: alelievr +#+ +:+ +#+ */ 7 | /* +#+#+#+#+#+ +#+ */ 8 | /* Created 2016/12/22 16:20:34 by alelievr #+# #+# */ 9 | // Updated: 2019/11/19 14:42:29 by juligonz ### ########.fr // 10 | /* */ 11 | /* ************************************************************************** */ 12 | 13 | #include "source-generator.h" 14 | 15 | static std::list< intmax_t > generateRandomNumbers(size_t num, intmax_t mask, bool sup = false) 16 | { 17 | std::list< intmax_t > ints; 18 | intmax_t r; 19 | 20 | if (sup) 21 | { 22 | ints.push_back(NOALIGN); 23 | ints.push_back(2); 24 | } 25 | 26 | for (size_t i = 0; i < num; i++) 27 | { 28 | r = ((intmax_t)rand() * (intmax_t)rand()) & mask; 29 | if (r == 0 || r == NOALIGN) 30 | r = 42; 31 | ints.push_back(r); 32 | } 33 | return ints; 34 | } 35 | 36 | static std::list< std::string > generateRandomStrings(size_t num) 37 | { 38 | std::list< std::string > strs; 39 | 40 | strs.push_back(""); 41 | 42 | for (size_t i = 0; i < num; i++) 43 | strs.push_back(rand_strings[(int)(rand() % (int)(sizeof(rand_strings) / sizeof(char *)))]); 44 | return strs; 45 | } 46 | 47 | static std::list< std::string > generateModifiers(char convertion) 48 | { 49 | std::list< std::string > mods; 50 | 51 | mods.push_back(""); 52 | if (strchr("aAeEfFgGcs", convertion)) 53 | mods.push_back("l"); 54 | if (strchr("idouxXDOU", convertion)) 55 | { 56 | mods.push_back("ll"); 57 | mods.push_back("l"); 58 | mods.push_back("h"); 59 | mods.push_back("hh"); 60 | // mods.push_back("j"); 61 | // mods.push_back("z"); 62 | } 63 | return mods; 64 | } 65 | 66 | std::list< std::string > generateTestFormats(char convertion) 67 | { 68 | std::string fmt; 69 | std::list< std::string > retFormats; 70 | 71 | srand((unsigned)time(NULL) + (unsigned)clock()); 72 | 73 | for (const char & c1 : PRINTF_FLAGS_BASIC) //first flag 74 | for (const char & c2 : PRINTF_FLAGS_BASIC) //second flag 75 | for (const char & c3 : PRINTF_FLAGS_BASIC) //... 76 | for (const char & c4 : PRINTF_FLAGS_BASIC) 77 | for (const char & c5 : PRINTF_FLAGS_BASIC) 78 | for (const intmax_t & align : generateRandomNumbers(2, 0x3F, true)) //align attribute 79 | for (const intmax_t & padd : generateRandomNumbers(2, 0x3F, true)) //padding attribute 80 | for (const std::string & modifier : generateModifiers(convertion)) 81 | for (const std::string & prefix : generateRandomStrings(1)) //additional string to format 82 | for (const std::string & sufix : generateRandomStrings(0)) //additional string to format 83 | { 84 | fmt = prefix + "%"; 85 | for (const char & c : {c1, c2, c3, c4, c5}) 86 | if (c && c != NO_FLAG[0]) 87 | { 88 | if (fmt.find(c) != std::string::npos) //flag duplication, aborting ... 89 | goto abortCurrentFormat; 90 | fmt += c; 91 | } 92 | //check converter to flag incompat 93 | for (size_t i = 0; i < sizeof(convertion_to_flag_incompatibilities) / sizeof(char[2]); i++) 94 | if (convertion == convertion_to_flag_incompatibilities[i][0] && fmt.find(convertion_to_flag_incompatibilities[i][1]) != std::string::npos) 95 | goto abortCurrentFormat; 96 | //check flag to flag incompat 97 | for (size_t i = 0; i < sizeof(flag_to_flag_incompatibilities) / sizeof(char[2]); i++) 98 | if (fmt.find(flag_to_flag_incompatibilities[i][0]) != std::string::npos && fmt.find(flag_to_flag_incompatibilities[i][1]) != std::string::npos) 99 | goto abortCurrentFormat; 100 | if (align != NOALIGN) 101 | fmt += std::to_string(align); 102 | if (!strchr("pcCS", convertion) && padd != NOPADD) 103 | fmt += "." + std::to_string(padd); 104 | fmt += modifier + convertion + sufix + prefix; //to test with string before and after 105 | retFormats.push_front(fmt); 106 | abortCurrentFormat: 107 | ; 108 | } 109 | return retFormats; 110 | } 111 | --------------------------------------------------------------------------------