2 # Copyright (C) 2006-2008, Parrot Foundation.
7 t/op/sprintf.t -- sprintf tests
11 % prove t/op/sprintf.t
15 These tests are based on C<sprintf> tests from perl 5.9.4.
17 Tests C<sprintf>, excluding handling of 64-bit integers or long
18 doubles (if supported), of machine-specific short and long
19 integers, machine-specific floating point exceptions (infinity,
20 not-a-number, etc.), of the effects of locale, and of features
21 specific to multi-byte characters (under the utf8 pragma and such).
23 Individual tests are stored in the F<sprintf_tests> file in the same
24 directory; There is one test per line. In each test, there are three
29 =item * printf template
31 =item * data to be formatted (as a parrot expression)
33 =item * expected result of formatting
37 Optional fields contain a comment.
39 Each field is separated by one or more tabs. If formatting requires more than
40 one data item (for example, if variable field widths are used), the Parrot
41 data expression should return a reference to an array having the requisite
42 number of elements. Even so, subterfuge is sometimes required:
43 see tests for C<%n> and C<%p>.
45 =head1 XXX: FIXME: TODO:
47 Tests that are expected to fail on a certain OS can be marked as such
48 by trailing the comment with a C<skip:> section. Skips are tags separated
49 by space consisting of a C<$^O> optionally trailed with C<:osvers>. In the
50 latter case, all os-levels below that are expected to fail. A special
51 tag C<all> is allowed for todo tests that should fail on any system.
53 %G 1234567e96 1.23457E+102 exponent too big skip: os390
54 %.0f -0.1 -0 C library bug: no minus skip: VMS
55 %d 4 1 4 != 1 skip: all
60 .const int TESTS = 308
66 load_bytecode 'Test/Builder.pbc'
67 .include "iglobals.pasm"
68 .include "sysinfo.pasm"
70 # Variable declarations, initializations
71 .local pmc test # the test harness object.
72 test = new [ 'Test'; 'Builder' ]
74 .local pmc todo_tests # keys indicate test file; values test number.
75 todo_tests = new 'Hash'
77 .local pmc skip_tests # keys indicate tests ID; values reasons.
78 skip_tests = new 'Hash'
80 .local string test_dir # the directory containing tests
83 .local pmc test_files # values are test file names to run.
84 test_files = new 'ResizablePMCArray'
86 # populate the list of test files
87 push test_files, 'sprintf_tests'
90 .local pmc file_iterator # iterate over list of files..
91 file_iterator = iter test_files
93 .local int test_number # the number of the test we're running
96 # these vars are in the loops below
97 .local string test_line # one line of one test file, a single test
98 .local int ok # is this a passing test?
100 # for any given test:
101 .local string template # the sprintf template
102 .local string data # the data to format with the template
103 .local string expected # expected result of this test
104 .local string description # user-facing description of the test
105 .local int skip_it # skip this test on this platform?
106 .local string actual # actual result of the test
108 todo_tests = 'set_todo_info'()
109 skip_tests = 'set_skip_info'()
111 # how many tests to run?
115 unless file_iterator goto end_outer_loop
116 .local string test_name # file name of the current test file
117 test_name = shift file_iterator
119 .local string test_file # full name of the current test file
120 test_file = test_dir . test_name
122 .local int local_test_number # local test number in test file
123 local_test_number = 0
126 .local pmc file_handle # currently open file
127 file_handle = new ['FileHandle']
128 file_handle.'open'(test_file, 'r')
130 unless file_handle goto bad_file
132 # loop over the file, one at a time.
135 # read in the file one line at a time...
136 $I0 = file_handle.'eof'()
139 test_line = file_handle.'readline'()
141 # skip lines without tabs, and comment lines
142 $I0 = index test_line, "\t"
143 if $I0 == -1 goto loop
144 $I0 = index test_line, '#'
145 if $I0 == 0 goto loop
147 inc local_test_number
151 ( template, data, expected, description, skip_it ) = parse_data( test_line )
154 # prepend test filename and line number to description
155 description = 'build_test_desc'( description, template )
158 data_hash = new 'Hash'
160 data_hash['2**32-1'] = 0xffffffff
161 $N0 = data_hash['2**32-1']
163 data_hash['2**38'] = $N0
164 data_hash["'string'"] = 'string'
166 $I0 = exists data_hash[data]
167 unless $I0 goto got_data
168 data = data_hash[data]
171 # data = backslash_escape (data)
172 # expected = backslash_escape (expected)
174 # Should this test be skipped?
176 $S0 .= ' (skipped on this platform)'
177 if skip_it goto must_skip
178 $I0 = exists skip_tests[test_name]
179 unless $I0 goto not_skip
180 $P0 = skip_tests[test_name]
181 $I0 = exists $P0[local_test_number]
182 unless $I0 goto not_skip
183 $S0 = $P0[local_test_number]
190 actual = 'sprintf'(template, data)
192 unless_null actual, sprintf_ok
193 $P1 = new 'Exception'
194 $P1[0] = 'sprintf error'
198 if expected == actual goto is_ok
199 description .= ' actual: >'
200 description .= actual
202 description .= ' expected: >'
203 description .= expected
208 $S0 = substr expected, 0, 1
209 if $S0 != "/" goto eh_bad_line
210 expected = replace expected, 0, 1, ''
211 expected = replace expected, -1, 1, ''
213 $I0 = index $S1, expected
214 if $I0 == -1 goto is_nok
224 $I0 = exists todo_tests[test_name]
225 unless $I0 goto not_todo
226 $P0 = todo_tests[test_name]
227 $I0 = exists $P0[local_test_number]
228 unless $I0 goto not_todo
229 test.'todo'(ok,description)
232 test.'ok'(ok,description)
236 file_handle.'close'()
244 print "Unable to open '"
250 .local string message
251 get_results '0', exception
253 $I0 = index message, 'is not a valid sprintf format'
254 if $I0 == -1 goto other_error
255 $I0 = index expected, ' INVALID'
256 if $I0 == -1 goto bad_error
264 $S0 = "Test not formatted properly!"
272 .param pmc args :slurpy
275 $S1 = sprintf $S0, args
281 # set todo information
283 .local pmc todo_tests # keys indicate test file; values test number
284 todo_tests = new 'Hash'
287 todo_info = new 'Hash'
289 jmpstack = new 'ResizableIntegerArray'
291 .local string test_file
293 local_branch jmpstack, reset_todo_info
294 test_file = 'sprintf_tests'
296 todo_info[64] = 'undecided perl5 vs. posix behavior'
297 todo_info[153] = '%hf should be rejected'
298 todo_info[187] = '%h alone is invalid'
299 todo_info[191] = '%l alone is invalid'
300 todo_info[223] = '%v alone is invalid, but a valid parrot extension'
301 todo_info[304] = 'undecided'
302 todo_info[305] = 'undecided'
303 todo_info[306] = 'undecided'
306 todo_tests[test_file] = todo_info
311 todo_info = new 'Hash'
312 local_return jmpstack
315 if $I0 > $I1 goto end_loop
320 local_return jmpstack
324 # set skip information
326 .local pmc skip_tests # keys indicate test file; values test number
327 skip_tests = new 'Hash'
330 skip_info = new 'Hash'
332 jmpstack = new 'ResizableIntegerArray'
334 .local string test_file
336 local_branch jmpstack, reset_skip_info
337 test_file = 'sprintf_tests'
338 skip_info[5] = 'parrot extension (%B)'
339 skip_info[7] = 'perl5-specific extension (%D)'
340 skip_info[9] = 'perl5-specific extension (%F)'
341 skip_info[16] = 'parrot extension (%H)'
342 skip_info[20] = 'parrot extension (%L)'
343 skip_info[23] = 'perl5-specific extension (%O)'
344 skip_info[24] = 'parrot extension (%P)'
345 skip_info[27] = 'parrot extension (%S)'
346 skip_info[29] = 'perl5-specific extension (%U)'
348 $S0 = 'perl5-specific extension (%v...)'
351 local_branch jmpstack, set_skip_loop
353 skip_info[114] = 'harness needs support for * modifier'
354 skip_info[144] = 'perl5 expresssion as test value'
355 skip_info[131] = 'harness needs support for * modifier'
356 skip_info[141] = 'harness needs support for * modifier'
357 skip_info[161] = 'harness needs support for * modifier'
358 skip_info[166] = 'harness needs support for * modifier'
359 skip_info[193] = 'perl5-specific test'
360 skip_info[200] = 'perl5-specific test'
361 skip_info[201] = 'perl5-specific test'
362 skip_info[202] = 'parrot extension (%p)'
363 skip_info[204] = 'parrot extension (%r)'
364 skip_info[210] = 'harness needs support for * modifier'
365 skip_info[214] = 'harness needs support for * modifier'
366 skip_info[233] = 'harness needs support for * modifier'
367 skip_info[234] = 'perl5-specific extension (%v...)'
368 skip_info[235] = 'perl5-specific extension (%v...)'
369 skip_info[300] = 'harness needs support for * modifier'
371 $S0 = 'perl5-specific test'
374 local_branch jmpstack, set_skip_loop
376 $S0 = 'perl5-specific extension (%v...)'
379 local_branch jmpstack, set_skip_loop
381 skip_info[307] = 'perl5-specific extension (%v...)'
382 skip_info[308] = 'perl5-specific extension (%v...)'
384 skip_tests[test_file] = skip_info
389 skip_info = new 'Hash'
390 local_return jmpstack
393 if $I0 > $I1 goto end_loop
394 if $S0 != '' goto set_skip_info
395 $S0 = 'unknown reason'
402 local_return jmpstack
407 .param string record # the data record
409 .local string template # the sprintf template
410 .local string data # the data to format with the template
411 .local string expected # expected result of this test
412 .local string description # user-facing description of the test
413 .local int skip_it # skip this test on this platform
416 # NOTE: there can be multiple tabs between entries, so skip until
418 # remove the trailing newline from record
419 record = chopn record, 1
420 $P1 = split "\t", record
421 $I0 = elements $P1 # length of array
422 .local int tab_number
425 if tab_number >= $I0 goto bad_line
426 template = $P1[tab_number]
428 if template == '' goto get_template
430 if tab_number >= $I0 goto bad_line
431 data = $P1[tab_number]
433 if data == '' goto get_data
436 if tab_number >= $I0 goto empty_expected
437 expected = $P1[tab_number]
439 if expected == '' goto get_expected
440 ## FIXME: description handling
442 if tab_number >= $I0 goto no_desc
443 description = $P1[tab_number]
445 if description == '' goto get_description
447 ( description, skip_it ) = find_skip_in_description( description )
450 # substr description, -1, 1, ''
454 .return ( template, data, expected, description, skip_it )
461 $P1 = new 'Exception'
462 $P1[0] = 'invalid data format'
467 .sub 'find_skip_in_description'
468 .param string description
471 parts = split ' skip: ', description
474 if $I0 > 1 goto check_os
475 .return( description, 0 )
478 description = shift parts
480 .local string skip_list
481 skip_list = shift parts
484 skip_os = split ' ', skip_list
489 load_bytecode 'config.pbc'
492 osname = $P1['osname']
495 unless it goto iter_end
496 .local string os_name
498 eq os_name, osname, skip_it
501 .return( description, 0 )
504 .return( description, 1 )
508 .sub 'build_test_desc'
510 .param string testname
516 desc = concat $S0, desc
522 # The following tests are not currently run, for the reasons stated:
528 >%.0f< >1.5< >2< >Standard vague: no rounding rules<
529 >%.0f< >2.5< >2< >Standard vague: no rounding rules<
539 # vim: expandtab shiftwidth=4 ft=pir: