``assertions``
==============

The ``assertions.lgt`` file contains definitions for two
meta-predicates, ``assertion/1-2``, which allows using of assertions on
your source code (e.g. when writing unit tests). The
``assertions_messages.lgt`` file defines the default message
translations generated on assertions succeed, fail, or throw an
exception. For more information on these entities, open the
``docs/tools.html`` file in a web browser.

API documentation
-----------------

To consult this tool API documentation, open in a web browser the link:

`docs/library_index.html#assertions <https://logtalk.org/docs/library_index.html#assertions>`__

Loading
-------

This tool can be loaded using the query:

::

   | ?- logtalk_load(assertions(loader)).

Adding assertions to your source code
-------------------------------------

The ``assertion/1`` predicate takes a goal as argument. For example,
assuming that you're writing a unit test:

::

   test(assertions_1) :-
       assertions::assertion(ground(x)),
       2 is 1 + 1.

The ``assertion/2`` predicate takes as arguments a term for passing
context information and a goal. Using again a unit test as an example:

::

   test(assertions_1) :-
       assertions::assertion(assertions_1, ground(x)),
       2 is 1 + 1.

When using a large number of assertions, you can use a lighter syntax by
adding a ``uses/2`` directive. For example:

::

   :- uses(assertions, [assertion/1, assertion/2]).

Automatically adding file and line context information to assertions
--------------------------------------------------------------------

The ``assertions/1`` parametric object can be used as a hook object to
automatically add file and line context information, represented by the
term ``file_lines(File, BeginLine-EndLine)``, to calls to the
``assertion/1`` predicate by goal-expanding it to calls to the
``assertion/2`` predicate (the expansion assumes that a ``uses/2``
directive is being used in the code that will be expanded to direct
``assertion/1`` calls to the ``assertions`` object). For example,
assuming the file using assertions is named ``source``, it would be
compiled and loaded using the call:

::

   logtalk_load(source, [hook(assertions(debug))])

Suppressing assertion calls from source code
--------------------------------------------

The ``assertions/1`` parametric object can be used as a hook object to
suppress calls to the ``assertion/1-2`` predicates using goal-expansion
(the expansion assumes ``assertions::assertion/1-2`` messages). For
example, assuming the file using assertions is named ``source``, it
would be compiled and loaded using the call:

::

   logtalk_load(source, [hook(assertions(production))])

Redirecting assertion failure messages
--------------------------------------

By default, assertion failures and errors are printed to the standard
output stream. These messages, however, can be intercepted by defining
the ``logtalk::message_hook/4`` multifile predicate. For example:

::

   :- category(redirect_assertions_messages).

       :- multifile(logtalk::message_hook/4).
       :- dynamic(logtalk::message_hook/4).

       logtalk::message_hook(Message, error, assertions, _) :-
           writeq(my_log_file, Message), write(my_log_file, '.\n').

   :- end_category.

Converting assertion failures into errors
-----------------------------------------

If you want an assertion failure to result in a runtime error, you can
intercept the assertion failure messages, optionally still printing
them, and throw an error. For example:

::

   :- category(assertions_failures_to_errors).

       :- multifile(logtalk::message_hook/4).
       :- dynamic(logtalk::message_hook/4).

       logtalk::message_hook(Message, error, assertions, Tokens) :-
           % uncomment the next two lines to also print the default message
           % logtalk::message_prefix_stream(error, assertions, Prefix, Stream),
           % logtalk::print_message_tokens(Stream, Prefix, Tokens),
           throw(error(Message, _)).

   :- end_category.

Other notes
-----------

All source files are formatted using tabs (the recommended setting is a
tab width equivalent to 4 spaces).
