xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Test/Tutorial.pod (revision 0:68f95e015346)
1*0Sstevel@tonic-gate=head1 NAME
2*0Sstevel@tonic-gate
3*0Sstevel@tonic-gateTest::Tutorial - A tutorial about writing really basic tests
4*0Sstevel@tonic-gate
5*0Sstevel@tonic-gate=head1 DESCRIPTION
6*0Sstevel@tonic-gate
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gateI<AHHHHHHH!!!!  NOT TESTING!  Anything but testing!
9*0Sstevel@tonic-gateBeat me, whip me, send me to Detroit, but don't make
10*0Sstevel@tonic-gateme write tests!>
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gateI<*sob*>
13*0Sstevel@tonic-gate
14*0Sstevel@tonic-gateI<Besides, I don't know how to write the damned things.>
15*0Sstevel@tonic-gate
16*0Sstevel@tonic-gate
17*0Sstevel@tonic-gateIs this you?  Is writing tests right up there with writing
18*0Sstevel@tonic-gatedocumentation and having your fingernails pulled out?  Did you open up
19*0Sstevel@tonic-gatea test and read
20*0Sstevel@tonic-gate
21*0Sstevel@tonic-gate    ######## We start with some black magic
22*0Sstevel@tonic-gate
23*0Sstevel@tonic-gateand decide that's quite enough for you?
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gateIt's ok.  That's all gone now.  We've done all the black magic for
26*0Sstevel@tonic-gateyou.  And here are the tricks...
27*0Sstevel@tonic-gate
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate=head2 Nuts and bolts of testing.
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gateHere's the most basic test program.
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gate    #!/usr/bin/perl -w
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate    print "1..1\n";
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate    print 1 + 1 == 2 ? "ok 1\n" : "not ok 1\n";
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gatesince 1 + 1 is 2, it prints:
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate    1..1
42*0Sstevel@tonic-gate    ok 1
43*0Sstevel@tonic-gate
44*0Sstevel@tonic-gateWhat this says is: C<1..1> "I'm going to run one test." [1] C<ok 1>
45*0Sstevel@tonic-gate"The first test passed".  And that's about all magic there is to
46*0Sstevel@tonic-gatetesting.  Your basic unit of testing is the I<ok>.  For each thing you
47*0Sstevel@tonic-gatetest, an C<ok> is printed.  Simple.  B<Test::Harness> interprets your test
48*0Sstevel@tonic-gateresults to determine if you succeeded or failed (more on that later).
49*0Sstevel@tonic-gate
50*0Sstevel@tonic-gateWriting all these print statements rapidly gets tedious.  Fortunately,
51*0Sstevel@tonic-gatethere's B<Test::Simple>.  It has one function, C<ok()>.
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate    #!/usr/bin/perl -w
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate    use Test::Simple tests => 1;
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate    ok( 1 + 1 == 2 );
58*0Sstevel@tonic-gate
59*0Sstevel@tonic-gateand that does the same thing as the code above.  C<ok()> is the backbone
60*0Sstevel@tonic-gateof Perl testing, and we'll be using it instead of roll-your-own from
61*0Sstevel@tonic-gatehere on.  If C<ok()> gets a true value, the test passes.  False, it
62*0Sstevel@tonic-gatefails.
63*0Sstevel@tonic-gate
64*0Sstevel@tonic-gate    #!/usr/bin/perl -w
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gate    use Test::Simple tests => 2;
67*0Sstevel@tonic-gate    ok( 1 + 1 == 2 );
68*0Sstevel@tonic-gate    ok( 2 + 2 == 5 );
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gatefrom that comes
71*0Sstevel@tonic-gate
72*0Sstevel@tonic-gate    1..2
73*0Sstevel@tonic-gate    ok 1
74*0Sstevel@tonic-gate    not ok 2
75*0Sstevel@tonic-gate    #     Failed test (test.pl at line 5)
76*0Sstevel@tonic-gate    # Looks like you failed 1 tests of 2.
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gateC<1..2> "I'm going to run two tests."  This number is used to ensure
79*0Sstevel@tonic-gateyour test program ran all the way through and didn't die or skip some
80*0Sstevel@tonic-gatetests.  C<ok 1> "The first test passed."  C<not ok 2> "The second test
81*0Sstevel@tonic-gatefailed".  Test::Simple helpfully prints out some extra commentary about
82*0Sstevel@tonic-gateyour tests.
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gateIt's not scary.  Come, hold my hand.  We're going to give an example
85*0Sstevel@tonic-gateof testing a module.  For our example, we'll be testing a date
86*0Sstevel@tonic-gatelibrary, B<Date::ICal>.  It's on CPAN, so download a copy and follow
87*0Sstevel@tonic-gatealong. [2]
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate
90*0Sstevel@tonic-gate=head2 Where to start?
91*0Sstevel@tonic-gate
92*0Sstevel@tonic-gateThis is the hardest part of testing, where do you start?  People often
93*0Sstevel@tonic-gateget overwhelmed at the apparent enormity of the task of testing a
94*0Sstevel@tonic-gatewhole module.  Best place to start is at the beginning.  Date::ICal is
95*0Sstevel@tonic-gatean object-oriented module, and that means you start by making an
96*0Sstevel@tonic-gateobject.  So we test C<new()>.
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gate    #!/usr/bin/perl -w
99*0Sstevel@tonic-gate
100*0Sstevel@tonic-gate    use Test::Simple tests => 2;
101*0Sstevel@tonic-gate
102*0Sstevel@tonic-gate    use Date::ICal;
103*0Sstevel@tonic-gate
104*0Sstevel@tonic-gate    my $ical = Date::ICal->new;         # create an object
105*0Sstevel@tonic-gate    ok( defined $ical );                # check that we got something
106*0Sstevel@tonic-gate    ok( $ical->isa('Date::ICal') );     # and it's the right class
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gaterun that and you should get:
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate    1..2
111*0Sstevel@tonic-gate    ok 1
112*0Sstevel@tonic-gate    ok 2
113*0Sstevel@tonic-gate
114*0Sstevel@tonic-gatecongratulations, you've written your first useful test.
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate
117*0Sstevel@tonic-gate=head2 Names
118*0Sstevel@tonic-gate
119*0Sstevel@tonic-gateThat output isn't terribly descriptive, is it?  When you have two
120*0Sstevel@tonic-gatetests you can figure out which one is #2, but what if you have 102?
121*0Sstevel@tonic-gate
122*0Sstevel@tonic-gateEach test can be given a little descriptive name as the second
123*0Sstevel@tonic-gateargument to C<ok()>.
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate    use Test::Simple tests => 2;
126*0Sstevel@tonic-gate
127*0Sstevel@tonic-gate    ok( defined $ical,              'new() returned something' );
128*0Sstevel@tonic-gate    ok( $ical->isa('Date::ICal'),   "  and it's the right class" );
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gateSo now you'd see...
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate    1..2
133*0Sstevel@tonic-gate    ok 1 - new() returned something
134*0Sstevel@tonic-gate    ok 2 -   and it's the right class
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate=head2 Test the manual
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gateSimplest way to build up a decent testing suite is to just test what
140*0Sstevel@tonic-gatethe manual says it does. [3] Let's pull something out of the
141*0Sstevel@tonic-gateL<Date::ICal/SYNOPSIS> and test that all its bits work.
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gate    #!/usr/bin/perl -w
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate    use Test::Simple tests => 8;
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gate    use Date::ICal;
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gate    $ical = Date::ICal->new( year => 1964, month => 10, day => 16,
150*0Sstevel@tonic-gate                             hour => 16, min => 12, sec => 47,
151*0Sstevel@tonic-gate                             tz => '0530' );
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate    ok( defined $ical,            'new() returned something' );
154*0Sstevel@tonic-gate    ok( $ical->isa('Date::ICal'), "  and it's the right class" );
155*0Sstevel@tonic-gate    ok( $ical->sec   == 47,       '  sec()'   );
156*0Sstevel@tonic-gate    ok( $ical->min   == 12,       '  min()'   );
157*0Sstevel@tonic-gate    ok( $ical->hour  == 16,       '  hour()'  );
158*0Sstevel@tonic-gate    ok( $ical->day   == 17,       '  day()'   );
159*0Sstevel@tonic-gate    ok( $ical->month == 10,       '  month()' );
160*0Sstevel@tonic-gate    ok( $ical->year  == 1964,     '  year()'  );
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gaterun that and you get:
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate    1..8
165*0Sstevel@tonic-gate    ok 1 - new() returned something
166*0Sstevel@tonic-gate    ok 2 -   and it's the right class
167*0Sstevel@tonic-gate    ok 3 -   sec()
168*0Sstevel@tonic-gate    ok 4 -   min()
169*0Sstevel@tonic-gate    ok 5 -   hour()
170*0Sstevel@tonic-gate    not ok 6 -   day()
171*0Sstevel@tonic-gate    #     Failed test (- at line 16)
172*0Sstevel@tonic-gate    ok 7 -   month()
173*0Sstevel@tonic-gate    ok 8 -   year()
174*0Sstevel@tonic-gate    # Looks like you failed 1 tests of 8.
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gateWhoops, a failure! [4] Test::Simple helpfully lets us know on what line
177*0Sstevel@tonic-gatethe failure occured, but not much else.  We were supposed to get 17,
178*0Sstevel@tonic-gatebut we didn't.  What did we get??  Dunno.  We'll have to re-run the
179*0Sstevel@tonic-gatetest in the debugger or throw in some print statements to find out.
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gateInstead, we'll switch from B<Test::Simple> to B<Test::More>.  B<Test::More>
182*0Sstevel@tonic-gatedoes everything B<Test::Simple> does, and more!  In fact, Test::More does
183*0Sstevel@tonic-gatethings I<exactly> the way Test::Simple does.  You can literally swap
184*0Sstevel@tonic-gateTest::Simple out and put Test::More in its place.  That's just what
185*0Sstevel@tonic-gatewe're going to do.
186*0Sstevel@tonic-gate
187*0Sstevel@tonic-gateTest::More does more than Test::Simple.  The most important difference
188*0Sstevel@tonic-gateat this point is it provides more informative ways to say "ok".
189*0Sstevel@tonic-gateAlthough you can write almost any test with a generic C<ok()>, it
190*0Sstevel@tonic-gatecan't tell you what went wrong.  Instead, we'll use the C<is()>
191*0Sstevel@tonic-gatefunction, which lets us declare that something is supposed to be the
192*0Sstevel@tonic-gatesame as something else:
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate    #!/usr/bin/perl -w
195*0Sstevel@tonic-gate
196*0Sstevel@tonic-gate    use Test::More tests => 8;
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate    use Date::ICal;
199*0Sstevel@tonic-gate
200*0Sstevel@tonic-gate    $ical = Date::ICal->new( year => 1964, month => 10, day => 16,
201*0Sstevel@tonic-gate                             hour => 16, min => 12, sec => 47,
202*0Sstevel@tonic-gate                             tz => '0530' );
203*0Sstevel@tonic-gate
204*0Sstevel@tonic-gate    ok( defined $ical,            'new() returned something' );
205*0Sstevel@tonic-gate    ok( $ical->isa('Date::ICal'), "  and it's the right class" );
206*0Sstevel@tonic-gate    is( $ical->sec,     47,       '  sec()'   );
207*0Sstevel@tonic-gate    is( $ical->min,     12,       '  min()'   );
208*0Sstevel@tonic-gate    is( $ical->hour,    16,       '  hour()'  );
209*0Sstevel@tonic-gate    is( $ical->day,     17,       '  day()'   );
210*0Sstevel@tonic-gate    is( $ical->month,   10,       '  month()' );
211*0Sstevel@tonic-gate    is( $ical->year,    1964,     '  year()'  );
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate"Is C<$ical-E<gt>sec> 47?"  "Is C<$ical-E<gt>min> 12?"  With C<is()> in place,
214*0Sstevel@tonic-gateyou get some more information
215*0Sstevel@tonic-gate
216*0Sstevel@tonic-gate    1..8
217*0Sstevel@tonic-gate    ok 1 - new() returned something
218*0Sstevel@tonic-gate    ok 2 -   and it's the right class
219*0Sstevel@tonic-gate    ok 3 -   sec()
220*0Sstevel@tonic-gate    ok 4 -   min()
221*0Sstevel@tonic-gate    ok 5 -   hour()
222*0Sstevel@tonic-gate    not ok 6 -   day()
223*0Sstevel@tonic-gate    #     Failed test (- at line 16)
224*0Sstevel@tonic-gate    #          got: '16'
225*0Sstevel@tonic-gate    #     expected: '17'
226*0Sstevel@tonic-gate    ok 7 -   month()
227*0Sstevel@tonic-gate    ok 8 -   year()
228*0Sstevel@tonic-gate    # Looks like you failed 1 tests of 8.
229*0Sstevel@tonic-gate
230*0Sstevel@tonic-gateletting us know that C<$ical-E<gt>day> returned 16, but we expected 17.  A
231*0Sstevel@tonic-gatequick check shows that the code is working fine, we made a mistake
232*0Sstevel@tonic-gatewhen writing up the tests.  Just change it to:
233*0Sstevel@tonic-gate
234*0Sstevel@tonic-gate    is( $ical->day,     16,       '  day()'   );
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gateand everything works.
237*0Sstevel@tonic-gate
238*0Sstevel@tonic-gateSo any time you're doing a "this equals that" sort of test, use C<is()>.
239*0Sstevel@tonic-gateIt even works on arrays.  The test is always in scalar context, so you
240*0Sstevel@tonic-gatecan test how many elements are in a list this way. [5]
241*0Sstevel@tonic-gate
242*0Sstevel@tonic-gate    is( @foo, 5, 'foo has 5 elements' );
243*0Sstevel@tonic-gate
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate=head2 Sometimes the tests are wrong
246*0Sstevel@tonic-gate
247*0Sstevel@tonic-gateWhich brings us to a very important lesson.  Code has bugs.  Tests are
248*0Sstevel@tonic-gatecode.  Ergo, tests have bugs.  A failing test could mean a bug in the
249*0Sstevel@tonic-gatecode, but don't discount the possibility that the test is wrong.
250*0Sstevel@tonic-gate
251*0Sstevel@tonic-gateOn the flip side, don't be tempted to prematurely declare a test
252*0Sstevel@tonic-gateincorrect just because you're having trouble finding the bug.
253*0Sstevel@tonic-gateInvalidating a test isn't something to be taken lightly, and don't use
254*0Sstevel@tonic-gateit as a cop out to avoid work.
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate=head2 Testing lots of values
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gateWe're going to be wanting to test a lot of dates here, trying to trick
260*0Sstevel@tonic-gatethe code with lots of different edge cases.  Does it work before 1970?
261*0Sstevel@tonic-gateAfter 2038?  Before 1904?  Do years after 10,000 give it trouble?
262*0Sstevel@tonic-gateDoes it get leap years right?  We could keep repeating the code above,
263*0Sstevel@tonic-gateor we could set up a little try/expect loop.
264*0Sstevel@tonic-gate
265*0Sstevel@tonic-gate    use Test::More tests => 32;
266*0Sstevel@tonic-gate    use Date::ICal;
267*0Sstevel@tonic-gate
268*0Sstevel@tonic-gate    my %ICal_Dates = (
269*0Sstevel@tonic-gate            # An ICal string     And the year, month, date
270*0Sstevel@tonic-gate            #                    hour, minute and second we expect.
271*0Sstevel@tonic-gate            '19971024T120000' =>    # from the docs.
272*0Sstevel@tonic-gate                                [ 1997, 10, 24, 12,  0,  0 ],
273*0Sstevel@tonic-gate            '20390123T232832' =>    # after the Unix epoch
274*0Sstevel@tonic-gate                                [ 2039,  1, 23, 23, 28, 32 ],
275*0Sstevel@tonic-gate            '19671225T000000' =>    # before the Unix epoch
276*0Sstevel@tonic-gate                                [ 1967, 12, 25,  0,  0,  0 ],
277*0Sstevel@tonic-gate            '18990505T232323' =>    # before the MacOS epoch
278*0Sstevel@tonic-gate                                [ 1899,  5,  5, 23, 23, 23 ],
279*0Sstevel@tonic-gate    );
280*0Sstevel@tonic-gate
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate    while( my($ical_str, $expect) = each %ICal_Dates ) {
283*0Sstevel@tonic-gate        my $ical = Date::ICal->new( ical => $ical_str );
284*0Sstevel@tonic-gate
285*0Sstevel@tonic-gate        ok( defined $ical,            "new(ical => '$ical_str')" );
286*0Sstevel@tonic-gate        ok( $ical->isa('Date::ICal'), "  and it's the right class" );
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate        is( $ical->year,    $expect->[0],     '  year()'  );
289*0Sstevel@tonic-gate        is( $ical->month,   $expect->[1],     '  month()' );
290*0Sstevel@tonic-gate        is( $ical->day,     $expect->[2],     '  day()'   );
291*0Sstevel@tonic-gate        is( $ical->hour,    $expect->[3],     '  hour()'  );
292*0Sstevel@tonic-gate        is( $ical->min,     $expect->[4],     '  min()'   );
293*0Sstevel@tonic-gate        is( $ical->sec,     $expect->[5],     '  sec()'   );
294*0Sstevel@tonic-gate    }
295*0Sstevel@tonic-gate
296*0Sstevel@tonic-gateSo now we can test bunches of dates by just adding them to
297*0Sstevel@tonic-gateC<%ICal_Dates>.  Now that it's less work to test with more dates, you'll
298*0Sstevel@tonic-gatebe inclined to just throw more in as you think of them.
299*0Sstevel@tonic-gateOnly problem is, every time we add to that we have to keep adjusting
300*0Sstevel@tonic-gatethe C<use Test::More tests =E<gt> ##> line.  That can rapidly get
301*0Sstevel@tonic-gateannoying.  There's two ways to make this work better.
302*0Sstevel@tonic-gate
303*0Sstevel@tonic-gateFirst, we can calculate the plan dynamically using the C<plan()>
304*0Sstevel@tonic-gatefunction.
305*0Sstevel@tonic-gate
306*0Sstevel@tonic-gate    use Test::More;
307*0Sstevel@tonic-gate    use Date::ICal;
308*0Sstevel@tonic-gate
309*0Sstevel@tonic-gate    my %ICal_Dates = (
310*0Sstevel@tonic-gate        ...same as before...
311*0Sstevel@tonic-gate    );
312*0Sstevel@tonic-gate
313*0Sstevel@tonic-gate    # For each key in the hash we're running 8 tests.
314*0Sstevel@tonic-gate    plan tests => keys %ICal_Dates * 8;
315*0Sstevel@tonic-gate
316*0Sstevel@tonic-gateOr to be even more flexible, we use C<no_plan>.  This means we're just
317*0Sstevel@tonic-gaterunning some tests, don't know how many. [6]
318*0Sstevel@tonic-gate
319*0Sstevel@tonic-gate    use Test::More 'no_plan';   # instead of tests => 32
320*0Sstevel@tonic-gate
321*0Sstevel@tonic-gatenow we can just add tests and not have to do all sorts of math to
322*0Sstevel@tonic-gatefigure out how many we're running.
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate
325*0Sstevel@tonic-gate=head2 Informative names
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gateTake a look at this line here
328*0Sstevel@tonic-gate
329*0Sstevel@tonic-gate    ok( defined $ical,            "new(ical => '$ical_str')" );
330*0Sstevel@tonic-gate
331*0Sstevel@tonic-gatewe've added more detail about what we're testing and the ICal string
332*0Sstevel@tonic-gateitself we're trying out to the name.  So you get results like:
333*0Sstevel@tonic-gate
334*0Sstevel@tonic-gate    ok 25 - new(ical => '19971024T120000')
335*0Sstevel@tonic-gate    ok 26 -   and it's the right class
336*0Sstevel@tonic-gate    ok 27 -   year()
337*0Sstevel@tonic-gate    ok 28 -   month()
338*0Sstevel@tonic-gate    ok 29 -   day()
339*0Sstevel@tonic-gate    ok 30 -   hour()
340*0Sstevel@tonic-gate    ok 31 -   min()
341*0Sstevel@tonic-gate    ok 32 -   sec()
342*0Sstevel@tonic-gate
343*0Sstevel@tonic-gateif something in there fails, you'll know which one it was and that
344*0Sstevel@tonic-gatewill make tracking down the problem easier.  So try to put a bit of
345*0Sstevel@tonic-gatedebugging information into the test names.
346*0Sstevel@tonic-gate
347*0Sstevel@tonic-gateDescribe what the tests test, to make debugging a failed test easier
348*0Sstevel@tonic-gatefor you or for the next person who runs your test.
349*0Sstevel@tonic-gate
350*0Sstevel@tonic-gate
351*0Sstevel@tonic-gate=head2 Skipping tests
352*0Sstevel@tonic-gate
353*0Sstevel@tonic-gatePoking around in the existing Date::ICal tests, I found this in
354*0Sstevel@tonic-gateF<t/01sanity.t> [7]
355*0Sstevel@tonic-gate
356*0Sstevel@tonic-gate    #!/usr/bin/perl -w
357*0Sstevel@tonic-gate
358*0Sstevel@tonic-gate    use Test::More tests => 7;
359*0Sstevel@tonic-gate    use Date::ICal;
360*0Sstevel@tonic-gate
361*0Sstevel@tonic-gate    # Make sure epoch time is being handled sanely.
362*0Sstevel@tonic-gate    my $t1 = Date::ICal->new( epoch => 0 );
363*0Sstevel@tonic-gate    is( $t1->epoch, 0,          "Epoch time of 0" );
364*0Sstevel@tonic-gate
365*0Sstevel@tonic-gate    # XXX This will only work on unix systems.
366*0Sstevel@tonic-gate    is( $t1->ical, '19700101Z', "  epoch to ical" );
367*0Sstevel@tonic-gate
368*0Sstevel@tonic-gate    is( $t1->year,  1970,       "  year()"  );
369*0Sstevel@tonic-gate    is( $t1->month, 1,          "  month()" );
370*0Sstevel@tonic-gate    is( $t1->day,   1,          "  day()"   );
371*0Sstevel@tonic-gate
372*0Sstevel@tonic-gate    # like the tests above, but starting with ical instead of epoch
373*0Sstevel@tonic-gate    my $t2 = Date::ICal->new( ical => '19700101Z' );
374*0Sstevel@tonic-gate    is( $t2->ical, '19700101Z', "Start of epoch in ICal notation" );
375*0Sstevel@tonic-gate
376*0Sstevel@tonic-gate    is( $t2->epoch, 0,          "  and back to ICal" );
377*0Sstevel@tonic-gate
378*0Sstevel@tonic-gateThe beginning of the epoch is different on most non-Unix operating
379*0Sstevel@tonic-gatesystems [8].  Even though Perl smooths out the differences for the most
380*0Sstevel@tonic-gatepart, certain ports do it differently.  MacPerl is one off the top of
381*0Sstevel@tonic-gatemy head. [9] We I<know> this will never work on MacOS.  So rather than
382*0Sstevel@tonic-gatejust putting a comment in the test, we can explicitly say it's never
383*0Sstevel@tonic-gategoing to work and skip the test.
384*0Sstevel@tonic-gate
385*0Sstevel@tonic-gate    use Test::More tests => 7;
386*0Sstevel@tonic-gate    use Date::ICal;
387*0Sstevel@tonic-gate
388*0Sstevel@tonic-gate    # Make sure epoch time is being handled sanely.
389*0Sstevel@tonic-gate    my $t1 = Date::ICal->new( epoch => 0 );
390*0Sstevel@tonic-gate    is( $t1->epoch, 0,          "Epoch time of 0" );
391*0Sstevel@tonic-gate
392*0Sstevel@tonic-gate    SKIP: {
393*0Sstevel@tonic-gate        skip('epoch to ICal not working on MacOS', 6)
394*0Sstevel@tonic-gate            if $^O eq 'MacOS';
395*0Sstevel@tonic-gate
396*0Sstevel@tonic-gate        is( $t1->ical, '19700101Z', "  epoch to ical" );
397*0Sstevel@tonic-gate
398*0Sstevel@tonic-gate        is( $t1->year,  1970,       "  year()"  );
399*0Sstevel@tonic-gate        is( $t1->month, 1,          "  month()" );
400*0Sstevel@tonic-gate        is( $t1->day,   1,          "  day()"   );
401*0Sstevel@tonic-gate
402*0Sstevel@tonic-gate        # like the tests above, but starting with ical instead of epoch
403*0Sstevel@tonic-gate        my $t2 = Date::ICal->new( ical => '19700101Z' );
404*0Sstevel@tonic-gate        is( $t2->ical, '19700101Z', "Start of epoch in ICal notation" );
405*0Sstevel@tonic-gate
406*0Sstevel@tonic-gate        is( $t2->epoch, 0,          "  and back to ICal" );
407*0Sstevel@tonic-gate    }
408*0Sstevel@tonic-gate
409*0Sstevel@tonic-gateA little bit of magic happens here.  When running on anything but
410*0Sstevel@tonic-gateMacOS, all the tests run normally.  But when on MacOS, C<skip()> causes
411*0Sstevel@tonic-gatethe entire contents of the SKIP block to be jumped over.  It's never
412*0Sstevel@tonic-gaterun.  Instead, it prints special output that tells Test::Harness that
413*0Sstevel@tonic-gatethe tests have been skipped.
414*0Sstevel@tonic-gate
415*0Sstevel@tonic-gate    1..7
416*0Sstevel@tonic-gate    ok 1 - Epoch time of 0
417*0Sstevel@tonic-gate    ok 2 # skip epoch to ICal not working on MacOS
418*0Sstevel@tonic-gate    ok 3 # skip epoch to ICal not working on MacOS
419*0Sstevel@tonic-gate    ok 4 # skip epoch to ICal not working on MacOS
420*0Sstevel@tonic-gate    ok 5 # skip epoch to ICal not working on MacOS
421*0Sstevel@tonic-gate    ok 6 # skip epoch to ICal not working on MacOS
422*0Sstevel@tonic-gate    ok 7 # skip epoch to ICal not working on MacOS
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gateThis means your tests won't fail on MacOS.  This means less emails
425*0Sstevel@tonic-gatefrom MacPerl users telling you about failing tests that you know will
426*0Sstevel@tonic-gatenever work.  You've got to be careful with skip tests.  These are for
427*0Sstevel@tonic-gatetests which don't work and I<never will>.  It is not for skipping
428*0Sstevel@tonic-gategenuine bugs (we'll get to that in a moment).
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gateThe tests are wholly and completely skipped. [10]  This will work.
431*0Sstevel@tonic-gate
432*0Sstevel@tonic-gate    SKIP: {
433*0Sstevel@tonic-gate        skip("I don't wanna die!");
434*0Sstevel@tonic-gate
435*0Sstevel@tonic-gate        die, die, die, die, die;
436*0Sstevel@tonic-gate    }
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gate
439*0Sstevel@tonic-gate=head2 Todo tests
440*0Sstevel@tonic-gate
441*0Sstevel@tonic-gateThumbing through the Date::ICal man page, I came across this:
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate   ical
444*0Sstevel@tonic-gate
445*0Sstevel@tonic-gate       $ical_string = $ical->ical;
446*0Sstevel@tonic-gate
447*0Sstevel@tonic-gate   Retrieves, or sets, the date on the object, using any
448*0Sstevel@tonic-gate   valid ICal date/time string.
449*0Sstevel@tonic-gate
450*0Sstevel@tonic-gate"Retrieves or sets".  Hmmm, didn't see a test for using C<ical()> to set
451*0Sstevel@tonic-gatethe date in the Date::ICal test suite.  So I'll write one.
452*0Sstevel@tonic-gate
453*0Sstevel@tonic-gate    use Test::More tests => 1;
454*0Sstevel@tonic-gate    use Date::ICal;
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate    my $ical = Date::ICal->new;
457*0Sstevel@tonic-gate    $ical->ical('20201231Z');
458*0Sstevel@tonic-gate    is( $ical->ical, '20201231Z',   'Setting via ical()' );
459*0Sstevel@tonic-gate
460*0Sstevel@tonic-gaterun that and I get
461*0Sstevel@tonic-gate
462*0Sstevel@tonic-gate    1..1
463*0Sstevel@tonic-gate    not ok 1 - Setting via ical()
464*0Sstevel@tonic-gate    #     Failed test (- at line 6)
465*0Sstevel@tonic-gate    #          got: '20010814T233649Z'
466*0Sstevel@tonic-gate    #     expected: '20201231Z'
467*0Sstevel@tonic-gate    # Looks like you failed 1 tests of 1.
468*0Sstevel@tonic-gate
469*0Sstevel@tonic-gateWhoops!  Looks like it's unimplemented.  Let's assume we don't have
470*0Sstevel@tonic-gatethe time to fix this. [11] Normally, you'd just comment out the test
471*0Sstevel@tonic-gateand put a note in a todo list somewhere.  Instead, we're going to
472*0Sstevel@tonic-gateexplicitly state "this test will fail" by wrapping it in a C<TODO> block.
473*0Sstevel@tonic-gate
474*0Sstevel@tonic-gate    use Test::More tests => 1;
475*0Sstevel@tonic-gate
476*0Sstevel@tonic-gate    TODO: {
477*0Sstevel@tonic-gate        local $TODO = 'ical($ical) not yet implemented';
478*0Sstevel@tonic-gate
479*0Sstevel@tonic-gate        my $ical = Date::ICal->new;
480*0Sstevel@tonic-gate        $ical->ical('20201231Z');
481*0Sstevel@tonic-gate
482*0Sstevel@tonic-gate        is( $ical->ical, '20201231Z',   'Setting via ical()' );
483*0Sstevel@tonic-gate    }
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gateNow when you run, it's a little different:
486*0Sstevel@tonic-gate
487*0Sstevel@tonic-gate    1..1
488*0Sstevel@tonic-gate    not ok 1 - Setting via ical() # TODO ical($ical) not yet implemented
489*0Sstevel@tonic-gate    #          got: '20010822T201551Z'
490*0Sstevel@tonic-gate    #     expected: '20201231Z'
491*0Sstevel@tonic-gate
492*0Sstevel@tonic-gateTest::More doesn't say "Looks like you failed 1 tests of 1".  That '#
493*0Sstevel@tonic-gateTODO' tells Test::Harness "this is supposed to fail" and it treats a
494*0Sstevel@tonic-gatefailure as a successful test.  So you can write tests even before
495*0Sstevel@tonic-gateyou've fixed the underlying code.
496*0Sstevel@tonic-gate
497*0Sstevel@tonic-gateIf a TODO test passes, Test::Harness will report it "UNEXPECTEDLY
498*0Sstevel@tonic-gateSUCCEEDED".  When that happens, you simply remove the TODO block with
499*0Sstevel@tonic-gateC<local $TODO> and turn it into a real test.
500*0Sstevel@tonic-gate
501*0Sstevel@tonic-gate
502*0Sstevel@tonic-gate=head2 Testing with taint mode.
503*0Sstevel@tonic-gate
504*0Sstevel@tonic-gateTaint mode is a funny thing.  It's the globalest of all global
505*0Sstevel@tonic-gatefeatures.  Once you turn it on it effects I<all> code in your program
506*0Sstevel@tonic-gateand I<all> modules used (and all the modules they use).  If a single
507*0Sstevel@tonic-gatepiece of code isn't taint clean, the whole thing explodes.  With that
508*0Sstevel@tonic-gatein mind, it's very important to ensure your module works under taint
509*0Sstevel@tonic-gatemode.
510*0Sstevel@tonic-gate
511*0Sstevel@tonic-gateIt's very simple to have your tests run under taint mode.  Just throw
512*0Sstevel@tonic-gatea C<-T> into the C<#!> line.  Test::Harness will read the switches
513*0Sstevel@tonic-gatein C<#!> and use them to run your tests.
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate    #!/usr/bin/perl -Tw
516*0Sstevel@tonic-gate
517*0Sstevel@tonic-gate    use Test::More 'no_plan';
518*0Sstevel@tonic-gate
519*0Sstevel@tonic-gate    ...test normally here...
520*0Sstevel@tonic-gate
521*0Sstevel@tonic-gateSo when you say C<make test> it will be run with taint mode and
522*0Sstevel@tonic-gatewarnings on.
523*0Sstevel@tonic-gate
524*0Sstevel@tonic-gate
525*0Sstevel@tonic-gate=head1 FOOTNOTES
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gate=over 4
528*0Sstevel@tonic-gate
529*0Sstevel@tonic-gate=item 1
530*0Sstevel@tonic-gate
531*0Sstevel@tonic-gateThe first number doesn't really mean anything, but it has to be 1.
532*0Sstevel@tonic-gateIt's the second number that's important.
533*0Sstevel@tonic-gate
534*0Sstevel@tonic-gate=item 2
535*0Sstevel@tonic-gate
536*0Sstevel@tonic-gateFor those following along at home, I'm using version 1.31.  It has
537*0Sstevel@tonic-gatesome bugs, which is good -- we'll uncover them with our tests.
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate=item 3
540*0Sstevel@tonic-gate
541*0Sstevel@tonic-gateYou can actually take this one step further and test the manual
542*0Sstevel@tonic-gateitself.  Have a look at B<Test::Inline> (formerly B<Pod::Tests>).
543*0Sstevel@tonic-gate
544*0Sstevel@tonic-gate=item 4
545*0Sstevel@tonic-gate
546*0Sstevel@tonic-gateYes, there's a mistake in the test suite.  What!  Me, contrived?
547*0Sstevel@tonic-gate
548*0Sstevel@tonic-gate=item 5
549*0Sstevel@tonic-gate
550*0Sstevel@tonic-gateWe'll get to testing the contents of lists later.
551*0Sstevel@tonic-gate
552*0Sstevel@tonic-gate=item 6
553*0Sstevel@tonic-gate
554*0Sstevel@tonic-gateBut what happens if your test program dies halfway through?!  Since we
555*0Sstevel@tonic-gatedidn't say how many tests we're going to run, how can we know it
556*0Sstevel@tonic-gatefailed?  No problem, Test::More employs some magic to catch that death
557*0Sstevel@tonic-gateand turn the test into a failure, even if every test passed up to that
558*0Sstevel@tonic-gatepoint.
559*0Sstevel@tonic-gate
560*0Sstevel@tonic-gate=item 7
561*0Sstevel@tonic-gate
562*0Sstevel@tonic-gateI cleaned it up a little.
563*0Sstevel@tonic-gate
564*0Sstevel@tonic-gate=item 8
565*0Sstevel@tonic-gate
566*0Sstevel@tonic-gateMost Operating Systems record time as the number of seconds since a
567*0Sstevel@tonic-gatecertain date.  This date is the beginning of the epoch.  Unix's starts
568*0Sstevel@tonic-gateat midnight January 1st, 1970 GMT.
569*0Sstevel@tonic-gate
570*0Sstevel@tonic-gate=item 9
571*0Sstevel@tonic-gate
572*0Sstevel@tonic-gateMacOS's epoch is midnight January 1st, 1904.  VMS's is midnight,
573*0Sstevel@tonic-gateNovember 17th, 1858, but vmsperl emulates the Unix epoch so it's not a
574*0Sstevel@tonic-gateproblem.
575*0Sstevel@tonic-gate
576*0Sstevel@tonic-gate=item 10
577*0Sstevel@tonic-gate
578*0Sstevel@tonic-gateAs long as the code inside the SKIP block at least compiles.  Please
579*0Sstevel@tonic-gatedon't ask how.  No, it's not a filter.
580*0Sstevel@tonic-gate
581*0Sstevel@tonic-gate=item 11
582*0Sstevel@tonic-gate
583*0Sstevel@tonic-gateDo NOT be tempted to use TODO tests as a way to avoid fixing simple
584*0Sstevel@tonic-gatebugs!
585*0Sstevel@tonic-gate
586*0Sstevel@tonic-gate=back
587*0Sstevel@tonic-gate
588*0Sstevel@tonic-gate=head1 AUTHORS
589*0Sstevel@tonic-gate
590*0Sstevel@tonic-gateMichael G Schwern E<lt>schwern@pobox.comE<gt> and the perl-qa dancers!
591*0Sstevel@tonic-gate
592*0Sstevel@tonic-gate=head1 COPYRIGHT
593*0Sstevel@tonic-gate
594*0Sstevel@tonic-gateCopyright 2001 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gateThis documentation is free; you can redistribute it and/or modify it
597*0Sstevel@tonic-gateunder the same terms as Perl itself.
598*0Sstevel@tonic-gate
599*0Sstevel@tonic-gateIrrespective of its distribution, all code examples in these files
600*0Sstevel@tonic-gateare hereby placed into the public domain.  You are permitted and
601*0Sstevel@tonic-gateencouraged to use this code in your own programs for fun
602*0Sstevel@tonic-gateor for profit as you see fit.  A simple comment in the code giving
603*0Sstevel@tonic-gatecredit would be courteous but is not required.
604*0Sstevel@tonic-gate
605*0Sstevel@tonic-gate=cut
606