1IO::Capture::Extended::UOsveerrvCioenwt(r3i)buted Perl DIoOc:u:mCeanpttautrieo:n:Extended::Overview(3)
2
3
4
6 IO::Capture::Extended - Extend functionality of IO::Capture
7
9 The programmer interface consists of two classes:
10
11 IO::Capture::Stdout::Extended
12 use IO::Capture::Stdout::Extended;
13
14 $capture = IO::Capture::Stdout::Extended->new();
15 $capture->start();
16 # some code that prints to STDOUT
17 $capture->stop();
18
19 # scalar context: return number of print statements with 'fox'
20 $matches = $capture->grep_print_statements('fox');
21
22 # list context: return list of print statements with 'fox'
23 @matches = $capture->grep_print_statements('fox');
24
25 # return number of print statements
26 $matches = $capture->statements;
27
28 # scalar context: return number of pattern matches
29 $regex = qr/some regular expression/;
30 $matches = $capture->matches($regex);
31
32 # list context: return list of pattern matches
33 @matches = $capture->matches($regex);
34
35 # return reference to array holding list of pattern matches
36 $matchesref = $capture->matches_ref($regex);
37
38 # scalar context: return number of 'screen' lines printed
39 $screen_lines = $capture->all_screen_lines();
40
41 # list context: return list of 'screen' lines printed
42 @all_screen_lines = $capture->all_screen_lines();
43
44 IO::Capture::Stderr::Extended
45 $capture = IO::Capture::Stderr::Extended->new();
46 $capture->start();
47 # some code that prints to STDERR
48 $capture->stop();
49
50 ... and then use all the methods defined above for
51 IO::Capture::Stdout::Extended.
52
54 IO::Capture::Extended is a distribution consisting of two classes, each
55 of which is a collection of subroutines which are useful in extending
56 the functionality of CPAN modules IO::Capture::Stdout and
57 IO::Capture::Stderr, particularly when used in a testing context such
58 as that provided by Test::Simple, Test::More or other modules built on
59 Test::Builder.
60
62 Requirements
63 IO::Capture distribution, available from CPAN
64 <http://search.cpan.org/~reynolds/IO-Capture-0.05/>. Use version 0.05
65 or later to take advantage of important bug fixes. The IO::Capture
66 distribution includes base class IO::Capture, IO::Capture::Stdout,
67 IO::Capture::Stderr and other packages. It also includes useful
68 documentation in IO::Capture::Overview.
69
70 General Comments
71 The IO::Capture::Stdout::Extended and IO::Capture::Stdout::Extended
72 methods are designed to provide return values which work nicely as
73 arguments to Test::More functions such as "ok()", "is()" and "like()".
74 The examples below illustrate that objective. Suggestions are welcome
75 for additional methods which would fulfill that objective.
76
77 Individual Methods
78 Note: Since IO::Capture::Extended is structured so as to make exactly
79 the same methods available for IO::Capture::Stdout::Extended and
80 IO::Capture::Stderr::Extended, whenver there appears below a reference
81 to, e.g., "IO::Capture::Stdout::Extended::grep_print_statements()", you
82 should assume that the remarks apply equally to
83 "IO::Capture::Stderr::Extended::grep_print_statements()". Wherever
84 reference is made to STDOUT, the remarks apply to STDERR as well.
85
86 "grep_print_statements()"
87
88 · Scalar Context
89
90 Problem: You wish to test a function that prints to STDOUT. You
91 can predict the number of "print" statements that match a pattern
92 and wish to test that prediction. (The example below is adapted
93 from IO::Capture::Overview.)
94
95 sub print_fox {
96 print "The quick brown fox jumped over ...";
97 print "garden wall";
98 print "The quick red fox jumped over ...";
99 print "garden wall";
100 }
101
102 $capture->start;
103 print_fox();
104 $capture->stop;
105 $matches = $capture->grep_print_statements('fox');
106 is($capture->grep_print_statements('fox'), 2,
107 "correct no. of print statements grepped");
108
109 Solution: Precede the function call with a call to the
110 IO::Capture::Stdout::Extended "start()" method and follow it with a
111 call to the "stop()" method. Call "grep_print_statements". Use
112 its return value as one of two arguments to "Test::More::is()".
113 Use your prediction as the other argument. Add a useful comment to
114 "is()".
115
116 Potential Pitfall: The number of print statements captured between
117 "IO::Capture::Stdout::Extended::start()" and "stop()" is not
118 necessarily the number of lines that would appear to be printed to
119 standard output by a given block of code. If your subroutine or
120 other code block prints partial lines -- i.e., lines lacking "\n"
121 newline characters -- the number of print statements will be
122 greater than the number of ''screen lines.'' This is illustrated
123 by the following:
124
125 sub print_fox_long {
126 print "The quick brown fox jumped over ...";
127 print "a less adept fox\n";
128 print "The quick red fox jumped over ...";
129 print "the garden wall\n";
130 }
131
132 $capture->start;
133 print_fox_long();
134 $capture->stop;
135 $matches = $capture->grep_print_statements("fox");
136 is($capture->grep_print_statements("fox"), 3,
137 "correct no. of print statements grepped");
138
139 The number of "print" statements matching "fox" is three -- even
140 though the number of lines on the screen which appear on STDOUT
141 containing "fox" is only two.
142
143 · List Context
144
145 Problem: As above, you wish to test a function that prints to
146 STDOUT. This time, you can predict the content of "print"
147 statements that match a pattern and wish to test that prediction.
148
149 %matches = map { $_, 1 } $capture->grep_print_statements('fox');
150 is(keys %matches, 2, "correct no. of print statements grepped");
151 ok($matches{'The quick brown fox jumped over ...'},
152 'print statement correctly grepped');
153 ok($matches{'The quick red fox jumped over ...'},
154 'print statement correctly grepped');
155
156 Solution: As above, call "grep_print_statements", but map its
157 output to a 'seen-hash'. You can then use the number of keys in
158 that seen-hash as an argument to "Test::More::is()". You can use
159 "ok()" to test whether the keys of that hash are as predicted.
160
161 "statements()"
162
163 Problem: You've written a function which prints to STDOUT. You can
164 make a prediction as to the number of screen lines which should be
165 printed. You want to test that prediction with "Test::More::is()".
166
167 sub print_greek {
168 local $_;
169 print "$_\n" for (qw| alpha beta gamma delta |);
170 }
171
172 $capture->start();
173 print_greek();
174 $capture->stop();
175 is($capture->statements, 4,
176 "number of print statements is correct");
177
178 Solution: Precede the function call with a call to the
179 IO::Capture::Stdout "start()" method and follow it with a call to the
180 "stop()" method. Call "IO::Capture::Stdout::Extended::statements()"
181 and use its return value as the first argument to "is()". Use your
182 prediction as the second argument to "is()". Be sure to write a useful
183 comment for your test.
184
185 Potential Pitfall: The number of print statements returned by
186 "statements" is not necessarily the number of lines that would appear
187 to be printed to standard output by a given block of code. If your
188 subroutine or other code block prints partial lines -- i.e., lines
189 lacking "\n" newline characters -- the number of print statements will
190 be greater than the number of ''screen lines.'' This is illustrated by
191 the following:
192
193 sub print_greek_long {
194 local $_;
195 for (qw| alpha beta gamma delta |) {
196 print $_;
197 print "\n";
198 }
199 }
200
201 $capture->start();
202 print_greek_long();
203 $capture->stop();
204 is($capture->statements, 8,
205 "number of print statements is correct");
206
207 This pitfall can be avoided by using "all_screen_lines()" below.
208
209 "all_screen_lines()"
210
211 · Scalar Context
212
213 Returns the number of lines which would normally be counted by eye
214 on STDOUT. This number is not necessarily equal to the number of
215 "print()" statements found in the captured output. This method
216 avoids the 'pitfall' found when using "statements()" above.
217
218 $capture->start();
219 print_greek_long();
220 $capture->stop();
221 $screen_lines = $capture->all_screen_lines;
222 is($screen_lines, 4, "correct no. of lines printed to screen");
223
224 · List Context
225
226 Returns an array holding lines as normally viewed on STDOUT. The
227 size of this array is not necessarily equal to the number of
228 "print()" statements found in the captured output. This method
229 avoids the 'pitfall' found when using "statements()" above.
230
231 $capture->start();
232 print_greek_long();
233 $capture->stop();
234 @all_screen_lines = $capture->all_screen_lines;
235 is($all_screen_lines[0],
236 "alpha",
237 "line correctly printed to screen");
238 is($all_screen_lines[1],
239 "beta",
240 "line correctly printed to screen");
241
242 Any newline ("\n") appearing at the end of a screen line is not
243 included in the list of lines returned by this method, i.e., the
244 lines are chomped.
245
246 "matches()"
247
248 · Scalar Context
249
250 Problem: You've written a function which, much like the ''mail
251 merge'' function in word processing programs, extracts data from
252 some data source, merges the data with text in a standard form, and
253 prints the result to STDOUT. You make a prediction as to the
254 number of forms which are printed to STDOUT and wish to confirm
255 that prediction.
256
257 my @week = (
258 [ qw| Monday Lundi Lunes | ],
259 [ qw| Tuesday Mardi Martes | ],
260 [ qw| Wednesday Mercredi Miercoles | ],
261 [ qw| Thursday Jeudi Jueves | ],
262 [ qw| Friday Vendredi Viernes | ],
263 [ qw| Saturday Samedi Sabado | ],
264 [ qw| Sunday Dimanche Domingo | ],
265 );
266
267 sub print_week {
268 my $weekref = shift;
269 my @week = @{$weekref};
270 for (my $day=0; $day<=$#week; $day++) {
271 print "English: $week[$day][0]\n";
272 print "French: $week[$day][1]\n";
273 print "Spanish: $week[$day][2]\n";
274 print "\n";
275 }
276 }
277
278 $capture->start();
279 print_week(\@week);
280 $capture->stop();
281 $regex = qr/English:.*?French:.*?Spanish:/s;
282
283 is($capture->matches($regex), 7,
284 "correct number of forms printed to screen");
285
286 Solution: Precede the function call with a call to the
287 IO::Capture::Stdout "start()" method and follow it with a call to
288 the "stop()" method. Write a Perl regular expression and assign it
289 to a variable using the "qr//" notation. (Remember to use the "/s"
290 modifier if the text you are testing crosses screen lines.) Pass
291 the regex variable to "IO::Capture::Stdout::Extended::matches()"
292 and use the return value of that method call as one argument to
293 "Test::More::is()". Use your prediction as the second argument to
294 "is()". Be sure to write a useful comment for your test.
295
296 · List Context
297
298 Problem: As above, you've written a function which, much like the
299 ''mail merge'' function in word processing programs, extracts data
300 from some data source, merges the data with text in a standard
301 form, and prints the result to STDOUT. This time, however, you
302 wish to do a quick test on the results by examining a sample form.
303
304 $capture->start();
305 print_week(\@week); # as defined above
306 $capture->stop();
307
308 @matches = $capture->matches($regex);
309 $predicted = "English: Monday\nFrench: Lundi\nSpanish:";
310 is($matches[0], $predicted, "first form matches test portion");
311
312 Solution: Same as above, but capture the output of "matches()" in
313 a list or array. Write a string which predicts typical contents of
314 one instance of your merged form. Use the contents of one form (one
315 element in the list output) and the prediction string as arguments
316 to "is()". Be sure to write a useful comment for your test.
317
318 Problem: As above, but now you wish to make sure that a form was
319 generated for each required field in the data source.
320
321 $regex = qr/French:\s+(.*?)\n/s;
322 @predicted = qw| Lundi Mardi Mercredi Jeudi
323 Vendredi Samedi Dimanche |;
324 ok(eq_array( [ $capture->matches($regex) ], \@predicted ),
325 "all predicted matches found");
326
327 Solution: Similar to above, but this time you predict which data
328 points are going to be present in the output. Store that
329 prediction in a list or array. Take references to (a) the array
330 holding that prediction; and (b) the result of
331 "$capture-"matches($regex)>. Pass those two references to
332 Test::More's utility function "eq_array", which will return a true
333 value if the underlying arrays are identical element-by-element.
334 Pass that value in turn to <ok()>. As always, be sure to write a
335 useful comment for your test.
336
337 "matches_ref()"
338
339 Problem: Same as the first ''List Context'' example above, but now you
340 would prefer to work with a method that returns an array reference
341 rather than all the elements in a list.
342
343 $matchesref = $capture->matches_ref($regex);
344 is(${$matchesref}[0], $predicted, "first form matches test portion");
345
346 Solution: Call "IO::Capture::Stdout::Extended::matches_ref()" instead
347 of "matches". You will have to rephrase your test in terms of an
348 element of a dereferenced array.
349
351 As Paul Johnson says, ''Did I mention that this is alpha code?''.
352
354 Contact the author or post to the perl-qa mailing list.
355
357 Thanks go first and foremost to the two authors of the IO::Capture
358 distribution, Mark Reynolds and Jon Morgan. Mark Reynolds was
359 responsive to this module's author's suggestions for bug fixes and
360 additional tests. The documentation found in IO::Capture::Overview was
361 particularly helpful in showing me how to extend IO::Capture's
362 functionality. This distribution is maintained independently but will
363 be updated as needed if and when IO::Capture is revised.
364
365 The methods in IO::Capture::Extended are offered to the Perl community
366 in gratitude for being turned on to IO::Capture by David Cantrell on
367 the perl.qa mailing list in February 2005
368 (<http://www.nntp.perl.org/group/perl.qa/3567>).
369
370 Other contributors to that discussion thread whose suggestions are
371 reflected in this module were David H. Adler, David Golden, Michael G.
372 Schwern and Tels. Fergal Daly also made suggestions in separate
373 communications.
374
375 The structure for this module was created with my own hacked-up version
376 of R. Geoffrey Avery's modulemaker utility, based on his CPAN module
377 ExtUtils::ModuleMaker.
378
380 James E Keenan. CPAN ID: JKEENAN. jkeenan [at] cpan [dot] org.
381
383 Copyright 2005-15 James E Keenan.
384
385 This program is free software; you can redistribute it and/or modify it
386 under the same terms as Perl itself.
387
388 The full text of the license can be found in the LICENSE file included
389 with this module.
390
392 perl(1). IO::Capture; IO::Capture::Stdout; IO::Capture::Overview.
393 Test::Simple; Test::More.
394
395
396
397perl v5.30.1 2020-01-30IO::Capture::Extended::Overview(3)