ai-code/.opencode/skills/basex-test/SKILL.md
2026-03-16 22:45:52 +00:00

274 lines
No EOL
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: basex-test
description: Use this skill when working with BaseX XQuery unit tests
metadata:
author: BaseX
version: "12.2"
homepage: https://docs.basex.org/main/Unit_Functions
allowed-tools: Read
---
# Unit Functions
This BaseX module contains annotations and functions for performing XQUnit tests. Each test is an XQuery function with the `%unit:test` annotation.
## [Introduction](#introduction)
The more complex a software application grows, the more error-prone it gets. This is why testing frameworks exist, which provide a standardized, automated way of testing software. The [xUnit](https://en.wikipedia.org/wiki/XUnit) frameworks (such as SUnit or JUnit) allow testing of atomic units of a program, such as single functions and algorithms.
This module borrows heavily from the existing frameworks: it provides various annotations for testing XQuery functions. Unit functions are provided to assert the validity of arbitrary conditions expressed in XQuery and to raise errors whenever a condition is not satisfied. Some additional functions exist to run all unit tests of the current module or a set of specified library modules.
## [Usage](#usage)
Tests are started via the `[TEST](Commands#test)` command. It compiles all XQuery modules in a given file
or directory and runs all functions that are annotated with `%unit:test`. A test report is generated and returned, which resembles the format returned by other xUnit testing frameworks, such as the Maven Surefire Plugin ([see below](#result)).
## [Conventions](#conventions)
All annotations, functions and errors in this module are assigned to the `http://basex.org/modules/unit` namespace, which is statically bound to the `unit` prefix.
## [Annotations](#annotations)
### [`unit:test`](#unit:test)
| | |
| --- | --- |
| Syntax | `unit:test()` <br>`unit:test("expected", CODE)` |
| Summary | With this annotation, a function can be marked as unit test. It will be evaluated if a test report is created for the module in which this function is located. `error` can be supplied as additional string argument. It is followed by `CODE`, which must be a valid [EQName](XQuery_3.0#expanded_qnames) string. If the function expression does not raise that error, the test will fail. |
| Examples | ```xquery<br>declare %unit:test function local:void() { () };<br>```<br><br>The following test will be successful, as it does nothing (and, hence, nothing wrong).<br><br>- - -<br><br>```xquery<br>declare %unit:test('expected', "err:XPTY0004") function local:add() {<br> 123 + 'strings and integers cannot be added'<br>};<br>```<br><br>The following test will be successful, as the function body will raise `err:XPTY0004`. |
### [`unit:before`](#unit:before)
| | |
| --- | --- |
| Syntax | `unit:before()` <br>`unit:before(FUNCTION)` |
| Summary | A function decorated with this annotation will be evaluated **before each** unit test as a separate transaction. `FUNCTION` can be supplied as additional argument. It must be a valid [EQName](XQuery_3.0#expanded_qnames) string. If specified, the function will only be evaluated before a function with the given name is tested. This extension is e.g. helpful if the results of updates need to be tested. |
| Examples | ```xquery<br>declare %updating %unit:before("local:check") function local:before-check() {<br> db:create('test-db')<br>};<br>declare %updating %unit:test function local:check() {<br> unit:assert(db:exists('test-db'))<br>};<br>```<br><br>The first function will be evaluated before the actual test. |
### [`unit:after`](#unit:after)
| | |
| --- | --- |
| Syntax | `unit:after()` <br>`unit:after(FUNCTION)` |
| Summary | A function decorated with this annotation will be evaluated **after each** unit test as a separate transaction. `FUNCTION` can be supplied as additional argument. It must be a valid [EQName](XQuery_3.0#expanded_qnames) string. If specified, the function will only be evaluated after a function with the given name is tested. |
### [`unit:before-module`](#unit:before-module)
| | |
| --- | --- |
| Syntax | `unit:before-module()` |
| Summary | If a function is decorated with this annotation, it will be evaluated **before all** unit tests in the current module as a separate transaction. |
### [`unit:after-module`](#unit:after-module)
| | |
| --- | --- |
| Syntax | `unit:after-module()` |
| Summary | If a function is decorated with this annotation, it will be evaluated **after all** unit tests in the current module as a separate transaction. |
### [`unit:ignore`](#unit:ignore)
| | |
| --- | --- |
| Syntax | `unit:ignore()` <br>`unit:ignore(MESSAGE)` |
| Summary | If a function is decorated with this annotation, it will temporarily be ignored by the test suite runner. |
## [Functions](#functions)
### [`unit:assert`](#unit:assert)
Signature
unit:assert(
$test as item()\*,
$info as item() := ()
) as empty-sequence()
SummaryAsserts that the effective boolean value of the specified `$test` is true and returns an empty sequence. Otherwise, raises an error. The _effective boolean value_ of an expression can be explicitly computed by using the `fn:boolean` function. The default failure message can be overridden with the `$info` argument.Errors
| | |
| --- | --- |
| [`fail`](#errors) | An assertion failed, or an error was raised. |
### [`unit:assert-equals`](#unit:assert-equals)
Signature
unit:assert-equals(
$returned as item()\*,
$expected as item()\*,
$info as item() := ()
) as empty-sequence()
SummaryAsserts that the specified arguments are equal according to the rules of the `[fn:deep-equal](Standard_Functions#fn:deep-equal)` function. Otherwise, raises an error. The default failure message can be overridden with the `$info` argument.Errors
| | |
| --- | --- |
| [`fail`](#errors) | An assertion failed, or an error was raised. |
### [`unit:fail`](#unit:fail)
Signature
unit:fail(
$info as item() := ()
) as empty-sequence()
SummaryRaises a unit error. The default failure message can be overridden with the `$info` argument.Errors
| | |
| --- | --- |
| [`fail`](#errors) | An assertion failed, or an error was raised. |
## [Example](#example)
The following XQUnit module `tests.xqm` contains all available unit annotations:
### [Query](#query)
```xquery
module namespace test = 'http://basex.org/modules/xqunit-tests';
(:~ Initializing function, which is called once before all tests. :)
declare %unit:before-module function test:before-all-tests() {
()
};
(:~ Initializing function, which is called once after all tests. :)
declare %unit:after-module function test:after-all-tests() {
()
};
(:~ Initializing function, which is called before each test. :)
declare %unit:before function test:before() {
()
};
(:~ Initializing function, which is called after each test. :)
declare %unit:after function test:after() {
()
};
(:~ Function demonstrating a successful test. :)
declare %unit:test function test:assert-success() {
unit:assert(<a/>)
};
(:~ Function demonstrating a failure using unit:assert. :)
declare %unit:test function test:assert-failure() {
unit:assert((), 'Empty sequence.')
};
(:~ Function demonstrating a failure using unit:assert-equals. :)
declare %unit:test function test:assert-equals-failure() {
unit:assert-equals(4 + 5, 6)
};
(:~ Function demonstrating an unexpected success. :)
declare %unit:test("expected", "err:FORG0001") function test:unexpected-success() {
()
};
(:~ Function demonstrating an expected failure. :)
declare %unit:test("expected", "err:FORG0001") function test:expected-failure() {
1 + <a/>
};
(:~ Function demonstrating the creation of a failure. :)
declare %unit:test function test:failure() {
unit:fail("Failure!")
};
(:~ Function demonstrating an error. :)
declare %unit:test function test:error() {
1 + <a/>
};
(:~ Skipping a test. :)
declare %unit:test %unit:ignore("Skipped!") function test:skipped() {
()
};
```
By running `TEST tests.xqm`, the following report will be generated (timings may differ):
### [Result](#result)
```xml
<testsuites time="PT0.256S">
<testsuite name="file:///C:/Users/user/Desktop/test.xqm"
time="PT0.212S" tests="8" failures="4" errors="1" skipped="1">
<testcase name="assert-success" time="PT0.016S"/>
<testcase name="assert-failure" time="PT0.005S">
<failure line="30" column="15">
<info>Empty sequence.</info>
</failure>
</testcase>
<testcase name="assert-equals-failure" time="PT0.006S">
<failure line="35" column="22">
<returned item="1" type="xs:integer">9</returned>
<expected item="1" type="xs:integer">6</expected>
<info>Item 1: 6 expected, 9 returned.</info>
</failure>
</testcase>
<testcase name="unexpected-success" time="PT0.006S">
<failure>
<expected>FORG0001</expected>
</failure>
</testcase>
<testcase name="expected-failure" time="PT0.004S"/>
<testcase name="failure" time="PT0.004S">
<failure line="50" column="13">
<info>Failure!</info>
</failure>
</testcase>
<testcase name="error" time="PT0.004S">
<error line="55" column="6" type="FORG0001">
<info>Cannot cast to xs:double: "".</info>
</error>
</testcase>
<testcase name="skipped" skipped="Skipped!" time="PT0S"/>
</testsuite>
</testsuites>
```
## [Errors](#errors)
| Code | Description |
| --- | --- |
| `fail` | An assertion failed, or an error was raised. |
| `no-args` | A test function must have no arguments. |
| `private` | A test function must not be private. |
## [Changelog](#changelog)
**Version 9.0**
* Updated: error codes updated; errors now use the module namespace
**Version 8.0.2**
* Updated: (expected) errors are compared by QNames instead of local names (including namespaces).
**Version 8.0**
* Added: `[unit:fail](#unit:fail)`, 0-argument signature.
* Updated: the info argument of functions can now be an arbitrary item.
* Updated: infos are now represented in an `info` child element.
* Updated: `[unit:before](#unit:before)` and `[unit:after](#unit:after)` can be extended by a filter argument.
* Deleted: `UNIT0006` (ignore results returned by functions).
**Version 7.9**
* Added: TEST command
* Removed: `[unit:test](#unit:test)`, `unit:test-uris`
**Version 7.8**
* Added: `[unit:assert-equals](#unit:assert-equals)`
* Updated: enhanced test report output
**Version 7.7**
* Added: New module added.