COPYRIGHT000644001750001750 345514550352012 15753 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Test-FITesque-RDF Upstream-Contact: Kjetil Kjernsmo (KJETILK) Source: https://metacpan.org/release/Test-FITesque-RDF Files: Changes META.json META.yml dist.ini doap.ttl lib/Test/FITesque/RDF.pm t/01basic.t t/integration-basic.t t/integration-http-list.t t/lib/Internal/Fixture/HTTPList.pm t/lib/Internal/Fixture/Multi.pm t/lib/Internal/Fixture/Simple.pm t/unit-http-list.t t/unit-http-mix.t t/unit-http-regex.t t/unit-http-server.t t/unit-list.t t/unit-multi-http.t t/unit-multi-vocab.t t/unit-multi.t t/unit-relative.t t/unit-simple.t Copyright: Copyright 2024 Kjetil Kjernsmo. License: Expat Files: INSTALL LICENSE README README.md t/data/http-external-content-blank.ttl t/data/http-external-content-invalid.ttl t/data/http-external-content.ttl t/data/http-list-multi.ttl t/data/http-list.ttl t/data/http-mix.ttl t/data/http-regex.ttl t/data/invalid.ttl t/data/list.ttl t/data/multi-vocab.ttl t/data/multi.ttl t/data/notests.ttl t/data/relative.ttl t/data/simple.ttl t/data/undescribed.ttl Copyright: Unknown License: Unknown Files: COPYRIGHT CREDITS SIGNATURE Copyright: None License: public-domain Files: Makefile.PL Copyright: Copyright 2020 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 License: Expat This software is Copyright (c) 2024 by Kjetil Kjernsmo. This is free software, licensed under: The MIT (X11) License License: Artistic-1.0 This software is Copyright (c) 2024 by the copyright holder(s). This is free software, licensed under: The Artistic License 1.0 License: GPL-1.0 This software is Copyright (c) 2024 by the copyright holder(s). This is free software, licensed under: The GNU General Public License, Version 1, February 1989 CREDITS000644001750001750 23514550352012 15451 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10Maintainer: - Kjetil Kjernsmo (KJETILK) Thanks: - Scott McWirther (KONOBI) - Slaven Rezić (SREZIC) Changes000644001750001750 353614550352012 15753 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10Test-FITesque-RDF ================= Created: 2019-04-09 Home page: Bug tracker: Maintainer: Kjetil Kjernsmo (KJETILK) 0.10 2024-01-13 Fix DNS from invalid host [ Bug Fixes ] - Add . to fix github issue #12. Slaven Rezić++ 0.018 2020-02-06 Support different status codes - Added: Make it possible to use status as regular expression. - Improve documentation. - Updated: Use the new coercions in Attean. 0.016 2019-10-28 Test coverage to 100% - Added: Add tests to bring the test coverage to 100%. 0.014 2019-09-23 Improve the RDF [ BACK COMPAT ] - Restructure HTTP request-response pair parameterization. [ Documentation ] - Improve documentation. 0.012 2019-08-26 Passing URIs as parameters - Added: If the object of a parameter is a IRI, pass a URI object. 0.011 2019-08-03 Implement regular expressions for stateful tests - Added: Improve documentation. - Added: Support regular expressions with a new array. - Introduce a -special key to the parameters to group all internal additions. - Some minor fixes. 0.010 2019-07-05 Adapt to existing vocabularies - Adapt to existing vocabularies. - Allow mixing parameters. 0.009 2019-07-04 Improve vocabulary usage - Added: Improve documentation. - Added: Improve error handling. - Added: Tests for multi-field values. - Improve Travis usage. - Some improvements to how ontologies are used. 0.008 2019-06-20 Fix bug in HTTP param selection 0.007 2019-06-13 Support content for HTTP request objects 0.006 2019-06-07 Create HTTP request-response objects 0.005 2019-06-03 Support several vocabularies for parameters 0.004 2019-06-03 Support RDF lists 0.003 2019-04-30 Add more dependencies 0.002 2019-04-30 Minor tweaks 0.001 2019-04-29 Initial release INSTALL000644001750001750 172614550352012 15510 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10 Installing Test-FITesque-RDF should be straightforward. INSTALLATION WITH CPANMINUS If you have cpanm, you only need one line: % cpanm Test::FITesque::RDF If you are installing into a system-wide directory, you may need to pass the "-S" flag to cpanm, which uses sudo to install the module: % cpanm -S Test::FITesque::RDF INSTALLATION WITH THE CPAN SHELL Alternatively, if your CPAN shell is set up, you should just be able to do: % cpan Test::FITesque::RDF MANUAL INSTALLATION As a last resort, you can manually install it. Download the tarball and unpack it. Consult the file META.json for a list of pre-requisites. Install these first. To build Test-FITesque-RDF: % perl Makefile.PL % make && make test Then install it: % make install If you are installing into a system-wide directory, you may need to run: % sudo make install LICENSE000644001750001750 221214550352012 15453 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10This software is Copyright (c) 2024 by Kjetil Kjernsmo. This is free software, licensed under: The MIT (X11) License The MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MANIFEST000644001750001750 152414550352012 15604 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10COPYRIGHT CREDITS Changes INSTALL LICENSE MANIFEST META.json META.yml Makefile.PL README README.md SIGNATURE dist.ini doap.ttl lib/Test/FITesque/RDF.pm t/01basic.t t/data/http-external-content-blank.ttl t/data/http-external-content-invalid.ttl t/data/http-external-content.ttl t/data/http-list-multi.ttl t/data/http-list.ttl t/data/http-mix.ttl t/data/http-regex.ttl t/data/invalid.ttl t/data/list.ttl t/data/multi-vocab.ttl t/data/multi.ttl t/data/notests.ttl t/data/relative.ttl t/data/simple.ttl t/data/undescribed.ttl t/integration-basic.t t/integration-http-list.t t/lib/Internal/Fixture/HTTPList.pm t/lib/Internal/Fixture/Multi.pm t/lib/Internal/Fixture/Simple.pm t/unit-http-list.t t/unit-http-mix.t t/unit-http-regex.t t/unit-http-server.t t/unit-list.t t/unit-multi-http.t t/unit-multi-vocab.t t/unit-multi.t t/unit-relative.t t/unit-simple.t META.json000644001750001750 477214550352012 16104 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10{ "abstract" : "Formulate Test::FITesque fixture tables in RDF", "author" : [ "Kjetil Kjernsmo (KJETILK) " ], "dynamic_config" : 0, "generated_by" : "Dist::Inkt::Profile::KJETILK version 0.101, CPAN::Meta::Converter version 2.150010", "keywords" : [], "license" : [ "mit" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Test-FITesque-RDF", "no_index" : { "directory" : [ "eg", "examples", "inc", "t", "xt" ] }, "optional_features" : {}, "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.17" } }, "develop" : { "recommends" : { "Dist::Inkt" : "0.001" } }, "runtime" : { "requires" : { "Attean" : "0.025", "HTTP::Message" : "0", "LWP::UserAgent" : "0", "Moo" : "1.006000", "Path::Tiny" : "0", "RDF::NS::Curated" : "1.002", "RDF::Prefixes" : "0", "Test::FITesque" : "0", "Try::Tiny" : "0", "Types::Path::Tiny" : "0", "Types::Standard" : "0", "Types::URI" : "0.007", "URI::NamespaceMap" : "1.08", "perl" : "5.014" } }, "test" : { "requires" : { "FindBin" : "0", "Test::Deep" : "0", "Test::HTTP::LocalServer" : "0", "Test::Modern" : "0", "Test::More" : "0.96" } } }, "provides" : { "Test::FITesque::RDF" : { "file" : "lib/Test/FITesque/RDF.pm", "version" : "0.10" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/kjetilk/p5-test-fitesque-rdf/issues" }, "homepage" : "https://metacpan.org/release/Test-FITesque-RDF", "license" : [ "http://www.opensource.org/licenses/mit-license.php" ], "repository" : { "type" : "git", "url" : "git://github.com/kjetilk/p5-test-fitesque-rdf.git", "web" : "https://github.com/kjetilk/p5-test-fitesque-rdf" }, "x_IRC" : "irc://irc.perl.org/#perlrdf", "x_identifier" : "http://purl.org/NET/cpan-uri/dist/Test-FITesque-RDF/project" }, "version" : "0.10", "x_serialization_backend" : "JSON::PP version 4.07", "x_static_install" : 1 } META.yml000644001750001750 275014550352012 15726 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10--- abstract: 'Formulate Test::FITesque fixture tables in RDF' author: - 'Kjetil Kjernsmo (KJETILK) ' build_requires: FindBin: '0' Test::Deep: '0' Test::HTTP::LocalServer: '0' Test::Modern: '0' Test::More: '0.96' configure_requires: ExtUtils::MakeMaker: '6.17' dynamic_config: 0 generated_by: 'Dist::Inkt::Profile::KJETILK version 0.101, CPAN::Meta::Converter version 2.150010' keywords: [] license: mit meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Test-FITesque-RDF no_index: directory: - eg - examples - inc - t - xt optional_features: {} provides: Test::FITesque::RDF: file: lib/Test/FITesque/RDF.pm version: '0.10' requires: Attean: '0.025' HTTP::Message: '0' LWP::UserAgent: '0' Moo: '1.006000' Path::Tiny: '0' RDF::NS::Curated: '1.002' RDF::Prefixes: '0' Test::FITesque: '0' Try::Tiny: '0' Types::Path::Tiny: '0' Types::Standard: '0' Types::URI: '0.007' URI::NamespaceMap: '1.08' perl: '5.014' resources: IRC: irc://irc.perl.org/#perlrdf Identifier: http://purl.org/NET/cpan-uri/dist/Test-FITesque-RDF/project bugtracker: https://github.com/kjetilk/p5-test-fitesque-rdf/issues homepage: https://metacpan.org/release/Test-FITesque-RDF license: http://www.opensource.org/licenses/mit-license.php repository: git://github.com/kjetilk/p5-test-fitesque-rdf.git version: '0.10' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' x_static_install: 1 Makefile.PL000644001750001750 1335014550352012 16445 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10use strict; use ExtUtils::MakeMaker 6.17; my $EUMM = eval( $ExtUtils::MakeMaker::VERSION ); my $meta = { "abstract" => "Formulate Test::FITesque fixture tables in RDF", "author" => ["Kjetil Kjernsmo (KJETILK) "], "dynamic_config" => 0, "generated_by" => "Dist::Inkt::Profile::KJETILK version 0.101, CPAN::Meta::Converter version 2.150010", "keywords" => [], "license" => ["mit"], "meta-spec" => { url => "http://search.cpan.org/perldoc?CPAN::Meta::Spec", version => 2, }, "name" => "Test-FITesque-RDF", "no_index" => { directory => ["eg", "examples", "inc", "t", "xt"] }, "prereqs" => { configure => { requires => { "ExtUtils::MakeMaker" => 6.17 } }, develop => { recommends => { "Dist::Inkt" => 0.001 } }, runtime => { requires => { "Attean" => 0.025, "HTTP::Message" => 0, "LWP::UserAgent" => 0, "Moo" => "1.006000", "Path::Tiny" => 0, "perl" => 5.014, "RDF::NS::Curated" => 1.002, "RDF::Prefixes" => 0, "Test::FITesque" => 0, "Try::Tiny" => 0, "Types::Path::Tiny" => 0, "Types::Standard" => 0, "Types::URI" => 0.007, "URI::NamespaceMap" => 1.08, }, }, test => { requires => { "FindBin" => 0, "Test::Deep" => 0, "Test::HTTP::LocalServer" => 0, "Test::Modern" => 0, "Test::More" => 0.96, }, }, }, "provides" => { "Test::FITesque::RDF" => { file => "lib/Test/FITesque/RDF.pm", version => "0.10" }, }, "release_status" => "stable", "resources" => { bugtracker => { web => "https://github.com/kjetilk/p5-test-fitesque-rdf/issues" }, homepage => "https://metacpan.org/release/Test-FITesque-RDF", license => ["http://www.opensource.org/licenses/mit-license.php"], repository => { type => "git", url => "git://github.com/kjetilk/p5-test-fitesque-rdf.git", web => "https://github.com/kjetilk/p5-test-fitesque-rdf", }, x_identifier => "http://purl.org/NET/cpan-uri/dist/Test-FITesque-RDF/project", x_IRC => "irc://irc.perl.org/#perlrdf", }, "version" => "0.10", "x_static_install" => 1, }; my %dynamic_config; my %WriteMakefileArgs = ( ABSTRACT => $meta->{abstract}, AUTHOR => ($EUMM >= 6.5702 ? $meta->{author} : $meta->{author}[0]), DISTNAME => $meta->{name}, VERSION => $meta->{version}, EXE_FILES => [ map $_->{file}, values %{ $meta->{x_provides_scripts} || {} } ], NAME => do { my $n = $meta->{name}; $n =~ s/-/::/g; $n }, test => { TESTS => "t/*.t" }, %dynamic_config, ); $WriteMakefileArgs{LICENSE} = $meta->{license}[0] if $EUMM >= 6.3001; sub deps { my %r; for my $stage (@_) { for my $dep (keys %{$meta->{prereqs}{$stage}{requires}}) { next if $dep eq 'perl'; my $ver = $meta->{prereqs}{$stage}{requires}{$dep}; $r{$dep} = $ver if !exists($r{$dep}) || $ver >= $r{$dep}; } } \%r; } my ($build_requires, $configure_requires, $runtime_requires, $test_requires); if ($EUMM >= 6.6303) { $WriteMakefileArgs{BUILD_REQUIRES} ||= deps('build'); $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure'); $WriteMakefileArgs{TEST_REQUIRES} ||= deps('test'); $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime'); } elsif ($EUMM >= 6.5503) { $WriteMakefileArgs{BUILD_REQUIRES} ||= deps('build', 'test'); $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure'); $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime'); } elsif ($EUMM >= 6.52) { $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure'); $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime', 'build', 'test'); } else { $WriteMakefileArgs{PREREQ_PM} ||= deps('configure', 'build', 'test', 'runtime'); } { my ($minperl) = reverse sort( grep defined && /^[0-9]+(\.[0-9]+)?$/, map $meta->{prereqs}{$_}{requires}{perl}, qw( configure build runtime ) ); if (defined($minperl)) { die "Installing $meta->{name} requires Perl >= $minperl" unless $] >= $minperl; $WriteMakefileArgs{MIN_PERL_VERSION} ||= $minperl if $EUMM >= 6.48; } } my $mm = WriteMakefile(%WriteMakefileArgs); exit(0); README000644001750001750 3221214550352012 15351 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10NAME Test::FITesque::RDF - Formulate Test::FITesque fixture tables in RDF SYNOPSIS my $suite = Test::FITesque::RDF->new(source => $file)->suite; $suite->run_tests; See `t/integration-basic.t` for a full test script example using this simplest way. To run a single test script with several fixture tables, you can either add the tests to a suite, like this: my @files = ('test1.ttl','test2.ttl'); my $suite = Test::FITesque::Suite->new; foreach my $file (@files) { $suite->add(Test::FITesque::RDF->new(source => $path . $file)->suite); } $suite->run_tests; or iterate and run the tests for each fixture table like this: my @files = ('test1.ttl','test2.ttl'); foreach my $file (@files) { diag("Reading tests from $path$file"); my $suite = Test::FITesque::RDF->new(source => $path . $file)->suite; $suite->run_tests; } DESCRIPTION This module enables the use of Resource Description Framework to describe fixture tables. It will take the filename of an RDF file and return a Test::FITesque::Suite object that can be used to run tests. The RDF serves to identify the implementation of certain fixtures, and can also supply parameters that can be used by the tests, e.g. input parameters or expectations. See Test::FITesque for more on how the fixtures are implemented. ATTRIBUTES AND METHODS This module implements the following attributes and methods: `source` Required attribute to the constructor. Takes a Path::Tiny object pointing to the RDF file containing the fixture tables. The value will be converted into an appropriate object, so a string can also be supplied. `suite` Will return a Test::FITesque::Suite object, based on the RDF data supplied to the constructor. `transform_rdf` Will return an arrayref containing tests in the structure used by Test::FITesque::Test. Most users will rather call the `suite` method than to call this method directly. `base_uri` A IRI to use in parsing the RDF fixture tables to resolve any relative URIs. REQUIRED RDF The following must exist in the test description (see below for an example and prefix expansions): `test:fixtures` The object(s) of this predicate lists the test fixtures that will run for this test suite. May take an RDF List. Links to the test descriptions, which follow below. `test:test_script` The object of this predicate points to information on how the actual test will be run. That is formulated in a separate resource which requires two predicates, `deps:test-requirement` predicate, whose object contains the class name of the implementation of the tests; and `nfo:definesFunction` whose object is a string which matches the actual function name within that class. `test:purpose` The object of this predicate provides a literal description of the test. `test:params` The object of this predicate links to the parameters, which may have many different shapes. See below for examples. PARAMETERIZATION This module seeks to parameterize the tests, and does so using mostly the `test:params` predicate above. This is passed on as a hashref to the test scripts. There are two main ways currently implemented, one creates key-value pairs, and uses predicates and objects for that respectively, in vocabularies chosen by the test writer. The other main way is create lists of HTTP requests and responses. If the object of a test parameter is a literal, it will be passed as a plain string, if it is a Attean::IRI, it will be passed as a URI object. Additionally, a special parameter `-special` is passed on for internal framework use. The leading dash is not allowed as the start character of a local name, and therefore chosen to avoid conflicts with other parameters. The literal given in `test:purpose` above is passed on as with the `description` key in this hashref. RDF EXAMPLE The below example starts with prefix declarations. Then, the tests in the fixture table are listed explicitly. Only tests mentioned using the `test:fixtures` predicate will be used. Tests may be an RDF List, in which case, the tests will run in the specified sequence, if not, no sequence may be assumed. Then, two test fixtures are declared. The actual implementation is referenced through `test:test_script` for both functions. The `test:params` predicate is used to link the parameters that will be sent as a hashref into the function. The predicate is required to exist outside of the parameters, but will be included as a parameter as well, named `description` in the `-special` hashref. There are two mechanisms for passing parameters to the test scripts, one is simply to pass arbitrary key-value pairs, the other is to pass lists of HTTP request-response objects. Both mechanisms may be used. Key-value parameters The key of the hashref passed as arguments will be the local part of the predicate used in the description (i.e. the part after the colon in e.g. `my:all`). It is up to the test writer to mint the URIs of the parameters. The test writer may optionally use a `param_base` to indicate the namespace, in which case the the local part is resolved by the framework, using URI::NamespaceMap. If `param_base` is not given, the full URI will be passed to the test script. @prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :test1, :test2 . :test1 a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . :test2 a test:AutomatedTest ; test:param_base ; test:purpose "Multiply two numbers"@en ; test:test_script ; test:params [ my:factor1 6 ; my:factor2 7 ; my:product 42 ] . a nfo:SoftwareItem ; nfo:definesFunction "string_found" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . a nfo:SoftwareItem ; nfo:definesFunction "multiplication" ; deps:test-requirement "Internal::Fixture::Multi"^^deps:CpanId . HTTP request-response lists To allow testing HTTP-based interfaces, this module also allows the construction of an ordered list of HTTP requests and response pairs. With those, the framework will construct HTTP::Request and HTTP::Response objects. In tests scripts, the request objects will typically be passed to the LWP::UserAgent as input, and then the response from the remote server will be compared with the asserted HTTP::Responses made by the test fixture. We will go through an example in chunks: @prefix test: . @prefix deps: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :public_writeread_unauthn_alt . :public_writeread_unauthn_alt a test:AutomatedTest ; test:purpose "To test if we can write first using HTTP PUT then read with GET"@en ; test:test_script ; test:params [ test:steps ( [ test:request :public_writeread_unauthn_alt_put_req ; test:response_assertion :public_writeread_unauthn_alt_put_res ] [ test:request :public_writeread_unauthn_alt_get_req ; test:response_assertion :public_writeread_unauthn_alt_get_res ] ) ] . a nfo:SoftwareItem ; deps:test-requirement "Example::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . In the above, after the prefixes, a single test is declared using the `test:fixtures` predicate, linking to a description of the test. The test is then described as an , and it's purpose is declared. It then links to its concrete implementation, which is given in the last three triples in the above. Then, the parameterization is started. In this example, there are two HTTP request-response pairs, which are given as a list object to the `test:steps` predicate. To link the request, the `test:request` predicate is used, to link the asserted response, the `test:response_assertion` predicate is used. Next, we look into the actual request and response messages linked from the above: :public_writeread_unauthn_alt_put_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content " a ." ; http:requestURI . :public_writeread_unauthn_alt_put_res a http:ResponseMessage ; http:status 201 . :public_writeread_unauthn_alt_get_req a http:RequestMessage ; http:method "GET" ; http:requestURI . :public_writeread_unauthn_alt_get_res a http:ResponseMessage ; httph:accept_post "text/turtle", "application/ld+json" ; httph:content_type "text/turtle" . These should be self-explanatory, but note that headers are given with lower-case names and underscores. They will be transformed to headers by replacing underscores with dashes and upcase the first letters. This module will transform the above to data structures that are suitable to be passed to Test::Fitesque, and the above will appear as { '-special' => { 'http-pairs' => [ { 'request' => ... , 'response' => ... , }, { ... } ] }, 'description' => 'To test if we can write first using HTTP PUT then read with GET' }, } Note that there are more examples in this module's test suite in the `t/data/` directory. You may maintain client state in a test script (i.e. for one `test:AutomatedTest`, as it is simply one script, so the result of one request may be used to influence the next. Server state can be relied on between different tests by using an `rdf:List` of test fixtures if it writes something into the server, there is nothing in the framework that changes that. To use data from one response to influence subsequent requests, the framework supports datatyping literals with the `dqm:regex` datatype for headers and HTTP status codes, for example: :check_acl_location_res a http:ResponseMessage ; httph:link '<(.*?)>;\\s+rel="acl"'^^dqm:regex ; http:status "200|204"^^dqm:regex . This makes it possible to use a Perl regular expression, which can be executed in a test script if desired. If present, it will supply another hashref to the `http-pairs` key with the key `regex-fields` containing hashrefs with the header field that had a correspondiing object datatyped regex as key and simply 1 as value. TODO Separate the implementation-specific details (such as `deps:test-requirement`) from the actual fixture tables. BUGS Please report any bugs to . SEE ALSO AUTHOR Kjetil Kjernsmo . COPYRIGHT AND LICENCE This software is Copyright (c) 2019, 2020 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. README.md000644001750001750 3230714550352012 15755 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10# NAME Test::FITesque::RDF - Formulate Test::FITesque fixture tables in RDF # SYNOPSIS my $suite = Test::FITesque::RDF->new(source => $file)->suite; $suite->run_tests; See `t/integration-basic.t` for a full test script example using this simplest way. To run a single test script with several fixture tables, you can either add the tests to a suite, like this: my @files = ('test1.ttl','test2.ttl'); my $suite = Test::FITesque::Suite->new; foreach my $file (@files) { $suite->add(Test::FITesque::RDF->new(source => $path . $file)->suite); } $suite->run_tests; or iterate and run the tests for each fixture table like this: my @files = ('test1.ttl','test2.ttl'); foreach my $file (@files) { diag("Reading tests from $path$file"); my $suite = Test::FITesque::RDF->new(source => $path . $file)->suite; $suite->run_tests; } # DESCRIPTION This module enables the use of Resource Description Framework to describe fixture tables. It will take the filename of an RDF file and return a [Test::FITesque::Suite](https://metacpan.org/pod/Test::FITesque::Suite) object that can be used to run tests. The RDF serves to identify the implementation of certain fixtures, and can also supply parameters that can be used by the tests, e.g. input parameters or expectations. See [Test::FITesque](https://metacpan.org/pod/Test::FITesque) for more on how the fixtures are implemented. ## ATTRIBUTES AND METHODS This module implements the following attributes and methods: - `source` Required attribute to the constructor. Takes a [Path::Tiny](https://metacpan.org/pod/Path::Tiny) object pointing to the RDF file containing the fixture tables. The value will be converted into an appropriate object, so a string can also be supplied. - `suite` Will return a [Test::FITesque::Suite](https://metacpan.org/pod/Test::FITesque::Suite) object, based on the RDF data supplied to the constructor. - `transform_rdf` Will return an arrayref containing tests in the structure used by [Test::FITesque::Test](https://metacpan.org/pod/Test::FITesque::Test). Most users will rather call the `suite` method than to call this method directly. - `base_uri` A [IRI](https://metacpan.org/pod/IRI) to use in parsing the RDF fixture tables to resolve any relative URIs. ## REQUIRED RDF The following must exist in the test description (see below for an example and prefix expansions): - `test:fixtures` The object(s) of this predicate lists the test fixtures that will run for this test suite. May take an RDF List. Links to the test descriptions, which follow below. - `test:test_script` The object of this predicate points to information on how the actual test will be run. That is formulated in a separate resource which requires two predicates, `deps:test-requirement` predicate, whose object contains the class name of the implementation of the tests; and `nfo:definesFunction` whose object is a string which matches the actual function name within that class. - `test:purpose` The object of this predicate provides a literal description of the test. - `test:params` The object of this predicate links to the parameters, which may have many different shapes. See below for examples. ## PARAMETERIZATION This module seeks to parameterize the tests, and does so using mostly the `test:params` predicate above. This is passed on as a hashref to the test scripts. There are two main ways currently implemented, one creates key-value pairs, and uses predicates and objects for that respectively, in vocabularies chosen by the test writer. The other main way is create lists of HTTP requests and responses. If the object of a test parameter is a literal, it will be passed as a plain string, if it is a [Attean::IRI](https://metacpan.org/pod/Attean::IRI), it will be passed as a [URI](https://metacpan.org/pod/URI) object. Additionally, a special parameter `-special` is passed on for internal framework use. The leading dash is not allowed as the start character of a local name, and therefore chosen to avoid conflicts with other parameters. The literal given in `test:purpose` above is passed on as with the `description` key in this hashref. ## RDF EXAMPLE The below example starts with prefix declarations. Then, the tests in the fixture table are listed explicitly. Only tests mentioned using the `test:fixtures` predicate will be used. Tests may be an RDF List, in which case, the tests will run in the specified sequence, if not, no sequence may be assumed. Then, two test fixtures are declared. The actual implementation is referenced through `test:test_script` for both functions. The `test:params` predicate is used to link the parameters that will be sent as a hashref into the function. The <test:purpose> predicate is required to exist outside of the parameters, but will be included as a parameter as well, named `description` in the `-special` hashref. There are two mechanisms for passing parameters to the test scripts, one is simply to pass arbitrary key-value pairs, the other is to pass lists of HTTP request-response objects. Both mechanisms may be used. ### Key-value parameters The key of the hashref passed as arguments will be the local part of the predicate used in the description (i.e. the part after the colon in e.g. `my:all`). It is up to the test writer to mint the URIs of the parameters. The test writer may optionally use a `param_base` to indicate the namespace, in which case the the local part is resolved by the framework, using [URI::NamespaceMap](https://metacpan.org/pod/URI::NamespaceMap). If `param_base` is not given, the full URI will be passed to the test script. @prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :test1, :test2 . :test1 a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . :test2 a test:AutomatedTest ; test:param_base ; test:purpose "Multiply two numbers"@en ; test:test_script ; test:params [ my:factor1 6 ; my:factor2 7 ; my:product 42 ] . a nfo:SoftwareItem ; nfo:definesFunction "string_found" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . a nfo:SoftwareItem ; nfo:definesFunction "multiplication" ; deps:test-requirement "Internal::Fixture::Multi"^^deps:CpanId . ### HTTP request-response lists To allow testing HTTP-based interfaces, this module also allows the construction of an ordered list of HTTP requests and response pairs. With those, the framework will construct [HTTP::Request](https://metacpan.org/pod/HTTP::Request) and [HTTP::Response](https://metacpan.org/pod/HTTP::Response) objects. In tests scripts, the request objects will typically be passed to the [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) as input, and then the response from the remote server will be compared with the asserted [HTTP::Response](https://metacpan.org/pod/HTTP::Response)s made by the test fixture. We will go through an example in chunks: @prefix test: . @prefix deps: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :public_writeread_unauthn_alt . :public_writeread_unauthn_alt a test:AutomatedTest ; test:purpose "To test if we can write first using HTTP PUT then read with GET"@en ; test:test_script ; test:params [ test:steps ( [ test:request :public_writeread_unauthn_alt_put_req ; test:response_assertion :public_writeread_unauthn_alt_put_res ] [ test:request :public_writeread_unauthn_alt_get_req ; test:response_assertion :public_writeread_unauthn_alt_get_res ] ) ] . a nfo:SoftwareItem ; deps:test-requirement "Example::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . In the above, after the prefixes, a single test is declared using the `test:fixtures` predicate, linking to a description of the test. The test is then described as an <test:AutomatedTest>, and it's purpose is declared. It then links to its concrete implementation, which is given in the last three triples in the above. Then, the parameterization is started. In this example, there are two HTTP request-response pairs, which are given as a list object to the `test:steps` predicate. To link the request, the `test:request` predicate is used, to link the asserted response, the `test:response_assertion` predicate is used. Next, we look into the actual request and response messages linked from the above: :public_writeread_unauthn_alt_put_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content " a ." ; http:requestURI . :public_writeread_unauthn_alt_put_res a http:ResponseMessage ; http:status 201 . :public_writeread_unauthn_alt_get_req a http:RequestMessage ; http:method "GET" ; http:requestURI . :public_writeread_unauthn_alt_get_res a http:ResponseMessage ; httph:accept_post "text/turtle", "application/ld+json" ; httph:content_type "text/turtle" . These should be self-explanatory, but note that headers are given with lower-case names and underscores. They will be transformed to headers by replacing underscores with dashes and upcase the first letters. This module will transform the above to data structures that are suitable to be passed to [Test::Fitesque](https://metacpan.org/pod/Test::Fitesque), and the above will appear as { '-special' => { 'http-pairs' => [ { 'request' => ... , 'response' => ... , }, { ... } ] }, 'description' => 'To test if we can write first using HTTP PUT then read with GET' }, } Note that there are more examples in this module's test suite in the `t/data/` directory. You may maintain client state in a test script (i.e. for one `test:AutomatedTest`, as it is simply one script, so the result of one request may be used to influence the next. Server state can be relied on between different tests by using an `rdf:List` of test fixtures if it writes something into the server, there is nothing in the framework that changes that. To use data from one response to influence subsequent requests, the framework supports datatyping literals with the `dqm:regex` datatype for headers and HTTP status codes, for example: :check_acl_location_res a http:ResponseMessage ; httph:link '<(.*?)>;\\s+rel="acl"'^^dqm:regex ; http:status "200|204"^^dqm:regex . This makes it possible to use a Perl regular expression, which can be executed in a test script if desired. If present, it will supply another hashref to the `http-pairs` key with the key `regex-fields` containing hashrefs with the header field that had a correspondiing object datatyped regex as key and simply `1` as value. # TODO Separate the implementation-specific details (such as `deps:test-requirement`) from the actual fixture tables. # BUGS Please report any bugs to [https://github.com/kjetilk/p5-test-fitesque-rdf/issues](https://github.com/kjetilk/p5-test-fitesque-rdf/issues). # SEE ALSO # AUTHOR Kjetil Kjernsmo . # COPYRIGHT AND LICENCE This software is Copyright (c) 2019, 2020 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License # DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. SIGNATURE000644001750001750 1251614550352012 15762 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.88. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: RIPEMD160 SHA256 526b0b98494952c39bc0d97d3ad416c666346cd2420d2b448dcfc82388a387f0 COPYRIGHT SHA256 30124a7479135ae55cc1c0d132de9c5e1bd7afa73b48d46182e6ce4ed2995415 CREDITS SHA256 db9d89d1c410cbc4d99f4ccb8275c51c92c93b469dca2e6154be738f7885ce99 Changes SHA256 8fd1468ddacc4d6d78f175943e8a5b918e87cc44b1e2edf913ca114fd0bf0708 INSTALL SHA256 be8d45dd9a3843e499874bed2d4ecc09b731417a2353b810506c52baacfdffae LICENSE SHA256 e19b54081db6f783e167b8178c5ca0fc4a3f356143ea86c27bbaf6ff39a28e20 MANIFEST SHA256 d388a0d514b333070ccc2f93d9913db7667033207a8628d8265d611fdb99ee81 META.json SHA256 6df5ffa35f28ad53a85f04ceae5f91bb302e91ea4b5bce20a6e36094ef4a0312 META.yml SHA256 13810f6a59fa718a971b685e796383deb69cdc6b68503b870f9a88334e027d35 Makefile.PL SHA256 a1f3741757471321cfefb7ce8e5abb4bb4309743206bfffc572db76771210506 README SHA256 57c33270d60fa178ff3914a61f738c2f77bf17e51ebdb62603f50fcf36a9e916 README.md SHA256 fb7d510bfb8c69d33753a712fb9ab4b159a89b6435ed69d7be15e8783ee1a250 dist.ini SHA256 f69a0030025367ad794e67dd495906940b9585906106584b7b4b3ef2475d878b doap.ttl SHA256 94f2d8858d9bdabfefc9158ad6858b52589b04ad3ce4b4aaa4277bf91196ba83 lib/Test/FITesque/RDF.pm SHA256 3c01388312e5d42a15630b913efca12a615f082948e0d17fd622ea1ed850cf43 t/01basic.t SHA256 8a6792e7905f9e2ceafa3a5c9a3b9eaa5c5e0f20a42df84b4a5045ef635343f1 t/data/http-external-content-blank.ttl SHA256 55ff2b660d8ab4f3bc465c41a25abc29f2328c6f8f99f3d16cc8225949fc29c8 t/data/http-external-content-invalid.ttl SHA256 1d78deca73ab457ca7c9b8b2e12ee16620da4ccefb2581adfff753b6d4a02019 t/data/http-external-content.ttl SHA256 e27ea62e34bbd745d0e1fe1cb8b91f1cdc330bd5dce5eead89e20a57d9ce9257 t/data/http-list-multi.ttl SHA256 5c34b74f872f5ab58c14853910fd4d2fa6d72ec20b436007833388a3cec2e8d5 t/data/http-list.ttl SHA256 2fc6f922192147cd3df913c0ea7b7ab1a2eb65acdd8482607cbc573c050acb92 t/data/http-mix.ttl SHA256 f90c297b00d75316cf6417045de1d39fe620981e4f4b4b2b3e9f35ec125fca04 t/data/http-regex.ttl SHA256 064b54ee839db012689eb2c531936277a84ac4b3d22c3976e52a1989247cff89 t/data/invalid.ttl SHA256 c74b9b1a617c39569df62ab0a7109c0bbba1d5a93d818d015c6f6818b6e3651e t/data/list.ttl SHA256 c4494a7663fa5929dad35a9758e518fca865fa4c8c88e6984674dd55c52ea3ca t/data/multi-vocab.ttl SHA256 c24cfb5236c82cb20191df5bf813e62b28ea79d21bab6aae119afd49dc5065a5 t/data/multi.ttl SHA256 67d7f4b45b79245796569cf4f41d798e25ad1ae404bfad02d80995125927e58b t/data/notests.ttl SHA256 ff0a3bda99ff1a003b758773a9a4ad2cb80f84997b07fffce633cce095032c4c t/data/relative.ttl SHA256 b2dadf5f14b482d07e5bb08fedae04ea3244adfcd36dffdcead671e5eb76c85b t/data/simple.ttl SHA256 692cc1eaff21870ef76a3c0786031309b9e1e615b7711dac189272690ef26992 t/data/undescribed.ttl SHA256 d1ce30659208eb1b955fee124509edb7215731c292af7c87acd7fadd8128e38b t/integration-basic.t SHA256 b9bd2bbf64b933818200c0b56e4022d4f8f8e836b0130ac0393b54dbafc0f833 t/integration-http-list.t SHA256 9318a8d60d1fd02d7f2f25569188760d9fce8bace6d1f2d23270642f0349a5d3 t/lib/Internal/Fixture/HTTPList.pm SHA256 25f16adad72d821a6df65551b9b68e8714c46296979ee3286faebc509bdd4e86 t/lib/Internal/Fixture/Multi.pm SHA256 db4ff2c284dd1849e68fd88fb12d93e390de95c91b0651025444409a53629fad t/lib/Internal/Fixture/Simple.pm SHA256 6624611631ff6ec1100e1b5cd912daa21e15d2d02ebf67e9d2f5f5647ba7bc69 t/unit-http-list.t SHA256 e3ef1a3c64c5875f0509cc4e4d328d632a3802fc5456b98aa144c280a7a1f6af t/unit-http-mix.t SHA256 bf0987223904f4bdff22bda7880f15d067a042f9d00086065b19cef2d5c0d7ba t/unit-http-regex.t SHA256 ad43e21f618c52b3f4865b0cebedda7373faef0121a921c14b1b1722ad486308 t/unit-http-server.t SHA256 df539194677254c0d2fc06e44104eacb1095f9ef5339b5d1bb5d061f124f9b9e t/unit-list.t SHA256 22ae35c81683e909da89428e86d15f8911f4f55f8c24cccc3d008e0e5c30710d t/unit-multi-http.t SHA256 0bc3f7720a9a159210e4cc8fab54dcd9533c19143a9388c3965aacee3a520e98 t/unit-multi-vocab.t SHA256 f337aaaa2d1f7ad74fcdc6f41fe05688e49dc07493cd069eaf640ca7b584dbf3 t/unit-multi.t SHA256 5b8023324c9ece4e4699001f8fcf52f1d690dc4fb980dbcda87b5cfc38c515a3 t/unit-relative.t SHA256 6caf112a41b2e3a6c20a0c2773163ce1cd13bdce1f3d7d077c00df91f19faf83 t/unit-simple.t -----BEGIN PGP SIGNATURE----- iQIzBAEBAwAdFiEEDsyLxtCi6bk7pBcmf77o3zqeSqUFAmWh1AkACgkQf77o3zqe SqWKyw/+Jwv4cfL+e8/iuPTBIXF+cfcXbJjsJHPewqXtMO7lbu3I7TwChCxUv0MO NKrMoVfZn8RTmURWR1pI3dfZ7CLzx0lJYtl/jkB9bRL4o1mERlZARI1KODFIAb1E pB+GRnBgFsJyQOsVHULUw979EULcGZt8adt9I+nvRroCmoWm6T8TkpiL+iwguRa9 jxBPT6DnpWbu3ofMcM5jjVlHhWgqO9a9OY1dLyIpeNzzRjcKqzsXvlCIvQyfaYHw xgFCngb2+T8KK+DTPX5DMfsr2Hps75B+3xXpcdQwrOr1fCfkJ+8o8AZ6Um/hwZZ8 SWv3kBasJ1DYIa0cz84vVtQ95+liPV+Y8NHfMITH7btTEODbNnI5ykirPwrkX+Hk 79Lg/RMW+Px6Ng5O/Jy9lyTM21CW0v6U8wB51zyjlAhtzhMS3ply8WGoPOk6ykfE WcogESeVkPrzG3prdE+RUi/K/qjyDG3bl9sat99M3jA0nCAfTrkxllyxR/ZZy75C yLMS0S3LHPjNlhyt1i0QyfoLSPvjIpUMT1t51qdoi2Q5T2lZiyvAenjVnkQdzVMD iW+CqG1TYMIlexfC7mE95TJ9W7vW1rOxSZtjF+Tz26MtCg2VqLUWDHw5zs6BCKSN gLVHQSJjD+qlyCG9ONKBSraSLgqXZr8/3TP6xVbspwEfamVcXYQ= =KE+f -----END PGP SIGNATURE----- dist.ini000644001750001750 10314550352012 16067 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10;;class='Dist::Inkt::Profile::KJETILK' ;;name='Test-FITesque-RDF' doap.ttl000644001750001750 4014314550352012 16143 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10@prefix dc: . @prefix doap: . @prefix doap-changeset: . @prefix doap-deps: . @prefix foaf: . @prefix owl: . @prefix prov: . @prefix rdfs: . @prefix types: . @prefix wot: . @prefix xsd: . a doap:Project; dc:contributor ; doap-deps:develop-recommendation [ doap-deps:on "Dist::Inkt 0.001"^^doap-deps:CpanId ]; doap-deps:runtime-requirement [ doap-deps:on "Try::Tiny"^^doap-deps:CpanId ], [ doap-deps:on "Types::Standard"^^doap-deps:CpanId ], [ doap-deps:on "Types::URI 0.007"^^doap-deps:CpanId ], [ doap-deps:on "Test::FITesque"^^doap-deps:CpanId ], [ doap-deps:on "URI::NamespaceMap 1.08"^^doap-deps:CpanId; ], [ doap-deps:on "RDF::NS::Curated 1.002"^^doap-deps:CpanId; ], [ doap-deps:on "RDF::Prefixes"^^doap-deps:CpanId ], [ doap-deps:on "Path::Tiny"^^doap-deps:CpanId ], [ doap-deps:on "HTTP::Message"^^doap-deps:CpanId ], [ doap-deps:on "perl 5.014"^^doap-deps:CpanId ], [ doap-deps:on "LWP::UserAgent"^^doap-deps:CpanId ], [ doap-deps:on "Types::Path::Tiny"^^doap-deps:CpanId ], [ doap-deps:on "Moo 1.006000"^^doap-deps:CpanId ], [ doap-deps:on "Attean 0.025"^^doap-deps:CpanId ]; doap-deps:test-requirement [ doap-deps:on "Test::More 0.96"^^doap-deps:CpanId ], [ doap-deps:on "Test::Modern"^^doap-deps:CpanId ], [ doap-deps:on "Test::Deep"^^doap-deps:CpanId ], [ doap-deps:on "Test::HTTP::LocalServer"^^doap-deps:CpanId; ], [ doap-deps:on "FindBin"^^doap-deps:CpanId ]; doap:bug-database ; doap:created "2019-04-09"^^xsd:date; doap:developer ; doap:download-page ; doap:helper ; doap:homepage ; doap:license ; doap:maintainer ; doap:name "Test-FITesque-RDF"; doap:programming-language "Perl"; doap:release , , , , , , , , , , , , , , , ; doap:repository [ a doap:GitRepository; doap:browse ; prov:has_provenance ; ]; doap:security-contact ; doap:shortdesc "Formulate Test::FITesque fixture tables in RDF"; doap:support-forum . a doap:Version; rdfs:label "Initial release"; dc:identifier "Test-FITesque-RDF-0.001"^^xsd:string; dc:issued "2019-04-29"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.001"^^xsd:string. a doap:Version; rdfs:label "Minor tweaks"; dc:identifier "Test-FITesque-RDF-0.002"^^xsd:string; dc:issued "2019-04-30"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.002"^^xsd:string. a doap:Version; rdfs:label "Add more dependencies"; dc:identifier "Test-FITesque-RDF-0.003"^^xsd:string; dc:issued "2019-04-30"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.003"^^xsd:string. a doap:Version; rdfs:label "Support RDF lists"; dc:identifier "Test-FITesque-RDF-0.004"^^xsd:string; dc:issued "2019-06-03"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.004"^^xsd:string. a doap:Version; rdfs:label "Support several vocabularies for parameters"; dc:identifier "Test-FITesque-RDF-0.005"^^xsd:string; dc:issued "2019-06-03"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.005"^^xsd:string. a doap:Version; rdfs:label "Create HTTP request-response objects"; dc:identifier "Test-FITesque-RDF-0.006"^^xsd:string; dc:issued "2019-06-07"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.006"^^xsd:string. a doap:Version; rdfs:label "Support content for HTTP request objects"; dc:identifier "Test-FITesque-RDF-0.007"^^xsd:string; dc:issued "2019-06-13"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.007"^^xsd:string. a doap:Version; rdfs:label "Fix bug in HTTP param selection"; dc:identifier "Test-FITesque-RDF-0.008"^^xsd:string; dc:issued "2019-06-20"^^xsd:date; doap-changeset:released-by ; doap:file-release ; doap:revision "0.008"^^xsd:string. a doap:Version; rdfs:label "Improve vocabulary usage"; dc:identifier "Test-FITesque-RDF-0.009"^^xsd:string; dc:issued "2019-07-04"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Improve Travis usage."; ], [ a doap-changeset:Change; rdfs:label "Some improvements to how ontologies are used."; ], [ a doap-changeset:Addition; rdfs:label "Improve documentation."; ], [ a doap-changeset:Addition; rdfs:label "Tests for multi-field values."; ], [ a doap-changeset:Addition; rdfs:label "Improve error handling."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.009"^^xsd:string. a doap:Version; rdfs:label "Adapt to existing vocabularies"; dc:identifier "Test-FITesque-RDF-0.010"^^xsd:string; dc:issued "2019-07-05"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Change; rdfs:label "Adapt to existing vocabularies."; ], [ a doap-changeset:Change; rdfs:label "Allow mixing parameters."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.010"^^xsd:string. a doap:Version; rdfs:label "Implement regular expressions for stateful tests"; dc:identifier "Test-FITesque-RDF-0.011"^^xsd:string; dc:issued "2019-08-03"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Support regular expressions with a new array."; ], [ a doap-changeset:Addition; rdfs:label "Improve documentation."; ], [ a doap-changeset:Change; rdfs:label "Introduce a -special key to the parameters to group all internal additions."; ], [ a doap-changeset:Change; rdfs:label "Some minor fixes."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.011"^^xsd:string. a doap:Version; rdfs:label "Passing URIs as parameters"; dc:identifier "Test-FITesque-RDF-0.012"^^xsd:string; dc:issued "2019-08-26"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "If the object of a parameter is a IRI, pass a URI object."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.012"^^xsd:string. a doap:Version; rdfs:label "Improve the RDF"; dc:identifier "Test-FITesque-RDF-0.014"^^xsd:string; dc:issued "2019-09-23"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:BackCompat; rdfs:label "Restructure HTTP request-response pair parameterization."; ], [ a doap-changeset:Documentation; rdfs:label "Improve documentation."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.014"^^xsd:string. a doap:Version; rdfs:label "Test coverage to 100%"; dc:identifier "Test-FITesque-RDF-0.016"^^xsd:string; dc:issued "2019-10-28"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Add tests to bring the test coverage to 100%."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.016"^^xsd:string. a doap:Version; rdfs:label "Support different status codes"; dc:identifier "Test-FITesque-RDF-0.018"^^xsd:string; dc:issued "2020-02-06"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Addition; rdfs:label "Make it possible to use status as regular expression."; ], [ a doap-changeset:Update; rdfs:label "Use the new coercions in Attean."; ], [ a doap-changeset:Change; rdfs:label "Improve documentation."; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.018"^^xsd:string. a doap:Version; rdfs:label "Fix DNS from invalid host"; dc:identifier "Test-FITesque-RDF-0.10"^^xsd:string; dc:issued "2024-01-13"^^xsd:date; doap-changeset:changeset [ doap-changeset:item [ a doap-changeset:Bugfix; rdfs:label "Add . to fix github issue #12."; doap-changeset:thanks ; ]; doap-changeset:versus ; ]; doap-changeset:released-by ; doap:file-release ; doap:revision "0.10"^^xsd:string. a foaf:Person; foaf:mbox ; foaf:name "Kjetil Kjernsmo"; foaf:nick "KJETILK", "KjetilK"; foaf:page ; owl:sameAs , , ; rdfs:seeAlso ; wot:hasKey _:B1. a foaf:Person; foaf:name "Scott McWhirter", "Scott McWirther"; foaf:nick "KONOBI", "konobi"; foaf:page . a foaf:Person; foaf:name "Slaven Rezić"; foaf:nick "SREZIC"; foaf:page . a foaf:Person; foaf:homepage ; foaf:mbox ; foaf:name "Kjetil Kjernsmo"; foaf:nick "KjetilK"; owl:sameAs , ; rdfs:seeAlso , ; wot:hasKey _:B1. dc:title "The MIT License"@en. a types:ChatChannel; dc:title "The Perl and RDF IRC channel"@en. _:B1 a wot:PubKey; wot:fingerprint "0ECC8BC6D0A2E9B93BA417267FBEE8DF3A9E4AA5". 01basic.t000644001750001750 72414550352012 16306 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Test that Test::FITesque::RDF compiles. =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use_ok('Test::FITesque::RDF'); diag( "Testing Test::FITesque::RDF $Test::FITesque::RDF::VERSION, Perl $], $^X" ); done_testing; integration-basic.t000644001750001750 346514550352012 20513 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Integration tests using Test::FITesque::Test with RDF data to see tests actually working =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use Test::Modern qw(-more -fatal -warnings -deeper); use FindBin qw($Bin); use Test::FITesque; use Test::FITesque::Test; use lib 't/lib'; use_ok('Test::FITesque::RDF'); subtest 'Run with no file' => sub { like( exception { my $suite = Test::FITesque::RDF->new(source => undef)->suite }, qr/Undef did not pass type constraint "Path"/, 'Failed due to missing file' ) }; subtest 'Run with invalid file' => sub { my $file = $Bin . '/data/invalid.ttl'; like( exception { my $suite = Test::FITesque::RDF->new(source => $file)->suite }, qr|Failed to parse \S+/t/data/invalid.ttl due to|, 'Failed correctly due to parse error' ) }; subtest 'Run with no tests file' => sub { my $file = $Bin . '/data/notests.ttl'; like( exception { my $suite = Test::FITesque::RDF->new(source => $file)->suite }, qr|No tests found in \S+t/data/notests.ttl|, 'Failed correctly due to no test error' ) }; subtest 'Run with no descriptions in file' => sub { my $file = $Bin . '/data/undescribed.ttl'; my @expect = (ignore(), ignore()); # TODO: Improve pattern matching cmp_deeply( warning { my $suite = Test::FITesque::RDF->new(source => $file)->suite }, bag(@expect), 'Failed correctly due to undescribed test error' ) }; subtest 'Test multiple tests' => sub { my $file = $Bin . '/data/multi.ttl'; my $suite = Test::FITesque::RDF->new(source => $file)->suite; $suite->run_tests; }; done_testing; integration-http-list.t000644001750001750 122614550352012 21353 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Integration tests using Test::FITesque::Test with HTTP formulated as RDF data to see tests actually working =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use FindBin qw($Bin); use Test::FITesque; use Test::FITesque::Test; use lib 't/lib'; my $file = $Bin . '/data/http-list.ttl'; use Test::FITesque::RDF; my $suite = Test::FITesque::RDF->new(source => $file)->suite; $suite->run_tests; done_testing; unit-http-list.t000644001750001750 455014550352012 20012 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms HTTP data correctly from RDF =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::Modern; use Test::Deep; use FindBin qw($Bin); use Data::Dumper; my $file = $Bin . '/data/http-list.ttl'; use Test::FITesque::RDF; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file) }, 'RDF Fixture object', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); my $data = $t->transform_rdf; cmp_deeply($data, [ [ [ 'Internal::Fixture::HTTPList' ], [ 'http_req_res_list_unauthenticated', { '-special' => { 'http-pairs' => ignore(), 'description' => 'More elaborate HTTP vocab for PUT then GET test' }, } ] ] ], 'Main structure ok'); my $params = $data->[0]->[1]->[1]->{'-special'}; is(scalar @{$params->{'http-pairs'}}, 2, 'There are two request-response pairs'); foreach my $pair (@{$params->{'http-pairs'}}) { object_ok($pair->{request}, 'Checking request object', isa => ['HTTP::Request'], can => [qw(method uri headers content)] ); object_ok($pair->{response}, 'Checking response object', isa => ['HTTP::Response'], can => [qw(code headers)] ); } is(${$params->{'http-pairs'}}[0]->{request}->method, 'PUT', 'First method is PUT'); is(${$params->{'http-pairs'}}[1]->{request}->method, 'GET', 'Second method is GET'); like(${$params->{'http-pairs'}}[0]->{request}->content, qr/dahut/, 'First request has content'); is(${$params->{'http-pairs'}}[0]->{response}->code, '201', 'First code is 201'); is(${$params->{'http-pairs'}}[1]->{response}->content_type, 'text/turtle', 'Second ctype is turtle'); cmp_deeply([${$params->{'http-pairs'}}[1]->{response}->header('Content-Type')], bag("text/turtle"), 'Response header field value bag comparison can be used for single values'); cmp_deeply([${$params->{'http-pairs'}}[1]->{response}->header('Accept-Post')], bag("text/turtle", "application/ld+json"), 'Response header field value bag comparison'); done_testing; unit-http-mix.t000644001750001750 313514550352012 17632 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms both basic key-value parameters and HTTP data correctly from RDF =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::Modern; use Test::Deep; use FindBin qw($Bin); use Data::Dumper; my $file = $Bin . '/data/http-mix.ttl'; use Test::FITesque::RDF; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file) }, 'RDF Fixture object', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); my $data = $t->transform_rdf; cmp_deeply($data, [ [ [ 'Internal::Fixture::HTTPList' ], [ 'http_req_res_list_unauthenticated', { 'user' => 'alice', '-special' => { 'description' => 'Mix HTTP and ordinary params.', 'http-pairs' => [ { 'regex-fields' => {}, 'request' => methods(method => 'GET'), 'response' => isa('HTTP::Response'), } ] } } ] ] ], 'Main structure ok'); is(scalar @{$data->[0]->[1]->[1]->{'-special'}->{'http-pairs'}}, 1, 'There is one request'); my $params = $data->[0]->[1]->[1]->{'-special'}->{'http-pairs'}->[0]; object_ok($params->{request}, 'Checking request object', isa => ['HTTP::Request'], can => [qw(method uri headers content)] ); done_testing; unit-http-regex.t000644001750001750 417614550352012 20155 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms HTTP data correctly from RDF =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::Modern; use Test::Deep; use FindBin qw($Bin); use Data::Dumper; my $file = $Bin . '/data/http-regex.ttl'; use Test::FITesque::RDF; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file) }, 'RDF Fixture object', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); my $data = $t->transform_rdf; #warn Dumper($data); cmp_deeply($data, [ [ [ 'Internal::Fixture::HTTPList' ], [ 'http_req_res_list_regex', { '-special' => { 'description' => 'Test fields with regexps', 'http-pairs' => [ { 'request' => isa("HTTP::Request"), 'response' => isa("HTTP::Response"), 'regex-fields' => { 'Link' => 1 }, }, { 'request' => isa("HTTP::Request"), 'response' => isa("HTTP::Response"), 'regex-fields' => {'status' => 1}, }, { 'request' => isa("HTTP::Request"), 'response' => isa("HTTP::Response"), 'regex-fields' => { 'Other-Header' => 1, 'Location' => 1 } } ] }, } ] ] ], 'Main structure ok'); my $params = $data->[0]->[1]->[1]->{'-special'}->{'http-pairs'}; is(scalar @{$params}, 3, 'There are three pairs'); like($params->[0]->{response}->header('Link'), qr|;\\s|, 'Should be single escaped'); is($params->[1]->{response}->code, '201|204', 'Status is correct'); #TODO: This could break if underlying framework starts to enforce a format that only includes three-digit status codes done_testing; unit-http-server.t000644001750001750 615014550352012 20343 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms HTTP data correctly from RDF when retrieving external content =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::HTTP::LocalServer; my $server = Test::HTTP::LocalServer->spawn(html => 'foo'); my $base_url = $server->url; use Test::Modern; use Test::Deep; use FindBin qw($Bin); use Path::Tiny qw(tempfile path); use Data::Dumper; use Test::FITesque::RDF; subtest 'Invalid remote source' => sub { my $file = $Bin . '/data/http-external-content-invalid.ttl'; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file) }, 'RDF Fixture object', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); like( exception { my $data = $t->transform_rdf; }, qr|Could not retrieve content from http://example.invalid./dahut . Got 500|, 'Failed to get from invalid host'); }; subtest 'Get content remotely' => sub { my $file = path($Bin . '/data/http-external-content.ttl'); my $ttl = $file->slurp_utf8; $ttl =~ s|urn:some_content_to_put|$base_url|; my $tempfile = tempfile(suffix => '.ttl'); my $fh = $tempfile->openw_utf8; print $fh $ttl; close $fh; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $tempfile) }, 'RDF Fixture object', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); my $data = $t->transform_rdf; cmp_deeply($data, [ [ [ 'Internal::Fixture::HTTPList' ], [ 'http_req_res_list_unauthenticated', { '-special' => { 'http-pairs' => ignore(), 'description' => 'Test for content on external URL that is invalid' }, } ] ] ], 'Main structure ok'); my $params = $data->[0]->[1]->[1]->{'-special'}; is(scalar @{$params->{'http-pairs'}}, 1, 'There is request-response pair'); foreach my $pair (@{$params->{'http-pairs'}}) { object_ok($pair->{request}, 'Checking request object', isa => ['HTTP::Request'], can => [qw(method uri headers content)] ); object_ok($pair->{response}, 'Checking response object', isa => ['HTTP::Response'], can => [qw(code headers)] ); } is(${$params->{'http-pairs'}}[0]->{request}->method, 'PUT', 'First method is PUT'); like(${$params->{'http-pairs'}}[0]->{request}->content, qr/foo/, 'First request has content'); }; subtest 'Remote source with blank node' => sub { my $file = $Bin . '/data/http-external-content-blank.ttl'; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file) }, 'RDF Fixture object', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); like( exception { my $data = $t->transform_rdf; }, qr|Unsupported object _:foo in \S+/http-external-content-blank.ttl|, 'Blank node is unsupported'); }; done_testing; unit-list.t000644001750001750 221514550352012 17031 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms data correctly from RDF with multiple tests and multiple parameters =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use Test::Deep; use FindBin qw($Bin); my $file = $Bin . '/data/list.ttl'; use_ok('Test::FITesque::RDF'); my $t = Test::FITesque::RDF->new(source => $file); my $data = $t->transform_rdf; my $multi = [ [ 'Internal::Fixture::Multi' ], [ 'multiplication', { '-special' => { 'description' => 'Multiply two numbers'}, 'factor1' => '6', 'product' => '42', 'factor2' => '7' } ] ]; my $simple = [ [ 'Internal::Fixture::Simple' ], [ 'string_found', { '-special' => { 'description' => 'Echo a string'}, 'all' => 'counter-clockwise dahut' } ] ]; cmp_deeply($data, [$simple, $multi], 'Compare the data structures'); done_testing; unit-multi-http.t000644001750001750 440514550352012 20170 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms data correctly from RDF with multiple tests and multiple parameters =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use Test::Deep; use FindBin qw($Bin); my $file = $Bin . '/data/http-list-multi.ttl'; use_ok('Test::FITesque::RDF'); my $t = Test::FITesque::RDF->new(source => $file); my $data = $t->transform_rdf; my $put_expect = [ [ 'Internal::Fixture::HTTPList' ], [ 'http_req_res_list_unauthenticated', { '-special' => { 'description' => 'More elaborate HTTP vocab for PUT then GET test', 'http-pairs' => [ { 'regex-fields' => {}, 'request' => methods(method => 'PUT'), 'response' => methods(code => '201'), }, { 'regex-fields' => {}, 'request' => methods(method => 'GET'), 'response' => isa('HTTP::Response') } ] } } ] ]; my $cors_expect = [ [ 'Internal::Fixture::HTTPList' ], [ 'http_req_res_list_unauthenticated', { '-special' => { 'description' => 'Testing CORS header when Origin is supplied by client', 'http-pairs' => [ { 'regex-fields' => {}, 'request' => methods(method => 'GET'), 'response' => isa('HTTP::Response') } ] } } ] ]; cmp_deeply($data, [$put_expect, $cors_expect], 'Check basic structure'); my $cors_actual = $data->[1]->[1]->[1]->{'-special'}->{'http-pairs'}->[0]; ok(defined($cors_actual->{'request'}->header('Origin')), 'Origin header found'); ok(defined($cors_actual->{'response'}->header('Access-Control-Allow-Origin')), 'ACAO header found'); is($cors_actual->{'request'}->header('Origin'), $cors_actual->{'response'}->header('Access-Control-Allow-Origin'), 'CORS echos origin'); done_testing; unit-multi-vocab.t000644001750001750 163114550352012 20301 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms data correctly from RDF with multiple vocabularies =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use Test::Deep; use FindBin qw($Bin); my $file = $Bin . '/data/multi-vocab.ttl'; use_ok('Test::FITesque::RDF'); my $t = Test::FITesque::RDF->new(source => $file); my $data = $t->transform_rdf; my $simple = [[ [ 'Internal::Fixture::Simple' ], [ 'multi_vocabs', { 'http://example.org/other-vocab#foo' => '42', 'all' => 'counter-clockwise dahut', '-special' => { 'description' => 'Echo a string' }, } ] ]]; cmp_deeply($data, $simple); done_testing; unit-multi.t000644001750001750 267714550352012 17224 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Unit test that Test::FITesque::RDF transforms data correctly from RDF with multiple tests and multiple parameters =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::More; use Test::Deep; use FindBin qw($Bin); my $file = $Bin . '/data/multi.ttl'; use_ok('Test::FITesque::RDF'); my $t = Test::FITesque::RDF->new(source => $file); my $data = $t->transform_rdf; my $multi = [ [ 'Internal::Fixture::Multi' ], [ 'multiplication', { '-special' => { 'description' => 'Multiply two numbers' }, 'factor1' => '6', 'product' => '42', 'factor2' => '7' } ] ]; my $simple = [ [ 'Internal::Fixture::Simple' ], [ 'string_found', { '-special' => { 'description' => 'Echo a string' }, 'all' => 'counter-clockwise dahut' } ] ]; my $nobase = [ [ 'Internal::Fixture::Simple' ], [ 'string_found_long', { '-special' => { 'description' => 'Run with no param_base' }, 'http://example.org/my-parameters#all' => 'counter-clockwise dahut' } ] ]; cmp_deeply($data, bag($multi, $simple, $nobase), 'Compare the data structures'); done_testing; unit-relative.t000644001750001750 203314550352012 17667 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Simple unit test that Test::FITesque::RDF transforms data correctly from RDF =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::Modern; use Test::Deep; use FindBin qw($Bin); my $file = $Bin . '/data/relative.ttl'; use Test::FITesque::RDF; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file, base_uri => 'http://example.org/') }, '$t', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf base_uri)]); my $data = $t->transform_rdf; cmp_deeply($data, [ [ [ 'Internal::Fixture::Simple' ], [ 'relative_uri', { '-special' => { 'description' => 'Check that a relative URI resolves' }, 'url' => all(isa('URI'), methods(as_string => 'http://example.org/foo/')) } ] ] ]); done_testing; unit-simple.t000644001750001750 163214550352012 17351 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t=pod =encoding utf-8 =head1 PURPOSE Simple unit test that Test::FITesque::RDF transforms data correctly from RDF =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =cut use strict; use warnings; use Test::Modern; use FindBin qw($Bin); my $file = $Bin . '/data/simple.ttl'; use Test::FITesque::RDF; my $t = object_ok( sub { Test::FITesque::RDF->new(source => $file) }, '$t', isa => [qw(Test::FITesque::RDF Moo::Object)], can => [qw(source suite transform_rdf)]); my $data = $t->transform_rdf; cmp_deeply($data, [ [ [ 'Internal::Fixture::Simple' ], [ 'string_found', { '-special' => { 'description' => 'Echo a string' }, 'all' => 'counter-clockwise dahut' } ] ] ]); done_testing; http-external-content-blank.ttl000644001750001750 240514550352012 23707 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures ( :html_content ). :html_content a test:AutomatedTest ; test:purpose "Test for content on external URL that is invalid"@en ; test:test_script ; test:params [ test:steps ( [ test:request :html_content_req ; test:response_assertion :html_content_res ] ) ] . :html_content_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/html" ; http:content _:foo ; http:requestURI . :html_content_res a http:ResponseMessage ; http:status 201 . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . http-external-content-invalid.ttl000644001750001750 243214550352012 24246 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures ( :invalid_url ). :invalid_url a test:AutomatedTest ; test:purpose "Test for content on external URL that is invalid"@en ; test:test_script ; test:params [ test:steps ( [ test:request :invalid_url_req ; test:response_assertion :invalid_url_res ] ) ] . :invalid_url_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content ; http:requestURI . :invalid_url_res a http:ResponseMessage ; http:status 500 . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . http-external-content.ttl000644001750001750 243114550352012 22621 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures ( :html_content ). :html_content a test:AutomatedTest ; test:purpose "Test for content on external URL that is invalid"@en ; test:test_script ; test:params [ test:steps ( [ test:request :html_content_req ; test:response_assertion :html_content_res ] ) ] . :html_content_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/html" ; http:content ; http:requestURI . :html_content_res a http:ResponseMessage ; http:status 201 . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . http-list-multi.ttl000644001750001750 513614550352012 21437 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix httph: . @prefix http: . @prefix nfo: . <#test-list> a test:FixtureTable ; test:fixtures ( <#public-writeread-unauthn-alt> <#public-cors-origin-set> ). <#public-writeread-unauthn-alt> a test:AutomatedTest ; test:purpose "More elaborate HTTP vocab for PUT then GET test"@en ; test:test_script ; test:params [ test:steps ( [ test:request <#public-writeread-unauthn-alt-put-req> ; test:response_assertion <#public-writeread-unauthn-alt-put-res> ] [ test:request <#public-writeread-unauthn-alt-get-req> ; test:response_assertion <#public-writeread-unauthn-alt-get-res> ] ) ] . <#public-writeread-unauthn-alt-put-req> a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content " a ." ; http:requestURI . <#public-writeread-unauthn-alt-put-res> a http:ResponseMessage ; http:status 201 . <#public-writeread-unauthn-alt-get-req> a http:RequestMessage ; http:method "GET" ; http:requestURI . <#public-writeread-unauthn-alt-get-res> a http:ResponseMessage ; httph:content_type "text/turtle" . <#public-cors-origin-set> a test:AutomatedTest ; test:purpose "Testing CORS header when Origin is supplied by client"@en ; test:test_script ; test:params [ test:steps ( [ test:request <#public-cors-origin-set-req> ; test:response_assertion <#public-cors-origin-set-res> ] ) ] . <#public-cors-origin-set-req> a http:RequestMessage ; http:method "GET" ; httph:origin ; http:requestURI . <#public-cors-origin-set-res> a http:ResponseMessage ; http:status 200 ; httph:access_control_allow_origin ; httph:content_type "text/turtle" . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . http-list.ttl000644001750001750 352414550352012 20306 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :public_writeread_unauthn_alt . :public_writeread_unauthn_alt a test:AutomatedTest ; test:purpose "More elaborate HTTP vocab for PUT then GET test"@en ; test:test_script ; test:params [ test:steps ( [ test:request :public_writeread_unauthn_alt_put_req ; test:response_assertion :public_writeread_unauthn_alt_put_res ] [ test:request :public_writeread_unauthn_alt_get_req ; test:response_assertion :public_writeread_unauthn_alt_get_res ] ) ] . :public_writeread_unauthn_alt_put_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content " a ." ; http:requestURI . :public_writeread_unauthn_alt_put_res a http:ResponseMessage ; http:status 201 . :public_writeread_unauthn_alt_get_req a http:RequestMessage ; http:method "GET" ; http:requestURI . :public_writeread_unauthn_alt_get_res a http:ResponseMessage ; httph:accept_post "text/turtle", "application/ld+json" ; httph:content_type "text/turtle" . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . http-mix.ttl000644001750001750 261114550352012 20124 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix my: . <#test-list> a test:FixtureTable ; test:fixtures <#public-mix> . <#public-mix> a test:AutomatedTest ; test:purpose "Mix HTTP and ordinary params."@en ; test:test_script ; test:param_base ; test:params [ my:user "alice" ; test:steps ( [ test:request <#public-writeread-unauthn-alt-get-req> ; test:response_assertion <#public-writeread-unauthn-alt-get-res> ] ) ] . <#public-writeread-unauthn-alt-get-req> a http:RequestMessage ; http:method "GET" ; http:requestURI . <#public-writeread-unauthn-alt-get-res> a http:ResponseMessage ; httph:accept_post "text/turtle", "application/ld+json" ; httph:content_type "text/turtle" . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . http-regex.ttl000644001750001750 434714550352012 20451 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix httph: . @prefix http: . @prefix rdfs: . @prefix nfo: . @prefix dqm: . @prefix : . :test_list a test:FixtureTable ; test:fixtures ( :check_acl_location ) . a nfo:SoftwareItem ; deps:test-requirement "Internal::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_regex" . :check_acl_location a test:AutomatedTest ; test:purpose "Test fields with regexps"@en ; test:test_script ; test:params [ test:steps ( [ test:request :check_acl_location_req ; test:response_assertion :check_acl_location_res ] [ test:request :put_new_acl_req ; test:response_assertion :put_new_acl_res ] [ test:request :check_result_req ; test:response_assertion :check_result_res ] ) ] . :check_acl_location_req a http:RequestMessage ; http:method "HEAD" ; http:requestURI . :check_acl_location_res a http:ResponseMessage ; httph:link '<(.*?)>;\\s+rel="acl"'^^dqm:regex ; http:status 200 . :put_new_acl_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content """ @prefix acl: . <#owner> a acl:Authorization; acl:default ; acl:accessTo ; acl:agent ; acl:mode acl:Read. """ . :put_new_acl_res a http:ResponseMessage ; http:status "201|204"^^dqm:regex . :check_result_req a http:RequestMessage ; http:method "GET" ; httph:accept "text/turtle" . :check_result_res a http:ResponseMessage ; http:status "301" ; httph:location 'http://(.*?)/'^^dqm:regex; httph:content_type 'text/turtle'; httph:other_header 'something (.*?) between'^^dqm:regex. invalid.ttl000644001750001750 4014550352012 17732 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/dataThis is not a valid Turtle file list.ttl000644001750001750 234014550352012 17324 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . <#test-list> a test:FixtureTable ; test:fixtures ( <#test1> <#test2> ) . <#test1> a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . <#test2> a test:AutomatedTest ; test:param_base ; test:purpose "Multiply two numbers"@en ; test:test_script ; test:params [ my:factor1 6 ; my:factor2 7 ; my:product 42 ] . a nfo:SoftwareItem ; nfo:definesFunction "string_found" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . a nfo:SoftwareItem ; nfo:definesFunction "multiplication" ; deps:test-requirement "Internal::Fixture::Multi"^^deps:CpanId . multi-vocab.ttl000644001750001750 146714550352012 20604 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . <#test-list> a test:FixtureTable ; test:fixtures <#test1> . <#test1> a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ; 42 ] . a nfo:SoftwareItem ; nfo:definesFunction "multi_vocabs" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . multi.ttl000644001750001750 317514550352012 17512 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :test1, :test2, :test3 . :test1 a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . :test2 a test:AutomatedTest ; test:param_base ; test:purpose "Multiply two numbers"@en ; test:test_script ; test:params [ my:factor1 6 ; my:factor2 7 ; my:product 42 ] . :test3 a test:AutomatedTest ; test:purpose "Run with no param_base"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . a nfo:SoftwareItem ; nfo:definesFunction "string_found" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . a nfo:SoftwareItem ; nfo:definesFunction "string_found_long" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . a nfo:SoftwareItem ; nfo:definesFunction "multiplication" ; deps:test-requirement "Internal::Fixture::Multi"^^deps:CpanId . notests.ttl000644001750001750 10614550352012 20026 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data a . relative.ttl000644001750001750 137714550352012 20175 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . <#test-list> a test:FixtureTable ; test:fixtures <#test1> . <#test1> a test:AutomatedTest ; test:param_base ; test:purpose "Check that a relative URI resolves"@en ; test:test_script ; test:params [ my:url ] . a nfo:SoftwareItem ; nfo:definesFunction "relative_uri" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . simple.ttl000644001750001750 140514550352012 17643 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . <#test-list> a test:FixtureTable ; test:fixtures <#test1> . <#test1> a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . a nfo:SoftwareItem ; nfo:definesFunction "string_found" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . undescribed.ttl000644001750001750 57614550352012 20631 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :test1, :test2 . RDF.pm000644001750001750 5034514550352012 20623 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/lib/Test/FITesqueuse 5.014; use strict; use warnings; package Test::FITesque::RDF; our $AUTHORITY = 'cpan:KJETILK'; our $VERSION = '0.10'; use Moo; use Attean::RDF; use Path::Tiny; use URI::NamespaceMap; use Test::FITesque::Test; use Types::Standard qw(InstanceOf); use Types::Namespace qw(Iri Namespace); use Types::Path::Tiny qw(Path); use Types::Attean qw(to_AtteanIRI); use Types::URI qw(to_Uri); use Carp qw(carp croak); use Data::Dumper; use HTTP::Request; use HTTP::Response; use LWP::UserAgent; use Try::Tiny; use Attean::SimpleQueryEvaluator; has source => ( is => 'ro', isa => Path, # TODO: Generalize to URLs required => 1, coerce => 1, ); has base_uri => ( is => 'ro', isa => Iri, coerce => 1, default => sub { 'http://localhost/' } ); has suite => ( is => 'lazy', isa => InstanceOf['Test::FITesque::Suite'], ); sub _build_suite { my $self = shift; my $suite = Test::FITesque::Suite->new(); foreach my $test (@{$self->transform_rdf}) { $suite->add(Test::FITesque::Test->new({ data => $test})); } return $suite; } sub transform_rdf { my $self = shift; my $ns = URI::NamespaceMap->new(['deps', 'dc', 'rdf']); $ns->add_mapping(test => 'http://ontologi.es/doap-tests#'); $ns->add_mapping(http => 'http://www.w3.org/2007/ont/http#'); $ns->add_mapping(httph => 'http://www.w3.org/2007/ont/httph#'); $ns->add_mapping(dqm => 'http://purl.org/dqm-vocabulary/v1/dqm#'); $ns->add_mapping(nfo => 'http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#'); my $parser = Attean->get_parser(filename => $self->source)->new( base => $self->base_uri ); my $model = Attean->temporary_model; my $graph_id = iri('http://example.org/graph'); # TODO: Use a proper URI for graph my $file_iter; try { $file_iter = $parser->parse_iter_from_io( $self->source->openr_utf8 ); } catch { croak 'Failed to parse ' . $self->source . " due to $_"; }; $model->add_iter($file_iter->as_quads($graph_id)); my $tests_uri_iter = $model->objects(undef, to_AtteanIRI($ns->test->fixtures))->materialize; if (scalar $tests_uri_iter->elements == 0) { croak "No tests found in " . $self->source; } if ($model->holds($tests_uri_iter->peek, to_AtteanIRI($ns->rdf->first), undef, $graph_id)) { # Then, the object is a list. This supports either unordered # objects or lists, not both. This could be changed by iterating # in the below loop, but I don't see much point to it. $tests_uri_iter = $model->get_list( $graph_id, $tests_uri_iter->peek); } my @data; while (my $test_uri = $tests_uri_iter->next) { my @instance; my $params_base_term = $model->objects($test_uri, to_AtteanIRI($ns->test->param_base))->next; my $params_base; if ($params_base_term) { $params_base = URI::Namespace->new($params_base_term); $ns->guess_and_add($params_base); } my $test_bgp = bgp(triplepattern($test_uri, to_AtteanIRI($ns->test->test_script), variable('script_class')), triplepattern(variable('script_class'), to_AtteanIRI($ns->deps->iri('test-requirement')), variable('handler')), # Because Perl doesn't support dashes in method names triplepattern(variable('script_class'), to_AtteanIRI($ns->nfo->definesFunction), variable('method')), triplepattern($test_uri, to_AtteanIRI($ns->test->purpose), variable('description')), triplepattern($test_uri, to_AtteanIRI($ns->test->params), variable('paramid'))); my $e = Attean::SimpleQueryEvaluator->new( model => $model, default_graph => $graph_id, ground_blanks => 1 ); my $test_iter = $e->evaluate( $test_bgp, $graph_id); # Each row will correspond to one test while (my $test = $test_iter->next) { push(@instance, [$test->value('handler')->value]); my $method = $test->value('method')->value; my $params_iter = $model->get_quads($test->value('paramid')); # Get the parameters for each test my $params; $params->{'-special'} = {description => $test->value('description')->value}; # Description should always be present while (my $param = $params_iter->next) { # First, see if there are HTTP request-responses that can be constructed my $pairs_head = $model->objects($param->subject, to_AtteanIRI($ns->test->steps))->next; my @pairs; if ($pairs_head) { # There exists a list of HTTP requests and responses my $steps_iter = $model->get_list($graph_id, $pairs_head); while (my $pairs_subject = $steps_iter->next) { my $pairs_bgp = bgp(triplepattern($pairs_subject, to_AtteanIRI($ns->test->request), variable('request')), triplepattern($pairs_subject, to_AtteanIRI($ns->test->response_assertion), variable('response_assertion'))); my $pair_iter = $e->evaluate( $pairs_bgp, $graph_id); # Each row will correspond to one request-response pair my $result; # Within each pair, there will be both requests and responses my $req = HTTP::Request->new; my $res = HTTP::Response->new; my $regex_headers = {}; while (my $pair = $pair_iter->next) { # First, do requests my $req_entry_iter = $model->get_quads($pair->value('request')); while (my $req_data = $req_entry_iter->next) { my $local_header = $ns->httph->local_part($req_data->predicate); if ($req_data->predicate->equals($ns->http->method)) { $req->method($req_data->object->value); } elsif ($req_data->predicate->equals($ns->http->requestURI)) { $req->uri(to_Uri($req_data->object)); } elsif ($req_data->predicate->equals($ns->http->content)) { if ($req_data->object->is_literal) { $req->content($req_data->object->value); # TODO: might need encoding } elsif ($req_data->object->is_iri) { # If the http:content predicate points to a IRI, the framework will retrieve content from there my $ua = LWP::UserAgent->new; my $content_response = $ua->get(to_Uri($req_data->object)); if ($content_response->is_success) { $req->content($content_response->decoded_content); # TODO: might need encoding } else { croak "Could not retrieve content from " . $req_data->object->as_string . " . Got " . $content_response->status_line; } } else { croak 'Unsupported object ' . $req_data->object->as_string . " in " . $self->source; } } elsif (defined($local_header)) { $req->push_header(_find_header($local_header) => $req_data->object->value); } } # Now, do asserted responses my $res_entry_iter = $model->get_quads($pair->value('response_assertion')); while (my $res_data = $res_entry_iter->next) { my $local_header = $ns->httph->local_part($res_data->predicate); if ($res_data->predicate->equals($ns->http->status)) { if ($res_data->object->datatype->equals($ns->dqm->regex)) { $regex_headers->{'status'} = 1; } $res->code($res_data->object->value); } elsif (defined($local_header)) { my $cleaned_header = _find_header($local_header); $res->push_header($cleaned_header => $res_data->object->value); if ($res_data->object->is_literal && $res_data->object->datatype->equals($ns->dqm->regex)) { $regex_headers->{$cleaned_header} = 1; } } } } $result = { 'request' => $req, 'response' => $res, 'regex-fields' => $regex_headers }; push(@pairs, $result); } $params->{'-special'}->{'http-pairs'} = \@pairs; } if ($param->object->is_literal || $param->object->is_iri) { my $key = $param->predicate->as_string; if (defined($params_base) && $params_base->local_part($param->predicate)) { $key = $params_base->local_part($param->predicate) } my $value = $param->object->value; if ($param->object->is_iri) { $value = to_Uri($param->object) } $params->{$key} = $value; } } push(@instance, [$method, $params]) } carp 'Test was listed as ' . $test_uri->as_string . ' but not fully described' unless scalar @instance; push(@data, \@instance); } return \@data; } sub _find_header { my $local_header = shift; $local_header =~ s/_/-/g; # Some heuristics for creating HTTP headers $local_header =~ s/\b(\w)/\u$1/g; return $local_header; } 1; __END__ =pod =encoding utf-8 =head1 NAME Test::FITesque::RDF - Formulate Test::FITesque fixture tables in RDF =head1 SYNOPSIS my $suite = Test::FITesque::RDF->new(source => $file)->suite; $suite->run_tests; See C for a full test script example using this simplest way. To run a single test script with several fixture tables, you can either add the tests to a suite, like this: my @files = ('test1.ttl','test2.ttl'); my $suite = Test::FITesque::Suite->new; foreach my $file (@files) { $suite->add(Test::FITesque::RDF->new(source => $path . $file)->suite); } $suite->run_tests; or iterate and run the tests for each fixture table like this: my @files = ('test1.ttl','test2.ttl'); foreach my $file (@files) { diag("Reading tests from $path$file"); my $suite = Test::FITesque::RDF->new(source => $path . $file)->suite; $suite->run_tests; } =head1 DESCRIPTION This module enables the use of Resource Description Framework to describe fixture tables. It will take the filename of an RDF file and return a L object that can be used to run tests. The RDF serves to identify the implementation of certain fixtures, and can also supply parameters that can be used by the tests, e.g. input parameters or expectations. See L for more on how the fixtures are implemented. =head2 ATTRIBUTES AND METHODS This module implements the following attributes and methods: =over =item C<< source >> Required attribute to the constructor. Takes a L object pointing to the RDF file containing the fixture tables. The value will be converted into an appropriate object, so a string can also be supplied. =item C<< suite >> Will return a L object, based on the RDF data supplied to the constructor. =item C<< transform_rdf >> Will return an arrayref containing tests in the structure used by L. Most users will rather call the C method than to call this method directly. =item C<< base_uri >> A L to use in parsing the RDF fixture tables to resolve any relative URIs. =back =head2 REQUIRED RDF The following must exist in the test description (see below for an example and prefix expansions): =over =item C<< test:fixtures >> The object(s) of this predicate lists the test fixtures that will run for this test suite. May take an RDF List. Links to the test descriptions, which follow below. =item C<< test:test_script >> The object of this predicate points to information on how the actual test will be run. That is formulated in a separate resource which requires two predicates, C<< deps:test-requirement >> predicate, whose object contains the class name of the implementation of the tests; and C<< nfo:definesFunction >> whose object is a string which matches the actual function name within that class. =item C<< test:purpose >> The object of this predicate provides a literal description of the test. =item C<< test:params >> The object of this predicate links to the parameters, which may have many different shapes. See below for examples. =back =head2 PARAMETERIZATION This module seeks to parameterize the tests, and does so using mostly the C predicate above. This is passed on as a hashref to the test scripts. There are two main ways currently implemented, one creates key-value pairs, and uses predicates and objects for that respectively, in vocabularies chosen by the test writer. The other main way is create lists of HTTP requests and responses. If the object of a test parameter is a literal, it will be passed as a plain string, if it is a L, it will be passed as a L object. Additionally, a special parameter C<-special> is passed on for internal framework use. The leading dash is not allowed as the start character of a local name, and therefore chosen to avoid conflicts with other parameters. The literal given in C above is passed on as with the C key in this hashref. =head2 RDF EXAMPLE The below example starts with prefix declarations. Then, the tests in the fixture table are listed explicitly. Only tests mentioned using the C predicate will be used. Tests may be an RDF List, in which case, the tests will run in the specified sequence, if not, no sequence may be assumed. Then, two test fixtures are declared. The actual implementation is referenced through C for both functions. The C predicate is used to link the parameters that will be sent as a hashref into the function. The predicate is required to exist outside of the parameters, but will be included as a parameter as well, named C in the C<-special> hashref. There are two mechanisms for passing parameters to the test scripts, one is simply to pass arbitrary key-value pairs, the other is to pass lists of HTTP request-response objects. Both mechanisms may be used. =head3 Key-value parameters The key of the hashref passed as arguments will be the local part of the predicate used in the description (i.e. the part after the colon in e.g. C). It is up to the test writer to mint the URIs of the parameters. The test writer may optionally use a C to indicate the namespace, in which case the the local part is resolved by the framework, using L. If C is not given, the full URI will be passed to the test script. @prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :test1, :test2 . :test1 a test:AutomatedTest ; test:param_base ; test:purpose "Echo a string"@en ; test:test_script ; test:params [ my:all "counter-clockwise dahut" ] . :test2 a test:AutomatedTest ; test:param_base ; test:purpose "Multiply two numbers"@en ; test:test_script ; test:params [ my:factor1 6 ; my:factor2 7 ; my:product 42 ] . a nfo:SoftwareItem ; nfo:definesFunction "string_found" ; deps:test-requirement "Internal::Fixture::Simple"^^deps:CpanId . a nfo:SoftwareItem ; nfo:definesFunction "multiplication" ; deps:test-requirement "Internal::Fixture::Multi"^^deps:CpanId . =head3 HTTP request-response lists To allow testing HTTP-based interfaces, this module also allows the construction of an ordered list of HTTP requests and response pairs. With those, the framework will construct L and L objects. In tests scripts, the request objects will typically be passed to the L as input, and then the response from the remote server will be compared with the asserted Ls made by the test fixture. We will go through an example in chunks: @prefix test: . @prefix deps: . @prefix httph: . @prefix http: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :public_writeread_unauthn_alt . :public_writeread_unauthn_alt a test:AutomatedTest ; test:purpose "To test if we can write first using HTTP PUT then read with GET"@en ; test:test_script ; test:params [ test:steps ( [ test:request :public_writeread_unauthn_alt_put_req ; test:response_assertion :public_writeread_unauthn_alt_put_res ] [ test:request :public_writeread_unauthn_alt_get_req ; test:response_assertion :public_writeread_unauthn_alt_get_res ] ) ] . a nfo:SoftwareItem ; deps:test-requirement "Example::Fixture::HTTPList"^^deps:CpanId ; nfo:definesFunction "http_req_res_list_unauthenticated" . In the above, after the prefixes, a single test is declared using the C predicate, linking to a description of the test. The test is then described as an , and it's purpose is declared. It then links to its concrete implementation, which is given in the last three triples in the above. Then, the parameterization is started. In this example, there are two HTTP request-response pairs, which are given as a list object to the C predicate. To link the request, the C predicate is used, to link the asserted response, the C predicate is used. Next, we look into the actual request and response messages linked from the above: :public_writeread_unauthn_alt_put_req a http:RequestMessage ; http:method "PUT" ; httph:content_type "text/turtle" ; http:content " a ." ; http:requestURI . :public_writeread_unauthn_alt_put_res a http:ResponseMessage ; http:status 201 . :public_writeread_unauthn_alt_get_req a http:RequestMessage ; http:method "GET" ; http:requestURI . :public_writeread_unauthn_alt_get_res a http:ResponseMessage ; httph:accept_post "text/turtle", "application/ld+json" ; httph:content_type "text/turtle" . These should be self-explanatory, but note that headers are given with lower-case names and underscores. They will be transformed to headers by replacing underscores with dashes and upcase the first letters. This module will transform the above to data structures that are suitable to be passed to L, and the above will appear as { '-special' => { 'http-pairs' => [ { 'request' => ... , 'response' => ... , }, { ... } ] }, 'description' => 'To test if we can write first using HTTP PUT then read with GET' }, } Note that there are more examples in this module's test suite in the C directory. You may maintain client state in a test script (i.e. for one C, as it is simply one script, so the result of one request may be used to influence the next. Server state can be relied on between different tests by using an C of test fixtures if it writes something into the server, there is nothing in the framework that changes that. To use data from one response to influence subsequent requests, the framework supports datatyping literals with the C datatype for headers and HTTP status codes, for example: :check_acl_location_res a http:ResponseMessage ; httph:link '<(.*?)>;\\s+rel="acl"'^^dqm:regex ; http:status "200|204"^^dqm:regex . This makes it possible to use a Perl regular expression, which can be executed in a test script if desired. If present, it will supply another hashref to the C key with the key C containing hashrefs with the header field that had a correspondiing object datatyped regex as key and simply C<1> as value. =head1 TODO Separate the implementation-specific details (such as C) from the actual fixture tables. =head1 BUGS Please report any bugs to L. =head1 SEE ALSO =head1 AUTHOR Kjetil Kjernsmo Ekjetilk@cpan.orgE. =head1 COPYRIGHT AND LICENCE This software is Copyright (c) 2019, 2020 by Inrupt Inc. This is free software, licensed under: The MIT (X11) License =head1 DISCLAIMER OF WARRANTIES THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. HTTPList.pm000644001750001750 260114550352012 22634 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/lib/Internal/Fixturepackage Internal::Fixture::HTTPList; use 5.010001; use strict; use warnings; use parent 'Test::FITesque::Fixture'; use Test::More ; use Test::Deep ; sub http_req_res_list_unauthenticated : Test : Plan(6) { my ($self, $args) = @_; note($args->{'-special'}->{description}); # TODO: Doesn't seem that hard to use Test::Deep for this after all my @pairs = @{$args->{'-special'}->{'http-pairs'}}; is(scalar @pairs, 2, 'There are two request-response pairs'); is($pairs[0]->{request}->method, 'PUT', 'First method is PUT'); is($pairs[1]->{request}->method, 'GET', 'Second method is GET'); is($pairs[0]->{response}->code, '201', 'First code is 201'); is($pairs[1]->{response}->content_type, 'text/turtle', 'Second ctype is turtle'); cmp_deeply([$pairs[1]->{response}->header('Accept-Post')], bag("text/turtle", "application/ld+json"), 'Response header field value bag comparison'); } 1; # # TODO: This should really mock an HTTP server, then it would be something like # sub http_req_res_list_unauthenticated : Test : Plan(2) { # my ($self, $args) = @_; # for (my $i=0; $i <= $#{$args->{'http-requests'}}; $i++) { # subtest "Request-response #" . $i+1 => sub { # my $ua = LWP::UserAgent->new; # my $response = $ua->request( ${$args->{'http-requests'}}[$i] ); # ## Here, compare $response and $ua->request( ${$args->{'http-responses'}}[$i] to see that they match # }; # } # }; Multi.pm000644001750001750 75414550352012 22302 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/lib/Internal/Fixturepackage Internal::Fixture::Multi; use 5.010001; use strict; use warnings; use parent 'Test::FITesque::Fixture'; use Test::More ; sub multiplication : Test : Plan(4) { my ($self, $args) = @_; note($args->{'-special'}->{description}); ok(defined($args->{factor1}), 'Factor 1 exists'); ok(defined($args->{factor2}), 'Factor 2 exists'); ok(defined($args->{product}), 'Product parameter exists'); is($args->{factor1} * $args->{factor2}, $args->{product}, 'Product is correct'); } 1; Simple.pm000644001750001750 162014550352012 22452 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.10/t/lib/Internal/Fixturepackage Internal::Fixture::Simple; use 5.010001; use strict; use warnings; use parent 'Test::FITesque::Fixture'; use Test::More ; sub string_found : Test : Plan(2) { my ($self, $args) = @_; note($args->{'-special'}->{description}); ok(defined($args->{all}), 'String exists'); like($args->{all}, qr/dahut/, 'Has a certain keyword'); } sub string_found_long : Test : Plan(2) { my ($self, $args) = @_; note($args->{'-special'}->{description}); ok(defined($args->{'http://example.org/my-parameters#all'}), 'String exists'); like($args->{'http://example.org/my-parameters#all'}, qr/dahut/, 'Has a certain keyword'); } sub relative_uri : Test : Plan(3) { my ($self, $args) = @_; note($args->{'-special'}->{description}); ok(defined($args->{url}), 'Url comes through'); isa_ok(defined($args->{url}), 'URI'); is($args->{url}->as_string, 'http://example.org/foo/', 'Url is resolved'); } 1;