Commit 50b4ea93db986b2a9498a31023a1d4a9865b63b5

  • avatar
  • Duke Leto <jonathan @le…o.net>
  • Sat Dec 19 04:37:46 CET 2009
  • Tree SHA1: 951c4c1
  • Parent SHA1: 9ab695b ([LIB] Move eval() from PIR to NQP; stop including no longer needed PASM macro files into Glue.pir)
  • raw diff | raw patch
[t] Plumage gets to be the first kid on the block to use the Tapir test harness

Tapir is just three PIR files, t/harness.pir and two libraries in
ext/Tapir/. A PBC or fakecutable for Tapir could be generated, but it
complicates the build process for no good reason. The make target for
'test' now invokes Tapir and there is now also a 'testv' target which is
verbose, i.e. prints out all TAP output.

In theory, we could add the Tapir git repo as a git submodule, but the current
setup is the simplest possible setup that could work.
  
1# Copyright (C) 2009, Jonathan "Duke" Leto
2
3=head1 AUTHOR
4
5Written and maintained by Jonathan "Duke" Leto C<< jonathan@leto.net >>.
6
7=cut
8
9.namespace [ 'Tapir'; 'Parser' ]
10
11.sub parse_tapstream :method
12 .param string tap
13 .param int exit_code :optional
14 .local string curr_line
15 .local pmc plan, pass, fail, skip, todo
16 .local int i, curr_test, reported_test
17 .local pmc tap_lines, parts, klass, stream
18
19 i = 0
20 curr_test = 1
21 fail = new 'Integer'
22 skip = new 'Integer'
23 todo = new 'Integer'
24 pass = new 'Integer'
25 plan = new 'Integer'
26 tap_lines = new 'ResizablePMCArray'
27 parts = new 'ResizablePMCArray'
28
29 split tap_lines, "\n", tap
30 $I0 = tap_lines
31
32 .local string plan_line
33 plan_line = tap_lines[0]
34 plan = self.'parse_plan'(plan_line)
35
36 .local string prefix
37 loop:
38 if i >= $I0 goto done
39 curr_line = tap_lines[i]
40
41 split parts, "ok ", curr_line
42
43 prefix = parts[0]
44 reported_test = parts[1]
45
46 if prefix == 'not ' goto fail_or_todo
47
48 if reported_test == curr_test goto pass_or_skip
49
50 # it was an unrecognized line
51 inc i
52 goto loop
53 pass_or_skip:
54 split parts, "# ", curr_line
55 $S0 = parts[1]
56 $S0 = substr $S0, 0, 4
57 downcase $S0
58 if $S0 != "skip" goto passz
59 # it is a SKIP test!
60 inc skip
61 inc i
62 inc curr_test
63 goto loop
64 fail_or_todo:
65 split parts, "# ", curr_line
66 $S0 = parts[1]
67 $S0 = substr $S0, 0, 4
68 downcase $S0
69 if $S0 != "todo" goto failz
70 # it is a TODO test!
71 inc todo
72 inc curr_test
73 inc i
74 goto loop
75 failz:
76 inc fail
77 inc curr_test
78 inc i
79 goto loop
80 passz:
81 inc pass
82 inc i
83 inc curr_test
84 goto loop
85
86 done:
87 stream = new [ 'Tapir'; 'Stream' ]
88 stream.'set_pass'(pass)
89 stream.'set_fail'(fail)
90 stream.'set_todo'(todo)
91 stream.'set_skip'(skip)
92 stream.'set_plan'(plan)
93 stream.'set_exit_code'(exit_code)
94 .return (stream)
95.end
96
97# parse_plan returns the expected number of test given a TAP stream as a string
98
99.sub parse_plan :method
100 .param string plan_line
101 .local pmc plan_parts
102 # yes, a numeric
103 .local num num_expected_tests
104
105 $I0 = length plan_line
106 if $I0 < 4 goto plan_error
107
108 # this needs to take into account TAP Versions
109 $S0 = substr plan_line, 0, 3
110 unless $S0 == "1.." goto plan_error
111
112 plan_parts = new 'FixedPMCArray'
113 plan_parts = 2
114
115 split plan_parts, "..", plan_line
116 num_expected_tests = plan_parts[1]
117
118 $I1 = num_expected_tests
119 unless $I1 == num_expected_tests goto plan_error
120 .return (num_expected_tests)
121 plan_error:
122 # this indicates an invalid plan
123 .return (-1)
124.end
125
126
127# Local Variables:
128# mode: pir
129# fill-column: 100
130# End:
131# vim: expandtab shiftwidth=4 ft=pir:
  
