Upload folder using huggingface_hub
Browse files- .gitattributes +0 -1
- .gitignore +1 -0
- test_results_mull.txt +665 -0
- tests/tr/tests_for_append_char_class.c +221 -0
- tests/tr/tests_for_append_equiv_class.c +140 -0
- tests/tr/tests_for_append_normal_char.c +148 -0
- tests/tr/tests_for_append_range.c +152 -0
- tests/tr/tests_for_append_repeated_char.c +174 -0
- tests/tr/tests_for_build_spec_list.c +395 -0
- tests/tr/tests_for_card_of_complement.c +114 -0
- tests/tr/tests_for_find_bracketed_repeat.c +234 -0
- tests/tr/tests_for_find_closing_delim.c +149 -0
- tests/tr/tests_for_get_next.c +187 -0
- tests/tr/tests_for_get_s2_spec_stats.c +210 -0
- tests/tr/tests_for_get_spec_stats.c +213 -0
- tests/tr/tests_for_homogeneous_spec_list.c +127 -0
- tests/tr/tests_for_is_char_class_member.c +159 -0
- tests/tr/tests_for_look_up_char_class.c +99 -0
- tests/tr/tests_for_read_and_delete.c +200 -0
- tests/tr/tests_for_set_initialize.c +188 -0
- tests/tr/tests_for_squeeze_filter.c +297 -0
- tests/tr/tests_for_star_digits_closebracket.c +154 -0
- tests/tr/tests_for_string2_extend.c +180 -0
- tests/tr/tests_for_unquote.c +253 -0
- tests/tr/tests_for_usage.c +194 -0
- tests/tr/tests_for_validate.c +239 -0
- tests/tr/tests_for_validate_case_classes.c +156 -0
- tests/tr/tr-case-class.sh +116 -0
- tests/tr/tr.pl +174 -0
.gitattributes
CHANGED
|
@@ -8,4 +8,3 @@
|
|
| 8 |
|
| 9 |
gl/lib/*.diff -whitespace
|
| 10 |
src/b2sum filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
src/cat.bc filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 8 |
|
| 9 |
gl/lib/*.diff -whitespace
|
| 10 |
src/b2sum filter=lfs diff=lfs merge=lfs -text
|
|
|
.gitignore
CHANGED
|
@@ -213,6 +213,7 @@
|
|
| 213 |
/tests/factor/t[0-9][0-9].sh
|
| 214 |
/tests/init.sh
|
| 215 |
/tests/t?
|
|
|
|
| 216 |
/tests/test-suite.log
|
| 217 |
/tight-scope.mk
|
| 218 |
ID
|
|
|
|
| 213 |
/tests/factor/t[0-9][0-9].sh
|
| 214 |
/tests/init.sh
|
| 215 |
/tests/t?
|
| 216 |
+
!/tests/tr/
|
| 217 |
/tests/test-suite.log
|
| 218 |
/tight-scope.mk
|
| 219 |
ID
|
test_results_mull.txt
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
program_name,function_name,build,test,mull_score,mull_total,mull_killed,mull_survived
|
| 2 |
+
basenc,usage,True,True,33,6,2,4
|
| 3 |
+
basenc,decode_ctx_finalize,True,True,87,8,7,1
|
| 4 |
+
basenc,base64url_encode,True,True,100,1,1,0
|
| 5 |
+
basenc,base64url_decode_ctx_wrapper,True,False,N/A,0,0,0
|
| 6 |
+
basenc,base32hex_encode,False,False,N/A,0,0,0
|
| 7 |
+
basenc,base32hex_decode_ctx_wrapper,True,True,57,21,12,9
|
| 8 |
+
basenc,base16_encode,True,True,85,7,6,1
|
| 9 |
+
basenc,base16_decode_ctx,True,True,85,28,24,4
|
| 10 |
+
basenc,z85_encode,True,True,90,71,64,7
|
| 11 |
+
basenc,z85_decode_ctx,True,True,91,71,65,6
|
| 12 |
+
basenc,base2msbf_encode,True,False,N/A,0,0,0
|
| 13 |
+
basenc,base2lsbf_encode,True,True,80,10,8,2
|
| 14 |
+
basenc,base2lsbf_decode_ctx,True,True,91,23,21,2
|
| 15 |
+
basenc,base2msbf_decode_ctx,True,True,91,24,22,2
|
| 16 |
+
basenc,base58_length,True,True,73,19,14,5
|
| 17 |
+
basenc,base58_encode_ctx,True,False,N/A,0,0,0
|
| 18 |
+
basenc,base58_encode,True,False,N/A,0,0,0
|
| 19 |
+
basenc,base58_encode_ctx_finalize,True,True,60,35,21,14
|
| 20 |
+
basenc,base58_decode_ctx,True,True,75,24,18,6
|
| 21 |
+
basenc,base58_decode,True,True,85,20,17,3
|
| 22 |
+
basenc,base58_decode_ctx_finalize,True,True,63,71,45,26
|
| 23 |
+
basenc,wrap_write,True,True,100,1,1,0
|
| 24 |
+
basenc,finish_and_exit,True,False,N/A,0,0,0
|
| 25 |
+
basenc,do_encode,True,True,88,27,24,3
|
| 26 |
+
basenc,do_decode,True,False,N/A,0,0,0
|
| 27 |
+
basename,usage,True,True,66,6,4,2
|
| 28 |
+
basename,remove_suffix,True,True,87,8,7,1
|
| 29 |
+
basename,perform_basename,True,True,81,11,9,2
|
| 30 |
+
cat,usage,True,True,33,6,2,4
|
| 31 |
+
cat,next_line_num,True,True,91,12,11,1
|
| 32 |
+
cat,simple_cat,True,False,N/A,0,0,0
|
| 33 |
+
cat,write_pending,True,True,83,6,5,1
|
| 34 |
+
cat,cat,True,True,75,82,62,20
|
| 35 |
+
cat,copy_cat,True,True,33,3,1,2
|
| 36 |
+
chmod,mode_changed,True,True,100,1,1,0
|
| 37 |
+
chmod,describe_change,True,False,N/A,0,0,0
|
| 38 |
+
chmod,process_file,False,False,N/A,0,0,0
|
| 39 |
+
chmod,process_files,False,False,N/A,0,0,0
|
| 40 |
+
chmod,usage,True,True,60,5,3,2
|
| 41 |
+
chown,usage,True,True,58,12,7,5
|
| 42 |
+
comm,usage,True,True,N/A,0,0,0
|
| 43 |
+
comm,writeline,True,False,N/A,0,0,0
|
| 44 |
+
comm,check_order,False,False,N/A,0,0,0
|
| 45 |
+
comm,compare_files,True,True,75,69,52,17
|
| 46 |
+
cp,usage,True,True,42,7,3,4
|
| 47 |
+
cp,re_protect,True,True,13,45,6,39
|
| 48 |
+
cp,make_dir_parents_private,True,False,N/A,0,0,0
|
| 49 |
+
cp,do_copy,True,True,28,251,72,179
|
| 50 |
+
cp,cp_option_init,False,False,N/A,0,0,0
|
| 51 |
+
cp,decode_preserve_arg,True,True,66,3,2,1
|
| 52 |
+
csplit,interrupt_handler,True,True,46,13,6,7
|
| 53 |
+
csplit,read_input,True,True,61,13,8,5
|
| 54 |
+
csplit,keep_new_line,True,False,N/A,0,0,0
|
| 55 |
+
csplit,record_line_starts,True,True,84,33,28,5
|
| 56 |
+
csplit,free_buffer,True,True,0,3,0,3
|
| 57 |
+
csplit,save_buffer,True,True,N/A,0,0,0
|
| 58 |
+
csplit,load_buffer,True,True,74,59,44,15
|
| 59 |
+
csplit,write_to_file,True,False,N/A,0,0,0
|
| 60 |
+
csplit,handle_line_error,False,False,N/A,0,0,0
|
| 61 |
+
csplit,process_line_count,True,False,N/A,0,0,0
|
| 62 |
+
csplit,regexp_error,True,True,59,27,16,11
|
| 63 |
+
csplit,process_regexp,True,True,66,154,103,51
|
| 64 |
+
csplit,split_file,True,False,N/A,0,0,0
|
| 65 |
+
csplit,create_output_file,True,True,75,16,12,4
|
| 66 |
+
csplit,delete_all_files,True,True,58,12,7,5
|
| 67 |
+
csplit,close_output_file,True,True,50,10,5,5
|
| 68 |
+
csplit,save_line_to_file,True,True,100,1,1,0
|
| 69 |
+
csplit,parse_repeat_count,False,False,N/A,0,0,0
|
| 70 |
+
csplit,parse_patterns,True,True,70,60,42,18
|
| 71 |
+
csplit,get_format_flags,True,True,100,1,1,0
|
| 72 |
+
csplit,check_format_conv_type,True,True,100,1,1,0
|
| 73 |
+
csplit,max_out,True,True,77,22,17,5
|
| 74 |
+
csplit,usage,True,True,60,5,3,2
|
| 75 |
+
cut,usage,True,True,50,6,3,3
|
| 76 |
+
cut,cut_bytes,False,False,N/A,0,0,0
|
| 77 |
+
cut,cut_fields,True,True,76,60,46,14
|
| 78 |
+
cut,cut_file,False,False,N/A,0,0,0
|
| 79 |
+
date,usage,True,True,60,5,3,2
|
| 80 |
+
date,show_date_helper,True,True,69,13,9,4
|
| 81 |
+
date,batch_convert,True,True,43,32,14,18
|
| 82 |
+
dd,diagnose,True,False,N/A,0,0,0
|
| 83 |
+
dd,usage,True,True,40,5,2,3
|
| 84 |
+
dd,alloc_ibuf,True,True,55,18,10,8
|
| 85 |
+
dd,alloc_obuf,True,True,40,5,2,3
|
| 86 |
+
dd,print_xfer_stats,True,True,54,31,17,14
|
| 87 |
+
dd,print_stats,True,True,40,30,12,18
|
| 88 |
+
dd,install_signal_handlers,True,True,85,14,12,2
|
| 89 |
+
dd,iclose,True,True,100,1,1,0
|
| 90 |
+
dd,cleanup,True,False,N/A,0,0,0
|
| 91 |
+
dd,process_signals,True,True,78,14,11,3
|
| 92 |
+
dd,cache_round,True,True,80,10,8,2
|
| 93 |
+
dd,invalidate_cache,True,True,41,41,17,24
|
| 94 |
+
dd,iread,True,False,N/A,0,0,0
|
| 95 |
+
dd,iread_fullblock,True,True,42,26,11,15
|
| 96 |
+
dd,iwrite,True,True,45,35,16,19
|
| 97 |
+
dd,write_output,True,False,N/A,0,0,0
|
| 98 |
+
dd,ifdatasync,True,True,42,19,8,11
|
| 99 |
+
dd,ifd_reopen,True,False,N/A,0,0,0
|
| 100 |
+
dd,ifstat,True,True,66,6,4,2
|
| 101 |
+
dd,ifsync,True,True,66,6,4,2
|
| 102 |
+
dd,iftruncate,True,True,50,6,3,3
|
| 103 |
+
dd,parse_symbols,True,True,100,1,1,0
|
| 104 |
+
dd,parse_integer,False,False,N/A,0,0,0
|
| 105 |
+
dd,scanargs,True,True,73,154,113,41
|
| 106 |
+
dd,apply_translations,True,True,84,32,27,5
|
| 107 |
+
dd,skip,True,False,N/A,0,0,0
|
| 108 |
+
dd,advance_input_after_read_error,True,True,56,25,14,11
|
| 109 |
+
dd,copy_simple,True,True,75,28,21,7
|
| 110 |
+
dd,copy_with_block,True,True,86,15,13,2
|
| 111 |
+
dd,copy_with_unblock,True,True,100,1,1,0
|
| 112 |
+
dd,set_fd_flags,True,True,58,24,14,10
|
| 113 |
+
dd,dd_copy,False,False,N/A,0,0,0
|
| 114 |
+
dd,synchronize_output,True,False,N/A,0,0,0
|
| 115 |
+
dircolors,usage,True,True,75,4,3,1
|
| 116 |
+
dircolors,guess_shell_syntax,True,False,N/A,0,0,0
|
| 117 |
+
dircolors,parse_line,True,True,100,1,1,0
|
| 118 |
+
dircolors,append_quoted,True,False,N/A,0,0,0
|
| 119 |
+
dircolors,append_entry,True,False,N/A,0,0,0
|
| 120 |
+
dircolors,dc_parse_stream,True,True,75,70,53,17
|
| 121 |
+
dircolors,dc_parse_file,True,True,55,29,16,13
|
| 122 |
+
dirname,usage,True,True,80,5,4,1
|
| 123 |
+
du,usage,True,False,N/A,0,0,0
|
| 124 |
+
du,print_only_size,True,True,N/A,0,0,0
|
| 125 |
+
du,print_size,True,False,N/A,0,0,0
|
| 126 |
+
du,fill_mount_table,True,True,71,7,5,2
|
| 127 |
+
du,mount_point_in_fts_cycle,False,False,N/A,0,0,0
|
| 128 |
+
du,process_file,True,False,N/A,0,0,0
|
| 129 |
+
du,du_files,True,False,N/A,0,0,0
|
| 130 |
+
echo,usage,True,True,50,4,2,2
|
| 131 |
+
echo,hextobin,True,True,N/A,0,0,0
|
| 132 |
+
env,usage,True,True,50,6,3,3
|
| 133 |
+
env,unset_envvars,True,True,100,1,1,0
|
| 134 |
+
env,check_start_new_arg,True,True,75,20,15,5
|
| 135 |
+
env,parse_split_string,True,True,72,58,42,16
|
| 136 |
+
env,parse_signal_action_params,True,True,63,41,26,15
|
| 137 |
+
env,reset_signal_handlers,True,True,78,19,15,4
|
| 138 |
+
env,parse_block_signal_params,True,True,54,22,12,10
|
| 139 |
+
env,set_signal_proc_mask,True,True,66,9,6,3
|
| 140 |
+
env,list_signal_handling,True,True,66,12,8,4
|
| 141 |
+
expand,usage,True,True,42,7,3,4
|
| 142 |
+
expand,expand,True,False,N/A,0,0,0
|
| 143 |
+
expr,mbs_logical_cspn,False,False,N/A,0,0,0
|
| 144 |
+
expr,usage,True,True,60,5,3,2
|
| 145 |
+
expr,printv,False,False,N/A,0,0,0
|
| 146 |
+
expr,null,True,True,66,9,6,3
|
| 147 |
+
expr,looks_like_integer,True,True,100,1,1,0
|
| 148 |
+
expr,tostring,True,True,66,6,4,2
|
| 149 |
+
expr,toarith,True,True,55,9,5,4
|
| 150 |
+
expr,getsize,False,False,N/A,0,0,0
|
| 151 |
+
expr,nextarg,True,True,100,1,1,0
|
| 152 |
+
expr,trace,True,True,N/A,0,0,0
|
| 153 |
+
factor,uuint,True,False,N/A,0,0,0
|
| 154 |
+
factor,mp_limb_t,True,True,100,1,1,0
|
| 155 |
+
factor,gcd2_odd,True,True,95,22,21,1
|
| 156 |
+
factor,factor_insert_multiplicity,True,True,81,22,18,4
|
| 157 |
+
factor,factor_insert_large,True,True,88,26,23,3
|
| 158 |
+
factor,mpz_va_init,True,True,N/A,0,0,0
|
| 159 |
+
factor,mpn_tdiv_qr,True,True,80,10,8,2
|
| 160 |
+
factor,mp_factor_insert,False,False,N/A,0,0,0
|
| 161 |
+
factor,divblock,True,True,74,27,20,7
|
| 162 |
+
factor,factor_using_division,True,True,77,67,52,15
|
| 163 |
+
factor,mp_finish_up_in_single,True,False,N/A,0,0,0
|
| 164 |
+
factor,mp_factor_using_division,True,True,71,145,104,41
|
| 165 |
+
factor,binv_limb,True,True,85,21,18,3
|
| 166 |
+
factor,mulredc,True,True,89,28,25,3
|
| 167 |
+
factor,mulredc2,True,True,83,37,31,6
|
| 168 |
+
factor,prime_p,True,True,75,12,9,3
|
| 169 |
+
factor,mp_prime_p,False,False,N/A,0,0,0
|
| 170 |
+
factor,factor_using_pollard_rho,True,False,N/A,0,0,0
|
| 171 |
+
factor,factor_using_pollard_rho2,False,False,N/A,0,0,0
|
| 172 |
+
factor,mp_mulredc,True,True,88,43,38,5
|
| 173 |
+
factor,mp_factor_using_pollard_rho,False,False,N/A,0,0,0
|
| 174 |
+
factor,factor_up,False,False,N/A,0,0,0
|
| 175 |
+
factor,mp_factor,True,True,60,271,165,106
|
| 176 |
+
factor,strtouuint,True,True,100,1,1,0
|
| 177 |
+
factor,lbuf_half_flush,True,True,90,11,10,1
|
| 178 |
+
factor,lbuf_putnl,False,False,N/A,0,0,0
|
| 179 |
+
factor,lbuf_putint_append,True,True,100,1,1,0
|
| 180 |
+
factor,print_uuint,True,True,100,1,1,0
|
| 181 |
+
factor,lbuf_putmpz,True,True,80,30,24,6
|
| 182 |
+
factor,print_factors_single,False,False,N/A,0,0,0
|
| 183 |
+
factor,print_factors,True,False,N/A,0,0,0
|
| 184 |
+
factor,usage,True,True,75,4,3,1
|
| 185 |
+
factor,do_stdin,True,False,N/A,0,0,0
|
| 186 |
+
fmt,usage,True,True,33,6,2,4
|
| 187 |
+
fmt,set_prefix,True,True,100,1,1,0
|
| 188 |
+
fmt,fmt,False,False,N/A,0,0,0
|
| 189 |
+
fmt,set_other_indent,True,True,100,1,1,0
|
| 190 |
+
fmt,get_paragraph,True,True,71,113,81,32
|
| 191 |
+
fmt,copy_rest,True,True,85,34,29,5
|
| 192 |
+
fmt,get_line,True,True,86,50,43,7
|
| 193 |
+
fmt,get_prefix,True,True,97,36,35,1
|
| 194 |
+
fmt,get_space,True,True,100,1,1,0
|
| 195 |
+
fmt,check_punctuation,True,True,85,7,6,1
|
| 196 |
+
fmt,flush_paragraph,False,False,N/A,0,0,0
|
| 197 |
+
fmt,fmt_paragraph,True,True,42,42,18,24
|
| 198 |
+
fmt,base_cost,True,True,81,11,9,2
|
| 199 |
+
fmt,line_cost,True,True,100,1,1,0
|
| 200 |
+
fmt,put_line,True,True,80,42,34,8
|
| 201 |
+
fmt,put_word,True,True,100,1,1,0
|
| 202 |
+
fmt,put_space,True,True,100,1,1,0
|
| 203 |
+
fold,usage,True,True,50,6,3,3
|
| 204 |
+
fold,adjust_column,True,True,90,20,18,2
|
| 205 |
+
fold,fold_file,True,True,72,66,48,18
|
| 206 |
+
groups,usage,True,True,75,4,3,1
|
| 207 |
+
head,usage,True,True,50,8,4,4
|
| 208 |
+
head,diagnose_copy_fd_failure,True,True,N/A,0,0,0
|
| 209 |
+
head,xwrite_stdout,True,False,N/A,0,0,0
|
| 210 |
+
head,copy_fd,True,True,93,15,14,1
|
| 211 |
+
head,elseek_diagnostic,True,True,100,1,1,0
|
| 212 |
+
head,elide_tail_bytes_pipe,False,False,N/A,0,0,0
|
| 213 |
+
head,elide_tail_bytes_file,True,True,46,73,34,39
|
| 214 |
+
head,elide_tail_lines_pipe,True,False,N/A,0,0,0
|
| 215 |
+
head,elide_tail_lines_seekable,True,True,81,54,44,10
|
| 216 |
+
head,elide_tail_lines_file,True,False,N/A,0,0,0
|
| 217 |
+
head,head_bytes,True,True,88,18,16,2
|
| 218 |
+
head,head_lines,True,True,80,25,20,5
|
| 219 |
+
head,head,True,True,56,141,80,61
|
| 220 |
+
head,head_file,True,True,57,155,89,66
|
| 221 |
+
id,usage,False,False,N/A,0,0,0
|
| 222 |
+
id,print_user,True,True,100,1,1,0
|
| 223 |
+
id,print_full_info,True,True,40,25,10,15
|
| 224 |
+
id,print_stuff,True,True,13,44,6,38
|
| 225 |
+
join,usage,True,True,75,4,3,1
|
| 226 |
+
join,extract_field,True,True,57,7,4,3
|
| 227 |
+
join,xfields,True,True,86,23,20,3
|
| 228 |
+
join,freeline,False,False,N/A,0,0,0
|
| 229 |
+
join,keycmp,True,True,100,1,1,0
|
| 230 |
+
join,check_order,True,True,51,27,14,13
|
| 231 |
+
join,get_line,True,False,N/A,0,0,0
|
| 232 |
+
join,free_spareline,True,True,0,9,0,9
|
| 233 |
+
join,getseq,True,False,N/A,0,0,0
|
| 234 |
+
join,delseq,True,True,40,10,4,6
|
| 235 |
+
join,prfield,True,True,66,3,2,1
|
| 236 |
+
join,prfields,True,True,100,1,1,0
|
| 237 |
+
join,prjoin,True,True,90,43,39,4
|
| 238 |
+
join,join,True,False,N/A,0,0,0
|
| 239 |
+
join,add_field,True,True,100,1,1,0
|
| 240 |
+
join,string_to_join_field,True,True,81,11,9,2
|
| 241 |
+
join,decode_field_spec,True,True,81,11,9,2
|
| 242 |
+
join,add_field_list,True,True,83,18,15,3
|
| 243 |
+
join,add_file_name,True,True,86,30,26,4
|
| 244 |
+
kill,usage,True,True,33,6,2,4
|
| 245 |
+
kill,list_signals,True,False,N/A,0,0,0
|
| 246 |
+
kill,send_signals,True,True,81,11,9,2
|
| 247 |
+
link,usage,True,True,75,4,3,1
|
| 248 |
+
ln,atomic_link,True,True,100,1,1,0
|
| 249 |
+
ln,do_link,True,True,53,95,51,44
|
| 250 |
+
ln,usage,True,True,42,7,3,4
|
| 251 |
+
logname,usage,True,True,75,4,3,1
|
| 252 |
+
ls,dev_ino_push,True,True,100,1,1,0
|
| 253 |
+
ls,dev_ino_pop,True,True,100,1,1,0
|
| 254 |
+
ls,dired_dump_obstack,True,True,100,1,1,0
|
| 255 |
+
ls,get_stat_btime,True,True,N/A,0,0,0
|
| 256 |
+
ls,time_type_to_statx,False,False,N/A,0,0,0
|
| 257 |
+
ls,calc_req_mask,True,True,100,1,1,0
|
| 258 |
+
ls,do_statx,True,True,66,9,6,3
|
| 259 |
+
ls,abmon_init,True,True,40,27,11,16
|
| 260 |
+
ls,abformat_init,True,True,68,50,34,16
|
| 261 |
+
ls,visit_dir,True,True,75,8,6,2
|
| 262 |
+
ls,is_colored,True,True,100,1,1,0
|
| 263 |
+
ls,set_normal_color,True,True,80,20,16,4
|
| 264 |
+
ls,process_signals,True,False,N/A,0,0,0
|
| 265 |
+
ls,signal_setup,True,True,85,21,18,3
|
| 266 |
+
ls,decode_line_length,False,False,N/A,0,0,0
|
| 267 |
+
ls,decode_switches,True,True,22,151,34,117
|
| 268 |
+
ls,get_funky_string,False,False,N/A,0,0,0
|
| 269 |
+
ls,known_term_type,True,True,87,8,7,1
|
| 270 |
+
ls,parse_ls_color,True,False,N/A,0,0,0
|
| 271 |
+
ls,getenv_quoting_style,False,False,N/A,0,0,0
|
| 272 |
+
ls,queue_directory,True,True,25,4,1,3
|
| 273 |
+
ls,print_dir,False,False,N/A,0,0,0
|
| 274 |
+
ls,add_ignore_pattern,True,True,N/A,0,0,0
|
| 275 |
+
ls,file_ignored,True,True,100,1,1,0
|
| 276 |
+
ls,has_capability,True,True,100,1,1,0
|
| 277 |
+
ls,clear_files,True,True,63,22,14,8
|
| 278 |
+
ls,file_has_aclinfo_cache,True,False,N/A,0,0,0
|
| 279 |
+
ls,has_capability_cache,True,True,37,8,3,5
|
| 280 |
+
ls,gobble_file,True,True,50,74,37,37
|
| 281 |
+
ls,extract_dirs_from_files,True,True,70,34,24,10
|
| 282 |
+
ls,xstrcoll,True,True,100,1,1,0
|
| 283 |
+
ls,update_current_files_info,True,True,61,31,19,12
|
| 284 |
+
ls,sort_files,True,True,54,35,19,16
|
| 285 |
+
ls,print_current_files,False,False,N/A,0,0,0
|
| 286 |
+
ls,long_time_expected_width,True,True,72,11,8,3
|
| 287 |
+
ls,format_user_or_group,True,True,91,12,11,1
|
| 288 |
+
ls,print_long_format,True,False,N/A,0,0,0
|
| 289 |
+
ls,quote_name_buf,True,True,60,45,27,18
|
| 290 |
+
ls,quote_name_width,True,True,52,42,22,20
|
| 291 |
+
ls,quote_name,True,False,N/A,0,0,0
|
| 292 |
+
ls,print_name_with_quoting,True,True,50,55,28,27
|
| 293 |
+
ls,prep_non_filename_text,False,False,N/A,0,0,0
|
| 294 |
+
ls,print_file_name_and_frills,True,True,48,52,25,27
|
| 295 |
+
ls,get_type_indicator,True,True,93,16,15,1
|
| 296 |
+
ls,print_color_indicator,True,True,64,25,16,9
|
| 297 |
+
ls,put_indicator,True,True,70,10,7,3
|
| 298 |
+
ls,length_of_file_name_and_frills,True,True,87,24,21,3
|
| 299 |
+
ls,print_many_per_line,True,False,N/A,0,0,0
|
| 300 |
+
ls,print_horizontal,False,False,N/A,0,0,0
|
| 301 |
+
ls,print_with_separator,True,True,61,52,32,20
|
| 302 |
+
ls,indent,True,True,100,1,1,0
|
| 303 |
+
ls,attach,True,True,100,1,1,0
|
| 304 |
+
ls,init_column_info,True,True,72,25,18,7
|
| 305 |
+
ls,calculate_columns,True,True,79,67,53,14
|
| 306 |
+
ls,usage,True,True,50,6,3,3
|
| 307 |
+
mkdir,usage,True,True,60,5,3,2
|
| 308 |
+
mkdir,make_ancestor,True,False,N/A,0,0,0
|
| 309 |
+
mkdir,process_dir,True,False,N/A,0,0,0
|
| 310 |
+
mkfifo,usage,True,True,60,5,3,2
|
| 311 |
+
mknod,usage,True,True,50,6,3,3
|
| 312 |
+
mktemp,usage,True,True,75,4,3,1
|
| 313 |
+
mv,rm_option_init,True,True,44,9,4,5
|
| 314 |
+
mv,cp_option_init,False,False,N/A,0,0,0
|
| 315 |
+
mv,do_move,True,False,N/A,0,0,0
|
| 316 |
+
mv,usage,True,True,42,7,3,4
|
| 317 |
+
nl,usage,True,True,50,6,3,3
|
| 318 |
+
nl,build_type_arg,False,False,N/A,0,0,0
|
| 319 |
+
nl,proc_text,True,True,N/A,0,0,0
|
| 320 |
+
nl,check_section,True,True,84,13,11,2
|
| 321 |
+
nl,process_file,True,True,81,16,13,3
|
| 322 |
+
nl,nl_file,False,False,N/A,0,0,0
|
| 323 |
+
nproc,usage,True,True,75,4,3,1
|
| 324 |
+
nohup,usage,True,True,28,7,2,5
|
| 325 |
+
numfmt,default_scale_base,True,True,N/A,0,0,0
|
| 326 |
+
numfmt,suffix_power,True,True,N/A,0,0,0
|
| 327 |
+
numfmt,powerld,True,True,100,1,1,0
|
| 328 |
+
numfmt,expld,True,True,81,16,13,3
|
| 329 |
+
numfmt,simple_round,True,False,N/A,0,0,0
|
| 330 |
+
numfmt,simple_strtod_int,True,True,81,22,18,4
|
| 331 |
+
numfmt,simple_strtod_float,True,True,79,43,34,9
|
| 332 |
+
numfmt,simple_strtod_human,False,False,N/A,0,0,0
|
| 333 |
+
numfmt,simple_strtod_fatal,True,True,100,1,1,0
|
| 334 |
+
numfmt,double_to_human,True,True,77,67,52,15
|
| 335 |
+
numfmt,unit_to_umax,True,True,70,17,12,5
|
| 336 |
+
numfmt,usage,True,True,57,7,4,3
|
| 337 |
+
numfmt,parse_format_string,True,False,N/A,0,0,0
|
| 338 |
+
numfmt,parse_human_number,True,True,84,78,66,12
|
| 339 |
+
numfmt,prepare_padded_number,True,True,72,96,70,26
|
| 340 |
+
numfmt,print_padded_number,True,True,100,1,1,0
|
| 341 |
+
numfmt,process_suffixed_number,True,True,76,90,69,21
|
| 342 |
+
numfmt,is_utf8_charset,True,False,N/A,0,0,0
|
| 343 |
+
numfmt,include_field,True,True,100,1,1,0
|
| 344 |
+
numfmt,process_field,True,True,58,141,83,58
|
| 345 |
+
numfmt,process_line,True,False,N/A,0,0,0
|
| 346 |
+
od,usage,True,True,50,6,3,3
|
| 347 |
+
od,dump_hexl_mode_trailer,True,True,100,1,1,0
|
| 348 |
+
od,print_named_ascii,True,True,88,27,24,3
|
| 349 |
+
od,print_ascii,True,True,90,21,19,2
|
| 350 |
+
od,simple_strtoi,True,True,100,1,1,0
|
| 351 |
+
od,ATTRIBUTE_NONNULL,True,True,88,9,8,1
|
| 352 |
+
od,open_next_file,True,True,54,11,6,5
|
| 353 |
+
od,check_and_close,True,True,62,8,5,3
|
| 354 |
+
od,skip,True,True,63,41,26,15
|
| 355 |
+
od,format_address_std,True,True,100,1,1,0
|
| 356 |
+
od,write_block,True,True,70,20,14,6
|
| 357 |
+
od,read_char,True,True,61,21,13,8
|
| 358 |
+
od,read_block,True,False,N/A,0,0,0
|
| 359 |
+
od,parse_old_offset,True,False,N/A,0,0,0
|
| 360 |
+
od,dump,False,False,N/A,0,0,0
|
| 361 |
+
od,dump_strings,True,True,71,66,47,19
|
| 362 |
+
paste,collapse_escapes,True,True,66,3,2,1
|
| 363 |
+
paste,paste_parallel,True,True,71,56,40,16
|
| 364 |
+
paste,paste_serial,True,False,N/A,0,0,0
|
| 365 |
+
paste,usage,True,True,50,6,3,3
|
| 366 |
+
pathchk,usage,True,True,75,4,3,1
|
| 367 |
+
pathchk,no_leading_hyphen,True,True,100,1,1,0
|
| 368 |
+
pathchk,portable_chars_only,True,True,40,5,2,3
|
| 369 |
+
pathchk,validate_file_name,True,True,60,41,25,16
|
| 370 |
+
pr,cols_ready_to_print,True,True,100,1,1,0
|
| 371 |
+
pr,first_last_page,True,True,100,1,1,0
|
| 372 |
+
pr,getoptarg,True,True,66,15,10,5
|
| 373 |
+
pr,init_parameters,True,True,75,41,31,10
|
| 374 |
+
pr,init_fps,True,True,48,58,28,30
|
| 375 |
+
pr,init_funcs,True,True,92,25,23,2
|
| 376 |
+
pr,open_file,True,False,N/A,0,0,0
|
| 377 |
+
pr,close_file,True,True,69,13,9,4
|
| 378 |
+
pr,hold_file,True,True,85,7,6,1
|
| 379 |
+
pr,reset_status,True,True,87,8,7,1
|
| 380 |
+
pr,print_files,True,False,N/A,0,0,0
|
| 381 |
+
pr,init_header,True,True,61,18,11,7
|
| 382 |
+
pr,init_page,True,True,46,100,46,54
|
| 383 |
+
pr,align_column,True,True,64,57,37,20
|
| 384 |
+
pr,print_page,True,False,N/A,0,0,0
|
| 385 |
+
pr,init_store_cols,True,False,N/A,0,0,0
|
| 386 |
+
pr,store_columns,True,False,N/A,0,0,0
|
| 387 |
+
pr,balance,True,True,100,1,1,0
|
| 388 |
+
pr,store_char,True,True,100,1,1,0
|
| 389 |
+
pr,add_line_number,True,True,100,1,1,0
|
| 390 |
+
pr,pad_across_to,True,True,100,1,1,0
|
| 391 |
+
pr,read_rest_of_line,True,True,76,21,16,5
|
| 392 |
+
pr,skip_read,True,True,75,29,22,7
|
| 393 |
+
pr,print_white_space,True,True,86,15,13,2
|
| 394 |
+
pr,print_sep_string,True,True,80,36,29,7
|
| 395 |
+
pr,print_char,True,True,78,23,18,5
|
| 396 |
+
pr,skip_to_page,True,False,N/A,0,0,0
|
| 397 |
+
pr,print_header,True,False,N/A,0,0,0
|
| 398 |
+
pr,read_line,True,True,59,59,35,24
|
| 399 |
+
pr,print_stored,True,True,78,47,37,10
|
| 400 |
+
pr,char_to_clump,True,True,86,60,52,8
|
| 401 |
+
pr,cleanup,True,True,0,5,0,5
|
| 402 |
+
pr,usage,False,False,N/A,0,0,0
|
| 403 |
+
printenv,usage,True,True,60,5,3,2
|
| 404 |
+
printf,usage,True,True,60,5,3,2
|
| 405 |
+
printf,verify_numeric,True,True,100,1,1,0
|
| 406 |
+
printf,print_esc_char,True,True,N/A,0,0,0
|
| 407 |
+
printf,print_esc,True,False,N/A,0,0,0
|
| 408 |
+
printf,print_direc,True,True,62,8,5,3
|
| 409 |
+
printf,get_curr_arg,True,True,93,29,27,2
|
| 410 |
+
printf,print_formatted,False,False,N/A,0,0,0
|
| 411 |
+
ptx,unescape_string,True,True,100,1,1,0
|
| 412 |
+
ptx,compile_regex,True,False,N/A,0,0,0
|
| 413 |
+
ptx,initialize_regex,False,False,N/A,0,0,0
|
| 414 |
+
ptx,swallow_file_in_memory,True,True,100,1,1,0
|
| 415 |
+
ptx,compare_words,True,True,66,27,18,9
|
| 416 |
+
ptx,compare_occurs,True,True,80,21,17,4
|
| 417 |
+
ptx,search_table,True,True,89,39,35,4
|
| 418 |
+
ptx,digest_break_file,True,True,72,11,8,3
|
| 419 |
+
ptx,digest_word_file,True,True,65,43,28,15
|
| 420 |
+
ptx,find_occurs_in_text,True,True,73,92,68,24
|
| 421 |
+
ptx,print_field,True,True,66,3,2,1
|
| 422 |
+
ptx,fix_output_parameters,True,True,76,43,33,10
|
| 423 |
+
ptx,define_all_fields,True,False,N/A,0,0,0
|
| 424 |
+
ptx,output_one_roff_line,True,True,100,1,1,0
|
| 425 |
+
ptx,output_one_tex_line,True,True,44,38,17,21
|
| 426 |
+
ptx,output_one_dumb_line,True,False,N/A,0,0,0
|
| 427 |
+
ptx,generate_all_output,True,False,N/A,0,0,0
|
| 428 |
+
ptx,usage,True,True,50,6,3,3
|
| 429 |
+
pwd,usage,True,True,60,5,3,2
|
| 430 |
+
pwd,file_name_prepend,True,True,58,17,10,7
|
| 431 |
+
pwd,find_dir_entry,True,False,N/A,0,0,0
|
| 432 |
+
pwd,robust_getcwd,True,True,69,53,37,16
|
| 433 |
+
readlink,usage,True,True,75,4,3,1
|
| 434 |
+
realpath,usage,True,True,75,4,3,1
|
| 435 |
+
realpath,path_prefix,True,True,100,1,1,0
|
| 436 |
+
realpath,process_path,True,True,16,6,1,5
|
| 437 |
+
rm,diagnose_leading_hyphen,True,True,87,8,7,1
|
| 438 |
+
rm,usage,True,True,40,5,2,3
|
| 439 |
+
rm,rm_option_init,True,True,20,10,2,8
|
| 440 |
+
rmdir,errno_may_be_non_empty,True,True,N/A,0,0,0
|
| 441 |
+
rmdir,remove_parents,True,True,87,16,14,2
|
| 442 |
+
rmdir,usage,True,True,100,1,1,0
|
| 443 |
+
seq,usage,False,False,N/A,0,0,0
|
| 444 |
+
seq,scan_arg,False,False,N/A,0,0,0
|
| 445 |
+
seq,print_numbers,False,False,N/A,0,0,0
|
| 446 |
+
seq,incr_grows,False,False,N/A,0,0,0
|
| 447 |
+
seq,seq_fast,False,False,N/A,0,0,0
|
| 448 |
+
shred,usage,True,True,66,6,4,2
|
| 449 |
+
shred,periodic_pattern,True,True,93,16,15,1
|
| 450 |
+
shred,fillpattern,True,True,88,26,23,3
|
| 451 |
+
shred,dosync,True,True,72,11,8,3
|
| 452 |
+
shred,direct_mode,True,True,28,7,2,5
|
| 453 |
+
shred,dorewind,True,True,80,5,4,1
|
| 454 |
+
shred,dopass,True,True,30,113,35,78
|
| 455 |
+
shred,genpattern,False,False,N/A,0,0,0
|
| 456 |
+
shred,do_wipefd,False,False,N/A,0,0,0
|
| 457 |
+
shred,wipefd,True,False,N/A,0,0,0
|
| 458 |
+
shred,incname,False,False,N/A,0,0,0
|
| 459 |
+
shred,wipename,True,False,N/A,0,0,0
|
| 460 |
+
shred,wipefile,False,False,N/A,0,0,0
|
| 461 |
+
shuf,usage,True,True,50,6,3,3
|
| 462 |
+
shuf,input_from_argv,True,True,75,12,9,3
|
| 463 |
+
shuf,input_size,True,True,100,1,1,0
|
| 464 |
+
shuf,read_input_reservoir_sampling,False,False,N/A,0,0,0
|
| 465 |
+
shuf,write_permuted_output_reservoir,True,False,N/A,0,0,0
|
| 466 |
+
shuf,read_input,True,True,100,1,1,0
|
| 467 |
+
shuf,write_permuted_lines,True,False,N/A,0,0,0
|
| 468 |
+
shuf,write_permuted_numbers,True,True,88,9,8,1
|
| 469 |
+
shuf,write_random_numbers,False,False,N/A,0,0,0
|
| 470 |
+
shuf,write_random_lines,False,False,N/A,0,0,0
|
| 471 |
+
sleep,usage,True,True,75,4,3,1
|
| 472 |
+
sleep,apply_suffix,False,False,N/A,0,0,0
|
| 473 |
+
sort,usage,True,True,42,7,3,4
|
| 474 |
+
sort,reap,True,True,90,10,9,1
|
| 475 |
+
sort,register_proc,True,True,80,5,4,1
|
| 476 |
+
sort,delete_proc,True,True,100,1,1,0
|
| 477 |
+
sort,exit_cleanup,True,True,N/A,0,0,0
|
| 478 |
+
sort,xfclose,True,True,N/A,0,0,0
|
| 479 |
+
sort,move_fd,True,True,100,1,1,0
|
| 480 |
+
sort,posix_spawn_file_actions_move_fd,True,True,100,1,1,0
|
| 481 |
+
sort,pipe_child,True,True,45,51,23,28
|
| 482 |
+
sort,zaptemp,True,True,20,15,3,12
|
| 483 |
+
sort,inittables,True,True,100,1,1,0
|
| 484 |
+
sort,specify_nmerge,True,True,92,13,12,1
|
| 485 |
+
sort,specify_sort_size,False,False,N/A,0,0,0
|
| 486 |
+
sort,specify_nthreads,False,False,N/A,0,0,0
|
| 487 |
+
sort,default_sort_size,True,True,0,29,0,29
|
| 488 |
+
sort,sort_buffer_size,True,True,57,61,35,26
|
| 489 |
+
sort,initbuf,True,True,88,9,8,1
|
| 490 |
+
sort,fillbuf,True,True,49,63,31,32
|
| 491 |
+
sort,traverse_raw_number,True,True,80,15,12,3
|
| 492 |
+
sort,find_unit_order,True,True,75,24,18,6
|
| 493 |
+
sort,human_numcompare,True,False,N/A,0,0,0
|
| 494 |
+
sort,numcompare,True,True,53,13,7,6
|
| 495 |
+
sort,general_numcompare,True,True,100,1,1,0
|
| 496 |
+
sort,getmonth,True,True,90,31,28,3
|
| 497 |
+
sort,link_libcrypto,True,True,N/A,0,0,0
|
| 498 |
+
sort,random_md5_state_init,True,True,85,7,6,1
|
| 499 |
+
sort,xstrxfrm,True,True,100,1,1,0
|
| 500 |
+
sort,compare_random,True,True,62,56,35,21
|
| 501 |
+
sort,mark_key,True,True,100,1,1,0
|
| 502 |
+
sort,debug_key,True,False,N/A,0,0,0
|
| 503 |
+
sort,default_key_compare,True,True,50,2,1,1
|
| 504 |
+
sort,key_to_opts,True,True,100,1,1,0
|
| 505 |
+
sort,key_warnings,True,False,N/A,0,0,0
|
| 506 |
+
sort,keycompare,True,True,58,82,48,34
|
| 507 |
+
sort,compare,True,True,92,25,23,2
|
| 508 |
+
sort,write_line,True,True,64,28,18,10
|
| 509 |
+
sort,check,True,True,50,90,45,45
|
| 510 |
+
sort,open_input_files,True,True,76,13,10,3
|
| 511 |
+
sort,mergefps,True,True,62,174,109,65
|
| 512 |
+
sort,mergefiles,False,False,N/A,0,0,0
|
| 513 |
+
sort,mergelines,True,False,N/A,0,0,0
|
| 514 |
+
sort,sequential_sort,True,False,N/A,0,0,0
|
| 515 |
+
sort,merge_tree_destroy,True,True,30,30,9,21
|
| 516 |
+
sort,queue_init,True,True,30,13,4,9
|
| 517 |
+
sort,write_unique,True,True,93,16,15,1
|
| 518 |
+
sort,mergelines_node,True,True,84,57,48,9
|
| 519 |
+
sort,queue_check_insert,True,True,55,18,10,8
|
| 520 |
+
sort,queue_check_insert_parent,True,True,50,28,14,14
|
| 521 |
+
sort,merge_loop,True,True,73,80,59,21
|
| 522 |
+
sort,sortlines,True,True,69,165,114,51
|
| 523 |
+
sort,avoid_trashing_input,False,False,N/A,0,0,0
|
| 524 |
+
sort,check_inputs,True,False,N/A,0,0,0
|
| 525 |
+
sort,check_output,True,True,83,6,5,1
|
| 526 |
+
sort,merge,True,False,N/A,0,0,0
|
| 527 |
+
sort,sort,True,False,N/A,0,0,0
|
| 528 |
+
sort,insertkey,True,True,N/A,0,0,0
|
| 529 |
+
sort,check_ordering_compatibility,True,True,28,21,6,15
|
| 530 |
+
split,set_suffix_length,True,True,71,21,15,6
|
| 531 |
+
split,usage,True,True,50,8,4,4
|
| 532 |
+
split,copy_to_tmpfile,True,False,N/A,0,0,0
|
| 533 |
+
split,input_file_size,True,False,N/A,0,0,0
|
| 534 |
+
split,next_file_name,True,False,N/A,0,0,0
|
| 535 |
+
split,create,True,True,75,69,52,17
|
| 536 |
+
split,closeout,True,True,82,28,23,5
|
| 537 |
+
split,cwrite,True,True,62,56,35,21
|
| 538 |
+
split,bytes_split,False,False,N/A,0,0,0
|
| 539 |
+
split,lines_split,True,False,N/A,0,0,0
|
| 540 |
+
split,line_bytes_split,True,False,N/A,0,0,0
|
| 541 |
+
split,lines_chunk_split,True,False,N/A,0,0,0
|
| 542 |
+
split,bytes_chunk_extract,True,True,75,36,27,9
|
| 543 |
+
split,ofile_open,True,True,63,19,12,7
|
| 544 |
+
split,lines_rr,False,False,N/A,0,0,0
|
| 545 |
+
split,parse_chunk,True,True,95,21,20,1
|
| 546 |
+
stat,statfs,True,True,N/A,0,0,0
|
| 547 |
+
stat,make_format,True,True,100,1,1,0
|
| 548 |
+
stat,out_epoch_sec,True,False,N/A,0,0,0
|
| 549 |
+
stat,out_file_context,True,True,71,7,5,2
|
| 550 |
+
stat,print_statfs,True,True,90,11,10,1
|
| 551 |
+
stat,out_mount_point,True,True,25,35,9,26
|
| 552 |
+
stat,getenv_quoting_style,True,True,100,1,1,0
|
| 553 |
+
stat,print_esc_char,True,True,N/A,0,0,0
|
| 554 |
+
stat,format_code_offset,True,False,N/A,0,0,0
|
| 555 |
+
stat,print_it,True,True,53,13,7,6
|
| 556 |
+
stat,do_statfs,True,True,59,22,13,9
|
| 557 |
+
stat,fmt_to_mask,True,True,N/A,0,0,0
|
| 558 |
+
stat,format_to_mask,True,True,100,1,1,0
|
| 559 |
+
stat,do_stat,True,True,45,37,17,20
|
| 560 |
+
stat,get_birthtime,False,False,N/A,0,0,0
|
| 561 |
+
stat,do_stat,True,True,43,39,17,22
|
| 562 |
+
stat,print_stat,True,True,76,17,13,4
|
| 563 |
+
stat,usage,False,False,N/A,0,0,0
|
| 564 |
+
sync,usage,True,True,100,1,1,0
|
| 565 |
+
sync,sync_arg,True,True,44,25,11,14
|
| 566 |
+
tac,usage,True,True,66,6,4,2
|
| 567 |
+
tac,output,True,True,100,1,1,0
|
| 568 |
+
tac,tac_seekable,True,False,N/A,0,0,0
|
| 569 |
+
tac,copy_to_temp,True,False,N/A,0,0,0
|
| 570 |
+
tac,tac_nonseekable,True,False,N/A,0,0,0
|
| 571 |
+
tac,tac_file,True,False,N/A,0,0,0
|
| 572 |
+
tail,usage,False,False,N/A,0,0,0
|
| 573 |
+
tail,xlseek,True,True,75,4,3,1
|
| 574 |
+
tail,record_open_fd,True,True,78,14,11,3
|
| 575 |
+
tail,xwrite_stdout,False,False,N/A,0,0,0
|
| 576 |
+
tail,dump_remainder,True,True,80,25,20,5
|
| 577 |
+
tail,file_lines,False,False,N/A,0,0,0
|
| 578 |
+
tail,pipe_lines,True,True,81,43,35,8
|
| 579 |
+
tail,pipe_bytes,True,True,80,45,36,9
|
| 580 |
+
tail,start_bytes,True,True,83,18,15,3
|
| 581 |
+
tail,start_lines,False,False,N/A,0,0,0
|
| 582 |
+
tail,fremote,True,True,88,9,8,1
|
| 583 |
+
tail,recheck,True,False,N/A,0,0,0
|
| 584 |
+
tail,any_live_files,True,True,85,7,6,1
|
| 585 |
+
tail,some_writers_exist,True,True,92,14,13,1
|
| 586 |
+
tail,tail_forever,False,False,N/A,0,0,0
|
| 587 |
+
tail,check_fspec,True,True,N/A,0,0,0
|
| 588 |
+
tail,tail_forever_inotify,True,False,N/A,0,0,0
|
| 589 |
+
tail,tail_bytes,True,False,N/A,0,0,0
|
| 590 |
+
tail,tail_lines,True,True,69,130,90,40
|
| 591 |
+
tail,tail_file,True,True,51,194,100,94
|
| 592 |
+
tail,parse_obsolete_option,True,True,75,29,22,7
|
| 593 |
+
tail,parse_options,True,False,N/A,0,0,0
|
| 594 |
+
tail,ignore_fifo_and_pipe,True,True,92,13,12,1
|
| 595 |
+
tee,usage,True,True,75,4,3,1
|
| 596 |
+
tee,fail_output,True,True,66,6,4,2
|
| 597 |
+
tee,tee_files,True,False,N/A,0,0,0
|
| 598 |
+
test,binop,True,True,100,1,1,0
|
| 599 |
+
test,term,True,False,N/A,0,0,0
|
| 600 |
+
test,binary_operator,True,True,84,19,16,3
|
| 601 |
+
test,unary_operator,True,False,N/A,0,0,0
|
| 602 |
+
test,and,True,True,53,77,41,36
|
| 603 |
+
test,or,True,True,46,60,28,32
|
| 604 |
+
test,two_arguments,True,True,93,15,14,1
|
| 605 |
+
test,three_arguments,True,True,66,102,68,34
|
| 606 |
+
test,posixtest,True,True,68,106,73,33
|
| 607 |
+
test,usage,True,True,50,4,2,2
|
| 608 |
+
touch,touch,True,False,N/A,0,0,0
|
| 609 |
+
touch,usage,True,True,60,5,3,2
|
| 610 |
+
tr,usage,True,True,75,4,3,1
|
| 611 |
+
tr,is_char_class_member,True,True,N/A,0,0,0
|
| 612 |
+
tr,unquote,True,True,66,6,4,2
|
| 613 |
+
tr,look_up_char_class,True,True,83,6,5,1
|
| 614 |
+
tr,append_normal_char,True,True,100,1,1,0
|
| 615 |
+
tr,append_range,True,True,70,10,7,3
|
| 616 |
+
tr,append_char_class,True,True,90,10,9,1
|
| 617 |
+
tr,append_repeated_char,True,True,100,1,1,0
|
| 618 |
+
tr,append_equiv_class,True,True,100,1,1,0
|
| 619 |
+
tr,find_closing_delim,True,True,80,10,8,2
|
| 620 |
+
tr,find_bracketed_repeat,True,True,72,29,21,8
|
| 621 |
+
tr,star_digits_closebracket,True,True,88,9,8,1
|
| 622 |
+
tr,build_spec_list,True,True,77,119,92,27
|
| 623 |
+
tr,get_next,True,True,92,26,24,2
|
| 624 |
+
tr,card_of_complement,True,True,84,114,96,18
|
| 625 |
+
tr,validate_case_classes,True,True,74,112,83,29
|
| 626 |
+
tr,get_spec_stats,True,True,82,117,96,21
|
| 627 |
+
tr,get_s2_spec_stats,True,True,78,87,68,19
|
| 628 |
+
tr,string2_extend,True,True,77,122,95,27
|
| 629 |
+
tr,homogeneous_spec_list,True,True,90,32,29,3
|
| 630 |
+
tr,validate,True,True,73,184,135,49
|
| 631 |
+
tr,squeeze_filter,True,True,86,43,37,6
|
| 632 |
+
tr,read_and_delete,True,True,100,1,1,0
|
| 633 |
+
tr,set_initialize,True,False,N/A,0,0,0
|
| 634 |
+
true,usage,True,False,N/A,0,0,0
|
| 635 |
+
truncate,usage,True,True,50,6,3,3
|
| 636 |
+
truncate,do_ftruncate,True,True,70,31,22,9
|
| 637 |
+
tsort,usage,True,True,60,5,3,2
|
| 638 |
+
tsort,record_relation,True,True,100,1,1,0
|
| 639 |
+
tsort,scan_zeros,True,True,100,1,1,0
|
| 640 |
+
tsort,detect_loop,True,True,75,8,6,2
|
| 641 |
+
tsort,recurse_tree,True,True,100,1,1,0
|
| 642 |
+
tsort,tsort,True,True,81,66,54,12
|
| 643 |
+
tty,usage,True,True,50,4,2,2
|
| 644 |
+
uname,usage,False,False,N/A,0,0,0
|
| 645 |
+
uname,print_element_env,True,True,100,1,1,0
|
| 646 |
+
uname,decode_switches,False,False,N/A,0,0,0
|
| 647 |
+
unexpand,usage,True,True,42,7,3,4
|
| 648 |
+
unexpand,unexpand,False,False,N/A,0,0,0
|
| 649 |
+
uniq,usage,True,True,33,6,2,4
|
| 650 |
+
uniq,writeline,True,True,100,1,1,0
|
| 651 |
+
uniq,check_file,True,False,N/A,0,0,0
|
| 652 |
+
unlink,usage,True,True,75,4,3,1
|
| 653 |
+
uptime,print_uptime,True,False,N/A,0,0,0
|
| 654 |
+
uptime,uptime,True,False,N/A,0,0,0
|
| 655 |
+
uptime,usage,True,True,57,7,4,3
|
| 656 |
+
wc,avx2_supported,True,True,100,1,1,0
|
| 657 |
+
wc,avx512_supported,True,True,0,1,0,1
|
| 658 |
+
wc,usage,True,True,40,5,2,3
|
| 659 |
+
wc,write_counts,True,True,100,1,1,0
|
| 660 |
+
wc,wc_lines,True,True,67,28,19,9
|
| 661 |
+
wc,wc,True,False,N/A,0,0,0
|
| 662 |
+
wc,wc_file,True,True,43,60,26,34
|
| 663 |
+
wc,compute_number_width,True,True,80,20,16,4
|
| 664 |
+
whoami,usage,True,True,50,4,2,2
|
| 665 |
+
yes,usage,True,True,75,4,3,1
|
tests/tr/tests_for_append_char_class.c
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
|
| 5 |
+
/* The program under test has already included all its own headers
|
| 6 |
+
and defined all internal symbols (including append_char_class,
|
| 7 |
+
spec_init, append_normal_char, and the enums/types).
|
| 8 |
+
We only write tests that call into those. */
|
| 9 |
+
|
| 10 |
+
/* Helpers */
|
| 11 |
+
static void free_spec_list(struct Spec_list *list)
|
| 12 |
+
{
|
| 13 |
+
if (!list || !list->head) return;
|
| 14 |
+
struct List_element *p = list->head;
|
| 15 |
+
while (p) {
|
| 16 |
+
struct List_element *next = p->next;
|
| 17 |
+
free(p);
|
| 18 |
+
p = next;
|
| 19 |
+
}
|
| 20 |
+
/* Don't leave dangling pointers in case caller reuses struct */
|
| 21 |
+
list->head = NULL;
|
| 22 |
+
list->tail = NULL;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
static size_t count_nodes(const struct Spec_list *list)
|
| 26 |
+
{
|
| 27 |
+
size_t n = 0;
|
| 28 |
+
if (!list || !list->head) return 0;
|
| 29 |
+
for (struct List_element const *p = list->head->next; p; p = p->next)
|
| 30 |
+
n++;
|
| 31 |
+
return n;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
void setUp(void) {
|
| 35 |
+
/* No global setup needed */
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
void tearDown(void) {
|
| 39 |
+
/* No global teardown needed */
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
/* Test: invalid inputs should return false and not modify the list */
|
| 43 |
+
void test_append_char_class_invalid_empty_len_zero(void)
|
| 44 |
+
{
|
| 45 |
+
struct Spec_list list;
|
| 46 |
+
spec_init(&list);
|
| 47 |
+
struct List_element *old_tail = list.tail;
|
| 48 |
+
|
| 49 |
+
bool ok = append_char_class(&list, "x", 0);
|
| 50 |
+
TEST_ASSERT_FALSE(ok);
|
| 51 |
+
TEST_ASSERT_EQUAL_PTR(old_tail, list.tail);
|
| 52 |
+
TEST_ASSERT_NULL(old_tail->next);
|
| 53 |
+
|
| 54 |
+
free_spec_list(&list);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
void test_append_char_class_invalid_names_do_not_change_list(void)
|
| 58 |
+
{
|
| 59 |
+
const char *invalids[] = {
|
| 60 |
+
"Alpha", /* wrong case */
|
| 61 |
+
"alph", /* too short */
|
| 62 |
+
"alpha ", /* trailing space included in len */
|
| 63 |
+
" xdigit", /* leading space */
|
| 64 |
+
"xdigitu", /* extra char */
|
| 65 |
+
"lowercase", /* not a class */
|
| 66 |
+
"", /* empty string with len=0 tested separately but also here */
|
| 67 |
+
};
|
| 68 |
+
size_t n = sizeof(invalids)/sizeof(invalids[0]);
|
| 69 |
+
|
| 70 |
+
for (size_t i = 0; i < n; i++) {
|
| 71 |
+
struct Spec_list list;
|
| 72 |
+
spec_init(&list);
|
| 73 |
+
struct List_element *old_tail = list.tail;
|
| 74 |
+
|
| 75 |
+
const char *s = invalids[i];
|
| 76 |
+
size_t len = strlen(s);
|
| 77 |
+
bool ok = append_char_class(&list, s, len);
|
| 78 |
+
TEST_ASSERT_FALSE(ok);
|
| 79 |
+
TEST_ASSERT_EQUAL_PTR(old_tail, list.tail);
|
| 80 |
+
TEST_ASSERT_NULL(old_tail->next);
|
| 81 |
+
|
| 82 |
+
free_spec_list(&list);
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/* Validate that each known good class name appends correctly with the
|
| 87 |
+
expected enum value and node type. */
|
| 88 |
+
void test_append_char_class_each_valid_name(void)
|
| 89 |
+
{
|
| 90 |
+
struct { const char *name; enum Char_class id; } cases[] = {
|
| 91 |
+
{"alnum", CC_ALNUM},
|
| 92 |
+
{"alpha", CC_ALPHA},
|
| 93 |
+
{"blank", CC_BLANK},
|
| 94 |
+
{"cntrl", CC_CNTRL},
|
| 95 |
+
{"digit", CC_DIGIT},
|
| 96 |
+
{"graph", CC_GRAPH},
|
| 97 |
+
{"lower", CC_LOWER},
|
| 98 |
+
{"print", CC_PRINT},
|
| 99 |
+
{"punct", CC_PUNCT},
|
| 100 |
+
{"space", CC_SPACE},
|
| 101 |
+
{"upper", CC_UPPER},
|
| 102 |
+
{"xdigit", CC_XDIGIT},
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
for (size_t i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
|
| 106 |
+
struct Spec_list list;
|
| 107 |
+
spec_init(&list);
|
| 108 |
+
|
| 109 |
+
bool ok = append_char_class(&list, cases[i].name, strlen(cases[i].name));
|
| 110 |
+
TEST_ASSERT_TRUE(ok);
|
| 111 |
+
TEST_ASSERT_NOT_NULL(list.head);
|
| 112 |
+
TEST_ASSERT_NOT_NULL(list.head->next);
|
| 113 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, list.head->next);
|
| 114 |
+
|
| 115 |
+
struct List_element *node = list.head->next;
|
| 116 |
+
TEST_ASSERT_EQUAL_INT(RE_CHAR_CLASS, node->type);
|
| 117 |
+
TEST_ASSERT_EQUAL_INT(cases[i].id, node->u.char_class);
|
| 118 |
+
TEST_ASSERT_NULL(node->next);
|
| 119 |
+
TEST_ASSERT_EQUAL_UINT32(1, count_nodes(&list));
|
| 120 |
+
|
| 121 |
+
free_spec_list(&list);
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
/* Multiple appends should chain correctly and preserve order */
|
| 126 |
+
void test_append_char_class_multiple_appends_chain_and_tail_updates(void)
|
| 127 |
+
{
|
| 128 |
+
struct Spec_list list;
|
| 129 |
+
spec_init(&list);
|
| 130 |
+
|
| 131 |
+
bool ok1 = append_char_class(&list, "digit", strlen("digit"));
|
| 132 |
+
TEST_ASSERT_TRUE(ok1);
|
| 133 |
+
struct List_element *first = list.head->next;
|
| 134 |
+
TEST_ASSERT_NOT_NULL(first);
|
| 135 |
+
TEST_ASSERT_EQUAL_INT(RE_CHAR_CLASS, first->type);
|
| 136 |
+
TEST_ASSERT_EQUAL_INT(CC_DIGIT, first->u.char_class);
|
| 137 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, first);
|
| 138 |
+
|
| 139 |
+
bool ok2 = append_char_class(&list, "space", strlen("space"));
|
| 140 |
+
TEST_ASSERT_TRUE(ok2);
|
| 141 |
+
struct List_element *second = first->next;
|
| 142 |
+
TEST_ASSERT_NOT_NULL(second);
|
| 143 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, second);
|
| 144 |
+
TEST_ASSERT_EQUAL_INT(RE_CHAR_CLASS, second->type);
|
| 145 |
+
TEST_ASSERT_EQUAL_INT(CC_SPACE, second->u.char_class);
|
| 146 |
+
TEST_ASSERT_NULL(second->next);
|
| 147 |
+
|
| 148 |
+
TEST_ASSERT_EQUAL_UINT32(2, count_nodes(&list));
|
| 149 |
+
|
| 150 |
+
free_spec_list(&list);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
/* Appending after an existing non-class node should still work. */
|
| 154 |
+
void test_append_char_class_after_existing_other_node(void)
|
| 155 |
+
{
|
| 156 |
+
struct Spec_list list;
|
| 157 |
+
spec_init(&list);
|
| 158 |
+
|
| 159 |
+
/* Add a normal character node first via provided helper. */
|
| 160 |
+
append_normal_char(&list, (unsigned char)'X');
|
| 161 |
+
TEST_ASSERT_EQUAL_UINT32(1, count_nodes(&list));
|
| 162 |
+
|
| 163 |
+
bool ok = append_char_class(&list, "upper", strlen("upper"));
|
| 164 |
+
TEST_ASSERT_TRUE(ok);
|
| 165 |
+
|
| 166 |
+
/* Verify structure: head -> normal_char('X') -> char_class(CC_UPPER) */
|
| 167 |
+
struct List_element *n1 = list.head->next;
|
| 168 |
+
struct List_element *n2 = n1 ? n1->next : NULL;
|
| 169 |
+
|
| 170 |
+
TEST_ASSERT_NOT_NULL(n1);
|
| 171 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, n1->type);
|
| 172 |
+
TEST_ASSERT_EQUAL_UINT8('X', n1->u.normal_char);
|
| 173 |
+
|
| 174 |
+
TEST_ASSERT_NOT_NULL(n2);
|
| 175 |
+
TEST_ASSERT_EQUAL_INT(RE_CHAR_CLASS, n2->type);
|
| 176 |
+
TEST_ASSERT_EQUAL_INT(CC_UPPER, n2->u.char_class);
|
| 177 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, n2);
|
| 178 |
+
TEST_ASSERT_NULL(n2->next);
|
| 179 |
+
|
| 180 |
+
TEST_ASSERT_EQUAL_UINT32(2, count_nodes(&list));
|
| 181 |
+
|
| 182 |
+
free_spec_list(&list);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
/* Invalid when length doesn't exactly match the class name */
|
| 186 |
+
void test_append_char_class_len_mismatch_fails(void)
|
| 187 |
+
{
|
| 188 |
+
struct Spec_list list;
|
| 189 |
+
spec_init(&list);
|
| 190 |
+
struct List_element *old_tail = list.tail;
|
| 191 |
+
|
| 192 |
+
const char *name = "alphaX";
|
| 193 |
+
/* Pass only len for "alpha" substring but pointer points to full string. */
|
| 194 |
+
bool ok = append_char_class(&list, name, 6); /* "alphaX" length -> should fail */
|
| 195 |
+
TEST_ASSERT_FALSE(ok);
|
| 196 |
+
TEST_ASSERT_EQUAL_PTR(old_tail, list.tail);
|
| 197 |
+
TEST_ASSERT_NULL(old_tail->next);
|
| 198 |
+
|
| 199 |
+
/* Now pass len for exact "alpha" but pointer advanced so the slice is exact */
|
| 200 |
+
ok = append_char_class(&list, name, 5); /* substring "alpha"; however strcmp uses len and compares exact against known names */
|
| 201 |
+
TEST_ASSERT_TRUE(ok);
|
| 202 |
+
TEST_ASSERT_NOT_NULL(list.head->next);
|
| 203 |
+
TEST_ASSERT_EQUAL_INT(RE_CHAR_CLASS, list.head->next->type);
|
| 204 |
+
TEST_ASSERT_EQUAL_INT(CC_ALPHA, list.head->next->u.char_class);
|
| 205 |
+
|
| 206 |
+
free_spec_list(&list);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
int main(void)
|
| 210 |
+
{
|
| 211 |
+
UNITY_BEGIN();
|
| 212 |
+
|
| 213 |
+
RUN_TEST(test_append_char_class_invalid_empty_len_zero);
|
| 214 |
+
RUN_TEST(test_append_char_class_invalid_names_do_not_change_list);
|
| 215 |
+
RUN_TEST(test_append_char_class_each_valid_name);
|
| 216 |
+
RUN_TEST(test_append_char_class_multiple_appends_chain_and_tail_updates);
|
| 217 |
+
RUN_TEST(test_append_char_class_after_existing_other_node);
|
| 218 |
+
RUN_TEST(test_append_char_class_len_mismatch_fails);
|
| 219 |
+
|
| 220 |
+
return UNITY_END();
|
| 221 |
+
}
|
tests/tr/tests_for_append_equiv_class.c
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
|
| 3 |
+
#include <stdlib.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <stdbool.h>
|
| 6 |
+
#include <stdint.h>
|
| 7 |
+
|
| 8 |
+
/* The program under test includes this file after defining all internal
|
| 9 |
+
structures and functions, so we can use Spec_list, List_element,
|
| 10 |
+
RE_EQUIV_CLASS, and spec_init/append_equiv_class directly. */
|
| 11 |
+
|
| 12 |
+
/* Test fixture state */
|
| 13 |
+
static struct Spec_list list_under_test;
|
| 14 |
+
|
| 15 |
+
static void free_spec_list(struct Spec_list *lst) {
|
| 16 |
+
if (!lst || !lst->head) return;
|
| 17 |
+
struct List_element *p = lst->head;
|
| 18 |
+
while (p) {
|
| 19 |
+
struct List_element *next = p->next;
|
| 20 |
+
free(p);
|
| 21 |
+
p = next;
|
| 22 |
+
}
|
| 23 |
+
lst->head = NULL;
|
| 24 |
+
lst->tail = NULL;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
void setUp(void) {
|
| 28 |
+
spec_init(&list_under_test);
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
void tearDown(void) {
|
| 32 |
+
free_spec_list(&list_under_test);
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
/* Helper to count elements in the list (excluding dummy head) */
|
| 36 |
+
static size_t count_elements(struct Spec_list *lst) {
|
| 37 |
+
size_t n = 0;
|
| 38 |
+
struct List_element *p = lst->head ? lst->head->next : NULL;
|
| 39 |
+
while (p) { ++n; p = p->next; }
|
| 40 |
+
return n;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
void test_append_equiv_class_len_one_basic(void) {
|
| 44 |
+
/* Append a single-character equivalence class 'A' */
|
| 45 |
+
const char *c = "A";
|
| 46 |
+
struct List_element *old_head = list_under_test.head;
|
| 47 |
+
|
| 48 |
+
bool ok = append_equiv_class(&list_under_test, c, 1);
|
| 49 |
+
TEST_ASSERT_TRUE(ok);
|
| 50 |
+
|
| 51 |
+
/* Verify list structure */
|
| 52 |
+
TEST_ASSERT_NOT_NULL(list_under_test.head);
|
| 53 |
+
TEST_ASSERT_EQUAL_PTR(old_head, list_under_test.head); /* head unchanged */
|
| 54 |
+
TEST_ASSERT_NOT_NULL(list_under_test.head->next);
|
| 55 |
+
|
| 56 |
+
struct List_element *first = list_under_test.head->next;
|
| 57 |
+
TEST_ASSERT_EQUAL_INT(RE_EQUIV_CLASS, first->type);
|
| 58 |
+
TEST_ASSERT_EQUAL_UINT8((unsigned char)'A', first->u.equiv_code);
|
| 59 |
+
TEST_ASSERT_NULL(first->next);
|
| 60 |
+
TEST_ASSERT_EQUAL_PTR(first, list_under_test.tail);
|
| 61 |
+
|
| 62 |
+
TEST_ASSERT_EQUAL_UINT(1, count_elements(&list_under_test));
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
void test_append_equiv_class_len_zero_noop(void) {
|
| 66 |
+
const char *ptr = "X"; /* content irrelevant since len=0 */
|
| 67 |
+
struct List_element *old_tail = list_under_test.tail;
|
| 68 |
+
struct List_element *old_next = list_under_test.head->next;
|
| 69 |
+
|
| 70 |
+
bool ok = append_equiv_class(&list_under_test, ptr, 0);
|
| 71 |
+
TEST_ASSERT_FALSE(ok);
|
| 72 |
+
|
| 73 |
+
/* Ensure list unchanged */
|
| 74 |
+
TEST_ASSERT_EQUAL_PTR(old_tail, list_under_test.tail);
|
| 75 |
+
TEST_ASSERT_EQUAL_PTR(old_next, list_under_test.head->next);
|
| 76 |
+
TEST_ASSERT_EQUAL_UINT(0, count_elements(&list_under_test));
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
void test_append_equiv_class_len_gt_one_noop(void) {
|
| 80 |
+
const char *ptr = "BC"; /* len=2 invalid */
|
| 81 |
+
struct List_element *old_tail = list_under_test.tail;
|
| 82 |
+
struct List_element *old_next = list_under_test.head->next;
|
| 83 |
+
|
| 84 |
+
bool ok = append_equiv_class(&list_under_test, ptr, 2);
|
| 85 |
+
TEST_ASSERT_FALSE(ok);
|
| 86 |
+
|
| 87 |
+
TEST_ASSERT_EQUAL_PTR(old_tail, list_under_test.tail);
|
| 88 |
+
TEST_ASSERT_EQUAL_PTR(old_next, list_under_test.head->next);
|
| 89 |
+
TEST_ASSERT_EQUAL_UINT(0, count_elements(&list_under_test));
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
void test_append_equiv_class_appends_multiple_and_chains(void) {
|
| 93 |
+
const char *x = "x";
|
| 94 |
+
const char *y = "y";
|
| 95 |
+
|
| 96 |
+
bool ok1 = append_equiv_class(&list_under_test, x, 1);
|
| 97 |
+
TEST_ASSERT_TRUE(ok1);
|
| 98 |
+
struct List_element *first = list_under_test.head->next;
|
| 99 |
+
TEST_ASSERT_NOT_NULL(first);
|
| 100 |
+
TEST_ASSERT_EQUAL_INT(RE_EQUIV_CLASS, first->type);
|
| 101 |
+
TEST_ASSERT_EQUAL_UINT8((unsigned char)'x', first->u.equiv_code);
|
| 102 |
+
TEST_ASSERT_NULL(first->next);
|
| 103 |
+
|
| 104 |
+
bool ok2 = append_equiv_class(&list_under_test, y, 1);
|
| 105 |
+
TEST_ASSERT_TRUE(ok2);
|
| 106 |
+
|
| 107 |
+
struct List_element *second = first->next;
|
| 108 |
+
TEST_ASSERT_NOT_NULL(second);
|
| 109 |
+
TEST_ASSERT_EQUAL_INT(RE_EQUIV_CLASS, second->type);
|
| 110 |
+
TEST_ASSERT_EQUAL_UINT8((unsigned char)'y', second->u.equiv_code);
|
| 111 |
+
TEST_ASSERT_NULL(second->next);
|
| 112 |
+
|
| 113 |
+
TEST_ASSERT_EQUAL_PTR(second, list_under_test.tail);
|
| 114 |
+
TEST_ASSERT_EQUAL_UINT(2, count_elements(&list_under_test));
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
void test_append_equiv_class_allows_nul_character(void) {
|
| 118 |
+
char zero = '\0';
|
| 119 |
+
bool ok = append_equiv_class(&list_under_test, &zero, 1);
|
| 120 |
+
TEST_ASSERT_TRUE(ok);
|
| 121 |
+
|
| 122 |
+
struct List_element *elem = list_under_test.head->next;
|
| 123 |
+
TEST_ASSERT_NOT_NULL(elem);
|
| 124 |
+
TEST_ASSERT_EQUAL_INT(RE_EQUIV_CLASS, elem->type);
|
| 125 |
+
TEST_ASSERT_EQUAL_UINT8((unsigned char)0, elem->u.equiv_code);
|
| 126 |
+
TEST_ASSERT_NULL(elem->next);
|
| 127 |
+
TEST_ASSERT_EQUAL_PTR(elem, list_under_test.tail);
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
int main(void) {
|
| 131 |
+
UNITY_BEGIN();
|
| 132 |
+
|
| 133 |
+
RUN_TEST(test_append_equiv_class_len_one_basic);
|
| 134 |
+
RUN_TEST(test_append_equiv_class_len_zero_noop);
|
| 135 |
+
RUN_TEST(test_append_equiv_class_len_gt_one_noop);
|
| 136 |
+
RUN_TEST(test_append_equiv_class_appends_multiple_and_chains);
|
| 137 |
+
RUN_TEST(test_append_equiv_class_allows_nul_character);
|
| 138 |
+
|
| 139 |
+
return UNITY_END();
|
| 140 |
+
}
|
tests/tr/tests_for_append_normal_char.c
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <stdint.h>
|
| 4 |
+
#include <stdbool.h>
|
| 5 |
+
#include <limits.h>
|
| 6 |
+
#include <string.h>
|
| 7 |
+
#include <stdio.h>
|
| 8 |
+
|
| 9 |
+
/* The following types and functions are declared in the program source:
|
| 10 |
+
* - struct Spec_list, struct List_element
|
| 11 |
+
* - enum Range_element_type with RE_NORMAL_CHAR
|
| 12 |
+
* - void spec_init(struct Spec_list*)
|
| 13 |
+
* - static void append_normal_char(struct Spec_list*, unsigned char)
|
| 14 |
+
*/
|
| 15 |
+
|
| 16 |
+
static void assert_node_is_char(struct List_element *node, unsigned char expected)
|
| 17 |
+
{
|
| 18 |
+
TEST_ASSERT_NOT_NULL(node);
|
| 19 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, node->type);
|
| 20 |
+
TEST_ASSERT_EQUAL_UINT8(expected, node->u.normal_char);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
void setUp(void) {
|
| 24 |
+
/* No global state to set for these tests. */
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
void tearDown(void) {
|
| 28 |
+
/* We intentionally do not free nodes, since the test process ends. */
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
void test_append_normal_char_single(void)
|
| 32 |
+
{
|
| 33 |
+
struct Spec_list list;
|
| 34 |
+
spec_init(&list);
|
| 35 |
+
|
| 36 |
+
struct List_element *orig_head = list.head;
|
| 37 |
+
struct List_element *orig_tail = list.tail;
|
| 38 |
+
|
| 39 |
+
TEST_ASSERT_NOT_NULL(orig_head);
|
| 40 |
+
TEST_ASSERT_NOT_NULL(orig_tail);
|
| 41 |
+
TEST_ASSERT_EQUAL_PTR(orig_head, orig_tail);
|
| 42 |
+
TEST_ASSERT_NULL(list.head->next);
|
| 43 |
+
|
| 44 |
+
unsigned char ch = (unsigned char)'A';
|
| 45 |
+
append_normal_char(&list, ch);
|
| 46 |
+
|
| 47 |
+
/* head is unchanged, but now points to first element */
|
| 48 |
+
TEST_ASSERT_EQUAL_PTR(orig_head, list.head);
|
| 49 |
+
TEST_ASSERT_NOT_NULL(list.head->next);
|
| 50 |
+
|
| 51 |
+
/* tail should have advanced to new node */
|
| 52 |
+
TEST_ASSERT_NOT_EQUAL(orig_tail, list.tail);
|
| 53 |
+
TEST_ASSERT_EQUAL_PTR(orig_tail->next, list.tail);
|
| 54 |
+
|
| 55 |
+
/* new tail node is a normal char with value 'A' and is terminal */
|
| 56 |
+
assert_node_is_char(list.tail, ch);
|
| 57 |
+
TEST_ASSERT_NULL(list.tail->next);
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
void test_append_normal_char_multiple_order_and_linking(void)
|
| 61 |
+
{
|
| 62 |
+
struct Spec_list list;
|
| 63 |
+
spec_init(&list);
|
| 64 |
+
|
| 65 |
+
const unsigned char seq[] = { 'A', 'B', 'C' };
|
| 66 |
+
for (size_t i = 0; i < sizeof(seq); i++)
|
| 67 |
+
append_normal_char(&list, seq[i]);
|
| 68 |
+
|
| 69 |
+
/* Traverse and verify order and types */
|
| 70 |
+
struct List_element *n = list.head->next;
|
| 71 |
+
TEST_ASSERT_NOT_NULL(n);
|
| 72 |
+
|
| 73 |
+
for (size_t i = 0; i < sizeof(seq); i++) {
|
| 74 |
+
assert_node_is_char(n, seq[i]);
|
| 75 |
+
if (i + 1 < sizeof(seq)) {
|
| 76 |
+
TEST_ASSERT_NOT_NULL(n->next);
|
| 77 |
+
n = n->next;
|
| 78 |
+
} else {
|
| 79 |
+
/* Last node */
|
| 80 |
+
TEST_ASSERT_NULL(n->next);
|
| 81 |
+
TEST_ASSERT_EQUAL_PTR(n, list.tail);
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
void test_append_normal_char_handles_zero_and_uchar_max(void)
|
| 87 |
+
{
|
| 88 |
+
struct Spec_list list;
|
| 89 |
+
spec_init(&list);
|
| 90 |
+
|
| 91 |
+
unsigned char c0 = (unsigned char)0;
|
| 92 |
+
unsigned char cmax = (unsigned char)UCHAR_MAX;
|
| 93 |
+
|
| 94 |
+
append_normal_char(&list, c0);
|
| 95 |
+
append_normal_char(&list, cmax);
|
| 96 |
+
|
| 97 |
+
struct List_element *first = list.head->next;
|
| 98 |
+
struct List_element *second = first ? first->next : NULL;
|
| 99 |
+
|
| 100 |
+
assert_node_is_char(first, c0);
|
| 101 |
+
TEST_ASSERT_NOT_NULL(second);
|
| 102 |
+
assert_node_is_char(second, cmax);
|
| 103 |
+
TEST_ASSERT_EQUAL_PTR(second, list.tail);
|
| 104 |
+
TEST_ASSERT_NULL(list.tail->next);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
void test_append_normal_char_many_appends_integrity(void)
|
| 108 |
+
{
|
| 109 |
+
struct Spec_list list;
|
| 110 |
+
spec_init(&list);
|
| 111 |
+
|
| 112 |
+
/* Append a sequence of 100 bytes cycling through 0..255 */
|
| 113 |
+
const size_t count = 100;
|
| 114 |
+
unsigned char last = 0;
|
| 115 |
+
for (size_t i = 0; i < count; i++) {
|
| 116 |
+
unsigned char v = (unsigned char)(i & 0xFF);
|
| 117 |
+
append_normal_char(&list, v);
|
| 118 |
+
last = v;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
/* Verify count and last value by traversal */
|
| 122 |
+
size_t seen = 0;
|
| 123 |
+
struct List_element *n = list.head->next;
|
| 124 |
+
for (; n; n = n->next) {
|
| 125 |
+
/* For the first few items, verify order exactly */
|
| 126 |
+
if (seen < 10) {
|
| 127 |
+
unsigned char expected = (unsigned char)(seen & 0xFF);
|
| 128 |
+
assert_node_is_char(n, expected);
|
| 129 |
+
}
|
| 130 |
+
seen++;
|
| 131 |
+
if (!n->next) {
|
| 132 |
+
/* Tail reached */
|
| 133 |
+
TEST_ASSERT_EQUAL_PTR(n, list.tail);
|
| 134 |
+
assert_node_is_char(n, last);
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
TEST_ASSERT_EQUAL_size_t(count, seen);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
int main(void)
|
| 141 |
+
{
|
| 142 |
+
UNITY_BEGIN();
|
| 143 |
+
RUN_TEST(test_append_normal_char_single);
|
| 144 |
+
RUN_TEST(test_append_normal_char_multiple_order_and_linking);
|
| 145 |
+
RUN_TEST(test_append_normal_char_handles_zero_and_uchar_max);
|
| 146 |
+
RUN_TEST(test_append_normal_char_many_appends_integrity);
|
| 147 |
+
return UNITY_END();
|
| 148 |
+
}
|
tests/tr/tests_for_append_range.c
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
|
| 3 |
+
#include <stdlib.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <limits.h>
|
| 6 |
+
#include <stdint.h>
|
| 7 |
+
#include <stdbool.h>
|
| 8 |
+
|
| 9 |
+
/* Unity setup/teardown */
|
| 10 |
+
void setUp(void) {
|
| 11 |
+
/* Setup code here, or leave empty */
|
| 12 |
+
}
|
| 13 |
+
void tearDown(void) {
|
| 14 |
+
/* Cleanup code here, or leave empty */
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Helper to free a Spec_list allocated via spec_init and append_* helpers */
|
| 18 |
+
static void free_spec_list(struct Spec_list *list) {
|
| 19 |
+
if (!list) return;
|
| 20 |
+
struct List_element *p = list->head;
|
| 21 |
+
while (p) {
|
| 22 |
+
struct List_element *n = p->next;
|
| 23 |
+
free(p);
|
| 24 |
+
p = n;
|
| 25 |
+
}
|
| 26 |
+
list->head = NULL;
|
| 27 |
+
list->tail = NULL;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
/* Tests */
|
| 31 |
+
void test_append_range_basic(void) {
|
| 32 |
+
struct Spec_list list;
|
| 33 |
+
spec_init(&list);
|
| 34 |
+
|
| 35 |
+
bool ok = append_range(&list, (unsigned char)'a', (unsigned char)'d');
|
| 36 |
+
TEST_ASSERT_TRUE(ok);
|
| 37 |
+
|
| 38 |
+
/* After first append, head->next should be the new node and tail should point to it */
|
| 39 |
+
TEST_ASSERT_NOT_NULL(list.head->next);
|
| 40 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, list.head->next);
|
| 41 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, list.tail->type);
|
| 42 |
+
TEST_ASSERT_EQUAL_UINT8('a', list.tail->u.range.first_char);
|
| 43 |
+
TEST_ASSERT_EQUAL_UINT8('d', list.tail->u.range.last_char);
|
| 44 |
+
TEST_ASSERT_NULL(list.tail->next);
|
| 45 |
+
|
| 46 |
+
free_spec_list(&list);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
void test_append_range_singleton_allowed(void) {
|
| 50 |
+
struct Spec_list list;
|
| 51 |
+
spec_init(&list);
|
| 52 |
+
|
| 53 |
+
bool ok = append_range(&list, (unsigned char)'x', (unsigned char)'x');
|
| 54 |
+
TEST_ASSERT_TRUE(ok);
|
| 55 |
+
TEST_ASSERT_NOT_NULL(list.head->next);
|
| 56 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, list.head->next);
|
| 57 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, list.tail->type);
|
| 58 |
+
TEST_ASSERT_EQUAL_UINT8('x', list.tail->u.range.first_char);
|
| 59 |
+
TEST_ASSERT_EQUAL_UINT8('x', list.tail->u.range.last_char);
|
| 60 |
+
|
| 61 |
+
free_spec_list(&list);
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
void test_append_range_reverse_no_modification(void) {
|
| 65 |
+
struct Spec_list list;
|
| 66 |
+
spec_init(&list);
|
| 67 |
+
struct List_element *orig_tail = list.tail; /* should be head */
|
| 68 |
+
|
| 69 |
+
bool ok = append_range(&list, (unsigned char)'z', (unsigned char)'a');
|
| 70 |
+
TEST_ASSERT_FALSE(ok);
|
| 71 |
+
|
| 72 |
+
/* Ensure list unchanged: no new node, tail unchanged */
|
| 73 |
+
TEST_ASSERT_NULL(list.head->next);
|
| 74 |
+
TEST_ASSERT_EQUAL_PTR(orig_tail, list.tail);
|
| 75 |
+
|
| 76 |
+
free_spec_list(&list);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
void test_append_range_multiple_appends_linking(void) {
|
| 80 |
+
struct Spec_list list;
|
| 81 |
+
spec_init(&list);
|
| 82 |
+
|
| 83 |
+
bool ok1 = append_range(&list, (unsigned char)'a', (unsigned char)'b');
|
| 84 |
+
TEST_ASSERT_TRUE(ok1);
|
| 85 |
+
struct List_element *first = list.head->next;
|
| 86 |
+
TEST_ASSERT_NOT_NULL(first);
|
| 87 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, first->type);
|
| 88 |
+
TEST_ASSERT_EQUAL_UINT8('a', first->u.range.first_char);
|
| 89 |
+
TEST_ASSERT_EQUAL_UINT8('b', first->u.range.last_char);
|
| 90 |
+
|
| 91 |
+
bool ok2 = append_range(&list, (unsigned char)'0', (unsigned char)'3');
|
| 92 |
+
TEST_ASSERT_TRUE(ok2);
|
| 93 |
+
struct List_element *second = list.tail; /* tail should now be second */
|
| 94 |
+
TEST_ASSERT_NOT_NULL(second);
|
| 95 |
+
TEST_ASSERT_EQUAL_PTR(first->next, second);
|
| 96 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, second->type);
|
| 97 |
+
TEST_ASSERT_EQUAL_UINT8('0', second->u.range.first_char);
|
| 98 |
+
TEST_ASSERT_EQUAL_UINT8('3', second->u.range.last_char);
|
| 99 |
+
TEST_ASSERT_NULL(second->next);
|
| 100 |
+
|
| 101 |
+
free_spec_list(&list);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
void test_append_range_after_normal_char_tail_update(void) {
|
| 105 |
+
struct Spec_list list;
|
| 106 |
+
spec_init(&list);
|
| 107 |
+
|
| 108 |
+
/* Create a prior normal element using helper */
|
| 109 |
+
append_normal_char(&list, (unsigned char)'Q');
|
| 110 |
+
struct List_element *normal = list.tail;
|
| 111 |
+
TEST_ASSERT_NOT_NULL(normal);
|
| 112 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, normal->type);
|
| 113 |
+
TEST_ASSERT_EQUAL_UINT8('Q', normal->u.normal_char);
|
| 114 |
+
|
| 115 |
+
bool ok = append_range(&list, (unsigned char)'m', (unsigned char)'p');
|
| 116 |
+
TEST_ASSERT_TRUE(ok);
|
| 117 |
+
struct List_element *range_node = list.tail;
|
| 118 |
+
|
| 119 |
+
TEST_ASSERT_EQUAL_PTR(normal->next, range_node);
|
| 120 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, range_node->type);
|
| 121 |
+
TEST_ASSERT_EQUAL_UINT8('m', range_node->u.range.first_char);
|
| 122 |
+
TEST_ASSERT_EQUAL_UINT8('p', range_node->u.range.last_char);
|
| 123 |
+
TEST_ASSERT_NULL(range_node->next);
|
| 124 |
+
|
| 125 |
+
free_spec_list(&list);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
void test_append_range_full_byte_range(void) {
|
| 129 |
+
struct Spec_list list;
|
| 130 |
+
spec_init(&list);
|
| 131 |
+
|
| 132 |
+
bool ok = append_range(&list, (unsigned char)0, (unsigned char)UCHAR_MAX);
|
| 133 |
+
TEST_ASSERT_TRUE(ok);
|
| 134 |
+
TEST_ASSERT_NOT_NULL(list.head->next);
|
| 135 |
+
TEST_ASSERT_EQUAL_PTR(list.tail, list.head->next);
|
| 136 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, list.tail->type);
|
| 137 |
+
TEST_ASSERT_EQUAL_UINT8(0, list.tail->u.range.first_char);
|
| 138 |
+
TEST_ASSERT_EQUAL_UINT8((unsigned char)UCHAR_MAX, list.tail->u.range.last_char);
|
| 139 |
+
|
| 140 |
+
free_spec_list(&list);
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
int main(void) {
|
| 144 |
+
UNITY_BEGIN();
|
| 145 |
+
RUN_TEST(test_append_range_basic);
|
| 146 |
+
RUN_TEST(test_append_range_singleton_allowed);
|
| 147 |
+
RUN_TEST(test_append_range_reverse_no_modification);
|
| 148 |
+
RUN_TEST(test_append_range_multiple_appends_linking);
|
| 149 |
+
RUN_TEST(test_append_range_after_normal_char_tail_update);
|
| 150 |
+
RUN_TEST(test_append_range_full_byte_range);
|
| 151 |
+
return UNITY_END();
|
| 152 |
+
}
|
tests/tr/tests_for_append_repeated_char.c
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdint.h>
|
| 5 |
+
#include <limits.h>
|
| 6 |
+
#include <stdio.h>
|
| 7 |
+
|
| 8 |
+
/* Unity hooks */
|
| 9 |
+
void setUp(void) {
|
| 10 |
+
/* Setup code here, or leave empty */
|
| 11 |
+
}
|
| 12 |
+
void tearDown(void) {
|
| 13 |
+
/* Cleanup code here, or leave empty */
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
/* Helper to free a Spec_list created with spec_init and appended nodes.
|
| 17 |
+
The program allocates with xmalloc which is compatible with free(). */
|
| 18 |
+
static void free_spec_list(struct Spec_list *s) {
|
| 19 |
+
if (!s) return;
|
| 20 |
+
struct List_element *p = s->head;
|
| 21 |
+
while (p) {
|
| 22 |
+
struct List_element *next = p->next;
|
| 23 |
+
free(p);
|
| 24 |
+
p = next;
|
| 25 |
+
}
|
| 26 |
+
s->head = s->tail = NULL;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Test that appending to a fresh Spec_list creates a single repeated-char node
|
| 30 |
+
with correct type, fields, and linkages. */
|
| 31 |
+
static void test_append_repeated_char_single_basic(void) {
|
| 32 |
+
struct Spec_list s;
|
| 33 |
+
spec_init(&s);
|
| 34 |
+
|
| 35 |
+
/* Before append: head exists, tail == head, and head->next == NULL. */
|
| 36 |
+
TEST_ASSERT_NOT_NULL(s.head);
|
| 37 |
+
TEST_ASSERT_EQUAL_PTR(s.head, s.tail);
|
| 38 |
+
TEST_ASSERT_NULL(s.head->next);
|
| 39 |
+
|
| 40 |
+
append_repeated_char(&s, (unsigned char)'x', (count)5);
|
| 41 |
+
|
| 42 |
+
/* After append: head->next == tail, a single node with correct values. */
|
| 43 |
+
TEST_ASSERT_NOT_NULL(s.head->next);
|
| 44 |
+
TEST_ASSERT_EQUAL_PTR(s.head->next, s.tail);
|
| 45 |
+
TEST_ASSERT_NULL(s.tail->next);
|
| 46 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, s.tail->type);
|
| 47 |
+
TEST_ASSERT_EQUAL_UINT8('x', s.tail->u.repeated_char.the_repeated_char);
|
| 48 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)5, (uint64_t)s.tail->u.repeated_char.repeat_count);
|
| 49 |
+
|
| 50 |
+
free_spec_list(&s);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Test that appending after existing nodes correctly links and updates tail. */
|
| 54 |
+
static void test_append_repeated_char_appends_after_existing(void) {
|
| 55 |
+
struct Spec_list s;
|
| 56 |
+
spec_init(&s);
|
| 57 |
+
|
| 58 |
+
append_normal_char(&s, (unsigned char)'A'); /* First node */
|
| 59 |
+
struct List_element *first_tail = s.tail;
|
| 60 |
+
|
| 61 |
+
append_repeated_char(&s, (unsigned char)'b', (count)2); /* Second node */
|
| 62 |
+
struct List_element *second = s.tail;
|
| 63 |
+
|
| 64 |
+
TEST_ASSERT_NOT_NULL(first_tail->next);
|
| 65 |
+
TEST_ASSERT_EQUAL_PTR(second, first_tail->next);
|
| 66 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, second->type);
|
| 67 |
+
TEST_ASSERT_EQUAL_UINT8('b', second->u.repeated_char.the_repeated_char);
|
| 68 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)2, (uint64_t)second->u.repeated_char.repeat_count);
|
| 69 |
+
|
| 70 |
+
append_repeated_char(&s, (unsigned char)'c', (count)1); /* Third node */
|
| 71 |
+
struct List_element *third = s.tail;
|
| 72 |
+
|
| 73 |
+
TEST_ASSERT_EQUAL_PTR(third, second->next);
|
| 74 |
+
TEST_ASSERT_NULL(third->next);
|
| 75 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, third->type);
|
| 76 |
+
TEST_ASSERT_EQUAL_UINT8('c', third->u.repeated_char.the_repeated_char);
|
| 77 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)1, (uint64_t)third->u.repeated_char.repeat_count);
|
| 78 |
+
|
| 79 |
+
free_spec_list(&s);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
/* Test get_next() traversal for a single repeated char with repeat_count > 0. */
|
| 83 |
+
static void test_append_repeated_char_get_next_semantics_nonzero(void) {
|
| 84 |
+
struct Spec_list s;
|
| 85 |
+
spec_init(&s);
|
| 86 |
+
|
| 87 |
+
append_repeated_char(&s, (unsigned char)'Z', (count)3);
|
| 88 |
+
|
| 89 |
+
s.state = BEGIN_STATE;
|
| 90 |
+
int c;
|
| 91 |
+
|
| 92 |
+
c = get_next(&s, NULL);
|
| 93 |
+
TEST_ASSERT_EQUAL_INT('Z', c);
|
| 94 |
+
c = get_next(&s, NULL);
|
| 95 |
+
TEST_ASSERT_EQUAL_INT('Z', c);
|
| 96 |
+
c = get_next(&s, NULL);
|
| 97 |
+
TEST_ASSERT_EQUAL_INT('Z', c);
|
| 98 |
+
c = get_next(&s, NULL);
|
| 99 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 100 |
+
|
| 101 |
+
free_spec_list(&s);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
/* Test get_next() traversal skips a repeated char with repeat_count == 0. */
|
| 105 |
+
static void test_append_repeated_char_get_next_semantics_zero(void) {
|
| 106 |
+
struct Spec_list s;
|
| 107 |
+
spec_init(&s);
|
| 108 |
+
|
| 109 |
+
append_normal_char(&s, (unsigned char)'A');
|
| 110 |
+
append_repeated_char(&s, (unsigned char)'X', (count)0); /* should produce no output */
|
| 111 |
+
append_normal_char(&s, (unsigned char)'B');
|
| 112 |
+
|
| 113 |
+
s.state = BEGIN_STATE;
|
| 114 |
+
|
| 115 |
+
int c = get_next(&s, NULL);
|
| 116 |
+
TEST_ASSERT_EQUAL_INT('A', c);
|
| 117 |
+
c = get_next(&s, NULL);
|
| 118 |
+
TEST_ASSERT_EQUAL_INT('B', c);
|
| 119 |
+
c = get_next(&s, NULL);
|
| 120 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 121 |
+
|
| 122 |
+
free_spec_list(&s);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
/* Test that NUL (0) as the repeated character is handled and produced. */
|
| 126 |
+
static void test_append_repeated_char_handles_nul_char(void) {
|
| 127 |
+
struct Spec_list s;
|
| 128 |
+
spec_init(&s);
|
| 129 |
+
|
| 130 |
+
append_repeated_char(&s, (unsigned char)0x00, (count)2);
|
| 131 |
+
append_normal_char(&s, (unsigned char)'C');
|
| 132 |
+
|
| 133 |
+
s.state = BEGIN_STATE;
|
| 134 |
+
|
| 135 |
+
int c = get_next(&s, NULL);
|
| 136 |
+
TEST_ASSERT_EQUAL_INT(0, c);
|
| 137 |
+
c = get_next(&s, NULL);
|
| 138 |
+
TEST_ASSERT_EQUAL_INT(0, c);
|
| 139 |
+
c = get_next(&s, NULL);
|
| 140 |
+
TEST_ASSERT_EQUAL_INT('C', c);
|
| 141 |
+
c = get_next(&s, NULL);
|
| 142 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 143 |
+
|
| 144 |
+
free_spec_list(&s);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
/* Test that large repeat_count values are stored correctly without iteration. */
|
| 148 |
+
static void test_append_repeated_char_stores_large_count(void) {
|
| 149 |
+
struct Spec_list s;
|
| 150 |
+
spec_init(&s);
|
| 151 |
+
|
| 152 |
+
/* Don't iterate this count; just verify it is stored. */
|
| 153 |
+
count large = (count)123456789; /* well within REPEAT_COUNT_MAXIMUM */
|
| 154 |
+
append_repeated_char(&s, (unsigned char)'Q', large);
|
| 155 |
+
|
| 156 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, s.tail->type);
|
| 157 |
+
TEST_ASSERT_EQUAL_UINT8('Q', s.tail->u.repeated_char.the_repeated_char);
|
| 158 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)large, (uint64_t)s.tail->u.repeated_char.repeat_count);
|
| 159 |
+
|
| 160 |
+
free_spec_list(&s);
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
int main(void) {
|
| 164 |
+
UNITY_BEGIN();
|
| 165 |
+
|
| 166 |
+
RUN_TEST(test_append_repeated_char_single_basic);
|
| 167 |
+
RUN_TEST(test_append_repeated_char_appends_after_existing);
|
| 168 |
+
RUN_TEST(test_append_repeated_char_get_next_semantics_nonzero);
|
| 169 |
+
RUN_TEST(test_append_repeated_char_get_next_semantics_zero);
|
| 170 |
+
RUN_TEST(test_append_repeated_char_handles_nul_char);
|
| 171 |
+
RUN_TEST(test_append_repeated_char_stores_large_count);
|
| 172 |
+
|
| 173 |
+
return UNITY_END();
|
| 174 |
+
}
|
tests/tr/tests_for_build_spec_list.c
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdbool.h>
|
| 5 |
+
#include <stdint.h>
|
| 6 |
+
|
| 7 |
+
/* We rely on internal helpers from the program source:
|
| 8 |
+
- spec_init
|
| 9 |
+
- unquote
|
| 10 |
+
- es_free
|
| 11 |
+
- build_spec_list
|
| 12 |
+
and data types/enums/structs defined in the TU. */
|
| 13 |
+
|
| 14 |
+
/* Local helper to free a Spec_list allocated by spec_init and populated by build_spec_list. */
|
| 15 |
+
static void tests_free_spec_list(struct Spec_list *sl)
|
| 16 |
+
{
|
| 17 |
+
if (!sl || !sl->head) return;
|
| 18 |
+
struct List_element *p = sl->head;
|
| 19 |
+
while (p) {
|
| 20 |
+
struct List_element *n = p->next;
|
| 21 |
+
free(p);
|
| 22 |
+
p = n;
|
| 23 |
+
}
|
| 24 |
+
sl->head = sl->tail = NULL;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/* Convenience wrapper to unquote a C string into E_string. Returns true on success. */
|
| 28 |
+
static bool tests_make_es(const char *in, struct E_string *es)
|
| 29 |
+
{
|
| 30 |
+
return unquote(in, es);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
void setUp(void) {
|
| 34 |
+
/* empty */
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
void tearDown(void) {
|
| 38 |
+
/* empty */
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
static void test_build_spec_list_normal_chars(void)
|
| 42 |
+
{
|
| 43 |
+
struct Spec_list sl = {0};
|
| 44 |
+
struct E_string es = {0};
|
| 45 |
+
|
| 46 |
+
spec_init(&sl);
|
| 47 |
+
TEST_ASSERT_TRUE(tests_make_es("abc", &es));
|
| 48 |
+
|
| 49 |
+
bool ok = build_spec_list(&es, &sl);
|
| 50 |
+
TEST_ASSERT_TRUE(ok);
|
| 51 |
+
|
| 52 |
+
struct List_element *p = sl.head->next;
|
| 53 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 54 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 55 |
+
TEST_ASSERT_EQUAL_UINT8('a', p->u.normal_char);
|
| 56 |
+
|
| 57 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 58 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 59 |
+
TEST_ASSERT_EQUAL_UINT8('b', p->u.normal_char);
|
| 60 |
+
|
| 61 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 62 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 63 |
+
TEST_ASSERT_EQUAL_UINT8('c', p->u.normal_char);
|
| 64 |
+
|
| 65 |
+
TEST_ASSERT_NULL(p->next);
|
| 66 |
+
|
| 67 |
+
es_free(&es);
|
| 68 |
+
tests_free_spec_list(&sl);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
static void test_build_spec_list_range_ok(void)
|
| 72 |
+
{
|
| 73 |
+
struct Spec_list sl = {0};
|
| 74 |
+
struct E_string es = {0};
|
| 75 |
+
|
| 76 |
+
spec_init(&sl);
|
| 77 |
+
TEST_ASSERT_TRUE(tests_make_es("a-c", &es));
|
| 78 |
+
|
| 79 |
+
bool ok = build_spec_list(&es, &sl);
|
| 80 |
+
TEST_ASSERT_TRUE(ok);
|
| 81 |
+
|
| 82 |
+
struct List_element *p = sl.head->next;
|
| 83 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 84 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, p->type);
|
| 85 |
+
TEST_ASSERT_EQUAL_UINT8('a', p->u.range.first_char);
|
| 86 |
+
TEST_ASSERT_EQUAL_UINT8('c', p->u.range.last_char);
|
| 87 |
+
TEST_ASSERT_NULL(p->next);
|
| 88 |
+
|
| 89 |
+
es_free(&es);
|
| 90 |
+
tests_free_spec_list(&sl);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
static void test_build_spec_list_range_reverse_invalid(void)
|
| 94 |
+
{
|
| 95 |
+
struct Spec_list sl = {0};
|
| 96 |
+
struct E_string es = {0};
|
| 97 |
+
|
| 98 |
+
spec_init(&sl);
|
| 99 |
+
TEST_ASSERT_TRUE(tests_make_es("z-a", &es));
|
| 100 |
+
|
| 101 |
+
bool ok = build_spec_list(&es, &sl);
|
| 102 |
+
TEST_ASSERT_FALSE(ok);
|
| 103 |
+
|
| 104 |
+
es_free(&es);
|
| 105 |
+
tests_free_spec_list(&sl);
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
static void test_build_spec_list_char_class_digit(void)
|
| 109 |
+
{
|
| 110 |
+
struct Spec_list sl = {0};
|
| 111 |
+
struct E_string es = {0};
|
| 112 |
+
|
| 113 |
+
spec_init(&sl);
|
| 114 |
+
TEST_ASSERT_TRUE(tests_make_es("[:digit:]", &es));
|
| 115 |
+
|
| 116 |
+
bool ok = build_spec_list(&es, &sl);
|
| 117 |
+
TEST_ASSERT_TRUE(ok);
|
| 118 |
+
|
| 119 |
+
struct List_element *p = sl.head->next;
|
| 120 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 121 |
+
TEST_ASSERT_EQUAL_INT(RE_CHAR_CLASS, p->type);
|
| 122 |
+
TEST_ASSERT_EQUAL_INT(CC_DIGIT, p->u.char_class);
|
| 123 |
+
TEST_ASSERT_NULL(p->next);
|
| 124 |
+
|
| 125 |
+
es_free(&es);
|
| 126 |
+
tests_free_spec_list(&sl);
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
static void test_build_spec_list_char_class_invalid(void)
|
| 130 |
+
{
|
| 131 |
+
struct Spec_list sl = {0};
|
| 132 |
+
struct E_string es = {0};
|
| 133 |
+
|
| 134 |
+
spec_init(&sl);
|
| 135 |
+
TEST_ASSERT_TRUE(tests_make_es("[:foo:]", &es));
|
| 136 |
+
|
| 137 |
+
bool ok = build_spec_list(&es, &sl);
|
| 138 |
+
TEST_ASSERT_FALSE(ok);
|
| 139 |
+
|
| 140 |
+
es_free(&es);
|
| 141 |
+
tests_free_spec_list(&sl);
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
static void test_build_spec_list_equiv_class_single_char(void)
|
| 145 |
+
{
|
| 146 |
+
struct Spec_list sl = {0};
|
| 147 |
+
struct E_string es = {0};
|
| 148 |
+
|
| 149 |
+
spec_init(&sl);
|
| 150 |
+
TEST_ASSERT_TRUE(tests_make_es("[=A=]", &es));
|
| 151 |
+
|
| 152 |
+
bool ok = build_spec_list(&es, &sl);
|
| 153 |
+
TEST_ASSERT_TRUE(ok);
|
| 154 |
+
|
| 155 |
+
struct List_element *p = sl.head->next;
|
| 156 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 157 |
+
TEST_ASSERT_EQUAL_INT(RE_EQUIV_CLASS, p->type);
|
| 158 |
+
TEST_ASSERT_EQUAL_UINT8('A', p->u.equiv_code);
|
| 159 |
+
TEST_ASSERT_NULL(p->next);
|
| 160 |
+
|
| 161 |
+
es_free(&es);
|
| 162 |
+
tests_free_spec_list(&sl);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
static void test_build_spec_list_equiv_class_multi_char_invalid(void)
|
| 166 |
+
{
|
| 167 |
+
struct Spec_list sl = {0};
|
| 168 |
+
struct E_string es = {0};
|
| 169 |
+
|
| 170 |
+
spec_init(&sl);
|
| 171 |
+
TEST_ASSERT_TRUE(tests_make_es("[=AB=]", &es));
|
| 172 |
+
|
| 173 |
+
bool ok = build_spec_list(&es, &sl);
|
| 174 |
+
TEST_ASSERT_FALSE(ok);
|
| 175 |
+
|
| 176 |
+
es_free(&es);
|
| 177 |
+
tests_free_spec_list(&sl);
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
static void test_build_spec_list_repeated_char_with_count_decimal(void)
|
| 181 |
+
{
|
| 182 |
+
struct Spec_list sl = {0};
|
| 183 |
+
struct E_string es = {0};
|
| 184 |
+
|
| 185 |
+
spec_init(&sl);
|
| 186 |
+
TEST_ASSERT_TRUE(tests_make_es("[x*5]", &es));
|
| 187 |
+
|
| 188 |
+
bool ok = build_spec_list(&es, &sl);
|
| 189 |
+
TEST_ASSERT_TRUE(ok);
|
| 190 |
+
|
| 191 |
+
struct List_element *p = sl.head->next;
|
| 192 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 193 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, p->type);
|
| 194 |
+
TEST_ASSERT_EQUAL_UINT8('x', p->u.repeated_char.the_repeated_char);
|
| 195 |
+
TEST_ASSERT_EQUAL_UINT64(5, p->u.repeated_char.repeat_count);
|
| 196 |
+
TEST_ASSERT_NULL(p->next);
|
| 197 |
+
|
| 198 |
+
es_free(&es);
|
| 199 |
+
tests_free_spec_list(&sl);
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
static void test_build_spec_list_repeated_char_with_count_octal(void)
|
| 203 |
+
{
|
| 204 |
+
struct Spec_list sl = {0};
|
| 205 |
+
struct E_string es = {0};
|
| 206 |
+
|
| 207 |
+
spec_init(&sl);
|
| 208 |
+
TEST_ASSERT_TRUE(tests_make_es("[A*010]", &es)); /* 010(octal) == 8 */
|
| 209 |
+
|
| 210 |
+
bool ok = build_spec_list(&es, &sl);
|
| 211 |
+
TEST_ASSERT_TRUE(ok);
|
| 212 |
+
|
| 213 |
+
struct List_element *p = sl.head->next;
|
| 214 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 215 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, p->type);
|
| 216 |
+
TEST_ASSERT_EQUAL_UINT8('A', p->u.repeated_char.the_repeated_char);
|
| 217 |
+
TEST_ASSERT_EQUAL_UINT64(8, p->u.repeated_char.repeat_count);
|
| 218 |
+
TEST_ASSERT_NULL(p->next);
|
| 219 |
+
|
| 220 |
+
es_free(&es);
|
| 221 |
+
tests_free_spec_list(&sl);
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
static void test_build_spec_list_repeated_char_no_count_indefinite(void)
|
| 225 |
+
{
|
| 226 |
+
struct Spec_list sl = {0};
|
| 227 |
+
struct E_string es = {0};
|
| 228 |
+
|
| 229 |
+
spec_init(&sl);
|
| 230 |
+
TEST_ASSERT_TRUE(tests_make_es("[y*]", &es));
|
| 231 |
+
|
| 232 |
+
bool ok = build_spec_list(&es, &sl);
|
| 233 |
+
TEST_ASSERT_TRUE(ok);
|
| 234 |
+
|
| 235 |
+
struct List_element *p = sl.head->next;
|
| 236 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 237 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, p->type);
|
| 238 |
+
TEST_ASSERT_EQUAL_UINT8('y', p->u.repeated_char.the_repeated_char);
|
| 239 |
+
TEST_ASSERT_EQUAL_UINT64(0, p->u.repeated_char.repeat_count);
|
| 240 |
+
TEST_ASSERT_NULL(p->next);
|
| 241 |
+
|
| 242 |
+
es_free(&es);
|
| 243 |
+
tests_free_spec_list(&sl);
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
static void test_build_spec_list_mixed_range_and_repeat(void)
|
| 247 |
+
{
|
| 248 |
+
struct Spec_list sl = {0};
|
| 249 |
+
struct E_string es = {0};
|
| 250 |
+
|
| 251 |
+
spec_init(&sl);
|
| 252 |
+
TEST_ASSERT_TRUE(tests_make_es("a-d[y*3]", &es));
|
| 253 |
+
|
| 254 |
+
bool ok = build_spec_list(&es, &sl);
|
| 255 |
+
TEST_ASSERT_TRUE(ok);
|
| 256 |
+
|
| 257 |
+
struct List_element *p = sl.head->next;
|
| 258 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 259 |
+
TEST_ASSERT_EQUAL_INT(RE_RANGE, p->type);
|
| 260 |
+
TEST_ASSERT_EQUAL_UINT8('a', p->u.range.first_char);
|
| 261 |
+
TEST_ASSERT_EQUAL_UINT8('d', p->u.range.last_char);
|
| 262 |
+
|
| 263 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 264 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, p->type);
|
| 265 |
+
TEST_ASSERT_EQUAL_UINT8('y', p->u.repeated_char.the_repeated_char);
|
| 266 |
+
TEST_ASSERT_EQUAL_UINT64(3, p->u.repeated_char.repeat_count);
|
| 267 |
+
|
| 268 |
+
TEST_ASSERT_NULL(p->next);
|
| 269 |
+
|
| 270 |
+
es_free(&es);
|
| 271 |
+
tests_free_spec_list(&sl);
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
static void test_build_spec_list_escaped_dash_is_literal(void)
|
| 275 |
+
{
|
| 276 |
+
struct Spec_list sl = {0};
|
| 277 |
+
struct E_string es = {0};
|
| 278 |
+
|
| 279 |
+
spec_init(&sl);
|
| 280 |
+
/* The input a\-b produces 'a', '-', 'b' with '-' marked as escaped. */
|
| 281 |
+
TEST_ASSERT_TRUE(tests_make_es("a\\-b", &es));
|
| 282 |
+
|
| 283 |
+
bool ok = build_spec_list(&es, &sl);
|
| 284 |
+
TEST_ASSERT_TRUE(ok);
|
| 285 |
+
|
| 286 |
+
struct List_element *p = sl.head->next;
|
| 287 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 288 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 289 |
+
TEST_ASSERT_EQUAL_UINT8('a', p->u.normal_char);
|
| 290 |
+
|
| 291 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 292 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 293 |
+
TEST_ASSERT_EQUAL_UINT8('-', p->u.normal_char);
|
| 294 |
+
|
| 295 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 296 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 297 |
+
TEST_ASSERT_EQUAL_UINT8('b', p->u.normal_char);
|
| 298 |
+
|
| 299 |
+
TEST_ASSERT_NULL(p->next);
|
| 300 |
+
|
| 301 |
+
es_free(&es);
|
| 302 |
+
tests_free_spec_list(&sl);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
static void test_build_spec_list_equiv_inner_char_is_escaped_bracket(void)
|
| 306 |
+
{
|
| 307 |
+
struct Spec_list sl = {0};
|
| 308 |
+
struct E_string es = {0};
|
| 309 |
+
|
| 310 |
+
spec_init(&sl);
|
| 311 |
+
/* [=\]=] should be recognized as an equivalence class for ']' */
|
| 312 |
+
TEST_ASSERT_TRUE(tests_make_es("[=\\]=]", &es));
|
| 313 |
+
|
| 314 |
+
bool ok = build_spec_list(&es, &sl);
|
| 315 |
+
TEST_ASSERT_TRUE(ok);
|
| 316 |
+
|
| 317 |
+
struct List_element *p = sl.head->next;
|
| 318 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 319 |
+
TEST_ASSERT_EQUAL_INT(RE_EQUIV_CLASS, p->type);
|
| 320 |
+
TEST_ASSERT_EQUAL_UINT8(']', p->u.equiv_code);
|
| 321 |
+
TEST_ASSERT_NULL(p->next);
|
| 322 |
+
|
| 323 |
+
es_free(&es);
|
| 324 |
+
tests_free_spec_list(&sl);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
static void test_build_spec_list_brackets_without_construct_are_literals(void)
|
| 328 |
+
{
|
| 329 |
+
struct Spec_list sl = {0};
|
| 330 |
+
struct E_string es = {0};
|
| 331 |
+
|
| 332 |
+
spec_init(&sl);
|
| 333 |
+
TEST_ASSERT_TRUE(tests_make_es("[ab]", &es));
|
| 334 |
+
|
| 335 |
+
bool ok = build_spec_list(&es, &sl);
|
| 336 |
+
TEST_ASSERT_TRUE(ok);
|
| 337 |
+
|
| 338 |
+
struct List_element *p = sl.head->next;
|
| 339 |
+
TEST_ASSERT_NOT_NULL(p);
|
| 340 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 341 |
+
TEST_ASSERT_EQUAL_UINT8('[', p->u.normal_char);
|
| 342 |
+
|
| 343 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 344 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 345 |
+
TEST_ASSERT_EQUAL_UINT8('a', p->u.normal_char);
|
| 346 |
+
|
| 347 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 348 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 349 |
+
TEST_ASSERT_EQUAL_UINT8('b', p->u.normal_char);
|
| 350 |
+
|
| 351 |
+
p = p->next; TEST_ASSERT_NOT_NULL(p);
|
| 352 |
+
TEST_ASSERT_EQUAL_INT(RE_NORMAL_CHAR, p->type);
|
| 353 |
+
TEST_ASSERT_EQUAL_UINT8(']', p->u.normal_char);
|
| 354 |
+
|
| 355 |
+
TEST_ASSERT_NULL(p->next);
|
| 356 |
+
|
| 357 |
+
es_free(&es);
|
| 358 |
+
tests_free_spec_list(&sl);
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
static void test_build_spec_list_repeat_invalid_count_string(void)
|
| 362 |
+
{
|
| 363 |
+
struct Spec_list sl = {0};
|
| 364 |
+
struct E_string es = {0};
|
| 365 |
+
|
| 366 |
+
spec_init(&sl);
|
| 367 |
+
TEST_ASSERT_TRUE(tests_make_es("[A*xyz]", &es));
|
| 368 |
+
|
| 369 |
+
bool ok = build_spec_list(&es, &sl);
|
| 370 |
+
TEST_ASSERT_FALSE(ok);
|
| 371 |
+
|
| 372 |
+
es_free(&es);
|
| 373 |
+
tests_free_spec_list(&sl);
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
int main(void)
|
| 377 |
+
{
|
| 378 |
+
UNITY_BEGIN();
|
| 379 |
+
RUN_TEST(test_build_spec_list_normal_chars);
|
| 380 |
+
RUN_TEST(test_build_spec_list_range_ok);
|
| 381 |
+
RUN_TEST(test_build_spec_list_range_reverse_invalid);
|
| 382 |
+
RUN_TEST(test_build_spec_list_char_class_digit);
|
| 383 |
+
RUN_TEST(test_build_spec_list_char_class_invalid);
|
| 384 |
+
RUN_TEST(test_build_spec_list_equiv_class_single_char);
|
| 385 |
+
RUN_TEST(test_build_spec_list_equiv_class_multi_char_invalid);
|
| 386 |
+
RUN_TEST(test_build_spec_list_repeated_char_with_count_decimal);
|
| 387 |
+
RUN_TEST(test_build_spec_list_repeated_char_with_count_octal);
|
| 388 |
+
RUN_TEST(test_build_spec_list_repeated_char_no_count_indefinite);
|
| 389 |
+
RUN_TEST(test_build_spec_list_mixed_range_and_repeat);
|
| 390 |
+
RUN_TEST(test_build_spec_list_escaped_dash_is_literal);
|
| 391 |
+
RUN_TEST(test_build_spec_list_equiv_inner_char_is_escaped_bracket);
|
| 392 |
+
RUN_TEST(test_build_spec_list_brackets_without_construct_are_literals);
|
| 393 |
+
RUN_TEST(test_build_spec_list_repeat_invalid_count_string);
|
| 394 |
+
return UNITY_END();
|
| 395 |
+
}
|
tests/tr/tests_for_card_of_complement.c
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdio.h>
|
| 5 |
+
|
| 6 |
+
/* We rely on internal functions/types from the included tr source:
|
| 7 |
+
- struct Spec_list
|
| 8 |
+
- void spec_init(struct Spec_list *)
|
| 9 |
+
- bool parse_str(char const *, struct Spec_list *)
|
| 10 |
+
- int card_of_complement(struct Spec_list *)
|
| 11 |
+
- N_CHARS enum value
|
| 12 |
+
*/
|
| 13 |
+
|
| 14 |
+
static struct Spec_list make_spec(const char *s)
|
| 15 |
+
{
|
| 16 |
+
struct Spec_list spec;
|
| 17 |
+
spec_init(&spec);
|
| 18 |
+
bool ok = parse_str(s, &spec);
|
| 19 |
+
TEST_ASSERT_TRUE_MESSAGE(ok, "parse_str failed for input spec");
|
| 20 |
+
return spec;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
void setUp(void) {
|
| 24 |
+
/* No global state to set for these tests */
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
void tearDown(void) {
|
| 28 |
+
/* No teardown needed */
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Empty spec: complement should be all characters */
|
| 32 |
+
void test_card_of_complement_empty(void)
|
| 33 |
+
{
|
| 34 |
+
struct Spec_list spec = make_spec("");
|
| 35 |
+
int got = card_of_complement(&spec);
|
| 36 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS, got);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
/* Single normal character */
|
| 40 |
+
void test_card_of_complement_single_char(void)
|
| 41 |
+
{
|
| 42 |
+
struct Spec_list spec = make_spec("A");
|
| 43 |
+
int got = card_of_complement(&spec);
|
| 44 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS - 1, got);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/* Simple range a-z (26 characters) */
|
| 48 |
+
void test_card_of_complement_range_az(void)
|
| 49 |
+
{
|
| 50 |
+
struct Spec_list spec = make_spec("a-z");
|
| 51 |
+
int got = card_of_complement(&spec);
|
| 52 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS - 26, got);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
/* Full byte range \000-\377 should cover all 256 characters */
|
| 56 |
+
void test_card_of_complement_full_range(void)
|
| 57 |
+
{
|
| 58 |
+
struct Spec_list spec = make_spec("\\000-\\377");
|
| 59 |
+
int got = card_of_complement(&spec);
|
| 60 |
+
TEST_ASSERT_EQUAL_INT(0, got);
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/* Character class [:digit:] (10 characters) */
|
| 64 |
+
void test_card_of_complement_class_digit(void)
|
| 65 |
+
{
|
| 66 |
+
struct Spec_list spec = make_spec("[:digit:]");
|
| 67 |
+
int got = card_of_complement(&spec);
|
| 68 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS - 10, got);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* Overlapping constructs: "0-95-7" -> union is still 10 digits */
|
| 72 |
+
void test_card_of_complement_overlap_and_duplicates(void)
|
| 73 |
+
{
|
| 74 |
+
struct Spec_list spec = make_spec("0-95-7");
|
| 75 |
+
int got = card_of_complement(&spec);
|
| 76 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS - 10, got);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
/* Repeated char constructs: [x*5]x -> still only 'x' in the set
|
| 80 |
+
Indefinite repeat [x*] contributes nothing to the set */
|
| 81 |
+
void test_card_of_complement_bracketed_repeat_and_indef(void)
|
| 82 |
+
{
|
| 83 |
+
/* [x*5]x */
|
| 84 |
+
struct Spec_list spec1 = make_spec("[x*5]x");
|
| 85 |
+
int got1 = card_of_complement(&spec1);
|
| 86 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS - 1, got1);
|
| 87 |
+
|
| 88 |
+
/* [x*] should contribute nothing */
|
| 89 |
+
struct Spec_list spec2 = make_spec("[x*]");
|
| 90 |
+
int got2 = card_of_complement(&spec2);
|
| 91 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS, got2);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
/* Equivalence class [=A=] (per implementation: only 'A') */
|
| 95 |
+
void test_card_of_complement_equiv_class(void)
|
| 96 |
+
{
|
| 97 |
+
struct Spec_list spec = make_spec("[=A=]");
|
| 98 |
+
int got = card_of_complement(&spec);
|
| 99 |
+
TEST_ASSERT_EQUAL_INT(N_CHARS - 1, got);
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
int main(void)
|
| 103 |
+
{
|
| 104 |
+
UNITY_BEGIN();
|
| 105 |
+
RUN_TEST(test_card_of_complement_empty);
|
| 106 |
+
RUN_TEST(test_card_of_complement_single_char);
|
| 107 |
+
RUN_TEST(test_card_of_complement_range_az);
|
| 108 |
+
RUN_TEST(test_card_of_complement_full_range);
|
| 109 |
+
RUN_TEST(test_card_of_complement_class_digit);
|
| 110 |
+
RUN_TEST(test_card_of_complement_overlap_and_duplicates);
|
| 111 |
+
RUN_TEST(test_card_of_complement_bracketed_repeat_and_indef);
|
| 112 |
+
RUN_TEST(test_card_of_complement_equiv_class);
|
| 113 |
+
return UNITY_END();
|
| 114 |
+
}
|
tests/tr/tests_for_find_bracketed_repeat.c
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdint.h>
|
| 5 |
+
#include <stdbool.h>
|
| 6 |
+
|
| 7 |
+
/* Helper to build an E_string with no escapes. */
|
| 8 |
+
static struct E_string t_new_es_from_str(const char *str)
|
| 9 |
+
{
|
| 10 |
+
struct E_string es;
|
| 11 |
+
size_t len = strlen(str);
|
| 12 |
+
es.len = len;
|
| 13 |
+
es.s = (char*)malloc(len);
|
| 14 |
+
memcpy(es.s, str, len);
|
| 15 |
+
es.escaped = (bool*)calloc(len, sizeof(bool));
|
| 16 |
+
return es;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
/* Helper to build an E_string and mark given indices as escaped. */
|
| 20 |
+
static struct E_string t_new_es_with_escapes(const char *str, const size_t *idxs, size_t nidx)
|
| 21 |
+
{
|
| 22 |
+
struct E_string es = t_new_es_from_str(str);
|
| 23 |
+
for (size_t i = 0; i < nidx; ++i)
|
| 24 |
+
{
|
| 25 |
+
if (idxs[i] < es.len)
|
| 26 |
+
es.escaped[idxs[i]] = true;
|
| 27 |
+
}
|
| 28 |
+
return es;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
static void t_free_es(struct E_string *es)
|
| 32 |
+
{
|
| 33 |
+
if (!es) return;
|
| 34 |
+
free(es->s);
|
| 35 |
+
free(es->escaped);
|
| 36 |
+
es->s = NULL;
|
| 37 |
+
es->escaped = NULL;
|
| 38 |
+
es->len = 0;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
void setUp(void) {
|
| 42 |
+
/* Setup code here, or leave empty */
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
void tearDown(void) {
|
| 46 |
+
/* Cleanup code here, or leave empty */
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/* 1) Basic: [a*] -> success, repeat_count = 0, ']' index correct */
|
| 50 |
+
void test_find_bracketed_repeat_basic_no_count(void)
|
| 51 |
+
{
|
| 52 |
+
struct E_string es = t_new_es_from_str("[a*]");
|
| 53 |
+
unsigned char c = 0;
|
| 54 |
+
count rep = (count)12345; /* init to non-zero */
|
| 55 |
+
size_t close_idx = 9999;
|
| 56 |
+
|
| 57 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 58 |
+
|
| 59 |
+
TEST_ASSERT_EQUAL_INT(0, r);
|
| 60 |
+
TEST_ASSERT_EQUAL_INT('a', c);
|
| 61 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)0, (uint64_t)rep);
|
| 62 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)3, (uint64_t)close_idx);
|
| 63 |
+
|
| 64 |
+
t_free_es(&es);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
/* 2) Decimal count: [x*12] -> repeat_count = 12 */
|
| 68 |
+
void test_find_bracketed_repeat_decimal_count(void)
|
| 69 |
+
{
|
| 70 |
+
struct E_string es = t_new_es_from_str("[x*12]");
|
| 71 |
+
unsigned char c = 0;
|
| 72 |
+
count rep = 0;
|
| 73 |
+
size_t close_idx = 0;
|
| 74 |
+
|
| 75 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 76 |
+
|
| 77 |
+
TEST_ASSERT_EQUAL_INT(0, r);
|
| 78 |
+
TEST_ASSERT_EQUAL_INT('x', c);
|
| 79 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)12, (uint64_t)rep);
|
| 80 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)5, (uint64_t)close_idx);
|
| 81 |
+
|
| 82 |
+
t_free_es(&es);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/* 3) Octal count: [y*010] -> repeat_count = 8 (octal 10) */
|
| 86 |
+
void test_find_bracketed_repeat_octal_count(void)
|
| 87 |
+
{
|
| 88 |
+
struct E_string es = t_new_es_from_str("[y*010]");
|
| 89 |
+
unsigned char c = 0;
|
| 90 |
+
count rep = 0;
|
| 91 |
+
size_t close_idx = 0;
|
| 92 |
+
|
| 93 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 94 |
+
|
| 95 |
+
TEST_ASSERT_EQUAL_INT(0, r);
|
| 96 |
+
TEST_ASSERT_EQUAL_INT('y', c);
|
| 97 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)8, (uint64_t)rep);
|
| 98 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)6, (uint64_t)close_idx);
|
| 99 |
+
|
| 100 |
+
t_free_es(&es);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
/* 4) Invalid numeric part: [z*1x3] -> -2 */
|
| 104 |
+
void test_find_bracketed_repeat_invalid_digits(void)
|
| 105 |
+
{
|
| 106 |
+
struct E_string es = t_new_es_from_str("[z*1x3]");
|
| 107 |
+
unsigned char c = 0;
|
| 108 |
+
count rep = 0;
|
| 109 |
+
size_t close_idx = 0;
|
| 110 |
+
|
| 111 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 112 |
+
|
| 113 |
+
TEST_ASSERT_EQUAL_INT(-2, r);
|
| 114 |
+
|
| 115 |
+
t_free_es(&es);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
/* 5) No closing bracket: [q*123 -> -1 */
|
| 119 |
+
void test_find_bracketed_repeat_no_closing_bracket(void)
|
| 120 |
+
{
|
| 121 |
+
struct E_string es = t_new_es_from_str("[q*123");
|
| 122 |
+
unsigned char c = 0;
|
| 123 |
+
count rep = 0;
|
| 124 |
+
size_t close_idx = 0;
|
| 125 |
+
|
| 126 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 127 |
+
|
| 128 |
+
TEST_ASSERT_EQUAL_INT(-1, r);
|
| 129 |
+
|
| 130 |
+
t_free_es(&es);
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
/* 6) Escaped '*' (i.e., not matching) -> -1 */
|
| 134 |
+
void test_find_bracketed_repeat_star_escaped(void)
|
| 135 |
+
{
|
| 136 |
+
const char *s = "[a*5]";
|
| 137 |
+
size_t esc_idxs[] = { 2 }; /* index of '*' */
|
| 138 |
+
struct E_string es = t_new_es_with_escapes(s, esc_idxs, 1);
|
| 139 |
+
|
| 140 |
+
unsigned char c = 0;
|
| 141 |
+
count rep = 0;
|
| 142 |
+
size_t close_idx = 0;
|
| 143 |
+
|
| 144 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 145 |
+
|
| 146 |
+
TEST_ASSERT_EQUAL_INT(-1, r);
|
| 147 |
+
|
| 148 |
+
t_free_es(&es);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
/* 7) Escaped ']' (closing bracket escaped) -> -1 */
|
| 152 |
+
void test_find_bracketed_repeat_closing_bracket_escaped(void)
|
| 153 |
+
{
|
| 154 |
+
const char *s = "[a*5]";
|
| 155 |
+
size_t esc_idxs[] = { 4 }; /* index of ']' */
|
| 156 |
+
struct E_string es = t_new_es_with_escapes(s, esc_idxs, 1);
|
| 157 |
+
|
| 158 |
+
unsigned char c = 0;
|
| 159 |
+
count rep = 0;
|
| 160 |
+
size_t close_idx = 0;
|
| 161 |
+
|
| 162 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 163 |
+
|
| 164 |
+
TEST_ASSERT_EQUAL_INT(-1, r);
|
| 165 |
+
|
| 166 |
+
t_free_es(&es);
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
/* 8) Overflow numeric part: a very long sequence of digits -> -2 */
|
| 170 |
+
void test_find_bracketed_repeat_overflow_digits(void)
|
| 171 |
+
{
|
| 172 |
+
/* Many digits to ensure overflow on typical platforms. */
|
| 173 |
+
const char *s = "[a*999999999999999999999999999999999999]";
|
| 174 |
+
struct E_string es = t_new_es_from_str(s);
|
| 175 |
+
|
| 176 |
+
unsigned char c = 0;
|
| 177 |
+
count rep = 0;
|
| 178 |
+
size_t close_idx = 0;
|
| 179 |
+
|
| 180 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 181 |
+
|
| 182 |
+
TEST_ASSERT_EQUAL_INT(-2, r);
|
| 183 |
+
|
| 184 |
+
t_free_es(&es);
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
/* 9) Any escaped character within the digits causes non-match -> -1 */
|
| 188 |
+
void test_find_bracketed_repeat_digit_escaped_in_middle(void)
|
| 189 |
+
{
|
| 190 |
+
const char *s = "[a*12]";
|
| 191 |
+
size_t esc_idxs[] = { 4 }; /* index of '2' */
|
| 192 |
+
struct E_string es = t_new_es_with_escapes(s, esc_idxs, 1);
|
| 193 |
+
|
| 194 |
+
unsigned char c = 0;
|
| 195 |
+
count rep = 0;
|
| 196 |
+
size_t close_idx = 0;
|
| 197 |
+
|
| 198 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 199 |
+
|
| 200 |
+
TEST_ASSERT_EQUAL_INT(-1, r);
|
| 201 |
+
|
| 202 |
+
t_free_es(&es);
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
/* 10) Missing '*' immediately after c -> -1 */
|
| 206 |
+
void test_find_bracketed_repeat_missing_star(void)
|
| 207 |
+
{
|
| 208 |
+
struct E_string es = t_new_es_from_str("[a+12]");
|
| 209 |
+
unsigned char c = 0;
|
| 210 |
+
count rep = 0;
|
| 211 |
+
size_t close_idx = 0;
|
| 212 |
+
|
| 213 |
+
int r = find_bracketed_repeat(&es, 1, &c, &rep, &close_idx);
|
| 214 |
+
|
| 215 |
+
TEST_ASSERT_EQUAL_INT(-1, r);
|
| 216 |
+
|
| 217 |
+
t_free_es(&es);
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
int main(void)
|
| 221 |
+
{
|
| 222 |
+
UNITY_BEGIN();
|
| 223 |
+
RUN_TEST(test_find_bracketed_repeat_basic_no_count);
|
| 224 |
+
RUN_TEST(test_find_bracketed_repeat_decimal_count);
|
| 225 |
+
RUN_TEST(test_find_bracketed_repeat_octal_count);
|
| 226 |
+
RUN_TEST(test_find_bracketed_repeat_invalid_digits);
|
| 227 |
+
RUN_TEST(test_find_bracketed_repeat_no_closing_bracket);
|
| 228 |
+
RUN_TEST(test_find_bracketed_repeat_star_escaped);
|
| 229 |
+
RUN_TEST(test_find_bracketed_repeat_closing_bracket_escaped);
|
| 230 |
+
RUN_TEST(test_find_bracketed_repeat_overflow_digits);
|
| 231 |
+
RUN_TEST(test_find_bracketed_repeat_digit_escaped_in_middle);
|
| 232 |
+
RUN_TEST(test_find_bracketed_repeat_missing_star);
|
| 233 |
+
return UNITY_END();
|
| 234 |
+
}
|
tests/tr/tests_for_find_closing_delim.c
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdbool.h>
|
| 5 |
+
#include <stddef.h>
|
| 6 |
+
|
| 7 |
+
/* Unity hooks */
|
| 8 |
+
void setUp(void) {
|
| 9 |
+
/* Setup code here, or leave empty */
|
| 10 |
+
}
|
| 11 |
+
void tearDown(void) {
|
| 12 |
+
/* Cleanup code here, or leave empty */
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
/* Helper to init an E_string with provided data and length. */
|
| 16 |
+
static void init_es(struct E_string *es, char *data, size_t len) {
|
| 17 |
+
es->s = data; /* data must remain valid for the test duration */
|
| 18 |
+
es->len = len;
|
| 19 |
+
es->escaped = (bool *)calloc(len, sizeof(bool));
|
| 20 |
+
TEST_ASSERT_NOT_NULL(es->escaped);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
/* Helper to free E_string escaped map (when allocated via init_es). */
|
| 24 |
+
static void free_es(struct E_string *es) {
|
| 25 |
+
free(es->escaped);
|
| 26 |
+
es->escaped = NULL;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Test: basic match for [: ... :] — should find ":]" starting at index 2 */
|
| 30 |
+
void test_find_closing_delim_basic_colon(void) {
|
| 31 |
+
char data[] = "[::]"; /* indexes: 0:'[',1:':',2:':',3:']' */
|
| 32 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 33 |
+
size_t idx = (size_t)-1;
|
| 34 |
+
TEST_ASSERT_TRUE(find_closing_delim(&es, 2, ':', &idx));
|
| 35 |
+
TEST_ASSERT_EQUAL_UINT(2, idx);
|
| 36 |
+
free_es(&es);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
/* Test: escaped pre-bracket char should not match */
|
| 40 |
+
void test_find_closing_delim_escaped_colon(void) {
|
| 41 |
+
char data[] = "[::]";
|
| 42 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 43 |
+
es.escaped[2] = true; /* escape ':' at index 2 */
|
| 44 |
+
size_t idx;
|
| 45 |
+
TEST_ASSERT_FALSE(find_closing_delim(&es, 2, ':', &idx));
|
| 46 |
+
free_es(&es);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/* Test: escaped closing bracket should not match */
|
| 50 |
+
void test_find_closing_delim_escaped_bracket(void) {
|
| 51 |
+
char data[] = "[::]";
|
| 52 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 53 |
+
es.escaped[3] = true; /* escape ']' at index 3 */
|
| 54 |
+
size_t idx;
|
| 55 |
+
TEST_ASSERT_FALSE(find_closing_delim(&es, 2, ':', &idx));
|
| 56 |
+
free_es(&es);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
/* Test: ensure start_idx is honored (ignore earlier pairs) */
|
| 60 |
+
void test_find_closing_delim_respects_start_idx(void) {
|
| 61 |
+
char data[] = "a:]:]"; /* indexes: 0 'a', 1 ':', 2 ']', 3 ':', 4 ']' */
|
| 62 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 63 |
+
size_t idx = 0;
|
| 64 |
+
/* Start at index 2, should skip pair at 1 and find pair at 3 */
|
| 65 |
+
TEST_ASSERT_TRUE(find_closing_delim(&es, 2, ':', &idx));
|
| 66 |
+
TEST_ASSERT_EQUAL_UINT(3, idx);
|
| 67 |
+
free_es(&es);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
/* Test: no match present */
|
| 71 |
+
void test_find_closing_delim_no_match(void) {
|
| 72 |
+
char data[] = "abcxyz";
|
| 73 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 74 |
+
size_t idx;
|
| 75 |
+
TEST_ASSERT_FALSE(find_closing_delim(&es, 0, ':', &idx));
|
| 76 |
+
free_es(&es);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
/* Test: start_idx at last character (cannot match due to lack of room) */
|
| 80 |
+
void test_find_closing_delim_start_at_last_char(void) {
|
| 81 |
+
char data[] = ":]"; /* len=2, last index=1 */
|
| 82 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 83 |
+
size_t idx;
|
| 84 |
+
TEST_ASSERT_FALSE(find_closing_delim(&es, 1, ':', &idx));
|
| 85 |
+
free_es(&es);
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
/* Test: equals variant [==] should find '=]' starting at index 2 */
|
| 89 |
+
void test_find_closing_delim_equals_variant(void) {
|
| 90 |
+
char data[] = "[==]"; /* 0:'[',1:'=',2:'=',3:']' */
|
| 91 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 92 |
+
size_t idx = 0;
|
| 93 |
+
TEST_ASSERT_TRUE(find_closing_delim(&es, 2, '=', &idx));
|
| 94 |
+
TEST_ASSERT_EQUAL_UINT(2, idx);
|
| 95 |
+
free_es(&es);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/* Test: embedded NUL bytes are handled (search should still succeed) */
|
| 99 |
+
void test_find_closing_delim_handles_nul_bytes(void) {
|
| 100 |
+
char data[6];
|
| 101 |
+
data[0] = 'a';
|
| 102 |
+
data[1] = ':';
|
| 103 |
+
data[2] = ']';
|
| 104 |
+
data[3] = '\0';
|
| 105 |
+
data[4] = ':';
|
| 106 |
+
data[5] = ']';
|
| 107 |
+
struct E_string es; init_es(&es, data, 6);
|
| 108 |
+
size_t idx = 999;
|
| 109 |
+
TEST_ASSERT_TRUE(find_closing_delim(&es, 0, ':', &idx));
|
| 110 |
+
TEST_ASSERT_EQUAL_UINT(1, idx); /* first occurrence at 1,2 */
|
| 111 |
+
free_es(&es);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/* Test: skip escaped first pair and find later valid pair */
|
| 115 |
+
void test_find_closing_delim_skips_escaped_pair(void) {
|
| 116 |
+
char data[] = ":]:]"; /* 0 ':',1 ']',2 ':',3 ']' */
|
| 117 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 118 |
+
es.escaped[0] = true; /* escape first ':' so 0,1 is invalid */
|
| 119 |
+
size_t idx = (size_t)-1;
|
| 120 |
+
TEST_ASSERT_TRUE(find_closing_delim(&es, 0, ':', &idx));
|
| 121 |
+
TEST_ASSERT_EQUAL_UINT(2, idx); /* should match pair at 2,3 */
|
| 122 |
+
free_es(&es);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
/* Test: escaped ']' in first pair; should find the next unescaped pair */
|
| 126 |
+
void test_find_closing_delim_skips_escaped_bracket_then_finds_next(void) {
|
| 127 |
+
char data[] = ":]:]"; /* 0 ':',1 ']',2 ':',3 ']' */
|
| 128 |
+
struct E_string es; init_es(&es, data, sizeof(data) - 1);
|
| 129 |
+
es.escaped[1] = true; /* escape ']' at index 1 */
|
| 130 |
+
size_t idx = 0;
|
| 131 |
+
TEST_ASSERT_TRUE(find_closing_delim(&es, 0, ':', &idx));
|
| 132 |
+
TEST_ASSERT_EQUAL_UINT(2, idx); /* match at 2,3 */
|
| 133 |
+
free_es(&es);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
int main(void) {
|
| 137 |
+
UNITY_BEGIN();
|
| 138 |
+
RUN_TEST(test_find_closing_delim_basic_colon);
|
| 139 |
+
RUN_TEST(test_find_closing_delim_escaped_colon);
|
| 140 |
+
RUN_TEST(test_find_closing_delim_escaped_bracket);
|
| 141 |
+
RUN_TEST(test_find_closing_delim_respects_start_idx);
|
| 142 |
+
RUN_TEST(test_find_closing_delim_no_match);
|
| 143 |
+
RUN_TEST(test_find_closing_delim_start_at_last_char);
|
| 144 |
+
RUN_TEST(test_find_closing_delim_equals_variant);
|
| 145 |
+
RUN_TEST(test_find_closing_delim_handles_nul_bytes);
|
| 146 |
+
RUN_TEST(test_find_closing_delim_skips_escaped_pair);
|
| 147 |
+
RUN_TEST(test_find_closing_delim_skips_escaped_bracket_then_finds_next);
|
| 148 |
+
return UNITY_END();
|
| 149 |
+
}
|
tests/tr/tests_for_get_next.c
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <ctype.h>
|
| 5 |
+
#include <locale.h>
|
| 6 |
+
|
| 7 |
+
/* Unity fixtures */
|
| 8 |
+
void setUp(void) {
|
| 9 |
+
/* Ensure predictable ctype behavior */
|
| 10 |
+
setlocale(LC_ALL, "C");
|
| 11 |
+
}
|
| 12 |
+
void tearDown(void) {
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
/* Local helpers for building specs for get_next */
|
| 16 |
+
static void tsl_spec_init(struct Spec_list *s) {
|
| 17 |
+
spec_init(s);
|
| 18 |
+
s->state = BEGIN_STATE;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
/* Tests */
|
| 22 |
+
static void test_get_next_normal_char_single(void) {
|
| 23 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 24 |
+
append_normal_char(&s, (unsigned char)'A');
|
| 25 |
+
|
| 26 |
+
enum Upper_Lower_class cls = UL_NONE;
|
| 27 |
+
int c = get_next(&s, &cls);
|
| 28 |
+
TEST_ASSERT_EQUAL_INT('A', c);
|
| 29 |
+
TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 30 |
+
|
| 31 |
+
c = get_next(&s, &cls);
|
| 32 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
static void test_get_next_range_basic(void) {
|
| 36 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 37 |
+
/* Range c..f yields c,d,e,f */
|
| 38 |
+
TEST_ASSERT_TRUE_MESSAGE(append_range(&s, (unsigned char)'c', (unsigned char)'f'), "append_range failed");
|
| 39 |
+
|
| 40 |
+
enum Upper_Lower_class cls;
|
| 41 |
+
int c;
|
| 42 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('c', c); TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 43 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('d', c); TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 44 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('e', c); TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 45 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('f', c); TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 46 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT(-1, c);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
static void test_get_next_char_class_lower_iteration(void) {
|
| 50 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 51 |
+
/* Append [:lower:] */
|
| 52 |
+
TEST_ASSERT_TRUE_MESSAGE(append_char_class(&s, "lower", strlen("lower")), "append_char_class lower failed");
|
| 53 |
+
|
| 54 |
+
enum Upper_Lower_class cls;
|
| 55 |
+
int prev = -1;
|
| 56 |
+
int count = 0;
|
| 57 |
+
while (1) {
|
| 58 |
+
int c = get_next(&s, &cls);
|
| 59 |
+
if (c == -1) break;
|
| 60 |
+
TEST_ASSERT_EQUAL_INT(UL_LOWER, cls);
|
| 61 |
+
TEST_ASSERT_TRUE_MESSAGE(islower(c) != 0, "Returned char not in lower class");
|
| 62 |
+
if (prev != -1) {
|
| 63 |
+
TEST_ASSERT_TRUE_MESSAGE(c > prev, "Class enumeration not strictly increasing");
|
| 64 |
+
}
|
| 65 |
+
prev = c;
|
| 66 |
+
count++;
|
| 67 |
+
/* Safety guard; in C locale should be finite and <= N_CHARS */
|
| 68 |
+
TEST_ASSERT_TRUE(count <= N_CHARS);
|
| 69 |
+
}
|
| 70 |
+
TEST_ASSERT_TRUE_MESSAGE(count > 0, "lower class produced no characters");
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
static void test_get_next_char_class_digit_class_is_UL_NONE(void) {
|
| 74 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 75 |
+
TEST_ASSERT_TRUE_MESSAGE(append_char_class(&s, "digit", strlen("digit")), "append_char_class digit failed");
|
| 76 |
+
enum Upper_Lower_class cls = UL_UPPER; /* initialize to different to catch no-change */
|
| 77 |
+
int c = get_next(&s, &cls);
|
| 78 |
+
TEST_ASSERT_NOT_EQUAL(-1, c);
|
| 79 |
+
TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
static void test_get_next_equiv_class_single(void) {
|
| 83 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 84 |
+
/* [=X=] equivalent in this implementation returns X once */
|
| 85 |
+
TEST_ASSERT_TRUE_MESSAGE(append_equiv_class(&s, "X", 1), "append_equiv_class failed");
|
| 86 |
+
|
| 87 |
+
enum Upper_Lower_class cls;
|
| 88 |
+
int c = get_next(&s, &cls);
|
| 89 |
+
TEST_ASSERT_EQUAL_INT('X', c);
|
| 90 |
+
TEST_ASSERT_EQUAL_INT(UL_NONE, cls);
|
| 91 |
+
c = get_next(&s, &cls);
|
| 92 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
static void test_get_next_repeated_char_positive_count(void) {
|
| 96 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 97 |
+
append_repeated_char(&s, (unsigned char)'Z', (count)3);
|
| 98 |
+
|
| 99 |
+
enum Upper_Lower_class cls;
|
| 100 |
+
int c;
|
| 101 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('Z', c);
|
| 102 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('Z', c);
|
| 103 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT('Z', c);
|
| 104 |
+
c = get_next(&s, &cls); TEST_ASSERT_EQUAL_INT(-1, c);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
static void test_get_next_repeated_char_zero_only(void) {
|
| 108 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 109 |
+
append_repeated_char(&s, (unsigned char)'Y', (count)0);
|
| 110 |
+
|
| 111 |
+
enum Upper_Lower_class cls;
|
| 112 |
+
int c = get_next(&s, &cls);
|
| 113 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
static void test_get_next_repeated_char_zero_then_normal(void) {
|
| 117 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 118 |
+
append_repeated_char(&s, (unsigned char)'W', (count)0);
|
| 119 |
+
append_normal_char(&s, (unsigned char)'Q');
|
| 120 |
+
|
| 121 |
+
enum Upper_Lower_class cls;
|
| 122 |
+
int c = get_next(&s, &cls);
|
| 123 |
+
TEST_ASSERT_EQUAL_INT('Q', c);
|
| 124 |
+
c = get_next(&s, &cls);
|
| 125 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
static void test_get_next_two_char_classes_transition(void) {
|
| 129 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 130 |
+
TEST_ASSERT_TRUE_MESSAGE(append_char_class(&s, "lower", strlen("lower")), "append lower failed");
|
| 131 |
+
TEST_ASSERT_TRUE_MESSAGE(append_char_class(&s, "upper", strlen("upper")), "append upper failed");
|
| 132 |
+
|
| 133 |
+
enum Upper_Lower_class cls;
|
| 134 |
+
int c = get_next(&s, &cls);
|
| 135 |
+
TEST_ASSERT_NOT_EQUAL(-1, c);
|
| 136 |
+
TEST_ASSERT_EQUAL_INT(UL_LOWER, cls);
|
| 137 |
+
TEST_ASSERT_TRUE(islower(c));
|
| 138 |
+
|
| 139 |
+
/* Skip the rest of the lower-class element to transition to next element */
|
| 140 |
+
skip_construct(&s);
|
| 141 |
+
|
| 142 |
+
c = get_next(&s, &cls);
|
| 143 |
+
TEST_ASSERT_NOT_EQUAL(-1, c);
|
| 144 |
+
TEST_ASSERT_EQUAL_INT(UL_UPPER, cls);
|
| 145 |
+
TEST_ASSERT_TRUE(isupper(c));
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
static void test_get_next_reset_begin_state_restarts(void) {
|
| 149 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 150 |
+
append_normal_char(&s, (unsigned char)'A');
|
| 151 |
+
append_normal_char(&s, (unsigned char)'B');
|
| 152 |
+
|
| 153 |
+
enum Upper_Lower_class cls;
|
| 154 |
+
int c = get_next(&s, &cls);
|
| 155 |
+
TEST_ASSERT_EQUAL_INT('A', c);
|
| 156 |
+
|
| 157 |
+
/* Reset and ensure we start from the beginning again */
|
| 158 |
+
s.state = BEGIN_STATE;
|
| 159 |
+
c = get_next(&s, &cls);
|
| 160 |
+
TEST_ASSERT_EQUAL_INT('A', c);
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
static void test_get_next_null_class_pointer(void) {
|
| 164 |
+
struct Spec_list s; tsl_spec_init(&s);
|
| 165 |
+
append_normal_char(&s, (unsigned char)'C');
|
| 166 |
+
|
| 167 |
+
int c = get_next(&s, NULL);
|
| 168 |
+
TEST_ASSERT_EQUAL_INT('C', c);
|
| 169 |
+
c = get_next(&s, NULL);
|
| 170 |
+
TEST_ASSERT_EQUAL_INT(-1, c);
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
int main(void) {
|
| 174 |
+
UNITY_BEGIN();
|
| 175 |
+
RUN_TEST(test_get_next_normal_char_single);
|
| 176 |
+
RUN_TEST(test_get_next_range_basic);
|
| 177 |
+
RUN_TEST(test_get_next_char_class_lower_iteration);
|
| 178 |
+
RUN_TEST(test_get_next_char_class_digit_class_is_UL_NONE);
|
| 179 |
+
RUN_TEST(test_get_next_equiv_class_single);
|
| 180 |
+
RUN_TEST(test_get_next_repeated_char_positive_count);
|
| 181 |
+
RUN_TEST(test_get_next_repeated_char_zero_only);
|
| 182 |
+
RUN_TEST(test_get_next_repeated_char_zero_then_normal);
|
| 183 |
+
RUN_TEST(test_get_next_two_char_classes_transition);
|
| 184 |
+
RUN_TEST(test_get_next_reset_begin_state_restarts);
|
| 185 |
+
RUN_TEST(test_get_next_null_class_pointer);
|
| 186 |
+
return UNITY_END();
|
| 187 |
+
}
|
tests/tr/tests_for_get_s2_spec_stats.c
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdio.h>
|
| 5 |
+
#include <stdbool.h>
|
| 6 |
+
|
| 7 |
+
/* The test file is included into the tr.c translation unit, so we can
|
| 8 |
+
directly access internal (static) functions and types. */
|
| 9 |
+
|
| 10 |
+
static void free_spec_list(struct Spec_list *s)
|
| 11 |
+
{
|
| 12 |
+
if (!s || !s->head) return;
|
| 13 |
+
struct List_element *p = s->head;
|
| 14 |
+
while (p) {
|
| 15 |
+
struct List_element *n = p->next;
|
| 16 |
+
free(p);
|
| 17 |
+
p = n;
|
| 18 |
+
}
|
| 19 |
+
s->head = NULL;
|
| 20 |
+
s->tail = NULL;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
static void init_and_parse(struct Spec_list *s, const char *str)
|
| 24 |
+
{
|
| 25 |
+
spec_init(s);
|
| 26 |
+
bool ok = parse_str(str, s);
|
| 27 |
+
TEST_ASSERT_MESSAGE(ok, "parse_str failed for input");
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
static size_t count_indefinite_repeat_nodes(struct Spec_list *s)
|
| 31 |
+
{
|
| 32 |
+
size_t cnt = 0;
|
| 33 |
+
for (struct List_element *p = s->head->next; p; p = p->next) {
|
| 34 |
+
if (p->type == RE_REPEATED_CHAR && p->u.repeated_char.repeat_count == 0)
|
| 35 |
+
cnt++;
|
| 36 |
+
}
|
| 37 |
+
return cnt;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
static struct List_element* find_first_repeat_node(struct Spec_list *s)
|
| 41 |
+
{
|
| 42 |
+
for (struct List_element *p = s->head->next; p; p = p->next) {
|
| 43 |
+
if (p->type == RE_REPEATED_CHAR)
|
| 44 |
+
return p;
|
| 45 |
+
}
|
| 46 |
+
return NULL;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
void setUp(void) {
|
| 50 |
+
/* no-op */
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
void tearDown(void) {
|
| 54 |
+
/* no-op */
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
/* 1) No indefinite repeats: lengths are computed, nothing extended */
|
| 58 |
+
void test_get_s2_spec_stats_no_indefinite(void)
|
| 59 |
+
{
|
| 60 |
+
struct Spec_list s2 = {0};
|
| 61 |
+
init_and_parse(&s2, "AB[Z*3]"); /* length = 2 + 3 = 5 */
|
| 62 |
+
|
| 63 |
+
get_s2_spec_stats(&s2, 10);
|
| 64 |
+
|
| 65 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)5, (unsigned long long)s2.length);
|
| 66 |
+
TEST_ASSERT_EQUAL_UINT32(0u, (unsigned int)s2.n_indefinite_repeats);
|
| 67 |
+
|
| 68 |
+
struct List_element *rep = find_first_repeat_node(&s2);
|
| 69 |
+
TEST_ASSERT_NOT_NULL(rep);
|
| 70 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, rep->type);
|
| 71 |
+
TEST_ASSERT_EQUAL_UINT32(3u, (unsigned int)rep->u.repeated_char.repeat_count);
|
| 72 |
+
|
| 73 |
+
free_spec_list(&s2);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/* 2) Single [c*] indefinite: extended to len_s1 */
|
| 77 |
+
void test_get_s2_spec_stats_single_indefinite_extend(void)
|
| 78 |
+
{
|
| 79 |
+
struct Spec_list s2 = {0};
|
| 80 |
+
init_and_parse(&s2, "A[Y*]Z"); /* initial length = 2 (1 + 0 + 1) */
|
| 81 |
+
|
| 82 |
+
get_s2_spec_stats(&s2, 26);
|
| 83 |
+
|
| 84 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)26, (unsigned long long)s2.length);
|
| 85 |
+
TEST_ASSERT_NOT_NULL(s2.indefinite_repeat_element);
|
| 86 |
+
TEST_ASSERT_EQUAL_INT('Y', s2.indefinite_repeat_element->u.repeated_char.the_repeated_char);
|
| 87 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)24,
|
| 88 |
+
(unsigned long long)s2.indefinite_repeat_element->u.repeated_char.repeat_count);
|
| 89 |
+
|
| 90 |
+
/* Recompute stats to ensure it's no longer treated as indefinite */
|
| 91 |
+
get_spec_stats(&s2);
|
| 92 |
+
TEST_ASSERT_EQUAL_UINT32(0u, (unsigned int)s2.n_indefinite_repeats);
|
| 93 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)26, (unsigned long long)s2.length);
|
| 94 |
+
|
| 95 |
+
free_spec_list(&s2);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/* 3) Single [c*] indefinite: len_s1 == s2.length, no change */
|
| 99 |
+
void test_get_s2_spec_stats_single_indefinite_equal_length(void)
|
| 100 |
+
{
|
| 101 |
+
struct Spec_list s2 = {0};
|
| 102 |
+
init_and_parse(&s2, "M[N*]"); /* initial length = 1 */
|
| 103 |
+
|
| 104 |
+
get_s2_spec_stats(&s2, 1);
|
| 105 |
+
|
| 106 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)1, (unsigned long long)s2.length);
|
| 107 |
+
TEST_ASSERT_NOT_NULL(s2.indefinite_repeat_element);
|
| 108 |
+
TEST_ASSERT_EQUAL_INT('N', s2.indefinite_repeat_element->u.repeated_char.the_repeated_char);
|
| 109 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)0,
|
| 110 |
+
(unsigned long long)s2.indefinite_repeat_element->u.repeated_char.repeat_count);
|
| 111 |
+
|
| 112 |
+
free_spec_list(&s2);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
/* 4) Single [c*] indefinite: len_s1 < s2.length, no extension occurs */
|
| 116 |
+
void test_get_s2_spec_stats_single_indefinite_len_s1_smaller(void)
|
| 117 |
+
{
|
| 118 |
+
struct Spec_list s2 = {0};
|
| 119 |
+
init_and_parse(&s2, "P[Q*]R"); /* initial length = 2 */
|
| 120 |
+
|
| 121 |
+
get_s2_spec_stats(&s2, 1);
|
| 122 |
+
|
| 123 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)2, (unsigned long long)s2.length);
|
| 124 |
+
TEST_ASSERT_NOT_NULL(s2.indefinite_repeat_element);
|
| 125 |
+
TEST_ASSERT_EQUAL_INT('Q', s2.indefinite_repeat_element->u.repeated_char.the_repeated_char);
|
| 126 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)0,
|
| 127 |
+
(unsigned long long)s2.indefinite_repeat_element->u.repeated_char.repeat_count);
|
| 128 |
+
|
| 129 |
+
free_spec_list(&s2);
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/* 5) [c*0] is treated as indefinite and extended */
|
| 133 |
+
void test_get_s2_spec_stats_indefinite_zero_explicit(void)
|
| 134 |
+
{
|
| 135 |
+
struct Spec_list s2 = {0};
|
| 136 |
+
init_and_parse(&s2, "X[W*0]Y"); /* initial length = 2 */
|
| 137 |
+
|
| 138 |
+
get_s2_spec_stats(&s2, 5);
|
| 139 |
+
|
| 140 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)5, (unsigned long long)s2.length);
|
| 141 |
+
TEST_ASSERT_NOT_NULL(s2.indefinite_repeat_element);
|
| 142 |
+
TEST_ASSERT_EQUAL_INT('W', s2.indefinite_repeat_element->u.repeated_char.the_repeated_char);
|
| 143 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)3,
|
| 144 |
+
(unsigned long long)s2.indefinite_repeat_element->u.repeated_char.repeat_count);
|
| 145 |
+
|
| 146 |
+
/* Recompute to ensure resolution of indefiniteness */
|
| 147 |
+
get_spec_stats(&s2);
|
| 148 |
+
TEST_ASSERT_EQUAL_UINT32(0u, (unsigned int)s2.n_indefinite_repeats);
|
| 149 |
+
|
| 150 |
+
free_spec_list(&s2);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
/* 6) Multiple indefinite repeats: no extension should occur */
|
| 154 |
+
void test_get_s2_spec_stats_multiple_indefinite_no_extension(void)
|
| 155 |
+
{
|
| 156 |
+
struct Spec_list s2 = {0};
|
| 157 |
+
init_and_parse(&s2, "[A*][B*]"); /* initial length = 0, two indefinites */
|
| 158 |
+
|
| 159 |
+
get_s2_spec_stats(&s2, 10);
|
| 160 |
+
|
| 161 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)0, (unsigned long long)s2.length);
|
| 162 |
+
|
| 163 |
+
/* Both repeats should still be indefinite (repeat_count == 0). */
|
| 164 |
+
size_t indef = count_indefinite_repeat_nodes(&s2);
|
| 165 |
+
TEST_ASSERT_EQUAL_UINT32(2u, (unsigned int)indef);
|
| 166 |
+
|
| 167 |
+
/* Also ensure neither was modified inadvertently. */
|
| 168 |
+
size_t zero_repeat_nodes = 0;
|
| 169 |
+
size_t nonzero_repeat_nodes = 0;
|
| 170 |
+
for (struct List_element *p = s2.head->next; p; p = p->next) {
|
| 171 |
+
if (p->type == RE_REPEATED_CHAR) {
|
| 172 |
+
if (p->u.repeated_char.repeat_count == 0) zero_repeat_nodes++;
|
| 173 |
+
else nonzero_repeat_nodes++;
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
TEST_ASSERT_EQUAL_UINT32(2u, (unsigned int)zero_repeat_nodes);
|
| 177 |
+
TEST_ASSERT_EQUAL_UINT32(0u, (unsigned int)nonzero_repeat_nodes);
|
| 178 |
+
|
| 179 |
+
free_spec_list(&s2);
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
/* 7) Range plus single indefinite: extend to len_s1 */
|
| 183 |
+
void test_get_s2_spec_stats_range_and_indefinite(void)
|
| 184 |
+
{
|
| 185 |
+
struct Spec_list s2 = {0};
|
| 186 |
+
init_and_parse(&s2, "a-c[Z*]"); /* range a-c -> 3, plus 0 => initial length 3 */
|
| 187 |
+
|
| 188 |
+
get_s2_spec_stats(&s2, 5);
|
| 189 |
+
|
| 190 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)5, (unsigned long long)s2.length);
|
| 191 |
+
TEST_ASSERT_NOT_NULL(s2.indefinite_repeat_element);
|
| 192 |
+
TEST_ASSERT_EQUAL_INT('Z', s2.indefinite_repeat_element->u.repeated_char.the_repeated_char);
|
| 193 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)2,
|
| 194 |
+
(unsigned long long)s2.indefinite_repeat_element->u.repeated_char.repeat_count);
|
| 195 |
+
|
| 196 |
+
free_spec_list(&s2);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
int main(void)
|
| 200 |
+
{
|
| 201 |
+
UNITY_BEGIN();
|
| 202 |
+
RUN_TEST(test_get_s2_spec_stats_no_indefinite);
|
| 203 |
+
RUN_TEST(test_get_s2_spec_stats_single_indefinite_extend);
|
| 204 |
+
RUN_TEST(test_get_s2_spec_stats_single_indefinite_equal_length);
|
| 205 |
+
RUN_TEST(test_get_s2_spec_stats_single_indefinite_len_s1_smaller);
|
| 206 |
+
RUN_TEST(test_get_s2_spec_stats_indefinite_zero_explicit);
|
| 207 |
+
RUN_TEST(test_get_s2_spec_stats_multiple_indefinite_no_extension);
|
| 208 |
+
RUN_TEST(test_get_s2_spec_stats_range_and_indefinite);
|
| 209 |
+
return UNITY_END();
|
| 210 |
+
}
|
tests/tr/tests_for_get_spec_stats.c
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <ctype.h>
|
| 5 |
+
#include <stdint.h>
|
| 6 |
+
|
| 7 |
+
/* setUp and tearDown required by Unity */
|
| 8 |
+
void setUp(void) {
|
| 9 |
+
/* no-op */
|
| 10 |
+
}
|
| 11 |
+
void tearDown(void) {
|
| 12 |
+
/* no-op */
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
/* Helpers: build a Spec_list via program internals and free it. */
|
| 16 |
+
|
| 17 |
+
static void init_and_parse(struct Spec_list *s, const char *pattern)
|
| 18 |
+
{
|
| 19 |
+
spec_init(s);
|
| 20 |
+
bool ok = parse_str(pattern, s);
|
| 21 |
+
TEST_ASSERT_TRUE_MESSAGE(ok, "parse_str() failed for pattern");
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
static void free_spec(struct Spec_list *s)
|
| 25 |
+
{
|
| 26 |
+
struct List_element *p = s->head;
|
| 27 |
+
while (p) {
|
| 28 |
+
struct List_element *next = p->next;
|
| 29 |
+
free(p);
|
| 30 |
+
p = next;
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
static uintmax_t count_upper_via_ctype(void)
|
| 35 |
+
{
|
| 36 |
+
uintmax_t n = 0;
|
| 37 |
+
for (int i = 0; i <= UCHAR_MAX; i++) {
|
| 38 |
+
if (isupper(i)) n++;
|
| 39 |
+
}
|
| 40 |
+
return n;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
static uintmax_t count_lower_via_ctype(void)
|
| 44 |
+
{
|
| 45 |
+
uintmax_t n = 0;
|
| 46 |
+
for (int i = 0; i <= UCHAR_MAX; i++) {
|
| 47 |
+
if (islower(i)) n++;
|
| 48 |
+
}
|
| 49 |
+
return n;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
/* Tests */
|
| 53 |
+
|
| 54 |
+
void test_get_spec_stats_simple_chars(void)
|
| 55 |
+
{
|
| 56 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 57 |
+
init_and_parse(&s, "abc");
|
| 58 |
+
|
| 59 |
+
get_spec_stats(&s);
|
| 60 |
+
|
| 61 |
+
TEST_ASSERT_TRUE(s.length == 3);
|
| 62 |
+
TEST_ASSERT_EQUAL_UINT(0, s.n_indefinite_repeats);
|
| 63 |
+
TEST_ASSERT_FALSE(s.has_char_class);
|
| 64 |
+
TEST_ASSERT_FALSE(s.has_restricted_char_class);
|
| 65 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 66 |
+
|
| 67 |
+
free_spec(&s);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
void test_get_spec_stats_range(void)
|
| 71 |
+
{
|
| 72 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 73 |
+
init_and_parse(&s, "a-c");
|
| 74 |
+
|
| 75 |
+
get_spec_stats(&s);
|
| 76 |
+
|
| 77 |
+
TEST_ASSERT_TRUE(s.length == 3);
|
| 78 |
+
TEST_ASSERT_EQUAL_UINT(0, s.n_indefinite_repeats);
|
| 79 |
+
TEST_ASSERT_FALSE(s.has_char_class);
|
| 80 |
+
TEST_ASSERT_FALSE(s.has_restricted_char_class);
|
| 81 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 82 |
+
|
| 83 |
+
free_spec(&s);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
void test_get_spec_stats_digit_class_restricted(void)
|
| 87 |
+
{
|
| 88 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 89 |
+
init_and_parse(&s, "[:digit:]");
|
| 90 |
+
|
| 91 |
+
get_spec_stats(&s);
|
| 92 |
+
|
| 93 |
+
TEST_ASSERT_TRUE(s.length == 10);
|
| 94 |
+
TEST_ASSERT_TRUE(s.has_char_class);
|
| 95 |
+
TEST_ASSERT_TRUE(s.has_restricted_char_class);
|
| 96 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 97 |
+
TEST_ASSERT_EQUAL_UINT(0, s.n_indefinite_repeats);
|
| 98 |
+
|
| 99 |
+
free_spec(&s);
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
void test_get_spec_stats_xdigit_class_length(void)
|
| 103 |
+
{
|
| 104 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 105 |
+
init_and_parse(&s, "[:xdigit:]");
|
| 106 |
+
|
| 107 |
+
get_spec_stats(&s);
|
| 108 |
+
|
| 109 |
+
/* Expect 0-9 (10) + A-F (6) + a-f (6) = 22 in ASCII semantics */
|
| 110 |
+
TEST_ASSERT_TRUE(s.length == 22);
|
| 111 |
+
TEST_ASSERT_TRUE(s.has_char_class);
|
| 112 |
+
TEST_ASSERT_TRUE(s.has_restricted_char_class);
|
| 113 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 114 |
+
|
| 115 |
+
free_spec(&s);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
void test_get_spec_stats_upper_class_unrestricted_and_length_matches_locale(void)
|
| 119 |
+
{
|
| 120 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 121 |
+
init_and_parse(&s, "[:upper:]");
|
| 122 |
+
|
| 123 |
+
get_spec_stats(&s);
|
| 124 |
+
|
| 125 |
+
uintmax_t expected = count_upper_via_ctype();
|
| 126 |
+
TEST_ASSERT_TRUE(s.length == expected);
|
| 127 |
+
TEST_ASSERT_TRUE(s.has_char_class);
|
| 128 |
+
TEST_ASSERT_FALSE(s.has_restricted_char_class);
|
| 129 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 130 |
+
|
| 131 |
+
free_spec(&s);
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
void test_get_spec_stats_equiv_class_singleton(void)
|
| 135 |
+
{
|
| 136 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 137 |
+
init_and_parse(&s, "[=A=]");
|
| 138 |
+
|
| 139 |
+
get_spec_stats(&s);
|
| 140 |
+
|
| 141 |
+
TEST_ASSERT_TRUE(s.length == 1);
|
| 142 |
+
TEST_ASSERT_TRUE(s.has_equiv_class);
|
| 143 |
+
TEST_ASSERT_FALSE(s.has_char_class);
|
| 144 |
+
TEST_ASSERT_FALSE(s.has_restricted_char_class);
|
| 145 |
+
TEST_ASSERT_EQUAL_UINT(0, s.n_indefinite_repeats);
|
| 146 |
+
|
| 147 |
+
free_spec(&s);
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
void test_get_spec_stats_repeated_char_definite_count(void)
|
| 151 |
+
{
|
| 152 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 153 |
+
init_and_parse(&s, "[x*5]");
|
| 154 |
+
|
| 155 |
+
get_spec_stats(&s);
|
| 156 |
+
|
| 157 |
+
TEST_ASSERT_TRUE(s.length == 5);
|
| 158 |
+
TEST_ASSERT_EQUAL_UINT(0, s.n_indefinite_repeats);
|
| 159 |
+
TEST_ASSERT_FALSE(s.has_char_class);
|
| 160 |
+
TEST_ASSERT_FALSE(s.has_restricted_char_class);
|
| 161 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 162 |
+
|
| 163 |
+
free_spec(&s);
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
void test_get_spec_stats_indefinite_repeats_zero_and_empty(void)
|
| 167 |
+
{
|
| 168 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 169 |
+
init_and_parse(&s, "[x*][y*0]a");
|
| 170 |
+
|
| 171 |
+
get_spec_stats(&s);
|
| 172 |
+
|
| 173 |
+
/* [x*] and [y*0] add no length but are both counted; plus 'a' */
|
| 174 |
+
TEST_ASSERT_TRUE(s.length == 1);
|
| 175 |
+
TEST_ASSERT_EQUAL_UINT(2, s.n_indefinite_repeats);
|
| 176 |
+
TEST_ASSERT_FALSE(s.has_char_class);
|
| 177 |
+
TEST_ASSERT_FALSE(s.has_restricted_char_class);
|
| 178 |
+
TEST_ASSERT_FALSE(s.has_equiv_class);
|
| 179 |
+
|
| 180 |
+
free_spec(&s);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
void test_get_spec_stats_mixed_constructs(void)
|
| 184 |
+
{
|
| 185 |
+
struct Spec_list s; memset(&s, 0, sizeof s);
|
| 186 |
+
/* A (1), [=B=] (1), c (1), 0-2 (3), [:digit:] (10), [x*3] (3), [y*] (0) */
|
| 187 |
+
init_and_parse(&s, "A[=B=]c0-2[:digit:][x*3][y*]");
|
| 188 |
+
|
| 189 |
+
get_spec_stats(&s);
|
| 190 |
+
|
| 191 |
+
TEST_ASSERT_TRUE(s.length == (uintmax_t)19);
|
| 192 |
+
TEST_ASSERT_TRUE(s.has_equiv_class);
|
| 193 |
+
TEST_ASSERT_TRUE(s.has_char_class);
|
| 194 |
+
TEST_ASSERT_TRUE(s.has_restricted_char_class);
|
| 195 |
+
TEST_ASSERT_EQUAL_UINT(1, s.n_indefinite_repeats);
|
| 196 |
+
|
| 197 |
+
free_spec(&s);
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
int main(void)
|
| 201 |
+
{
|
| 202 |
+
UNITY_BEGIN();
|
| 203 |
+
RUN_TEST(test_get_spec_stats_simple_chars);
|
| 204 |
+
RUN_TEST(test_get_spec_stats_range);
|
| 205 |
+
RUN_TEST(test_get_spec_stats_digit_class_restricted);
|
| 206 |
+
RUN_TEST(test_get_spec_stats_xdigit_class_length);
|
| 207 |
+
RUN_TEST(test_get_spec_stats_upper_class_unrestricted_and_length_matches_locale);
|
| 208 |
+
RUN_TEST(test_get_spec_stats_equiv_class_singleton);
|
| 209 |
+
RUN_TEST(test_get_spec_stats_repeated_char_definite_count);
|
| 210 |
+
RUN_TEST(test_get_spec_stats_indefinite_repeats_zero_and_empty);
|
| 211 |
+
RUN_TEST(test_get_spec_stats_mixed_constructs);
|
| 212 |
+
return UNITY_END();
|
| 213 |
+
}
|
tests/tr/tests_for_homogeneous_spec_list.c
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdbool.h>
|
| 5 |
+
#include <stdio.h>
|
| 6 |
+
|
| 7 |
+
/* The program source includes this test file after all internal
|
| 8 |
+
definitions, so we can use Spec_list and helper functions directly. */
|
| 9 |
+
|
| 10 |
+
void setUp(void) {
|
| 11 |
+
/* Setup code here, or leave empty */
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
void tearDown(void) {
|
| 15 |
+
/* Cleanup code here, or leave empty */
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
/* Helper to initialize a fresh Spec_list. */
|
| 19 |
+
static void init_list(struct Spec_list *s) {
|
| 20 |
+
spec_init(s);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
void test_homogeneous_spec_list_empty_returns_false(void) {
|
| 24 |
+
struct Spec_list s;
|
| 25 |
+
init_list(&s);
|
| 26 |
+
TEST_ASSERT_FALSE(homogeneous_spec_list(&s));
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
void test_homogeneous_spec_list_single_normal_char_true(void) {
|
| 30 |
+
struct Spec_list s;
|
| 31 |
+
init_list(&s);
|
| 32 |
+
append_normal_char(&s, 'x');
|
| 33 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
void test_homogeneous_spec_list_two_identical_normal_chars_true(void) {
|
| 37 |
+
struct Spec_list s;
|
| 38 |
+
init_list(&s);
|
| 39 |
+
append_normal_char(&s, 'a');
|
| 40 |
+
append_normal_char(&s, 'a');
|
| 41 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
void test_homogeneous_spec_list_two_different_normal_chars_false(void) {
|
| 45 |
+
struct Spec_list s;
|
| 46 |
+
init_list(&s);
|
| 47 |
+
append_normal_char(&s, 'a');
|
| 48 |
+
append_normal_char(&s, 'b');
|
| 49 |
+
TEST_ASSERT_FALSE(homogeneous_spec_list(&s));
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
void test_homogeneous_spec_list_range_same_endpoints_true(void) {
|
| 53 |
+
struct Spec_list s;
|
| 54 |
+
init_list(&s);
|
| 55 |
+
TEST_ASSERT_TRUE_MESSAGE(append_range(&s, 'm', 'm'), "append_range must succeed for same endpoints");
|
| 56 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
void test_homogeneous_spec_list_range_different_endpoints_false(void) {
|
| 60 |
+
struct Spec_list s;
|
| 61 |
+
init_list(&s);
|
| 62 |
+
TEST_ASSERT_TRUE_MESSAGE(append_range(&s, 'a', 'b'), "append_range must succeed for increasing endpoints");
|
| 63 |
+
TEST_ASSERT_FALSE(homogeneous_spec_list(&s));
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
void test_homogeneous_spec_list_repeated_char_positive_count_true(void) {
|
| 67 |
+
struct Spec_list s;
|
| 68 |
+
init_list(&s);
|
| 69 |
+
append_repeated_char(&s, 'z', 5);
|
| 70 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
void test_homogeneous_spec_list_repeated_char_zero_count_only_false(void) {
|
| 74 |
+
struct Spec_list s;
|
| 75 |
+
init_list(&s);
|
| 76 |
+
append_repeated_char(&s, 'q', 0); /* contributes nothing */
|
| 77 |
+
TEST_ASSERT_FALSE(homogeneous_spec_list(&s));
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
void test_homogeneous_spec_list_mixed_all_same_char_true(void) {
|
| 81 |
+
struct Spec_list s;
|
| 82 |
+
init_list(&s);
|
| 83 |
+
/* Sequence expansion will be: 'c', 'c','c','c','c', 'c' */
|
| 84 |
+
TEST_ASSERT_TRUE(append_range(&s, 'c', 'c'));
|
| 85 |
+
append_repeated_char(&s, 'c', 4);
|
| 86 |
+
append_normal_char(&s, 'c');
|
| 87 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
void test_homogeneous_spec_list_zero_repeat_then_single_char_true(void) {
|
| 91 |
+
struct Spec_list s;
|
| 92 |
+
init_list(&s);
|
| 93 |
+
append_repeated_char(&s, 'x', 0); /* no output */
|
| 94 |
+
append_normal_char(&s, 'x'); /* single output */
|
| 95 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
void test_homogeneous_spec_list_char_class_digit_false(void) {
|
| 99 |
+
struct Spec_list s;
|
| 100 |
+
init_list(&s);
|
| 101 |
+
TEST_ASSERT_TRUE_MESSAGE(append_char_class(&s, "digit", 5), "append_char_class 'digit' should succeed");
|
| 102 |
+
TEST_ASSERT_FALSE(homogeneous_spec_list(&s));
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
void test_homogeneous_spec_list_equiv_class_single_char_true(void) {
|
| 106 |
+
struct Spec_list s;
|
| 107 |
+
init_list(&s);
|
| 108 |
+
TEST_ASSERT_TRUE_MESSAGE(append_equiv_class(&s, "Q", 1), "append_equiv_class with single char should succeed");
|
| 109 |
+
TEST_ASSERT_TRUE(homogeneous_spec_list(&s));
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
int main(void) {
|
| 113 |
+
UNITY_BEGIN();
|
| 114 |
+
RUN_TEST(test_homogeneous_spec_list_empty_returns_false);
|
| 115 |
+
RUN_TEST(test_homogeneous_spec_list_single_normal_char_true);
|
| 116 |
+
RUN_TEST(test_homogeneous_spec_list_two_identical_normal_chars_true);
|
| 117 |
+
RUN_TEST(test_homogeneous_spec_list_two_different_normal_chars_false);
|
| 118 |
+
RUN_TEST(test_homogeneous_spec_list_range_same_endpoints_true);
|
| 119 |
+
RUN_TEST(test_homogeneous_spec_list_range_different_endpoints_false);
|
| 120 |
+
RUN_TEST(test_homogeneous_spec_list_repeated_char_positive_count_true);
|
| 121 |
+
RUN_TEST(test_homogeneous_spec_list_repeated_char_zero_count_only_false);
|
| 122 |
+
RUN_TEST(test_homogeneous_spec_list_mixed_all_same_char_true);
|
| 123 |
+
RUN_TEST(test_homogeneous_spec_list_zero_repeat_then_single_char_true);
|
| 124 |
+
RUN_TEST(test_homogeneous_spec_list_char_class_digit_false);
|
| 125 |
+
RUN_TEST(test_homogeneous_spec_list_equiv_class_single_char_true);
|
| 126 |
+
return UNITY_END();
|
| 127 |
+
}
|
tests/tr/tests_for_is_char_class_member.c
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
|
| 3 |
+
#include <stdlib.h>
|
| 4 |
+
#include <stdio.h>
|
| 5 |
+
#include <string.h>
|
| 6 |
+
#include <stdbool.h>
|
| 7 |
+
#include <locale.h>
|
| 8 |
+
#include <ctype.h>
|
| 9 |
+
#include <limits.h>
|
| 10 |
+
|
| 11 |
+
/* Unity hooks */
|
| 12 |
+
void setUp(void) {
|
| 13 |
+
/* Ensure C-locale so standard ctype behaviors are predictable (ASCII). */
|
| 14 |
+
setlocale(LC_ALL, "C");
|
| 15 |
+
}
|
| 16 |
+
void tearDown(void) {
|
| 17 |
+
/* Nothing to clean */
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
/* Reference classifier using the same predicates the target uses. */
|
| 21 |
+
static bool ref_is_member(enum Char_class cls, unsigned char c) {
|
| 22 |
+
switch (cls) {
|
| 23 |
+
case CC_ALNUM: return isalnum(c) != 0;
|
| 24 |
+
case CC_ALPHA: return isalpha(c) != 0;
|
| 25 |
+
case CC_BLANK: return isblank(c) != 0;
|
| 26 |
+
case CC_CNTRL: return iscntrl(c) != 0;
|
| 27 |
+
case CC_DIGIT: return c_isdigit(c) != 0; /* ASCII-digit only */
|
| 28 |
+
case CC_GRAPH: return isgraph(c) != 0;
|
| 29 |
+
case CC_LOWER: return islower(c) != 0;
|
| 30 |
+
case CC_PRINT: return isprint(c) != 0;
|
| 31 |
+
case CC_PUNCT: return ispunct(c) != 0;
|
| 32 |
+
case CC_SPACE: return isspace(c) != 0;
|
| 33 |
+
case CC_UPPER: return isupper(c) != 0;
|
| 34 |
+
case CC_XDIGIT: return c_isxdigit(c) != 0; /* ASCII-hex only */
|
| 35 |
+
default: return false; /* Do not test CC_NO_CLASS here. */
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
/* Basic spot checks per class. */
|
| 40 |
+
void test_is_char_class_member_alpha_basic(void) {
|
| 41 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_ALPHA, 'A'));
|
| 42 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_ALPHA, 'z'));
|
| 43 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_ALPHA, '0'));
|
| 44 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_ALPHA, '_'));
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
void test_is_char_class_member_alnum_basic(void) {
|
| 48 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_ALNUM, 'A'));
|
| 49 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_ALNUM, '0'));
|
| 50 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_ALNUM, ' '));
|
| 51 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_ALNUM, '!'));
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
void test_is_char_class_member_digit_basic(void) {
|
| 55 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_DIGIT, '0'));
|
| 56 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_DIGIT, '5'));
|
| 57 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_DIGIT, '9'));
|
| 58 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_DIGIT, 'a'));
|
| 59 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_DIGIT, '/'));
|
| 60 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_DIGIT, ':'));
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
void test_is_char_class_member_xdigit_basic(void) {
|
| 64 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_XDIGIT, '0'));
|
| 65 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_XDIGIT, '9'));
|
| 66 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_XDIGIT, 'a'));
|
| 67 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_XDIGIT, 'f'));
|
| 68 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_XDIGIT, 'A'));
|
| 69 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_XDIGIT, 'F'));
|
| 70 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_XDIGIT, 'g'));
|
| 71 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_XDIGIT, 'G'));
|
| 72 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_XDIGIT, 'z'));
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
void test_is_char_class_member_lower_upper_basic(void) {
|
| 76 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_LOWER, 'a'));
|
| 77 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_LOWER, 'z'));
|
| 78 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_LOWER, 'A'));
|
| 79 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_LOWER, '0'));
|
| 80 |
+
|
| 81 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_UPPER, 'A'));
|
| 82 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_UPPER, 'Z'));
|
| 83 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_UPPER, 'a'));
|
| 84 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_UPPER, '0'));
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
void test_is_char_class_member_space_blank_basic(void) {
|
| 88 |
+
/* CC_SPACE: any whitespace */
|
| 89 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_SPACE, ' '));
|
| 90 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_SPACE, '\t'));
|
| 91 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_SPACE, '\n'));
|
| 92 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_SPACE, '\r'));
|
| 93 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_SPACE, '\v'));
|
| 94 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_SPACE, '\f'));
|
| 95 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_SPACE, 'A'));
|
| 96 |
+
|
| 97 |
+
/* CC_BLANK: space or horizontal tab only */
|
| 98 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_BLANK, ' '));
|
| 99 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_BLANK, '\t'));
|
| 100 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_BLANK, '\n'));
|
| 101 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_BLANK, 'A'));
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
void test_is_char_class_member_print_graph_punct_basic(void) {
|
| 105 |
+
/* PRINT includes space; GRAPH excludes space */
|
| 106 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_PRINT, ' '));
|
| 107 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_PRINT, 'A'));
|
| 108 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_PRINT, '\n'));
|
| 109 |
+
|
| 110 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_GRAPH, ' '));
|
| 111 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_GRAPH, '!'));
|
| 112 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_GRAPH, 'A'));
|
| 113 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_GRAPH, '\n'));
|
| 114 |
+
|
| 115 |
+
/* PUNCT: printable, not alnum, not space */
|
| 116 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_PUNCT, '!'));
|
| 117 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_PUNCT, '.'));
|
| 118 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_PUNCT, '_'));
|
| 119 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_PUNCT, 'A'));
|
| 120 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_PUNCT, '0'));
|
| 121 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_PUNCT, ' '));
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
void test_is_char_class_member_cntrl_basic(void) {
|
| 125 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_CNTRL, '\0'));
|
| 126 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_CNTRL, '\n'));
|
| 127 |
+
TEST_ASSERT_TRUE(is_char_class_member(CC_CNTRL, '\177')); /* DEL */
|
| 128 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_CNTRL, 'A'));
|
| 129 |
+
TEST_ASSERT_FALSE(is_char_class_member(CC_CNTRL, ' '));
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/* Exhaustive cross-check: for all bytes and all valid classes,
|
| 133 |
+
the function should match the reference behavior. */
|
| 134 |
+
void test_is_char_class_member_exhaustive_matches_reference(void) {
|
| 135 |
+
for (int cls = CC_ALNUM; cls <= CC_XDIGIT; ++cls) {
|
| 136 |
+
enum Char_class ccls = (enum Char_class)cls;
|
| 137 |
+
for (int v = 0; v <= UCHAR_MAX; ++v) {
|
| 138 |
+
unsigned char uc = (unsigned char)v;
|
| 139 |
+
bool got = is_char_class_member(ccls, uc);
|
| 140 |
+
bool exp = ref_is_member(ccls, uc);
|
| 141 |
+
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
| 142 |
+
(int)exp, (int)got, "Mismatch in exhaustive check");
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
int main(void) {
|
| 148 |
+
UNITY_BEGIN();
|
| 149 |
+
RUN_TEST(test_is_char_class_member_alpha_basic);
|
| 150 |
+
RUN_TEST(test_is_char_class_member_alnum_basic);
|
| 151 |
+
RUN_TEST(test_is_char_class_member_digit_basic);
|
| 152 |
+
RUN_TEST(test_is_char_class_member_xdigit_basic);
|
| 153 |
+
RUN_TEST(test_is_char_class_member_lower_upper_basic);
|
| 154 |
+
RUN_TEST(test_is_char_class_member_space_blank_basic);
|
| 155 |
+
RUN_TEST(test_is_char_class_member_print_graph_punct_basic);
|
| 156 |
+
RUN_TEST(test_is_char_class_member_cntrl_basic);
|
| 157 |
+
RUN_TEST(test_is_char_class_member_exhaustive_matches_reference);
|
| 158 |
+
return UNITY_END();
|
| 159 |
+
}
|
tests/tr/tests_for_look_up_char_class.c
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stddef.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdio.h>
|
| 5 |
+
|
| 6 |
+
void setUp(void) {
|
| 7 |
+
/* Setup code here, or leave empty */
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
void tearDown(void) {
|
| 11 |
+
/* Cleanup code here, or leave empty */
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
/* Target: static enum Char_class look_up_char_class (char const *class_str, size_t len) */
|
| 15 |
+
|
| 16 |
+
static void assert_lookup_eq(const char *s, size_t len, enum Char_class expected)
|
| 17 |
+
{
|
| 18 |
+
enum Char_class got = look_up_char_class(s, len);
|
| 19 |
+
TEST_ASSERT_EQUAL_INT((int)expected, (int)got);
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
void test_look_up_char_class_all_valid_exact(void)
|
| 23 |
+
{
|
| 24 |
+
struct { const char *name; enum Char_class cls; } cases[] = {
|
| 25 |
+
{"alnum", CC_ALNUM},
|
| 26 |
+
{"alpha", CC_ALPHA},
|
| 27 |
+
{"blank", CC_BLANK},
|
| 28 |
+
{"cntrl", CC_CNTRL},
|
| 29 |
+
{"digit", CC_DIGIT},
|
| 30 |
+
{"graph", CC_GRAPH},
|
| 31 |
+
{"lower", CC_LOWER},
|
| 32 |
+
{"print", CC_PRINT},
|
| 33 |
+
{"punct", CC_PUNCT},
|
| 34 |
+
{"space", CC_SPACE},
|
| 35 |
+
{"upper", CC_UPPER},
|
| 36 |
+
{"xdigit", CC_XDIGIT},
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
for (size_t i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
|
| 40 |
+
assert_lookup_eq(cases[i].name, strlen(cases[i].name), cases[i].cls);
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
void test_look_up_char_class_case_sensitivity(void)
|
| 45 |
+
{
|
| 46 |
+
/* Upper/lower/capitalized variants should not match */
|
| 47 |
+
assert_lookup_eq("ALPHA", 5, CC_NO_CLASS);
|
| 48 |
+
assert_lookup_eq("Alpha", 5, CC_NO_CLASS);
|
| 49 |
+
assert_lookup_eq("AlPhA", 5, CC_NO_CLASS);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
void test_look_up_char_class_trimmed_len_matches_prefix_only(void)
|
| 53 |
+
{
|
| 54 |
+
/* Provide a longer string but len equal to the class name length. */
|
| 55 |
+
const char *s = "alphabeta"; /* longer than "alpha" */
|
| 56 |
+
assert_lookup_eq(s, 5, CC_ALPHA);
|
| 57 |
+
|
| 58 |
+
const char *s2 = "uppermost"; /* prefix is "upper" */
|
| 59 |
+
assert_lookup_eq(s2, 5, CC_UPPER);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
void test_look_up_char_class_too_short_len_fails(void)
|
| 63 |
+
{
|
| 64 |
+
/* len shorter than actual class name should not match */
|
| 65 |
+
assert_lookup_eq("alpha", 4, CC_NO_CLASS);
|
| 66 |
+
assert_lookup_eq("xdigit", 5, CC_NO_CLASS); /* missing final 't' */
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
void test_look_up_char_class_non_null_terminated_segment(void)
|
| 70 |
+
{
|
| 71 |
+
/* Pass a pointer into a buffer with no terminating NUL at len */
|
| 72 |
+
char buf[] = "zzlowerzz"; /* we want to match "lower" starting at buf+2 */
|
| 73 |
+
assert_lookup_eq(buf + 2, 5, CC_LOWER);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
void test_look_up_char_class_len_zero_fails(void)
|
| 77 |
+
{
|
| 78 |
+
assert_lookup_eq("alpha", 0, CC_NO_CLASS);
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
void test_look_up_char_class_invalid_names_fail(void)
|
| 82 |
+
{
|
| 83 |
+
assert_lookup_eq("foo", 3, CC_NO_CLASS);
|
| 84 |
+
assert_lookup_eq("", 0, CC_NO_CLASS);
|
| 85 |
+
assert_lookup_eq("alnumx", 6, CC_NO_CLASS); /* extra char with full len */
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
int main(void)
|
| 89 |
+
{
|
| 90 |
+
UNITY_BEGIN();
|
| 91 |
+
RUN_TEST(test_look_up_char_class_all_valid_exact);
|
| 92 |
+
RUN_TEST(test_look_up_char_class_case_sensitivity);
|
| 93 |
+
RUN_TEST(test_look_up_char_class_trimmed_len_matches_prefix_only);
|
| 94 |
+
RUN_TEST(test_look_up_char_class_too_short_len_fails);
|
| 95 |
+
RUN_TEST(test_look_up_char_class_non_null_terminated_segment);
|
| 96 |
+
RUN_TEST(test_look_up_char_class_len_zero_fails);
|
| 97 |
+
RUN_TEST(test_look_up_char_class_invalid_names_fail);
|
| 98 |
+
return UNITY_END();
|
| 99 |
+
}
|
tests/tr/tests_for_read_and_delete.c
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <unistd.h>
|
| 3 |
+
#include <fcntl.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <stdlib.h>
|
| 6 |
+
#include <stdint.h>
|
| 7 |
+
#include <stdio.h>
|
| 8 |
+
|
| 9 |
+
/* Access to program internals: in_delete_set and read_and_delete are
|
| 10 |
+
visible since this file is included into the same translation unit. */
|
| 11 |
+
|
| 12 |
+
static int g_saved_stdin = -1;
|
| 13 |
+
|
| 14 |
+
static void reset_delete_set(void) {
|
| 15 |
+
for (size_t i = 0; i < N_CHARS; i++) {
|
| 16 |
+
in_delete_set[i] = false;
|
| 17 |
+
}
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
static void set_delete_byte(unsigned char b) {
|
| 21 |
+
in_delete_set[b] = true;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
/* Replace STDIN with a pipe containing 'data' of length 'len'. */
|
| 25 |
+
static void replace_stdin_with_bytes(const unsigned char *data, size_t len) {
|
| 26 |
+
int fds[2];
|
| 27 |
+
if (pipe(fds) != 0) {
|
| 28 |
+
/* If pipe fails, abort the test */
|
| 29 |
+
TEST_FAIL_MESSAGE("pipe() failed");
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
/* Save original stdin if not yet saved */
|
| 33 |
+
if (g_saved_stdin == -1) {
|
| 34 |
+
g_saved_stdin = dup(STDIN_FILENO);
|
| 35 |
+
TEST_ASSERT_NOT_EQUAL_MESSAGE(-1, g_saved_stdin, "dup(STDIN) failed");
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/* Write all bytes to the write end */
|
| 39 |
+
size_t written = 0;
|
| 40 |
+
while (written < len) {
|
| 41 |
+
ssize_t w = write(fds[1], data + written, len - written);
|
| 42 |
+
TEST_ASSERT_TRUE_MESSAGE(w >= 0, "write() failed");
|
| 43 |
+
written += (size_t)w;
|
| 44 |
+
}
|
| 45 |
+
/* Close writer to signal EOF */
|
| 46 |
+
close(fds[1]);
|
| 47 |
+
|
| 48 |
+
/* Replace stdin */
|
| 49 |
+
TEST_ASSERT_NOT_EQUAL_MESSAGE(-1, dup2(fds[0], STDIN_FILENO), "dup2() failed");
|
| 50 |
+
close(fds[0]);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Replace STDIN with an immediate EOF (empty pipe) */
|
| 54 |
+
static void replace_stdin_with_eof(void) {
|
| 55 |
+
int fds[2];
|
| 56 |
+
if (pipe(fds) != 0) {
|
| 57 |
+
TEST_FAIL_MESSAGE("pipe() failed");
|
| 58 |
+
}
|
| 59 |
+
if (g_saved_stdin == -1) {
|
| 60 |
+
g_saved_stdin = dup(STDIN_FILENO);
|
| 61 |
+
TEST_ASSERT_NOT_EQUAL_MESSAGE(-1, g_saved_stdin, "dup(STDIN) failed");
|
| 62 |
+
}
|
| 63 |
+
/* Close writer immediately to make reader see EOF */
|
| 64 |
+
close(fds[1]);
|
| 65 |
+
TEST_ASSERT_NOT_EQUAL_MESSAGE(-1, dup2(fds[0], STDIN_FILENO), "dup2() failed");
|
| 66 |
+
close(fds[0]);
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
static void assert_buf_equals(const unsigned char *buf, size_t n,
|
| 70 |
+
const unsigned char *expected, size_t m) {
|
| 71 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)m, (uint64_t)n);
|
| 72 |
+
for (size_t i = 0; i < m; i++) {
|
| 73 |
+
if (buf[i] != expected[i]) {
|
| 74 |
+
char msg[128];
|
| 75 |
+
snprintf(msg, sizeof msg, "byte mismatch at index %zu", i);
|
| 76 |
+
TEST_FAIL_MESSAGE(msg);
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
void setUp(void) {
|
| 82 |
+
/* Ensure a clean delete set and save stdin for restoration */
|
| 83 |
+
reset_delete_set();
|
| 84 |
+
if (g_saved_stdin == -1) {
|
| 85 |
+
g_saved_stdin = dup(STDIN_FILENO);
|
| 86 |
+
TEST_ASSERT_NOT_EQUAL_MESSAGE(-1, g_saved_stdin, "dup(STDIN) in setUp failed");
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
void tearDown(void) {
|
| 91 |
+
/* Restore original stdin if changed */
|
| 92 |
+
if (g_saved_stdin != -1) {
|
| 93 |
+
int r = dup2(g_saved_stdin, STDIN_FILENO);
|
| 94 |
+
TEST_ASSERT_NOT_EQUAL_MESSAGE(-1, r, "dup2 restore in tearDown failed");
|
| 95 |
+
close(g_saved_stdin);
|
| 96 |
+
g_saved_stdin = -1;
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
/* 1) No deletions: should return all input unchanged */
|
| 101 |
+
static void test_read_and_delete_no_deletion_returns_all(void) {
|
| 102 |
+
const unsigned char input[] = { 'a','b','c' };
|
| 103 |
+
replace_stdin_with_bytes(input, sizeof input);
|
| 104 |
+
|
| 105 |
+
unsigned char buf[16];
|
| 106 |
+
size_t n = read_and_delete((char*)buf, sizeof buf);
|
| 107 |
+
|
| 108 |
+
const unsigned char exp[] = { 'a','b','c' };
|
| 109 |
+
assert_buf_equals(buf, n, exp, sizeof exp);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
/* 2) Delete specific characters in the middle and scattered */
|
| 113 |
+
static void test_read_and_delete_deletes_specific_characters(void) {
|
| 114 |
+
reset_delete_set();
|
| 115 |
+
set_delete_byte((unsigned char)'b');
|
| 116 |
+
set_delete_byte((unsigned char)'x');
|
| 117 |
+
const unsigned char input[] = { 'a','b','b','b','x','c' }; /* -> "ac" */
|
| 118 |
+
replace_stdin_with_bytes(input, sizeof input);
|
| 119 |
+
|
| 120 |
+
unsigned char buf[16];
|
| 121 |
+
size_t n = read_and_delete((char*)buf, sizeof buf);
|
| 122 |
+
|
| 123 |
+
const unsigned char exp[] = { 'a','c' };
|
| 124 |
+
assert_buf_equals(buf, n, exp, sizeof exp);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
/* 3) Deletions at the start of buffer */
|
| 128 |
+
static void test_read_and_delete_deletes_at_start(void) {
|
| 129 |
+
reset_delete_set();
|
| 130 |
+
set_delete_byte((unsigned char)'b');
|
| 131 |
+
const unsigned char input[] = { 'b','b','a','b','c' }; /* -> "ac"? Actually 'b's deleted => "ac" */
|
| 132 |
+
replace_stdin_with_bytes(input, sizeof input);
|
| 133 |
+
|
| 134 |
+
unsigned char buf[16];
|
| 135 |
+
size_t n = read_and_delete((char*)buf, sizeof buf);
|
| 136 |
+
|
| 137 |
+
const unsigned char exp[] = { 'a','c' };
|
| 138 |
+
assert_buf_equals(buf, n, exp, sizeof exp);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
/* 4) First read yields only deletions (n_saved==0), then next read yields data */
|
| 142 |
+
static void test_read_and_delete_handles_two_reads_when_first_has_only_deletes(void) {
|
| 143 |
+
reset_delete_set();
|
| 144 |
+
set_delete_byte((unsigned char)'x');
|
| 145 |
+
const unsigned char input[] = { 'x','x','x','a','b','c' }; /* size=3 ensures 2 reads: "xxx" then "abc" */
|
| 146 |
+
replace_stdin_with_bytes(input, sizeof input);
|
| 147 |
+
|
| 148 |
+
unsigned char buf[3];
|
| 149 |
+
size_t n = read_and_delete((char*)buf, sizeof buf); /* size=3 */
|
| 150 |
+
|
| 151 |
+
const unsigned char exp[] = { 'a','b','c' };
|
| 152 |
+
assert_buf_equals(buf, n, exp, sizeof exp);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
/* 5) All bytes deleted followed by EOF should return 0 */
|
| 156 |
+
static void test_read_and_delete_returns_zero_when_all_deleted_and_eof(void) {
|
| 157 |
+
reset_delete_set();
|
| 158 |
+
set_delete_byte((unsigned char)'x');
|
| 159 |
+
const unsigned char input[] = { 'x','x','x' }; /* all deleted */
|
| 160 |
+
replace_stdin_with_bytes(input, sizeof input);
|
| 161 |
+
|
| 162 |
+
unsigned char buf[8];
|
| 163 |
+
size_t n = read_and_delete((char*)buf, sizeof buf);
|
| 164 |
+
|
| 165 |
+
TEST_ASSERT_EQUAL_UINT64(0, (uint64_t)n);
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
/* 6) Immediate EOF should return 0 */
|
| 169 |
+
static void test_read_and_delete_returns_zero_on_immediate_eof(void) {
|
| 170 |
+
replace_stdin_with_eof();
|
| 171 |
+
unsigned char buf[8];
|
| 172 |
+
size_t n = read_and_delete((char*)buf, sizeof buf);
|
| 173 |
+
TEST_ASSERT_EQUAL_UINT64(0, (uint64_t)n);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
/* 7) Ensure NUL bytes are preserved if not deleted and deletions elsewhere apply */
|
| 177 |
+
static void test_read_and_delete_preserves_nul_bytes(void) {
|
| 178 |
+
reset_delete_set();
|
| 179 |
+
set_delete_byte((unsigned char)'A');
|
| 180 |
+
const unsigned char input[] = { 0x00, 'A', 0x00 };
|
| 181 |
+
replace_stdin_with_bytes(input, sizeof input);
|
| 182 |
+
|
| 183 |
+
unsigned char buf[8];
|
| 184 |
+
size_t n = read_and_delete((char*)buf, sizeof buf);
|
| 185 |
+
|
| 186 |
+
const unsigned char exp[] = { 0x00, 0x00 };
|
| 187 |
+
assert_buf_equals(buf, n, exp, sizeof exp);
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
int main(void) {
|
| 191 |
+
UNITY_BEGIN();
|
| 192 |
+
RUN_TEST(test_read_and_delete_no_deletion_returns_all);
|
| 193 |
+
RUN_TEST(test_read_and_delete_deletes_specific_characters);
|
| 194 |
+
RUN_TEST(test_read_and_delete_deletes_at_start);
|
| 195 |
+
RUN_TEST(test_read_and_delete_handles_two_reads_when_first_has_only_deletes);
|
| 196 |
+
RUN_TEST(test_read_and_delete_returns_zero_when_all_deleted_and_eof);
|
| 197 |
+
RUN_TEST(test_read_and_delete_returns_zero_on_immediate_eof);
|
| 198 |
+
RUN_TEST(test_read_and_delete_preserves_nul_bytes);
|
| 199 |
+
return UNITY_END();
|
| 200 |
+
}
|
tests/tr/tests_for_set_initialize.c
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdbool.h>
|
| 3 |
+
#include <stddef.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <stdio.h>
|
| 6 |
+
|
| 7 |
+
/* The test file is included into the tr source after all internal
|
| 8 |
+
declarations, so we can use the program's internal symbols directly. */
|
| 9 |
+
|
| 10 |
+
static size_t count_true(const bool *arr)
|
| 11 |
+
{
|
| 12 |
+
size_t c = 0;
|
| 13 |
+
for (size_t i = 0; i < N_CHARS; i++)
|
| 14 |
+
if (arr[i]) c++;
|
| 15 |
+
return c;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
static void clear_bool_array(bool *arr)
|
| 19 |
+
{
|
| 20 |
+
memset(arr, 0, N_CHARS * sizeof(bool));
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
static void build_spec(const char *s, struct Spec_list *out)
|
| 24 |
+
{
|
| 25 |
+
spec_init(out);
|
| 26 |
+
bool ok = parse_str(s, out);
|
| 27 |
+
TEST_ASSERT_TRUE_MESSAGE(ok, "parse_str failed for input spec");
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
void setUp(void) {
|
| 31 |
+
/* no-op */
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
void tearDown(void) {
|
| 35 |
+
/* no-op */
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/* 1) Simple normal characters */
|
| 39 |
+
void test_set_initialize_single_chars(void)
|
| 40 |
+
{
|
| 41 |
+
struct Spec_list sp;
|
| 42 |
+
bool in_set[N_CHARS];
|
| 43 |
+
build_spec("ABC", &sp);
|
| 44 |
+
clear_bool_array(in_set);
|
| 45 |
+
|
| 46 |
+
set_initialize(&sp, false, in_set);
|
| 47 |
+
|
| 48 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'A']);
|
| 49 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'B']);
|
| 50 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'C']);
|
| 51 |
+
TEST_ASSERT_EQUAL_size_t(3u, count_true(in_set));
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
/* 2) Range a-d => a,b,c,d */
|
| 55 |
+
void test_set_initialize_range(void)
|
| 56 |
+
{
|
| 57 |
+
struct Spec_list sp;
|
| 58 |
+
bool in_set[N_CHARS];
|
| 59 |
+
build_spec("a-d", &sp);
|
| 60 |
+
clear_bool_array(in_set);
|
| 61 |
+
|
| 62 |
+
set_initialize(&sp, false, in_set);
|
| 63 |
+
|
| 64 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'a']);
|
| 65 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'b']);
|
| 66 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'c']);
|
| 67 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'d']);
|
| 68 |
+
TEST_ASSERT_EQUAL_size_t(4u, count_true(in_set));
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* 3) Character class [:digit:] => '0'..'9' */
|
| 72 |
+
void test_set_initialize_char_class_digit(void)
|
| 73 |
+
{
|
| 74 |
+
struct Spec_list sp;
|
| 75 |
+
bool in_set[N_CHARS];
|
| 76 |
+
build_spec("[[:digit:]]", &sp);
|
| 77 |
+
clear_bool_array(in_set);
|
| 78 |
+
|
| 79 |
+
set_initialize(&sp, false, in_set);
|
| 80 |
+
|
| 81 |
+
for (int i = 0; i <= 9; i++)
|
| 82 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)('0' + i)]);
|
| 83 |
+
TEST_ASSERT_FALSE(in_set[(unsigned char)'a']);
|
| 84 |
+
TEST_ASSERT_EQUAL_size_t(10u, count_true(in_set));
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
/* 4) Repeated character [x*5] => just 'x' is a member */
|
| 88 |
+
void test_set_initialize_repeated_char_n(void)
|
| 89 |
+
{
|
| 90 |
+
struct Spec_list sp;
|
| 91 |
+
bool in_set[N_CHARS];
|
| 92 |
+
build_spec("[x*5]", &sp);
|
| 93 |
+
clear_bool_array(in_set);
|
| 94 |
+
|
| 95 |
+
set_initialize(&sp, false, in_set);
|
| 96 |
+
|
| 97 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'x']);
|
| 98 |
+
TEST_ASSERT_EQUAL_size_t(1u, count_true(in_set));
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
/* 5) Indefinite repeat [q*] should contribute no members */
|
| 102 |
+
void test_set_initialize_indefinite_repeat_zero_effect(void)
|
| 103 |
+
{
|
| 104 |
+
struct Spec_list sp;
|
| 105 |
+
bool in_set[N_CHARS];
|
| 106 |
+
build_spec("A[q*]B", &sp);
|
| 107 |
+
clear_bool_array(in_set);
|
| 108 |
+
|
| 109 |
+
set_initialize(&sp, false, in_set);
|
| 110 |
+
|
| 111 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'A']);
|
| 112 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'B']);
|
| 113 |
+
TEST_ASSERT_FALSE(in_set[(unsigned char)'q']);
|
| 114 |
+
TEST_ASSERT_EQUAL_size_t(2u, count_true(in_set));
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
/* 6) Equivalence class [=m=] => behaves like 'm' in this implementation */
|
| 118 |
+
void test_set_initialize_equiv_class_single_char(void)
|
| 119 |
+
{
|
| 120 |
+
struct Spec_list sp;
|
| 121 |
+
bool in_set[N_CHARS];
|
| 122 |
+
build_spec("[=m=]", &sp);
|
| 123 |
+
clear_bool_array(in_set);
|
| 124 |
+
|
| 125 |
+
set_initialize(&sp, false, in_set);
|
| 126 |
+
|
| 127 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'m']);
|
| 128 |
+
TEST_ASSERT_EQUAL_size_t(1u, count_true(in_set));
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
/* 7) Complement behavior: complement of {'a'} => all except 'a' */
|
| 132 |
+
void test_set_initialize_complement_simple(void)
|
| 133 |
+
{
|
| 134 |
+
struct Spec_list sp;
|
| 135 |
+
bool in_set[N_CHARS];
|
| 136 |
+
build_spec("a", &sp);
|
| 137 |
+
clear_bool_array(in_set);
|
| 138 |
+
|
| 139 |
+
set_initialize(&sp, true, in_set);
|
| 140 |
+
|
| 141 |
+
TEST_ASSERT_FALSE(in_set[(unsigned char)'a']);
|
| 142 |
+
/* Count should be N_CHARS - 1 */
|
| 143 |
+
TEST_ASSERT_EQUAL_size_t((size_t)N_CHARS - 1, count_true(in_set));
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
/* 8) Composite spec: a-c, digits, Z, [=x=], [y*3], [q*] (no effect) */
|
| 147 |
+
void test_set_initialize_composite_union(void)
|
| 148 |
+
{
|
| 149 |
+
struct Spec_list sp;
|
| 150 |
+
bool in_set[N_CHARS];
|
| 151 |
+
build_spec("a-c[[:digit:]]Z[=x=][y*3][q*]", &sp);
|
| 152 |
+
clear_bool_array(in_set);
|
| 153 |
+
|
| 154 |
+
set_initialize(&sp, false, in_set);
|
| 155 |
+
|
| 156 |
+
/* Range a-c */
|
| 157 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'a']);
|
| 158 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'b']);
|
| 159 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'c']);
|
| 160 |
+
/* Digits */
|
| 161 |
+
for (int i = 0; i <= 9; i++)
|
| 162 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)('0' + i)]);
|
| 163 |
+
/* Z */
|
| 164 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'Z']);
|
| 165 |
+
/* [=x=] */
|
| 166 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'x']);
|
| 167 |
+
/* [y*3] */
|
| 168 |
+
TEST_ASSERT_TRUE(in_set[(unsigned char)'y']);
|
| 169 |
+
/* [q*] has no effect */
|
| 170 |
+
TEST_ASSERT_FALSE(in_set[(unsigned char)'q']);
|
| 171 |
+
|
| 172 |
+
/* Total expected: 3 (a-c) + 10 (digits) + 1 (Z) + 1 (x) + 1 (y) = 16 */
|
| 173 |
+
TEST_ASSERT_EQUAL_size_t(16u, count_true(in_set));
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
int main(void)
|
| 177 |
+
{
|
| 178 |
+
UNITY_BEGIN();
|
| 179 |
+
RUN_TEST(test_set_initialize_single_chars);
|
| 180 |
+
RUN_TEST(test_set_initialize_range);
|
| 181 |
+
RUN_TEST(test_set_initialize_char_class_digit);
|
| 182 |
+
RUN_TEST(test_set_initialize_repeated_char_n);
|
| 183 |
+
RUN_TEST(test_set_initialize_indefinite_repeat_zero_effect);
|
| 184 |
+
RUN_TEST(test_set_initialize_equiv_class_single_char);
|
| 185 |
+
RUN_TEST(test_set_initialize_complement_simple);
|
| 186 |
+
RUN_TEST(test_set_initialize_composite_union);
|
| 187 |
+
return UNITY_END();
|
| 188 |
+
}
|
tests/tr/tests_for_squeeze_filter.c
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdio.h>
|
| 3 |
+
#include <stdlib.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <unistd.h>
|
| 6 |
+
#include <limits.h>
|
| 7 |
+
#include <errno.h>
|
| 8 |
+
#include <stdbool.h>
|
| 9 |
+
|
| 10 |
+
/* We are included into the tr.c translation unit, so we can access:
|
| 11 |
+
- static void squeeze_filter(char *buf, size_t size, size_t (*reader)(char*, size_t))
|
| 12 |
+
- static bool in_squeeze_set[N_CHARS];
|
| 13 |
+
- N_CHARS constant
|
| 14 |
+
*/
|
| 15 |
+
|
| 16 |
+
/* ------------------------ Test Harness Helpers ------------------------ */
|
| 17 |
+
|
| 18 |
+
/* Reader context (globals local to this test file, to avoid passing ctx) */
|
| 19 |
+
static const unsigned char *t_in_data = NULL;
|
| 20 |
+
static size_t t_in_len = 0;
|
| 21 |
+
static size_t t_in_pos = 0;
|
| 22 |
+
static size_t t_reader_chunk = 0; /* max bytes returned per reader call */
|
| 23 |
+
|
| 24 |
+
/* Reader implementation: returns up to min(size, t_reader_chunk, remaining) */
|
| 25 |
+
static size_t test_reader_fixed_chunks(char *buf, size_t size)
|
| 26 |
+
{
|
| 27 |
+
if (t_in_pos >= t_in_len)
|
| 28 |
+
return 0;
|
| 29 |
+
size_t remaining = t_in_len - t_in_pos;
|
| 30 |
+
size_t n = remaining;
|
| 31 |
+
if (t_reader_chunk > 0 && n > t_reader_chunk)
|
| 32 |
+
n = t_reader_chunk;
|
| 33 |
+
if (n > size)
|
| 34 |
+
n = size;
|
| 35 |
+
memcpy(buf, t_in_data + t_in_pos, n);
|
| 36 |
+
t_in_pos += n;
|
| 37 |
+
return n;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
/* Clear and set the squeeze set */
|
| 41 |
+
static void clear_squeeze_set(void)
|
| 42 |
+
{
|
| 43 |
+
/* in_squeeze_set is defined in tr.c */
|
| 44 |
+
for (size_t i = 0; i < N_CHARS; i++)
|
| 45 |
+
in_squeeze_set[i] = false;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
static void set_squeeze_chars(const unsigned char *chars, size_t n)
|
| 49 |
+
{
|
| 50 |
+
clear_squeeze_set();
|
| 51 |
+
for (size_t i = 0; i < n; i++)
|
| 52 |
+
in_squeeze_set[chars[i]] = true;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
/* Capture stdout produced by squeeze_filter into a buffer we return. */
|
| 56 |
+
struct Captured {
|
| 57 |
+
char *data;
|
| 58 |
+
size_t len;
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
static struct Captured run_and_capture(const unsigned char *input, size_t in_len,
|
| 62 |
+
size_t reader_chunk, size_t squeeze_buf_size)
|
| 63 |
+
{
|
| 64 |
+
struct Captured cap = { NULL, 0 };
|
| 65 |
+
|
| 66 |
+
/* Prepare temp file for capturing stdout */
|
| 67 |
+
FILE *tmpf = tmpfile();
|
| 68 |
+
if (!tmpf) {
|
| 69 |
+
TEST_FAIL_MESSAGE("tmpfile() failed; cannot capture stdout");
|
| 70 |
+
}
|
| 71 |
+
int tmpfd = fileno(tmpf);
|
| 72 |
+
|
| 73 |
+
/* Save and redirect stdout */
|
| 74 |
+
fflush(stdout);
|
| 75 |
+
int saved_stdout = dup(STDOUT_FILENO);
|
| 76 |
+
if (saved_stdout < 0) {
|
| 77 |
+
fclose(tmpf);
|
| 78 |
+
TEST_FAIL_MESSAGE("dup(STDOUT_FILENO) failed");
|
| 79 |
+
}
|
| 80 |
+
if (dup2(tmpfd, STDOUT_FILENO) < 0) {
|
| 81 |
+
int errsv = errno;
|
| 82 |
+
dup2(saved_stdout, STDOUT_FILENO);
|
| 83 |
+
close(saved_stdout);
|
| 84 |
+
fclose(tmpf);
|
| 85 |
+
(void)errsv; /* avoid unused warning */
|
| 86 |
+
TEST_FAIL_MESSAGE("dup2(tmpfd, STDOUT_FILENO) failed");
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
/* Setup reader ctx */
|
| 90 |
+
t_in_data = input;
|
| 91 |
+
t_in_len = in_len;
|
| 92 |
+
t_in_pos = 0;
|
| 93 |
+
t_reader_chunk = reader_chunk;
|
| 94 |
+
|
| 95 |
+
/* Run the function under test */
|
| 96 |
+
char *work_buf = (char *)malloc(squeeze_buf_size > 0 ? squeeze_buf_size : 1);
|
| 97 |
+
if (!work_buf) {
|
| 98 |
+
/* Restore stdout before failing */
|
| 99 |
+
fflush(stdout);
|
| 100 |
+
dup2(saved_stdout, STDOUT_FILENO);
|
| 101 |
+
close(saved_stdout);
|
| 102 |
+
fclose(tmpf);
|
| 103 |
+
TEST_FAIL_MESSAGE("malloc failed");
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
squeeze_filter(work_buf, squeeze_buf_size, test_reader_fixed_chunks);
|
| 107 |
+
|
| 108 |
+
free(work_buf);
|
| 109 |
+
|
| 110 |
+
/* Restore stdout */
|
| 111 |
+
fflush(stdout);
|
| 112 |
+
if (dup2(saved_stdout, STDOUT_FILENO) < 0) {
|
| 113 |
+
close(saved_stdout);
|
| 114 |
+
fclose(tmpf);
|
| 115 |
+
TEST_FAIL_MESSAGE("dup2(restore stdout) failed");
|
| 116 |
+
}
|
| 117 |
+
close(saved_stdout);
|
| 118 |
+
|
| 119 |
+
/* Read back captured output */
|
| 120 |
+
if (fseek(tmpf, 0, SEEK_END) != 0) {
|
| 121 |
+
fclose(tmpf);
|
| 122 |
+
TEST_FAIL_MESSAGE("fseek end failed");
|
| 123 |
+
}
|
| 124 |
+
long sz = ftell(tmpf);
|
| 125 |
+
if (sz < 0) {
|
| 126 |
+
fclose(tmpf);
|
| 127 |
+
TEST_FAIL_MESSAGE("ftell failed");
|
| 128 |
+
}
|
| 129 |
+
if (fseek(tmpf, 0, SEEK_SET) != 0) {
|
| 130 |
+
fclose(tmpf);
|
| 131 |
+
TEST_FAIL_MESSAGE("fseek set failed");
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
cap.len = (size_t)sz;
|
| 135 |
+
cap.data = (char *)malloc(cap.len ? cap.len : 1);
|
| 136 |
+
if (!cap.data) {
|
| 137 |
+
fclose(tmpf);
|
| 138 |
+
TEST_FAIL_MESSAGE("malloc for captured output failed");
|
| 139 |
+
}
|
| 140 |
+
size_t nread = fread(cap.data, 1, cap.len, tmpf);
|
| 141 |
+
fclose(tmpf);
|
| 142 |
+
if (nread != cap.len) {
|
| 143 |
+
free(cap.data);
|
| 144 |
+
cap.data = NULL;
|
| 145 |
+
cap.len = 0;
|
| 146 |
+
TEST_FAIL_MESSAGE("fread captured output failed");
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
return cap;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
/* ------------------------ Unity Setup/Teardown ------------------------ */
|
| 153 |
+
|
| 154 |
+
void setUp(void) {
|
| 155 |
+
/* Reset the squeeze set before each test */
|
| 156 |
+
clear_squeeze_set();
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
void tearDown(void) {
|
| 160 |
+
/* Nothing to cleanup */
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
/* ------------------------------ Tests -------------------------------- */
|
| 164 |
+
|
| 165 |
+
/* No characters in squeeze set: output must equal input */
|
| 166 |
+
void test_squeeze_filter_no_squeeze_set_identity(void)
|
| 167 |
+
{
|
| 168 |
+
const char *in = "abcabc";
|
| 169 |
+
/* No squeeze chars set */
|
| 170 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 171 |
+
4 /*reader chunk*/, 64 /*buf size*/);
|
| 172 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(in), cap.len);
|
| 173 |
+
TEST_ASSERT_EQUAL_MEMORY(in, cap.data, cap.len);
|
| 174 |
+
free(cap.data);
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
/* Squeeze runs of a single character inside one buffer */
|
| 178 |
+
void test_squeeze_filter_single_char(void)
|
| 179 |
+
{
|
| 180 |
+
const char *in = "aaabaaa";
|
| 181 |
+
const char *expected = "aba";
|
| 182 |
+
const unsigned char squeeze_chars[] = { (unsigned char)'a' };
|
| 183 |
+
set_squeeze_chars(squeeze_chars, 1);
|
| 184 |
+
|
| 185 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 186 |
+
64, 128);
|
| 187 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(expected), cap.len);
|
| 188 |
+
TEST_ASSERT_EQUAL_MEMORY(expected, cap.data, cap.len);
|
| 189 |
+
free(cap.data);
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
/* Squeeze runs of multiple different characters; other chars preserved */
|
| 193 |
+
void test_squeeze_filter_multiple_chars(void)
|
| 194 |
+
{
|
| 195 |
+
const char *in = "aaabbbccbaaa"; /* runs of a & b; cc should remain */
|
| 196 |
+
const char *expected = "abccba";
|
| 197 |
+
const unsigned char squeeze_chars[] = { (unsigned char)'a', (unsigned char)'b' };
|
| 198 |
+
set_squeeze_chars(squeeze_chars, 2);
|
| 199 |
+
|
| 200 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 201 |
+
64, 128);
|
| 202 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(expected), cap.len);
|
| 203 |
+
TEST_ASSERT_EQUAL_MEMORY(expected, cap.data, cap.len);
|
| 204 |
+
free(cap.data);
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
/* Boundary case: last byte of a buffer is in squeeze set and the run continues
|
| 208 |
+
in the next buffer. Ensure only a single occurrence is output across boundary. */
|
| 209 |
+
void test_squeeze_filter_cross_boundary_run_continues(void)
|
| 210 |
+
{
|
| 211 |
+
const char *in = "abbb"; /* 'b' squeezed, boundary after "ab" */
|
| 212 |
+
const char *expected = "ab";
|
| 213 |
+
const unsigned char squeeze_chars[] = { (unsigned char)'b' };
|
| 214 |
+
set_squeeze_chars(squeeze_chars, 1);
|
| 215 |
+
|
| 216 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 217 |
+
2 /*reader chunk to split after 'ab'*/, 64);
|
| 218 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(expected), cap.len);
|
| 219 |
+
TEST_ASSERT_EQUAL_MEMORY(expected, cap.data, cap.len);
|
| 220 |
+
free(cap.data);
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
/* All bytes are squeezable and come in many small buffers: should yield one byte */
|
| 224 |
+
void test_squeeze_filter_all_squeezed_across_many_buffers(void)
|
| 225 |
+
{
|
| 226 |
+
const char *in = "xxxx";
|
| 227 |
+
const char *expected = "x";
|
| 228 |
+
const unsigned char squeeze_chars[] = { (unsigned char)'x' };
|
| 229 |
+
set_squeeze_chars(squeeze_chars, 1);
|
| 230 |
+
|
| 231 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 232 |
+
1 /*one byte per read*/, 16);
|
| 233 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(expected), cap.len);
|
| 234 |
+
TEST_ASSERT_EQUAL_MEMORY(expected, cap.data, cap.len);
|
| 235 |
+
free(cap.data);
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
/* Repeats of non-squeezable characters must be preserved */
|
| 239 |
+
void test_squeeze_filter_non_squeezable_repeats_preserved(void)
|
| 240 |
+
{
|
| 241 |
+
const char *in = "bbbbbbb"; /* 'b' not squeezed */
|
| 242 |
+
const unsigned char squeeze_chars[] = { (unsigned char)'a' };
|
| 243 |
+
set_squeeze_chars(squeeze_chars, 1);
|
| 244 |
+
|
| 245 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 246 |
+
3 /*chunk*/, 32);
|
| 247 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(in), cap.len);
|
| 248 |
+
TEST_ASSERT_EQUAL_MEMORY(in, cap.data, cap.len);
|
| 249 |
+
free(cap.data);
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
/* Non-ASCII byte handling: squeezing byte 0x80 across boundary */
|
| 253 |
+
void test_squeeze_filter_non_ascii_byte(void)
|
| 254 |
+
{
|
| 255 |
+
unsigned char in[] = { 0x80, 0x80, 'a', 0x80 };
|
| 256 |
+
unsigned char expected[] = { 0x80, 'a', 0x80 };
|
| 257 |
+
unsigned char squeeze_chars[] = { 0x80 };
|
| 258 |
+
set_squeeze_chars(squeeze_chars, 1);
|
| 259 |
+
|
| 260 |
+
struct Captured cap = run_and_capture(in, sizeof(in),
|
| 261 |
+
2 /*chunk to split after first two bytes*/, 32);
|
| 262 |
+
TEST_ASSERT_EQUAL_UINT64(sizeof(expected), cap.len);
|
| 263 |
+
TEST_ASSERT_EQUAL_MEMORY(expected, cap.data, cap.len);
|
| 264 |
+
free(cap.data);
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
/* Alternating runs with multiple squeezable chars across boundaries */
|
| 268 |
+
void test_squeeze_filter_multiple_runs_across_boundaries(void)
|
| 269 |
+
{
|
| 270 |
+
const char *in = "aaabbbcccaaabbb";
|
| 271 |
+
const char *expected = "abcccab"; /* 'a' and 'b' squeezed; 'c' preserved */
|
| 272 |
+
const unsigned char squeeze_chars[] = { (unsigned char)'a', (unsigned char)'b' };
|
| 273 |
+
set_squeeze_chars(squeeze_chars, 2);
|
| 274 |
+
|
| 275 |
+
/* Choose small reader chunk to force multiple boundaries */
|
| 276 |
+
struct Captured cap = run_and_capture((const unsigned char*)in, strlen(in),
|
| 277 |
+
3, 64);
|
| 278 |
+
TEST_ASSERT_EQUAL_UINT64(strlen(expected), cap.len);
|
| 279 |
+
TEST_ASSERT_EQUAL_MEMORY(expected, cap.data, cap.len);
|
| 280 |
+
free(cap.data);
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
/* ------------------------------ main --------------------------------- */
|
| 284 |
+
|
| 285 |
+
int main(void)
|
| 286 |
+
{
|
| 287 |
+
UNITY_BEGIN();
|
| 288 |
+
RUN_TEST(test_squeeze_filter_no_squeeze_set_identity);
|
| 289 |
+
RUN_TEST(test_squeeze_filter_single_char);
|
| 290 |
+
RUN_TEST(test_squeeze_filter_multiple_chars);
|
| 291 |
+
RUN_TEST(test_squeeze_filter_cross_boundary_run_continues);
|
| 292 |
+
RUN_TEST(test_squeeze_filter_all_squeezed_across_many_buffers);
|
| 293 |
+
RUN_TEST(test_squeeze_filter_non_squeezable_repeats_preserved);
|
| 294 |
+
RUN_TEST(test_squeeze_filter_non_ascii_byte);
|
| 295 |
+
RUN_TEST(test_squeeze_filter_multiple_runs_across_boundaries);
|
| 296 |
+
return UNITY_END();
|
| 297 |
+
}
|
tests/tr/tests_for_star_digits_closebracket.c
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdbool.h>
|
| 5 |
+
#include <stddef.h>
|
| 6 |
+
|
| 7 |
+
/* Helper to initialize an E_string from a C string literal. */
|
| 8 |
+
static void es_init_from_cstr(struct E_string *es, const char *lit)
|
| 9 |
+
{
|
| 10 |
+
size_t len = strlen(lit);
|
| 11 |
+
es->len = len;
|
| 12 |
+
es->s = (char*)malloc(len);
|
| 13 |
+
es->escaped = (bool*)calloc(len, sizeof(bool));
|
| 14 |
+
memcpy(es->s, lit, len);
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Helper to free E_string allocated by es_init_from_cstr. */
|
| 18 |
+
static void es_free_local(struct E_string *es)
|
| 19 |
+
{
|
| 20 |
+
free(es->s);
|
| 21 |
+
free(es->escaped);
|
| 22 |
+
es->s = NULL;
|
| 23 |
+
es->escaped = NULL;
|
| 24 |
+
es->len = 0;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
void setUp(void) {
|
| 28 |
+
/* Setup code here, or leave empty */
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
void tearDown(void) {
|
| 32 |
+
/* Cleanup code here, or leave empty */
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
/* 1) Basic true: "*]" starting at index 0 */
|
| 36 |
+
void test_star_digits_closebracket_basic_true_empty_digits(void)
|
| 37 |
+
{
|
| 38 |
+
struct E_string es; es_init_from_cstr(&es, "*]");
|
| 39 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 40 |
+
TEST_ASSERT_TRUE(got);
|
| 41 |
+
es_free_local(&es);
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/* 2) True with digits: "*123]" */
|
| 45 |
+
void test_star_digits_closebracket_true_with_digits(void)
|
| 46 |
+
{
|
| 47 |
+
struct E_string es; es_init_from_cstr(&es, "*123]");
|
| 48 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 49 |
+
TEST_ASSERT_TRUE(got);
|
| 50 |
+
es_free_local(&es);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* 3) True when pattern starts mid-string: "abc*456]xyz" at index 3 */
|
| 54 |
+
void test_star_digits_closebracket_true_mid_string_start_index(void)
|
| 55 |
+
{
|
| 56 |
+
struct E_string es; es_init_from_cstr(&es, "abc*456]xyz");
|
| 57 |
+
bool got = star_digits_closebracket(&es, 3);
|
| 58 |
+
TEST_ASSERT_TRUE(got);
|
| 59 |
+
es_free_local(&es);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/* 4) False: starting character is not '*' */
|
| 63 |
+
void test_star_digits_closebracket_false_starts_not_star(void)
|
| 64 |
+
{
|
| 65 |
+
struct E_string es; es_init_from_cstr(&es, "a*]");
|
| 66 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 67 |
+
TEST_ASSERT_FALSE(got);
|
| 68 |
+
es_free_local(&es);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* 5) False: '*' is escaped */
|
| 72 |
+
void test_star_digits_closebracket_false_star_escaped(void)
|
| 73 |
+
{
|
| 74 |
+
struct E_string es; es_init_from_cstr(&es, "*]");
|
| 75 |
+
es.escaped[0] = true; /* escape the '*' */
|
| 76 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 77 |
+
TEST_ASSERT_FALSE(got);
|
| 78 |
+
es_free_local(&es);
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
/* 6) False: closing ']' is escaped */
|
| 82 |
+
void test_star_digits_closebracket_false_escaped_closing_bracket(void)
|
| 83 |
+
{
|
| 84 |
+
struct E_string es; es_init_from_cstr(&es, "*]");
|
| 85 |
+
es.escaped[1] = true; /* escape the ']' */
|
| 86 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 87 |
+
TEST_ASSERT_FALSE(got);
|
| 88 |
+
es_free_local(&es);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
/* 7) False: an escaped digit occurs (escapes are not allowed) */
|
| 92 |
+
void test_star_digits_closebracket_false_escaped_digit(void)
|
| 93 |
+
{
|
| 94 |
+
struct E_string es; es_init_from_cstr(&es, "*1]");
|
| 95 |
+
es.escaped[1] = true; /* escape the '1' */
|
| 96 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 97 |
+
TEST_ASSERT_FALSE(got);
|
| 98 |
+
es_free_local(&es);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
/* 8) False: non-digit before ']' */
|
| 102 |
+
void test_star_digits_closebracket_false_non_digit_before_close(void)
|
| 103 |
+
{
|
| 104 |
+
struct E_string es; es_init_from_cstr(&es, "*12a]");
|
| 105 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 106 |
+
TEST_ASSERT_FALSE(got);
|
| 107 |
+
es_free_local(&es);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
/* 9) False: no closing bracket at all */
|
| 111 |
+
void test_star_digits_closebracket_false_no_closing_bracket(void)
|
| 112 |
+
{
|
| 113 |
+
struct E_string es; es_init_from_cstr(&es, "*123");
|
| 114 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 115 |
+
TEST_ASSERT_FALSE(got);
|
| 116 |
+
es_free_local(&es);
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
/* 10) False: '*' at end of string (no room for "]") */
|
| 120 |
+
void test_star_digits_closebracket_false_star_at_end(void)
|
| 121 |
+
{
|
| 122 |
+
struct E_string es; es_init_from_cstr(&es, "abc*");
|
| 123 |
+
bool got = star_digits_closebracket(&es, 3);
|
| 124 |
+
TEST_ASSERT_FALSE(got);
|
| 125 |
+
es_free_local(&es);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
/* 11) False: first non-digit after '*' is an escaped ']' (even if a later unescaped ']' exists) */
|
| 129 |
+
void test_star_digits_closebracket_false_escaped_bracket_then_later_valid_bracket(void)
|
| 130 |
+
{
|
| 131 |
+
/* String: "*1]2]" where the first ']' is escaped; function should stop at that escaped ']' and return false */
|
| 132 |
+
struct E_string es; es_init_from_cstr(&es, "*1]2]");
|
| 133 |
+
es.escaped[2] = true; /* escape the first ']' */
|
| 134 |
+
bool got = star_digits_closebracket(&es, 0);
|
| 135 |
+
TEST_ASSERT_FALSE(got);
|
| 136 |
+
es_free_local(&es);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
int main(void)
|
| 140 |
+
{
|
| 141 |
+
UNITY_BEGIN();
|
| 142 |
+
RUN_TEST(test_star_digits_closebracket_basic_true_empty_digits);
|
| 143 |
+
RUN_TEST(test_star_digits_closebracket_true_with_digits);
|
| 144 |
+
RUN_TEST(test_star_digits_closebracket_true_mid_string_start_index);
|
| 145 |
+
RUN_TEST(test_star_digits_closebracket_false_starts_not_star);
|
| 146 |
+
RUN_TEST(test_star_digits_closebracket_false_star_escaped);
|
| 147 |
+
RUN_TEST(test_star_digits_closebracket_false_escaped_closing_bracket);
|
| 148 |
+
RUN_TEST(test_star_digits_closebracket_false_escaped_digit);
|
| 149 |
+
RUN_TEST(test_star_digits_closebracket_false_non_digit_before_close);
|
| 150 |
+
RUN_TEST(test_star_digits_closebracket_false_no_closing_bracket);
|
| 151 |
+
RUN_TEST(test_star_digits_closebracket_false_star_at_end);
|
| 152 |
+
RUN_TEST(test_star_digits_closebracket_false_escaped_bracket_then_later_valid_bracket);
|
| 153 |
+
return UNITY_END();
|
| 154 |
+
}
|
tests/tr/tests_for_string2_extend.c
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
|
| 3 |
+
#include <stdio.h>
|
| 4 |
+
#include <stdlib.h>
|
| 5 |
+
#include <string.h>
|
| 6 |
+
#include <stdbool.h>
|
| 7 |
+
#include <unistd.h>
|
| 8 |
+
#include <sys/types.h>
|
| 9 |
+
#include <sys/wait.h>
|
| 10 |
+
#include <signal.h>
|
| 11 |
+
|
| 12 |
+
/* The program under test has included this file after defining all
|
| 13 |
+
internal functions and globals. We can use its internal symbols here. */
|
| 14 |
+
|
| 15 |
+
/* Helpers for tests */
|
| 16 |
+
static void build_spec(struct Spec_list *s, const char *str)
|
| 17 |
+
{
|
| 18 |
+
spec_init(s);
|
| 19 |
+
TEST_ASSERT_TRUE_MESSAGE(parse_str(str, s), "parse_str failed");
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
static size_t expand_spec(struct Spec_list *s, unsigned char *out, size_t max)
|
| 23 |
+
{
|
| 24 |
+
size_t n = 0;
|
| 25 |
+
int c;
|
| 26 |
+
s->state = BEGIN_STATE;
|
| 27 |
+
while ((c = get_next(s, NULL)) != -1)
|
| 28 |
+
{
|
| 29 |
+
if (n < max) out[n] = (unsigned char)c;
|
| 30 |
+
n++;
|
| 31 |
+
}
|
| 32 |
+
return n;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
void setUp(void) {
|
| 36 |
+
/* Ensure translating mode is enabled for string2_extend preconditions. */
|
| 37 |
+
translating = true;
|
| 38 |
+
/* Ensure defaults that don't interfere. */
|
| 39 |
+
complement = false;
|
| 40 |
+
truncate_set1 = false;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
void tearDown(void) {
|
| 44 |
+
/* No persistent resources to clean. */
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/* Test: s2 ends with a normal character; extend by repeating that char. */
|
| 48 |
+
void test_string2_extend_after_normal_char(void)
|
| 49 |
+
{
|
| 50 |
+
struct Spec_list s1, s2;
|
| 51 |
+
build_spec(&s1, "abcd"); /* length 4 */
|
| 52 |
+
get_s1_spec_stats(&s1);
|
| 53 |
+
|
| 54 |
+
build_spec(&s2, "ab"); /* length 2, ends with 'b' */
|
| 55 |
+
get_s2_spec_stats(&s2, s1.length);
|
| 56 |
+
|
| 57 |
+
TEST_ASSERT_TRUE(s1.length > s2.length);
|
| 58 |
+
size_t need = s1.length - s2.length;
|
| 59 |
+
|
| 60 |
+
string2_extend(&s1, &s2);
|
| 61 |
+
|
| 62 |
+
TEST_ASSERT_EQUAL_UINT64(s1.length, s2.length);
|
| 63 |
+
TEST_ASSERT_NOT_NULL(s2.tail);
|
| 64 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, s2.tail->type);
|
| 65 |
+
TEST_ASSERT_EQUAL_UINT8('b', s2.tail->u.repeated_char.the_repeated_char);
|
| 66 |
+
TEST_ASSERT_EQUAL_UINT64(need, s2.tail->u.repeated_char.repeat_count);
|
| 67 |
+
|
| 68 |
+
unsigned char buf[64];
|
| 69 |
+
size_t n = expand_spec(&s2, buf, sizeof buf);
|
| 70 |
+
TEST_ASSERT_EQUAL_UINT64(s1.length, n);
|
| 71 |
+
TEST_ASSERT_EQUAL_UINT8('a', buf[0]);
|
| 72 |
+
TEST_ASSERT_EQUAL_UINT8('b', buf[1]);
|
| 73 |
+
/* The rest should be 'b'. */
|
| 74 |
+
for (size_t i = 2; i < n; i++)
|
| 75 |
+
TEST_ASSERT_EQUAL_UINT8('b', buf[i]);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
/* Test: s2 ends with a range; extend with last char of the range. */
|
| 79 |
+
void test_string2_extend_after_range(void)
|
| 80 |
+
{
|
| 81 |
+
struct Spec_list s1, s2;
|
| 82 |
+
build_spec(&s1, "abcde"); /* length 5 */
|
| 83 |
+
get_s1_spec_stats(&s1);
|
| 84 |
+
|
| 85 |
+
build_spec(&s2, "a-c"); /* expands to a,b,c (len 3), last 'c' */
|
| 86 |
+
get_s2_spec_stats(&s2, s1.length);
|
| 87 |
+
|
| 88 |
+
TEST_ASSERT_TRUE(s1.length > s2.length);
|
| 89 |
+
size_t need = s1.length - s2.length; /* expect 2 */
|
| 90 |
+
|
| 91 |
+
string2_extend(&s1, &s2);
|
| 92 |
+
|
| 93 |
+
TEST_ASSERT_EQUAL_UINT64(s1.length, s2.length);
|
| 94 |
+
TEST_ASSERT_NOT_NULL(s2.tail);
|
| 95 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, s2.tail->type);
|
| 96 |
+
TEST_ASSERT_EQUAL_UINT8('c', s2.tail->u.repeated_char.the_repeated_char);
|
| 97 |
+
TEST_ASSERT_EQUAL_UINT64(need, s2.tail->u.repeated_char.repeat_count);
|
| 98 |
+
|
| 99 |
+
unsigned char buf[64];
|
| 100 |
+
size_t n = expand_spec(&s2, buf, sizeof buf);
|
| 101 |
+
TEST_ASSERT_EQUAL_UINT64(s1.length, n);
|
| 102 |
+
TEST_ASSERT_EQUAL_UINT8('a', buf[0]);
|
| 103 |
+
TEST_ASSERT_EQUAL_UINT8('b', buf[1]);
|
| 104 |
+
TEST_ASSERT_EQUAL_UINT8('c', buf[2]);
|
| 105 |
+
for (size_t i = 3; i < n; i++)
|
| 106 |
+
TEST_ASSERT_EQUAL_UINT8('c', buf[i]);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
/* Test: s2 ends with a repeated-char construct; extend with that char. */
|
| 110 |
+
void test_string2_extend_after_repeated_char(void)
|
| 111 |
+
{
|
| 112 |
+
struct Spec_list s1, s2;
|
| 113 |
+
build_spec(&s1, "[A*5]"); /* length 5 */
|
| 114 |
+
get_s1_spec_stats(&s1);
|
| 115 |
+
|
| 116 |
+
build_spec(&s2, "[x*3]"); /* length 3, last is RE_REPEATED_CHAR 'x' */
|
| 117 |
+
get_s2_spec_stats(&s2, s1.length);
|
| 118 |
+
|
| 119 |
+
TEST_ASSERT_TRUE(s1.length > s2.length);
|
| 120 |
+
size_t need = s1.length - s2.length; /* expect 2 */
|
| 121 |
+
|
| 122 |
+
string2_extend(&s1, &s2);
|
| 123 |
+
|
| 124 |
+
TEST_ASSERT_EQUAL_UINT64(s1.length, s2.length);
|
| 125 |
+
TEST_ASSERT_NOT_NULL(s2.tail);
|
| 126 |
+
TEST_ASSERT_EQUAL_INT(RE_REPEATED_CHAR, s2.tail->type);
|
| 127 |
+
TEST_ASSERT_EQUAL_UINT8('x', s2.tail->u.repeated_char.the_repeated_char);
|
| 128 |
+
TEST_ASSERT_EQUAL_UINT64(need, s2.tail->u.repeated_char.repeat_count);
|
| 129 |
+
|
| 130 |
+
unsigned char buf[64];
|
| 131 |
+
size_t n = expand_spec(&s2, buf, sizeof buf);
|
| 132 |
+
TEST_ASSERT_EQUAL_UINT64(s1.length, n);
|
| 133 |
+
for (size_t i = 0; i < n; i++)
|
| 134 |
+
TEST_ASSERT_EQUAL_UINT8('x', buf[i]);
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
/* Test: error path when s2 ends with a character class and needs extension.
|
| 138 |
+
We run in a child process to observe the EXIT_FAILURE without aborting tests. */
|
| 139 |
+
void test_string2_extend_error_when_class_tail(void)
|
| 140 |
+
{
|
| 141 |
+
struct Spec_list s1, s2;
|
| 142 |
+
build_spec(&s1, "[A*300]"); /* ensure s1.length > any class size */
|
| 143 |
+
get_s1_spec_stats(&s1);
|
| 144 |
+
|
| 145 |
+
build_spec(&s2, "[:lower:]"); /* ends with RE_CHAR_CLASS */
|
| 146 |
+
get_s2_spec_stats(&s2, s1.length);
|
| 147 |
+
|
| 148 |
+
TEST_ASSERT_TRUE(s1.length > s2.length);
|
| 149 |
+
|
| 150 |
+
fflush(stdout);
|
| 151 |
+
fflush(stderr);
|
| 152 |
+
pid_t pid = fork();
|
| 153 |
+
TEST_ASSERT_MESSAGE(pid >= 0, "fork failed");
|
| 154 |
+
|
| 155 |
+
if (pid == 0) {
|
| 156 |
+
/* Child: call the function expecting it to exit with failure. */
|
| 157 |
+
/* Avoid Unity asserts in child. */
|
| 158 |
+
string2_extend(&s1, &s2);
|
| 159 |
+
/* If we get here, the function did not exit as expected. */
|
| 160 |
+
_exit(0);
|
| 161 |
+
} else {
|
| 162 |
+
int status = 0;
|
| 163 |
+
pid_t w = waitpid(pid, &status, 0);
|
| 164 |
+
TEST_ASSERT_EQUAL_INT(pid, w);
|
| 165 |
+
TEST_ASSERT_TRUE(WIFEXITED(status));
|
| 166 |
+
/* Expect EXIT_FAILURE; accept any non-zero failure to be robust. */
|
| 167 |
+
int code = WEXITSTATUS(status);
|
| 168 |
+
TEST_ASSERT_TRUE_MESSAGE(code != 0, "Child did not exit with failure");
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
int main(void)
|
| 173 |
+
{
|
| 174 |
+
UNITY_BEGIN();
|
| 175 |
+
RUN_TEST(test_string2_extend_after_normal_char);
|
| 176 |
+
RUN_TEST(test_string2_extend_after_range);
|
| 177 |
+
RUN_TEST(test_string2_extend_after_repeated_char);
|
| 178 |
+
RUN_TEST(test_string2_extend_error_when_class_tail);
|
| 179 |
+
return UNITY_END();
|
| 180 |
+
}
|
tests/tr/tests_for_unquote.c
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdio.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdlib.h>
|
| 5 |
+
#include <stdbool.h>
|
| 6 |
+
#include <unistd.h>
|
| 7 |
+
|
| 8 |
+
/* Helper: capture stderr without affecting stdout (Unity uses stdout). */
|
| 9 |
+
typedef struct {
|
| 10 |
+
int old_fd;
|
| 11 |
+
FILE *tmp;
|
| 12 |
+
} StderrCapture;
|
| 13 |
+
|
| 14 |
+
static void stderr_capture_start(StderrCapture *cap) {
|
| 15 |
+
fflush(stderr);
|
| 16 |
+
cap->old_fd = dup(STDERR_FILENO);
|
| 17 |
+
cap->tmp = tmpfile();
|
| 18 |
+
dup2(fileno(cap->tmp), STDERR_FILENO);
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
static char* stderr_capture_finish(StderrCapture *cap) {
|
| 22 |
+
fflush(stderr);
|
| 23 |
+
long size;
|
| 24 |
+
fseek(cap->tmp, 0, SEEK_END);
|
| 25 |
+
size = ftell(cap->tmp);
|
| 26 |
+
fseek(cap->tmp, 0, SEEK_SET);
|
| 27 |
+
char *buf = (char*)malloc((size_t)size + 1);
|
| 28 |
+
if (!buf) buf = NULL;
|
| 29 |
+
if (buf && size > 0) {
|
| 30 |
+
size_t n = fread(buf, 1, (size_t)size, cap->tmp);
|
| 31 |
+
buf[n] = '\0';
|
| 32 |
+
} else if (buf) {
|
| 33 |
+
buf[0] = '\0';
|
| 34 |
+
}
|
| 35 |
+
dup2(cap->old_fd, STDERR_FILENO);
|
| 36 |
+
close(cap->old_fd);
|
| 37 |
+
fclose(cap->tmp);
|
| 38 |
+
return buf;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
/* Helper: assert E_string contents and escaped flags. */
|
| 42 |
+
static void assert_es_eq(const struct E_string *es,
|
| 43 |
+
const unsigned char *exp_bytes, size_t exp_len,
|
| 44 |
+
const bool *exp_escaped /* may be NULL to skip */) {
|
| 45 |
+
TEST_ASSERT_NOT_NULL(es);
|
| 46 |
+
TEST_ASSERT_NOT_NULL(es->s);
|
| 47 |
+
TEST_ASSERT_NOT_NULL(es->escaped);
|
| 48 |
+
TEST_ASSERT_EQUAL_size_t(exp_len, es->len);
|
| 49 |
+
for (size_t i = 0; i < exp_len; i++) {
|
| 50 |
+
TEST_ASSERT_EQUAL_UINT8(exp_bytes[i], (unsigned char)es->s[i]);
|
| 51 |
+
if (exp_escaped) {
|
| 52 |
+
TEST_ASSERT_EQUAL_INT(exp_escaped[i], es->escaped[i]);
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
void setUp(void) {
|
| 58 |
+
/* no-op */
|
| 59 |
+
}
|
| 60 |
+
void tearDown(void) {
|
| 61 |
+
/* no-op */
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
/* Tests */
|
| 65 |
+
|
| 66 |
+
static void test_unquote_no_escapes(void) {
|
| 67 |
+
struct E_string es;
|
| 68 |
+
const char *in = "abc";
|
| 69 |
+
bool ok = unquote(in, &es);
|
| 70 |
+
TEST_ASSERT_TRUE(ok);
|
| 71 |
+
|
| 72 |
+
unsigned char exp[] = { 'a', 'b', 'c' };
|
| 73 |
+
bool esc[] = { false, false, false };
|
| 74 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 75 |
+
|
| 76 |
+
es_free(&es);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
static void test_unquote_standard_escapes(void) {
|
| 80 |
+
struct E_string es;
|
| 81 |
+
/* Input representing: \a \b \f \n \r \t \v \\ */
|
| 82 |
+
const char *in = "\\a\\b\\f\\n\\r\\t\\v\\\\";
|
| 83 |
+
bool ok = unquote(in, &es);
|
| 84 |
+
TEST_ASSERT_TRUE(ok);
|
| 85 |
+
|
| 86 |
+
unsigned char exp[] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\' };
|
| 87 |
+
bool esc[] = { true, true, true, true, true, true, true, true };
|
| 88 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 89 |
+
|
| 90 |
+
es_free(&es);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
static void test_unquote_octal_basic(void) {
|
| 94 |
+
struct E_string es;
|
| 95 |
+
|
| 96 |
+
/* One digit octal: \7A -> 0x07, 'A' */
|
| 97 |
+
const char *in1 = "\\7A";
|
| 98 |
+
bool ok1 = unquote(in1, &es);
|
| 99 |
+
TEST_ASSERT_TRUE(ok1);
|
| 100 |
+
{
|
| 101 |
+
unsigned char exp1[] = { 7, 'A' };
|
| 102 |
+
bool esc1[] = { true, false };
|
| 103 |
+
assert_es_eq(&es, exp1, sizeof(exp1), esc1);
|
| 104 |
+
es_free(&es);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/* Two digit octal: \12 -> 0x0A (newline) */
|
| 108 |
+
const char *in2 = "\\12";
|
| 109 |
+
bool ok2 = unquote(in2, &es);
|
| 110 |
+
TEST_ASSERT_TRUE(ok2);
|
| 111 |
+
{
|
| 112 |
+
unsigned char exp2[] = { 10 };
|
| 113 |
+
bool esc2[] = { true };
|
| 114 |
+
assert_es_eq(&es, exp2, sizeof(exp2), esc2);
|
| 115 |
+
es_free(&es);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
/* Three digit octal within range: \377X -> 255, 'X' */
|
| 119 |
+
const char *in3 = "\\377X";
|
| 120 |
+
bool ok3 = unquote(in3, &es);
|
| 121 |
+
TEST_ASSERT_TRUE(ok3);
|
| 122 |
+
{
|
| 123 |
+
unsigned char exp3[] = { 255, 'X' };
|
| 124 |
+
bool esc3[] = { true, false };
|
| 125 |
+
assert_es_eq(&es, exp3, sizeof(exp3), esc3);
|
| 126 |
+
es_free(&es);
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
static void test_unquote_octal_ambiguous_400_warns_and_leaves_digit(void) {
|
| 131 |
+
struct E_string es;
|
| 132 |
+
const char *in = "\\400"; /* 0400 would overflow 8-bit if third digit consumed */
|
| 133 |
+
|
| 134 |
+
StderrCapture cap;
|
| 135 |
+
stderr_capture_start(&cap);
|
| 136 |
+
bool ok = unquote(in, &es);
|
| 137 |
+
char *captured = stderr_capture_finish(&cap);
|
| 138 |
+
|
| 139 |
+
TEST_ASSERT_TRUE(ok);
|
| 140 |
+
|
| 141 |
+
/* Expect two outputs: ' ' (32) and '0' leftover */
|
| 142 |
+
unsigned char exp[] = { 32, '0' };
|
| 143 |
+
bool esc[] = { true, false };
|
| 144 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 145 |
+
|
| 146 |
+
/* Warning should be emitted */
|
| 147 |
+
TEST_ASSERT_NOT_NULL(captured);
|
| 148 |
+
TEST_ASSERT_TRUE_MESSAGE(strlen(captured) > 0, "Expected warning on stderr");
|
| 149 |
+
free(captured);
|
| 150 |
+
|
| 151 |
+
es_free(&es);
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
static void test_unquote_octal_ambiguous_777_warns_and_leaves_digit(void) {
|
| 155 |
+
struct E_string es;
|
| 156 |
+
const char *in = "\\777Y";
|
| 157 |
+
|
| 158 |
+
StderrCapture cap;
|
| 159 |
+
stderr_capture_start(&cap);
|
| 160 |
+
bool ok = unquote(in, &es);
|
| 161 |
+
char *captured = stderr_capture_finish(&cap);
|
| 162 |
+
|
| 163 |
+
TEST_ASSERT_TRUE(ok);
|
| 164 |
+
|
| 165 |
+
/* \77 -> 63 ('?'), leftover '7', then 'Y' */
|
| 166 |
+
unsigned char exp[] = { 63, '7', 'Y' };
|
| 167 |
+
bool esc[] = { true, false, false };
|
| 168 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 169 |
+
|
| 170 |
+
TEST_ASSERT_NOT_NULL(captured);
|
| 171 |
+
TEST_ASSERT_TRUE_MESSAGE(strlen(captured) > 0, "Expected warning on stderr");
|
| 172 |
+
free(captured);
|
| 173 |
+
|
| 174 |
+
es_free(&es);
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
static void test_unquote_unknown_escape(void) {
|
| 178 |
+
struct E_string es;
|
| 179 |
+
const char *in = "\\q";
|
| 180 |
+
bool ok = unquote(in, &es);
|
| 181 |
+
TEST_ASSERT_TRUE(ok);
|
| 182 |
+
|
| 183 |
+
unsigned char exp[] = { 'q' };
|
| 184 |
+
bool esc[] = { true };
|
| 185 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 186 |
+
|
| 187 |
+
es_free(&es);
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
static void test_unquote_trailing_backslash_warns_and_literal_backslash(void) {
|
| 191 |
+
struct E_string es;
|
| 192 |
+
const char *in = "\\";
|
| 193 |
+
|
| 194 |
+
StderrCapture cap;
|
| 195 |
+
stderr_capture_start(&cap);
|
| 196 |
+
bool ok = unquote(in, &es);
|
| 197 |
+
char *captured = stderr_capture_finish(&cap);
|
| 198 |
+
|
| 199 |
+
TEST_ASSERT_TRUE(ok);
|
| 200 |
+
|
| 201 |
+
/* Should produce a single backslash with escaped=false */
|
| 202 |
+
unsigned char exp[] = { '\\' };
|
| 203 |
+
bool esc[] = { false };
|
| 204 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 205 |
+
|
| 206 |
+
TEST_ASSERT_NOT_NULL(captured);
|
| 207 |
+
TEST_ASSERT_TRUE_MESSAGE(strlen(captured) > 0, "Expected warning on stderr");
|
| 208 |
+
free(captured);
|
| 209 |
+
|
| 210 |
+
es_free(&es);
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
static void test_unquote_zero_byte_produced(void) {
|
| 214 |
+
struct E_string es;
|
| 215 |
+
const char *in = "\\0X";
|
| 216 |
+
bool ok = unquote(in, &es);
|
| 217 |
+
TEST_ASSERT_TRUE(ok);
|
| 218 |
+
|
| 219 |
+
unsigned char exp[] = { 0, 'X' };
|
| 220 |
+
bool esc[] = { true, false };
|
| 221 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 222 |
+
|
| 223 |
+
es_free(&es);
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
static void test_unquote_mixed_sequence(void) {
|
| 227 |
+
struct E_string es;
|
| 228 |
+
const char *in = "ab\\n\\123z";
|
| 229 |
+
bool ok = unquote(in, &es);
|
| 230 |
+
TEST_ASSERT_TRUE(ok);
|
| 231 |
+
|
| 232 |
+
unsigned char exp[] = { 'a', 'b', '\n', 0123, 'z' };
|
| 233 |
+
bool esc[] = { false, false, true, true, false };
|
| 234 |
+
assert_es_eq(&es, exp, sizeof(exp), esc);
|
| 235 |
+
|
| 236 |
+
es_free(&es);
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
int main(void) {
|
| 240 |
+
UNITY_BEGIN();
|
| 241 |
+
|
| 242 |
+
RUN_TEST(test_unquote_no_escapes);
|
| 243 |
+
RUN_TEST(test_unquote_standard_escapes);
|
| 244 |
+
RUN_TEST(test_unquote_octal_basic);
|
| 245 |
+
RUN_TEST(test_unquote_octal_ambiguous_400_warns_and_leaves_digit);
|
| 246 |
+
RUN_TEST(test_unquote_octal_ambiguous_777_warns_and_leaves_digit);
|
| 247 |
+
RUN_TEST(test_unquote_unknown_escape);
|
| 248 |
+
RUN_TEST(test_unquote_trailing_backslash_warns_and_literal_backslash);
|
| 249 |
+
RUN_TEST(test_unquote_zero_byte_produced);
|
| 250 |
+
RUN_TEST(test_unquote_mixed_sequence);
|
| 251 |
+
|
| 252 |
+
return UNITY_END();
|
| 253 |
+
}
|
tests/tr/tests_for_usage.c
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
|
| 3 |
+
#include <stdlib.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <stdio.h>
|
| 6 |
+
#include <stdbool.h>
|
| 7 |
+
#include <unistd.h>
|
| 8 |
+
#include <sys/wait.h>
|
| 9 |
+
#include <errno.h>
|
| 10 |
+
|
| 11 |
+
/* usage(int) is defined in the included program source. */
|
| 12 |
+
extern void usage (int status);
|
| 13 |
+
|
| 14 |
+
/* program_name is provided by gnulib (declared via earlier includes in the TU). */
|
| 15 |
+
extern const char *program_name;
|
| 16 |
+
|
| 17 |
+
static bool str_contains(const char *haystack, const char *needle) {
|
| 18 |
+
if (!haystack || !needle) return false;
|
| 19 |
+
return strstr(haystack, needle) != NULL;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
typedef struct {
|
| 23 |
+
int exit_status; /* -1 if did not exit normally */
|
| 24 |
+
char *out_buf; /* captured stdout */
|
| 25 |
+
size_t out_len;
|
| 26 |
+
char *err_buf; /* captured stderr */
|
| 27 |
+
size_t err_len;
|
| 28 |
+
} UsageRunResult;
|
| 29 |
+
|
| 30 |
+
static void free_result(UsageRunResult *r) {
|
| 31 |
+
if (!r) return;
|
| 32 |
+
free(r->out_buf);
|
| 33 |
+
free(r->err_buf);
|
| 34 |
+
r->out_buf = NULL;
|
| 35 |
+
r->err_buf = NULL;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
static char *read_all_from_fd(int fd, size_t *out_len) {
|
| 39 |
+
size_t cap = 4096;
|
| 40 |
+
size_t len = 0;
|
| 41 |
+
char *buf = (char *)malloc(cap);
|
| 42 |
+
if (!buf) return NULL;
|
| 43 |
+
|
| 44 |
+
while (1) {
|
| 45 |
+
if (len == cap) {
|
| 46 |
+
size_t new_cap = cap * 2;
|
| 47 |
+
char *nb = (char *)realloc(buf, new_cap);
|
| 48 |
+
if (!nb) { free(buf); return NULL; }
|
| 49 |
+
buf = nb; cap = new_cap;
|
| 50 |
+
}
|
| 51 |
+
ssize_t n = read(fd, buf + len, cap - len);
|
| 52 |
+
if (n < 0) {
|
| 53 |
+
if (errno == EINTR) continue;
|
| 54 |
+
free(buf);
|
| 55 |
+
return NULL;
|
| 56 |
+
}
|
| 57 |
+
if (n == 0) break; /* EOF */
|
| 58 |
+
len += (size_t)n;
|
| 59 |
+
}
|
| 60 |
+
/* NUL-terminate for convenience in strstr, though binary-safe length is kept */
|
| 61 |
+
if (len == cap) {
|
| 62 |
+
char *nb = (char *)realloc(buf, cap + 1);
|
| 63 |
+
if (!nb) { free(buf); return NULL; }
|
| 64 |
+
buf = nb; cap += 1;
|
| 65 |
+
}
|
| 66 |
+
buf[len] = '\0';
|
| 67 |
+
if (out_len) *out_len = len;
|
| 68 |
+
return buf;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
static UsageRunResult run_usage_and_capture(int status_to_pass, const char *progname_to_set) {
|
| 72 |
+
UsageRunResult res;
|
| 73 |
+
memset(&res, 0, sizeof(res));
|
| 74 |
+
res.exit_status = -1;
|
| 75 |
+
res.out_buf = NULL; res.err_buf = NULL; res.out_len = 0; res.err_len = 0;
|
| 76 |
+
|
| 77 |
+
int out_pipe[2];
|
| 78 |
+
int err_pipe[2];
|
| 79 |
+
if (pipe(out_pipe) != 0) return res;
|
| 80 |
+
if (pipe(err_pipe) != 0) { close(out_pipe[0]); close(out_pipe[1]); return res; }
|
| 81 |
+
|
| 82 |
+
fflush(stdout);
|
| 83 |
+
fflush(stderr);
|
| 84 |
+
pid_t pid = fork();
|
| 85 |
+
if (pid == -1) {
|
| 86 |
+
close(out_pipe[0]); close(out_pipe[1]);
|
| 87 |
+
close(err_pipe[0]); close(err_pipe[1]);
|
| 88 |
+
return res;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
if (pid == 0) {
|
| 92 |
+
/* Child: redirect stdout/stderr, set program_name, then call usage */
|
| 93 |
+
/* Close read ends */
|
| 94 |
+
close(out_pipe[0]);
|
| 95 |
+
close(err_pipe[0]);
|
| 96 |
+
/* Duplicate write ends to stdout/stderr */
|
| 97 |
+
if (dup2(out_pipe[1], STDOUT_FILENO) == -1) _exit(127);
|
| 98 |
+
if (dup2(err_pipe[1], STDERR_FILENO) == -1) _exit(127);
|
| 99 |
+
/* Close original write ends */
|
| 100 |
+
close(out_pipe[1]);
|
| 101 |
+
close(err_pipe[1]);
|
| 102 |
+
|
| 103 |
+
/* Set the program name visible to usage() */
|
| 104 |
+
program_name = progname_to_set ? progname_to_set : "tr";
|
| 105 |
+
|
| 106 |
+
/* Call function under test; it will exit() */
|
| 107 |
+
usage(status_to_pass);
|
| 108 |
+
/* Should not reach here; ensure child exits */
|
| 109 |
+
_exit(127);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
/* Parent */
|
| 113 |
+
close(out_pipe[1]);
|
| 114 |
+
close(err_pipe[1]);
|
| 115 |
+
|
| 116 |
+
res.out_buf = read_all_from_fd(out_pipe[0], &res.out_len);
|
| 117 |
+
res.err_buf = read_all_from_fd(err_pipe[0], &res.err_len);
|
| 118 |
+
|
| 119 |
+
close(out_pipe[0]);
|
| 120 |
+
close(err_pipe[0]);
|
| 121 |
+
|
| 122 |
+
int wstatus = 0;
|
| 123 |
+
if (waitpid(pid, &wstatus, 0) == pid) {
|
| 124 |
+
if (WIFEXITED(wstatus)) {
|
| 125 |
+
res.exit_status = WEXITSTATUS(wstatus);
|
| 126 |
+
} else {
|
| 127 |
+
res.exit_status = -1;
|
| 128 |
+
}
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
return res;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
void setUp(void) {
|
| 135 |
+
/* Nothing needed */
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
void tearDown(void) {
|
| 139 |
+
/* Nothing needed */
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
/* Test that usage(EXIT_SUCCESS) prints full usage to stdout, exits 0, and not to stderr. */
|
| 143 |
+
void test_usage_prints_help_to_stdout_and_exits_zero(void) {
|
| 144 |
+
UsageRunResult r = run_usage_and_capture(EXIT_SUCCESS, "tr");
|
| 145 |
+
|
| 146 |
+
TEST_ASSERT_EQUAL_INT_MESSAGE(0, r.exit_status, "usage(EXIT_SUCCESS) should exit(0)");
|
| 147 |
+
TEST_ASSERT_NOT_NULL_MESSAGE(r.out_buf, "stdout capture should not be NULL");
|
| 148 |
+
TEST_ASSERT_TRUE_MESSAGE(r.out_len > 0, "stdout should be non-empty for success case");
|
| 149 |
+
TEST_ASSERT_EQUAL_size_t_MESSAGE(0, r.err_len, "stderr should be empty for success case");
|
| 150 |
+
|
| 151 |
+
/* Check that the Usage line mentions the program name and expected tokens */
|
| 152 |
+
TEST_ASSERT_TRUE_MESSAGE(str_contains(r.out_buf, "Usage:"), "Output should contain 'Usage:'");
|
| 153 |
+
TEST_ASSERT_TRUE_MESSAGE(str_contains(r.out_buf, "Usage: tr "), "Usage line should reference program_name");
|
| 154 |
+
TEST_ASSERT_TRUE_MESSAGE(str_contains(r.out_buf, "STRING1"), "Output should mention STRING1");
|
| 155 |
+
|
| 156 |
+
free_result(&r);
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
/* Test that non-zero status emits try-help on stderr and exits with that status, stdout empty. */
|
| 160 |
+
void test_usage_nonzero_emits_try_help_to_stderr_and_exits_status(void) {
|
| 161 |
+
int code = 2;
|
| 162 |
+
UsageRunResult r = run_usage_and_capture(code, "tr");
|
| 163 |
+
|
| 164 |
+
TEST_ASSERT_EQUAL_INT_MESSAGE(code, r.exit_status, "usage(nonzero) should exit with provided status");
|
| 165 |
+
TEST_ASSERT_EQUAL_size_t_MESSAGE(0, r.out_len, "stdout should be empty for nonzero status");
|
| 166 |
+
TEST_ASSERT_NOT_NULL_MESSAGE(r.err_buf, "stderr capture should not be NULL");
|
| 167 |
+
TEST_ASSERT_TRUE_MESSAGE(r.err_len > 0, "stderr should be non-empty for nonzero status");
|
| 168 |
+
|
| 169 |
+
/* Look for the '--help' hint and program name mention */
|
| 170 |
+
TEST_ASSERT_TRUE_MESSAGE(str_contains(r.err_buf, "--help"), "stderr should suggest --help");
|
| 171 |
+
TEST_ASSERT_TRUE_MESSAGE(str_contains(r.err_buf, "tr"), "stderr should mention program name");
|
| 172 |
+
|
| 173 |
+
free_result(&r);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
/* Test that program_name is respected in the Usage line. */
|
| 177 |
+
void test_usage_respects_program_name_variable(void) {
|
| 178 |
+
const char *alt = "mytr";
|
| 179 |
+
UsageRunResult r = run_usage_and_capture(EXIT_SUCCESS, alt);
|
| 180 |
+
|
| 181 |
+
TEST_ASSERT_EQUAL_INT_MESSAGE(0, r.exit_status, "usage(EXIT_SUCCESS) should exit(0)");
|
| 182 |
+
TEST_ASSERT_NOT_NULL_MESSAGE(r.out_buf, "stdout capture should not be NULL");
|
| 183 |
+
TEST_ASSERT_TRUE_MESSAGE(str_contains(r.out_buf, "Usage: mytr "), "Usage line should reflect custom program_name");
|
| 184 |
+
|
| 185 |
+
free_result(&r);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
int main(void) {
|
| 189 |
+
UNITY_BEGIN();
|
| 190 |
+
RUN_TEST(test_usage_prints_help_to_stdout_and_exits_zero);
|
| 191 |
+
RUN_TEST(test_usage_nonzero_emits_try_help_to_stderr_and_exits_status);
|
| 192 |
+
RUN_TEST(test_usage_respects_program_name_variable);
|
| 193 |
+
return UNITY_END();
|
| 194 |
+
}
|
tests/tr/tests_for_validate.c
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <stdio.h>
|
| 4 |
+
#include <string.h>
|
| 5 |
+
#include <stdbool.h>
|
| 6 |
+
#include <unistd.h>
|
| 7 |
+
#include <sys/wait.h>
|
| 8 |
+
|
| 9 |
+
/* The test file is included after the program source, so we can directly
|
| 10 |
+
use the program's internal functions and globals: spec_init, parse_str,
|
| 11 |
+
validate, get_next, etc., and flags translating, complement, truncate_set1. */
|
| 12 |
+
|
| 13 |
+
static void init_spec_from_str(struct Spec_list *s, const char *str)
|
| 14 |
+
{
|
| 15 |
+
spec_init(s);
|
| 16 |
+
bool ok = parse_str(str, s);
|
| 17 |
+
TEST_ASSERT_TRUE_MESSAGE(ok, "parse_str failed for test input");
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
/* Expand a spec into a C string for small ASCII-only tests. */
|
| 21 |
+
static void expand_spec(struct Spec_list *s, char *out, size_t out_cap)
|
| 22 |
+
{
|
| 23 |
+
size_t idx = 0;
|
| 24 |
+
s->state = BEGIN_STATE;
|
| 25 |
+
int c;
|
| 26 |
+
while ((c = get_next(s, NULL)) != -1 && idx + 1 < out_cap)
|
| 27 |
+
{
|
| 28 |
+
out[idx++] = (char)c;
|
| 29 |
+
}
|
| 30 |
+
out[idx] = '\0';
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
/* Run validate in a child process to capture exit on fatal errors without
|
| 34 |
+
stopping the whole test suite. Returns child's exit status (or 255 on error). */
|
| 35 |
+
static int run_validate_in_child(const char *s1, const char *s2,
|
| 36 |
+
bool trans, bool comp, bool trunc)
|
| 37 |
+
{
|
| 38 |
+
fflush(stdout);
|
| 39 |
+
fflush(stderr);
|
| 40 |
+
pid_t pid = fork();
|
| 41 |
+
if (pid < 0)
|
| 42 |
+
return 255;
|
| 43 |
+
if (pid == 0)
|
| 44 |
+
{
|
| 45 |
+
struct Spec_list a, b;
|
| 46 |
+
init_spec_from_str(&a, s1);
|
| 47 |
+
struct Spec_list *pb = NULL;
|
| 48 |
+
if (s2)
|
| 49 |
+
{
|
| 50 |
+
init_spec_from_str(&b, s2);
|
| 51 |
+
pb = &b;
|
| 52 |
+
}
|
| 53 |
+
translating = trans;
|
| 54 |
+
complement = comp;
|
| 55 |
+
truncate_set1 = trunc;
|
| 56 |
+
/* If validate returns, exit success (0). If it calls error(EXIT_FAILURE,
|
| 57 |
+
...), the process will exit with EXIT_FAILURE. */
|
| 58 |
+
validate(&a, pb);
|
| 59 |
+
_exit(0);
|
| 60 |
+
}
|
| 61 |
+
int status = 0;
|
| 62 |
+
if (waitpid(pid, &status, 0) < 0)
|
| 63 |
+
return 255;
|
| 64 |
+
if (WIFEXITED(status))
|
| 65 |
+
return WEXITSTATUS(status);
|
| 66 |
+
return 255;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
void setUp(void) {
|
| 70 |
+
/* Reset globals to safe defaults for each test. */
|
| 71 |
+
translating = false;
|
| 72 |
+
complement = false;
|
| 73 |
+
truncate_set1 = false;
|
| 74 |
+
}
|
| 75 |
+
void tearDown(void) {
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
/* Non-translating basic: s2 == NULL; length computed. */
|
| 79 |
+
static void test_validate_non_translating_basic(void)
|
| 80 |
+
{
|
| 81 |
+
struct Spec_list s1;
|
| 82 |
+
init_spec_from_str(&s1, "abc");
|
| 83 |
+
translating = false;
|
| 84 |
+
complement = false;
|
| 85 |
+
validate(&s1, NULL);
|
| 86 |
+
TEST_ASSERT_EQUAL_UINT64(3, (unsigned long long)s1.length);
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
/* Translating: equal lengths, no extension. */
|
| 90 |
+
static void test_validate_translating_equal_lengths(void)
|
| 91 |
+
{
|
| 92 |
+
struct Spec_list s1, s2;
|
| 93 |
+
init_spec_from_str(&s1, "ab");
|
| 94 |
+
init_spec_from_str(&s2, "XY");
|
| 95 |
+
translating = true;
|
| 96 |
+
complement = false;
|
| 97 |
+
truncate_set1 = false;
|
| 98 |
+
validate(&s1, &s2);
|
| 99 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)s1.length,
|
| 100 |
+
(unsigned long long)s2.length);
|
| 101 |
+
TEST_ASSERT_EQUAL_UINT64(2, (unsigned long long)s1.length);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
/* Translating: string2 extended by repeating its last char. */
|
| 105 |
+
static void test_validate_translating_extend_string2(void)
|
| 106 |
+
{
|
| 107 |
+
struct Spec_list s1, s2;
|
| 108 |
+
init_spec_from_str(&s1, "abcd");
|
| 109 |
+
init_spec_from_str(&s2, "XY");
|
| 110 |
+
translating = true;
|
| 111 |
+
complement = false;
|
| 112 |
+
truncate_set1 = false;
|
| 113 |
+
validate(&s1, &s2);
|
| 114 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)s1.length,
|
| 115 |
+
(unsigned long long)s2.length);
|
| 116 |
+
char buf[16];
|
| 117 |
+
expand_spec(&s2, buf, sizeof buf);
|
| 118 |
+
TEST_ASSERT_EQUAL_STRING("XYYY", buf);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
/* Translating with --truncate-set1: no extension of string2. */
|
| 122 |
+
static void test_validate_translating_no_extend_when_truncate(void)
|
| 123 |
+
{
|
| 124 |
+
struct Spec_list s1, s2;
|
| 125 |
+
init_spec_from_str(&s1, "abcd");
|
| 126 |
+
init_spec_from_str(&s2, "XY");
|
| 127 |
+
translating = true;
|
| 128 |
+
complement = false;
|
| 129 |
+
truncate_set1 = true;
|
| 130 |
+
validate(&s1, &s2);
|
| 131 |
+
TEST_ASSERT_EQUAL_UINT64(4, (unsigned long long)s1.length);
|
| 132 |
+
TEST_ASSERT_EQUAL_UINT64(2, (unsigned long long)s2.length);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
/* Case classes aligned: [:upper:] vs [:lower:] with trailing literals.
|
| 136 |
+
Lengths both discounted to 2 independent of actual class sizes. */
|
| 137 |
+
static void test_validate_case_class_alignment_success_and_length_adjust(void)
|
| 138 |
+
{
|
| 139 |
+
struct Spec_list s1, s2;
|
| 140 |
+
init_spec_from_str(&s1, "[:upper:]a");
|
| 141 |
+
init_spec_from_str(&s2, "[:lower:]b");
|
| 142 |
+
translating = true;
|
| 143 |
+
complement = false;
|
| 144 |
+
truncate_set1 = false;
|
| 145 |
+
validate(&s1, &s2);
|
| 146 |
+
TEST_ASSERT_EQUAL_UINT64(2, (unsigned long long)s1.length);
|
| 147 |
+
TEST_ASSERT_EQUAL_UINT64(2, (unsigned long long)s2.length);
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
/* Complemented class with homogeneous s2 mapping: valid. */
|
| 151 |
+
static void test_validate_complement_class_homogeneous_ok(void)
|
| 152 |
+
{
|
| 153 |
+
struct Spec_list s1, s2;
|
| 154 |
+
init_spec_from_str(&s1, "[:digit:]");
|
| 155 |
+
init_spec_from_str(&s2, "[X*]");
|
| 156 |
+
translating = true;
|
| 157 |
+
complement = true;
|
| 158 |
+
truncate_set1 = false;
|
| 159 |
+
validate(&s1, &s2);
|
| 160 |
+
TEST_ASSERT_EQUAL_UINT64((unsigned long long)s1.length,
|
| 161 |
+
(unsigned long long)s2.length);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
/* Error: s2 has equivalence class when translating. */
|
| 165 |
+
static void test_validate_error_s2_equiv_class(void)
|
| 166 |
+
{
|
| 167 |
+
int st = run_validate_in_child("A", "[=A=]", true, false, false);
|
| 168 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
/* Error: s2 empty and extension required without --truncate-set1. */
|
| 172 |
+
static void test_validate_error_s2_empty_requires_non_truncate(void)
|
| 173 |
+
{
|
| 174 |
+
int st = run_validate_in_child("abc", "", true, false, false);
|
| 175 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
/* Error: multiple [c*] constructs in string2. */
|
| 179 |
+
static void test_validate_error_multiple_indefinite_in_s2(void)
|
| 180 |
+
{
|
| 181 |
+
int st = run_validate_in_child("abcd", "[X*][Y*]", true, false, false);
|
| 182 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
/* Error: [c*] appears in string1. */
|
| 186 |
+
static void test_validate_error_indefinite_in_s1(void)
|
| 187 |
+
{
|
| 188 |
+
int st = run_validate_in_child("[X*]", "A", false, false, false);
|
| 189 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
/* Error: restricted class (e.g., [:digit:]) in string2 when translating. */
|
| 193 |
+
static void test_validate_error_s2_restricted_class(void)
|
| 194 |
+
{
|
| 195 |
+
int st = run_validate_in_child("ab", "[:digit:]", true, false, false);
|
| 196 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
/* Error: misaligned case classes (s2 uses [:upper:] but s1 doesn't). */
|
| 200 |
+
static void test_validate_error_misaligned_case_classes(void)
|
| 201 |
+
{
|
| 202 |
+
int st = run_validate_in_child("abc", "[:upper:]", true, false, false);
|
| 203 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
/* Error: extending s2 that ends with a character class. */
|
| 207 |
+
static void test_validate_error_extend_with_trailing_class(void)
|
| 208 |
+
{
|
| 209 |
+
/* s1 two lower classes, s2 one lower class, so extension needed. */
|
| 210 |
+
int st = run_validate_in_child("[:lower:][:lower:]", "[:lower:]", true, false, false);
|
| 211 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
/* Error: complemented class translating must map all to one char (non-homogeneous s2). */
|
| 215 |
+
static void test_validate_error_complement_class_nonhomogeneous(void)
|
| 216 |
+
{
|
| 217 |
+
int st = run_validate_in_child("[:digit:]", "AB", true, true, false);
|
| 218 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, st);
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
int main(void)
|
| 222 |
+
{
|
| 223 |
+
UNITY_BEGIN();
|
| 224 |
+
RUN_TEST(test_validate_non_translating_basic);
|
| 225 |
+
RUN_TEST(test_validate_translating_equal_lengths);
|
| 226 |
+
RUN_TEST(test_validate_translating_extend_string2);
|
| 227 |
+
RUN_TEST(test_validate_translating_no_extend_when_truncate);
|
| 228 |
+
RUN_TEST(test_validate_case_class_alignment_success_and_length_adjust);
|
| 229 |
+
RUN_TEST(test_validate_complement_class_homogeneous_ok);
|
| 230 |
+
RUN_TEST(test_validate_error_s2_equiv_class);
|
| 231 |
+
RUN_TEST(test_validate_error_s2_empty_requires_non_truncate);
|
| 232 |
+
RUN_TEST(test_validate_error_multiple_indefinite_in_s2);
|
| 233 |
+
RUN_TEST(test_validate_error_indefinite_in_s1);
|
| 234 |
+
RUN_TEST(test_validate_error_s2_restricted_class);
|
| 235 |
+
RUN_TEST(test_validate_error_misaligned_case_classes);
|
| 236 |
+
RUN_TEST(test_validate_error_extend_with_trailing_class);
|
| 237 |
+
RUN_TEST(test_validate_error_complement_class_nonhomogeneous);
|
| 238 |
+
return UNITY_END();
|
| 239 |
+
}
|
tests/tr/tests_for_validate_case_classes.c
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "../../unity/unity.h"
|
| 2 |
+
#include <stdlib.h>
|
| 3 |
+
#include <string.h>
|
| 4 |
+
#include <stdint.h>
|
| 5 |
+
#include <unistd.h>
|
| 6 |
+
#include <sys/wait.h>
|
| 7 |
+
|
| 8 |
+
/* Helper: build a Spec_list from a pattern string and compute stats. */
|
| 9 |
+
static void build_spec_with_stats(const char *spec_str, struct Spec_list *s)
|
| 10 |
+
{
|
| 11 |
+
spec_init(s);
|
| 12 |
+
TEST_ASSERT_TRUE_MESSAGE(parse_str(spec_str, s), "parse_str() failed");
|
| 13 |
+
get_spec_stats(s);
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
void setUp(void) {
|
| 17 |
+
/* Reset any global state that might affect validate_case_classes. */
|
| 18 |
+
/* Explicitly ensure complement is false by default. */
|
| 19 |
+
complement = false;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
void tearDown(void) {
|
| 23 |
+
/* Ensure complement is reset for any subsequent tests. */
|
| 24 |
+
complement = false;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/* Test: Early return when complement is true. Nothing should change. */
|
| 28 |
+
void test_validate_case_classes_noop_when_complement(void)
|
| 29 |
+
{
|
| 30 |
+
complement = true;
|
| 31 |
+
|
| 32 |
+
struct Spec_list s1, s2;
|
| 33 |
+
build_spec_with_stats("[:upper:]", &s1);
|
| 34 |
+
build_spec_with_stats("[:lower:]", &s2);
|
| 35 |
+
|
| 36 |
+
uintmax_t len1_before = s1.length;
|
| 37 |
+
uintmax_t len2_before = s2.length;
|
| 38 |
+
struct List_element *t1_before = s1.tail;
|
| 39 |
+
struct List_element *t2_before = s2.tail;
|
| 40 |
+
|
| 41 |
+
validate_case_classes(&s1, &s2);
|
| 42 |
+
|
| 43 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)len1_before, (uint64_t)s1.length);
|
| 44 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)len2_before, (uint64_t)s2.length);
|
| 45 |
+
TEST_ASSERT_TRUE(s1.tail == t1_before);
|
| 46 |
+
TEST_ASSERT_TRUE(s2.tail == t2_before);
|
| 47 |
+
|
| 48 |
+
complement = false; /* restore */
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
/* Test: Early return when s2 has no character class. Nothing should change. */
|
| 52 |
+
void test_validate_case_classes_noop_when_s2_has_no_char_class(void)
|
| 53 |
+
{
|
| 54 |
+
struct Spec_list s1, s2;
|
| 55 |
+
build_spec_with_stats("ABC", &s1);
|
| 56 |
+
build_spec_with_stats("xyz", &s2);
|
| 57 |
+
|
| 58 |
+
/* Ensure s2 has no char class according to computed stats. */
|
| 59 |
+
TEST_ASSERT_FALSE(s2.has_char_class);
|
| 60 |
+
|
| 61 |
+
uintmax_t len1_before = s1.length;
|
| 62 |
+
uintmax_t len2_before = s2.length;
|
| 63 |
+
struct List_element *t1_before = s1.tail;
|
| 64 |
+
struct List_element *t2_before = s2.tail;
|
| 65 |
+
|
| 66 |
+
validate_case_classes(&s1, &s2);
|
| 67 |
+
|
| 68 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)len1_before, (uint64_t)s1.length);
|
| 69 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)len2_before, (uint64_t)s2.length);
|
| 70 |
+
TEST_ASSERT_TRUE(s1.tail == t1_before);
|
| 71 |
+
TEST_ASSERT_TRUE(s2.tail == t2_before);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
/* Test: Lengths are adjusted for aligned case classes, with surrounding chars. */
|
| 75 |
+
void test_validate_case_classes_adjusts_lengths_on_aligned_classes(void)
|
| 76 |
+
{
|
| 77 |
+
/* s1: X [:upper:] Y; s2: x [:lower:] z */
|
| 78 |
+
struct Spec_list s1, s2;
|
| 79 |
+
build_spec_with_stats("X[:upper:]Y", &s1);
|
| 80 |
+
build_spec_with_stats("x[:lower:]z", &s2);
|
| 81 |
+
|
| 82 |
+
/* Precondition: s2 has char class so function will act. */
|
| 83 |
+
TEST_ASSERT_TRUE(s2.has_char_class);
|
| 84 |
+
|
| 85 |
+
struct List_element *t1_before = s1.tail;
|
| 86 |
+
struct List_element *t2_before = s2.tail;
|
| 87 |
+
|
| 88 |
+
validate_case_classes(&s1, &s2);
|
| 89 |
+
|
| 90 |
+
/* After adjustment, each class contributes 1, so total lengths should be 3. */
|
| 91 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)3, (uint64_t)s1.length);
|
| 92 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)3, (uint64_t)s2.length);
|
| 93 |
+
|
| 94 |
+
/* Tail pointers must be restored. */
|
| 95 |
+
TEST_ASSERT_TRUE(s1.tail == t1_before);
|
| 96 |
+
TEST_ASSERT_TRUE(s2.tail == t2_before);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
/* Test: Multiple aligned pairs adjust total length to number of constructs. */
|
| 100 |
+
void test_validate_case_classes_multiple_pairs(void)
|
| 101 |
+
{
|
| 102 |
+
struct Spec_list s1, s2;
|
| 103 |
+
build_spec_with_stats("[:upper:][:lower:]", &s1);
|
| 104 |
+
build_spec_with_stats("[:lower:][:upper:]", &s2);
|
| 105 |
+
|
| 106 |
+
TEST_ASSERT_TRUE(s2.has_char_class);
|
| 107 |
+
|
| 108 |
+
validate_case_classes(&s1, &s2);
|
| 109 |
+
|
| 110 |
+
/* Two constructs remain, each contributing 1 after adjustment. */
|
| 111 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)2, (uint64_t)s1.length);
|
| 112 |
+
TEST_ASSERT_EQUAL_UINT64((uint64_t)2, (uint64_t)s2.length);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
/* Test: Misalignment triggers fatal error (process exits with EXIT_FAILURE). */
|
| 116 |
+
void test_validate_case_classes_misaligned_triggers_exit(void)
|
| 117 |
+
{
|
| 118 |
+
fflush(stdout);
|
| 119 |
+
fflush(stderr);
|
| 120 |
+
pid_t pid = fork();
|
| 121 |
+
TEST_ASSERT_TRUE_MESSAGE(pid >= 0, "fork failed");
|
| 122 |
+
|
| 123 |
+
if (pid == 0) {
|
| 124 |
+
/* Child process: set up misaligned specs and call the function. */
|
| 125 |
+
complement = false;
|
| 126 |
+
struct Spec_list s1, s2;
|
| 127 |
+
spec_init(&s1);
|
| 128 |
+
spec_init(&s2);
|
| 129 |
+
if (!parse_str("ABC", &s1) || !parse_str("[:lower:]", &s2)) {
|
| 130 |
+
_exit(200); /* setup failure */
|
| 131 |
+
}
|
| 132 |
+
get_spec_stats(&s1);
|
| 133 |
+
get_spec_stats(&s2);
|
| 134 |
+
/* This should call error(EXIT_FAILURE, ...), exiting the process. */
|
| 135 |
+
validate_case_classes(&s1, &s2);
|
| 136 |
+
_exit(201); /* Should not reach here. */
|
| 137 |
+
} else {
|
| 138 |
+
int status = 0;
|
| 139 |
+
pid_t w = waitpid(pid, &status, 0);
|
| 140 |
+
TEST_ASSERT_TRUE_MESSAGE(w == pid, "waitpid failed");
|
| 141 |
+
TEST_ASSERT_TRUE_MESSAGE(WIFEXITED(status), "child did not exit normally");
|
| 142 |
+
int ec = WEXITSTATUS(status);
|
| 143 |
+
TEST_ASSERT_EQUAL_INT(EXIT_FAILURE, ec);
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
int main(void)
|
| 148 |
+
{
|
| 149 |
+
UNITY_BEGIN();
|
| 150 |
+
RUN_TEST(test_validate_case_classes_noop_when_complement);
|
| 151 |
+
RUN_TEST(test_validate_case_classes_noop_when_s2_has_no_char_class);
|
| 152 |
+
RUN_TEST(test_validate_case_classes_adjusts_lengths_on_aligned_classes);
|
| 153 |
+
RUN_TEST(test_validate_case_classes_multiple_pairs);
|
| 154 |
+
RUN_TEST(test_validate_case_classes_misaligned_triggers_exit);
|
| 155 |
+
return UNITY_END();
|
| 156 |
+
}
|
tests/tr/tr-case-class.sh
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
# Test case conversion classes
|
| 3 |
+
|
| 4 |
+
# Copyright (C) 2010-2025 Free Software Foundation, Inc.
|
| 5 |
+
|
| 6 |
+
# This program is free software: you can redistribute it and/or modify
|
| 7 |
+
# it under the terms of the GNU General Public License as published by
|
| 8 |
+
# the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
# (at your option) any later version.
|
| 10 |
+
|
| 11 |
+
# This program is distributed in the hope that it will be useful,
|
| 12 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
# GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
# You should have received a copy of the GNU General Public License
|
| 17 |
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
| 18 |
+
|
| 19 |
+
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
| 20 |
+
print_ver_ tr
|
| 21 |
+
|
| 22 |
+
# Ensure we support translation of case classes with extension
|
| 23 |
+
echo '01234567899999999999999999' > exp
|
| 24 |
+
echo 'abcdefghijklmnopqrstuvwxyz' |
|
| 25 |
+
tr '[:lower:]' '0-9' > out || fail=1
|
| 26 |
+
compare exp out || fail=1
|
| 27 |
+
echo 'abcdefghijklmnopqrstuvwxyz' |
|
| 28 |
+
tr '[:lower:][:lower:]' '[:upper:]0-9' > out || fail=1
|
| 29 |
+
compare exp out || fail=1
|
| 30 |
+
|
| 31 |
+
# Validate the alignment of case classes
|
| 32 |
+
returns_ 1 tr 'A-Z[:lower:]' 'a-y[:upper:]' </dev/null || fail=1
|
| 33 |
+
returns_ 1 tr '[:upper:][:lower:]' 'a-y[:upper:]' </dev/null || fail=1
|
| 34 |
+
returns_ 1 tr 'A-Y[:lower:]' 'a-z[:upper:]' </dev/null || fail=1
|
| 35 |
+
returns_ 1 tr 'A-Z[:lower:]' '[:lower:][:upper:]' </dev/null || fail=1
|
| 36 |
+
returns_ 1 tr 'A-Z[:lower:]' '[:lower:]A-Z' </dev/null || fail=1
|
| 37 |
+
tr '[:upper:][:lower:]' 'a-z[:upper:]' < /dev/null || fail=1
|
| 38 |
+
tr '[:upper:][:lower:]' '[:upper:]a-z' < /dev/null || fail=1
|
| 39 |
+
|
| 40 |
+
# Before coreutils 8.6 the trailing space in string1
|
| 41 |
+
# caused the case class in string2 to be extended.
|
| 42 |
+
# However that was not portable, dependent on locale
|
| 43 |
+
# and in contravention of POSIX.
|
| 44 |
+
tr '[:upper:] ' '[:lower:]' < /dev/null 2>out && fail=1
|
| 45 |
+
echo 'tr: when translating with string1 longer than string2,
|
| 46 |
+
the latter string must not end with a character class' > exp
|
| 47 |
+
compare exp out || fail=1
|
| 48 |
+
|
| 49 |
+
# Up to coreutils-6.9, tr rejected an unmatched [:lower:] or [:upper:] in SET1.
|
| 50 |
+
echo '#$%123abcABC' | tr '[:lower:]' '[.*]' > out || fail=1
|
| 51 |
+
echo '#$%123...ABC' > exp
|
| 52 |
+
compare exp out || fail=1
|
| 53 |
+
echo '#$%123abcABC' | tr '[:upper:]' '[.*]' > out || fail=1
|
| 54 |
+
echo '#$%123abc...' > exp
|
| 55 |
+
compare exp out || fail=1
|
| 56 |
+
|
| 57 |
+
# When doing a case-converting translation with something after the
|
| 58 |
+
# [:upper:] and [:lower:] elements, ensure that tr honors the following byte.
|
| 59 |
+
echo 'abc.' | tr '[:lower:].' '[:upper:]x' > out || fail=1
|
| 60 |
+
echo 'ABCx' > exp
|
| 61 |
+
compare exp out || fail=1
|
| 62 |
+
|
| 63 |
+
# Before coreutils 8.6 the disparate number of upper and lower
|
| 64 |
+
# characters in some locales, triggered abort()s and invalid behavior
|
| 65 |
+
export LC_ALL=en_US.ISO-8859-1
|
| 66 |
+
|
| 67 |
+
if test "$(locale charmap 2>/dev/null)" = ISO-8859-1; then
|
| 68 |
+
# Up to coreutils-6.9.91, this would fail with the diagnostic:
|
| 69 |
+
# tr: misaligned [:upper:] and/or [:lower:] construct
|
| 70 |
+
# with LC_CTYPE=en_US.ISO-8859-1.
|
| 71 |
+
tr '[:upper:]' '[:lower:]' < /dev/null || fail=1
|
| 72 |
+
|
| 73 |
+
tr '[:upper:] ' '[:lower:]' < /dev/null 2>out && fail=1
|
| 74 |
+
echo 'tr: when translating with string1 longer than string2,
|
| 75 |
+
the latter string must not end with a character class' > exp
|
| 76 |
+
compare exp out || fail=1
|
| 77 |
+
|
| 78 |
+
# Ensure when there are a different number of elements
|
| 79 |
+
# in each string, we validate the case mapping correctly
|
| 80 |
+
echo 'abc.xyz' |
|
| 81 |
+
tr 'ab[:lower:]' '0-1[:upper:]' > out || fail=1
|
| 82 |
+
echo 'ABC.XYZ' > exp
|
| 83 |
+
compare exp out || fail=1
|
| 84 |
+
|
| 85 |
+
# Ensure we extend string2 appropriately
|
| 86 |
+
echo 'ABC- XYZ' |
|
| 87 |
+
tr '[:upper:]- ' '[:lower:]_' > out || fail=1
|
| 88 |
+
echo 'abc__xyz' > exp
|
| 89 |
+
compare exp out || fail=1
|
| 90 |
+
|
| 91 |
+
# Ensure the size of the case classes are accounted
|
| 92 |
+
# for as a unit.
|
| 93 |
+
echo 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|
| 94 |
+
tr '[:upper:]A-B' '[:lower:]0' >out || fail=1
|
| 95 |
+
echo '00cdefghijklmnopqrstuvwxyz' > exp
|
| 96 |
+
compare exp out || fail=1
|
| 97 |
+
|
| 98 |
+
# Ensure the size of the case classes are accounted
|
| 99 |
+
# for as a unit.
|
| 100 |
+
echo 'a' |
|
| 101 |
+
tr -t '[:lower:]a' '[:upper:]0' >out || fail=1
|
| 102 |
+
echo '0' > exp
|
| 103 |
+
compare exp out || fail=1
|
| 104 |
+
|
| 105 |
+
# Ensure the size of the case classes are accounted
|
| 106 |
+
# for as a unit.
|
| 107 |
+
echo 'a' |
|
| 108 |
+
tr -t '[:lower:][:lower:]a' '[:lower:][:upper:]0' >out || fail=1
|
| 109 |
+
echo '0' > exp
|
| 110 |
+
compare exp out || fail=1
|
| 111 |
+
fi
|
| 112 |
+
|
| 113 |
+
# coreutils 8.6 - 8.32 inclusive, would abort trying to validate the following
|
| 114 |
+
returns_ 1 tr -c '[:upper:]\000-\370' '[:lower:]' < /dev/null || fail=1
|
| 115 |
+
|
| 116 |
+
Exit $fail
|
tests/tr/tr.pl
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/perl
|
| 2 |
+
|
| 3 |
+
# Copyright (C) 2008-2025 Free Software Foundation, Inc.
|
| 4 |
+
|
| 5 |
+
# This program is free software: you can redistribute it and/or modify
|
| 6 |
+
# it under the terms of the GNU General Public License as published by
|
| 7 |
+
# the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
# (at your option) any later version.
|
| 9 |
+
|
| 10 |
+
# This program is distributed in the hope that it will be useful,
|
| 11 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
# GNU General Public License for more details.
|
| 14 |
+
|
| 15 |
+
# You should have received a copy of the GNU General Public License
|
| 16 |
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
| 17 |
+
|
| 18 |
+
use strict;
|
| 19 |
+
|
| 20 |
+
my $prog = 'tr';
|
| 21 |
+
|
| 22 |
+
# Turn off localization of executable's output.
|
| 23 |
+
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
|
| 24 |
+
|
| 25 |
+
my $map_all_to_1 =
|
| 26 |
+
"$prog: when translating with complemented character classes,\n"
|
| 27 |
+
. "string2 must map all characters in the domain to one\n";
|
| 28 |
+
|
| 29 |
+
my @Tests =
|
| 30 |
+
(
|
| 31 |
+
['1', qw(abcd '[]*]'), {IN=>'abcd'}, {OUT=>']]]]'}],
|
| 32 |
+
['2', qw(abc '[%*]xyz'), {IN=>'abc'}, {OUT=>'xyz'}],
|
| 33 |
+
['3', qw('' '[.*]'), {IN=>'abc'}, {OUT=>'abc'}],
|
| 34 |
+
|
| 35 |
+
# Test --truncate-set1 behavior when string1 is longer than string2
|
| 36 |
+
['4', qw(-t abcd xy), {IN=>'abcde'}, {OUT=>'xycde'}],
|
| 37 |
+
# Test bsd behavior (the default) when string1 is longer than string2
|
| 38 |
+
['5', qw(abcd xy), {IN=>'abcde'}, {OUT=>'xyyye'}],
|
| 39 |
+
# Do it the posix way
|
| 40 |
+
['6', qw(abcd 'x[y*]'), {IN=>'abcde'}, {OUT=>'xyyye'}],
|
| 41 |
+
['7', qw(-s a-p '%[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.$'}],
|
| 42 |
+
['8', qw(-s a-p '[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'.$'}],
|
| 43 |
+
['9', qw(-s a-p '%[.*]'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.'}],
|
| 44 |
+
['a', qw(-s '[a-z]'), {IN=>'aabbcc'}, {OUT=>'abc'}],
|
| 45 |
+
['b', qw(-s '[a-c]'), {IN=>'aabbcc'}, {OUT=>'abc'}],
|
| 46 |
+
['c', qw(-s '[a-b]'), {IN=>'aabbcc'}, {OUT=>'abcc'}],
|
| 47 |
+
['d', qw(-s '[b-c]'), {IN=>'aabbcc'}, {OUT=>'aabc'}],
|
| 48 |
+
['e', qw(-s '[\0-\5]'),
|
| 49 |
+
{IN=>"\0\0a\1\1b\2\2\2c\3\3\3d\4\4\4\4e\5\5"}, {OUT=>"\0a\1b\2c\3d\4e\5"}],
|
| 50 |
+
# tests of delete
|
| 51 |
+
['f', qw(-d '[=[=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>']]]]]]]]'}],
|
| 52 |
+
['g', qw(-d '[=]=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>'[[[[[[['}],
|
| 53 |
+
['h', qw(-d '[:xdigit:]'), {IN=>'0123456789acbdefABCDEF'}, {OUT=>''}],
|
| 54 |
+
['i', qw(-d '[:xdigit:]'), {IN=>'w0x1y2z3456789acbdefABCDEFz'},
|
| 55 |
+
{OUT=>'wxyzz'}],
|
| 56 |
+
['j', qw(-d '[:digit:]'), {IN=>'0123456789'}, {OUT=>''}],
|
| 57 |
+
['k', qw(-d '[:digit:]'),
|
| 58 |
+
{IN=>'a0b1c2d3e4f5g6h7i8j9k'}, {OUT=>'abcdefghijk'}],
|
| 59 |
+
['l', qw(-d '[:lower:]'), {IN=>'abcdefghijklmnopqrstuvwxyz'}, {OUT=>''}],
|
| 60 |
+
['m', qw(-d '[:upper:]'), {IN=>'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
|
| 61 |
+
['n', qw(-d '[:lower:][:upper:]'),
|
| 62 |
+
{IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
|
| 63 |
+
['o', qw(-d '[:alpha:]'),
|
| 64 |
+
{IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
|
| 65 |
+
['p', qw(-d '[:alnum:]'),
|
| 66 |
+
{IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'},
|
| 67 |
+
{OUT=>''}],
|
| 68 |
+
['q', qw(-d '[:alnum:]'),
|
| 69 |
+
{IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'},
|
| 70 |
+
{OUT=>'..'}],
|
| 71 |
+
['r', qw(-ds '[:alnum:]' .),
|
| 72 |
+
{IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'},
|
| 73 |
+
{OUT=>'.'}],
|
| 74 |
+
|
| 75 |
+
# The classic example, with string2 BSD-style
|
| 76 |
+
['s', qw(-cs '[:alnum:]' '\n'),
|
| 77 |
+
{IN=>'The big black fox jumped over the fence.'},
|
| 78 |
+
{OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}],
|
| 79 |
+
|
| 80 |
+
# The classic example, POSIX-style
|
| 81 |
+
['t', qw(-cs '[:alnum:]' '[\n*]'),
|
| 82 |
+
{IN=>'The big black fox jumped over the fence.'},
|
| 83 |
+
{OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}],
|
| 84 |
+
['u', qw(-ds b a), {IN=>'aabbaa'}, {OUT=>'a'}],
|
| 85 |
+
['v', qw(-ds '[:xdigit:]' Z), {IN=>'ZZ0123456789acbdefABCDEFZZ'}, {OUT=>'Z'}],
|
| 86 |
+
|
| 87 |
+
# Try some data with 8th bit set in case something is mistakenly
|
| 88 |
+
# sign-extended.
|
| 89 |
+
['w', qw(-ds '\350' '\345'),
|
| 90 |
+
{IN=>"\300\301\377\345\345\350\345"},
|
| 91 |
+
{OUT=>"\300\301\377\345"}],
|
| 92 |
+
['x', qw(-s abcdefghijklmn '[:*016]'),
|
| 93 |
+
{IN=>'abcdefghijklmnop'}, {OUT=>':op'}],
|
| 94 |
+
['y', qw(-d a-z), {IN=>'abc $code'}, {OUT=>' $'}],
|
| 95 |
+
['z', qw(-ds a-z '$.'), {IN=>'a.b.c $$$$code\\'}, {OUT=>'. $\\'}],
|
| 96 |
+
|
| 97 |
+
# Make sure that a-a is accepted.
|
| 98 |
+
['range-a-a', qw(a-a z), {IN=>'abc'}, {OUT=>'zbc'}],
|
| 99 |
+
#
|
| 100 |
+
['null', qw(a ''), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
| 101 |
+
{ERR=>"$prog: when not truncating set1, string2 must be non-empty\n"}],
|
| 102 |
+
['upcase', qw('[:lower:]' '[:upper:]'),
|
| 103 |
+
{IN=>'abcxyzABCXYZ'},
|
| 104 |
+
{OUT=>'ABCXYZABCXYZ'}],
|
| 105 |
+
['dncase', qw('[:upper:]' '[:lower:]'),
|
| 106 |
+
{IN=>'abcxyzABCXYZ'},
|
| 107 |
+
{OUT=>'abcxyzabcxyz'}],
|
| 108 |
+
#
|
| 109 |
+
['rep-cclass', qw('a[=*2][=c=]' xyyz), {IN=>'a=c'}, {OUT=>'xyz'}],
|
| 110 |
+
['rep-1', qw('[:*3][:digit:]' a-m), {IN=>':1239'}, {OUT=>'cefgm'}],
|
| 111 |
+
['rep-2', qw('a[b*512]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}],
|
| 112 |
+
['rep-3', qw('a[b*513]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}],
|
| 113 |
+
# Another couple octal repeat count tests.
|
| 114 |
+
['o-rep-1', qw('[b*08]' '[x*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
| 115 |
+
{ERR=>"$prog: invalid repeat count '08' in [c*n] construct\n"}],
|
| 116 |
+
['o-rep-2', qw('[b*010]cd' '[a*7]BC[x*]'), {IN=>'bcd'}, {OUT=>'BCx'}],
|
| 117 |
+
|
| 118 |
+
['esc', qw('a\-z' A-Z), {IN=>'abc-z'}, {OUT=>'AbcBC'}],
|
| 119 |
+
['bs-055', qw('a\055b' def), {IN=>"a\055b"}, {OUT=>'def'}],
|
| 120 |
+
['bs-at-end', qw('\\' x), {IN=>"\\"}, {OUT=>'x'},
|
| 121 |
+
{ERR=>"$prog: warning: an unescaped backslash at end of "
|
| 122 |
+
. "string is not portable\n"}],
|
| 123 |
+
|
| 124 |
+
#
|
| 125 |
+
# From Ross
|
| 126 |
+
['ross-0a', qw(-cs '[:upper:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
| 127 |
+
{ERR=>$map_all_to_1}],
|
| 128 |
+
['ross-0b', qw(-cs '[:cntrl:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
| 129 |
+
{ERR=>$map_all_to_1}],
|
| 130 |
+
['ross-1a', qw(-cs '[:upper:]' '[X*]'),
|
| 131 |
+
{IN=>'AMZamz123.-+AMZ'}, {OUT=>'AMZXAMZ'}],
|
| 132 |
+
['ross-1b', qw(-cs '[:upper:][:digit:]' '[Z*]'), {IN=>''}, {OUT=>''}],
|
| 133 |
+
['ross-2', qw(-dcs '[:lower:]' n-rs-z),
|
| 134 |
+
{IN=>'amzAMZ123.-+amz'}, {OUT=>'amzamz'}],
|
| 135 |
+
['ross-3', qw(-ds '[:xdigit:]' '[:alnum:]'),
|
| 136 |
+
{IN=>'.ZABCDEFGzabcdefg.0123456788899.GG'}, {OUT=>'.ZGzg..G'}],
|
| 137 |
+
['ross-4', qw(-dcs '[:alnum:]' '[:digit:]'), {IN=>''}, {OUT=>''}],
|
| 138 |
+
['ross-5', qw(-dc '[:lower:]'), {IN=>''}, {OUT=>''}],
|
| 139 |
+
['ross-6', qw(-dc '[:upper:]'), {IN=>''}, {OUT=>''}],
|
| 140 |
+
|
| 141 |
+
# Ensure that these fail.
|
| 142 |
+
# Prior to 2.0.20, each would evoke a failed assertion.
|
| 143 |
+
['empty-eq', qw('[==]' x), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
| 144 |
+
{ERR=>"$prog: missing equivalence class character '[==]'\n"}],
|
| 145 |
+
['empty-cc', qw('[::]' x), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
| 146 |
+
{ERR=>"$prog: missing character class name '[::]'\n"}],
|
| 147 |
+
|
| 148 |
+
# Weird repeat counts.
|
| 149 |
+
['repeat-bs-9', qw(abc '[b*\9]'), {IN=>'abcd'}, {OUT=>'[b*d'}],
|
| 150 |
+
['repeat-0', qw(abc '[b*0]'), {IN=>'abcd'}, {OUT=>'bbbd'}],
|
| 151 |
+
['repeat-zeros', qw(abc '[b*00000000000000000000]'),
|
| 152 |
+
{IN=>'abcd'}, {OUT=>'bbbd'}],
|
| 153 |
+
['repeat-compl', qw(-c '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}],
|
| 154 |
+
['repeat-xC', qw(-C '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}],
|
| 155 |
+
|
| 156 |
+
# From Glenn Fowler.
|
| 157 |
+
['fowler-1', qw(ah -H), {IN=>'aha'}, {OUT=>'-H-'}],
|
| 158 |
+
|
| 159 |
+
# Up to coreutils-6.9, this would provoke a failed assertion.
|
| 160 |
+
['no-abort-1', qw(-c a '[b*256]'), {IN=>'abc'}, {OUT=>'abb'}],
|
| 161 |
+
);
|
| 162 |
+
|
| 163 |
+
@Tests = triple_test \@Tests;
|
| 164 |
+
|
| 165 |
+
# tr takes its input only from stdin, not from a file argument, so
|
| 166 |
+
# remove the tests that provide file arguments and keep only the ones
|
| 167 |
+
# generated by triple_test (identifiable by their .r and .p suffixes).
|
| 168 |
+
@Tests = grep {$_->[0] =~ /\.[pr]$/} @Tests;
|
| 169 |
+
|
| 170 |
+
my $save_temps = $ENV{DEBUG};
|
| 171 |
+
my $verbose = $ENV{VERBOSE};
|
| 172 |
+
|
| 173 |
+
my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
|
| 174 |
+
exit $fail;
|