Michael G Schwern wrote:
> On Mon, Dec 06, 2004 at 10:00:32AM -0000, Clayton, Nik wrote:
>> Then you have one of ok() or ok2() at your disposal. ok()'s first
>> parameter is the code to test.  The second parameter is the test name. 
>> This is a printf()like format string, and the third and subsequent
>> parameters should fill out any values in the string.
>> 
>>     ok(a_func() == 0, "test name");
>>     ok(some_func(i), "some_func(%d)", i);
> 
> Why add that extra auto-sprintf complexity?  Can't the user
> do the exact same thing with:
> 
>       ok(some_func(i), sprintf("some_func(%d)", i));

Yes they can.  It was just an easy feature to add.

> Making the test name a sprintf string can complicate things
> if they want to do formatting themselves, they have the extra problem of
> escaping their result for sprintf.
> 
> Also, folks putting in bare strings might be surprised.
> 
>       ok( tax(.05), "taxing at 5%" );

True.  I'll take this under advisement. :-)

>> ok2() is for situations where the code to test is sufficiently
>> self-documenting that you don't need to provide a test name.
>> 
>>     ok2(code to test); /* test name is automatically the same as the
>> code */ 
>> 
>> E.g.,
>> 
>>     ok(1 == 1, "1 equals one"); /* PRINT: ok 1 - 1 equals 1 */
>>     ok2(1 == 2);                /* PRINT: not ok 2 - 1 == 2 */
> 
> Why the split?  You can do variable length argument lists in C.

Right.  And this may be my ignorance showing here, but as I understand
it, if you do that you must have an argument that hints at how many optional
arguments are present.

There's no way to tell from the first argument whether or not the second
argument exists.  If it doesn't exist you can't even safely check for its
existence.

To give a printf() example, something like this:

    int n = 42;
    printf("%d %d\n", n);

will fail, because you haven't supplied enough arguments.  printf() will
fail off the end of its argument list and segfault.

>> This is normally implemented with a "do { ... } while(0);" loop, with a
>> "continue;" immediately after the skip() call.  This ensures that there
>> are no additional side effects from the skipped tests.
>> 
>>     do {
>>         if(getuid() != 0) {
>>             skip(1, "Test only makes sense as root");            
>>         continue; }
>> 
>>         ok(do_something_as_root() == 0,
> "do_something_as_root() worked");
>>     } while(0);
> 
> It might make more sense to do this.
> 
>       if( getuid() != 0 ) {
>           skip(1, "Test only makes sense as root");
>       }
>       else {
>           ok(do_something_as_root() == 0,
> "do_something_as_root() worked");
>       }
> 
> I'm becoming less and less happy with the way skip is implemented in
> Test::More. 

The user can do either.  I'll document the approaches as being equivalent.

>> Two macros, SKIP_START and SKIP_END can handle some of this for you.  The
>> above example could be re-written:
>> 
>>     SKIP_START(getuid() != 0, 1, "Test only makes sense as root");
>> 
>>     ok(do_something_as_root() == 0, "do_something_as_root() worked");
>> 
>>     SKIP_END;
> 
> That's pretty cool.  Does it work with loops?  What if in that SKIP section
> somebody calls a routine which then calls ok()?

SKIP_START and SKIP_END are macros that encapsulate the "do { ... } while(0)"
logic, nothing more, designed to handle the common case effectively.  They're
in tap.h

>> You also have diag(), which takes a printf() style format string and
>> related arguments, and sends the output to stderr as a test comment. 
>> diag() adds the necessary trailing "\n" for you.
>> 
>>     diag("Expected return code 0, got return code %d", rcode);
> 
> Don't forget about adding the # comment on the front of each line.

Yep, the code does that.

>> Finally, there's exit_status(), which returns an int suitable for use
>> when return'ing from main(), or calling exit().  You should always do
>> one of: 
>> 
>>     return exit_status();
>>     exit(exit_status());
> 
> What is this for?  <--- possible C ignorance

> I hope you're not emulating Test::More's exit code == # of
> tests failed "feature" that I'm planning on getting rid of.

Right now that's exactly what I'm doing.  The test suite for libtap 
consists of a series of Test::More test files and a series of C files that
try and test exactly the same thing.

For each one of these I make sure that the output from libtap is identical
to the output from Test::More (modulo differences in reporting which 
file/line a test failed on) and that the exit code is identical.

exit_status() is required to do this, since a library can't intercept all
the ways a program might exit *and* change the exit code (again, AFAIK).

N
-- 
1        1         2         3         4         5         6         7    7
         0         0         0         0         0         0         0    5
                                                    -- The 75 column-ometer
Not speaking on behalf of my employer.                              </bush>

Reply via email to