Qwiratry::Test
Reusable conformance ("contract") test kit for Qwiratry
Format and Location plugins.
Instead of every plugin re-writing the same discovery / factory / round-trip /
error-handling tests, a plugin depends on Qwiratry::Test at test time and calls
one routine that runs the shared battery against its implementation. The plugin
then only needs to add tests for behaviour that is genuinely specific to it.
Requirements
- Rakudo with RakuAST (
RAKUDO_RAKUAST=1), as required by Qwiratry itself. Qwiratry (a runtime dependency of this kit).
Installation
zef install Qwiratry::Test
Usage
Add the kit to your plugin's META6.json as a test-phase dependency:
"depends": {
"runtime": { "requires": [ "Qwiratry" ] },
"test": { "requires": [ "Qwiratry::Test" ] }
}
(The classic flat "test-depends": [ "Qwiratry::Test" ] array works too.)
use Test;
use Qwiratry::Test::Format;
conforms-to-format-contract(
format => 'JSON',
parse-samples => [ '{"b":2,"a":1}', '[1,2,3]' ],
render-values => [ { :a(1), :b(2) }, [1, 2, 3] ],
:lossless,
);
done-testing;
conforms-to-format-contract verifies:
- the format is discoverable through
Qwiratry::Format.formats; - the factory autoloads
::Parse / ::Render classes that inherit
Qwiratry::Format::Base::Parse / ::Render; parse yields defined data and render yields Str;- the lossless round-trip law
parse ∘ render ∘ parse == parse (when :lossless); - the
↱ (parse) and ↴ (render) pipeline operators agree with direct calls; - invalid input is rejected (when
:invalid-samples are supplied).
Everything except :format is optional and capability-driven — pass only the
samples and flags that apply to your format. :parse/:render (default both)
and :pipeline (default on) let you narrow the surface.
Testing a location plugin
use Test;
use Qwiratry::Test::Location;
conforms-to-location-contract(
backend => 'HTTP',
scheme => 'https',
sample-location => 'https://example.test/data',
:!writable, # a GET-only backend skips write/round-trip checks
:needs-network, # gate live checks behind QWIRATRY_TEST_NETWORK
);
done-testing;
conforms-to-location-contract verifies:
- the backend is discoverable through
Qwiratry::Location.backends; - the factory autoloads
::Source / ::Destination classes that inherit
Qwiratry::Location::Base::Source / ::Destination; - the URI scheme resolves to the backend (when
:scheme is supplied); - write-then-read round-trips, directly and through the
⮷ / ⮳ operators
(when both :writable and :readable and a :roundtrip-location are given); - a missing location raises
X::Qwiratry::IO::LocationError
(when :missing-location is supplied).
Use :needs-network for backends that reach the outside world; those subtests
are skipped unless QWIRATRY_TEST_NETWORK is set, so plugin CI stays hermetic by
default.
How the kit tests itself
To avoid a circular dependency, the base Qwiratry distribution does not
depend on this kit. Instead, Qwiratry::Test depends on Qwiratry and its own
test suite runs the kit against Qwiratry's bundled reference implementations —
the File location backend and the JSONdemo format — so the contract battery
is validated end to end. See t/.
Versioning
The kit's assertions are effectively part of Qwiratry's plugin API. Tightening a
check is a semver-relevant change, so plugins should pin a minimum version, e.g.
"Qwiratry::Test:ver<0.0.1+>".
License
Licensed under the same terms as Raku itself.
Author
Tim Nelson (wayland at wayland dot id dot au)