Qwiratry::Test
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::TestUsage
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.)
Testing a format plugin
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/::Renderclasses that inheritQwiratry::Format::Base::Parse/::Render;parseyields defined data andrenderyieldsStr;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-samplesare 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/::Destinationclasses that inheritQwiratry::Location::Base::Source/::Destination;the URI scheme resolves to the backend (when
:schemeis supplied);write-then-read round-trips, directly and through the
⮷/⮳operators (when both:writableand:readableand a:roundtrip-locationare given);a missing location raises
X::Qwiratry::IO::LocationError(when:missing-locationis 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)