The Jamal assertions module contains macros to check the consistency of the documentation. The checks are implemented as assertions, asserting some simple conditions and giving an error if the condition is false. Although it may be used other than checking the consistency of the documentation, that is the module’s primary purpose.
Macros can gather information from different parts of the document and the documented system. The assertions can check that the gathered information is consistent.
For example, the macro
{@snip:xml pom=pom.xml}
reads the pom.xml
file from the same directory where the document is.
It stores the XML in the memory, and you can query it via the pom
macro afterward.
You can use this pom
macro with an XPath expression to get parts of the project description.
For example, the following macro will get the version string of the project:
{pom //project/version}
This version currently is
2.8.3-SNAPSHOT
If we create an assertion that this version is in the 2.xxx
range, we can write it as the following:
here we have an assertion
{#assert:startsWith /{pom //project/version}/2./ERROR: we are not in the 2.xxx range anymore}
assertion was okay
which results
here we have an assertion
assertion was okay
The output of the assertion is an empty string when the condition is ok.
Since the string {pom //project/version}
starts with 2.
, the assertion does not fail.
If we do a different assertion that tests that the version does NOT start with 2.
, the assertion will result in an error.
{@try! {#assert:startsWith (not) /{pom //project/version}/2./ERROR: we are still in the 1.xxx range}}
if the assertion was not okay, the macro try! displays the error message
which results
ERROR: we are still in the 1.xxx range
if the assertion was not okay, the macro try! displays the error message
Note
|
This document uses the We use this macro in the samples to demonstrate the situation when an error happens. The samples in this documentation are executed when Jamal processes the document. |
Checking documentation consistency can be done in many ways. The one we have shown in this section is only a single example. The assertion package helps consistency checks.
The macro package is defined in a jar file as a Java module. The macros are automatically loaded using the service loader. To use the macros, the library has to be on the classpath. To do it as a Maven dependency use the following Maven coordinates:
<dependency>
<groupId>com.javax0.jamal</groupId>
<artifactId>jamal-assertions</artifactId>
<version>2.8.3-SNAPSHOT</version>
</dependency>
When you start Jamal
-
from the command line using jbang,
-
from IntelliJ AsciiDoctor editor,
-
in JavaDoc configuring
jamal-all
as dependency, -
in a
pom.jam
orpom.xml.jam
file using the Jamal Maven extension
then the library and the macros are included and are usable without any further configuration.
All assertions have the same options and the same syntax.
The options follow the macro’s name between (
and )
characters.
The rest of the macro is the parameters.
The parameters are parsed using the Standard Built-In Parameter Parsing.
The different assertions can have different number of parameters.
The last parameter is always optional.
If it is present, it specifies the error message for the failing assertion.
Let us look at the sample we have already visited in the previous section.
{#assert:startsWith (not) /{pom //project/version}/2./ERROR: we are still in the 1.xxx range}
The assertion macro assert:startsWith
has two mandatory parameters and the optional message as the third parameter.
This assertion checks that the first parameter interpreted as a string starts with the second parameter.
In this example, we want an error when the version does NOT start with 2.
thus the use of the option not
.
All the assertions interpret three options. These are
-
trim
with the aliasstrip
, -
not
with the aliasnegate
, and -
test
with aliasesboolean
andbool
.
The option names and the aliases are equivalent; you can use the one that fits your taste.
The first option trim
tells the assertion that the parameters should be stripped before evaluating the assertion.
This process will remove all white space from the start and the end of the parameters.
The second option, negate
reverses the outcome of the assertion.
The option test
will modify the behavior of the macro.
When this option is used the assertion will not fail if the assertion is false.
Instead, the return value of the assertion will be the literal string true
or false
.
Asserts that the first argument contains the second argument.
Example .Jamal source
1. OK: {@assert:contains /abba/bb/contains}
2. OK: {@assert:contains (not) /abba/aa/abba does not contain aa}
3. ERROR: {@try! {@assert:contains /abba/aa/abba does not contain aa}}
4. ERROR: {@try! {@assert:contains /abba/aa/}}
5. ERROR: {@try! {@assert:contains (not) /abba/bb/abba contains bb}}
6. ERROR: {@try! {@assert:contains (not) /abba/bb/}}
results
1. OK:
2. OK:
3. ERROR: abba does not contain aa
4. ERROR: assert:contains has failed 'abba' does not contain 'aa'
5. ERROR: abba contains bb
6. ERROR: assert:contains has failed 'abba' contains 'bb'
Asserts that the first argument is a zero-length string.
Note that there is no assert:blank
assertion.
If you want to check that the argument is empty OR blank, you should use the trim
option.
Example .Jamal source
1. OK: {@assert:empty //this is empty}
2. OK: {@assert:empty (trim) / /this is empty also, as trimmed}
3. OK: {@assert:empty (not) / /this is not empty as expected}
4. OK: {@assert:empty (not trim) / wuff /this is not empty as expected, even though trimmed}
5. ERROR: {@try! {@assert:empty (not) //sadly nothing here}}
6. ERROR: {@try! {@assert:empty / /blank is not empty unless trimmed}}
7. ERROR: {@try! {@assert:empty /wuff/not empty is not empty}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. ERROR: sadly nothing here
6. ERROR: blank is not empty unless trimmed
7. ERROR: not empty is not empty
Asserts that the first argument starts with the second argument.
Example .Jamal source
1. OK: {@assert:startsWith /abba/abb/abba starts with abb}
2. OK: {@assert:startsWith (trim) / abba/ abb /the same as above}
3. OK: {@assert:startsWith (not) /abba/ebb/abba does not start with ebb}
4. ERROR: {@try! {@assert:startsWith (not) /abba/abb/ but it does start with abb}}
5. ERROR: {@try! {@assert:startsWith /abba/ebb/abba does not start with ebb}}
results
1. OK:
2. OK:
3. OK:
4. ERROR: but it does start with abb
5. ERROR: abba does not start with ebb
Asserts that the first argument ends with the second argument.
Example .Jamal source
1. OK: {@assert:endsWith /abba/bba/abba ends with bba}
2. OK: {@assert:endsWith (trim) / abba/ bba /the same as above}
3. OK: {@assert:endsWith (not) /abba/bbe/abba does not end with bbe}
4. ERROR: {@try! {@assert:endsWith (not) /abba/bba/ but it does end with bba}}
5. ERROR: {@try! {@assert:endsWith /abba/bbe/abba does not end with bbe}}
results
1. OK:
2. OK:
3. OK:
4. ERROR: but it does end with bba
5. ERROR: abba does not end with bbe
Asserts that the first and the second arguments are equal strings.
Example .Jamal source
1. OK: {@assert:equals /abba/abba/abba is abba}
2. OK: {@assert:equals (trim) / abba/ abba /the same as above}
3. OK: {@assert:equals (not) /abba/boney m/abba is not boney m}
4. ERROR: {@try! {@assert:equals (not) /abba/abba/abba forever}}
5. ERROR: {@try! {@assert:equals /abba/boney N/we meant real Swedish music}}
6. ERROR: {@try! {@assert:equals /333/+333/this is not numeric comparison}}
results
1. OK:
2. OK:
3. OK:
4. ERROR: abba forever
5. ERROR: we meant real Swedish music
6. ERROR: this is not numeric comparison
This assertion has only one optional argument, the message.
If this macro is evaluated, it will always result in an error.
The use of this assertion makes sense in part of the code that is conditionally evaluated, like a part of an if
macro.
Note that this macro also interprets the trim
option, though it has no parameters to be trimmed.
The option trim
can be used but has no effect.
The option not
is also interpreted.
If the option not
is used, the macro will result in an empty string and will not error.
Example .Jamal source
1. ERROR: {@try! {@assert:fail just fail, okay? just fail}}
results
1. ERROR: just fail, okay? just fail
This assertion interprets the first two arguments as integer values. It checks that the first argument is greater than the second.
Example .Jamal source
1. OK: {@assert:greater /6/3/six is greater than three}
2. OK: {@assert:greater /-3/-6/minus three is greater than minus six}
3. OK: {@assert:greater (trim) / 6 / 3 /space needs trimming, converted to numeric}
4. OK: {@assert:greater (not) /3/6/three is not greater than six}
5. OK: {@assert:greater (not) /3/3/three is not greater than three}
6. ERROR: {@try! {@assert:greater /60/3A/3A is not numeric}}
7. ERROR: {@try! {@assert:greater / 6 / 3 /with spaces it is not numeric}}
8. ERROR: {@try! {@assert:greater (not) /6/666/six is not greater than 666}}
9. ERROR: {@try! {@assert:greater /3/3/three is not greater than three, three is three}}
10. ERROR: {@try! {@assert:greater /-6/-3/this is numeric comparison, negative numbers are negative}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. OK:
6. ERROR: The parameter in assert:greater is not a well formatted integer: '3A'
7. ERROR: The parameter in assert:greater is not a well formatted integer: ' 6 '
8. ERROR:
9. ERROR: three is not greater than three, three is three
10. ERROR: this is numeric comparison, negative numbers are negative
This assertion interprets the first two arguments as integer values. It checks that the first argument is greater or equal than the second.
Example .Jamal source
1. OK: {@assert:greaterOrEqual /6/3/six is greater than three}
2. OK: {@assert:greaterOrEqual /-3/-6/minus three is greater than minus six}
3. OK: {@assert:greaterOrEqual (trim) / 6 / 3 /space needs trimming, converted to numeric}
4. OK: {@assert:greaterOrEqual (not) /3/6/three is not greater than six}
5. OK: {@assert:greaterOrEqual /3/3/three is not greater than three but it is equal}
6. ERROR: {@try! {@assert:greaterOrEqual /60/3A/3A is not numeric}}
7. ERROR: {@try! {@assert:greaterOrEqual / 6 / 3 /with spaces it is not numeric}}
8. ERROR: {@try! {@assert:greaterOrEqual (not) /6/666/six is not greater than 666}}
9. ERROR: {@try! {@assert:greaterOrEqual (not) /3/3/three is not greater than three, three is three}}
10. ERROR: {@try! {@assert:greaterOrEqual /-6/-3/this is numeric comparison, negative numbers are negative}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. OK:
6. ERROR: The parameter in assert:greaterOrEquals is not a well formatted integer: '3A'
7. ERROR: The parameter in assert:greaterOrEquals is not a well formatted integer: ' 6 '
8. ERROR:
9. ERROR: three is not greater than three, three is three
10. ERROR: this is numeric comparison, negative numbers are negative
This assertion interprets the first two arguments as integer values. It checks that the first argument is less than the second.
Example .Jamal source
1. OK: {@assert:less /3/6/three is less than six}
2. OK: {@assert:less /-6/-3/minus six is less than minus three}
3. OK: {@assert:less (trim) / 3 / 6 /space needs trimming, converted to numeric}
4. OK: {@assert:less (not) /6/3/six is not less than three}
5. OK: {@assert:less (not) /3/3/three is not less than three}
6. ERROR: {@try! {@assert:less /60/3A/3A is not numeric}}
7. ERROR: {@try! {@assert:less / 3 / 6 /with spaces it is not numeric}}
8. ERROR: {@try! {@assert:less (not) /666/6/666 is not less than six}}
9. ERROR: {@try! {@assert:less /3/3/three is not less than three, three is three}}
10. ERROR: {@try! {@assert:less /-3/-6/this is numeric comparison, negative numbers are negative}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. OK:
6. ERROR: The parameter in assert:less is not a well formatted integer: '3A'
7. ERROR: The parameter in assert:less is not a well formatted integer: ' 3 '
8. ERROR:
9. ERROR: three is not less than three, three is three
10. ERROR: this is numeric comparison, negative numbers are negative
This assertion interprets the first two arguments as integer values. It checks that the first argument is less or equal than the second.
Example .Jamal source
1. OK: {@assert:lessOrEqual /3/6/three is less than six}
2. OK: {@assert:lessOrEqual /-6/-3/minus six is less than minus three}
3. OK: {@assert:lessOrEqual (trim) / 3 / 6 /space needs trimming, converted to numeric}
4. OK: {@assert:lessOrEqual (not) /6/3/six is not less than three}
5. OK: {@assert:lessOrEqual /3/3/three is not less than three but it is equal}
6. ERROR: {@try! {@assert:lessOrEqual /60/3A/3A is not numeric}}
7. ERROR: {@try! {@assert:lessOrEqual / 3 / 6 /with spaces it is not numeric}}
8. ERROR: {@try! {@assert:lessOrEqual /666/6/666 is not less than six}}
9. ERROR: {@try! {@assert:lessOrEqual (not) /3/3/three is not less than three, three is three}}
10. ERROR: {@try! {@assert:lessOrEqual /-3/-6/this is numeric comparison, negative numbers are negative}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. OK:
6. ERROR: The parameter in assert:lessOrEquals is not a well formatted integer: '3A'
7. ERROR: The parameter in assert:lessOrEquals is not a well formatted integer: ' 3 '
8. ERROR: 666 is not less than six
9. ERROR: three is not less than three, three is three
10. ERROR: this is numeric comparison, negative numbers are negative
This assertion interprets the first two arguments as integer values. It checks that the two arguments are equal as integer numbers.
Example .Jamal source
1. OK: {@assert:intEquals /3/3/three is three}
2. OK: {@assert:intEquals (trim) / 3/3 /three is three but needs trimming if it needs trimming}
3. OK: {@assert:intEquals /+3/3/plus three is three}
4. OK: {@assert:intEquals (not) /-3/3/minus three is not three}
5. ERROR: {@try! {@assert:intEquals /3A/3A/3A is not numeric}}
6. ERROR: {@try! {@assert:intEquals / 3 / 6 /with spaces it is not numeric}}
7. ERROR: {@try! {@assert:intEquals /666/6/666 is not six}}
8. ERROR: {@try! {@assert:intEquals (not) /3/3/three is three}}
9. ERROR: {@try! {@assert:intEquals /3/6/simply not equal}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. ERROR: The parameter in assert:intEquals is not a well formatted integer: '3A'
6. ERROR: The parameter in assert:intEquals is not a well formatted integer: ' 3 '
7. ERROR: 666 is not six
8. ERROR: three is three
9. ERROR: simply not equal
This macro checks that the first argument can be interpreted as an integer number.
Example .Jamal source
1. OK: {@assert:int /3/3 is an int}
2. OK: {@assert:int (trim) / 3/3 is an int if trimmed}
3. OK: {@assert:int /+3/plus three is also int}
4. OK: {@assert:int (not) /3.14/that is not an int}
5. ERROR: {@try! {@assert:int /3A/3A is not numeric}}
6. ERROR: {@try! {@assert:int / 3 /3 with spaces it is not int}}
7. ERROR: {@try! {@assert:int /3.14/3.14 is not an int}}
8. ERROR: {@try! {@assert:int (not) /3/three is an int, not a not int}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. ERROR: 3A is not numeric
6. ERROR: 3 with spaces it is not int
7. ERROR: 3.14 is not an int
8. ERROR: three is an int, not a not int
This macro checks that the first argument can be interpreted as a numeric (possibly floating-point) number.
1. OK: {@assert:numeric /3/3 is an int}
2. OK: {@assert:numeric (trim) / 3/3 is an int if trimmed}
3. OK: {@assert:numeric /+3/plus three is also int}
4. OK: {@assert:numeric /3.14/that is numeric}
5. OK: {@assert:numeric /0x0.C90FDAP2f/that is also numeric}
6. ERROR: {@try! {@assert:numeric /3A/3A is not numeric}}
7. ERROR: {@try! {@assert:numeric / 3 /3 with spaces it is not int}}
8. ERROR: {@try! {@assert:numeric (not) /3.14/3.14 is not a not numeric}}
9. ERROR: {@try! {@assert:numeric (not) /3/three is an int, not a not int, and thus a numeric}}
results
1. OK:
2. OK:
3. OK:
4. OK:
5. OK:
6. ERROR: 3A is not numeric
7. ERROR:
8. ERROR: 3.14 is not a not numeric
9. ERROR: three is an int, not a not int, and thus a numeric