From 2b93819ae3ad57d624d8a0c6000c7fe36ca9f825 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Wed, 28 Mar 2018 20:17:10 +0200 Subject: [PATCH 001/236] 3.6.1 changelog (1st draft) --- CHANGELOG | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index cc7eedfff..7e552370d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,34 @@ +Version 3.6.1 (2018-03-xx) + Friendica Core: + Update to the translations (DE, PL, ZN CH) [translation teams] + Update to the documentation [annando, rudloff, tobiasd] + Enhancements to the DB handling [annando] + Enhancements to the relais system [annando] + Enhancements to the handling of URL that contain unicode characters [annando] + Enhancements to the Vagrant VM configuration [fabrixxm] + Enhancementa to the Babel module [MrPetovan] + Fixed a bug in the relocation process of a Friendica instance [annando] + Fixed a bug in the shell wrapper for the console [MrPetovan] + Fixed a bug with the console tool po2php [MrPetovan] + Fixed a bug in the ACL [annando, MrPetovan] + Fixed a bug that prevented the deletion of contact groups [annando] + Fixed wrong version of a dependency preventing the usage of PHP 5.6 [MrPetovan] + Added preloading config adampter [MrPetovan] + Added memcached support [MrPetovan] + Added password exposure check [MrPetovan] + Added a console to unify the PHP utility scripts [MrPetovan] + Added hashtag autocompletion [rabuzarus] + Added feedtest module [MrPetovan] + The execute-ables were moved from /util to /bin [MrPetovan] + General code refactoring and beautification work [annando, MrPetovan] + + Friendica Addons: + Updates to the translations (NL, PL, ZH CN) [translation teams] + NSFW: add hashtag only hiding [MrPetovan] + + Closed Issues: + 4601, 4616, 4647, 4660, 4661, 4663, 4664, 4665, 4666, 4669, 4670 + Version 3.6 (2018-03-23) Friendica Core: Updates to the translations (DE, EN_GB, EN_US, ES, FR, IT, ZH_CN) [translation teams] From 27c09b445e357a4a48290897f4a980e650f9d713 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Thu, 29 Mar 2018 06:23:28 +0200 Subject: [PATCH 002/236] typo --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7e552370d..b727bb392 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,7 +3,7 @@ Version 3.6.1 (2018-03-xx) Update to the translations (DE, PL, ZN CH) [translation teams] Update to the documentation [annando, rudloff, tobiasd] Enhancements to the DB handling [annando] - Enhancements to the relais system [annando] + Enhancements to the relay system [annando] Enhancements to the handling of URL that contain unicode characters [annando] Enhancements to the Vagrant VM configuration [fabrixxm] Enhancementa to the Babel module [MrPetovan] From 535a9838fc21e47fca904ff84bb1307e5ae8037d Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Thu, 29 Mar 2018 12:42:55 +0200 Subject: [PATCH 003/236] 3rd draft --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b727bb392..39ad32094 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,7 +5,7 @@ Version 3.6.1 (2018-03-xx) Enhancements to the DB handling [annando] Enhancements to the relay system [annando] Enhancements to the handling of URL that contain unicode characters [annando] - Enhancements to the Vagrant VM configuration [fabrixxm] + Enhancements to the Vagrant VM configuration [fabrixxm, tobiasd] Enhancementa to the Babel module [MrPetovan] Fixed a bug in the relocation process of a Friendica instance [annando] Fixed a bug in the shell wrapper for the console [MrPetovan] From 7a46bbbd3af25298aca37be09a8a98bae76b202b Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Fri, 30 Mar 2018 08:22:08 +0200 Subject: [PATCH 004/236] 4th draft --- CHANGELOG | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 39ad32094..59f9244ab 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ Version 3.6.1 (2018-03-xx) Enhancements to the handling of URL that contain unicode characters [annando] Enhancements to the Vagrant VM configuration [fabrixxm, tobiasd] Enhancementa to the Babel module [MrPetovan] + Enhancements to the display it the [code] elements [MrPetovan] Fixed a bug in the relocation process of a Friendica instance [annando] Fixed a bug in the shell wrapper for the console [MrPetovan] Fixed a bug with the console tool po2php [MrPetovan] @@ -21,13 +22,15 @@ Version 3.6.1 (2018-03-xx) Added feedtest module [MrPetovan] The execute-ables were moved from /util to /bin [MrPetovan] General code refactoring and beautification work [annando, MrPetovan] + Switced to cropperjs to better support touch screen devices [rabuzarus] Friendica Addons: Updates to the translations (NL, PL, ZH CN) [translation teams] NSFW: add hashtag only hiding [MrPetovan] Closed Issues: - 4601, 4616, 4647, 4660, 4661, 4663, 4664, 4665, 4666, 4669, 4670 + 4572, 4601, 4616, 4647, 4660, 4661, 4663, 4664, 4665, 4666, 4669 + 4670 Version 3.6 (2018-03-23) Friendica Core: From 8ea37a9d0bc4136d6b72a1cffa4a7b2f19b59d8c Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Sat, 31 Mar 2018 08:44:25 +0200 Subject: [PATCH 005/236] 5th draft --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 59f9244ab..405430163 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,10 +11,12 @@ Version 3.6.1 (2018-03-xx) Fixed a bug in the relocation process of a Friendica instance [annando] Fixed a bug in the shell wrapper for the console [MrPetovan] Fixed a bug with the console tool po2php [MrPetovan] + Fixed a bug with the console tool blockaccounts [MrPetovan] Fixed a bug in the ACL [annando, MrPetovan] Fixed a bug that prevented the deletion of contact groups [annando] Fixed wrong version of a dependency preventing the usage of PHP 5.6 [MrPetovan] Added preloading config adampter [MrPetovan] + Added a tool to set user passwords to the console [annando] Added memcached support [MrPetovan] Added password exposure check [MrPetovan] Added a console to unify the PHP utility scripts [MrPetovan] From 23371880e8f76b8b89b8bf8c694f9559a79c387e Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 24 Apr 2018 16:16:57 +0200 Subject: [PATCH 006/236] $called_api should always be an array In order to avoid a PHP 7.2 error when using count() --- include/api.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/api.php b/include/api.php index 72997dd3a..f0120684c 100644 --- a/include/api.php +++ b/include/api.php @@ -54,7 +54,7 @@ define('API_METHOD_POST', 'POST,PUT'); define('API_METHOD_DELETE', 'POST,DELETE'); $API = []; -$called_api = null; +$called_api = []; /** * It is not sufficient to use local_user() to check whether someone is allowed to use the API, @@ -2200,7 +2200,7 @@ function api_statuses_repeat($type) } // this should output the last post (the one we just posted). - $called_api = null; + $called_api = []; return api_status_show($type); } From 9bb11ccfa5ddd8e614be18b0c5b217d66cfae4a0 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 24 Apr 2018 16:22:29 +0200 Subject: [PATCH 007/236] $attachments should aways be an array In order to avoid a PHP 7.2 error when using count() --- include/api.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/api.php b/include/api.php index f0120684c..ebf48c9b7 100644 --- a/include/api.php +++ b/include/api.php @@ -2716,7 +2716,7 @@ function api_convert_item($item) * * @param string $body * - * @return array|false + * @return array */ function api_get_attachments(&$body) { @@ -2727,7 +2727,7 @@ function api_get_attachments(&$body) $ret = preg_match_all("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $text, $images); if (!$ret) { - return false; + return []; } $attachments = []; From f66cb9b0a3f46b481a8fc99559fd7f6f074254da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Wed, 25 Jan 2017 15:59:27 +0100 Subject: [PATCH 008/236] added more curly braces + a bit more usage of dbm::is_result() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- src/Protocol/DFRN.php | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index b66e1d5bf..913097d1d 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -63,7 +63,7 @@ class DFRN * @param array $owner Owner record * * @return string DFRN entries - * @todo Add type-hints + * @todo Find proper type-hints */ public static function entries($items, $owner) { @@ -96,6 +96,7 @@ class DFRN * @param boolean $onlyheader Output only the header without content? (Default is "no") * * @return string DFRN feed entries + * @todo Find proper type-hints */ public static function feed($dfrn_id, $owner_nick, $last_update, $direction = 0, $onlyheader = false) { @@ -120,8 +121,6 @@ class DFRN } } - - // default permissions - anonymous user $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; @@ -134,6 +133,8 @@ class DFRN ); if (! DBM::is_result($r)) { + if (! dbm::is_result($r)) { + logger(sprintf('No contact found for nickname=%d', $owner_nick), LOGGER_WARNING); killme(); } @@ -169,6 +170,7 @@ class DFRN ); if (! DBM::is_result($r)) { + logger(sprintf('No contact found for uid=%d', $owner_id), LOGGER_WARNING); killme(); } @@ -177,8 +179,9 @@ class DFRN $groups = Group::getIdsByContactId($contact['id']); if (count($groups)) { - for ($x = 0; $x < count($groups); $x ++) + for ($x = 0; $x < count($groups); $x ++) { $groups[$x] = '<' . intval($groups[$x]) . '>' ; + } $gs = implode('|', $groups); } else { $gs = '<<>>' ; // Impossible to match @@ -397,7 +400,7 @@ class DFRN * @param array $owner Owner record * * @return string DFRN mail - * @todo Add type-hints + * @todo Find proper type-hints */ public static function mail($item, $owner) { @@ -433,7 +436,7 @@ class DFRN * @param array $owner Owner record * * @return string DFRN suggestions - * @todo Add type-hints + * @todo Find proper type-hints */ public static function fsuggest($item, $owner) { @@ -462,7 +465,7 @@ class DFRN * @param int $uid User ID * * @return string DFRN relocations - * @todo Add type-hints + * @todo Find proper type-hints */ public static function relocate($owner, $uid) { @@ -524,7 +527,7 @@ class DFRN * @param bool $public Is it a header for public posts? * * @return object XML root object - * @todo Add type-hints + * @todo Find proper type-hints */ private static function addHeader($doc, $owner, $authorelement, $alternatelink = "", $public = false) { @@ -600,7 +603,7 @@ class DFRN * @param boolean $public boolean * * @return object XML author object - * @todo Add type-hints + * @todo Find proper type-hints */ private static function addAuthor($doc, $owner, $authorelement, $public) { @@ -744,7 +747,7 @@ class DFRN * @param array $item Item elements * * @return object XML author object - * @todo Add type-hints + * @todo Find proper type-hints */ private static function addEntryAuthor($doc, $element, $contact_url, $item) { @@ -785,7 +788,7 @@ class DFRN * @param string $activity activity value * * @return object XML activity object - * @todo Add type-hints + * @todo Find proper type-hints */ private static function createActivity($doc, $element, $activity) { @@ -796,12 +799,15 @@ class DFRN if (!$r) { return false; } + if ($r->type) { XML::addElement($doc, $entry, "activity:object-type", $r->type); } + if ($r->id) { XML::addElement($doc, $entry, "id", $r->id); } + if ($r->title) { XML::addElement($doc, $entry, "title", $r->title); } @@ -848,7 +854,7 @@ class DFRN * @param array $item Item element * * @return object XML attachment object - * @todo Add type-hints + * @todo Find proper type-hints */ private static function getAttachment($doc, $root, $item) { @@ -888,7 +894,7 @@ class DFRN * @param bool $single If set, the entry is created as an XML document with a single "entry" element * * @return object XML entry object - * @todo Add type-hints + * @todo Find proper type-hints */ private static function entry($doc, $type, $item, $owner, $comment = false, $cid = 0, $single = false) { @@ -1289,7 +1295,6 @@ class DFRN $postvars['dissolve'] = '1'; } - if ((($contact['rel']) && ($contact['rel'] != CONTACT_IS_SHARING) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { $postvars['data'] = $atom; $postvars['perm'] = 'rw'; From cf9fa51f2f12d969f3c45c22649268b70d2cf7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Thu, 26 Jan 2017 09:38:52 +0100 Subject: [PATCH 009/236] Continued: - added missing space/curly braces - added TODOs for later adding a lot type-hints, without these (and they are long time around in PHP) anything can be handled over to the method/function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- src/Protocol/DFRN.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 913097d1d..c464c14c2 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1581,7 +1581,7 @@ class DFRN $href = ""; $width = 0; foreach ($avatar->attributes as $attributes) { - /// @TODO Rewrite these similar if () to one switch + /// @TODO Rewrite these similar if() to one switch if ($attributes->name == "href") { $href = $attributes->textContent; } @@ -2801,6 +2801,7 @@ class DFRN { logger("Processing deletions"); $uri = null; + foreach ($deletion->attributes as $attributes) { if ($attributes->name == "ref") { $uri = $attributes->textContent; From 5debcbb5a6c7d82b5429e411e1fc3ecfce191f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Thu, 26 Jan 2017 15:23:30 +0100 Subject: [PATCH 010/236] added spaces + some curly braces + some usage of dbm::is_result() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- mod/_well_known.php | 5 +++-- mod/admin.php | 1 + mod/events.php | 1 + mod/poco.php | 2 +- mod/share.php | 17 +++++++++-------- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/mod/_well_known.php b/mod/_well_known.php index 782dc7a1b..89097c0ff 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -43,7 +43,8 @@ function wk_social_relay() $tags = []; if ($scope == SR_SCOPE_TAGS) { - $server_tags = Config::get('system', 'relay_server_tags'); + + $server_tags = get_config('system', 'relay_server_tags'); $tagitems = explode(",", $server_tags); /// @todo Check if it was better to use "strtolower" on the tags @@ -52,7 +53,7 @@ function wk_social_relay() $tags[$tag] = $tag; } - if (Config::get('system', 'relay_user_tags')) { + if (get_config('system', 'relay_user_tags')) { $terms = q("SELECT DISTINCT(`term`) FROM `search`"); foreach ($terms AS $term) { diff --git a/mod/admin.php b/mod/admin.php index 1447dbaf1..39416dae5 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -2162,6 +2162,7 @@ function admin_page_themes(App $a) } $readme = null; + if (is_file("view/theme/$theme/README.md")) { $readme = Markdown::convert(file_get_contents("view/theme/$theme/README.md"), false); } elseif (is_file("view/theme/$theme/README")) { diff --git a/mod/events.php b/mod/events.php index cad440f16..bbd6337c3 100644 --- a/mod/events.php +++ b/mod/events.php @@ -433,6 +433,7 @@ function events_content(App $a) { if (x($_REQUEST, 'location')) {$orig_event['location'] = $_REQUEST['location'];} if (x($_REQUEST, 'start')) {$orig_event['start'] = $_REQUEST['start'];} if (x($_REQUEST, 'finish')) {$orig_event['finish'] = $_REQUEST['finish'];} + if (x($_REQUEST,'finish')) $orig_event['finish'] = $_REQUEST['finish']; $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : ''); $a_checked = ((x($orig_event) && $orig_event['adjust']) ? ' checked="checked" ' : ''); diff --git a/mod/poco.php b/mod/poco.php index 0728020ec..183d7acd1 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -43,8 +43,8 @@ function poco_init(App $a) { echo json_encode($ret); killme(); } + if ($a->argc > 1 && $a->argv[1] === '@global') { - // List of all profiles that this server recently had data from $global = true; $update_limit = date(DateTimeFormat::MYSQL, time() - 30 * 86400); } diff --git a/mod/share.php b/mod/share.php index f67dd3d20..ed9b5f9d1 100644 --- a/mod/share.php +++ b/mod/share.php @@ -23,10 +23,11 @@ function share_init(App $a) { } else { $o = share_header($r[0]['author-name'], $r[0]['author-link'], $r[0]['author-avatar'], $r[0]['guid'], $r[0]['created'], $r[0]['plink']); - if ($r[0]['title']) + if ($r[0]['title']) { $o .= '[b]'.$r[0]['title'].'[/b]'."\n"; + } $o .= $r[0]['body']; - $o.= "[/share]"; + $o .= "[/share]"; } echo $o; @@ -34,17 +35,17 @@ function share_init(App $a) { } function share_header($author, $profile, $avatar, $guid, $posted, $link) { - $header = "[share author='".str_replace(["'", "[", "]"], ["'", "[", "]"], $author). - "' profile='".str_replace(["'", "[", "]"], ["'", "[", "]"], $profile). - "' avatar='".str_replace(["'", "[", "]"], ["'", "[", "]"], $avatar); + $header = "[share author='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $author). + "' profile='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $profile). + "' avatar='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $avatar); if ($guid) { - $header .= "' guid='".str_replace(["'", "[", "]"], ["'", "[", "]"], $guid); + $header .= "' guid='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $guid); } if ($posted) { - $header .= "' posted='".str_replace(["'", "[", "]"], ["'", "[", "]"], $posted); + $header .= "' posted='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $posted); } - $header .= "' link='".str_replace(["'", "[", "]"], ["'", "[", "]"], $link)."']"; + $header .= "' link='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $link)."']"; return $header; } From 3195d6e125fddbb219a8bde13b588fcafc5fd821 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Mon, 9 Apr 2018 21:23:41 +0200 Subject: [PATCH 011/236] Add API tests --- .travis.yml | 12 +- composer.json | 11 +- composer.lock | 1379 +++++++++++++- doc/Tests.md | 18 + include/dba.php | 9 + phpunit.xml | 2 +- tests/ApiTest.php | 3669 ++++++++++++++++++++++++++++++++++++++ tests/BaseObjectTest.php | 8 +- tests/DatabaseTest.php | 60 + tests/TextTest.php | 7 +- tests/bootstrap.php | 22 + tests/datasets/api.yml | 160 ++ 12 files changed, 5342 insertions(+), 15 deletions(-) create mode 100644 doc/Tests.md create mode 100644 tests/ApiTest.php create mode 100644 tests/DatabaseTest.php create mode 100644 tests/bootstrap.php create mode 100644 tests/datasets/api.yml diff --git a/.travis.yml b/.travis.yml index d68b7727e..82b5a5d21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,14 @@ php: - 7.1 - 7.2 -install: composer install +services: + - mysql +env: + - USER=travis DB=test + +install: + - composer install +before_script: + - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' + # In order to avoid bin/worker.php warnings + - touch .htconfig.php diff --git a/composer.json b/composer.json index b7cd645bd..9668b9341 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,8 @@ ], "autoload": { "psr-4": { - "Friendica\\": "src/" + "Friendica\\": "src/", + "Friendica\\Test\\": "tests/" }, "psr-0": { "": "library/" @@ -68,5 +69,13 @@ "exclude": [ "log", "cache", "/photo", "/proxy" ] + }, + "require-dev": { + "phpunit/dbunit": "^2.0", + "phpdocumentor/reflection-docblock": "^3.0.2", + "phpunit/php-token-stream": "^1.4.2" + }, + "scripts": { + "test": "phpunit" } } diff --git a/composer.lock b/composer.lock index f294c16ef..dd2665ebb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "f97245142e60a521f048a667bec4e436", + "content-hash": "ab5a551aff0505691c4836d063fc5171", "packages": [ { "name": "asika/simple-console", @@ -2090,7 +2090,1382 @@ "time": "2016-12-14T21:57:25+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-11-10T14:09:06+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2018-04-18T13:57:24+00:00" + }, + { + "name": "phpunit/dbunit", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/dbunit.git", + "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/5c35d74549c21ba55d0ea74ba89d191a51f8cf25", + "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "ext-simplexml": "*", + "php": "^5.4 || ^7.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0", + "symfony/yaml": "^2.1 || ^3.0" + }, + "bin": [ + "dbunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.", + "homepage": "https://github.com/sebastianbergmann/dbunit/", + "keywords": [ + "database", + "testing", + "xunit" + ], + "time": "2016-12-02T14:39:14+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.2 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "^1.0 || ^2.0" + }, + "require-dev": { + "ext-xdebug": "^2.1.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-xdebug": "^2.5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2017-04-02T07:44:40+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-12-04T08:55:13+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "5.7.27", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.6.2", + "phpunit/php-code-coverage": "^4.0.4", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "^1.2.4", + "sebastian/diff": "^1.4.3", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "^1.1", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "^1.0.6|^2.0.1", + "symfony/yaml": "~2.1|~3.0|~4.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2018-02-01T05:50:59+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2017-06-30T09:13:00+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-11-26T07:53:53+00:00" + }, + { + "name": "sebastian/exporter", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-11-19T08:54:04+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-02-18T15:18:39+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-11-19T07:33:16+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2018-04-03T05:14:20+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-01-29T19:49:41+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": { diff --git a/doc/Tests.md b/doc/Tests.md new file mode 100644 index 000000000..6acb4e783 --- /dev/null +++ b/doc/Tests.md @@ -0,0 +1,18 @@ +# Themes + +* [Home](help) + +You can run unit tests with [PHPUnit](https://phpunit.de/): + +```bash +phpunit +``` + +Some tests require access to a MySQL database. +You can specify the database credentials in environment variables: + +```bash +USER=database_user PASS=database_password DB=database_name phpunit +``` + +**Warning**: This will empty all the tables! Never use this on a production database. diff --git a/include/dba.php b/include/dba.php index 1d3b43214..53d7041a5 100644 --- a/include/dba.php +++ b/include/dba.php @@ -102,6 +102,15 @@ class dba { return self::$connected; } + /** + * Return the database object. + * @return PDO|mysqli + */ + public static function get_db() + { + return self::$db; + } + /** * @brief Returns the MySQL server version string * diff --git a/phpunit.xml b/phpunit.xml index 6a275ad3f..b2d978aee 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,5 @@ - + tests/ diff --git a/tests/ApiTest.php b/tests/ApiTest.php new file mode 100644 index 000000000..f0e27b4af --- /dev/null +++ b/tests/ApiTest.php @@ -0,0 +1,3669 @@ +selfUser = [ + 'id' => 42, + 'name' => 'Self contact', + 'nick' => 'selfcontact', + 'nurl' => 'http://localhost/profile/selfcontact' + ]; + $this->otherUser = [ + 'id' => 43, + 'name' => 'othercontact', + 'nick' => 'othercontact', + 'nurl' => 'http://localhost/profile/othercontact' + ]; + + // User ID that we know is not in the database + $this->wrongUserId = 666; + + // Most API require login so we force the session + $_SESSION = [ + 'allow_api' => true, + 'authenticated' => true, + 'uid' => $this->selfUser['id'] + ]; + + // Reusable App object + $this->app = new App(__DIR__.'/../'); + $a = $this->app; + + // Default config + Config::set('config', 'hostname', 'localhost'); + Config::set('system', 'throttle_limit_day', 100); + Config::set('system', 'throttle_limit_week', 100); + Config::set('system', 'throttle_limit_month', 100); + Config::set('system', 'theme', 'system_theme'); + } + + /** + * Assert that an user array contains expected keys. + * @param array $user User array + * @return void + */ + private function assertSelfUser(array $user) + { + $this->assertEquals($this->selfUser['id'], $user['uid']); + $this->assertEquals($this->selfUser['id'], $user['cid']); + $this->assertEquals(1, $user['self']); + $this->assertEquals('Friendica', $user['location']); + $this->assertEquals($this->selfUser['name'], $user['name']); + $this->assertEquals($this->selfUser['nick'], $user['screen_name']); + $this->assertEquals('dfrn', $user['network']); + $this->assertTrue($user['verified']); + } + + /** + * Assert that an user array contains expected keys. + * @param array $user User array + * @return void + */ + private function assertOtherUser(array $user) + { + $this->assertEquals($this->otherUser['id'], $user['id']); + $this->assertEquals($this->otherUser['id'], $user['id_str']); + $this->assertEquals(0, $user['self']); + $this->assertEquals($this->otherUser['name'], $user['name']); + $this->assertEquals($this->otherUser['nick'], $user['screen_name']); + $this->assertFalse($user['verified']); + } + + /** + * Assert that a status array contains expected keys. + * @param array $status Status array + * @return void + */ + private function assertStatus(array $status) + { + $this->assertInternalType('string', $status['text']); + $this->assertInternalType('int', $status['id']); + // We could probably do more checks here. + } + + /** + * Assert that a list array contains expected keys. + * @param array $list List array + * @return void + */ + private function assertList(array $list) + { + $this->assertInternalType('string', $list['name']); + $this->assertInternalType('int', $list['id']); + $this->assertInternalType('string', $list['id_str']); + $this->assertContains($list['mode'], ['public', 'private']); + // We could probably do more checks here. + } + + /** + * Assert that the string is XML and contain the root element. + * @param string $result XML string + * @param string $root_element Root element name + * @return void + */ + private function assertXml($result, $root_element) + { + $this->assertStringStartsWith('', $result); + $this->assertContains('<'.$root_element, $result); + // We could probably do more checks here. + } + + /** + * Get the path to a temporary empty PNG image. + * @return string Path + */ + private function getTempImage() + { + $tmpFile = tempnam(sys_get_temp_dir(), 'tmp_file'); + file_put_contents( + $tmpFile, + base64_decode( + // Empty 1x1 px PNG image + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==' + ) + ); + + return $tmpFile; + } + + /** + * Test the api_user() function. + * @return void + */ + public function testApiUser() + { + $this->assertEquals($this->selfUser['id'], api_user()); + } + + /** + * Test the api_user() function with an unallowed user. + * @return void + */ + public function testApiUserWithUnallowedUser() + { + $_SESSION = ['allow_api' => false]; + $this->assertEquals(false, api_user()); + } + + /** + * Test the api_source() function. + * @return void + */ + public function testApiSource() + { + $this->assertEquals('api', api_source()); + } + + /** + * Test the api_source() function with a Twidere user agent. + * @return void + */ + public function testApiSourceWithTwidere() + { + $_SERVER['HTTP_USER_AGENT'] = 'Twidere'; + $this->assertEquals('Twidere', api_source()); + } + + /** + * Test the api_source() function with a GET parameter. + * @return void + */ + public function testApiSourceWithGet() + { + $_GET['source'] = 'source_name'; + $this->assertEquals('source_name', api_source()); + } + + /** + * Test the api_date() function. + * @return void + */ + public function testApiDate() + { + $this->assertEquals('Wed Oct 10 00:00:00 +0000 1990', api_date('1990-10-10')); + } + + /** + * Test the api_register_func() function. + * @return void + */ + public function testApiRegisterFunc() + { + global $API; + $this->assertNull( + api_register_func( + 'api_path', + function () { + }, + true, + 'method' + ) + ); + $this->assertTrue($API['api_path']['auth']); + $this->assertEquals('method', $API['api_path']['method']); + $this->assertTrue(is_callable($API['api_path']['func'])); + } + + /** + * Test the api_login() function without any login. + * @return void + * @runInSeparateProcess + * @expectedException Friendica\Network\HTTPException\UnauthorizedException + */ + public function testApiLoginWithoutLogin() + { + api_login($this->app); + } + + /** + * Test the api_login() function with a bad login. + * @return void + * @runInSeparateProcess + * @expectedException Friendica\Network\HTTPException\UnauthorizedException + */ + public function testApiLoginWithBadLogin() + { + $_SERVER['PHP_AUTH_USER'] = 'user@server'; + api_login($this->app); + } + + /** + * Test the api_login() function with oAuth. + * @return void + */ + public function testApiLoginWithOauth() + { + $this->markTestIncomplete('Can we test this easily?'); + } + + /** + * Test the api_login() function with authentication provided by an addon. + * @return void + */ + public function testApiLoginWithAddonAuth() + { + $this->markTestIncomplete('Can we test this easily?'); + } + + /** + * Test the api_login() function with a correct login. + * @return void + * @runInSeparateProcess + */ + public function testApiLoginWithCorrectLogin() + { + $_SERVER['PHP_AUTH_USER'] = 'Test user'; + $_SERVER['PHP_AUTH_PW'] = 'password'; + api_login($this->app); + } + + /** + * Test the api_login() function with a remote user. + * @return void + * @runInSeparateProcess + * @expectedException Friendica\Network\HTTPException\UnauthorizedException + */ + public function testApiLoginWithRemoteUser() + { + $_SERVER['REDIRECT_REMOTE_USER'] = '123456dXNlcjpwYXNzd29yZA=='; + api_login($this->app); + } + + /** + * Test the api_check_method() function. + * @return void + */ + public function testApiCheckMethod() + { + $this->assertFalse(api_check_method('method')); + } + + /** + * Test the api_check_method() function with a correct method. + * @return void + */ + public function testApiCheckMethodWithCorrectMethod() + { + $_SERVER['REQUEST_METHOD'] = 'method'; + $this->assertTrue(api_check_method('method')); + } + + /** + * Test the api_check_method() function with a wildcard. + * @return void + */ + public function testApiCheckMethodWithWildcard() + { + $this->assertTrue(api_check_method('*')); + } + + /** + * Test the api_call() function. + * @return void + * @runInSeparateProcess + */ + public function testApiCall() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return ['data' => ['some_data']]; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + $_GET['callback'] = 'callback_name'; + + $this->app->query_string = 'api_path'; + $this->assertEquals( + 'callback_name(["some_data"])', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with the profiled enabled. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithProfiler() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return ['data' => ['some_data']]; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + Config::set('system', 'profiler', true); + Config::set('rendertime', 'callstack', true); + $this->app->callstack = [ + 'database' => ['some_function' => 200], + 'database_write' => ['some_function' => 200], + 'cache' => ['some_function' => 200], + 'cache_write' => ['some_function' => 200], + 'network' => ['some_function' => 200] + ]; + + $this->app->query_string = 'api_path'; + $this->assertEquals( + '["some_data"]', + api_call($this->app) + ); + } + + /** + * Test the api_call() function without any result. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithNoResult() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return false; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + + $this->app->query_string = 'api_path'; + $this->assertEquals( + '{"status":{"error":"Internal Server Error","code":"500 Internal Server Error","request":"api_path"}}', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with an unimplemented API. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithUninplementedApi() + { + $this->assertEquals( + '{"status":{"error":"Not Implemented","code":"501 Not Implemented","request":""}}', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with a JSON result. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithJson() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return ['data' => ['some_data']]; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + + $this->app->query_string = 'api_path.json'; + $this->assertEquals( + '["some_data"]', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with an XML result. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithXml() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return 'some_data'; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + + $this->app->query_string = 'api_path.xml'; + $this->assertEquals( + 'some_data', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with an RSS result. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithRss() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return 'some_data'; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + + $this->app->query_string = 'api_path.rss'; + $this->assertEquals( + ''.PHP_EOL. + 'some_data', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with an Atom result. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithAtom() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'func' => function () { + return 'some_data'; + } + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + + $this->app->query_string = 'api_path.atom'; + $this->assertEquals( + ''.PHP_EOL. + 'some_data', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with an unallowed method. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithWrongMethod() + { + global $API; + $API['api_path'] = ['method' => 'method']; + + $this->app->query_string = 'api_path'; + $this->assertEquals( + '{"status":{"error":"Method Not Allowed","code":"405 Method Not Allowed","request":"api_path"}}', + api_call($this->app) + ); + } + + /** + * Test the api_call() function with an unauthorized user. + * @return void + * @runInSeparateProcess + */ + public function testApiCallWithWrongAuth() + { + global $API; + $API['api_path'] = [ + 'method' => 'method', + 'auth' => true + ]; + $_SERVER['REQUEST_METHOD'] = 'method'; + $_SESSION['authenticated'] = false; + + $this->app->query_string = 'api_path'; + $this->assertEquals( + '{"status":{"error":"This API requires login","code":"401 Unauthorized","request":"api_path"}}', + api_call($this->app) + ); + } + + /** + * Test the api_error() function with a JSON result. + * @return void + * @runInSeparateProcess + */ + public function testApiErrorWithJson() + { + $this->assertEquals( + '{"status":{"error":"error_message","code":"200 Friendica\\\\Network\\\\HTTP","request":""}}', + api_error('json', new HTTPException('error_message')) + ); + } + + /** + * Test the api_error() function with an XML result. + * @return void + * @runInSeparateProcess + */ + public function testApiErrorWithXml() + { + $this->assertEquals( + ''.PHP_EOL. + ''.PHP_EOL. + ' error_message'.PHP_EOL. + ' 200 Friendica\Network\HTTP'.PHP_EOL. + ' '.PHP_EOL. + ''.PHP_EOL, + api_error('xml', new HTTPException('error_message')) + ); + } + + /** + * Test the api_error() function with an RSS result. + * @return void + * @runInSeparateProcess + */ + public function testApiErrorWithRss() + { + $this->assertEquals( + ''.PHP_EOL. + ''.PHP_EOL. + ' error_message'.PHP_EOL. + ' 200 Friendica\Network\HTTP'.PHP_EOL. + ' '.PHP_EOL. + ''.PHP_EOL, + api_error('rss', new HTTPException('error_message')) + ); + } + + /** + * Test the api_error() function with an Atom result. + * @return void + * @runInSeparateProcess + */ + public function testApiErrorWithAtom() + { + $this->assertEquals( + ''.PHP_EOL. + ''.PHP_EOL. + ' error_message'.PHP_EOL. + ' 200 Friendica\Network\HTTP'.PHP_EOL. + ' '.PHP_EOL. + ''.PHP_EOL, + api_error('atom', new HTTPException('error_message')) + ); + } + + /** + * Test the api_rss_extra() function. + * @return void + */ + public function testApiRssExtra() + { + $user_info = ['url' => 'user_url']; + $result = api_rss_extra($this->app, [], $user_info); + $this->assertEquals($user_info, $result['$user']); + $this->assertEquals($user_info['url'], $result['$rss']['alternate']); + $this->assertArrayHasKey('self', $result['$rss']); + $this->assertArrayHasKey('base', $result['$rss']); + $this->assertArrayHasKey('updated', $result['$rss']); + $this->assertArrayHasKey('atom_updated', $result['$rss']); + $this->assertArrayHasKey('language', $result['$rss']); + $this->assertArrayHasKey('logo', $result['$rss']); + } + + /** + * Test the api_rss_extra() function without any user info. + * @return void + * @runInSeparateProcess + */ + public function testApiRssExtraWithoutUserInfo() + { + $result = api_rss_extra($this->app, [], null); + $this->assertInternalType('array', $result['$user']); + $this->assertArrayHasKey('alternate', $result['$rss']); + $this->assertArrayHasKey('self', $result['$rss']); + $this->assertArrayHasKey('base', $result['$rss']); + $this->assertArrayHasKey('updated', $result['$rss']); + $this->assertArrayHasKey('atom_updated', $result['$rss']); + $this->assertArrayHasKey('language', $result['$rss']); + $this->assertArrayHasKey('logo', $result['$rss']); + } + + /** + * Test the api_unique_id_to_nurl() function. + * @return void + */ + public function testApiUniqueIdToNurl() + { + $this->assertFalse(api_unique_id_to_nurl($this->wrongUserId)); + } + + /** + * Test the api_unique_id_to_nurl() function with a correct ID. + * @return void + */ + public function testApiUniqueIdToNurlWithCorrectId() + { + $this->assertEquals($this->otherUser['nurl'], api_unique_id_to_nurl($this->otherUser['id'])); + } + + /** + * Test the api_get_user() function. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUser() + { + $user = api_get_user($this->app); + $this->assertSelfUser($user); + $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']); + $this->assertEquals('6fdbe8', $user['profile_link_color']); + $this->assertEquals('ededed', $user['profile_background_color']); + } + + /** + * Test the api_get_user() function with a Frio schema. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithFrioSchema() + { + PConfig::set($this->selfUser['id'], 'frio', 'schema', 'red'); + $user = api_get_user($this->app); + $this->assertSelfUser($user); + $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']); + $this->assertEquals('6fdbe8', $user['profile_link_color']); + $this->assertEquals('ededed', $user['profile_background_color']); + } + + /** + * Test the api_get_user() function with a custom Frio schema. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithCustomFrioSchema() + { + PConfig::set($this->selfUser['id'], 'frio', 'schema', '---'); + PConfig::set($this->selfUser['id'], 'frio', 'nav_bg', '#123456'); + PConfig::set($this->selfUser['id'], 'frio', 'link_color', '#123456'); + PConfig::set($this->selfUser['id'], 'frio', 'background_color', '#123456'); + $user = api_get_user($this->app); + $this->assertSelfUser($user); + $this->assertEquals('123456', $user['profile_sidebar_fill_color']); + $this->assertEquals('123456', $user['profile_link_color']); + $this->assertEquals('123456', $user['profile_background_color']); + } + + /** + * Test the api_get_user() function with an empty Frio schema. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithEmptyFrioSchema() + { + PConfig::set($this->selfUser['id'], 'frio', 'schema', '---'); + $user = api_get_user($this->app); + $this->assertSelfUser($user); + $this->assertEquals('708fa0', $user['profile_sidebar_fill_color']); + $this->assertEquals('6fdbe8', $user['profile_link_color']); + $this->assertEquals('ededed', $user['profile_background_color']); + } + + /** + * Test the api_get_user() function with an user that is not allowed to use the API. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithoutApiUser() + { + $_SERVER['PHP_AUTH_USER'] = 'Test user'; + $_SERVER['PHP_AUTH_PW'] = 'password'; + $_SESSION['allow_api'] = false; + $this->assertFalse(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with an user ID in a GET parameter. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithGetId() + { + $_GET['user_id'] = $this->otherUser['id']; + $this->assertOtherUser(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with a wrong user ID in a GET parameter. + * @return void + * @runInSeparateProcess + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiGetUserWithWrongGetId() + { + $_GET['user_id'] = $this->wrongUserId; + $this->assertOtherUser(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with an user name in a GET parameter. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithGetName() + { + $_GET['screen_name'] = $this->selfUser['nick']; + $this->assertSelfUser(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with a profile URL in a GET parameter. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithGetUrl() + { + $_GET['profileurl'] = $this->selfUser['nurl']; + $this->assertSelfUser(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with an user ID in the API path. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithNumericCalledApi() + { + global $called_api; + $called_api = ['api_path']; + $this->app->argv[1] = $this->otherUser['id'].'.json'; + $this->assertOtherUser(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with the $called_api global variable. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithCalledApi() + { + global $called_api; + $called_api = ['api_path']; + $this->assertSelfUser(api_get_user($this->app)); + } + + /** + * Test the api_get_user() function with a valid user. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithCorrectUser() + { + $this->assertOtherUser(api_get_user($this->app, $this->otherUser['id'])); + } + + /** + * Test the api_get_user() function with a wrong user ID. + * @return void + * @runInSeparateProcess + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiGetUserWithWrongUser() + { + $this->assertOtherUser(api_get_user($this->app, $this->wrongUserId)); + } + + /** + * Test the api_get_user() function with a 0 user ID. + * @return void + * @runInSeparateProcess + */ + public function testApiGetUserWithZeroUser() + { + $this->assertSelfUser(api_get_user($this->app, 0)); + } + + + /** + * Test the api_item_get_user() function. + * @return void + * @runInSeparateProcess + */ + public function testApiItemGetUser() + { + $users = api_item_get_user($this->app, []); + $this->assertSelfUser($users[0]); + } + + /** + * Test the api_item_get_user() function with a different item parent. + * @return void + */ + public function testApiItemGetUserWithDifferentParent() + { + $users = api_item_get_user($this->app, ['thr-parent' => 'item_parent', 'uri' => 'item_uri']); + $this->assertSelfUser($users[0]); + $this->assertEquals($users[0], $users[1]); + } + + /** + * Test the api_walk_recursive() function. + * @return void + */ + public function testApiWalkRecursive() + { + $array = ['item1']; + $this->assertEquals( + $array, + api_walk_recursive( + $array, + function () { + // Should we test this with a callback that actually does something? + return true; + } + ) + ); + } + + /** + * Test the api_walk_recursive() function with an array. + * @return void + */ + public function testApiWalkRecursiveWithArray() + { + $array = [['item1'], ['item2']]; + $this->assertEquals( + $array, + api_walk_recursive( + $array, + function () { + // Should we test this with a callback that actually does something? + return true; + } + ) + ); + } + + /** + * Test the api_reformat_xml() function. + * @return void + */ + public function testApiReformatXml() + { + $item = true; + $key = ''; + $this->assertTrue(api_reformat_xml($item, $key)); + $this->assertEquals('true', $item); + } + + /** + * Test the api_reformat_xml() function with a statusnet_api key. + * @return void + */ + public function testApiReformatXmlWithStatusnetKey() + { + $item = ''; + $key = 'statusnet_api'; + $this->assertTrue(api_reformat_xml($item, $key)); + $this->assertEquals('statusnet:api', $key); + } + + /** + * Test the api_reformat_xml() function with a friendica_api key. + * @return void + */ + public function testApiReformatXmlWithFriendicaKey() + { + $item = ''; + $key = 'friendica_api'; + $this->assertTrue(api_reformat_xml($item, $key)); + $this->assertEquals('friendica:api', $key); + } + + /** + * Test the api_create_xml() function. + * @return void + */ + public function testApiCreateXml() + { + $this->assertEquals( + ''.PHP_EOL. + ''.PHP_EOL. + ' some_data'.PHP_EOL. + ''.PHP_EOL, + api_create_xml(['data' => ['some_data']], 'root_element') + ); + } + + /** + * Test the api_create_xml() function without any XML namespace. + * @return void + */ + public function testApiCreateXmlWithoutNamespaces() + { + $this->assertEquals( + ''.PHP_EOL. + ''.PHP_EOL. + ' some_data'.PHP_EOL. + ''.PHP_EOL, + api_create_xml(['data' => ['some_data']], 'ok') + ); + } + + /** + * Test the api_format_data() function. + * @return void + */ + public function testApiFormatData() + { + $data = ['some_data']; + $this->assertEquals($data, api_format_data('root_element', 'json', $data)); + } + + /** + * Test the api_format_data() function with an XML result. + * @return void + */ + public function testApiFormatDataWithXml() + { + $this->assertEquals( + ''.PHP_EOL. + ''.PHP_EOL. + ' some_data'.PHP_EOL. + ''.PHP_EOL, + api_format_data('root_element', 'xml', ['data' => ['some_data']]) + ); + } + + /** + * Test the api_account_verify_credentials() function. + * @return void + */ + public function testApiAccountVerifyCredentials() + { + $this->assertArrayHasKey('user', api_account_verify_credentials('json')); + } + + /** + * Test the api_account_verify_credentials() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiAccountVerifyCredentialsWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_account_verify_credentials('json'); + } + + /** + * Test the requestdata() function. + * @return void + */ + public function testRequestdata() + { + $this->assertNull(requestdata('variable_name')); + } + + /** + * Test the requestdata() function with a POST parameter. + * @return void + */ + public function testRequestdataWithPost() + { + $_POST['variable_name'] = 'variable_value'; + $this->assertEquals('variable_value', requestdata('variable_name')); + } + + /** + * Test the requestdata() function with a GET parameter. + * @return void + */ + public function testRequestdataWithGet() + { + $_GET['variable_name'] = 'variable_value'; + $this->assertEquals('variable_value', requestdata('variable_name')); + } + + /** + * Test the api_statuses_mediap() function. + * @return void + */ + public function testApiStatusesMediap() + { + $this->app->argc = 2; + + $_FILES = [ + 'media' => [ + 'id' => 666, + 'size' => 666, + 'width' => 666, + 'height' => 666, + 'tmp_name' => $this->getTempImage(), + 'type' => 'image/png' + ] + ]; + $_GET['status'] = 'Status content'; + + $result = api_statuses_mediap('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_statuses_mediap() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesMediapWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_statuses_mediap('json'); + } + + /** + * Test the api_statuses_update() function. + * @return void + */ + public function testApiStatusesUpdate() + { + $_GET['status'] = 'Status content'; + $_GET['in_reply_to_status_id'] = -1; + $_GET['lat'] = 48; + $_GET['long'] = 7; + $_FILES = [ + 'media' => [ + 'id' => 666, + 'size' => 666, + 'width' => 666, + 'height' => 666, + 'tmp_name' => $this->getTempImage(), + 'type' => 'image/png' + ] + ]; + + $result = api_statuses_update('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_statuses_update() function with an HTML status. + * @return void + */ + public function testApiStatusesUpdateWithHtml() + { + $_GET['htmlstatus'] = 'Status content'; + + $result = api_statuses_update('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_statuses_update() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesUpdateWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_statuses_update('json'); + } + + /** + * Test the api_statuses_update() function with a parent status. + * @return void + */ + public function testApiStatusesUpdateWithParent() + { + $this->markTestIncomplete('This triggers an exit() somewhere and kills PHPUnit.'); + } + + /** + * Test the api_statuses_update() function with a media_ids parameter. + * @return void + */ + public function testApiStatusesUpdateWithMediaIds() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_statuses_update() function with the throttle limit reached. + * @return void + */ + public function testApiStatusesUpdateWithDayThrottleReached() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_media_upload() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiMediaUpload() + { + api_media_upload(); + } + + /** + * Test the api_media_upload() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiMediaUploadWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_media_upload(); + } + + /** + * Test the api_media_upload() function with an invalid uploaded media. + * @return void + * @expectedException Friendica\Network\HTTPException\InternalServerErrorException + */ + public function testApiMediaUploadWithMedia() + { + $_FILES = [ + 'media' => [ + 'id' => 666 + ] + ]; + api_media_upload(); + } + + /** + * Test the api_media_upload() function with an valid uploaded media. + * @return void + */ + public function testApiMediaUploadWithValidMedia() + { + $_FILES = [ + 'media' => [ + 'id' => 666, + 'size' => 666, + 'width' => 666, + 'height' => 666, + 'tmp_name' => $this->getTempImage(), + 'type' => 'image/png' + ] + ]; + $app = get_app(); + $app->argc = 2; + + $result = api_media_upload(); + $this->assertEquals('image/png', $result['media']['image']['image_type']); + $this->assertEquals(1, $result['media']['image']['w']); + $this->assertEquals(1, $result['media']['image']['h']); + } + + /** + * Test the api_status_show() function. + * @return void + */ + public function testApiStatusShow() + { + $result = api_status_show('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_status_show() function with an XML result. + * @return void + */ + public function testApiStatusShowWithXml() + { + $result = api_status_show('xml'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_status_show() function with a raw result. + * @return void + */ + public function testApiStatusShowWithRaw() + { + $this->assertStatus(api_status_show('raw')); + } + + /** + * Test the api_users_show() function. + * @return void + */ + public function testApiUsersShow() + { + $result = api_users_show('json'); + // We can't use assertSelfUser() here because the user object is missing some properties. + $this->assertEquals($this->selfUser['id'], $result['user']['cid']); + $this->assertEquals('Friendica', $result['user']['location']); + $this->assertEquals($this->selfUser['name'], $result['user']['name']); + $this->assertEquals($this->selfUser['nick'], $result['user']['screen_name']); + $this->assertEquals('dfrn', $result['user']['network']); + $this->assertTrue($result['user']['verified']); + } + + /** + * Test the api_users_show() function with an XML result. + * @return void + */ + public function testApiUsersShowWithXml() + { + $result = api_users_show('xml'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_users_search() function. + * @return void + */ + public function testApiUsersSearch() + { + $_GET['q'] = 'othercontact'; + $result = api_users_search('json'); + $this->assertOtherUser($result['users'][0]); + } + + /** + * Test the api_users_search() function with an XML result. + * @return void + */ + public function testApiUsersSearchWithXml() + { + $_GET['q'] = 'othercontact'; + $result = api_users_search('xml'); + $this->assertXml($result, 'users'); + } + + /** + * Test the api_users_search() function without a GET q parameter. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiUsersSearchWithoutQuery() + { + api_users_search('json'); + } + + /** + * Test the api_users_lookup() function. + * @return void + * @expectedException Friendica\Network\HTTPException\NotFoundException + */ + public function testApiUsersLookup() + { + api_users_lookup('json'); + } + + /** + * Test the api_users_lookup() function with an user ID. + * @return void + */ + public function testApiUsersLookupWithUserId() + { + $_REQUEST['user_id'] = $this->otherUser['id']; + $result = api_users_lookup('json'); + $this->assertOtherUser($result['users'][0]); + } + + /** + * Test the api_search() function. + * @return void + */ + public function testApiSearch() + { + $_REQUEST['q'] = 'reply'; + $_REQUEST['max_id'] = 10; + $result = api_search('json'); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + $this->assertContains('reply', $status['text'], null, true); + } + } + + /** + * Test the api_search() function a count parameter. + * @return void + */ + public function testApiSearchWithCount() + { + $_REQUEST['q'] = 'reply'; + $_REQUEST['count'] = 20; + $result = api_search('json'); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + $this->assertContains('reply', $status['text'], null, true); + } + } + + /** + * Test the api_search() function with an rpp parameter. + * @return void + */ + public function testApiSearchWithRpp() + { + $_REQUEST['q'] = 'reply'; + $_REQUEST['rpp'] = 20; + $result = api_search('json'); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + $this->assertContains('reply', $status['text'], null, true); + } + } + + + /** + * Test the api_search() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiSearchWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_search('json'); + } + + /** + * Test the api_search() function without any GET query parameter. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiSearchWithoutQuery() + { + api_search('json'); + } + + /** + * Test the api_statuses_home_timeline() function. + * @return void + */ + public function testApiStatusesHomeTimeline() + { + $_REQUEST['max_id'] = 10; + $_REQUEST['exclude_replies'] = true; + $_REQUEST['conversation_id'] = 1; + $result = api_statuses_home_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_home_timeline() function with a negative page parameter. + * @return void + */ + public function testApiStatusesHomeTimelineWithNegativePage() + { + $_REQUEST['page'] = -2; + $result = api_statuses_home_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_home_timeline() with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesHomeTimelineWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_statuses_home_timeline('json'); + } + + /** + * Test the api_statuses_home_timeline() function with an RSS result. + * @return void + */ + public function testApiStatusesHomeTimelineWithRss() + { + $result = api_statuses_home_timeline('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_statuses_public_timeline() function. + * @return void + */ + public function testApiStatusesPublicTimeline() + { + $_REQUEST['max_id'] = 10; + $_REQUEST['conversation_id'] = 1; + $result = api_statuses_public_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_public_timeline() function with the exclude_replies parameter. + * @return void + */ + public function testApiStatusesPublicTimelineWithExcludeReplies() + { + $_REQUEST['max_id'] = 10; + $_REQUEST['exclude_replies'] = true; + $result = api_statuses_public_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_public_timeline() function with a negative page parameter. + * @return void + */ + public function testApiStatusesPublicTimelineWithNegativePage() + { + $_REQUEST['page'] = -2; + $result = api_statuses_public_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_public_timeline() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesPublicTimelineWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_statuses_public_timeline('json'); + } + + /** + * Test the api_statuses_public_timeline() function with an RSS result. + * @return void + */ + public function testApiStatusesPublicTimelineWithRss() + { + $result = api_statuses_public_timeline('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_statuses_networkpublic_timeline() function. + * @return void + */ + public function testApiStatusesNetworkpublicTimeline() + { + $_REQUEST['max_id'] = 10; + $result = api_statuses_networkpublic_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_networkpublic_timeline() function with a negative page parameter. + * @return void + */ + public function testApiStatusesNetworkpublicTimelineWithNegativePage() + { + $_REQUEST['page'] = -2; + $result = api_statuses_networkpublic_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_networkpublic_timeline() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesNetworkpublicTimelineWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_statuses_networkpublic_timeline('json'); + } + + /** + * Test the api_statuses_networkpublic_timeline() function with an RSS result. + * @return void + */ + public function testApiStatusesNetworkpublicTimelineWithRss() + { + $result = api_statuses_networkpublic_timeline('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_statuses_show() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiStatusesShow() + { + api_statuses_show('json'); + } + + /** + * Test the api_statuses_show() function with an ID. + * @return void + */ + public function testApiStatusesShowWithId() + { + $this->app->argv[3] = 1; + $result = api_statuses_show('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_statuses_show() function with the conversation parameter. + * @return void + */ + public function testApiStatusesShowWithConversation() + { + $this->app->argv[3] = 1; + $_REQUEST['conversation'] = 1; + $result = api_statuses_show('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_show() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesShowWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_statuses_show('json'); + } + + /** + * Test the api_conversation_show() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiConversationShow() + { + api_conversation_show('json'); + } + + /** + * Test the api_conversation_show() function with an ID. + * @return void + */ + public function testApiConversationShowWithId() + { + $this->app->argv[3] = 1; + $_REQUEST['max_id'] = 10; + $_REQUEST['page'] = -2; + $result = api_conversation_show('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_conversation_show() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiConversationShowWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_conversation_show('json'); + } + + /** + * Test the api_statuses_repeat() function. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesRepeat() + { + api_statuses_repeat('json'); + } + + /** + * Test the api_statuses_repeat() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesRepeatWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_statuses_repeat('json'); + } + + /** + * Test the api_statuses_repeat() function with an ID. + * @return void + */ + public function testApiStatusesRepeatWithId() + { + $this->app->argv[3] = 1; + $result = api_statuses_repeat('json'); + $this->assertStatus($result['status']); + + // Also test with a shared status + $this->app->argv[3] = 5; + $result = api_statuses_repeat('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_statuses_destroy() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiStatusesDestroy() + { + api_statuses_destroy('json'); + } + + /** + * Test the api_statuses_destroy() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesDestroyWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_statuses_destroy('json'); + } + + /** + * Test the api_statuses_destroy() function with an ID. + * @return void + */ + public function testApiStatusesDestroyWithId() + { + $this->app->argv[3] = 1; + $result = api_statuses_destroy('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_statuses_mentions() function. + * @return void + */ + public function testApiStatusesMentions() + { + $this->app->user = ['nickname' => $this->selfUser['nick']]; + $_REQUEST['max_id'] = 10; + $result = api_statuses_mentions('json'); + $this->assertEmpty($result['status']); + // We should test with mentions in the database. + } + + /** + * Test the api_statuses_mentions() function with a negative page parameter. + * @return void + */ + public function testApiStatusesMentionsWithNegativePage() + { + $_REQUEST['page'] = -2; + $result = api_statuses_mentions('json'); + $this->assertEmpty($result['status']); + } + + /** + * Test the api_statuses_mentions() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesMentionsWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_statuses_mentions('json'); + } + + /** + * Test the api_statuses_mentions() function with an RSS result. + * @return void + */ + public function testApiStatusesMentionsWithRss() + { + $result = api_statuses_mentions('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_statuses_user_timeline() function. + * @return void + */ + public function testApiStatusesUserTimeline() + { + $_REQUEST['max_id'] = 10; + $_REQUEST['exclude_replies'] = true; + $_REQUEST['conversation_id'] = 1; + $result = api_statuses_user_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_user_timeline() function with a negative page parameter. + * @return void + */ + public function testApiStatusesUserTimelineWithNegativePage() + { + $_REQUEST['page'] = -2; + $result = api_statuses_user_timeline('json'); + $this->assertNotEmpty($result['status']); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_statuses_user_timeline() function with an RSS result. + * @return void + */ + public function testApiStatusesUserTimelineWithRss() + { + $result = api_statuses_user_timeline('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_statuses_user_timeline() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiStatusesUserTimelineWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_statuses_user_timeline('json'); + } + + /** + * Test the api_favorites_create_destroy() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFavoritesCreateDestroy() + { + api_favorites_create_destroy('json'); + } + + /** + * Test the api_favorites_create_destroy() function with an invalid ID. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFavoritesCreateDestroyWithInvalidId() + { + // This triggers a very specific condition ($action_argv_id + 2) + $this->app->argv[1] = '1.1'; + $this->app->argc = 5; + api_favorites_create_destroy('json'); + } + + /** + * Test the api_favorites_create_destroy() function with an invalid action. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFavoritesCreateDestroyWithInvalidAction() + { + $this->app->argv[1] = '1.1'; + $this->app->argc = 10; + $_REQUEST['id'] = 1; + api_favorites_create_destroy('json'); + } + + /** + * Test the api_favorites_create_destroy() function with the create action. + * @return void + */ + public function testApiFavoritesCreateDestroyWithCreateAction() + { + $this->app->argv[1] = '1.1'; + $this->app->argv[3] = 'create'; + $this->app->argc = 10; + $_REQUEST['id'] = 1; + $result = api_favorites_create_destroy('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_favorites_create_destroy() function with the create action and an RSS result. + * @return void + */ + public function testApiFavoritesCreateDestroyWithCreateActionAndRss() + { + $this->app->argv[1] = '1.1'; + $this->app->argv[3] = 'create'; + $this->app->argc = 10; + $_REQUEST['id'] = 1; + $result = api_favorites_create_destroy('rss'); + $this->assertXml($result, 'status'); + } + + /** + * Test the api_favorites_create_destroy() function with the destroy action. + * @return void + */ + public function testApiFavoritesCreateDestroyWithDestroyAction() + { + $this->app->argv[1] = '1.1'; + $this->app->argv[3] = 'destroy'; + $this->app->argc = 10; + $_REQUEST['id'] = 1; + $result = api_favorites_create_destroy('json'); + $this->assertStatus($result['status']); + } + + /** + * Test the api_favorites_create_destroy() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFavoritesCreateDestroyWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_favorites_create_destroy('json'); + } + + /** + * Test the api_favorites() function. + * @return void + */ + public function testApiFavorites() + { + $_REQUEST['page'] = -1; + $_REQUEST['max_id'] = 10; + $result = api_favorites('json'); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_favorites() function with an RSS result. + * @return void + */ + public function testApiFavoritesWithRss() + { + $result = api_favorites('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_favorites() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFavoritesWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_favorites('json'); + } + + /** + * Test the api_format_messages() function. + * @return void + */ + public function testApiFormatMessages() + { + $result = api_format_messages( + ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], + ['id' => 2, 'screen_name' => 'recipient_name'], + ['id' => 3, 'screen_name' => 'sender_name'] + ); + $this->assertEquals('item_title'.PHP_EOL.'item_body', $result['text']); + $this->assertEquals(1, $result['id']); + $this->assertEquals(2, $result['recipient_id']); + $this->assertEquals(3, $result['sender_id']); + $this->assertEquals('recipient_name', $result['recipient_screen_name']); + $this->assertEquals('sender_name', $result['sender_screen_name']); + } + + /** + * Test the api_format_messages() function with HTML. + * @return void + */ + public function testApiFormatMessagesWithHtmlText() + { + $_GET['getText'] = 'html'; + $result = api_format_messages( + ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], + ['id' => 2, 'screen_name' => 'recipient_name'], + ['id' => 3, 'screen_name' => 'sender_name'] + ); + $this->assertEquals('item_title', $result['title']); + $this->assertEquals('item_body', $result['text']); + } + + /** + * Test the api_format_messages() function with plain text. + * @return void + */ + public function testApiFormatMessagesWithPlainText() + { + $_GET['getText'] = 'plain'; + $result = api_format_messages( + ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], + ['id' => 2, 'screen_name' => 'recipient_name'], + ['id' => 3, 'screen_name' => 'sender_name'] + ); + $this->assertEquals('item_title', $result['title']); + $this->assertEquals('item_body', $result['text']); + } + + /** + * Test the api_format_messages() function with the getUserObjects GET parameter set to false. + * @return void + */ + public function testApiFormatMessagesWithoutUserObjects() + { + $_GET['getUserObjects'] = 'false'; + $result = api_format_messages( + ['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], + ['id' => 2, 'screen_name' => 'recipient_name'], + ['id' => 3, 'screen_name' => 'sender_name'] + ); + $this->assertNull($result['sender']); + $this->assertNull($result['recipient']); + } + + /** + * Test the api_convert_item() function. + * @return void + */ + public function testApiConvertItem() + { + $result = api_convert_item( + [ + 'network' => 'feed', + 'title' => 'item_title', + // We need a long string to test that it is correctly cut + 'body' => 'perspiciatis impedit voluptatem quis molestiae ea qui '. + 'reiciendis dolorum aut ducimus sunt consequatur inventore dolor '. + 'officiis pariatur doloremque nemo culpa aut quidem qui dolore '. + 'laudantium atque commodi alias voluptatem non possimus aperiam '. + 'ipsum rerum consequuntur aut amet fugit quia aliquid praesentium '. + 'repellendus quibusdam et et inventore mollitia rerum sit autem '. + 'pariatur maiores ipsum accusantium perferendis vel sit possimus '. + 'veritatis nihil distinctio qui eum repellat officia illum quos '. + 'impedit quam iste esse unde qui suscipit aut facilis ut inventore '. + 'omnis exercitationem quo magnam consequatur maxime aut illum '. + 'soluta quaerat natus unde aspernatur et sed beatae nihil ullam '. + 'temporibus corporis ratione blanditiis perspiciatis impedit '. + 'voluptatem quis molestiae ea qui reiciendis dolorum aut ducimus '. + 'sunt consequatur inventore dolor officiis pariatur doloremque '. + 'nemo culpa aut quidem qui dolore laudantium atque commodi alias '. + 'voluptatem non possimus aperiam ipsum rerum consequuntur aut '. + 'amet fugit quia aliquid praesentium repellendus quibusdam et et '. + 'inventore mollitia rerum sit autem pariatur maiores ipsum accusantium '. + 'perferendis vel sit possimus veritatis nihil distinctio qui eum '. + 'repellat officia illum quos impedit quam iste esse unde qui '. + 'suscipit aut facilis ut inventore omnis exercitationem quo magnam '. + 'consequatur maxime aut illum soluta quaerat natus unde aspernatur '. + 'et sed beatae nihil ullam temporibus corporis ratione blanditiis' + ] + ); + $this->assertStringStartsWith('item_title', $result['text']); + $this->assertStringStartsWith('

