]> git.mxchange.org Git - friendica.git/commitdiff
Merge pull request #5022 from Rudloff/feature/test_api
authorHypolite Petovan <mrpetovan@gmail.com>
Wed, 16 May 2018 12:25:11 +0000 (08:25 -0400)
committerGitHub <noreply@github.com>
Wed, 16 May 2018 12:25:11 +0000 (08:25 -0400)
 Add API tests

15 files changed:
.travis.yml
composer.json
composer.lock
doc/Home.md
doc/Tests.md [new file with mode: 0644]
doc/de/Home.md
include/api.php
include/dba.php
phpunit.xml
tests/ApiTest.php [new file with mode: 0644]
tests/BaseObjectTest.php
tests/DatabaseTest.php [new file with mode: 0644]
tests/TextTest.php
tests/bootstrap.php [new file with mode: 0644]
tests/datasets/api.yml [new file with mode: 0644]

index d68b7727e893648344978d94f4ff378589a62e15..82b5a5d218bd3de32b17a142b8e22026263b1e5b 100644 (file)
@@ -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
index b7cd645bdb43d72580af2d8e0e31c2a98c3a344a..9668b9341c14e819a1f267fd4cd7d314d3742261 100644 (file)
@@ -47,7 +47,8 @@
        ],
        "autoload": {
                "psr-4": {
-                       "Friendica\\": "src/"
+                       "Friendica\\": "src/",
+                       "Friendica\\Test\\": "tests/"
                },
                "psr-0": {
                        "": "library/"
                "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"
        }
 }
index f294c16ef5f59a6274ea9c75e0f867fbaf61b4dd..dd2665ebbe251b4dffa61f87ea267c1d2c1eaa2a 100644 (file)
@@ -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",
             "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": {
index 74dca6bed83d7038635eb70115fef5c24c02675d..079d5450f752353e9da854885f09f7d2ec35dde3 100644 (file)
@@ -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/Tests.md b/doc/Tests.md
new file mode 100644 (file)
index 0000000..6acb4e7
--- /dev/null
@@ -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.
index 2c46909ee7dd954540b8127d919d0fe46c36299f..62f16621d90afa6e612cf0a8eb86342d5a66db38 100644 (file)
@@ -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)
-
index ae2f06406e79ef2caddde9604c244a6b0eb8414d..cc31a94e65185b22f7e2dad566ae64bcc8676251 100644 (file)
@@ -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);
 }
 
@@ -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 = [];
index 1d3b432141d525e015539b5b3a6864f5153749ca..53d7041a5aee13dc2fea245ce0f01b5df218bed5 100644 (file)
@@ -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
         *
index 6a275ad3fcd4f0534f15a3b9dfb006f92668a034..b2d978aee6ed895fb126ca90abdec6217aa768e6 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<phpunit bootstrap="boot.php">
+<phpunit bootstrap="tests/bootstrap.php">
     <testsuites>
         <testsuite>
             <directory>tests/</directory>
