Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faster way of testing your prolog program

Tags:

testing

prolog

I am new to Prolog, and the task of launching the prolog interpreter from the terminal, typing consult('some_prolog_program.pl'), and then testing the predicate you just wrote is very time consuming, is there a way to run a scripted test to speed up development?

For example in C I can write a main where I would use the functions I defined, I can then execute:

make && ./a.out

to test the code, can I do something similar with Prolog?

like image 964
chutsu Avatar asked Nov 28 '11 10:11

chutsu


4 Answers

  1. You can have the interpreter always open and then recompile the file.

  2. You can auto-run a predicate after compiling the file:

    :- foo(4,2).
    

    This will run foo(4,2) when the line is encountered in the file.

  3. There are flags that can be used while launching (most) Prolog interpreters that allow you to compile a file and run predicates (check the man page). This way you could make a Bash script. The following will consult file.pl and run foo/0 using SWI-Prolog:

    #!/bin/sh
    exec swipl -q  -f none -g "load_files([file],[silent(true)])" \
               -t foo -- $*
    

    This predicate will unify Arguments with a list of the flags you gave at the command line:

    current_prolog_flag(argv, Arguments)
    

    But unless you are going to run a lot of tests, I don't think that writing all this extra code will be faster.

Personally I really like the flexibility of testing any predicate at any time with or without tracing (see trace/0) without having to write extra code to call them (unlike in C).

P.S. about reloading the file without leaving the interpreter: You might have some problem if you have used dynamic predicates or global variables; you will have to do some cleaning.

like image 177
Thanos Tintinidis Avatar answered Oct 19 '22 00:10

Thanos Tintinidis


You can invoke a test file from the command-line with prolog +l <file>

Also, you can build a single run_tests predicate that exercises a series of calls and validates the actual results against expected results. Here's an article with a good worked-out example: http://kenegozi.com/blog/2008/07/24/unit-testing-in-prolog

like image 37
Raymond Hettinger Avatar answered Oct 19 '22 01:10

Raymond Hettinger


In SWI, you can load things as usual. Then, when you edit your files you simply say make. on the toplevel and it checks all dependencies automatically and only reloads the modified files.

For bigger projects it does make a lot of sense to use makefiles. In particular to do unit testing. See SWI's package plunit.

like image 2
false Avatar answered Oct 19 '22 01:10

false


For simple scripts in SWI-Prolog, using REPL to test the code manually is usually good enough. Changed files can be reloaded via make/0 (?- make. on toplevel). Just keep the Prolog REPL running while editing, then save the edits, run make. in the REPL and hit , , Enter to execute the last query before the make. from history.

The main benefit of REPL is its interactivity:

  • You may fiddle with the arguments.

  • Transition to debugging or tracing (both command line and graphical) is easy.

  • You don't need to perform I/O to print the result. Output is handled by the toplevel, which prints the substitution. You see the whole substitution, not only its part you just happen to print (possibly accidentally overlooking other parts).

  • You may interactively choose how many substitutions you want to see for a goal that succeeds multiple times.

  • It is obvious if there is a choice point left after the last result returned by a non-deterministic predicate, which is hard to observe otherwise. In that case, false. is printed when backtracking beyond the last result.

If you need to preserve the test calls to repeat them later, create a protocol (transcript or "log" of the interactive session) and edit it to become a script, or even a test suite (see below). The protocol is a plain text file with escape sequences for the terminal, containing a verbatim copy of what you see during the interactive session. View the protocol using cat protocol.txt on Linux (and other *NIXes) or type protocol.txt on Windows.

If interactivity is not needed, perform the test calls from the command line non-interactively. Let's test the CLP(FD) factorial example n_factorial/2, saved in factorial.pl (don't forget to add :- use_module(library(clpfd)). when copying the code):

$ swipl -q -t "between(0, 9, N), n_factorial(N, F), format('~D   ', F), fail." factorial.pl
1   1   2   6   24   120   720   5,040   40,320   362,880

On Windows, you may need to specify full path to swipl.exe as it's not in the PATH, probably.

If the call is always the same, you may save it to a shell script or Makefile (run would be a good name for the target).

In your current workflow for testing functions in C, you create a new program and call the function under test from its entry point (main function). Prolog scripts can have an entry point, too. See library(main). Prolog does not require compilation, so you can just directly call the script (./test.pl) without calling Make first.

For larger projects, you may want to create a less ad-hoc test suite. A unit testing framework like PlUnit is needed. Its use is beyond the scope of this answer; see the documentation.

like image 1
Palec Avatar answered Oct 19 '22 01:10

Palec