.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Test::Output 3" .TH Test::Output 3 "2017-03-29" "perl v5.16.3" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Test::Output \- Utilities to test STDOUT and STDERR messages. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use Test::More tests => 4; \& use Test::Output; \& \& sub writer { \& print "Write out.\en"; \& print STDERR "Error out.\en"; \& } \& \& stdout_is(\e&writer,"Write out.\en",\*(AqTest STDOUT\*(Aq); \& \& stderr_isnt(\e&writer,"No error out.\en",\*(AqTest STDERR\*(Aq); \& \& combined_is( \& \e&writer, \& "Write out.\enError out.\en", \& \*(AqTest STDOUT & STDERR combined\*(Aq \& ); \& \& output_is( \& \e&writer, \& "Write out.\en", \& "Error out.\en", \& \*(AqTest STDOUT & STDERR\*(Aq \& ); \& \& # Use bare blocks. \& \& stdout_is { print "test" } "test", "Test STDOUT"; \& stderr_isnt { print "bad test" } "test", "Test STDERR"; \& output_is { print \*(AqSTDOUT\*(Aq; print STDERR \*(AqSTDERR\*(Aq } \& "STDOUT", "STDERR", "Test output"; .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" Test::Output provides a simple interface for testing output sent to \f(CW\*(C`STDOUT\*(C'\fR or \f(CW\*(C`STDERR\*(C'\fR. A number of different utilities are included to try and be as flexible as possible to the tester. .PP Likewise, Capture::Tiny provides a much more robust capture mechanism without than the original Test::Output::Tie. .SH "TESTS" .IX Header "TESTS" .SS "\s-1STDOUT\s0" .IX Subsection "STDOUT" .IP "\fBstdout_is\fR" 4 .IX Item "stdout_is" .PD 0 .IP "\fBstdout_isnt\fR" 4 .IX Item "stdout_isnt" .PD .Vb 4 \& stdout_is ( $coderef, $expected, \*(Aqdescription\*(Aq ); \& stdout_is { ... } $expected, \*(Aqdescription\*(Aq; \& stdout_isnt( $coderef, $expected, \*(Aqdescription\*(Aq ); \& stdout_isnt { ... } $expected, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`stdout_is()\*(C'\fR captures output sent to \f(CW\*(C`STDOUT\*(C'\fR from \f(CW$coderef\fR and compares it against \f(CW$expected\fR. The test passes if equal. .Sp \&\f(CW\*(C`stdout_isnt()\*(C'\fR passes if \f(CW\*(C`STDOUT\*(C'\fR is not equal to \f(CW$expected\fR. .IP "\fBstdout_like\fR" 4 .IX Item "stdout_like" .PD 0 .IP "\fBstdout_unlike\fR" 4 .IX Item "stdout_unlike" .PD .Vb 4 \& stdout_like ( $coderef, qr/$expected/, \*(Aqdescription\*(Aq ); \& stdout_like { ... } qr/$expected/, \*(Aqdescription\*(Aq; \& stdout_unlike( $coderef, qr/$expected/, \*(Aqdescription\*(Aq ); \& stdout_unlike { ... } qr/$expected/, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`stdout_like()\*(C'\fR captures the output sent to \f(CW\*(C`STDOUT\*(C'\fR from \f(CW$coderef\fR and compares it to the regex in \f(CW$expected\fR. The test passes if the regex matches. .Sp \&\f(CW\*(C`stdout_unlike()\*(C'\fR passes if \s-1STDOUT\s0 does not match the regex. .SS "\s-1STDERR\s0" .IX Subsection "STDERR" .IP "\fBstderr_is\fR" 4 .IX Item "stderr_is" .PD 0 .IP "\fBstderr_isnt\fR" 4 .IX Item "stderr_isnt" .PD .Vb 2 \& stderr_is ( $coderef, $expected, \*(Aqdescription\*(Aq ); \& stderr_is {... } $expected, \*(Aqdescription\*(Aq; \& \& stderr_isnt( $coderef, $expected, \*(Aqdescription\*(Aq ); \& stderr_isnt {... } $expected, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`stderr_is()\*(C'\fR is similar to \f(CW\*(C`stdout_is\*(C'\fR, except that it captures \f(CW\*(C`STDERR\*(C'\fR. The test passes if \f(CW\*(C`STDERR\*(C'\fR from \f(CW$coderef\fR equals \f(CW$expected\fR. .Sp \&\f(CW\*(C`stderr_isnt()\*(C'\fR passes if \f(CW\*(C`STDERR\*(C'\fR is not equal to \f(CW$expected\fR. .IP "\fBstderr_like\fR" 4 .IX Item "stderr_like" .PD 0 .IP "\fBstderr_unlike\fR" 4 .IX Item "stderr_unlike" .PD .Vb 4 \& stderr_like ( $coderef, qr/$expected/, \*(Aqdescription\*(Aq ); \& stderr_like { ...} qr/$expected/, \*(Aqdescription\*(Aq; \& stderr_unlike( $coderef, qr/$expected/, \*(Aqdescription\*(Aq ); \& stderr_unlike { ...} qr/$expected/, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`stderr_like()\*(C'\fR is similar to \f(CW\*(C`stdout_like()\*(C'\fR except that it compares the regex \&\f(CW$expected\fR to \f(CW\*(C`STDERR\*(C'\fR captured from \f(CW$codref\fR. The test passes if the regex matches. .Sp \&\f(CW\*(C`stderr_unlike()\*(C'\fR passes if \f(CW\*(C`STDERR\*(C'\fR does not match the regex. .SS "\s-1COMBINED OUTPUT\s0" .IX Subsection "COMBINED OUTPUT" .IP "\fBcombined_is\fR" 4 .IX Item "combined_is" .PD 0 .IP "\fBcombined_isnt\fR" 4 .IX Item "combined_isnt" .PD .Vb 4 \& combined_is ( $coderef, $expected, \*(Aqdescription\*(Aq ); \& combined_is {... } $expected, \*(Aqdescription\*(Aq; \& combined_isnt ( $coderef, $expected, \*(Aqdescription\*(Aq ); \& combined_isnt {... } $expected, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`combined_is()\*(C'\fR directs \f(CW\*(C`STDERR\*(C'\fR to \f(CW\*(C`STDOUT\*(C'\fR then captures \f(CW\*(C`STDOUT\*(C'\fR. This is equivalent to UNIXs \f(CW\*(C`2>&1\*(C'\fR. The test passes if the combined \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR from \f(CW$coderef\fR equals \f(CW$expected\fR. .Sp \&\f(CW\*(C`combined_isnt()\*(C'\fR passes if combined \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR are not equal to \f(CW$expected\fR. .IP "\fBcombined_like\fR" 4 .IX Item "combined_like" .PD 0 .IP "\fBcombined_unlike\fR" 4 .IX Item "combined_unlike" .PD .Vb 4 \& combined_like ( $coderef, qr/$expected/, \*(Aqdescription\*(Aq ); \& combined_like { ...} qr/$expected/, \*(Aqdescription\*(Aq; \& combined_unlike ( $coderef, qr/$expected/, \*(Aqdescription\*(Aq ); \& combined_unlike { ...} qr/$expected/, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`combined_like()\*(C'\fR is similar to \f(CW\*(C`combined_is()\*(C'\fR except that it compares a regex (\f(CW\*(C`$expected)\*(C'\fR to \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR captured from \f(CW$codref\fR. The test passes if the regex matches. .Sp \&\f(CW\*(C`combined_unlike()\*(C'\fR passes if the combined \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR does not match the regex. .SS "\s-1OUTPUT\s0" .IX Subsection "OUTPUT" .IP "\fBoutput_is\fR" 4 .IX Item "output_is" .PD 0 .IP "\fBoutput_isnt\fR" 4 .IX Item "output_isnt" .PD .Vb 4 \& output_is ( $coderef, $expected_stdout, $expected_stderr, \*(Aqdescription\*(Aq ); \& output_is {... } $expected_stdout, $expected_stderr, \*(Aqdescription\*(Aq; \& output_isnt( $coderef, $expected_stdout, $expected_stderr, \*(Aqdescription\*(Aq ); \& output_isnt {... } $expected_stdout, $expected_stderr, \*(Aqdescription\*(Aq; .Ve .Sp The \f(CW\*(C`output_is()\*(C'\fR function is a combination of the \f(CW\*(C`stdout_is()\*(C'\fR and \f(CW\*(C`stderr_is()\*(C'\fR functions. For example: .Sp .Vb 1 \& output_is(sub {print "foo"; print STDERR "bar";},\*(Aqfoo\*(Aq,\*(Aqbar\*(Aq); .Ve .Sp is functionally equivalent to .Sp .Vb 2 \& stdout_is(sub {print "foo";},\*(Aqfoo\*(Aq) \& && stderr_is(sub {print STDERR "bar";\*(Aqbar\*(Aq); .Ve .Sp except that \f(CW$coderef\fR is only executed once. .Sp Unlike \f(CW\*(C`stdout_is()\*(C'\fR and \f(CW\*(C`stderr_is()\*(C'\fR which ignore \s-1STDERR\s0 and \s-1STDOUT\s0 respectively, \f(CW\*(C`output_is()\*(C'\fR requires both \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR to match in order to pass. Setting either \f(CW$expected_stdout\fR or \f(CW$expected_stderr\fR to \f(CW\*(C`undef\*(C'\fR ignores \f(CW\*(C`STDOUT\*(C'\fR or \f(CW\*(C`STDERR\*(C'\fR respectively. .Sp .Vb 1 \& output_is(sub {print "foo"; print STDERR "bar";},\*(Aqfoo\*(Aq,undef); .Ve .Sp is the same as .Sp .Vb 1 \& stdout_is(sub {print "foo";},\*(Aqfoo\*(Aq) .Ve .Sp \&\f(CW\*(C`output_isnt()\*(C'\fR provides the opposite function of \f(CW\*(C`output_is()\*(C'\fR. It is a combination of \f(CW\*(C`stdout_isnt()\*(C'\fR and \f(CW\*(C`stderr_isnt()\*(C'\fR. .Sp .Vb 1 \& output_isnt(sub {print "foo"; print STDERR "bar";},\*(Aqbar\*(Aq,\*(Aqfoo\*(Aq); .Ve .Sp is functionally equivalent to .Sp .Vb 2 \& stdout_is(sub {print "foo";},\*(Aqbar\*(Aq) \& && stderr_is(sub {print STDERR "bar";\*(Aqfoo\*(Aq); .Ve .Sp As with \f(CW\*(C`output_is()\*(C'\fR, setting either \f(CW$expected_stdout\fR or \f(CW$expected_stderr\fR to \&\f(CW\*(C`undef\*(C'\fR ignores the output to that facility. .Sp .Vb 1 \& output_isnt(sub {print "foo"; print STDERR "bar";},undef,\*(Aqfoo\*(Aq); .Ve .Sp is the same as .Sp .Vb 1 \& stderr_is(sub {print STDERR "bar";},\*(Aqfoo\*(Aq) .Ve .IP "\fBoutput_like\fR" 4 .IX Item "output_like" .PD 0 .IP "\fBoutput_unlike\fR" 4 .IX Item "output_unlike" .PD .Vb 4 \& output_like ( $coderef, $regex_stdout, $regex_stderr, \*(Aqdescription\*(Aq ); \& output_like { ... } $regex_stdout, $regex_stderr, \*(Aqdescription\*(Aq; \& output_unlike( $coderef, $regex_stdout, $regex_stderr, \*(Aqdescription\*(Aq ); \& output_unlike { ... } $regex_stdout, $regex_stderr, \*(Aqdescription\*(Aq; .Ve .Sp \&\f(CW\*(C`output_like()\*(C'\fR and \f(CW\*(C`output_unlike()\*(C'\fR follow the same principles as \f(CW\*(C`output_is()\*(C'\fR and \f(CW\*(C`output_isnt()\*(C'\fR except they use a regular expression for matching. .Sp \&\f(CW\*(C`output_like()\*(C'\fR attempts to match \f(CW$regex_stdout\fR and \f(CW$regex_stderr\fR against \&\f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR produced by \f(CW$coderef\fR. The test passes if both match. .Sp .Vb 1 \& output_like(sub {print "foo"; print STDERR "bar";},qr/foo/,qr/bar/); .Ve .Sp The above test is successful. .Sp Like \f(CW\*(C`output_is()\*(C'\fR, setting either \f(CW$regex_stdout\fR or \f(CW$regex_stderr\fR to \&\f(CW\*(C`undef\*(C'\fR ignores the output to that facility. .Sp .Vb 1 \& output_like(sub {print "foo"; print STDERR "bar";},qr/foo/,undef); .Ve .Sp is the same as .Sp .Vb 1 \& stdout_like(sub {print "foo"; print STDERR "bar";},qr/foo/); .Ve .Sp \&\f(CW\*(C`output_unlike()\*(C'\fR test pass if output from \f(CW$coderef\fR doesn't match \&\f(CW$regex_stdout\fR and \f(CW$regex_stderr\fR. .SH "EXPORTS" .IX Header "EXPORTS" By default, all subroutines are exported by default. .IP "\(bu" 4 :stdout \- the subs with \f(CW\*(C`stdout\*(C'\fR in the name. .IP "\(bu" 4 :stderr \- the subs with \f(CW\*(C`stderr\*(C'\fR in the name. .IP "\(bu" 4 :functions \- the subs with \f(CW\*(C`_from\*(C'\fR at the end. .IP "\(bu" 4 :output \- the subs with \f(CW\*(C`output\*(C'\fR in the name. .IP "\(bu" 4 :combined \- the subs with \f(CW\*(C`combined\*(C'\fR in the name. .IP "\(bu" 4 :tests \- everything that outputs \s-1TAP\s0 .IP "\(bu" 4 :all \- everything (which is the same as the default) .SH "FUNCTIONS" .IX Header "FUNCTIONS" .SS "stdout_from" .IX Subsection "stdout_from" .Vb 2 \& my $stdout = stdout_from($coderef) \& my $stdout = stdout_from { ... }; .Ve .PP \&\fIstdout_from()\fR executes \f(CW$coderef\fR and captures \s-1STDOUT.\s0 .SS "stderr_from" .IX Subsection "stderr_from" .Vb 2 \& my $stderr = stderr_from($coderef) \& my $stderr = stderr_from { ... }; .Ve .PP \&\f(CW\*(C`stderr_from()\*(C'\fR executes \f(CW$coderef\fR and captures \f(CW\*(C`STDERR\*(C'\fR. .SS "output_from" .IX Subsection "output_from" .Vb 2 \& my ($stdout, $stderr) = output_from($coderef) \& my ($stdout, $stderr) = output_from {...}; .Ve .PP \&\f(CW\*(C`output_from()\*(C'\fR executes \f(CW$coderef\fR one time capturing both \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR. .SS "combined_from" .IX Subsection "combined_from" .Vb 2 \& my $combined = combined_from($coderef); \& my $combined = combined_from {...}; .Ve .PP \&\f(CW\*(C`combined_from()\*(C'\fR executes \f(CW$coderef\fR one time combines \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR, and captures them. \f(CW\*(C`combined_from()\*(C'\fR is equivalent to using \f(CW\*(C`2>&1\*(C'\fR in \s-1UNIX.\s0 .SH "AUTHOR" .IX Header "AUTHOR" Currently maintained by brian d foy, \f(CW\*(C`bdfoy@cpan.org\*(C'\fR. .PP Shawn Sorichetti, \f(CW\*(C`\*(C'\fR .SH "SOURCE AVAILABILITY" .IX Header "SOURCE AVAILABILITY" This module is in Github: .PP .Vb 1 \& http://github.com/briandfoy/test\-output/tree/master .Ve .SH "BUGS" .IX Header "BUGS" Please report any bugs or feature requests to \&\f(CW\*(C`bug\-test\-output@rt.cpan.org\*(C'\fR, or through the web interface at . I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. .SH "ACKNOWLEDGEMENTS" .IX Header "ACKNOWLEDGEMENTS" Thanks to chromatic whose TieOut.pm was the basis for capturing output. .PP Also thanks to rjbs for his help cleaning the documentation, and pushing me to Sub::Exporter. (This feature has been removed since it uses none of Sub::Exporter's strengths). .PP Thanks to David Wheeler for providing code block support and tests. .PP Thanks to Michael G Schwern for the solution to combining \f(CW\*(C`STDOUT\*(C'\fR and \f(CW\*(C`STDERR\*(C'\fR. .SH "COPYRIGHT & LICENSE" .IX Header "COPYRIGHT & LICENSE" Copyright 2005\-2013 Shawn Sorichetti, All Rights Reserved. .PP This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.