diff --git a/tests/ApiTest.php b/tests/ApiTest.php
new file mode 100644 (file)
index 0000000..f0e27b4
--- /dev/null
@@ -0,0 +1,3669 @@
+<?php
+/**
+ * ApiTest class.
+ */
+
+namespace Friendica\Test;
+
+use Friendica\App;
+use Friendica\Core\Config;
+use Friendica\Core\PConfig;
+use Friendica\Network\BadRequestException;
+use Friendica\Network\HTTPException;
+use Friendica\Render\FriendicaSmarty;
+
+/**
+ * Tests for the API functions.
+ *
+ * Functions that use header() need to be tested in a separate process.
+ * @see https://phpunit.de/manual/5.7/en/appendixes.annotations.html#appendixes.annotations.runTestsInSeparateProcesses
+ */
+class ApiTest extends DatabaseTest
+{
+
+       /**
+        * Create variables used by tests.
+        */
+       protected function setUp()
+       {
+               global $a;
+               parent::setUp();
+
+               // User data that the test database is populated with
+               $this->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('<?xml version="1.0"?>', $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(
+                       '<?xml version="1.0" encoding="UTF-8"?>'.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(
+                       '<?xml version="1.0" encoding="UTF-8"?>'.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(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<status xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                       '  <error>error_message</error>'.PHP_EOL.
+                       '  <code>200 Friendica\Network\HTTP</code>'.PHP_EOL.
+                       '  <request/>'.PHP_EOL.
+                       '</status>'.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(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<status xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                       '  <error>error_message</error>'.PHP_EOL.
+                       '  <code>200 Friendica\Network\HTTP</code>'.PHP_EOL.
+                       '  <request/>'.PHP_EOL.
+                       '</status>'.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(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<status xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                       '  <error>error_message</error>'.PHP_EOL.
+                       '  <code>200 Friendica\Network\HTTP</code>'.PHP_EOL.
+                       '  <request/>'.PHP_EOL.
+                       '</status>'.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(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<root_element xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                               '  <data>some_data</data>'.PHP_EOL.
+                       '</root_element>'.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(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<ok>'.PHP_EOL.
+                               '  <data>some_data</data>'.PHP_EOL.
+                       '</ok>'.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(
+                       '<?xml version="1.0"?>'.PHP_EOL.
+                       '<root_element xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" '.
+                               'xmlns:friendica="http://friendi.ca/schema/api/1/" '.
+                               'xmlns:georss="http://www.georss.org/georss">'.PHP_EOL.
+                               '  <data>some_data</data>'.PHP_EOL.
+                       '</root_element>'.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'] = '<b>Status content</b>';
+
+               $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'] = '<b>Status content</b>';
+
+               $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('<strong>item_body</strong>', $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('<h4>item_title</h4><br>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('<h4>item_title</h4><br>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('<h4>item_title</h4><br>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 <a href="url">link_text</a>')
+               );
+       }
+
+       /**
+        * 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('<aclstring>');
+               // 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']);
+       }
+}
index b7b90b138e2914f2c006a74b76f7d854d7159b28..b3d018958354b845245269e2a5a08e1611f27a90 100644 (file)
@@ -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 (file)
index 0000000..1215093
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * DatabaseTest class.
+ */
+
+namespace Friendica\Test;
+
+use dba;
+use Friendica\Database\DBStructure;
+use PHPUnit_Extensions_Database_DB_IDatabaseConnection;
+use PHPUnit\DbUnit\DataSet\YamlDataSet;
+use PHPUnit\DbUnit\TestCaseTrait;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Abstract class used by tests that need a database.
+ */
+abstract class DatabaseTest extends TestCase
+{
+
+       use TestCaseTrait;
+
+       /**
+        * Get database connection.
+        *
+        * This function is executed before each test in order to get a database connection that can be used by tests.
+        * If no prior connection is available, it tries to create one using the USER, PASS and DB environment variables.
+        *
+        * If it could not connect to the database, the test is skipped.
+        *
+        * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
+        * @see https://phpunit.de/manual/5.7/en/database.html
+        */
+       protected function getConnection()
+       {
+               if (!dba::$connected) {
+                       dba::connect('localhost', getenv('USER'), getenv('PASS'), getenv('DB'));
+
+                       if (dba::$connected) {
+                               $app = get_app();
+                               // We need to do this in order to disable logging
+                               $app->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(), getenv('DB'));
+       }
+
+       /**
+        * 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');
+       }
+}
index 3cda2342f36b88aa36f7a5ff1759fed4ddc23b67..ac1b7d7757b580eeccc38fa160b4cd983c4dcc1d 100644 (file)
@@ -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 (file)
index 0000000..4474e4e
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is loaded by PHPUnit before any test.
+ */
+
+use PHPUnit\DbUnit\DataSet\YamlDataSet;
+use PHPUnit\DbUnit\TestCaseTrait;
+use PHPUnit\Framework\TestCase;
+
+require_once __DIR__.'/../boot.php';
+require_once __DIR__.'/../include/api.php';
+
+// Backward compatibility
+if (!class_exists(TestCase::class)) {
+       class_alias(PHPUnit_Framework_TestCase::class, TestCase::class);
+}
+if (!trait_exists(TestCaseTrait::class)) {
+       class_alias(PHPUnit_Extensions_Database_TestCase_Trait::class, TestCaseTrait::class);
+}
+if (!class_exists(YamlDataSet::class)) {
+       class_alias(PHPUnit_Extensions_Database_DataSet_YamlDataSet::class, YamlDataSet::class);
+}
diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml
new file mode 100644 (file)
index 0000000..ae1fd32
--- /dev/null
@@ -0,0 +1,192 @@
+---
+# Empty these tables
+cache:
+config:
+conversation:
+pconfig:
+photo:
+workerqueue:
+mail:
+
+# Populate tables with test data
+user:
+    -
+        uid: 42
+        username: Test user
+        nickname: selfcontact
+        verified: true
+        password: $2y$10$DLRNTRmJgKe1cSrFJ5Jb0edCqvXlA9sh/RHdSnfxjbR.04yZRm4Qm
+        theme: frio
+
+contact:
+    -
+        id: 42
+        uid: 42
+        name: Self contact
+        nick: selfcontact
+        self: true
+        nurl: http://localhost/profile/selfcontact
+        url: http://localhost/profile/selfcontact
+        about: User used in tests
+        pending: false
+        blocked: false
+        rel: 1
+        network: dfrn
+    -
+        id: 43
+        uid: 0
+        # Having the same name and nick allows us to test
+        # the fallback to api_get_nick() in api_get_user()
+        name: othercontact
+        nick: othercontact
+        self: false
+        nurl: http://localhost/profile/othercontact
+        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
+
+item:
+    -
+        id: 1
+        visible: true
+        contact-id: 42
+        author-id: 42
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: true
+        body: Parent status
+        parent: 1
+        author-link: http://localhost/profile/selfcontact
+        wall: true
+        starred: true
+        allow_cid: ''
+        allow_gid: ''
+        deny_cid: ''
+        deny_gid: ''
+    -
+        id: 2
+        visible: true
+        contact-id: 42
+        author-id: 42
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Reply
+        parent: 1
+        author-link: http://localhost/profile/selfcontact
+        wall: true
+        starred: false
+    -
+        id: 3
+        visible: true
+        contact-id: 43
+        author-id: 43
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Other user status
+        parent: 3
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+    -
+        id: 4
+        visible: true
+        contact-id: 43
+        author-id: 43
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: Other user reply
+        parent: 1
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+    -
+        id: 5
+        visible: true
+        contact-id: 42
+        author-id: 42
+        owner-id: 42
+        uid: 42
+        verb: http://activitystrea.ms/schema/1.0/post
+        unseen: false
+        body: '[share]Shared status[/share]'
+        parent: 1
+        author-link: http://localhost/profile/othercontact
+        wall: true
+        starred: false
+        allow_cid: ''
+        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:
+    -
+        iid: 1
+        visible: true
+        contact-id: 42
+        uid: 42
+        wall: true
+    -
+        iid: 3
+        visible: true
+        contact-id: 43
+        uid: 0
+        wall: true
+    -
+        iid: 6
+        visible: true
+        contact-id: 44
+        uid: 0
+        wall: true
+
+group:
+    -
+        id: 1
+        uid: 42
+        visible: true
+        name: Visible list
+    -
+        id: 2
+        uid: 42
+        visible: false
+        name: Private list
+
+search:
+    -
+        id: 1
+        term: Saved search
+        uid: 42