COPYRIGHT000644001750001750 355613616663364 16066 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018Format: 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: 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: dist.ini 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-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 2019 Kjetil Kjernsmo. License: Expat Files: Changes META.json META.yml doap.ttl lib/Test/FITesque/RDF.pm t/unit-http-regex.t Copyright: Copyright 2020 Kjetil Kjernsmo. License: Expat Files: COPYRIGHT CREDITS SIGNATURE Copyright: None License: public-domain Files: Makefile.PL Copyright: Copyright 2013 Toby Inkster. License: GPL-1.0+ or Artistic-1.0 License: Expat This software is Copyright (c) 2020 by Kjetil Kjernsmo. This is free software, licensed under: The MIT (X11) License License: Artistic-1.0 This software is Copyright (c) 2020 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) 2020 by the copyright holder(s). This is free software, licensed under: The GNU General Public License, Version 1, February 1989 CREDITS000644001750001750 16213616663364 15561 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018Maintainer: - Kjetil Kjernsmo (KJETILK) Thanks: - Scott McWirther (KONOBI) Changes000644001750001750 335613616663364 16064 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018Test-FITesque-RDF ================= Created: 2019-04-09 Home page: Bug tracker: Maintainer: Kjetil Kjernsmo (KJETILK) 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 172613616663364 15621 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018 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 221213616663364 15564 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018This software is Copyright (c) 2020 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 152413616663364 15715 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018COPYRIGHT 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 477713616663364 16222 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018{ "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.018" } }, "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.018", "x_serialization_backend" : "JSON::PP version 2.97001", "x_static_install" : 1 } META.yml000644001750001750 275213616663364 16041 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018--- 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.018' 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.018' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' x_static_install: 1 Makefile.PL000644001750001750 1465113616663364 16563 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018use 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.018 }, }, "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.018, "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; } } sub FixMakefile { return unless -d 'inc'; my $file = shift; local *MAKEFILE; open MAKEFILE, "< $file" or die "FixMakefile: Couldn't open $file: $!; bailing out"; my $makefile = do { local $/; }; close MAKEFILE or die $!; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; open MAKEFILE, "> $file" or die "FixMakefile: Couldn't open $file: $!; bailing out"; print MAKEFILE $makefile or die $!; close MAKEFILE or die $!; } my $mm = WriteMakefile(%WriteMakefileArgs); FixMakefile($mm->{FIRST_MAKEFILE} || 'Makefile'); exit(0); README000644001750001750 3220413616663364 15463 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018NAME 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 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 3230113616663364 16060 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018# 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 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 1251313616663364 16070 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.83. 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: SHA256 SHA256 7b62f96424e3fecfd1fdde40bbc44159303e21073f2f8d1acfa669275f185b5a COPYRIGHT SHA256 c2fa5f625b8687ad497be645c96ca038d9c28c3a052e07523f06f240c17a9799 CREDITS SHA256 4cff263ba857c8d44d1106cc9026fc7621689142542cd2153272afc58d0193c1 Changes SHA256 8fd1468ddacc4d6d78f175943e8a5b918e87cc44b1e2edf913ca114fd0bf0708 INSTALL SHA256 b90e5ee8ac6aa5503fafe671ac7ee2e705d75157d8137d1fe640c93083a67a5f LICENSE SHA256 e19b54081db6f783e167b8178c5ca0fc4a3f356143ea86c27bbaf6ff39a28e20 MANIFEST SHA256 dc8626888a3dbe4d942f3d98e6969ae40264321d9e3bc1ad52fcec5750e064ce META.json SHA256 bdbc8fc72bda1102ae80a18d50b28e0d12d87e933bc8f54da87344a9367d6e97 META.yml SHA256 7c75f1ff9230ebd28e9713e05f1548197d7cd268f15c64dea0875b166c0acd1c Makefile.PL SHA256 826fd973a11e7cc144aa26fcb9944eab1cc4e4a19d102de7f61da417cebc6380 README SHA256 1f7a5b781f31118e907bff255c3af3201c785aaeaff45bf5394215d73c17c8a4 README.md SHA256 fb7d510bfb8c69d33753a712fb9ab4b159a89b6435ed69d7be15e8783ee1a250 dist.ini SHA256 276654bde63cbe0446f0e6c607275ea54e51f39452771cf7f33b191039c23670 doap.ttl SHA256 c9a4940617dd3ba76c7ddacc68799b6f673b8f41669549164993b96e54507828 lib/Test/FITesque/RDF.pm SHA256 3c01388312e5d42a15630b913efca12a615f082948e0d17fd622ea1ed850cf43 t/01basic.t SHA256 8a6792e7905f9e2ceafa3a5c9a3b9eaa5c5e0f20a42df84b4a5045ef635343f1 t/data/http-external-content-blank.ttl SHA256 0bc576b8257876f9e00bb18fc2d303c977dce33203eccabeee643838f083a869 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 00fbf3728abc183789bddb7c40eb920fa903e326c564d4cd082597d87808d21f 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----- iQIzBAEBCAAdFiEEDsyLxtCi6bk7pBcmf77o3zqeSqUFAl47ZvQACgkQf77o3zqe SqUuHQ/+NK4RB383z1D4cX5V4XtlhVfrPXtZy4Nn02ahX8FD6n/MMVXskiW0UweE +lYiFVHPIllK4+BlIkF6QG0tDRoUOc9j5zAAw1mKmYGU8tdQ2//GITJUX0FOJHDs lyP+mMi1HCOU2tYBZw9Q8JE5yvhuWY3oN+ZxhxeGdj/7jy0pNh6y/7pTf9XwsMUI HAeeOkKRGw9jwGPv+uqbi+YC3IrkfFJOagUV6bied/lXhwLhmeihXRGYH4aqFfhK kHXOjg1NlIQu72wnkQIYStq8CNFw/nPyxOR3gpvbP8117mEWBDMMpJEJ3pORCBHh moRJ/lP3SvsUn28EFzN3W2Bunu2BWrIjQRC3+HHwk3VpSxcamFdc6YaItoU+FM6h iGqTmxvwWiWWZ5YUROWKEtzo6teZcdmhMjDTQMRPv1CgPVLazwvBitytQls6cRN4 o5mngpVd13ZlwcLstAWXfLkps6fDSBQ/Mq2F4j1CBnl9Lfa3bwm3EH+HVBmlfL8v nPghJDcQ4g+CyiEFNzkUiKs3aizZwlIdrCUWc5S+NEe/3CrtqewKEgyfgKIdcCCV lnCI4PIO16jgWW48DvZwBDNW+5Qzdl9fjeU3iGL8x3siaiFUh4tAzsEchzuMcTrU B5Lf0prbCTZKDxaK80byAmSJsaBM5bPz0E5BCdwDQWIluA2XT5k= =iGPt -----END PGP SIGNATURE----- dist.ini000644001750001750 10313616663364 16200 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018;;class='Dist::Inkt::Profile::KJETILK' ;;name='Test-FITesque-RDF' doap.ttl000644001750001750 3611713616663364 16262 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018@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:Documentation; rdfs:label "Improve documentation."; ], [ a doap-changeset:BackCompat; rdfs:label "Restructure HTTP request-response pair parameterization."; ]; 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 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: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 72413616663364 16417 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 346513616663364 20624 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 122613616663364 21464 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 455013616663364 20123 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 313513616663364 17743 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 417613616663364 20266 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 614713616663364 20462 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 221513616663364 17142 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 440513616663364 20301 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 163113616663364 20412 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 267713616663364 17335 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 203313616663364 20000 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 163213616663364 17462 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 240513616663364 24020 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 243113616663364 24356 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 243113616663364 22732 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 513613616663364 21550 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 352413616663364 20417 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 261113616663364 20235 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 434713616663364 20562 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 4013616663364 20043 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/t/dataThis is not a valid Turtle file list.ttl000644001750001750 234013616663364 17435 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 146713616663364 20715 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 317513616663364 17623 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 10613616663364 20137 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/t/data a . relative.ttl000644001750001750 137713616663364 20306 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 140513616663364 17754 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 57613616663364 20742 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/t/data@prefix test: . @prefix deps: . @prefix dc: . @prefix my: . @prefix nfo: . @prefix : . :test_list a test:FixtureTable ; test:fixtures :test1, :test2 . RDF.pm000644001750001750 5034013616663364 20727 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/lib/Test/FITesqueuse 5.014; use strict; use warnings; package Test::FITesque::RDF; our $AUTHORITY = 'cpan:KJETILK'; our $VERSION = '0.018'; 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 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 260113616663364 22745 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 75413616663364 22413 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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 162013616663364 22563 0ustar00kjetilkjetil000000000000Test-FITesque-RDF-0.018/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;