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