1# Copyright (C) 2009, Jonathan "Duke" Leto <jonathan@leto.net>
2
3.namespace [ 'Tapir'; 'Stream' ]
4
5# 06:28:33 <@chromatic> :load executes only when loading from bytecode.
6# 06:28:48 <@chromatic> :init executes right after compilation.
7# 06:29:17 <@chromatic> The effects of :init should be frozen into PBC.
8# 06:37:26 <@chromatic> :anon :init trips the "Do something special with bytecode" magic.
9
10.sub _initialize :load :anon
11 .local pmc klass
12
13 klass = newclass [ 'Tapir'; 'Stream' ]
14 klass.'add_attribute'('pass')
15 klass.'add_attribute'('fail')
16 klass.'add_attribute'('skip')
17 klass.'add_attribute'('todo')
18 klass.'add_attribute'('plan')
19 klass.'add_attribute'('exit_code')
20.end
21
22.sub is_pass :method
23 .local pmc fail
24 fail = getattribute self, "fail"
25 if fail goto failz
26
27 .local pmc exit_code
28 exit_code = self."get_exit_code"()
29 if exit_code goto failz
30
31 .local pmc skip, pass, todo, plan
32 skip = self."get_skip"()
33 pass = self."get_pass"()
34 todo = self."get_todo"()
35 plan = self."get_plan"()
36 $P0 = pass + todo
37 $P0 += skip
38
39 $I1 = plan == $P0
40 .return( $I1 )
41 failz:
42 .return( 0 )
43.end
44
45.sub set_exit_code :method
46 .param pmc exit_code
47 setattribute self, "exit_code", exit_code
48.end
49
50.sub set_pass :method
51 .param pmc pass
52 setattribute self, "pass", pass
53.end
54
55.sub set_fail :method
56 .param pmc fail
57 setattribute self, "fail", fail
58.end
59
60.sub set_todo :method
61 .param pmc todo
62 setattribute self, "todo", todo
63.end
64
65.sub set_skip :method
66 .param pmc skip
67 setattribute self, "skip", skip
68.end
69
70.sub set_plan :method
71 .param pmc plan
72 setattribute self, "plan", plan
73.end
74
75.sub get_exit_code :method
76 .local pmc exit_code
77 exit_code = getattribute self, "exit_code"
78 .return( exit_code )
79.end
80
81.sub get_pass :method
82 .local pmc pass
83 pass = getattribute self, "pass"
84 .return( pass )
85.end
86
87.sub get_fail :method
88 .local pmc fail
89 fail = getattribute self, "fail"
90 .return( fail )
91.end
92
93.sub get_todo :method
94 .local pmc todo
95 todo = getattribute self, "todo"
96 .return( todo )
97.end
98
99.sub get_skip :method
100 .local pmc skip
101 skip = getattribute self, "skip"
102 .return( skip )
103.end
104
105.sub get_plan :method
106 .local pmc plan
107 plan = getattribute self, "plan"
108 .return( plan )
109.end
110
111.sub total :method
112 .local pmc skip, pass, fail, todo
113 skip = getattribute self, "skip"
114 pass = getattribute self, "pass"
115 fail = getattribute self, "fail"
116 todo = getattribute self, "todo"
117 $P0 = pass + fail
118 $P0 += todo
119 $P0 += skip
120 .return( $P0 )
121.end
122
123
124# Local Variables:
125# mode: pir
126# fill-column: 100
127# End:
128# vim: expandtab shiftwidth=4 ft=pir:
  
