AryaWu commited on
Commit
63b20c6
·
verified ·
1 Parent(s): 78d2150

Upload folder using huggingface_hub

Browse files
.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;