Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Testing Files and Test Modules
by Phil Crow | Pages: 1, 2, 3

Directory Contents

If knowing that certain file names are present is not enough, use the compare_dirs_ok function to check the contents of all files in one directory against files in another directory. A typical module might build one directory during make test, with the other built ahead of time and shipped with the distribution.

compare_dirs_ok($test_built, $shipped, $name);

This will generate a separate diagnostic diff output for each pair of files that differs, in addition to listing files that are missing from either distribution. (If you need to know which files are missing from the built directory, either reverse the order of the directories or use dir_only_contains_ok in addition to compare_dirs_ok. This is a bug and might eventually be fixed.) Even though this could yield many diagnostic reports, all of those separate failures only count as one failed test.

There are many times when testing all files in the directories is just wrong. In these cases, it is best to use File::Find or an equivalent, putting an exclusion criterion at the top of your wanted function and a call to compare_ok at the bottom. This probably requires you to use no_plan with Test::More:

use Test::More qw(no_plan);

Test::More wants to know the exact number of tests you are about to run. If you tell it the wrong number, the test harness will think something is wrong with your test script, causing it to report failures. To avoid this confusion, use no_plan--but keep in mind that plans are there for a reason. If your test dies, the plan lets the harness know how many tests it missed. If you have no_plan, the harness doesn't always have enough information to keep score. Thus, you should put such tests in separate scripts, so that the harness can count your other tests properly.

Filtering

While the above list of functions seemed sufficient during planning, reality set in as soon as I tried it out on my CVS module. I wanted to compare two CVS repositories: one ready for shipment with the distribution, the other built during testing. As soon as I tried the test it failed, not because the operative parts of the module were not working, but because the CVS timestamps differed between the two versions.

To deal with cosmetic differences that should not count as failures, I added two functions to the above list: one for single files and the other for directories. These new functions accept a code reference that receives each line prior to comparison. It performs any needed alterations, and then returns a line suitable for comparison. My example function below redacts the offending timestamps. With the filtered versions in place, the tests pass and fail when they should.

My final tests for the CVS repository directories look like this:

compare_dirs_filter_ok(
    't/cvsroot/CVSROOT',
    't/sampleroot/CVSROOT',
    \&chop_dates,
    "make repo"
);

The code reference argument comes between the directory names and the test name. The chop_dates function is not particularly complex. It removes two kinds of dates favored by CVS, as shown in its comments.

sub chop_dates {
    my $line =  shift;

    #  2003.10.15.13.45.57 (year month day hour minute sec)
    $line    =~ s/\d{4}(.\d\d){5}//;

    #  Thu Oct 16 18:00:28 2003
    $line    =~ s/\w{3} \w{3} \d\d? \d\d:\d\d:\d\d \d{4}//;

    return $line;
}

This shows the general behavior of filters. They receive a line of input which they must not directly change. Instead, they must return a new, corrected line.

In addition to compare_dirs_filter_ok for whole directory structures, there is also compare_filter_ok, which works similarly for single file comparisons. (There is no file_filter_ok, but maybe there should be.)

Pages: 1, 2, 3

Next Pagearrow