item_title


perspiciatis impedit voluptatem', $result['html']); + } + + /** + * Test the api_convert_item() function with an empty item body. + * @return void + */ + public function testApiConvertItemWithoutBody() + { + $result = api_convert_item( + [ + 'network' => 'feed', + 'title' => 'item_title', + 'body' => '', + 'plink' => 'item_plink' + ] + ); + $this->assertEquals('item_title', $result['text']); + $this->assertEquals('

item_title


item_plink', $result['html']); + } + + /** + * Test the api_convert_item() function with the title in the body. + * @return void + */ + public function testApiConvertItemWithTitleInBody() + { + $result = api_convert_item( + [ + 'title' => 'item_title', + 'body' => 'item_title item_body' + ] + ); + $this->assertEquals('item_title item_body', $result['text']); + $this->assertEquals('

item_title


item_title item_body', $result['html']); + } + + /** + * Test the api_get_attachments() function. + * @return void + */ + public function testApiGetAttachments() + { + $body = 'body'; + $this->assertEmpty(api_get_attachments($body)); + } + + /** + * Test the api_get_attachments() function with an img tag. + * @return void + */ + public function testApiGetAttachmentsWithImage() + { + $body = '[img]img_url[/img]'; + $this->assertInternalType('array', api_get_attachments($body)); + } + + /** + * Test the api_get_attachments() function with an img tag and an AndStatus user agent. + * @return void + */ + public function testApiGetAttachmentsWithImageAndAndStatus() + { + $_SERVER['HTTP_USER_AGENT'] = 'AndStatus'; + $body = '[img]img_url[/img]'; + $this->assertInternalType('array', api_get_attachments($body)); + } + + /** + * Test the api_get_entitities() function. + * @return void + */ + public function testApiGetEntitities() + { + $text = 'text'; + $this->assertInternalType('array', api_get_entitities($text, 'bbcode')); + } + + /** + * Test the api_get_entitities() function with the include_entities parameter. + * @return void + */ + public function testApiGetEntititiesWithIncludeEntities() + { + $_REQUEST['include_entities'] = 'true'; + $text = 'text'; + $result = api_get_entitities($text, 'bbcode'); + $this->assertInternalType('array', $result['hashtags']); + $this->assertInternalType('array', $result['symbols']); + $this->assertInternalType('array', $result['urls']); + $this->assertInternalType('array', $result['user_mentions']); + } + + /** + * Test the api_format_items_embeded_images() function. + * @return void + */ + public function testApiFormatItemsEmbededImages() + { + $this->assertEquals( + 'text http://localhost/display/item_guid', + api_format_items_embeded_images(['guid' => 'item_guid'], 'text data:image/foo') + ); + } + + /** + * Test the api_contactlink_to_array() function. + * @return void + */ + public function testApiContactlinkToArray() + { + $this->assertEquals( + [ + 'name' => 'text', + 'url' => '', + ], + api_contactlink_to_array('text') + ); + } + + /** + * Test the api_contactlink_to_array() function with an URL. + * @return void + */ + public function testApiContactlinkToArrayWithUrl() + { + $this->assertEquals( + [ + 'name' => ['link_text'], + 'url' => ['url'], + ], + api_contactlink_to_array('text link_text') + ); + } + + /** + * Test the api_format_items_activities() function. + * @return void + */ + public function testApiFormatItemsActivities() + { + $item = []; + $result = api_format_items_activities($item); + $this->assertArrayHasKey('like', $result); + $this->assertArrayHasKey('dislike', $result); + $this->assertArrayHasKey('attendyes', $result); + $this->assertArrayHasKey('attendno', $result); + $this->assertArrayHasKey('attendmaybe', $result); + } + + /** + * Test the api_format_items_activities() function with an XML result. + * @return void + */ + public function testApiFormatItemsActivitiesWithXml() + { + $item = []; + $result = api_format_items_activities($item, 'xml'); + $this->assertArrayHasKey('friendica:like', $result); + $this->assertArrayHasKey('friendica:dislike', $result); + $this->assertArrayHasKey('friendica:attendyes', $result); + $this->assertArrayHasKey('friendica:attendno', $result); + $this->assertArrayHasKey('friendica:attendmaybe', $result); + } + + /** + * Test the api_format_items_profiles() function. + * @return void + */ + public function testApiFormatItemsProfiles() + { + $profile_row = [ + 'id' => 'profile_id', + 'profile-name' => 'profile_name', + 'is-default' => true, + 'hide-friends' => true, + 'photo' => 'profile_photo', + 'thumb' => 'profile_thumb', + 'publish' => true, + 'net-publish' => true, + 'pdesc' => 'description', + 'dob' => 'date_of_birth', + 'address' => 'address', + 'locality' => 'city', + 'region' => 'region', + 'postal-code' => 'postal_code', + 'country-name' => 'country', + 'hometown' => 'hometown', + 'gender' => 'gender', + 'marital' => 'marital', + 'with' => 'marital_with', + 'howlong' => 'marital_since', + 'sexual' => 'sexual', + 'politic' => 'politic', + 'religion' => 'religion', + 'pub_keywords' => 'public_keywords', + 'prv_keywords' => 'private_keywords', + + 'likes' => 'likes', + 'dislikes' => 'dislikes', + 'about' => 'about', + 'music' => 'music', + 'book' => 'book', + 'tv' => 'tv', + 'film' => 'film', + 'interest' => 'interest', + 'romance' => 'romance', + 'work' => 'work', + 'education' => 'education', + 'contact' => 'social_networks', + 'homepage' => 'homepage' + ]; + $result = api_format_items_profiles($profile_row); + $this->assertEquals( + [ + 'profile_id' => 'profile_id', + 'profile_name' => 'profile_name', + 'is_default' => true, + 'hide_friends' => true, + 'profile_photo' => 'profile_photo', + 'profile_thumb' => 'profile_thumb', + 'publish' => true, + 'net_publish' => true, + 'description' => 'description', + 'date_of_birth' => 'date_of_birth', + 'address' => 'address', + 'city' => 'city', + 'region' => 'region', + 'postal_code' => 'postal_code', + 'country' => 'country', + 'hometown' => 'hometown', + 'gender' => 'gender', + 'marital' => 'marital', + 'marital_with' => 'marital_with', + 'marital_since' => 'marital_since', + 'sexual' => 'sexual', + 'politic' => 'politic', + 'religion' => 'religion', + 'public_keywords' => 'public_keywords', + 'private_keywords' => 'private_keywords', + + 'likes' => 'likes', + 'dislikes' => 'dislikes', + 'about' => 'about', + 'music' => 'music', + 'book' => 'book', + 'tv' => 'tv', + 'film' => 'film', + 'interest' => 'interest', + 'romance' => 'romance', + 'work' => 'work', + 'education' => 'education', + 'social_networks' => 'social_networks', + 'homepage' => 'homepage', + 'users' => null + ], + $result + ); + } + + /** + * Test the api_format_items() function. + * @return void + */ + public function testApiFormatItems() + { + $items = [ + [ + 'item_network' => 'item_network', + 'source' => 'web', + 'coord' => '5 7' + ] + ]; + $result = api_format_items($items, [], true); + foreach ($result as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_format_items() function with an XML result. + * @return void + */ + public function testApiFormatItemsWithXml() + { + $items = [ + [ + 'coord' => '5 7' + ] + ]; + $result = api_format_items($items, [], true, 'xml'); + foreach ($result as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_format_items() function. + * @return void + */ + public function testApiAccountRateLimitStatus() + { + $result = api_account_rate_limit_status('json'); + $this->assertEquals(150, $result['hash']['remaining_hits']); + $this->assertEquals(150, $result['hash']['hourly_limit']); + $this->assertInternalType('int', $result['hash']['reset_time_in_seconds']); + } + + /** + * Test the api_format_items() function with an XML result. + * @return void + */ + public function testApiAccountRateLimitStatusWithXml() + { + $result = api_account_rate_limit_status('xml'); + $this->assertXml($result, 'hash'); + } + + /** + * Test the api_help_test() function. + * @return void + */ + public function testApiHelpTest() + { + $result = api_help_test('json'); + $this->assertEquals(['ok' => 'ok'], $result); + } + + /** + * Test the api_help_test() function with an XML result. + * @return void + */ + public function testApiHelpTestWithXml() + { + $this->markTestIncomplete('Triggers this error: "key() expects parameter 1 to be array, string given"'); + $result = api_help_test('xml'); + $this->assertXml($result, 'ok'); + } + + /** + * Test the api_lists_list() function. + * @return void + */ + public function testApiListsList() + { + $result = api_lists_list('json'); + $this->assertEquals(['lists_list' => []], $result); + } + + /** + * Test the api_lists_ownerships() function. + * @return void + */ + public function testApiListsOwnerships() + { + $result = api_lists_ownerships('json'); + foreach ($result['lists']['lists'] as $list) { + $this->assertList($list); + } + } + + /** + * Test the api_lists_ownerships() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiListsOwnershipsWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_lists_ownerships('json'); + } + + /** + * Test the api_lists_statuses() function. + * @expectedException Friendica\Network\HTTPException\BadRequestException + * @return void + */ + public function testApiListsStatuses() + { + api_lists_statuses('json'); + } + + /** + * Test the api_lists_statuses() function with a list ID. + * @return void + */ + public function testApiListsStatusesWithListId() + { + $_REQUEST['list_id'] = 1; + $_REQUEST['page'] = -1; + $_REQUEST['max_id'] = 10; + $result = api_lists_statuses('json'); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + + /** + * Test the api_lists_statuses() function with a list ID and a RSS result. + * @return void + */ + public function testApiListsStatusesWithListIdAndRss() + { + $_REQUEST['list_id'] = 1; + $result = api_lists_statuses('rss'); + $this->assertXml($result, 'statuses'); + } + + /** + * Test the api_lists_statuses() function with an unallowed user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiListsStatusesWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_lists_statuses('json'); + } + + /** + * Test the api_statuses_f() function. + * @return void + */ + public function testApiStatusesFWithFriends() + { + $_GET['page'] = -1; + $result = api_statuses_f('friends'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_statuses_f() function. + * @return void + */ + public function testApiStatusesFWithFollowers() + { + $result = api_statuses_f('followers'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_statuses_f() function. + * @return void + */ + public function testApiStatusesFWithBlocks() + { + $result = api_statuses_f('blocks'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_statuses_f() function. + * @return void + */ + public function testApiStatusesFWithIncoming() + { + $result = api_statuses_f('incoming'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_statuses_f() function an undefined cursor GET variable. + * @return void + */ + public function testApiStatusesFWithUndefinedCursor() + { + $_GET['cursor'] = 'undefined'; + $this->assertFalse(api_statuses_f('friends')); + } + + /** + * Test the api_statuses_friends() function. + * @return void + */ + public function testApiStatusesFriends() + { + $result = api_statuses_friends('json'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_statuses_friends() function an undefined cursor GET variable. + * @return void + */ + public function testApiStatusesFriendsWithUndefinedCursor() + { + $_GET['cursor'] = 'undefined'; + $this->assertFalse(api_statuses_friends('json')); + } + + /** + * Test the api_statuses_followers() function. + * @return void + */ + public function testApiStatusesFollowers() + { + $result = api_statuses_followers('json'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_statuses_followers() function an undefined cursor GET variable. + * @return void + */ + public function testApiStatusesFollowersWithUndefinedCursor() + { + $_GET['cursor'] = 'undefined'; + $this->assertFalse(api_statuses_followers('json')); + } + + /** + * Test the api_blocks_list() function. + * @return void + */ + public function testApiBlocksList() + { + $result = api_blocks_list('json'); + $this->assertArrayHasKey('user', $result); + } + + /** + * Test the api_blocks_list() function an undefined cursor GET variable. + * @return void + */ + public function testApiBlocksListWithUndefinedCursor() + { + $_GET['cursor'] = 'undefined'; + $this->assertFalse(api_blocks_list('json')); + } + + /** + * Test the api_friendships_incoming() function. + * @return void + */ + public function testApiFriendshipsIncoming() + { + $result = api_friendships_incoming('json'); + $this->assertArrayHasKey('id', $result); + } + + /** + * Test the api_friendships_incoming() function an undefined cursor GET variable. + * @return void + */ + public function testApiFriendshipsIncomingWithUndefinedCursor() + { + $_GET['cursor'] = 'undefined'; + $this->assertFalse(api_friendships_incoming('json')); + } + + /** + * Test the api_statusnet_config() function. + * @return void + */ + public function testApiStatusnetConfig() + { + $result = api_statusnet_config('json'); + $this->assertEquals('localhost', $result['config']['site']['server']); + $this->assertEquals('default', $result['config']['site']['theme']); + $this->assertEquals('http://localhost/images/friendica-64.png', $result['config']['site']['logo']); + $this->assertTrue($result['config']['site']['fancy']); + $this->assertEquals('en', $result['config']['site']['language']); + $this->assertEquals('UTC', $result['config']['site']['timezone']); + $this->assertEquals(200000, $result['config']['site']['textlimit']); + $this->assertEquals('false', $result['config']['site']['private']); + $this->assertEquals('false', $result['config']['site']['ssl']); + $this->assertEquals(30, $result['config']['site']['shorturllength']); + } + + /** + * Test the api_statusnet_version() function. + * @return void + */ + public function testApiStatusnetVersion() + { + $result = api_statusnet_version('json'); + $this->assertEquals('0.9.7', $result['version']); + } + + /** + * Test the api_ff_ids() function. + * @return void + */ + public function testApiFfIds() + { + $result = api_ff_ids('json'); + $this->assertNull($result); + } + + /** + * Test the api_ff_ids() function with a result. + * @return void + */ + public function testApiFfIdsWithResult() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_ff_ids() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFfIdsWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_ff_ids('json'); + } + + /** + * Test the api_friends_ids() function. + * @return void + */ + public function testApiFriendsIds() + { + $result = api_friends_ids('json'); + $this->assertNull($result); + } + + /** + * Test the api_followers_ids() function. + * @return void + */ + public function testApiFollowersIds() + { + $result = api_followers_ids('json'); + $this->assertNull($result); + } + + /** + * Test the api_direct_messages_new() function. + * @return void + */ + public function testApiDirectMessagesNew() + { + $result = api_direct_messages_new('json'); + $this->assertNull($result); + } + + /** + * Test the api_direct_messages_new() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiDirectMessagesNewWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_direct_messages_new('json'); + } + + /** + * Test the api_direct_messages_new() function with an user ID. + * @return void + */ + public function testApiDirectMessagesNewWithUserId() + { + $_POST['text'] = 'message_text'; + $_POST['user_id'] = $this->otherUser['id']; + $result = api_direct_messages_new('json'); + $this->assertEquals(['direct_message' => ['error' => -1]], $result); + } + + /** + * Test the api_direct_messages_new() function with a screen name. + * @return void + */ + public function testApiDirectMessagesNewWithScreenName() + { + $_POST['text'] = 'message_text'; + $_POST['screen_name'] = $this->otherUser['nick']; + $result = api_direct_messages_new('json'); + $this->assertEquals(1, $result['direct_message']['id']); + $this->assertContains('message_text', $result['direct_message']['text']); + $this->assertEquals('selfcontact', $result['direct_message']['sender_screen_name']); + $this->assertEquals(1, $result['direct_message']['friendica_seen']); + } + + /** + * Test the api_direct_messages_new() function with a title. + * @return void + */ + public function testApiDirectMessagesNewWithTitle() + { + $_POST['text'] = 'message_text'; + $_POST['screen_name'] = $this->otherUser['nick']; + $_REQUEST['title'] = 'message_title'; + $result = api_direct_messages_new('json'); + $this->assertEquals(1, $result['direct_message']['id']); + $this->assertContains('message_text', $result['direct_message']['text']); + $this->assertContains('message_title', $result['direct_message']['text']); + $this->assertEquals('selfcontact', $result['direct_message']['sender_screen_name']); + $this->assertEquals(1, $result['direct_message']['friendica_seen']); + } + + /** + * Test the api_direct_messages_new() function with an RSS result. + * @return void + */ + public function testApiDirectMessagesNewWithRss() + { + $_POST['text'] = 'message_text'; + $_POST['screen_name'] = $this->otherUser['nick']; + $result = api_direct_messages_new('rss'); + $this->assertXml($result, 'direct-messages'); + } + + /** + * Test the api_direct_messages_destroy() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiDirectMessagesDestroy() + { + api_direct_messages_destroy('json'); + } + + /** + * Test the api_direct_messages_destroy() function with the friendica_verbose GET param. + * @return void + */ + public function testApiDirectMessagesDestroyWithVerbose() + { + $_GET['friendica_verbose'] = 'true'; + $result = api_direct_messages_destroy('json'); + $this->assertEquals( + [ + '$result' => [ + 'result' => 'error', + 'message' => 'message id or parenturi not specified' + ] + ], + $result + ); + } + + /** + * Test the api_direct_messages_destroy() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiDirectMessagesDestroyWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_direct_messages_destroy('json'); + } + + /** + * Test the api_direct_messages_destroy() function with a non-zero ID. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiDirectMessagesDestroyWithId() + { + $_REQUEST['id'] = 1; + api_direct_messages_destroy('json'); + } + + /** + * Test the api_direct_messages_destroy() with a non-zero ID and the friendica_verbose GET param. + * @return void + */ + public function testApiDirectMessagesDestroyWithIdAndVerbose() + { + $_REQUEST['id'] = 1; + $_REQUEST['friendica_parenturi'] = 'parent_uri'; + $_GET['friendica_verbose'] = 'true'; + $result = api_direct_messages_destroy('json'); + $this->assertEquals( + [ + '$result' => [ + 'result' => 'error', + 'message' => 'message id not in database' + ] + ], + $result + ); + } + + /** + * Test the api_direct_messages_destroy() function with a non-zero ID. + * @return void + */ + public function testApiDirectMessagesDestroyWithCorrectId() + { + $this->markTestIncomplete('We need to add a dataset for this.'); + } + + /** + * Test the api_direct_messages_box() function. + * @return void + */ + public function testApiDirectMessagesBoxWithSentbox() + { + $_REQUEST['page'] = -1; + $_REQUEST['max_id'] = 10; + $result = api_direct_messages_box('json', 'sentbox', 'false'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_box() function. + * @return void + */ + public function testApiDirectMessagesBoxWithConversation() + { + $result = api_direct_messages_box('json', 'conversation', 'false'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_box() function. + * @return void + */ + public function testApiDirectMessagesBoxWithAll() + { + $result = api_direct_messages_box('json', 'all', 'false'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_box() function. + * @return void + */ + public function testApiDirectMessagesBoxWithInbox() + { + $result = api_direct_messages_box('json', 'inbox', 'false'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_box() function. + * @return void + */ + public function testApiDirectMessagesBoxWithVerbose() + { + $result = api_direct_messages_box('json', 'sentbox', 'true'); + $this->assertEquals( + [ + '$result' => [ + 'result' => 'error', + 'message' => 'no mails available' + ] + ], + $result + ); + } + + /** + * Test the api_direct_messages_box() function with a RSS result. + * @return void + */ + public function testApiDirectMessagesBoxWithRss() + { + $result = api_direct_messages_box('rss', 'sentbox', 'false'); + $this->assertXml($result, 'direct-messages'); + } + + /** + * Test the api_direct_messages_box() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiDirectMessagesBoxWithUnallowedUser() + { + $_SESSION['allow_api'] = false; + $_GET['screen_name'] = $this->selfUser['nick']; + api_direct_messages_box('json', 'sentbox', 'false'); + } + + /** + * Test the api_direct_messages_sentbox() function. + * @return void + */ + public function testApiDirectMessagesSentbox() + { + $result = api_direct_messages_sentbox('json'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_inbox() function. + * @return void + */ + public function testApiDirectMessagesInbox() + { + $result = api_direct_messages_inbox('json'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_all() function. + * @return void + */ + public function testApiDirectMessagesAll() + { + $result = api_direct_messages_all('json'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_direct_messages_conversation() function. + * @return void + */ + public function testApiDirectMessagesConversation() + { + $result = api_direct_messages_conversation('json'); + $this->assertArrayHasKey('direct_message', $result); + } + + /** + * Test the api_oauth_request_token() function. + * @return void + */ + public function testApiOauthRequestToken() + { + $this->markTestIncomplete('killme() kills phpunit as well'); + } + + /** + * Test the api_oauth_access_token() function. + * @return void + */ + public function testApiOauthAccessToken() + { + $this->markTestIncomplete('killme() kills phpunit as well'); + } + + /** + * Test the api_fr_photoalbum_delete() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoalbumDelete() + { + api_fr_photoalbum_delete('json'); + } + + /** + * Test the api_fr_photoalbum_delete() function with an album name. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoalbumDeleteWithAlbum() + { + $_REQUEST['album'] = 'album_name'; + api_fr_photoalbum_delete('json'); + } + + /** + * Test the api_fr_photoalbum_delete() function with an album name. + * @return void + */ + public function testApiFrPhotoalbumDeleteWithValidAlbum() + { + $this->markTestIncomplete('We need to add a dataset for this.'); + } + + /** + * Test the api_fr_photoalbum_delete() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoalbumUpdate() + { + api_fr_photoalbum_update('json'); + } + + /** + * Test the api_fr_photoalbum_delete() function with an album name. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoalbumUpdateWithAlbum() + { + $_REQUEST['album'] = 'album_name'; + api_fr_photoalbum_update('json'); + } + + /** + * Test the api_fr_photoalbum_delete() function with an album name. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoalbumUpdateWithAlbumAndNewAlbum() + { + $_REQUEST['album'] = 'album_name'; + $_REQUEST['album_new'] = 'album_name'; + api_fr_photoalbum_update('json'); + } + + /** + * Test the api_fr_photoalbum_update() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFrPhotoalbumUpdateWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_fr_photoalbum_update('json'); + } + + /** + * Test the api_fr_photoalbum_delete() function with an album name. + * @return void + */ + public function testApiFrPhotoalbumUpdateWithValidAlbum() + { + $this->markTestIncomplete('We need to add a dataset for this.'); + } + + /** + * Test the api_fr_photos_list() function. + * @return void + */ + public function testApiFrPhotosList() + { + $result = api_fr_photos_list('json'); + $this->assertArrayHasKey('photo', $result); + } + + /** + * Test the api_fr_photos_list() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFrPhotosListWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_fr_photos_list('json'); + } + + /** + * Test the api_fr_photo_create_update() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoCreateUpdate() + { + api_fr_photo_create_update('json'); + } + + /** + * Test the api_fr_photo_create_update() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFrPhotoCreateUpdateWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_fr_photo_create_update('json'); + } + + /** + * Test the api_fr_photo_create_update() function with an album name. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoCreateUpdateWithAlbum() + { + $_REQUEST['album'] = 'album_name'; + api_fr_photo_create_update('json'); + } + + /** + * Test the api_fr_photo_create_update() function with the update mode. + * @return void + */ + public function testApiFrPhotoCreateUpdateWithUpdate() + { + $this->markTestIncomplete('We need to create a dataset for this'); + } + + /** + * Test the api_fr_photo_create_update() function with an uploaded file. + * @return void + */ + public function testApiFrPhotoCreateUpdateWithFile() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_fr_photo_delete() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoDelete() + { + api_fr_photo_delete('json'); + } + + /** + * Test the api_fr_photo_delete() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFrPhotoDeleteWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_fr_photo_delete('json'); + } + + /** + * Test the api_fr_photo_delete() function with a photo ID. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoDeleteWithPhotoId() + { + $_REQUEST['photo_id'] = 1; + api_fr_photo_delete('json'); + } + + /** + * Test the api_fr_photo_delete() function with a correct photo ID. + * @return void + */ + public function testApiFrPhotoDeleteWithCorrectPhotoId() + { + $this->markTestIncomplete('We need to create a dataset for this.'); + } + + /** + * Test the api_fr_photo_detail() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFrPhotoDetail() + { + api_fr_photo_detail('json'); + } + + /** + * Test the api_fr_photo_detail() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFrPhotoDetailWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_fr_photo_detail('json'); + } + + /** + * Test the api_fr_photo_detail() function with a photo ID. + * @return void + * @expectedException Friendica\Network\HTTPException\NotFoundException + */ + public function testApiFrPhotoDetailWithPhotoId() + { + $_REQUEST['photo_id'] = 1; + api_fr_photo_detail('json'); + } + + /** + * Test the api_fr_photo_detail() function with a correct photo ID. + * @return void + */ + public function testApiFrPhotoDetailCorrectPhotoId() + { + $this->markTestIncomplete('We need to create a dataset for this.'); + } + + /** + * Test the api_account_update_profile_image() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiAccountUpdateProfileImage() + { + api_account_update_profile_image('json'); + } + + /** + * Test the api_account_update_profile_image() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiAccountUpdateProfileImageWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_account_update_profile_image('json'); + } + + /** + * Test the api_account_update_profile_image() function with an uploaded file. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiAccountUpdateProfileImageWithUpload() + { + $this->markTestIncomplete(); + } + + + /** + * Test the api_account_update_profile() function. + * @return void + */ + public function testApiAccountUpdateProfile() + { + $_POST['name'] = 'new_name'; + $_POST['description'] = 'new_description'; + $result = api_account_update_profile('json'); + // We can't use assertSelfUser() here because the user object is missing some properties. + $this->assertEquals($this->selfUser['id'], $result['user']['cid']); + $this->assertEquals('Friendica', $result['user']['location']); + $this->assertEquals($this->selfUser['nick'], $result['user']['screen_name']); + $this->assertEquals('dfrn', $result['user']['network']); + $this->assertEquals('new_name', $result['user']['name']); + $this->assertEquals('new_description', $result['user']['description']); + } + + /** + * Test the check_acl_input() function. + * @return void + */ + public function testCheckAclInput() + { + $result = check_acl_input(''); + // Where does this result come from? + $this->assertEquals(1, $result); + } + + /** + * Test the check_acl_input() function with an empty ACL string. + * @return void + */ + public function testCheckAclInputWithEmptyAclString() + { + $result = check_acl_input(' '); + $this->assertFalse($result); + } + + /** + * Test the save_media_to_database() function. + * @return void + */ + public function testSaveMediaToDatabase() + { + $this->markTestIncomplete(); + } + + /** + * Test the post_photo_item() function. + * @return void + */ + public function testPostPhotoItem() + { + $this->markTestIncomplete(); + } + + /** + * Test the prepare_photo_data() function. + * @return void + */ + public function testPreparePhotoData() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_remoteauth() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFriendicaRemoteauth() + { + api_friendica_remoteauth(); + } + + /** + * Test the api_friendica_remoteauth() function with an URL. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFriendicaRemoteauthWithUrl() + { + $_GET['url'] = 'url'; + $_GET['c_url'] = 'url'; + api_friendica_remoteauth(); + } + + /** + * Test the api_friendica_remoteauth() function with a correct URL. + * @return void + */ + public function testApiFriendicaRemoteauthWithCorrectUrl() + { + $this->markTestIncomplete("We can't use an assertion here because of goaway()."); + $_GET['url'] = 'url'; + $_GET['c_url'] = $this->selfUser['nurl']; + api_friendica_remoteauth(); + } + + /** + * Test the api_share_as_retweet() function. + * @return void + */ + public function testApiShareAsRetweet() + { + $item = []; + $result = api_share_as_retweet($item); + $this->assertFalse($result); + } + + /** + * Test the api_share_as_retweet() function with a valid item. + * @return void + */ + public function testApiShareAsRetweetWithValidItem() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_get_nick() function. + * @return void + */ + public function testApiGetNick() + { + $result = api_get_nick($this->otherUser['nurl']); + $this->assertEquals('othercontact', $result); + } + + /** + * Test the api_get_nick() function with a wrong URL. + * @return void + */ + public function testApiGetNickWithWrongUrl() + { + $result = api_get_nick('wrong_url'); + $this->assertFalse($result); + } + + /** + * Test the api_in_reply_to() function. + * @return void + */ + public function testApiInReplyTo() + { + $result = api_in_reply_to([]); + $this->assertArrayHasKey('status_id', $result); + $this->assertArrayHasKey('user_id', $result); + $this->assertArrayHasKey('status_id_str', $result); + $this->assertArrayHasKey('user_id_str', $result); + $this->assertArrayHasKey('screen_name', $result); + } + + /** + * Test the api_in_reply_to() function with a valid item. + * @return void + */ + public function testApiInReplyToWithValidItem() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_clean_plain_items() function. + * @return void + */ + public function testApiCleanPlainItems() + { + $_REQUEST['include_entities'] = 'true'; + $result = api_clean_plain_items('some_text [url="some_url"]some_text[/url]'); + $this->assertEquals('some_text [url="some_url"]"some_url"[/url]', $result); + } + + /** + * Test the api_clean_attachments() function. + * @return void + */ + public function testApiCleanAttachments() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_best_nickname() function. + * @return void + */ + public function testApiBestNickname() + { + $contacts = []; + $result = api_best_nickname($contacts); + $this->assertNull($result); + } + + /** + * Test the api_best_nickname() function with contacts. + * @return void + */ + public function testApiBestNicknameWithContacts() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_group_show() function. + * @return void + */ + public function testApiFriendicaGroupShow() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_group_delete() function. + * @return void + */ + public function testApiFriendicaGroupDelete() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_lists_destroy() function. + * @return void + */ + public function testApiListsDestroy() + { + $this->markTestIncomplete(); + } + + /** + * Test the group_create() function. + * @return void + */ + public function testGroupCreate() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_group_create() function. + * @return void + */ + public function testApiFriendicaGroupCreate() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_lists_create() function. + * @return void + */ + public function testApiListsCreate() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_group_update() function. + * @return void + */ + public function testApiFriendicaGroupUpdate() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_lists_update() function. + * @return void + */ + public function testApiListsUpdate() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_activity() function. + * @return void + */ + public function testApiFriendicaActivity() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_notification() function. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFriendicaNotification() + { + api_friendica_notification('json'); + } + + /** + * Test the api_friendica_notification() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFriendicaNotificationWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_friendica_notification('json'); + } + + /** + * Test the api_friendica_notification() function with an argument count. + * @return void + */ + public function testApiFriendicaNotificationWithArgumentCount() + { + $this->app->argc = 3; + $result = api_friendica_notification('json'); + $this->assertEquals(['note' => false], $result); + } + + /** + * Test the api_friendica_notification() function with an XML result. + * @return void + */ + public function testApiFriendicaNotificationWithXmlResult() + { + $this->markTestIncomplete('Fails with "Invalid argument supplied for foreach()".'); + $this->app->argc = 3; + $result = api_friendica_notification('xml'); + $this->assertXml($result, 'notes'); + } + + /** + * Test the api_friendica_notification_seen() function. + * @return void + */ + public function testApiFriendicaNotificationSeen() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_direct_messages_setseen() function. + * @return void + */ + public function testApiFriendicaDirectMessagesSetseen() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_direct_messages_search() function. + * @return void + */ + public function testApiFriendicaDirectMessagesSearch() + { + $this->markTestIncomplete(); + } + + /** + * Test the api_friendica_profile_show() function. + * @return void + */ + public function testApiFriendicaProfileShow() + { + $result = api_friendica_profile_show('json'); + // We can't use assertSelfUser() here because the user object is missing some properties. + $this->assertEquals($this->selfUser['id'], $result['$result']['friendica_owner']['cid']); + $this->assertEquals('Friendica', $result['$result']['friendica_owner']['location']); + $this->assertEquals($this->selfUser['name'], $result['$result']['friendica_owner']['name']); + $this->assertEquals($this->selfUser['nick'], $result['$result']['friendica_owner']['screen_name']); + $this->assertEquals('dfrn', $result['$result']['friendica_owner']['network']); + $this->assertTrue($result['$result']['friendica_owner']['verified']); + $this->assertFalse($result['$result']['multi_profiles']); + } + + /** + * Test the api_friendica_profile_show() function with a profile ID. + * @return void + */ + public function testApiFriendicaProfileShowWithProfileId() + { + $this->markTestIncomplete('We need to add a dataset for this.'); + } + + /** + * Test the api_friendica_profile_show() function with a wrong profile ID. + * @return void + * @expectedException Friendica\Network\HTTPException\BadRequestException + */ + public function testApiFriendicaProfileShowWithWrongProfileId() + { + $_REQUEST['profile_id'] = 666; + api_friendica_profile_show('json'); + } + + /** + * Test the api_friendica_profile_show() function without an authenticated user. + * @return void + * @expectedException Friendica\Network\HTTPException\ForbiddenException + */ + public function testApiFriendicaProfileShowWithoutAuthenticatedUser() + { + $_SESSION['authenticated'] = false; + api_friendica_profile_show('json'); + } + + /** + * Test the api_saved_searches_list() function. + * @return void + */ + public function testApiSavedSearchesList() + { + $result = api_saved_searches_list('json'); + $this->assertEquals(1, $result['terms'][0]['id']); + $this->assertEquals(1, $result['terms'][0]['id_str']); + $this->assertEquals('Saved search', $result['terms'][0]['name']); + $this->assertEquals('Saved search', $result['terms'][0]['query']); + } +} diff --git a/tests/BaseObjectTest.php b/tests/BaseObjectTest.php index b7b90b138..b3d018958 100644 --- a/tests/BaseObjectTest.php +++ b/tests/BaseObjectTest.php @@ -7,14 +7,12 @@ namespace Friendica\Test; use Friendica\App; use Friendica\BaseObject; -// backward compatibility -if (!class_exists('\PHPUnit\Framework\TestCase')) { - class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase'); -} +use PHPUnit\Framework\TestCase; + /** * Tests for the BaseObject class. */ -class BaseObjectTest extends \PHPUnit\Framework\TestCase +class BaseObjectTest extends TestCase { /** diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php new file mode 100644 index 000000000..c0a5c7b8d --- /dev/null +++ b/tests/DatabaseTest.php @@ -0,0 +1,60 @@ +module = 'install'; + + // Create database structure + DBStructure::update(false, true, true); + } else { + $this->markTestSkipped('Could not connect to the database.'); + } + } + + return $this->createDefaultDBConnection(dba::get_db(), 'friendica_test:'); + } + + /** + * Get dataset to populate the database with. + * @return YamlDataSet + * @see https://phpunit.de/manual/5.7/en/database.html + */ + protected function getDataSet() + { + return new YamlDataSet( + __DIR__.'/datasets/api.yml' + ); + } +} diff --git a/tests/TextTest.php b/tests/TextTest.php index 3cda2342f..ac1b7d775 100644 --- a/tests/TextTest.php +++ b/tests/TextTest.php @@ -5,15 +5,12 @@ namespace Friendica\Test; -// backward compatibility -if (!class_exists('\PHPUnit\Framework\TestCase')) { - class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase'); -} +use PHPUnit\Framework\TestCase; /** * Tests for text functions. */ -class TextTest extends \PHPUnit\Framework\TestCase +class TextTest extends TestCase { /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 000000000..4474e4ee8 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,22 @@ + Date: Thu, 10 May 2018 20:04:30 +0200 Subject: [PATCH 012/236] Add link to test doc on documentation home --- doc/Home.md | 2 +- doc/de/Home.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Home.md b/doc/Home.md index 74dca6bed..079d5450f 100644 --- a/doc/Home.md +++ b/doc/Home.md @@ -50,6 +50,7 @@ Friendica Documentation and Resources * [Translate Friendica](help/translations) * [Use Composer](help/Composer) * [Move classes to `src`](help/Developer-How-To-Move-Classes-to-src) + * [Run tests](help/Tests) * Reference * [Twitter/GNU Social API Functions](help/api) * [Code (Doxygen generated - sets cookies)](doc/html/) @@ -71,4 +72,3 @@ Friendica Documentation and Resources * [Site/Version Info](friendica) * [Friendica Credits](credits) - diff --git a/doc/de/Home.md b/doc/de/Home.md index 2c46909ee..62f16621d 100644 --- a/doc/de/Home.md +++ b/doc/de/Home.md @@ -55,6 +55,7 @@ Friendica - Dokumentation und Ressourcen * [Code-Referenz (mit doxygen generiert - setzt Cookies)](doc/html/) * [Twitter/GNU Social API Functions](help/api) (EN) * [Translation of Friendica](help/translations) (EN) +* [Run tests](help/Tests) (EN) **Externe Ressourcen** @@ -71,4 +72,3 @@ Friendica - Dokumentation und Ressourcen * [Seite/Friendica-Version](friendica) * [Mitwirkenden bei Friendica](credits) - From 6a654df444206a23ddf19aa0d768da634875d812 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Thu, 10 May 2018 22:21:55 +0200 Subject: [PATCH 013/236] Add a new contact to test rel=2 in tests See https://github.com/friendica/friendica/pull/5022#discussion_r187416029 --- tests/datasets/api.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index 138e18e84..ae1fd3242 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -44,6 +44,18 @@ contact: url: http://localhost/profile/othercontact pending: false blocked: false + rel: 0 + network: dfrn + - + id: 44 + uid: 42 + name: Friend contact + nick: friendcontact + self: false + nurl: http://localhost/profile/friendcontact + url: http://localhost/profile/friendcontact + pending: false + blocked: false rel: 2 network: dfrn @@ -126,6 +138,20 @@ item: allow_gid: '' deny_cid: '' deny_gid: '' + - + id: 6 + visible: true + contact-id: 44 + author-id: 44 + owner-id: 42 + uid: 42 + verb: http://activitystrea.ms/schema/1.0/post + unseen: false + body: Friend user status + parent: 6 + author-link: http://localhost/profile/othercontact + wall: true + starred: false thread: - @@ -140,6 +166,12 @@ thread: contact-id: 43 uid: 0 wall: true + - + iid: 6 + visible: true + contact-id: 44 + uid: 0 + wall: true group: - From 3191fee76362b0fe9b5b188e9ef8bcd73a5f8a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Sun, 13 May 2018 10:02:47 +0200 Subject: [PATCH 014/236] Ops, one to much ... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- src/Protocol/DFRN.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index c464c14c2..5a0151c1c 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -132,7 +132,6 @@ class DFRN dbesc($owner_nick) ); - if (! DBM::is_result($r)) { if (! dbm::is_result($r)) { logger(sprintf('No contact found for nickname=%d', $owner_nick), LOGGER_WARNING); killme(); From 594f946ad68cc0ab8a9a18c6778298c9976318cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Sun, 13 May 2018 10:04:49 +0200 Subject: [PATCH 015/236] No extra empty line here MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- mod/_well_known.php | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/_well_known.php b/mod/_well_known.php index 89097c0ff..4f247abef 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -43,7 +43,6 @@ function wk_social_relay() $tags = []; if ($scope == SR_SCOPE_TAGS) { - $server_tags = get_config('system', 'relay_server_tags'); $tagitems = explode(",", $server_tags); From 8d9547777e3c4a37405c4a11f8aad1b63b514ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Sun, 13 May 2018 10:05:31 +0200 Subject: [PATCH 016/236] Ops, was redundant here. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- mod/events.php | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/events.php b/mod/events.php index bbd6337c3..cad440f16 100644 --- a/mod/events.php +++ b/mod/events.php @@ -433,7 +433,6 @@ function events_content(App $a) { if (x($_REQUEST, 'location')) {$orig_event['location'] = $_REQUEST['location'];} if (x($_REQUEST, 'start')) {$orig_event['start'] = $_REQUEST['start'];} if (x($_REQUEST, 'finish')) {$orig_event['finish'] = $_REQUEST['finish'];} - if (x($_REQUEST,'finish')) $orig_event['finish'] = $_REQUEST['finish']; $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : ''); $a_checked = ((x($orig_event) && $orig_event['adjust']) ? ' checked="checked" ' : ''); From 445cc1cb99b244482141723c724f769c37cca32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Sun, 13 May 2018 10:06:43 +0200 Subject: [PATCH 017/236] Fixes: - brought back comment (ops) - DBM is the class name (not dbm) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- mod/poco.php | 1 + src/Protocol/DFRN.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/poco.php b/mod/poco.php index 183d7acd1..671551f83 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -45,6 +45,7 @@ function poco_init(App $a) { } if ($a->argc > 1 && $a->argv[1] === '@global') { + // List of all profiles that this server recently had data from $global = true; $update_limit = date(DateTimeFormat::MYSQL, time() - 30 * 86400); } diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 5a0151c1c..0f9cbeafa 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -132,7 +132,7 @@ class DFRN dbesc($owner_nick) ); - if (! dbm::is_result($r)) { + if (! DBM::is_result($r)) { logger(sprintf('No contact found for nickname=%d', $owner_nick), LOGGER_WARNING); killme(); } From 87dbe0352142200330b4414f292efe4658c5fb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Sun, 13 May 2018 10:20:15 +0200 Subject: [PATCH 018/236] reverted back ... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- mod/_well_known.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/_well_known.php b/mod/_well_known.php index 4f247abef..782dc7a1b 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -43,7 +43,7 @@ function wk_social_relay() $tags = []; if ($scope == SR_SCOPE_TAGS) { - $server_tags = get_config('system', 'relay_server_tags'); + $server_tags = Config::get('system', 'relay_server_tags'); $tagitems = explode(",", $server_tags); /// @todo Check if it was better to use "strtolower" on the tags @@ -52,7 +52,7 @@ function wk_social_relay() $tags[$tag] = $tag; } - if (get_config('system', 'relay_user_tags')) { + if (Config::get('system', 'relay_user_tags')) { $terms = q("SELECT DISTINCT(`term`) FROM `search`"); foreach ($terms AS $term) { From 99440f3c56d1a87aa5aa357d68e371c726f6ba0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Sun, 13 May 2018 14:20:15 +0200 Subject: [PATCH 019/236] Beatification: - added space after curly braces (MrPetovan) - added TODO for possible rewrite candidate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- mod/share.php | 7 +++++++ src/Protocol/DFRN.php | 1 + 2 files changed, 8 insertions(+) diff --git a/mod/share.php b/mod/share.php index ed9b5f9d1..555273443 100644 --- a/mod/share.php +++ b/mod/share.php @@ -5,6 +5,7 @@ use Friendica\Database\DBM; function share_init(App $a) { $post_id = (($a->argc > 1) ? intval($a->argv[1]) : 0); + if (!$post_id || !local_user()) { killme(); } @@ -14,9 +15,11 @@ function share_init(App $a) { WHERE `item`.`id` = %d LIMIT 1", intval($post_id) ); + if (!DBM::is_result($r) || ($r[0]['private'] == 1)) { killme(); } + if (strpos($r[0]['body'], "[/share]") !== false) { $pos = strpos($r[0]['body'], "[share"); $o = substr($r[0]['body'], $pos); @@ -26,6 +29,7 @@ function share_init(App $a) { if ($r[0]['title']) { $o .= '[b]'.$r[0]['title'].'[/b]'."\n"; } + $o .= $r[0]['body']; $o .= "[/share]"; } @@ -34,6 +38,7 @@ function share_init(App $a) { killme(); } +/// @TODO Rewrite to handle over whole record array function share_header($author, $profile, $avatar, $guid, $posted, $link) { $header = "[share author='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $author). "' profile='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $profile). @@ -42,9 +47,11 @@ function share_header($author, $profile, $avatar, $guid, $posted, $link) { if ($guid) { $header .= "' guid='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $guid); } + if ($posted) { $header .= "' posted='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $posted); } + $header .= "' link='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $link)."']"; return $header; diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 0f9cbeafa..00bb91f8d 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -181,6 +181,7 @@ class DFRN for ($x = 0; $x < count($groups); $x ++) { $groups[$x] = '<' . intval($groups[$x]) . '>' ; } + $gs = implode('|', $groups); } else { $gs = '<<>>' ; // Impossible to match From bc259cdc441717cce9b52fcd1c554925b843a25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20H=C3=A4der?= Date: Thu, 26 Jan 2017 16:01:56 +0100 Subject: [PATCH 020/236] added spaces + some curly braces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- include/security.php | 3 ++- include/text.php | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/security.php b/include/security.php index b13a507cf..70896992d 100644 --- a/include/security.php +++ b/include/security.php @@ -299,8 +299,9 @@ function permissions_sql($owner_id, $remote_verified = false, $groups = null) $gs = '<<>>'; // should be impossible to match if (is_array($groups) && count($groups)) { - foreach ($groups as $g) + foreach ($groups as $g) { $gs .= '|<' . intval($g) . '>'; + } } $sql = sprintf( diff --git a/include/text.php b/include/text.php index 4c9a8864d..b59ecdbc0 100644 --- a/include/text.php +++ b/include/text.php @@ -1660,10 +1660,11 @@ function bb_translate_video($s) { $r = preg_match_all("/\[video\](.*?)\[\/video\]/ism",$s,$matches,PREG_SET_ORDER); if ($r) { foreach ($matches as $mtch) { - if ((stristr($mtch[1],'youtube')) || (stristr($mtch[1],'youtu.be'))) - $s = str_replace($mtch[0],'[youtube]' . $mtch[1] . '[/youtube]',$s); - elseif (stristr($mtch[1],'vimeo')) - $s = str_replace($mtch[0],'[vimeo]' . $mtch[1] . '[/vimeo]',$s); + if ((stristr($mtch[1], 'youtube')) || (stristr($mtch[1], 'youtu.be'))) { + $s = str_replace($mtch[0], '[youtube]' . $mtch[1] . '[/youtube]', $s); + } elseif (stristr($mtch[1], 'vimeo')) { + $s = str_replace($mtch[0], '[vimeo]' . $mtch[1] . '[/vimeo]', $s); + } } } return $s; @@ -1781,7 +1782,7 @@ function file_tag_file_query($table,$s,$type = 'file') { } // ex. given music,video return