diff --git a/.travis.yml b/.travis.yml index b7b0f49ca5..8e945a6454 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ language: php php: # Test oldest and newest maintained versions. - '7.3' - # - '8.0' + - '8.0' env: # Test oldest and newest maintained versions. diff --git a/application/helpers/postgreSQL.php b/application/helpers/postgreSQL.php index 6acd07d0d2..919b79ee51 100644 --- a/application/helpers/postgreSQL.php +++ b/application/helpers/postgreSQL.php @@ -372,7 +372,8 @@ public static function list_fields($entity, $db = NULL) { SELECT column_name, column_default, is_nullable, data_type, udt_name, character_maximum_length, numeric_precision, numeric_precision_radix, numeric_scale FROM information_schema.columns - WHERE table_name = \'' . $entity . '\' + WHERE table_name = \'' . $entity . '\' + AND table_schema != \'information_schema\' ORDER BY ordinal_position '); diff --git a/composer.json b/composer.json index 25a01df3d6..8faa3968d8 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,16 @@ { + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/misantron/dbunit" + } + ], "require": { "firebase/php-jwt": "^5.4", "phpoffice/phpspreadsheet": "^1.18" }, "require-dev": { "phpunit/phpunit": "^9.5", - "misantron/dbunit": "^5.1" + "misantron/dbunit": "dev-master" } } diff --git a/composer.lock b/composer.lock index f9d9ce3713..6eff9858be 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c505b8dc101b76633c8ae935e66c78b2", + "content-hash": "2fccf8723ed1dfa22f7247880fd11bd9", "packages": [ { "name": "ezyang/htmlpurifier", @@ -885,37 +885,45 @@ }, { "name": "misantron/dbunit", - "version": "5.1.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/misantron/dbunit.git", - "reference": "a3e5d3c74a2ae78827c86e14e3d06d7a8d44ca65" + "reference": "73a9c07dca119c68e92002adb4fab9022235a91f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/misantron/dbunit/zipball/a3e5d3c74a2ae78827c86e14e3d06d7a8d44ca65", - "reference": "a3e5d3c74a2ae78827c86e14e3d06d7a8d44ca65", + "url": "https://api.github.com/repos/misantron/dbunit/zipball/73a9c07dca119c68e92002adb4fab9022235a91f", + "reference": "73a9c07dca119c68e92002adb4fab9022235a91f", "shasum": "" }, "require": { - "ext-libxml": "*", "ext-pdo": "*", - "ext-simplexml": "*", - "php": "^7.2|^7.3|^7.4", - "phpunit/phpunit": "^8.5|^9.2", - "symfony/yaml": "^4.4|^5.0" + "php": "^7.2 || ^8.0", + "phpunit/phpunit": "^8.5 || ^9.2", + "symfony/yaml": "^4.4 || ^5.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "php-coveralls/php-coveralls": "^2.2" + "friendsofphp/php-cs-fixer": "^2.18 || ^3.0", + "php-coveralls/php-coveralls": "^2.4", + "phpstan/phpstan": "^0.12.98", + "squizlabs/php_codesniffer": "^3.6" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { "PHPUnit\\DbUnit\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", + "autoload-dev": { + "psr-4": { + "PHPUnit\\DbUnit\\Tests\\": "tests/" + }, + "files": [ + "tests/_files/DatabaseTestUtility.php" + ] + }, "license": [ "MIT" ], @@ -923,21 +931,20 @@ { "name": "Aleksandr Ivanov", "email": "misantron@gmail.com", - "role": "developer" + "role": "Developer" } ], "description": "DbUnit fork supporting PHPUnit 8/9", - "homepage": "https://github.com/misantron/dbunit/", "keywords": [ "database", - "dbUnit", + "dbunit", "testing" ], "support": { - "issues": "https://github.com/misantron/dbunit/issues", - "source": "https://github.com/misantron/dbunit/tree/master" + "source": "https://github.com/misantron/dbunit/tree/master", + "issues": "https://github.com/misantron/dbunit/issues" }, - "time": "2020-07-07T20:48:08+00:00" + "time": "2021-09-09T19:30:23+00:00" }, { "name": "myclabs/deep-copy", @@ -1324,33 +1331,33 @@ }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -1385,9 +1392,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/1.14.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-09-10T09:02:12+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1709,16 +1716,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.7", + "version": "9.5.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "d0dc8b6999c937616df4fb046792004b33fd31c5" + "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0dc8b6999c937616df4fb046792004b33fd31c5", - "reference": "d0dc8b6999c937616df4fb046792004b33fd31c5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", + "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", "shasum": "" }, "require": { @@ -1730,7 +1737,7 @@ "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", @@ -1796,7 +1803,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9" }, "funding": [ { @@ -1808,7 +1815,7 @@ "type": "github" } ], - "time": "2021-07-19T06:14:47+00:00" + "time": "2021-08-31T06:47:40+00:00" }, { "name": "sebastian/cli-parser", @@ -3107,7 +3114,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "misantron/dbunit": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": [], diff --git a/docker/phpunit.sh b/docker/phpunit.sh index 414ef6f983..8a8b2b1fbb 100755 --- a/docker/phpunit.sh +++ b/docker/phpunit.sh @@ -25,7 +25,7 @@ docker-compose -f docker-compose-phpunit.yml build \ --build-arg GID=$(id -g) \ --build-arg USER=$(id -un) \ --build-arg GROUP=$(id -gn) \ - --build-arg PHP_VERSION=7.3 \ + --build-arg PHP_VERSION=8 \ --build-arg PG_VERSION=13 \ --build-arg PORT=$PORT # When the container is brought up, the database will start diff --git a/docker/warehouse/Dockerfile b/docker/warehouse/Dockerfile index 54aa6e2a4c..ee7b201644 100644 --- a/docker/warehouse/Dockerfile +++ b/docker/warehouse/Dockerfile @@ -1,8 +1,6 @@ -# This image contains Debian's Apache httpd in conjunction with PHP7.3 -# (as mod_php) and uses mpm_prefork by default. +# This image contains Debian's Apache httpd in conjunction with PHP8.0. # https://hub.docker.com/_/php -# Currently warehouse is not compatible with PHP 7.4 -FROM php:7.3-apache +FROM php:8.0-apache # Use PHP development configuration file RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" # Increase size of files which can be uploaded. diff --git a/modules/data_cleaner/controllers/verification_rule.php b/modules/data_cleaner/controllers/verification_rule.php index f6ef3bda6a..def0c67d40 100644 --- a/modules/data_cleaner/controllers/verification_rule.php +++ b/modules/data_cleaner/controllers/verification_rule.php @@ -134,7 +134,7 @@ private function get_server_list() { $response = curl_exec($session); if (curl_errno($session)) { $this->session->set_flash('flash_info', 'The list of verification rule servers could not be retrieved from the internet. ' . - 'More information is avaailable in the server logs.'); + 'More information is available in the server logs.'); kohana::log('error', 'Error occurred when retrieving list of verification rule servers. ' . curl_error($session)); return array(); } diff --git a/modules/data_cleaner/tests/services/data_cleanerTest.php b/modules/data_cleaner/tests/services/data_cleanerTest.php index 3d684c6484..b8e8c166a6 100644 --- a/modules/data_cleaner/tests/services/data_cleanerTest.php +++ b/modules/data_cleaner/tests/services/data_cleanerTest.php @@ -26,9 +26,6 @@ * @subpackage Data Cleaner */ -use PHPUnit\DbUnit\DataSet\YamlDataSet as DbUDataSetYamlDataSet; -use PHPUnit\DbUnit\DataSet\CompositeDataSet as DbUDataSetCompositeDataSet; - require_once 'client_helpers/data_entry_helper.php'; /** @@ -36,83 +33,77 @@ * @backupGlobals disabled * @backupStaticAttributes disabled */ -class Controllers_Services_Data_Cleaner_Test extends Indicia_DatabaseTestCase { +class Controllers_Services_Data_Cleaner_Test extends SimpleDatabaseTestCase { protected $request; /** * @return PHPUnit_Extensions_Database_DataSet_IDataSet */ - public function getDataSet() - { - $ds1 = new DbUDataSetYamlDataSet('modules/phpUnit/config/core_fixture.yaml'); - - // Create a rule to test against - $ds2 = new Indicia_ArrayDataSet( - array( - 'verification_rules' => array( - array( - 'title' => 'Test PeriodWithinYear rule', - 'description' => 'Test rule for unit testing', - 'test_type' => 'PeriodWithinYear', - 'error_message' => 'PeriodWithinYear test failed', - 'source_url' => null, - 'source_filename' => null, - 'created_on' => '2016-07-22:16:00:00', - 'created_by_id' => 1, - 'updated_on' => '2016-07-22:16:00:00', - 'updated_by_id' => 1, - 'reverse_rule' => 'F', - ), - ), - 'verification_rule_metadata' => array( - array( - 'verification_rule_id' => '1', - 'key' => 'Tvk', - 'value' => 'TESTKEY', - 'created_on' => '2016-07-22:16:00:00', - 'created_by_id' => 1, - 'updated_on' => '2016-07-22:16:00:00', - 'updated_by_id' => 1, - ), - array( - 'verification_rule_id' => '1', - 'key' => 'StartDate', - 'value' => '0801', - 'created_on' => '2016-07-22:16:00:00', - 'created_by_id' => 1, - 'updated_on' => '2016-07-22:16:00:00', - 'updated_by_id' => 1, - ), - array( - 'verification_rule_id' => '1', - 'key' => 'EndDate', - 'value' => '0831', - 'created_on' => '2016-07-22:16:00:00', - 'created_by_id' => 1, - 'updated_on' => '2016-07-22:16:00:00', - 'updated_by_id' => 1, - ), - ), - 'cache_verification_rules_period_within_year' => array( - array( - 'verification_rule_id' => '1', - 'reverse_rule' => 'f', - 'taxa_taxon_list_external_key' => 'TESTKEY', - 'start_date' => '214', - 'end_date' => '244', - 'survey_id' => NULL, - 'stages' => NULL, - 'error_message' => 'PeriodWithinYear test failed', - ), - ), - ) - ); + public function getDataSet() { + require 'modules/phpUnit/config/core_fixture.php'; + + // Create a rule to test against. + $local_fixture = [ + 'verification_rules' => [ + [ + 'title' => 'Test PeriodWithinYear rule', + 'description' => 'Test rule for unit testing', + 'test_type' => 'PeriodWithinYear', + 'error_message' => 'PeriodWithinYear test failed', + 'source_url' => NULL, + 'source_filename' => NULL, + 'created_on' => '2016-07-22 16:00:00', + 'created_by_id' => 1, + 'updated_on' => '2016-07-22 16:00:00', + 'updated_by_id' => 1, + 'reverse_rule' => 'F', + ], + ], + 'verification_rule_metadata' => [ + [ + 'verification_rule_id' => '1', + 'key' => 'Tvk', + 'value' => 'TESTKEY', + 'created_on' => '2016-07-22 16:00:00', + 'created_by_id' => 1, + 'updated_on' => '2016-07-22 16:00:00', + 'updated_by_id' => 1, + ], + [ + 'verification_rule_id' => '1', + 'key' => 'StartDate', + 'value' => '0801', + 'created_on' => '2016-07-22 16:00:00', + 'created_by_id' => 1, + 'updated_on' => '2016-07-22 16:00:00', + 'updated_by_id' => 1, + ], + [ + 'verification_rule_id' => '1', + 'key' => 'EndDate', + 'value' => '0831', + 'created_on' => '2016-07-22 16:00:00', + 'created_by_id' => 1, + 'updated_on' => '2016-07-22 16:00:00', + 'updated_by_id' => 1, + ], + ], + 'cache_verification_rules_period_within_year' => [ + [ + 'verification_rule_id' => '1', + 'reverse_rule' => 'f', + 'taxa_taxon_list_external_key' => 'TESTKEY', + 'start_date' => '214', + 'end_date' => '244', + 'survey_id' => NULL, + 'stages' => NULL, + 'error_message' => 'PeriodWithinYear test failed', + ], + ], + ]; - $compositeDs = new DbUDataSetCompositeDataSet(); - $compositeDs->addDataSet($ds1); - $compositeDs->addDataSet($ds2); - return $compositeDs; + return array_merge($core_fixture, $local_fixture); } public function setUp(): void { @@ -123,7 +114,7 @@ public function setUp(): void { $token = $auth['auth_token']; $nonce = $auth['nonce']; $this->request = data_entry_helper::$base_url . - "index.php/services/data_cleaner/verify?auth_token=$token&nonce=$nonce"; + "index.php/services/data_cleaner/verify?auth_token=$token&nonce=$nonce"; $cache = Cache::instance(); $cache->delete('data-cleaner-rules'); @@ -134,7 +125,7 @@ public function setUp(): void { * incomplete or wrong works. */ public function testIncorrectParams() { - $response = data_entry_helper::http_post($this->request, null); + $response = data_entry_helper::http_post($this->request, NULL); $this->assertEquals($response['output'], 'Invalid parameters'); } @@ -144,29 +135,45 @@ public function testIncorrectParams() { * data_cleaner_period_within_year module must be enabled. */ public function testPeriodWithinYearFail() { - $response = data_entry_helper::http_post($this->request, array( - 'sample' => json_encode(array( + $response = data_entry_helper::http_post($this->request, [ + 'sample' => json_encode([ 'sample:survey_id' => 1, 'sample:date' => '12/09/2012', 'sample:entered_sref' => 'SU1234', 'sample:entered_sref_system' => 'osgb', - )), - 'occurrences' => json_encode(array( - array( + ]), + 'occurrences' => json_encode([ + [ 'occurrence:taxa_taxon_list_id' => 1, - ), - )), - 'rule_types' => json_encode(array('PeriodWithinYear')), - )); + ], + ]), + 'rule_types' => json_encode(['PeriodWithinYear']), + ]); $errors = json_decode($response['output'], TRUE); $this->assertTrue($response['result'], 'Invalid response'); $this->assertIsArray($errors, 'Errors list not returned'); - $this->assertEquals(1, count($errors), 'Errors list empty. Is the data_cleaner_period_within_year module installed?'); - $this->assertArrayHasKey('taxa_taxon_list_id', $errors[0], 'Errors list missing taxa_taxon_list_id'); - $this->assertEquals('1', $errors[0]['taxa_taxon_list_id'], 'Incorrect taxa_taxon_list_id returned'); + $this->assertEquals( + 1, + count($errors), + 'Errors list empty. Is the data_cleaner_period_within_year module installed?' + ); + $this->assertArrayHasKey( + 'taxa_taxon_list_id', + $errors[0], + 'Errors list missing taxa_taxon_list_id' + ); + $this->assertEquals( + '1', + $errors[0]['taxa_taxon_list_id'], + 'Incorrect taxa_taxon_list_id returned' + ); $this->assertArrayHasKey('message', $errors[0], 'Errors list missing message'); - $this->assertEquals('PeriodWithinYear test failed', $errors[0]['message'], 'Incorrect message returned'); + $this->assertEquals( + 'PeriodWithinYear test failed', + $errors[0]['message'], + 'Incorrect message returned' + ); } /** diff --git a/modules/phpUnit/config/core_fixture.php b/modules/phpUnit/config/core_fixture.php new file mode 100644 index 0000000000..dd431f2583 --- /dev/null +++ b/modules/phpUnit/config/core_fixture.php @@ -0,0 +1,932 @@ + [ + [ + "title" => "Test website", + "description" => "Website for unit testing", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "url" => "http:,//www.indicia.org.uk", + "password" => "password", + "verification_checks_enabled" => 'true', + ], + ], + "users_websites" => [ + [ + "user_id" => 1, + "website_id" => 1, + "site_role_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "surveys" => [ + [ + "title" => "Test survey", + "description" => "Survey for unit testing", + "website_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "title" => "Test survey 2", + "description" => "Additional survey for unit testing", + "website_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "taxon_meanings" => [ + [ + // No support for INSERT INTO table DEFAULT VALUES. + // Use high id values to avoid conflict with any values created by sequence + // during testing. + "id" => 10000, + ], + [ + "id" => 10001, + ], + ], + "taxon_groups" => [ + [ + "title" => "Test taxon group", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "taxon_ranks" => [ + [ + "rank" => "Genus", + "short_name" => "Genus", + "italicise_taxon" => "false", + "sort_order" => 290, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "rank" => "Species", + "short_name" => "Species", + "italicise_taxon" => "true", + "sort_order" => 300, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "taxon_lists" => [ + [ + "title" => "Test taxon list", + "description" => "Taxon list for unit testing", + "website_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "taxa" => [ + [ + "taxon" => "Test taxon", + "taxon_group_id" => 1, + "language_id" => 2, + "external_key" => "TESTKEY", + "taxon_rank_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "taxon" => "Test taxon 2", + "taxon_group_id" => 1, + "language_id" => 2, + "external_key" => "TESTKEY2", + "taxon_rank_id" => 2, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "taxa_taxon_lists" => [ + [ + "taxon_list_id" => 1, + "taxon_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "taxon_meaning_id" => 10000, + "taxonomic_sort_order" => 1, + "preferred" => "true", + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "taxon_list_id" => 1, + "taxon_id" => 2, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "taxon_meaning_id" => 10001, + "taxonomic_sort_order" => 1, + "preferred" => "true", + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "cache_taxa_taxon_lists" => [ + [ + "id" => 1, + "preferred" => true, + "taxon_list_id" => 1, + "taxon_list_title" => "Test taxa taxon list", + "website_id" => 1, + "preferred_taxa_taxon_list_id" => 1, + "taxonomic_sort_order" => 1, + "taxon" => "Test taxon", + "language_iso" => "lat", + "language" => "Latin", + "preferred_taxon" => "Test taxon", + "preferred_language_iso" => "lat", + "preferred_language" => "Latin", + "external_key" => "TESTKEY", + "taxon_rank" => "Genus", + "taxon_rank_sort_order" => "290", + "taxon_meaning_id" => 10000, + "taxon_group_id" => 1, + "taxon_group" => "Test taxon group", + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 2, + "preferred" => true, + "taxon_list_id" => 1, + "taxon_list_title" => "Test taxa taxon list 2", + "website_id" => 1, + "preferred_taxa_taxon_list_id" => 2, + "taxonomic_sort_order" => 2, + "taxon" => "Test taxon 2", + "language_iso" => "lat", + "language" => "Latin", + "preferred_taxon" => "Test taxon", + "preferred_language_iso" => "lat", + "preferred_language" => "Latin", + "external_key" => "TESTKEY2", + "taxon_rank" => "Species", + "taxon_rank_sort_order" => "300", + "taxon_meaning_id" => 10001, + "taxon_group_id" => 1, + "taxon_group" => "Test taxon group", + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + ], + "cache_taxon_searchterms" => [ + [ + "id" => 1, + "taxa_taxon_list_id" => 1, + "taxon_list_id" => 1, + "searchterm" => "testtaxon", + "original" => "Test taxon", + "taxon_group" => "Test taxon group", + "taxon_meaning_id" => 10000, + "preferred_taxon" => "Test taxon", + "default_common_name" => "Test taxon", + "language_iso" => "lat", + "name_type" => "L", + "simplified" => "t", + "taxon_group_id" => 1, + "preferred" => "t", + "searchterm_length" => 9, + "preferred_taxa_taxon_list_id" => 1, + "external_key" => "TESTKEY", + "taxon_rank_sort_order" => "290", + ], + [ + "id" => 2, + "taxa_taxon_list_id" => 1, + "taxon_list_id" => 1, + "searchterm" => "Test taxon", + "original" => "Test taxon", + "taxon_group" => "Test taxon group", + "taxon_meaning_id" => 10000, + "preferred_taxon" => "Test taxon", + "default_common_name" => "Test taxon", + "language_iso" => "lat", + "name_type" => "L", + "simplified" => "f", + "taxon_group_id" => 1, + "preferred" => "t", + "searchterm_length" => 10, + "preferred_taxa_taxon_list_id" => 1, + "external_key" => "TESTKEY", + "taxon_rank_sort_order" => "290", + ], + [ + "id" => 3, + "taxa_taxon_list_id" => 2, + "taxon_list_id" => 1, + "searchterm" => "testtaxon2", + "original" => "Test taxon 2", + "taxon_group" => "Test taxon group", + "taxon_meaning_id" => 10001, + "preferred_taxon" => "Test taxon 2", + "default_common_name" => "Test taxon 2", + "language_iso" => "lat", + "name_type" => "L", + "simplified" => "t", + "taxon_group_id" => 1, + "preferred" => "t", + "searchterm_length" => 10, + "preferred_taxa_taxon_list_id" => 1, + "external_key" => "TESTKEY2", + "taxon_rank_sort_order" => "300", + ], + [ + "id" => 4, + "taxa_taxon_list_id" => 2, + "taxon_list_id" => 1, + "searchterm" => "Test taxon 2", + "original" => "Test taxon 2", + "taxon_group" => "Test taxon group", + "taxon_meaning_id" => 10001, + "preferred_taxon" => "Test taxon 2", + "default_common_name" => "Test taxon 2", + "language_iso" => "lat", + "name_type" => "L", + "simplified" => "f", + "taxon_group_id" => 1, + "preferred" => "t", + "searchterm_length" => 12, + "preferred_taxa_taxon_list_id" => 1, + "external_key" => "TESTKEY2", + "taxon_rank_sort_order" => "300", + ], + ], + "meanings" => [ + // No support for INSERT INTO table DEFAULT VALUES. + // Use high id values to avoid conflict with any values created by sequence + // during testing. + [ + "id" => 10000, + ], + [ + "id" => 10001, + ], + [ + "id" => 10002, + ], + [ + "id" => 10003, + ], + [ + "id" => 10004, + ], + [ + "id" => 10005, + ], + [ + "id" => 10006, + ], + ], + "termlists" => [ + [ + "title" => "Test term list", + "description" => "Term list list for unit testing", + "website_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "external_key" => "TESTKEY", + ], + [ + "title" => "Location types", + "description" => "Term list for location types", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "external_key" => "indicia:location_types", + ], + [ + "title" => "Sample methods", + "description" => "Term list for sample methods", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "external_key" => "indicia:sample_methods", + ], + [ + "title" => "User identifier types", + "description" => "Term list for user identifier types", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "external_key" => "indicia:user_identifier_types", + ], + [ + "title" => "Group types", + "description" => "Term list for group types", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "external_key" => "indicia:group_types", + ], + [ + "title" => "Media types", + "description" => "Term list for media types", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "external_key" => "indicia:media_types", + ], + ], + + "terms" => [ + [ + "term" => "Test term", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "term" => "Test location type", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "term" => "Test sample method", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "term" => "email", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "term" => "twitter", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "term" => "Test group type", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "term" => "Image:Local", + "language_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "termlists_terms" => [ + [ + // Test term list. + "termlist_id" => 1, + // Test term. + "term_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10000, + "preferred" => "true", + "sort_order" => 1, + ], + [ + // Location types. + "termlist_id" => 2, + // Test location type. + "term_id" => 2, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10001, + "preferred" => "true", + "sort_order" => 1, + ], + [ + // Sample methods. + "termlist_id" => 3, + // Test sample method. + "term_id" => 3, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10002, + "preferred" => "true", + "sort_order" => 1, + ], + [ + // User identifier types. + "termlist_id" => 4, + // Email. + "term_id" => 4, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10003, + "preferred" => "true", + "sort_order" => 1, + ], + [ + // User identifier types. + "termlist_id" => 4, + // Twitter. + "term_id" => 5, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10004, + "preferred" => "true", + "sort_order" => 2, + ], + [ + // Group types. + "termlist_id" => 5, + // Test group type. + "term_id" => 6, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10005, + "preferred" => "true", + "sort_order" => 2, + ], + [ + // Media types. + "termlist_id" => 6, + // Image:Local. + "term_id" => 7, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "meaning_id" => 10005, + "preferred" => "true", + "sort_order" => 1, + ], + ], + "cache_termlists_terms" => [ + [ + "id" => 1, + "preferred" => "true", + "termlist_id" => 1, + "termlist_title" => "Test term list", + "website_id" => 1, + "preferred_termlists_term_id" => 1, + "sort_order" => 1, + "term" => "Test term", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "Test term", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10000, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 2, + "preferred" => "true", + "termlist_id" => 2, + "termlist_title" => "Location types", + "website_id" => 1, + "preferred_termlists_term_id" => 2, + "sort_order" => 1, + "term" => "Test location type", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "Test location type", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10001, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 3, + "preferred" => "true", + "termlist_id" => 3, + "termlist_title" => "Sample methods", + "website_id" => 1, + "preferred_termlists_term_id" => 3, + "sort_order" => 1, + "term" => "Test sample method", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "Test term", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10002, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 4, + "preferred" => "true", + "termlist_id" => 4, + "termlist_title" => "User identifier types", + "website_id" => 1, + "preferred_termlists_term_id" => 4, + "sort_order" => 1, + "term" => "email", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "email", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10003, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 5, + "preferred" => "true", + "termlist_id" => 4, + "termlist_title" => "User identifier types", + "website_id" => 1, + "preferred_termlists_term_id" => 5, + "sort_order" => 2, + "term" => "twitter", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "twitter", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10004, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 6, + "preferred" => "true", + "termlist_id" => 5, + "termlist_title" => "Group types", + "website_id" => 1, + "preferred_termlists_term_id" => 6, + "sort_order" => 1, + "term" => "Test group type", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "Test group type", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10005, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + [ + "id" => 7, + "preferred" => "true", + "termlist_id" => 6, + "termlist_title" => "Media types", + "website_id" => 1, + "preferred_termlists_term_id" => 7, + "sort_order" => 1, + "term" => "Image:Local", + "language_iso" => "eng", + "language" => "English", + "preferred_term" => "Image:Local", + "preferred_language_iso" => "eng", + "preferred_language" => "English", + "meaning_id" => 10006, + "cache_created_on" => "2016-07-22 16:00:00", + "cache_updated_on" => "2016-07-22 16:00:00", + ], + ], + "samples" => [ + [ + "survey_id" => 1, + "date_start" => "2016-07-22", + "date_end" => "2016-07-22", + "date_type" => "D", + "entered_sref" => "SU01", + "entered_sref_system" => "OSGB", + "comment" => "Sample for unit testing with a \" double quote", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "recorder_names" => "PHPUnit", + "record_status" => "C", + ], + [ + "survey_id" => 1, + "date_start" => "2016-07-22", + "date_end" => "2016-07-22", + "date_type" => "D", + "entered_sref" => "SU01", + "entered_sref_system" => "OSGB", + "comment" => "Sample for unit testing with a \nline break", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "recorder_names" => "PHPUnit", + "record_status" => "C", + ], + ], + "map_squares" => [ + [ + "geom" => "010300002031BF0D0001000000050000004E9C282E3C320BC18FC3A8120A2F59412CCEAACFA94309C1E75E7B57062F5941A7DE4D3BB84209C11FD1A351893E5941BBB729FE3E320BC1D8E4B8118D3E59414E9C282E3C320BC18FC3A8120A2F5941", + "x" => -214871, + "y" => 6609705, + "size" => 10000, + ], + ], + "occurrences" => [ + [ + "sample_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "website_id" => 1, + "comment" => "Occurrence for unit testing", + "taxa_taxon_list_id" => 1, + "record_status" => "C", + "release_status" => "R", + "confidential" => "f", + ], + [ + "sample_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "website_id" => 1, + "comment" => "Confidential occurrence for unit testing", + "taxa_taxon_list_id" => 1, + "record_status" => "C", + "release_status" => "R", + "confidential" => "t", + ], + ], + "cache_occurrences_functional" => [ + [ + "id" => 1, + "sample_id" => 1, + "website_id" => 1, + "survey_id" => 1, + "date_start" => "2016-07-22", + "date_end" => "2016-07-22", + "date_type" => "D", + "created_on" => "2016-07-22 16:00:00", + "updated_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "taxa_taxon_list_id" => 1, + "preferred_taxa_taxon_list_id" => 1, + "taxon_meaning_id" => 10000, + "taxa_taxon_list_external_key" => "TESTKEY", + "taxon_group_id" => 1, + "record_status" => "C", + "release_status" => "R", + "zero_abundance" => "f", + "confidential" => "f", + "map_sq_1km_id" => 1, + "map_sq_2km_id" => 1, + "map_sq_10km_id" => 1, + "verification_checks_enabled" => "true", + ], + [ + "id" => 2, + "sample_id" => 1, + "website_id" => 1, + "survey_id" => 1, + "date_start" => "2016-07-22", + "date_end" => "2016-07-22", + "date_type" => "D", + "created_on" => "2016-07-22 16:00:00", + "updated_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "taxa_taxon_list_id" => 1, + "preferred_taxa_taxon_list_id" => 1, + "taxon_meaning_id" => 10000, + "taxa_taxon_list_external_key" => "TESTKEY", + "taxon_group_id" => 1, + "record_status" => "C", + "release_status" => "R", + "zero_abundance" => "f", + "confidential" => "t", + "map_sq_1km_id" => 1, + "map_sq_2km_id" => 1, + "map_sq_10km_id" => 1, + "verification_checks_enabled" => "true", + ], + ], + "cache_occurrences_nonfunctional" => [ + [ + "id" => 1, + ], + [ + "id" => 2, + ], + ], + "cache_samples_functional" => [ + [ + "id" => 1, + "website_id" => 1, + "survey_id" => 1, + "date_start" => "2016-07-22", + "date_end" => "2016-07-22", + "date_type" => "D", + "created_on" => "2016-07-22 16:00:00", + "updated_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "record_status" => "C", + "map_sq_1km_id" => 1, + "map_sq_2km_id" => 1, + "map_sq_10km_id" => 1, + ], + ], + "cache_samples_nonfunctional" => [ + [ + "id" => 1, + "website_title" => "Test website", + "survey_title" => "Test survey", + "public_entered_sref" => "SU01", + "entered_sref_system" => "OSGB", + "recorders" => "PHPUnit", + ], + ], + "sample_attributes" => [ + [ + "caption" => "Altitude", + "data_type" => "I", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "public" => "false", + ], + ], + "sample_attributes_websites" => [ + [ + "website_id" => 1, + "sample_attribute_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "restrict_to_survey_id" => 1, + ], + ], + "occurrence_attributes" => [ + [ + "caption" => "Identified_by", + "data_type" => "T", + "public" => "false", + "system_function" => "det_full_name", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "occurrence_attributes_websites" => [ + [ + "website_id" => 1, + "occurrence_attribute_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "restrict_to_survey_id" => 1, + ], + ], + "locations" => [ + [ + "name" => "Test location", + "centroid_sref" => "SU01", + "centroid_sref_system" => "OSGB", + "location_type_id" => "2", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + "public" => "true", + ], + ], + "location_attributes" => [ + [ + "caption" => "Test text", + "data_type" => "T", + "public" => "false", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "caption" => "Test lookup", + "data_type" => "L", + "termlist_id" => 1, + "public" => "false", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + [ + "caption" => "Test integer", + "data_type" => "I", + "termlist_id" => 1, + "public" => "false", + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], + "location_attributes_websites" => [ + [ + // Test website. + "website_id" => 1, + // Test text. + "location_attribute_id" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + ], + [ + // Test website. + "website_id" => 1, + // Test lookup. + "location_attribute_id" => 2, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + ], + [ + // Test website. + "website_id" => 1, + // Test integer. + "location_attribute_id" => 3, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + ], + ], + "location_attribute_values" => [ + [ + // Test location. + "location_id" => 1, + // Test lookup. + "location_attribute_id" => 2, + // Test term. + "int_value" => 1, + "created_on" => "2016-07-22 16:00:00", + "created_by_id" => 1, + "updated_on" => "2016-07-22 16:00:00", + "updated_by_id" => 1, + ], + ], +]; diff --git a/modules/phpUnit/libraries/Indicia_ArrayDataSet.php b/modules/phpUnit/libraries/Indicia_ArrayDataSet.php index d3f26b8406..322bb0a25a 100644 --- a/modules/phpUnit/libraries/Indicia_ArrayDataSet.php +++ b/modules/phpUnit/libraries/Indicia_ArrayDataSet.php @@ -9,47 +9,44 @@ /** * Implements a dataset created from a PHP array. - * https://phpunit.de/manual/current/en/database.html#database.available-implementations + * https://phpunit.de/manual/6.5/en/database.html#database.available-implementations */ -class Indicia_ArrayDataSet extends DbUDataSetAbstractDataSet -{ - /** - * @var array - */ - protected $tables = []; - - /** - * @param array $data - */ - public function __construct(array $data) - { - foreach ($data AS $tableName => $rows) { - $columns = []; - if (isset($rows[0])) { - $columns = array_keys($rows[0]); - } - - $metaData = new DbUDataSetDefaultTableMetadata($tableName, $columns); - $table = new DbUDataSetDefaultTable($metaData); - - foreach ($rows AS $row) { - $table->addRow($row); - } - $this->tables[$tableName] = $table; - } +class Indicia_ArrayDataSet extends DbUDataSetAbstractDataSet { + /** + * @var array + */ + protected $tables = []; + + /** + * @param array $data + */ + public function __construct(array $data) { + foreach ($data as $tableName => $rows) { + $columns = []; + if (isset($rows[0])) { + $columns = array_keys($rows[0]); + } + + $metaData = new DbUDataSetDefaultTableMetadata($tableName, $columns); + $table = new DbUDataSetDefaultTable($metaData); + + foreach ($rows as $row) { + $table->addRow($row); + } + $this->tables[$tableName] = $table; } + } - protected function createIterator(bool $reverse = false): DbUDataSetITableIterator - { - return new DbUDataSetDefaultTableIterator($this->tables, $reverse); + protected function createIterator(bool $reverse = false): DbUDataSetITableIterator { + return new DbUDataSetDefaultTableIterator($this->tables, $reverse); + } + + public function getTable(string $tableName): DbUDataSetITable { + if (!isset($this->tables[$tableName])) { + throw new InvalidArgumentException("$tableName is not a table in the current database."); } - public function getTable(string $tableName): DbUDataSetITable - { - if (!isset($this->tables[$tableName])) { - throw new InvalidArgumentException("$tableName is not a table in the current database."); - } + return $this->tables[$tableName]; + } - return $this->tables[$tableName]; - } -} \ No newline at end of file +} diff --git a/modules/phpUnit/libraries/Indicia_DatabaseTestCase.php b/modules/phpUnit/libraries/Indicia_DatabaseTestCase.php index 0a2f191c71..963d4d4706 100644 --- a/modules/phpUnit/libraries/Indicia_DatabaseTestCase.php +++ b/modules/phpUnit/libraries/Indicia_DatabaseTestCase.php @@ -13,47 +13,58 @@ /** * An abstract test case to efficiently make database connections. - * https://phpunit.de/manual/current/en/database.html#database.tip-use-your-own-abstract-database-testcase + * + * https://phpunit.de/manual/6.5/en/database.html#database.tip-use-your-own-abstract-database-testcase */ abstract class Indicia_DatabaseTestCase extends DbUTestCase { // Only instantiate pdo once for test clean-up/fixture load. static private $pdo = NULL; - // only instantiate PHPUnit_Extensions_Database_DB_IDatabaseConnection once per test - private $conn = null; + // Only instantiate PHPUnit_Extensions_Database_DB_IDatabaseConnection once + // per test. + private $conn = NULL; final public function getConnection() { - if ($this->conn === null) { - if (self::$pdo == null) { + if ($this->conn === NULL) { + if (self::$pdo == NULL) { $dsn = 'pgsql:host=127.0.0.1;dbname=indicia'; $user = 'indicia_user'; $pass = 'indicia_user_pass'; self::$pdo = new PDO($dsn, $user, $pass); - } + } $this->conn = $this->createDefaultDBConnection(self::$pdo, 'indicia'); } return $this->conn; } - - // Default implementation which does nothing + + /** + * Default implementation which does nothing. + */ public function getDataSet() { - return new Indicia_ArrayDataSet(array()); + return new Indicia_ArrayDataSet([]); } - // Override the operation used to set up the database. - // The default is CLEAN_INSERT($cascadeTruncates = FALSE) - // We require truncates to be cascaded to prevent foreign key - // violations and sequences to be restarted. + /** + * Override the operation used to set up the database. + * + * The default is CLEAN_INSERT($cascadeTruncates = FALSE) + * We require truncates to be cascaded to prevent foreign key + * violations and sequences to be restarted. + */ protected function getSetUpOperation() { - return My_Operation_Factory::RESTART_INSERT(true); + return My_Operation_Factory::RESTART_INSERT(TRUE); } - - // Override the function to create the database connection so that is uses - // My_DB_DefaultDatabaseConnection. + + /** + * Override the function to create the database connection. + * + * Use My_DB_DefaultDatabaseConnection. + */ protected function createDefaultDBConnection(PDO $connection, $schema = ''): dbUDatabaseDefualtConnection { return new My_DB_DefaultDatabaseConnection($connection, $schema); - } + } + } /** @@ -61,6 +72,7 @@ protected function createDefaultDBConnection(PDO $connection, $schema = ''): dbU * a database specific command to restart sequences. */ class My_DB_MetaData_PgSQL extends DbUDatabaseMetadataPgSQL { + public function getRestartCommand($table) { // Assumes sequence naming convention has been followed. $seq = $table . '_id_seq'; @@ -75,14 +87,16 @@ public function getRestartCommand($table) { } /** - * Extends PHPUnit_Extensions_Database_DB_MetaData in order to replace the + * Extends PHPUnit_Extensions_Database_DB_MetaData in order to replace the * default postgres driver with mine. */ abstract class My_DB_MetaData extends DbUDatabaseMetadataAbstractMetadata { + public static function createMetaData(PDO $pdo, $schema = '') { self::$metaDataClassMap['pgsql'] = 'My_DB_MetaData_PgSQL'; return parent::createMetaData($pdo, $schema); - } + } + } /** @@ -91,6 +105,7 @@ public static function createMetaData(PDO $pdo, $schema = '') { * b. give access to the command that will restart sequences. */ class My_DB_DefaultDatabaseConnection extends dbUDatabaseDefualtConnection { + public function __construct(PDO $connection, $schema = '') { $this->connection = $connection; $this->metaData = My_DB_MetaData::createMetaData($connection, $schema); @@ -100,12 +115,14 @@ public function __construct(PDO $connection, $schema = '') { public function getRestartCommand($table) { return $this->getMetaData()->getRestartCommand($table); } + } /** * New class to add a Restart operation. */ -Class My_Operation_Restart implements DbUOperationOperation { +class My_Operation_Restart implements DbUOperationOperation { + public function execute( DbUDatabaseConnection $connection, DbUDatasetIDataset $dataSet @@ -114,8 +131,9 @@ public function execute( $tableName = $table->getTableMetaData()->getTableName(); $query = $connection->getRestartCommand($tableName); try { - $connection->getConnection()->query($query); - } catch (\Exception $e) { + $connection->getConnection()->query($query); + } + catch (\Exception $e) { if ($e instanceof PDOException) { throw new DbUOperationException('RESTART', $query, [], $table, $e->getMessage()); } @@ -123,23 +141,25 @@ public function execute( } } } + } /** - * Extends PHPUnit_Extensions_Database_Operation_Factory in order to add + * Extends PHPUnit_Extensions_Database_Operation_Factory in order to add * functions that call the Restart operation. */ -Class My_Operation_Factory extends DbUOperationFactory { +class My_Operation_Factory extends DbUOperationFactory { public static function RESTART_INSERT($cascadeTruncates = FALSE) { return new DbUOperationComposite([ self::TRUNCATE($cascadeTruncates), self::RESTART(), - self::INSERT() + self::INSERT(), ]); } public static function RESTART() { return new My_Operation_Restart(); } + } diff --git a/modules/phpUnit/libraries/MY_Session.php b/modules/phpUnit/libraries/MY_Session.php index 2766863265..69c9d685db 100644 --- a/modules/phpUnit/libraries/MY_Session.php +++ b/modules/phpUnit/libraries/MY_Session.php @@ -1,128 +1,127 @@ -destroy(); - - if (Session::$config['driver'] !== 'native') - { - // Set driver name - $driver = 'Session_'.ucfirst(Session::$config['driver']).'_Driver'; - - // Load the driver - if ( ! Kohana::auto_load($driver)) - throw new Kohana_Exception('core.driver_not_found', Session::$config['driver'], get_class($this)); - - // Initialize the driver - Session::$driver = new $driver(); - - // Validate the driver - if ( ! (Session::$driver instanceof Session_Driver)) - throw new Kohana_Exception('core.driver_implements', Session::$config['driver'], get_class($this), 'Session_Driver'); - - // Register non-native driver as the session handler - session_set_save_handler - ( - array(Session::$driver, 'open'), - array(Session::$driver, 'close'), - array(Session::$driver, 'read'), - array(Session::$driver, 'write'), - array(Session::$driver, 'destroy'), - array(Session::$driver, 'gc') - ); - } - - // Validate the session name - if ( ! preg_match('~^(?=.*[a-z])[a-z0-9_]++$~iD', Session::$config['name'])) - throw new Kohana_Exception('session.invalid_session_name', Session::$config['name']); - - // Name the session, this will also be the name of the cookie - session_name(Session::$config['name']); - - // Set the session cookie parameters - session_set_cookie_params - ( - Session::$config['expiration'], - Kohana::config('cookie.path'), - Kohana::config('cookie.domain'), - Kohana::config('cookie.secure'), - Kohana::config('cookie.httponly') - ); - - // DO NOT start the session! phpUnit has done so. - // session_start(); - - // Put session_id in the session variable - $_SESSION['session_id'] = session_id(); - - // Set defaults - if ( ! isset($_SESSION['_kf_flash_'])) - { - $_SESSION['total_hits'] = 0; - $_SESSION['_kf_flash_'] = array(); - - $_SESSION['user_agent'] = Kohana::$user_agent; - $_SESSION['ip_address'] = $this->input->ip_address(); - } - - // Set up flash variables - Session::$flash =& $_SESSION['_kf_flash_']; - - // Increase total hits - $_SESSION['total_hits'] += 1; - - // Validate data only on hits after one - if ($_SESSION['total_hits'] > 1) - { - // Validate the session - foreach (Session::$config['validate'] as $valid) - { - switch ($valid) - { - // Check user agent for consistency - case 'user_agent': - if ($_SESSION[$valid] !== Kohana::$user_agent) - return $this->create(); - break; - - // Check ip address for consistency - case 'ip_address': - if ($_SESSION[$valid] !== $this->input->$valid()) - return $this->create(); - break; - - // Check expiration time to prevent users from manually modifying it - case 'expiration': - if (time() - $_SESSION['last_activity'] > ini_get('session.gc_maxlifetime')) - return $this->create(); - break; - } - } - } - - // Expire flash keys - $this->expire_flash(); - - // Update last activity - $_SESSION['last_activity'] = time(); - - // Set the new data - Session::set($vars); - } + /** + * Create a new session. + * + * @param array variables to set after creation + * + * @return void + */ + public function create($vars = NULL) { + // Destroy any current sessions. + $this->destroy(); + + if (Session::$config['driver'] !== 'native') { + // Set driver name. + $driver = 'Session_' . ucfirst(Session::$config['driver']) . '_Driver'; + + // Load the driver. + if (!Kohana::auto_load($driver)) { + throw new Kohana_Exception('core.driver_not_found', Session::$config['driver'], get_class($this)); + } + + // Initialize the driver. + Session::$driver = new $driver(); + + // Validate the driver. + if (!(Session::$driver instanceof Session_Driver)) { + throw new Kohana_Exception('core.driver_implements', Session::$config['driver'], get_class($this), 'Session_Driver'); + } + // Register non-native driver as the session handler. + session_set_save_handler( + [Session::$driver, 'open'], + [Session::$driver, 'close'], + [Session::$driver, 'read'], + [Session::$driver, 'write'], + [Session::$driver, 'destroy'], + [Session::$driver, 'gc'] + ); + } + + // Validate the session name. + if (!preg_match('~^(?=.*[a-z])[a-z0-9_]++$~iD', Session::$config['name'])) { + throw new Kohana_Exception('session.invalid_session_name', Session::$config['name']); + } + // Name the session, this will also be the name of the cookie. + session_name(Session::$config['name']); + + // Set the session cookie parameters. + session_set_cookie_params( + Session::$config['expiration'], + Kohana::config('cookie.path'), + Kohana::config('cookie.domain'), + Kohana::config('cookie.secure'), + Kohana::config('cookie.httponly') + ); + + // DO NOT start the session! phpUnit has done so. + // session_start(); + + // Put session_id in the session variable. + $_SESSION['session_id'] = session_id(); + + // Set defaults. + if (!isset($_SESSION['_kf_flash_'])) { + $_SESSION['total_hits'] = 0; + $_SESSION['_kf_flash_'] = []; + + $_SESSION['user_agent'] = Kohana::$user_agent; + $_SESSION['ip_address'] = $this->input->ip_address(); + } + + // Set up flash variables. + Session::$flash =& $_SESSION['_kf_flash_']; + + // Increase total hits. + $_SESSION['total_hits'] += 1; + + // Validate data only on hits after one. + if ($_SESSION['total_hits'] > 1) { + // Validate the session. + foreach (Session::$config['validate'] as $valid) { + switch ($valid) { + // Check user agent for consistency. + case 'user_agent': + if ($_SESSION[$valid] !== Kohana::$user_agent) { + return $this->create(); + } + break; + + // Check ip address for consistency. + case 'ip_address': + if ($_SESSION[$valid] !== $this->input->$valid()) { + return $this->create(); + } + break; + + // Check expiration time to prevent users from manually modifying it. + case 'expiration': + if (time() - $_SESSION['last_activity'] > ini_get('session.gc_maxlifetime')) { + return $this->create(); + } + break; + } + } + } + + // Expire flash keys. + $this->expire_flash(); + + // Update last activity. + $_SESSION['last_activity'] = time(); + + // Set the new data. + Session::set($vars); + } } \ No newline at end of file diff --git a/modules/phpUnit/libraries/SimpleDatabaseTestCase.php b/modules/phpUnit/libraries/SimpleDatabaseTestCase.php new file mode 100644 index 0000000000..0e3dfa5692 --- /dev/null +++ b/modules/phpUnit/libraries/SimpleDatabaseTestCase.php @@ -0,0 +1,87 @@ +getDataSet(); + self::setupFixture($fixture); + } + + /** + * Set up database fixture defined in file. + */ + private static function setupFixture($fixture) { + + // Remove any pre-existing data in fixture tables. + self::deleteFixture($fixture); + + // Set up fixture. + foreach ($fixture as $table => $records) { + foreach ($records as $record) { + if (!pg_insert(self::$conn, 'indicia.' . $table, $record)) { + throw new Exception("Failed inserting $record into $table"); + } + } + } + + // Fixture files may also contain the expected form of the survey export + // for the configuration established by the fixture. + if (isset($export)) { + return $export; + } + } + + /** + * Delete database fixture. + */ + private static function deleteFixture($fixture) { + // Drop content in fixture tables. + $tables = array_keys($fixture); + $table_list = implode(',', $tables); + pg_query(self::$conn, "TRUNCATE TABLE $table_list CASCADE"); + // And reset primary key sequences. + foreach ($tables as $table) { + if (substr($table, 0, 6) !== 'cache_') { + // Cache tables don't have their own sequences. + $seq = $table . '_id_seq'; + pg_query(self::$conn, "SELECT setval('$seq', 1, false)"); + } + } + + // Clear the cache to ensure tests use new database contents. + $cache = Cache::instance(); + $cache->delete_all(); + + } + +} diff --git a/modules/phpUnit/tests/Helper_Text_Test.php b/modules/phpUnit/tests/Helper_Text_Test.php index 0082bc2f22..44357e9743 100644 --- a/modules/phpUnit/tests/Helper_Text_Test.php +++ b/modules/phpUnit/tests/Helper_Text_Test.php @@ -277,7 +277,7 @@ public function censor_provider() * @group core.helpers.text.censor * @test */ - public function censor($str, $badwords, $replacement = '#', $replace_partial_words = FALSE, $expected_result) + public function censor($str, $badwords, $replacement, $replace_partial_words, $expected_result) { $result = text::censor($str, $badwords, $replacement, $replace_partial_words); $this->assertEquals($expected_result, $result); diff --git a/modules/rest_api/helpers/rest_crud.php b/modules/rest_api/helpers/rest_crud.php index 2bc323b5d2..4fe8f53e90 100644 --- a/modules/rest_api/helpers/rest_crud.php +++ b/modules/rest_api/helpers/rest_crud.php @@ -625,7 +625,7 @@ private static function getResponseMetadata(array $responseMetadata) { if (preg_match('/_media$/', $subTable)) { $subTable = 'media'; } - if (array_key_exists($subTable, self::$entityConfig[$entity]->subModels)) { + if (property_exists(self::$entityConfig[$entity]->subModels, $subTable)) { if (!isset($r[$subTable])) { $r[$subTable] = []; } diff --git a/modules/rest_api/tests/Rest_ControllerTest.php b/modules/rest_api/tests/Rest_ControllerTest.php index f008acb01a..2785f0a83d 100644 --- a/modules/rest_api/tests/Rest_ControllerTest.php +++ b/modules/rest_api/tests/Rest_ControllerTest.php @@ -90,9 +90,9 @@ public function getDataSet() { * Create an occurrence comment for annotation testing. */ $ds2 = new Indicia_ArrayDataSet( - array( - 'filters' => array( - array( + [ + 'filters' => [ + [ 'title' => 'Test filter', 'description' => 'Filter for unit testing', 'definition' => '{"quality":"!R"}', @@ -101,8 +101,8 @@ public function getDataSet() { 'created_by_id' => 1, 'updated_on' => '2016-07-22:16:00:00', 'updated_by_id' => 1, - ), - array( + ], + [ 'title' => 'Test user permission filter', 'description' => 'Filter for unit testing', 'definition' => '{"quality":"!R","occurrence_id":2}', @@ -111,27 +111,27 @@ public function getDataSet() { 'created_by_id' => 1, 'updated_on' => '2016-07-22:16:00:00', 'updated_by_id' => 1, - ), - ), - 'filters_users' => array( - array( + ], + ], + 'filters_users' => [ + [ 'filter_id' => 2, 'user_id' => 1, 'created_on' => '2016-07-22:16:00:00', 'created_by_id' => 1 - ) - ), - 'occurrence_comments' => array( - array( + ], + ], + 'occurrence_comments' => [ + [ 'comment' => 'Occurrence comment for unit testing', 'created_on' => '2016-07-22:16:00:00', 'created_by_id' => 1, 'updated_on' => '2016-07-22:16:00:00', 'updated_by_id' => 1, 'occurrence_id' => 1, - ), - ), - ) + ], + ], + ] ); $compositeDs = new DbUDataSetCompositeDataSet(); @@ -143,19 +143,19 @@ public function getDataSet() { $db = new Database(); $db->update( 'users', - array('password' => '18d025c6c8809e34371e2ec7d84215bd3eb6031dcd804006f4'), - array('id' => 1) + ['password' => '18d025c6c8809e34371e2ec7d84215bd3eb6031dcd804006f4'], + ['id' => 1] ); return $compositeDs; } public static function setUpBeforeClass(): void { - // grab the clients registered on this system + // Grab the clients registered on this system. $clientUserIds = array_keys(Kohana::config('rest.clients')); $clientConfigs = array_values(Kohana::config('rest.clients')); - // just test the first client + // Just test the first client. self::$clientUserId = $clientUserIds[0]; self::$config = $clientConfigs[0]; } @@ -194,8 +194,8 @@ public function testJwt() { $db = new Database(); $db->update( 'websites', - array('public_key' => NULL), - array('id' => 1) + ['public_key' => NULL], + ['id' => 1] ); $cache->delete($cacheKey); // Make an otherwise valid call - should be unauthorised. @@ -206,8 +206,8 @@ public function testJwt() { $db = new Database(); $db->update( 'websites', - array('public_key' => 'INVALID!!!'), - array('id' => 1) + ['public_key' => 'INVALID!!!'], + ['id' => 1] ); $cache->delete($cacheKey); // Make an otherwise valid call - should be unauthorised. @@ -218,8 +218,8 @@ public function testJwt() { $db = new Database(); $db->update( 'websites', - array('public_key' => self::$publicKey), - array('id' => 1) + ['public_key' => self::$publicKey], + ['id' => 1] ); $cache->delete($cacheKey); // Make a valid call - should be authorised. @@ -255,17 +255,20 @@ public function testJwtHeaderCaseInsensitive() { $response = $this->callService( 'samples', FALSE, - ['values' => [ - 'survey_id' => 1, - 'entered_sref' => 'SU1234', - 'entered_sref_system' => 'OSGB', - 'date' => '01/08/2020', - 'comment' => 'A sample to delete', - ]] + [ + 'values' => [ + 'survey_id' => 1, + 'entered_sref' => 'SU1234', + 'entered_sref_system' => 'OSGB', + 'date' => '01/08/2020', + 'comment' => 'A sample to delete', + ] + ] ); $this->assertEquals(201, $response['httpCode']); $id = $response['response']['values']['id']; - // Now GET to check values stored OK using manually set auth header in lowercase. + // Now GET to check values stored OK using manually set auth header in + // lowercase. $this->authMethod = 'none'; $storedObj = $this->callService("samples/$id", FALSE, NULL, ['authorization: bearer ' . self::$jwt]); $this->assertResponseOk($storedObj, "/samples/$id GET"); @@ -350,8 +353,14 @@ private function putTest($table, array $exampleData, array $updateData) { $storedObj = $this->callService("$table/$id"); $expectedValues = array_merge($exampleData, $updateData); foreach ($expectedValues as $field => $value) { - $this->assertTrue(isset($storedObj['response']['values'][$field]), "Stored info in $table does not include value for $field"); - $this->assertEquals($value, $storedObj['response']['values'][$field], "Stored info in $table does not match value for $field"); + $this->assertTrue( + isset($storedObj['response']['values'][$field]), + "Stored info in $table does not include value for $field" + ); + $this->assertEquals( + $value, $storedObj['response']['values'][$field], + "Stored info in $table does not match value for $field" + ); } } @@ -384,8 +393,14 @@ private function getTest($table, $exampleData) { $this->assertTrue(array_key_exists('ETag', $headers), "$table GET does not return ETag."); $this->assertEquals($insertedRecordETag, $headers['ETag'], 'GET returns ETag which does not match expected'); foreach ($exampleData as $field => $value) { - $this->assertTrue(isset($storedObj['response']['values'][$field]), "Stored info in $table does not include value for $field"); - $this->assertEquals($exampleData[$field], $storedObj['response']['values'][$field], "Stored info in $table does not match value for $field"); + $this->assertTrue( + isset($storedObj['response']['values'][$field]), + "Stored info in $table does not include value for $field" + ); + $this->assertEquals( + $exampleData[$field], $storedObj['response']['values'][$field], + "Stored info in $table does not match value for $field" + ); } } @@ -459,7 +474,10 @@ private function getListTest($table, $exampleData) { break; } } - $this->assertFalse($found, 'POSTed survey found in filtered retrieved list using GET which it should be excluded from.'); + $this->assertFalse( + $found, + 'POSTed survey found in filtered retrieved list using GET which it should be excluded from.' + ); } /** @@ -599,13 +617,15 @@ public function testJwtSamplePostUserAuth() { $response = $this->callService( 'samples', FALSE, - ['values' => [ - 'survey_id' => 1, - 'entered_sref' => 'SU1234', - 'entered_sref_system' => 'OSGB', - 'date' => '01/08/2020', - 'comment' => 'A sample comment test', - ]] + [ + 'values' => [ + 'survey_id' => 1, + 'entered_sref' => 'SU1234', + 'entered_sref_system' => 'OSGB', + 'date' => '01/08/2020', + 'comment' => 'A sample comment test', + ], + ] ); $this->assertEquals(401, $response['httpCode']); // Grant website access. @@ -615,20 +635,25 @@ public function testJwtSamplePostUserAuth() { $response = $this->callService( 'samples', FALSE, - ['values' => [ - 'survey_id' => 1, - 'entered_sref' => 'SU1234', - 'entered_sref_system' => 'OSGB', - 'date' => '01/08/2020', - 'comment' => 'A sample comment test', - ]] + [ + 'values' => [ + 'survey_id' => 1, + 'entered_sref' => 'SU1234', + 'entered_sref_system' => 'OSGB', + 'date' => '01/08/2020', + 'comment' => 'A sample comment test', + ], + ] ); $this->assertEquals(201, $response['httpCode']); $id = $response['response']['values']['id']; // Check created_by_id. $response = $this->callService("samples/$id"); $this->assertEquals(200, $response['httpCode']); - $this->assertEquals($userId, $response['response']['values']['created_by_id'], 'Created_by_id not set correctly for sample'); + $this->assertEquals( + $userId, $response['response']['values']['created_by_id'], + 'Created_by_id not set correctly for sample' + ); // Re-authenticate as user 1. self::$jwt = $this->getJwt(self::$privateKey, 'http://www.indicia.org.uk', 1, time() + 120); // They shouldn't have access. @@ -653,9 +678,7 @@ public function testJwtSamplePostMoreTests() { $response = $this->callService( 'samples', FALSE, - [ - 'values' => $data - ] + ['values' => $data] ); $this->assertEquals(201, $response['httpCode']); $headers = $this->parseHeaders($response['headers']); @@ -697,12 +720,10 @@ public function testJwtSamplePostMoreTests() { $response = $this->callService( 'samples', FALSE, - [ - 'values' => $data - ] + ['values' => $data] ); $this->assertEquals(400, $response['httpCode']); - // GET the posted data; + // GET the posted data. $response = $this->callService("samples/$id"); $this->assertResponseOk($response, "/samples GET"); $this->assertTrue(array_key_exists('comment', $response['response']['values']), @@ -719,7 +740,7 @@ public function testJwtSamplePostMoreTests() { 'GET samples response does not contain processed lat output.'); $this->assertTrue(array_key_exists('lon', $response['response']['values']), 'GET samples response does not contain processed lon output.'); - // PUT a bad update with ID mismatch + // PUT a bad update with ID mismatch. $data = [ 'id' => $id + 1, 'entered_sref' => 'SU121341', @@ -843,7 +864,10 @@ public function testJwtSamplePostList() { FALSE, $data ); - $this->assertEquals(400, $response['httpCode'], 'POSTing a list to normal endpoint should fail'); + $this->assertEquals( + 400, $response['httpCode'], + 'POSTing a list to normal endpoint should fail' + ); $response = $this->callService( 'samples/list', FALSE, @@ -851,11 +875,17 @@ public function testJwtSamplePostList() { ); $this->assertEquals(201, $response['httpCode']); foreach ($response['response'] as $idx => $item) { - $this->assertTrue(is_numeric($idx), 'Response from list post should be a simple list array'); + $this->assertTrue( + is_numeric($idx), + 'Response from list post should be a simple list array' + ); $id = $item['values']['id']; $occCount = $db->query("select count(*) from occurrences where sample_id=$id") ->current()->count; - $this->assertEquals(1, $occCount, 'No occurrence created when submitted with a sample in a list.'); + $this->assertEquals( + 1, $occCount, + 'No occurrence created when submitted with a sample in a list.' + ); } } @@ -883,7 +913,10 @@ public function testJwtSamplePostExtKey() { FALSE, ['values' => $data] ); - $this->assertEquals(409, $response['httpCode'], 'Duplicate external key did not return 409 Conflict response.'); + $this->assertEquals( + 409, $response['httpCode'], + 'Duplicate external key did not return 409 Conflict response.' + ); $this->assertArrayHasKey('duplicate_of', $response['response']); $this->assertArrayHasKey('id', $response['response']['duplicate_of']); $this->assertArrayHasKey('href', $response['response']['duplicate_of']); @@ -895,7 +928,10 @@ public function testJwtSamplePostExtKey() { FALSE, ['values' => $data] ); - $this->assertEquals(201, $response['httpCode'], 'Duplicate external key in different survey not accepted.'); + $this->assertEquals( + 201, $response['httpCode'], + 'Duplicate external key in different survey not accepted.' + ); // PUT with same external key should be OK. $response = $this->callService( "samples/$id", @@ -1135,9 +1171,18 @@ public function testJwtSamplePostWithMedia() { $id = $response['response']['values']['id']; $smpMediaCount = $db->query("select count(*) from sample_media where sample_id=$id and path='$uploadedFileName'") ->current()->count; - $this->assertEquals(1, $smpMediaCount, 'No media created when submitted with a sample.'); - $this->assertFileExists(DOCROOT . 'upload/' . $uploadedFileName, 'Uploaded media file does not exist in destination'); - $this->assertFileExists(DOCROOT . 'upload/thumb-' . $uploadedFileName, 'Uploaded media thumbnail does not exist in destination'); + $this->assertEquals( + 1, $smpMediaCount, + 'No media created when submitted with a sample.' + ); + $this->assertFileExists( + DOCROOT . 'upload/' . $uploadedFileName, + 'Uploaded media file does not exist in destination' + ); + $this->assertFileExists( + DOCROOT . 'upload/thumb-' . $uploadedFileName, + 'Uploaded media thumbnail does not exist in destination' + ); // Post a sample which refers to an incorrect file. $data = [ 'values' => [ @@ -1185,7 +1230,7 @@ public function testJwtSampleOccurrenceMediaPost() { $file, 'image/jpg', basename($file) - ) + ), ], [], NULL, TRUE ); @@ -1222,10 +1267,16 @@ public function testJwtSampleOccurrenceMediaPost() { $this->assertEquals(201, $response['httpCode']); $id = $response['response']['values']['id']; $occurrences = $db->query("select id from occurrences where sample_id=$id"); - $this->assertEquals(1, count($occurrences), 'Posting a sample with occurrence did not create the occurrence'); + $this->assertEquals( + 1, count($occurrences), + 'Posting a sample with occurrence did not create the occurrence' + ); $occurrenceId = $occurrences->current()->id; $occurrences = $db->query("select id from occurrence_media where occurrence_id=$occurrenceId"); - $this->assertEquals(1, count($occurrences), 'Posting a sample with occurrence and media did not create the media'); + $this->assertEquals( + 1, count($occurrences), + 'Posting a sample with occurrence and media did not create the media' + ); // Check occurrence exists. $response = $this->callService("occurrences/$occurrenceId"); $this->assertResponseOk($response, "/occurrences/$occurrenceId GET"); @@ -1310,7 +1361,10 @@ public function testJwtLocationPost() { $db = new Database(); $locationsWebsitesCount = $db->query("select count(*) from locations_websites where location_id=$id") ->current()->count; - $this->assertEquals(1, $locationsWebsitesCount, 'No locations_websites record created for a location POST.'); + $this->assertEquals( + 1, $locationsWebsitesCount, + 'No locations_websites record created for a location POST.' + ); } /** @@ -1320,7 +1374,7 @@ public function testJwtLocationPut() { $this->putTest('locations', [ 'name' => 'Location test', 'centroid_sref' => 'ST1234', - 'centroid_sref_system' => 'OSGB' + 'centroid_sref_system' => 'OSGB', ], [ 'name' => 'Location test updated', ]); @@ -1333,7 +1387,7 @@ public function testJwtLocationGet() { $this->getTest('locations', [ 'name' => 'Location GET test', 'centroid_sref' => 'ST1234', - 'centroid_sref_system' => 'OSGB' + 'centroid_sref_system' => 'OSGB', ]); } @@ -1359,7 +1413,7 @@ public function testJwtLocationOptions() { * Test behaviour around REST support for ETags. */ public function testJwtLocationETags() { - $this->eTagsTest('locations', [ + $this->eTagsTest('locations', [ 'name' => 'Location GET test', 'centroid_sref' => 'ST1234', 'centroid_sref_system' => 'OSGB', @@ -1377,7 +1431,7 @@ public function testJwtSurveyPost() { * Test /surveys PUT behaviour. */ public function testJwtSurveyPut() { - $this->putTest('surveys', [ + $this->putTest('surveys', [ 'title' => 'Test survey', 'description' => 'A test', ], [ @@ -1389,7 +1443,7 @@ public function testJwtSurveyPut() { * A basic test of /surveys GET. */ public function testJwtSurveyGet() { - $this->getTest('surveys', [ + $this->getTest('surveys', [ 'title' => 'Test survey', 'description' => 'A test', ]); @@ -1399,7 +1453,7 @@ public function testJwtSurveyGet() { * A basic test of /surveys GET. */ public function testJwtSurveysGetList() { - $this->getListTest('surveys', [ + $this->getListTest('surveys', [ 'title' => 'Test survey ' . microtime(TRUE), 'description' => 'A test', ]); @@ -1409,7 +1463,7 @@ public function testJwtSurveysGetList() { * Test DELETE for a survey. */ public function testJwtSurveyDelete() { - $this->deleteTest('surveys', [ + $this->deleteTest('surveys', [ 'title' => 'Test survey', 'description' => 'A test', ]); @@ -1418,7 +1472,7 @@ public function testJwtSurveyDelete() { public function testJwtSurveyPostPermissions() { $this->authMethod = 'jwtUser'; self::$jwt = $this->getJwt(self::$privateKey, 'http://www.indicia.org.uk', 1, time() + 120); - $data = [ + $data = [ 'title' => 'Test survey', 'description' => 'A test', ]; @@ -1485,7 +1539,7 @@ public function testJwtSurveyOptions() { * Test behaviour around REST support for ETags. */ public function testJwtSurveyETags() { - $this->eTagsTest('surveys', [ + $this->eTagsTest('surveys', [ 'title' => 'Test survey', 'description' => 'A test', ]); @@ -1502,7 +1556,7 @@ public function testJwtSampleAttributePost() { * Test /sample_attributes PUT behaviour. */ public function testJwtSampleAttributePut() { - $this->putTest('sample_attributes', [ + $this->putTest('sample_attributes', [ 'caption' => 'Test sample attribute', 'data_type' => 'T', ], [ @@ -1514,7 +1568,7 @@ public function testJwtSampleAttributePut() { * A basic test of /sample_attributes GET. */ public function testJwtSampleAttributeGet() { - $this->getTest('sample_attributes', [ + $this->getTest('sample_attributes', [ 'caption' => 'Test sample attribute', 'data_type' => 'T', ]); @@ -1524,7 +1578,7 @@ public function testJwtSampleAttributeGet() { * A basic test of /sample_attributes GET. */ public function testJwtSampleAttributeGetList() { - $this->getListTest('sample_attributes', [ + $this->getListTest('sample_attributes', [ 'caption' => 'Test sample attribute ' . microtime(TRUE), 'data_type' => 'T', ]); @@ -1551,7 +1605,7 @@ public function testJwtSampleAttributeOptions() { * Test behaviour around REST support for ETags. */ public function testJwtSampleAttributeETags() { - $this->eTagsTest('sample_attributes', [ + $this->eTagsTest('sample_attributes', [ 'caption' => 'Test sample attribute', 'data_type' => 'T', ]); @@ -1568,7 +1622,7 @@ public function testJwtOccurrenceAttributePost() { * Test /occurrence_attributes PUT behaviour. */ public function testJwtOccurrenceAttributePut() { - $this->putTest('occurrence_attributes', [ + $this->putTest('occurrence_attributes', [ 'caption' => 'Test occurrence attribute', 'data_type' => 'T', ], [ @@ -1580,7 +1634,7 @@ public function testJwtOccurrenceAttributePut() { * A basic test of /occurrence_attributes GET. */ public function testJwtOccurrenceAttributeGet() { - $this->getTest('occurrence_attributes', [ + $this->getTest('occurrence_attributes', [ 'caption' => 'Test occurrence attribute', 'data_type' => 'T', ]); @@ -1617,7 +1671,7 @@ public function testJwtOccurrenceAttributeOptions() { * Test behaviour around REST support for ETags. */ public function testJwtOccurrenceAttributeETags() { - $this->eTagsTest('occurrence_attributes', [ + $this->eTagsTest('occurrence_attributes', [ 'caption' => 'Test occurrence attribute', 'data_type' => 'T', ]); @@ -1746,7 +1800,7 @@ public function testJwtOccurrencePost() { ], 'taxa_taxon_list_id'); } - /** + /** * Test /occurrences PUT in isolation. */ public function testJwtOccurrencePut() { @@ -1805,7 +1859,7 @@ public function testJwtOccurrenceOptions() { */ public function testJwtOccurrenceETags() { $sampleId = $this->postSampleToAddOccurrencesTo(); - $this->eTagsTest('occurrences', [ + $this->eTagsTest('occurrences', [ 'taxa_taxon_list_id' => 1, 'sample_id' => $sampleId, ]); @@ -1834,7 +1888,10 @@ public function testJwtOccurrencePostExtKey() { FALSE, ['values' => $data] ); - $this->assertEquals(409, $response['httpCode'], 'Duplicate external key did not return 409 Conflict response.'); + $this->assertEquals( + 409, $response['httpCode'], + 'Duplicate external key did not return 409 Conflict response.' + ); } /** @@ -1853,7 +1910,10 @@ public function testJwtOccurrencePostDeletedSample() { FALSE, ['values' => $data] ); - $this->assertEquals(400, $response['httpCode'], 'Adding occurrence to deleted sample did not return 400 Bad request response.'); + $this->assertEquals( + 400, $response['httpCode'], + 'Adding occurrence to deleted sample did not return 400 Bad request response.' + ); } public function testProjects_authentication() { @@ -1866,20 +1926,32 @@ public function testProjects_authentication() { // user and website authentications don't allow access to projects $this->authMethod = 'hmacUser'; $response = $this->callService('projects'); - $this->assertTrue($response['httpCode']===401, 'Invalid authentication method hmacUser for projects ' . - "but response still OK. Http response $response[httpCode]."); + $this->assertTrue( + $response['httpCode'] === 401, + 'Invalid authentication method hmacUser for projects ' . + "but response still OK. Http response $response[httpCode]." + ); $this->authMethod = 'directUser'; $response = $this->callService('projects'); - $this->assertTrue($response['httpCode']===401, 'Invalid authentication method directUser for projects ' . - "but response still OK. Http response $response[httpCode]."); + $this->assertTrue( + $response['httpCode'] === 401, + 'Invalid authentication method directUser for projects ' . + "but response still OK. Http response $response[httpCode]." + ); $this->authMethod = 'hmacWebsite'; $response = $this->callService('projects'); - $this->assertTrue($response['httpCode']===401, 'Invalid authentication method hmacWebsite for projects ' . - "but response still OK. Http response $response[httpCode]."); + $this->assertTrue( + $response['httpCode'] === 401, + 'Invalid authentication method hmacWebsite for projects ' . + "but response still OK. Http response $response[httpCode]." + ); $this->authMethod = 'directWebsite'; $response = $this->callService('projects'); - $this->assertTrue($response['httpCode']===401, 'Invalid authentication method directWebsite for projects ' . - "but response still OK. Http response $response[httpCode]."); + $this->assertTrue( + $response['httpCode'] === 401, + 'Invalid authentication method directWebsite for projects ' . + "but response still OK. Http response $response[httpCode]." + ); $this->authMethod = 'hmacClient'; } @@ -1893,14 +1965,23 @@ public function testProjects_get() { $this->assertEquals(count($viaConfig), count($response['response']['data']), 'Incorrect number of projects returned from /projects.'); foreach ($response['response']['data'] as $projDef) { - $this->assertArrayHasKey($projDef['id'], $viaConfig, "Unexpected project $projDef[id]returned by /projects."); + $this->assertArrayHasKey( + $projDef['id'], $viaConfig, + "Unexpected project $projDef[id]returned by /projects." + ); $this->assertEquals($viaConfig[$projDef['id']]['title'], $projDef['title'], "Unexpected title $projDef[title] returned for project $projDef[id] by /projects."); $this->assertEquals($viaConfig[$projDef['id']]['description'], $projDef['description'], "Unexpected description $projDef[description] returned for project $projDef[id] by /projects."); - // Some project keys are supposed to be removed - $this->assertNotContains('filter_id', $projDef, 'Project definition should not contain filter_id'); - $this->assertNotContains('sharing', $projDef, 'Project definition should not contain sharing'); + // Some project keys are supposed to be removed. + $this->assertNotContains( + 'filter_id', $projDef, + 'Project definition should not contain filter_id' + ); + $this->assertNotContains( + 'sharing', $projDef, + 'Project definition should not contain sharing' + ); } } @@ -1916,17 +1997,23 @@ public function testProjects_get_id() { $this->assertEquals($projDef['description'], $response['response']['description'], "Unexpected description " . $response['response']['description'] . " returned for project $projDef[id] by /projects/$projDef[id]."); - // Some project keys are supposed to be removed - $this->assertNotContains('filter_id', $projDef, 'Project definition should not contain filter_id'); - $this->assertNotContains('sharing', $projDef, 'Project definition should not contain sharing'); + // Some project keys are supposed to be removed. + $this->assertNotContains( + 'filter_id', $projDef, + 'Project definition should not contain filter_id' + ); + $this->assertNotContains( + 'sharing', $projDef, + 'Project definition should not contain sharing' + ); } } public function testTaxon_observations_authentication() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testProjects_clientAuthentication"); $proj_id = self::$config['projects'][array_keys(self::$config['projects'])[0]]['id']; - $queryWithProj = array('proj_id' => $proj_id, 'edited_date_from' => '2015-01-01'); - $query = array('edited_date_from' => '2015-01-01'); + $queryWithProj = ['proj_id' => $proj_id, 'edited_date_from' => '2015-01-01']; + $query = ['edited_date_from' => '2015-01-01']; $this->authMethod = 'hmacClient'; $this->checkResourceAuthentication('taxon-observations', $queryWithProj); @@ -1936,7 +2023,7 @@ public function testTaxon_observations_authentication() { $this->checkResourceAuthentication('taxon-observations', $query); // @todo The following test needs to check filtered response rather than authentication $this->authMethod = 'directUser'; - $this->checkResourceAuthentication('taxon-observations', $query + array('filter_id' => self::$userFilterId)); + $this->checkResourceAuthentication('taxon-observations', $query + ['filter_id' => self::$userFilterId]); $this->authMethod = 'hmacWebsite'; $this->checkResourceAuthentication('taxon-observations', $query); $this->authMethod = 'directWebsite'; @@ -1951,10 +2038,10 @@ public function testTaxon_observations_get_incorrect_params() { $this->assertEquals(400, $response['httpCode'], 'Requesting taxon observations without params should be a bad request'); foreach (self::$config['projects'] as $projDef) { - $response = $this->callService("taxon-observations", array('proj_id' => $projDef['id'])); + $response = $this->callService("taxon-observations", ['proj_id' => $projDef['id']]); $this->assertEquals(400, $response['httpCode'], 'Requesting taxon observations without edited_date_from should be a bad request'); - $response = $this->callService("taxon-observations", array('edited_date_from' => '2015-01-01')); + $response = $this->callService("taxon-observations", ['edited_date_from' => '2015-01-01']); $this->assertEquals(400, $response['httpCode'], 'Requesting taxon observations without proj_id should be a bad request'); // only test a single project @@ -1971,12 +2058,11 @@ public function testTaxon_observations_get() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testTaxon_observations_get"); foreach (self::$config['projects'] as $projDef) { - $response = $this->callService("taxon-observations", array( + $response = $this->callService("taxon-observations", [ 'proj_id' => $projDef['id'], 'edited_date_from' => '2015-01-01', 'edited_date_to' => date("Y-m-d\TH:i:s") - ) - ); + ]); $this->assertResponseOk($response, '/taxon-observations'); $this->assertArrayHasKey('paging', $response['response'], 'Paging missing from response to call to taxon-observations'); @@ -1985,9 +2071,10 @@ public function testTaxon_observations_get() { $data = $response['response']['data']; $this->assertIsArray($data, 'Taxon-observations data invalid. ' . var_export($data, true)); $this->assertNotCount(0, $data, 'Taxon-observations data absent. ' . var_export($data, true)); - foreach ($data as $occurrence) + foreach ($data as $occurrence) { $this->checkValidTaxonObservation($occurrence); - // only test a single project + } + // Only test a single project. break; } } @@ -2003,17 +2090,18 @@ public function testAnnotations_get() { foreach (self::$config['projects'] as $projDef) { $response = $this->callService( "annotations", - array('proj_id' => $projDef['id'], 'edited_date_from' => '2015-01-01') + ['proj_id' => $projDef['id'], 'edited_date_from' => '2015-01-01'] ); $this->assertResponseOk($response, '/annotations'); $this->assertArrayHasKey('paging', $response['response'], 'Paging missing from response to call to annotations'); $this->assertArrayHasKey('data', $response['response'], 'Data missing from response to call to annotations'); $data = $response['response']['data']; - $this->assertIsArray($data, 'Annotations data invalid. ' . var_export($data, true)); - $this->assertNotCount(0, $data, 'Annotations data absent. ' . var_export($data, true)); - foreach ($data as $annotation) + $this->assertIsArray($data, 'Annotations data invalid. ' . var_export($data, TRUE)); + $this->assertNotCount(0, $data, 'Annotations data absent. ' . var_export($data, TRUE)); + foreach ($data as $annotation) { $this->checkValidAnnotation($annotation); - // only test a single project + } + // Only test a single project. break; } } @@ -2034,8 +2122,14 @@ public function testTaxaSearch_get() { 'taxon_list_id' => 1, ]); $this->assertResponseOk($response, '/taxa/search'); - $this->assertArrayHasKey('paging', $response['response'], 'Paging missing from response to call to taxa/search'); - $this->assertArrayHasKey('data', $response['response'], 'Data missing from response to call to taxa/search'); + $this->assertArrayHasKey( + 'paging', $response['response'], + 'Paging missing from response to call to taxa/search' + ); + $this->assertArrayHasKey( + 'data', $response['response'], + 'Data missing from response to call to taxa/search' + ); $data = $response['response']['data']; $this->assertIsArray($data, 'taxa/search data invalid.'); $this->assertCount(2, $data, 'Taxa/search data wrong count returned.'); @@ -2044,8 +2138,14 @@ public function testTaxaSearch_get() { 'taxon_list_id' => 1, ]); $this->assertResponseOk($response, '/taxa/search'); - $this->assertArrayHasKey('paging', $response['response'], 'Paging missing from response to call to taxa/search'); - $this->assertArrayHasKey('data', $response['response'], 'Data missing from response to call to taxa/search'); + $this->assertArrayHasKey( + 'paging', $response['response'], + 'Paging missing from response to call to taxa/search' + ); + $this->assertArrayHasKey( + 'data', $response['response'], + 'Data missing from response to call to taxa/search' + ); $data = $response['response']['data']; $this->assertIsArray($data, 'taxa/search data invalid.'); $this->assertCount(1, $data, 'Taxa/search data wrong count returned.'); @@ -2071,7 +2171,7 @@ public function testReportsHierarchy_get() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testReportsHierarchy_get"); $projDef = self::$config['projects']['BRC1']; - $response = $this->callService("reports", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports'); // Check a folder that should definitely exist. $this->checkReportFolderInReponse($response['response'], 'library'); @@ -2082,19 +2182,19 @@ public function testReportsHierarchy_get() { // should be an additional featured folder at the top level with shortcuts // to favourite reports. $this->authMethod = 'hmacWebsite'; - $response = $this->callService("reports", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports", ['proj_id' => $projDef['id']]); $this->checkReportFolderInReponse($response['response'], 'featured'); $this->checkReportInReponse($response['response'], 'demo'); // now check some folder contents $this->authMethod = 'hmacClient'; - $response = $this->callService("reports/featured", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports/featured", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports/featured'); $this->checkReportInReponse($response['response'], 'library/occurrences/filterable_explore_list'); - $response = $this->callService("reports/library", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports/library", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports/library'); $this->checkReportFolderInReponse($response['response'], 'occurrences'); - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports/library/occurrences", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports/library/occurrences'); $this->checkReportInReponse($response['response'], 'filterable_explore_list'); } @@ -2103,15 +2203,19 @@ public function testMissingReportFile() { $this->authMethod = 'jwtUser'; self::$jwt = $this->getJwt(self::$privateKey, 'http://www.indicia.org.uk', 1, time() + 120); $response = $this->callService('reports/some_random_report_name.xml', []); - $this->assertEquals(404, $response['httpCode'], 'Request for a missing report does not return 404.'); + $this->assertEquals( + 404, $response['httpCode'], + 'Request for a missing report does not return 404.' + ); } public function testReportParams_get() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testReportParams_get"); - // First grab a list of reports so we can use the links to get the correct params URL + // First grab a list of reports so we can use the links to get the correct + // params URL. $projDef = self::$config['projects']['BRC1']; - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports/library/occurrences", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports/library/occurrences'); $reportDef = $response['response']['filterable_explore_list']; $this->assertArrayHasKey('params', $reportDef, 'Report response does not define parameters'); @@ -2127,9 +2231,10 @@ public function testReportParams_get() { public function testReportColumns_get() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testReportColumns_get"); - // First grab a list of reports so we can use the links to get the correct columns URL + // First grab a list of reports so we can use the links to get the correct + // columns URL. $projDef = self::$config['projects']['BRC1']; - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports/library/occurrences", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports/library/occurrences'); $reportDef = $response['response']['filterable_explore_list']; $this->assertArrayHasKey('columns', $reportDef, 'Report response does not define columns'); @@ -2145,9 +2250,10 @@ public function testReportColumns_get() { public function testReportOutput_get() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testReportOutput_get"); - // First grab a list of reports so we can use the links to get the correct columns URL + // First grab a list of reports so we can use the links to get the correct + // columns URL. $projDef = self::$config['projects']['BRC1']; - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id'])); + $response = $this->callService("reports/library/occurrences", ['proj_id' => $projDef['id']]); $this->assertResponseOk($response, '/reports/library/occurrences'); $reportDef = $response['response']['filterable_explore_list']; $this->assertArrayHasKey('href', $reportDef, 'Report response missing href'); @@ -2156,34 +2262,57 @@ public function testReportOutput_get() { $this->assertResponseOk($response, '/reports/library/occurrences/filterable_explore_list.xml'); $this->assertArrayHasKey('data', $response['response']); $this->assertCount(1, $response['response']['data'], 'Report call returns incorrect record count'); - $this->assertEquals(1, $response['response']['data'][0]['occurrence_id'], 'Report call returns incorrect record'); + $this->assertEquals( + 1, $response['response']['data'][0]['occurrence_id'], + 'Report call returns incorrect record' + ); } public function testAcceptHeader() { Kohana::log('debug', "Running unit test, Rest_ControllerTest::testAcceptHeader"); $projDef = self::$config['projects']['BRC1']; - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id']), NULL, ['Accept: application/json']); + $response = $this->callService( + "reports/library/occurrences", + ['proj_id' => $projDef['id']], + NULL, + ['Accept: application/json'] + ); $decoded = json_decode($response['response'], TRUE); $this->assertNotEquals(NULL, $decoded, 'JSON response could not be decoded: ' . $response['response']); $this->assertEquals(200, $response['httpCode']); $this->assertEquals(0, $response['curlErrno']); - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id']), NULL, ['Accept: text/html']); + $response = $this->callService( + "reports/library/occurrences", + ['proj_id' => $projDef['id']], + NULL, + ['Accept: text/html'] + ); $this->assertMatchesRegularExpression('/^/', $response['response']); $this->assertMatchesRegularExpression('//', $response['response']); $this->assertMatchesRegularExpression('/<\/html>$/', $response['response']); $this->assertEquals(200, $response['httpCode']); $this->assertEquals(0, $response['curlErrno']); - // try requesting an invalid content type as first preference - response should select the second. - $response = $this->callService("reports/library/occurrences", array('proj_id' => $projDef['id']), NULL, ['Accept: image/png, application/json']); + // Try requesting an invalid content type as first preference - response + // should select the second. + $response = $this->callService( + "reports/library/occurrences", + ['proj_id' => $projDef['id']], + NULL, + ['Accept: image/png, application/json'] + ); $decoded = json_decode($response['response'], TRUE); - $this->assertNotEquals(NULL, $decoded, 'JSON response could not be decoded: ' . $response['response']); + $this->assertNotEquals( + NULL, $decoded, + 'JSON response could not be decoded: ' . $response['response'] + ); $this->assertEquals(200, $response['httpCode']); $this->assertEquals(0, $response['curlErrno']); } /** - * Tests authentication against a resource, by passing incorrect user or secret, then - * finally passing the correct details to check a valid response returns. + * Tests authentication against a resource, by passing incorrect user or + * secret, then finally passing the correct details to check a valid response + * returns. * * @param $resource * @param string $user @@ -2210,11 +2339,16 @@ private function checkResourceAuthentication($resource, $query = []) { self::$userPassword = '---'; $response = $this->callService($resource, $query, TRUE); - $this->assertEquals(401, $response['httpCode'], - "Incorrect secret or password passed to /$resource but request authorised. Http response $response[httpCode]."); - $this->assertEquals('Unauthorized', $response['response']['status'], - "Incorrect secret or password passed to /$resource but data still returned. ". - var_export($response, true)); + $this->assertEquals( + 401, $response['httpCode'], + "Incorrect secret or password passed to /$resource but request " . + "authorised. Http response $response[httpCode]." + ); + $this->assertEquals( + 'Unauthorized', $response['response']['status'], + "Incorrect secret or password passed to /$resource but data still returned. " . + var_export($response, TRUE) + ); self::$config['shared_secret'] = $correctClientSecret; self::$websitePassword = $correctWebsitePassword; self::$userPassword = $correctUserPassword; @@ -2227,10 +2361,16 @@ private function checkResourceAuthentication($resource, $query = []) { self::$websitePassword = $correctWebsitePassword; self::$userPassword = $correctUserPassword; $response = $this->callService($resource, $query, TRUE); - $this->assertEquals(401, $response['httpCode'], - "Incorrect userId passed to /$resource but request authorised. Http response $response[httpCode]."); - $this->assertEquals('Unauthorized', $response['response']['status'], - "Incorrect userId passed to /$resource but data still returned. " . var_export($response, true)); + $this->assertEquals( + 401, $response['httpCode'], + "Incorrect userId passed to /$resource but request authorised. Http " . + "response $response[httpCode]." + ); + $this->assertEquals( + 'Unauthorized', $response['response']['status'], + "Incorrect userId passed to /$resource but data still returned. " . + var_export($response, TRUE) + ); // Now test with everything correct. self::$clientUserId = $correctClientUserId; @@ -2266,14 +2406,14 @@ private function assertResponseOk($response, $apiCall) { * @param $data Array to be tested as a taxon occurrence resource */ private function checkValidTaxonObservation($data) { - $this->assertIsArray($data, 'Taxon-observation object invalid. ' . var_export($data, true)); - $mustHave = array('id', 'href', 'datasetName', 'taxonVersionKey', 'taxonName', - 'startDate', 'endDate', 'dateType', 'projection', 'precision', 'recorder', 'lastEditDate'); + $this->assertIsArray($data, 'Taxon-observation object invalid. ' . var_export($data, TRUE)); + $mustHave = ['id', 'href', 'datasetName', 'taxonVersionKey', 'taxonName', + 'startDate', 'endDate', 'dateType', 'projection', 'precision', 'recorder', 'lastEditDate']; foreach ($mustHave as $key) { $this->assertArrayHasKey($key, $data, - "Missing $key from taxon-observation resource. " . var_export($data, true)); + "Missing $key from taxon-observation resource. " . var_export($data, TRUE)); $this->assertNotEmpty($data[$key], - "Empty $key in taxon-observation resource" . var_export($data, true)); + "Empty $key in taxon-observation resource" . var_export($data, TRUE)); } // @todo Format tests } @@ -2283,19 +2423,27 @@ private function checkValidTaxonObservation($data) { * @param $data Array to be tested as an annotation resource */ private function checkValidAnnotation($data) { - $this->assertIsArray($data, 'Annotation object invalid. ' . var_export($data, true)); - $mustHave = array('id', 'href', 'taxonObservation', 'taxonVersionKey', 'comment', - 'question', 'authorName', 'dateTime'); + $this->assertIsArray($data, 'Annotation object invalid. ' . var_export($data, TRUE)); + $mustHave = ['id', 'href', 'taxonObservation', 'taxonVersionKey', 'comment', + 'question', 'authorName', 'dateTime']; foreach ($mustHave as $key) { $this->assertArrayHasKey($key, $data, - "Missing $key from annotation resource. " . var_export($data, true)); + "Missing $key from annotation resource. " . var_export($data, TRUE)); $this->assertNotEmpty($data[$key], - "Empty $key in annotation resource" . var_export($data, true)); + "Empty $key in annotation resource" . var_export($data, TRUE)); + } + if (!empty($data['statusCode1'])) { + $this->assertMatchesRegularExpression( + '/[AUN]/', $data['statusCode1'], + 'Invalid statusCode1 value for annotation' + ); + } + if (!empty($data['statusCode2'])) { + $this->assertMatchesRegularExpression( + '/[1-6]/', $data['statusCode2'], + 'Invalid statusCode2 value for annotation' + ); } - if (!empty($data['statusCode1'])) - $this->assertMatchesRegularExpression('/[AUN]/', $data['statusCode1'], 'Invalid statusCode1 value for annotation'); - if (!empty($data['statusCode2'])) - $this->assertMatchesRegularExpression('/[1-6]/', $data['statusCode2'], 'Invalid statusCode2 value for annotation'); // We should be able to request the taxon observation associated with the occurrence $session = $this->initCurl($data['taxonObservation']['href']); $response = $this->getCurlResponse($session); @@ -2317,7 +2465,7 @@ private function checkReportFolderInReponse($response, $folder) { /** * Assert that a folder exists in the response from a call to /reports. * @param array $response - * @param string $folder + * @param string $reportFile */ private function checkReportInReponse($response, $reportFile) { $this->assertArrayHasKey($reportFile, $response); @@ -2331,6 +2479,7 @@ private function checkReportInReponse($response, $reportFile) { * * @param $session * @param $url + * @param additionalRequestHeader */ private function setRequestHeader($session, $url, $additionalRequestHeader = []) { switch ($this->authMethod) { @@ -2476,6 +2625,9 @@ private function callUrl($url, $postData = NULL, $additionalRequestHeader = [], * @param $method * @param mixed|FALSE $query * @param string $postData + * @param $additionalRequestHeader + * @param $customMethod + * @param $files * @return array */ private function callService($method, $query = FALSE, $postData = NULL, $additionalRequestHeader = [], $customMethod = NULL, $files = FALSE) { diff --git a/modules/taxon_associations/tests/TaxonAssocations_ServicesTest.php b/modules/taxon_associations/tests/TaxonAssocations_ServicesTest.php index 75b81c2cd8..2e5c2165c8 100644 --- a/modules/taxon_associations/tests/TaxonAssocations_ServicesTest.php +++ b/modules/taxon_associations/tests/TaxonAssocations_ServicesTest.php @@ -3,9 +3,9 @@ require_once 'client_helpers/data_entry_helper.php'; require_once 'client_helpers/submission_builder.php'; -define ('CORE_FIXTURE_TERMLIST_COUNT', 4); -define ('CORE_FIXTURE_TERM_COUNT', 5); -define ('CORE_FIXTURE_TERMLISTS_TERM_COUNT', 5); +define('CORE_FIXTURE_TERMLIST_COUNT', 4); +define('CORE_FIXTURE_TERM_COUNT', 5); +define('CORE_FIXTURE_TERMLISTS_TERM_COUNT', 5); class TaxonAssociations_ServicesTest extends Indicia_DatabaseTestCase { @@ -13,16 +13,16 @@ class TaxonAssociations_ServicesTest extends Indicia_DatabaseTestCase { public function getDataSet() { - $ds1 = new PHPUnit_Extensions_Database_DataSet_YamlDataSet('modules/phpUnit/config/core_fixture.yaml'); + $ds1 = new PHPUnit_Extensions_Database_DataSet_YamlDataSet('modules/phpUnit/config/core_fixture.yaml'); $ds2 = new Indicia_ArrayDataSet( - array( - 'meanings' => array( - array( - 'id' => 20000 - ) - ), - 'termlists' => array( - array( + [ + 'meanings' => [ + [ + 'id' => 20000, + ], + ], + 'termlists' => [ + [ 'title' => 'Taxon association types', 'description' => 'Types of associations between taxa', 'website_id' => 1, @@ -30,21 +30,21 @@ public function getDataSet() 'created_by_id' => 1, 'updated_on' => '2016-07-22:16:00:00', 'updated_by_id' => 1, - 'external_key' => NULL - ), - ), - 'terms' => array( - array( + 'external_key' => NULL, + ], + ], + 'terms' => [ + [ 'term' => 'is associated with', 'language_id' => 1, 'created_on' => '2016-07-22:16:00:00', 'created_by_id' => 1, 'updated_on' => '2016-07-22:16:00:00', - 'updated_by_id' => 1 - ), - ), - 'termlists_terms' => array( - array( + 'updated_by_id' => 1, + ], + ], + 'termlists_terms' => [ + [ 'termlist_id' => CORE_FIXTURE_TERMLIST_COUNT + 1, 'term_id' => CORE_FIXTURE_TERM_COUNT + 1, 'created_on' => '2016-07-22:16:00:00', @@ -52,11 +52,11 @@ public function getDataSet() 'updated_on' => '2016-07-22:16:00:00', 'updated_by_id' => 1, 'meaning_id' => 20000, - 'preferred' => true, - 'sort_order' => 1 - ), - ), - ) + 'preferred' => TRUE, + 'sort_order' => 1, + ], + ], + ] ); $compositeDs = new PHPUnit_Extensions_Database_DataSet_CompositeDataSet(); @@ -67,20 +67,30 @@ public function getDataSet() public function setup() { $this->auth = data_entry_helper::get_read_write_auth(1, 'password'); - // make the tokens re-usable - $this->auth['write_tokens']['persist_auth']=true; + // Make the tokens re-usable. + $this->auth['write_tokens']['persist_auth'] = true; parent::setup(); } function testPost() { - $array = array( + $array = [ 'taxon_association:from_taxon_meaning_id' => 10000, 'taxon_association:to_taxon_meaning_id' => 10001, 'taxon_association:association_type_id' => CORE_FIXTURE_TERMLISTS_TERM_COUNT + 1, + ]; + $s = submission_builder::build_submission( + $array, ['model' => 'taxon_association'] + ); + $r = data_entry_helper::forward_post_to( + 'taxon_association', $s, $this->auth['write_tokens'] + ); + Kohana::log( + 'debug', + "Submission response to taxon_association save " . print_r($r, TRUE) + ); + $this->assertTrue( + isset($r['success']), + 'Submitting a taxon_association did not return success response' ); - $s = submission_builder::build_submission($array, array('model' => 'taxon_association')); - $r = data_entry_helper::forward_post_to('taxon_association', $s, $this->auth['write_tokens']); - Kohana::log('debug', "Submission response to taxon_association save " . print_r($r, TRUE)); - $this->assertTrue(isset($r['success']), 'Submitting a taxon_association did not return success response'); } } \ No newline at end of file diff --git a/system/core/utf8.php b/system/core/utf8.php index 9f20f421c7..61f6933aa9 100644 --- a/system/core/utf8.php +++ b/system/core/utf8.php @@ -49,7 +49,8 @@ ); } -if (extension_loaded('mbstring') AND (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING)) +// Function overloading was deprecated in PHP 7.2 and removed in PHP 8.0. +if (extension_loaded('mbstring') AND defined('MB_OVERLOAD_STRING') AND (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING)) { trigger_error ( diff --git a/system/libraries/drivers/Database/Pgsql.php b/system/libraries/drivers/Database/Pgsql.php index 0731e6eb1c..3a09101cf0 100644 --- a/system/libraries/drivers/Database/Pgsql.php +++ b/system/libraries/drivers/Database/Pgsql.php @@ -326,7 +326,7 @@ class Pgsql_Result extends Database_Result { * @param boolean return objects or arrays * @param string SQL query that was run */ - public function __construct($result, $link, $object = TRUE, $sql) + public function __construct($result, $link, $object, $sql) { $this->link = $link; $this->result = $result; @@ -453,10 +453,12 @@ public function insert_id() $ER = error_reporting(0); $result = pg_query($this->link, $query); - $insert_id = pg_fetch_array($result, NULL, PGSQL_ASSOC); - - $this->insert_id = $insert_id['insert_id']; - + // $result is false when tables have no serial column. + if ($result !== false) { + $insert_id = pg_fetch_array($result, NULL, PGSQL_ASSOC); + $this->insert_id = $insert_id['insert_id']; + } + // Reset error reporting error_reporting($ER); } diff --git a/system/vendor/swift/Swift/Connection/SMTP.php b/system/vendor/swift/Swift/Connection/SMTP.php index a16f0306c1..393261b8ae 100644 --- a/system/vendor/swift/Swift/Connection/SMTP.php +++ b/system/vendor/swift/Swift/Connection/SMTP.php @@ -253,7 +253,7 @@ public function read() $this->smtpErrors()); } $ret .= trim($tmp) . "\r\n"; - if ($tmp{3} == " ") break; + if ($tmp[3] == " ") break; } return $ret = substr($ret, 0, -2); } @@ -385,7 +385,7 @@ public function runAuthenticators($user, $pass, Swift $swift) foreach ($this->authenticators as $name => $obj) { //Server supports this authentication mechanism - if (in_array($name, $this->getAttributes("AUTH")) || $name{0} == "*") + if (in_array($name, $this->getAttributes("AUTH")) || $name[0] == "*") { $tried++; if ($log->hasLevel(Swift_Log::LOG_EVERYTHING))