Skip to main content

A tool for running in-source unittests for Anwer Set Programming (ASP)

Project description

asp-selftest

Starting with in-source testing in mind, asp-selftest has evolved into:

  1. In-source test runner for Answer Set Programming (ASP) with Clingo.
  2. Rich SyntaxErrors with ASP source, based on Clingo's log messages.
  3. Minimalistic plugins based on ASP predicates used as directives. (plugins: reification, clingo_main, dynamic plugins, sequencing, testrunner, mimic default clingo)

In-source Testing

It allows one to write constraints in ASP that will automatically be checked on loading. Consider logic.lp which contains:

node(A)  :-  edge(A, _).
node(B)  :-  edge(_, B).

cannot("at least one edge")  :-  not { edge(_, _) } > 0.

#program test_edge_leads_to_nodes(base).
edge(x, y).
cannot("node x")  :-  not node(x).
cannot("node y")  :-  not node(y).
cannot("node z")  :-  not node(z).  % fails

Using cannot we capture the results from constraints that cannot be true. This leads to the following output:

$ clingo+ logic.lp --run-tests
...
AssertionError: cannot("at least one edge")
File test.lp, line 1, in base().
Model:
<empty>

If we fix it (remove it), we get the next failure:

$ clingo+ logic.lp --run-tests
...
AssertionError: cannot("node z")
File test.lp, line 5, in test_edge_leads_to_nodes(base).
Model:
edge(x,y)  node(x)    node(y)

SyntaxError

If we make a mistake, it tells us in a sensible way:

$ clingo+ logic.lp
...
Traceback (most recent call last):
  ...
  File "logic.lp", line 2
    1 node(A)  :-  edge(A, _).
    2 node(B)  :-  edge(_, A).
           ^ 'B' is unsafe
      ^^^^^^^^^^^^^^^^^^^^^^^^ unsafe variables in:  node(B):-[#inc_base];edge(#Anon0,A).

Status

This tools is still a work in progress. I use it for a project to providing formal specifications for railway interlocking. It consist of 35 files, 100+ tests and 600+ cannots.

asp-selftest has been presented at Declarative Amsterdam in November 2024.

Changes

From version v0.0.30 upwards, @all, @any, @model and the special treatment of predicate assert are removed. From this version on, only cannot is supported.

Tests from #include files are run in their own context, making it easier to add cannot to base-parts.

It is tenfold faster. It runs all my 100+ tests in less than 2 seconds.

Also, asp-test is removed. Only clingo+ remains. The latter is a drop-in replacement for clingo with the added ability to activate plugins, of which these are default:

  1. TesterHook - runs in-source unit tests.
  2. SyntaxErrorHandler - provides nice in-source error messages, a la Python

You can write you own plugins. I have one for reifying rules from theory atoms, for example.

Why In-Source?

With in-source testing, source and tests stay together in the same file. This enables automatic collection and running and avoid maintaining a test tree, and it eases refactoring greatly.

Installing and running

Installing

pip install asp-selftest

Run it using:

$ clingo+ <file.lp> --run-tests

There is one additional option to silence the in-source Python tests:

$ clingo+ --silent --run-tests

A bit of documentation

  1. Use #program's to specify tests and their dependencies. Here we have a unit called unit_A with a unit test for it called test_unit_A. Test must start with test_. Formal arguments are treated as dependencies.

    #program unit_A.
    
    #program test_unit_A(base, unit_A).
    

    The implicit program base (see Clingo Guide) must be referenced explicitly if needed.

    The actual arguments to test_unit_a will be a generic placeholder and have no meaning inside test_unit_A.

  2. Within a test program, use cannot much like ASP constraints, only with a head. Its arguments are just for identification in the reporting.

     #program step.
     fact.
    
     #program test_step(step).
     cannot("step fact")  :-  not fact(3).
    

    Note that "step fact" is just a way of distinquishing the constraint. It can be an atom, a string, a number or anything else.

  3. Note that cannot is much like an constraint in ASP. To assert somefact is true, we must use not:

     somefact.
     cannot("somefact must be true")  :-  not somefact.
    

    It is helpful to read cannot as it cannot be the case that.... Alternatively, one can use constraint as an alias for cannot. Just your preference.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

asp_selftest-0.1.2.tar.gz (44.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

asp_selftest-0.1.2-py3-none-any.whl (51.1 kB view details)

Uploaded Python 3

File details

Details for the file asp_selftest-0.1.2.tar.gz.

File metadata

  • Download URL: asp_selftest-0.1.2.tar.gz
  • Upload date:
  • Size: 44.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for asp_selftest-0.1.2.tar.gz
Algorithm Hash digest
SHA256 0bd2b962413d7524cc77bbd62bf039d34d4e1916fe9cc20f9be6a9adf8e7c7fd
MD5 2e4690680e1b261038de177478cb82ed
BLAKE2b-256 b6fcad83644150b38adb49862b5628130e5a7b4d2f6d79db726851bbc93038d3

See more details on using hashes here.

File details

Details for the file asp_selftest-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: asp_selftest-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 51.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for asp_selftest-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e69513b1aeaef2b1f0aa9ab85f35b57e454dbd5c025ca2e2f8627c958daceb65
MD5 813e48a46925dd7128c930bd8e9ba8d8
BLAKE2b-256 62f9f67684896fcbe416ba2057af7133ee3025fce8c2333644b071ca3a8f2e6e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page