How to add trace output to unit tests?

Is there a way to have a successful test output a message?

This unit test:

test(foo1) :-
    format(user_error, '>>>I am here>>>~n', []).

outputs nothing.

But these tests output the message:

test(foo2, fail) :-
    format(user_error, '>>>I am here>>>~n', []).
test(foo3) :-
    format(user_error, '>>>I am here>>>~n', []),
    fail.

(Why am I doing this? Because - until plunit is improved (there’s a separate thread on this) - it’s useful for me to output some tracing messages from my tests to isolate which test is crashing.)

A related question: I noticed that plunit.pl has this:

with_output_to(string(Output), Goal,
                       [ capture([user_output, user_error])])

but the capture option doesn’t seem to be described in the documentation for with_output_to/2.

1 Like

That is one of the things the next iteration must address. You can hack this on older versions by hooking e.g.

print_message(silent, plunit(begin(Unit:Test, File:Line, STO)))

Because it calls with_output_to/3 :slight_smile: That is not picked up by the doc system yet, but is in library(streams). Before you try, this does not work for C(++) stdout output, only for Prolog I/O and foreign I/O that uses the SWI-Stream.h I/O functions.

In the other thread where I noted the GUI test runners, they show each test run and typically change color of the test to green if the test succeeds and color the test red if the test fails.

image

(Image from Wikipedia CsUnit).

Most GUI test runners include the console output of the test run as some test cases will create a stack trace that is sent to the console instead of being captured for the test.

Another nice feature that many of the GUI test runners have is the ability to run subsets of the test, e.g. only failed test. The really nice ones will not only show failed test but by clicking on the failed test will start the build environment and then take you to the line of code in the editor.

As I noted I only used one of these GUI test runners extensively with F# so don’t know how many of these features were hard coded to work with F# and Visual Studio, not to be confused with Visual Studio Code.

Another workaround is to use Sdprintf() in a trivial foreign predicate.

/* ffi_term_chars must be called inside a PL_STRINGS_{MARK,RELEASE} */
static
const char *ffi_term_chars(term_t t)
{ char *s;
  int nchars_rc;
  if ( !t )
    return "<null-term>";
  nchars_rc = PL_get_nchars(t, NULL, &s, CVT_ALL|CVT_WRITEQ|BUF_STACK|CVT_EXCEPTION);
  if ( nchars_rc )
    return s;
  { static char s_x[100]; /* TODO: this is non-reentrant */
    sprintf(s_x, "<unknown term: %lu>", (unsigned long)t);
    return s_x;
  }
}

static foreign_t
sdprintf_(term_t t)
{ PL_STRINGS_MARK();
    Sdprintf("%s", ffi_term_chars(t));
  PL_STRINGS_RELEASE();
  return TRUE;
}

We also have PL_write_term(). I see it was not documented. Added (simple) documentation. It is a bit easier though:

PL_write_term(Serror, t, 1200, PL_WRT_QUOTED);

There are a lot of flags, covering most of what write_term/2 supports.