6767 "src/*.c" "src/*$(O)" src/plumage$(EXE) plumage$(EXE) Makefile
6868
6969test: FORCE all
70 $(PARROT_NQP) t/harness t/*.t
70 $(PARROT) t/harness.pir --exec=$(PARROT_NQP) t/*.t
71
72testv: FORCE all
73 $(PARROT) t/harness.pir --verbose --exec=$(PARROT_NQP) t/*.t
74
7175
7276# Local variables:
7377# mode: makefile
t/harness.pir
(265 / 0)
  
1# Copyright (C) 2009, Jonathan "Duke" Leto <jonathan@leto.net>
2
3
4.sub version
5 say "Tapir version 0.01"
6 exit 0
7.end
8
9.sub help
10 say <<"HELP"
11
12Tapir is a TAP test harness. There are different ways to run it, depending on
13your preferences and build, but this should always work:
14
15 parrot t/harness.pir t/*.t
16
17If you have created binary "fakecutable" (this requires a working compiler in
18your PATH) then you can use Tapir like this:
19
20 ./tapir t/*.t
21
22Currently supported arguments:
23 -v Print the output of each test file
24 --verbose
25
26 --version Print out the current Tapir version
27
28 -e
29 --exec=program Use a given program to execute test scripts
30 i.e. ./tapir --exec=perl t/*.t to run Perl tests
31 -h
32 --help This message
33
34HELP
35 exit 0
36.end
37
38.sub _parse_opts
39 .param pmc argv
40 .local pmc getopts, opts
41 load_bytecode "Getopt/Obj.pbc"
42 getopts = new 'Getopt::Obj'
43 getopts."notOptStop"(1)
44 push getopts, "exec|e:s"
45 push getopts, "verbose|v"
46 push getopts, "version"
47 push getopts, "help|h"
48 opts = getopts."get_options"(argv)
49 .return(opts)
50.end
51
52.sub _find_max_file_length
53 .param pmc files
54 .local int numfiles
55 .local int maxlength
56 numfiles = files
57 maxlength = 0
58 $I0 = -1
59 loop_top:
60 inc $I0
61 if $I0 > numfiles goto loop_bottom
62 $S0 = files[$I0]
63 $I1 = length $S0
64 if $I1 <= maxlength goto loop_top
65 maxlength = $I1
66 goto loop_top
67 loop_bottom:
68 .return(maxlength)
69.end
70
71.sub _print_elipses
72 .param string filename
73 .param int maxlength
74 .local int namelength
75 .local int lengthdiff
76 namelength = length filename
77 lengthdiff = maxlength - namelength
78 $I0 = lengthdiff + 2
79 $S0 = repeat ".", $I0
80 print " "
81 print $S0
82 print " "
83.end
84
85.sub main :main
86 .param pmc argv
87 .local pmc opts
88 .local string exec, verbose
89 .local int argc
90 .local num start_time, end_time
91
92 start_time = time
93 $S0 = shift argv # get rid of harness.pir in the args list
94
95 argc = elements argv
96 if argc > 0 goto load_libs
97 help()
98
99 load_libs:
100 load_bytecode 'ext/Tapir/Parser.pbc'
101 load_bytecode 'ext/Tapir/Stream.pbc'
102
103
104 # parse command line args
105 opts = _parse_opts(argv)
106 exec = opts["exec"]
107 $S1 = opts["version"]
108 $S2 = opts["help"]
109 verbose = opts["verbose"]
110
111 unless $S2 goto check_version
112 help()
113
114 check_version:
115 unless $S1 goto make_parser
116 version()
117
118 make_parser:
119 .local pmc tapir, klass
120 klass = newclass [ 'Tapir'; 'Parser' ]
121 tapir = klass.'new'()
122
123 .local pmc stream, qx_data
124 .local int i
125 .local string file
126 .local string output
127 .local int success, exit_code
128 .local int total_files, failing_files, failing_tests, tests
129 .local int namelength
130
131 namelength = _find_max_file_length(argv)
132 i = 0
133 failing_files = 0
134 failing_tests = 0
135 total_files = 0
136 tests = 0
137 loop:
138 file = argv[i]
139 unless file goto done
140 inc total_files
141 print file
142 _print_elipses(file, namelength)
143
144 # we assume the test is PIR unless given an --exec flag
145 # how to do proper shebang-line detection?
146 .local string exec_cmd
147 exec_cmd = 'parrot'
148 unless exec goto run_cmd
149 exec_cmd = exec
150 run_cmd:
151 qx_data = qx(exec_cmd,file)
152 output = qx_data[0]
153 exit_code = qx_data[1]
154 unless verbose goto parse
155 print output
156 parse:
157 stream = tapir.'parse_tapstream'(output, exit_code)
158 success = stream.'is_pass'()
159 unless success goto fail
160 print "passed "
161
162 $I0 = stream.'total'() # includes todo tests
163 print $I0
164 tests += $I0
165 say " tests"
166
167 unless exit_code goto redo
168 # all tests passed but file had non-zero exit code
169 inc failing_files
170
171 goto redo
172 fail:
173 print "failed "
174 $I0 = stream.'get_fail'()
175 print $I0
176 inc failing_files
177 inc failing_tests
178 $S1 = stream.'total'()
179 $S0 = "/" . $S1
180 print $S0
181 print " tests"
182 $I1 = stream.'get_exit_code'()
183 unless $I1 goto newline
184 print ", exit code = "
185 say $I1
186 goto redo
187 newline:
188 print "\n"
189 redo:
190 inc i
191 goto loop
192
193 done:
194 if failing_files goto print_fail
195 print "PASSED "
196 print tests
197 print " test(s) in "
198 print total_files
199 print " files"
200 goto over
201 print_fail:
202 print "FAILED "
203 print failing_tests
204 print " test(s) in "
205 print failing_files
206 print "/"
207 print total_files
208 print " files"
209 over:
210 end_time = time
211 $N1 = end_time - start_time
212 print " ("
213 $P0 = new 'FixedPMCArray'
214 $P0 = 1
215 $P0[0] = $N1
216 $S1 = sprintf "%.4f", $P0
217 print $S1
218 say " seconds)"
219 $I0 = failing_files != 0
220 exit $I0
221.end
222
223.sub 'qx'
224 .param pmc command_and_args :slurpy
225
226 .local string cmd
227 cmd = join ' ', command_and_args
228
229 .local pmc pipe
230 pipe = open cmd, 'rp'
231 unless pipe goto pipe_open_error
232
233 .local pmc output
234 pipe.'encoding'('utf8')
235 output = pipe.'readall'()
236 pipe.'close'()
237
238 .local pmc exit_status
239 $I0 = pipe.'exit_status'()
240 exit_status = box $I0
241
242 find_dynamic_lex $P0, '$!'
243 if null $P0 goto skip_exit_status
244 store_dynamic_lex '$!', exit_status
245 skip_exit_status:
246
247 # hack
248 $P0 = new 'FixedPMCArray'
249 $P0 = 2
250 $P0[0] = output
251 $P0[1] = exit_status
252 .return ($P0)
253
254 pipe_open_error:
255 $S0 = 'Unable to execute "'
256 $S0 .= cmd
257 $S0 .= '"'
258 die $S0
259.end
260
261# Local Variables:
262# mode: pir
263# fill-column: 100
264# End:
265# vim: expandtab shiftwidth=4 ft=pir: