PK }mO j j phpdoc.dist.xmlnu W+A
bovigo/callmap API Doc
docs/api
docs/api
src/main/php
PK }mOҗ .travis.ymlnu W+A language: php
php:
- 7.2
- 7.3
- 7.4snapshot
- nightly
matrix:
fast_finish: true
allow_failures:
- php: nightly
- php: 7.4snapshot
install:
- composer install
script:
- vendor/bin/phpunit --coverage-text
after_success:
- composer require php-coveralls/php-coveralls
- travis_retry vendor/bin/php-coveralls
- composer require phpstan/phpstan
- vendor/bin/phpstan analyse
PK }mOqf!W W .coveralls.ymlnu W+A coverage_clover: docs/phpunit/clover.xml
json_path: docs/phpunit/coveralls-upload.json
PK }mO~d
composer.locknu W+A {
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2fee578634e338a9690a7eef34629163",
"packages": [],
"packages-dev": [
{
"name": "bovigo/assert",
"version": "v5.0.0",
"source": {
"type": "git",
"url": "https://github.com/bovigo/assert.git",
"reference": "6bd98242163f1257b706a6cf7a4e9e5e1a8c1f5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bovigo/assert/zipball/6bd98242163f1257b706a6cf7a4e9e5e1a8c1f5e",
"reference": "6bd98242163f1257b706a6cf7a4e9e5e1a8c1f5e",
"shasum": ""
},
"require": {
"php": "^7.2",
"sebastian/comparator": "^3.0",
"sebastian/exporter": "^3.1"
},
"require-dev": {
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": "^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0.x-dev"
}
},
"autoload": {
"psr-4": {
"bovigo\\assert\\": "src/main/php"
},
"files": [
"src/main/php/assert.php",
"src/main/php/predicate/predicates.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Provides assertions for unit tests.",
"time": "2019-04-08T11:44:39+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "ae466f726242e637cebdd526a7d991b9433bacf1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1",
"reference": "ae466f726242e637cebdd526a7d991b9433bacf1",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"ext-pdo": "*",
"ext-phar": "*",
"phpbench/phpbench": "^0.13",
"phpstan/phpstan-phpunit": "^0.11",
"phpstan/phpstan-shim": "^0.11",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.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://www.doctrine-project.org/projects/instantiator.html",
"keywords": [
"constructor",
"instantiate"
],
"time": "2019-10-21T16:45:58+00:00"
},
{
"name": "myclabs/deep-copy",
"version": "1.9.3",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea",
"reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"replace": {
"myclabs/deep-copy": "self.version"
},
"require-dev": {
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
"phpunit/phpunit": "^7.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": "2019-08-09T12:45:53+00:00"
},
{
"name": "phar-io/manifest",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/phar-io/manifest.git",
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-phar": "*",
"phar-io/version": "^2.0",
"php": "^5.6 || ^7.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": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "Developer"
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"time": "2018-07-08T19:23:20+00:00"
},
{
"name": "phar-io/version",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/phar-io/version.git",
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "Developer"
}
],
"description": "Library for handling version information and constraints",
"time": "2018-07-08T19:19:57+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
"reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "~6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.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": "2018-08-07T13:53:10+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "4.3.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"shasum": ""
},
"require": {
"php": "^7.0",
"phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0",
"phpdocumentor/type-resolver": "~0.4 || ^1.0.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
"doctrine/instantiator": "^1.0.5",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.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"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2019-09-12T14:27:41+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
"reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
"shasum": ""
},
"require": {
"php": "^7.1",
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "^7.1",
"mockery/mockery": "~1",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.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"
}
],
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"time": "2019-08-22T18:11:29+00:00"
},
{
"name": "phpspec/prophecy",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203",
"reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.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 || ^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Prophecy\\": "src/Prophecy"
}
},
"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": "2019-10-03T11:07:50+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "7.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa0d179a13284c7420fc281fc32750e6cc7c9e2f",
"reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
"php": "^7.2",
"phpunit/php-file-iterator": "^2.0.2",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^3.1.1",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^4.2.2",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1.3"
},
"require-dev": {
"phpunit/phpunit": "^8.2.2"
},
"suggest": {
"ext-xdebug": "^2.7.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.0-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 provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"time": "2019-09-17T06:24:36+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "050bedf145a257b1ff02746c31894800e5122946"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
"reference": "050bedf145a257b1ff02746c31894800e5122946",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.1"
},
"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": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"time": "2018-09-13T20:33:42+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": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "1038454804406b0b5f5f520358e78c1c2f71501e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e",
"reference": "1038454804406b0b5f5f520358e78c1c2f71501e",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-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": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"time": "2019-06-07T04:22:29+00:00"
},
{
"name": "phpunit/php-token-stream",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "995192df77f63a59e47f025390d2d1fdf8f425ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff",
"reference": "995192df77f63a59e47f025390d2d1fdf8f425ff",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-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": "2019-09-17T06:23:10+00:00"
},
{
"name": "phpunit/phpunit",
"version": "8.4.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "67f9e35bffc0dd52d55d565ddbe4230454fd6a4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/67f9e35bffc0dd52d55d565ddbe4230454fd6a4e",
"reference": "67f9e35bffc0dd52d55d565ddbe4230454fd6a4e",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.2.0",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.9.1",
"phar-io/manifest": "^1.0.3",
"phar-io/version": "^2.0.1",
"php": "^7.2",
"phpspec/prophecy": "^1.8.1",
"phpunit/php-code-coverage": "^7.0.7",
"phpunit/php-file-iterator": "^2.0.2",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^2.1.2",
"sebastian/comparator": "^3.0.2",
"sebastian/diff": "^3.0.2",
"sebastian/environment": "^4.2.2",
"sebastian/exporter": "^3.1.1",
"sebastian/global-state": "^3.0.0",
"sebastian/object-enumerator": "^3.0.3",
"sebastian/resource-operations": "^2.0.1",
"sebastian/type": "^1.1.3",
"sebastian/version": "^2.0.1"
},
"require-dev": {
"ext-pdo": "*"
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*",
"phpunit/php-invoker": "^2.0.0"
},
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "8.4-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": "2019-11-06T09:42:23+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": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
"reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
"shasum": ""
},
"require": {
"php": "^7.1",
"sebastian/diff": "^3.0",
"sebastian/exporter": "^3.1"
},
"require-dev": {
"phpunit/phpunit": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-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": "https://github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
"time": "2018-07-12T15:12:46+00:00"
},
{
"name": "sebastian/diff",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
"reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8.0",
"symfony/process": "^2 || ^3.3 || ^4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-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",
"udiff",
"unidiff",
"unified diff"
],
"time": "2019-02-04T06:01:07+00:00"
},
{
"name": "sebastian/environment",
"version": "4.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
"reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.5"
},
"suggest": {
"ext-posix": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-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": "2019-05-05T09:05:15+00:00"
},
{
"name": "sebastian/exporter",
"version": "3.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e",
"reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e",
"shasum": ""
},
"require": {
"php": "^7.0",
"sebastian/recursion-context": "^3.0"
},
"require-dev": {
"ext-mbstring": "*",
"phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"time": "2019-09-14T09:02:43+00:00"
},
{
"name": "sebastian/global-state",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
"reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
"shasum": ""
},
"require": {
"php": "^7.2",
"sebastian/object-reflector": "^1.1.1",
"sebastian/recursion-context": "^3.0"
},
"require-dev": {
"ext-dom": "*",
"phpunit/phpunit": "^8.0"
},
"suggest": {
"ext-uopz": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.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": "2019-02-01T05:30:01+00:00"
},
{
"name": "sebastian/object-enumerator",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
"reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
"reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
"shasum": ""
},
"require": {
"php": "^7.0",
"sebastian/object-reflector": "^1.1.1",
"sebastian/recursion-context": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.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-08-03T12:35:26+00:00"
},
{
"name": "sebastian/object-reflector",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-reflector.git",
"reference": "773f97c67f28de00d397be301821b06708fca0be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
"reference": "773f97c67f28de00d397be301821b06708fca0be",
"shasum": ""
},
"require": {
"php": "^7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
"time": "2017-03-29T09:07:27+00:00"
},
{
"name": "sebastian/recursion-context",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
"reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
"shasum": ""
},
"require": {
"php": "^7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.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": "2017-03-03T06:23:57+00:00"
},
{
"name": "sebastian/resource-operations",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/resource-operations.git",
"reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
"reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-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": "2018-10-04T04:07:39+00:00"
},
{
"name": "sebastian/type",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3",
"reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3",
"shasum": ""
},
"require": {
"php": "^7.2"
},
"require-dev": {
"phpunit/phpunit": "^8.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-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": "Collection of value objects that represent the types of the PHP type system",
"homepage": "https://github.com/sebastianbergmann/type",
"time": "2019-07-02T08:10:15+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/polyfill-ctype",
"version": "v1.12.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "550ebaac289296ce228a706d0867afc34687e3f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4",
"reference": "550ebaac289296ce228a706d0867afc34687e3f4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.12-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"time": "2019-08-06T08:03:45+00:00"
},
{
"name": "theseer/tokenizer",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
"reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
"reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": "^7.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"time": "2019-06-13T22:48:21+00:00"
},
{
"name": "webmozart/assert",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "88e6d84706d09a236046d686bbea96f07b3a34f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4",
"reference": "88e6d84706d09a236046d686bbea96f07b3a34f4",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"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": "2019-08-24T08:43:50+00:00"
},
{
"name": "xp-framework/core",
"version": "v9.10.0",
"source": {
"type": "git",
"url": "https://github.com/xp-framework/core.git",
"reference": "ff3d06223e16a8b72fe1c0523092775b43ebf18d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/xp-framework/core/zipball/ff3d06223e16a8b72fe1c0523092775b43ebf18d",
"reference": "ff3d06223e16a8b72fe1c0523092775b43ebf18d",
"shasum": ""
},
"require": {
"php": ">=7.0.0"
},
"suggest": {
"php": ">=7.1.0"
},
"type": "library",
"autoload": {
"files": [
"src/main/php/__xp.php",
"src/main/resources/autoload.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "The XP framework is an all-purpose, object oriented PHP framework.",
"homepage": "http://xp-framework.net/",
"keywords": [
"framework",
"xp"
],
"time": "2019-10-04T09:02:22+00:00"
},
{
"name": "xp-framework/unittest",
"version": "v9.7.1",
"source": {
"type": "git",
"url": "https://github.com/xp-framework/unittest.git",
"reference": "70bdc4bdd801b8b4d8bb8eb43589d90fc797d78e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/xp-framework/unittest/zipball/70bdc4bdd801b8b4d8bb8eb43589d90fc797d78e",
"reference": "70bdc4bdd801b8b4d8bb8eb43589d90fc797d78e",
"shasum": ""
},
"require": {
"php": ">=5.6.0",
"xp-framework/core": "^9.0 | ^8.0 | ^7.0 | ^6.10"
},
"bin": [
"bin/xp.xp-framework.unittest.test"
],
"type": "library",
"autoload": {
"files": [
"src/main/php/autoload.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Unittests for the XP Framework",
"homepage": "http://xp-framework.net/",
"keywords": [
"module",
"xp"
],
"time": "2019-08-22T16:33:01+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": "^7.2"
},
"platform-dev": []
}
PK }mO(]5
CODE_OF_CONDUCT.mdnu W+A # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at team@bovigo.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
PK }mOnKP KP README.mdnu W+A bovigo/callmap
==============
Allows to stub and mock method and function calls by applying a callmap.
Compatible with any [unit test framework](http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#PHP).
Package status
--------------
[![Build Status](https://secure.travis-ci.org/bovigo/callmap.png)](http://travis-ci.org/bovigo/callmap) [![Build Status Windows](https://ci.appveyor.com/api/projects/status/t36eyscvd5057fpv?svg=true)](https://ci.appveyor.com/project/mikey179/callmap/branch/master) [![Coverage Status](https://coveralls.io/repos/github/bovigo/callmap/badge.svg?branch=master)](https://coveralls.io/github/bovigo/callmap?branch=master)
[![Latest Stable Version](https://poser.pugx.org/bovigo/callmap/version.png)](https://packagist.org/packages/bovigo/callmap) [![Latest Unstable Version](https://poser.pugx.org/bovigo/callmap/v/unstable.png)](//packagist.org/packages/bovigo/callmap)
Installation
------------
_bovigo/callmap_ is distributed as [Composer](https://getcomposer.org/) package.
To install it as a development dependency of your package use the following
command:
composer require --dev "bovigo/callmap": "^5.0"
To install it as a runtime dependency for your package use the following command:
composer require "bovigo/callmap=^5.0"
Requirements
------------
_bovigo/callmap_ requires at least PHP 7.2.
For argument verification one of the following packages is required:
* [bovigo/assert](https://github.com/bovigo/assert) (since release 2.0.0)
* [PHPUnit](https://phpunit.de/)
* [xp-framework/unittest](https://github.com/xp-framework/unittest) (since release 1.1.0)
The order specified here is also the one in which the verification logic will
select the assertions to be used for argument verification. This means even if
you run your tests with _PHPUnit_ but _bovigo/assert_ is present as well argument
verification will be done with the latter.
Usage
-----
Explore the [tests](https://github.com/bovigo/callmap/tree/master/src/test/php)
to see how _bovigo/callmap_ can be used. For the very eager, here's a code
example which features almost all of the possibilities:
```php
// set up the instance to be used
$yourClass = NewInstance::of(YourClass::class, ['some', 'arguments'])
->returns([
'aMethod' => 313,
'otherMethod' => function() { return 'yeah'; },
'play' => onConsecutiveCalls(303, 808, 909, throws(new \Exception('error')),
'ups' => throws(new \Exception('error')),
'hey' => 'strtoupper'
]);
// do some stuff, e.g. execute the logic to test
...
// verify method invocations and received arguments
verify($yourClass, 'aMethod')->wasCalledOnce();
verify($yourClass, 'hey')->received('foo');
```
However, if you prefer text instead of code, read on.
Note: for the sake of brevity below it is assumed the used classes and functions
are imported into the current namespace via
```php
use bovigo\callmap\NewInstance;
use bovigo\callmap\NewCallable;
use function bovigo\callmap\throws;
use function bovigo\callmap\onConsecutiveCalls;
use function bovigo\callmap\verify;
```
### Specify return values for method invocations ###
As the first step, you need to get an instance of the class, interface or trait
you want to specify return values for. To do this, _bovigo/callmap_ provides two
possibilities. The first one is to create a new instance where this instance is
a proxy to the actual class:
```php
$yourClass = NewInstance::of(YourClass::class, ['some', 'arguments']);
```
This creates an instance where each method call is passed to the original class
in case no return value was specified via the callmap. Also, it calls the
constructor of the class to instantiate of. If the class doesn't have a
constructor, or you create an instance of an interface or trait, the list of
constructor arguments can be left away.
The other option is to create a complete stub:
```php
$yourClass = NewInstance::stub(YourClass::class);
```
Instances created that way don't forward method calls.
Ok, so we created an instance of the thing that we want to specify return values
for, how to do that?
```php
$yourClass->returns([
'aMethod' => 303,
'otherMethod' => function() { return 'yeah'; }
]);
```
We simply pass a callmap to the `returns()` method. Now, if something calls
`$yourClass->aMethod()`, the return value will always be `303`. In the case of
`$yourClass->otherMethod()`, the callable will be evaluated and its return value
will be returned.
Please be aware that the array provided with the `returns()` method should
contain all methods that should be stubbed. If you call this method a second
time the complete callmap will be replaced:
```php
$yourClass->returns(['aMethod' => 303]);
$yourClass->returns(['otherMethod' => function() { return 'yeah'; }]);
```
As a result of this, `$yourClass->aMethod()` is not set any more to return `303`.
### Default return values ###
Depending on what is instantiated and how, there will be default return values
for the case that no call mapping has been passed for a method which actually is
called.
1. Interfaces
Default return value is always `null`, except the return type declaration
specifies the interface itself and is not optional, or the `@return` type
hint in the doc comment specifies the short class name or the fully
qualified class name of the interface itself or any other interface it
extends. In that case the default return value will be the instance itself.
2. Traits
When instantiated with `NewInstance::of()` the default return value will be
the value a call to the according method returns.
When instantiated with `NewInstance::stub()` and for abstract methods the
default return value is `null`, except the `@return` type hint in the doc
comment specifies `$this` or `self`.
3. Classes
When instantiated with `NewInstance::of()` the default return value will be
the value which is returned by the according method of the original class.
When instantiated with `NewInstance::stub()` and for abstract methods the
default return value is `null`, except the return type declaration specifies
the class itself and is not optional, or the `@return` type hint in the doc
comment specifies `$this` or `self`, the short class name or the fully
qualified class name of the class or of a parent class or any interface the
class implements. Exception to this: if the return type is `\Traversable`
and the class implements this interface return value will be `null`.
### Specify a series of return values ###
Sometimes a method gets called more than once and you need to specify different
return values for each call.
```php
$yourClass->returns(['aMethod' => onConsecutiveCalls(303, 808, 909)]);
```
This will return a different value on each invocation of `$yourClass->aMethod()`
in the order of the specified return values. If the method is called more often
than return values are specified, each subsequent call will return the default
return value as if no call mapping has been specified.
### I want to return a callable, but it is executed on method invocation ###
Because callables are executed when the method is invoked it is required to wrap
them into another callable. To ease this, the `wrap()` function is provided:
```php
$yourClass->returns(['aMethod' => wrap(function() { })]);
$this->assertTrue(is_callable($yourClass->aMethod()); // true
```
The reason it is that way is that it is far more likely you want to calculate
the return value with a callable instead of simply returning the callable as a
result of the method call.
### Let's throw an exception ###
Sometimes you don't need to specify a return value, but want the method to throw
an exception on invocation. Of course you could do that by providing a callable
in the callmap which throws the exception, but there's a more handy way available:
```php
$yourClass->returns(['aMethod' => throws(new \Exception('error'))]);
```
Now each call to this method will throw this exception. Since release 3.1.0 it
is also possible to throw an `\Error` (basically, any `\Throwable` for that
matter):
```php
$yourClass->returns(['aMethod' => throws(new \Error('error'))]);
```
Of course this can be combined with a series of return values:
```php
$yourClass->returns(['aMethod' => onConsecutiveCalls(303, throws(new \Exception('error')))]);
```
Here, the first invocation of `$yourClass->aMethod()` will return `303`, whereas
the second call will lead to the exception being thrown.
In case a method gets invoked more often than results are defined with
`onConsecutiveCalls()` then it falls back to the default return value (see above).
### Is there a way to access the passed arguments? ###
It might be useful to use the arguments passed to a method before returning a
value. If you specify a callable this callable will receive all arguments passed
to the method:
```php
$yourClass->returns(['aMethod' => function($arg1, $arg2) { return $arg2;}]);
echo $yourClass->aMethod(303, 'foo'); // prints foo
```
However, if a method has optional parameters the default value will *not* be
passed as argument if it wasn't given in the actual method call. Only explicitly
passed arguments will be forwarded to the callable.
### Do I have to specify a closure or can I use an arbitrary callable? ###
You can:
```php
$yourClass->returns(['aMethod' => 'strtoupper']);
echo $yourClass->aMethod('foo'); // prints FOO
```
### How do I specify that an object returns itself? ###
Actually, you don't. _bovigo/callmap_ is smart enough to detect when it should
return the object instance instead of null when no call mapping for a method was
provided. To achieve that, _bovigo/callmap_ tries to detect the return type of a
method from either from the return type hint or the method's doc comment. If the
return type specified is the class or interface itself it will return the
instance instead of null, except when the return type hint allows null.
If no return type is defined and the return type specified in the doc comment is
one of `$this`, `self`, the short class name or the fully qualified class name
of the class or of a parent class or any interface the class implements, it will
return the instance instead of null.
Exception to this: if the return type is `\Traversable` this doesn't apply, even
if the class implements this interface.
Please note that `@inheritDoc` is not supported.
In case this leads to a false interpretation and the instance is returned when
in fact it should not, you can always overrule that by explicitly stating a
return value in the callmap.
### Which methods can be used in the callmap? ###
Only non-static, non-final public and protected methods can be used.
In case you want to map a private, or a final, or a static method you are out of
luck. Probably you should rethink your class design.
Oh, and of course you can't use all of this with a class which is declared as
final.
### What happens if a method specified in the callmap doesn't exist? ###
In case the callmap contains a method which doesn't exist or is not applicable
for mapping (see above) `returns()` will throw an `\InvalidArgumentException`.
This also prevents typos and wondering why something doesn't work as expected.
### Verify method invocations ###
Sometimes it is required to ensure that a method was invoked a certain amount of
times. In order to do that, _bovigo/callmap_ provides the `verify()` function:
```php
verify($yourClass, 'aMethod')->wasCalledOnce();
```
In case it was not called exactly once, this will throw a `CallAmountViolation`.
Otherwise, it will simply return true. This allows you to use it in an assertion
in case the test method doesn't have any other assertion and you want to have one:
```php
$this->assertTrue(verify($yourClass, 'aMethod')->wasCalledOnce());
```
Of course you can verify the call amount even if you didn't specify the method
in the callmap.
Here is a list of methods that the instance returned by `verify()` offers for
verifying the amount of method invocations:
* `wasCalledAtMost($times)`
Asserts that the method was invoked at maximum the given amount of times.
* `wasCalledAtLeastOnce()`
Asserts that the method was invoked at least once.
* `wasCalledAtLeast($times)`
Asserts that the method was invoked at minimum the given amount of times.
* `wasCalledOnce()`
Asserts that the method was invoked exactly once.
* `wasCalled($times)`
Asserts that the method was invoked exactly the given amount of times.
* `wasNeverCalled()`
Asserts that the method was never invoked.
In case the method to check doesn't exist or is not applicable for mapping (see
above) all of those methods throw an `\InvalidArgumentException`. This also
prevents typos and wondering why something doesn't work as expected.
By the way, if PHPUnit is available, `CallAmountViolation` will extend
`PHPUnit\Framework\ExpectationFailedException`. In case it isn't available it
will simply extend `\Exception`.
### Verify passed arguments ###
_Please note that for this feature a framework which provides assertions must be
present. Please see the requirements section above for the list of currently
supported assertion frameworks._
In some cases it is useful to verify that an instance received the correct
arguments. You can do this with `verify()` as well:
```php
verify($yourClass, 'aMethod')->received(303, 'foo');
```
This will verify that each of the expected arguments matches the actually
received arguments of the first invocation of that method. In case you want to
verify another invocation, we got you covered:
```php
verify($yourClass, 'aMethod')->receivedOn(3, 303, 'foo');
```
This applies verification to the arguments the method received on the third
invocation.
There is also a shortcut to verify that the method didn't receive any arguments:
```php
verify($yourClass, 'aMethod')->receivedNothing(); // received nothing on first invocation
verify($yourClass, 'aMethod')->receivedNothing(3); // received nothing on third invocation
```
In case the method wasn't invoked (that much), a `MissingInvocation` exception
will be thrown.
In case the method received less arguments than expected, a `ArgumentMismatch`
exception will be thrown. It will also be thrown when `receivedNothing()` detects
that at least one argument was received.
Please not that each method has its own invocation count (whereas in PHPUnit the
invocation count is for the whole mock object). Also, invocation count starts at
1 for the first invocation, not at 0.
If the verification succeeds, it will simply return true. This allows you to use
it in an assertion in case the test method doesn't have any other assertion and
you want to have one:
```php
$this->assertTrue(verify($yourClass, 'aMethod')->receivedNothing());
```
In case the verification fails an exception will be thrown. Which exactly
depends on the available assertion framework.
#### Verification details for bovigo/assert
_Available since release 2.0.0._
Both `reveived()` and `receivedOn()` also accept any instance of
`bovigo\assert\predicate\Predicate`:
```php
verify($yourClass, 'aMethod')->received(isInstanceOf('another\ExampleClass'));
```
In case a bare value is passed it is assumed that `bovigo\assert\predicate\equals()`
is meant. Additionally, instances of `PHPUnit\Framework\Constraint\Constraint`
are accepted as well as _bovigo/assert_ knows how to handle those.
In case the verification fails an `bovigo\assert\AssertionFailure` will be
thrown. In case _PHPUnit_ is available as well this exception is also an instance
of `PHPUnit\Framework\ExpectationFailedException`.
#### Verification details for PHPUnit
Both `reveived()` and `receivedOn()` also accept any instance of `PHPUnit\Framework\Constraint\Constraint`:
```php
verify($yourClass, 'aMethod')->received($this->isInstanceOf('another\ExampleClass'));
```
In case a bare value is passed it is assumed that `PHPUnit\Framework\Constraint\IsEqual`.
In case the verification fails an `PPHPUnit\Framework\ExpectationFailedException`
will be thrown by the used `PHPUnit\Framework\Constraint\Constraint`.
#### Verification details for xp-framework/unittest
_Available since release 1.1.0._
In case xp-framework/unittest is present, `\util\Objects::equal()` will be used.
In case the verification fails an `\unittest\AssertionFailedError` will be
thrown.
### Mocking injected functions
_Available since release 3.1.0._
Sometimes it is necessary to mock a function. This can be cases like when PHP's
native `fsockopen()` function is used. One way would be to redefine this
function in the namespace where it is called, and let this redefinition decide
what to do.
```php
class Socket
{
public function connect(string $host, int $port, float $timeout)
{
$errno = 0;
$errstr = '';
$resource = fsockopen($host, $port, $errno, $errstr, $timeout);
if (false === $resource) {
throw new ConnectionFailure(
'Connect to ' . $host . ':'. $port
. ' within ' . $timeout . ' seconds failed: '
. $errstr . ' (' . $errno . ').'
);
}
// continue working with $resource
}
// other methods here
}
```
However, this approach is not as optimal, as most likely it is required to not
just mock the function, but to also evaluate whether it was called and maybe
if it was called with the correct arguments.
_bovigo/callmap_ suggests to use function injection for this. Instead of
hardcoding the usage of the `fsockopen()` function or even to introduce a new
interface just for the sake of abstracting this function, why not inject the
function as a callable?
```php
class Socket
{
private $fsockopen = 'fsockopen';
public function openWith(callable $fsockopen)
{
$this->fsockopen = $fsockopen;
}
public function connect(string $host, int $port, float $timeout)
{
$errno = 0;
$errstr = '';
$fsockopen = $this->fsockopen;
$resource = $fsockopen($host, $port, $errno, $errstr, $timeout);
if (false === $resource) {
throw new ConnectionFailure(
'Connect to ' . $host . ':'. $port
. ' within ' . $timeout . ' seconds failed: '
. $errstr . ' (' . $errno . ').'
);
}
// continue working with $resource
}
// other methods here
}
```
Now a mocked callable can be generated with _bovigo/callmap_:
```php
class SocketTest extends \PHPUnit\Framework\TestCase
{
/**
* @expectedException ConnectionFailure
*/
public function testSocketFailure()
{
$socket = new Socket();
$socket->openWith(NewCallable::of('fsockopen')->returns(false));
$socket->connect('example.org', 80, 1.0);
}
}
```
As with `NewInstance::of()` the callable generated with `NewCallable::of()` will
call the original function when no return value is specified via the `returns()`
method. In case the mocked function must not be called the callable can be
generated with `NewCallable::stub()` instead:
```php
$strlen = NewCallable::of('strlen');
// int(5), as original function will be called because no mapped return value defined
var_dump($strlen('hello'));
$strlen = NewCallable::stub('strlen');
// NULL, as no return value defined and original function not called
var_dump($strlen('hello'));
```
As with a callmap for a method, several different invocation results can be set:
```php
NewCallable::of('strlen')->returns(onConsecutiveCalls(5, 9, 10));
NewCallable::of('strlen')->returns(throws(new \Exception('failure!')));
```
For the latter, since release 3.2.0 a shortcut is available:
```php
NewCallable::of('strlen')->throws(new \Exception('failure!'));
```
It is also possible to verify function invocations, as can be done with method
invocations:
```php
$strlen = NewCallable::of('strlen');
// do something with $strlen
verify($strlen)->wasCalledOnce();
verify($strlen)->received('Hello world');
```
Everything that applies to method verification can be applied to function
verification, [see above](#verify-method-invocations). The only difference is
that the second parameter for `verify()` can be left away, as there is no method
that must be named.
PK }mO&
.gitignorenu W+A docs/**
vendor
PK }mOWO src/main/php/Proxy.phpnu W+A *() instead
* @param string $method
* @return Invocations
* @throws \InvalidArgumentException in case the method does not exist or is not applicable
* @since 3.1.0
*/
public function invocations(string $method): Invocations;
}
PK }mO. src/main/php/ClassProxy.phpnu W+A invocations($method));
}
/**
* determines return type
*
* @internal
* @param \ReflectionFunctionAbstract $function
* @return string
*/
function determineReturnTypeOf(\ReflectionFunctionAbstract $function): string
{
$returnType = $function->getReturnType();
if (null === $returnType) {
return '';
}
if ($returnType->isBuiltin()) {
return ': ' . $returnType->getName();
}
if ('self' == $returnType->getName()) {
if ($function instanceof \ReflectionMethod) {
return ': ' . ($returnType->allowsNull() ? '?' : '') . '\\' . $function->getDeclaringClass()->getName();
}
throw new \UnexpectedValueException('Function ' . $function->getName() . ' defines return type self but that is not possible.');
}
return ': ' . ($returnType->allowsNull() ? '?' : '') . '\\' . $returnType->getName();
}
/**
* returns correct representation of parameters for given method
*
* @internal
* @param \ReflectionFunctionAbstract $function
* @return array
*/
function paramsOf(\ReflectionFunctionAbstract $function): array
{
$params = [];
foreach ($function->getParameters() as $parameter) {
/* @var $parameter \ReflectionParameter */
$param = '';
if ($parameter->isArray()) {
$param .= 'array ';
} elseif ($parameter->getClass() !== null) {
$param .= '\\' . $parameter->getClass()->getName() . ' ';
} elseif ($parameter->isCallable()) {
$param .= 'callable ';
} else {
$paramType = $parameter->getType();
if (null !== $paramType) {
$param .= $paramType->getName() . ' ';
}
}
if ($parameter->isPassedByReference()) {
$param .= '&';
}
if ($parameter->isVariadic()) {
$param .= '...';
}
$param .= '$' . $parameter->getName();
if (!$parameter->isVariadic() && $parameter->isOptional()) {
if ($function->isInternal() || $parameter->allowsNull()) {
$param .= ' = null';
} else {
$param .= ' = ' . var_export($parameter->getDefaultValue(), true);
}
}
$params[$parameter->getName()] = $param;
}
return ['names' => array_keys($params), 'string' => join(', ', $params)];
}
/**
* internal helper function to be able to mock eval in tests
*
* Since eval() is a language construct and not a function but we want to
* mock it when testing dynamic code creation we wrap it into our own
* function.
*
* @param string $code
* @return bool
* @since 3.0.0
* @internal
*/
function compile(string $code)
{
return eval($code);
}
/**
* blacklist our own classes from being displayed in PHPUnit error stacks
*/
if (class_exists('\PHPUnit\Util\Blacklist')) {
\PHPUnit\Util\Blacklist::$blacklistedClassNames = array_merge(
\PHPUnit\Util\Blacklist::$blacklistedClassNames,
[Verification::class => 1]
);
}
}
PK }mOq " src/main/php/InvocationResults.phpnu W+A results = $results;
}
/**
* checks whether a result for the invocation with the given number exists
*
* @param int $number
* @return bool
*/
public function hasResultForInvocation(int $number): bool
{
return isset($this->results[$number]);
}
/**
* returns the result for invocation with the given number
*
* @param int $number
* @return mixed
*/
public function resultForInvocation(int $number)
{
return $this->results[$number] ?? null;
}
}
PK }mO-Vi src/main/php/Invocations.phpnu W+A name = $name;
$this->paramNames = $paramNames;
}
/**
* returns name of method or function these invocations are from
*
* @return string
*/
public function name(): string
{
return $this->name;
}
/**
* records method/function call
*
* @param mixed[] $arguments list of passed arguments
* @return int amount of calls for given method
*/
public function recordCall(array $arguments): int
{
$this->callHistory[] = $arguments;
return count($this->callHistory);
}
/**
* returns amount of calls received
*
* @return int
*/
public function count(): int
{
return count($this->callHistory);
}
/**
* returns name of argument at requested position
*
* Returns null if there is no argument at requested position or the name
* of that argument is unknown.
*
* @param int $argumentPosition
* @param string $suffix optional string to append after argument name
* @return string|null
*/
public function argumentName(int $argumentPosition, string $suffix = ''): ?string
{
if (isset($this->paramNames[$argumentPosition])) {
return '$' . $this->paramNames[$argumentPosition] . $suffix;
}
return null;
}
/**
* returns the arguments received for a specific invocation
*
* @param int $invocation nth invocation to check, defaults to 1 aka first invocation
* @return mixed[]
* @throws \bovigo\callmap\MissingInvocation in case no such invocation was received
*/
public function argumentsOf(int $invocation = 1): array
{
if (isset($this->callHistory[$invocation - 1])) {
return $this->callHistory[$invocation - 1];
}
$totalInvocations = $this->count();
throw new MissingInvocation(sprintf(
'Missing invocation #%d for %s, was %s.',
$invocation,
$this->name,
($totalInvocations === 0 ?
'never called' :
('only called ' . ($totalInvocations === 1 ?
'once' : $totalInvocations . ' times')
)
)
));
}
}
PK }mO: x- - src/main/php/NewInstance.phpnu W+A newInstanceArgs($constructorArgs);
}
/**
* returns a new stub of the given class or interface
*
* The instance is created without calling the constructor of the target
* class. In contrast to instances returned by of(), method calls are not
* passed to the target method if no mapping exists, but return null.
*
* @api
* @param string|object $target interface or class to create a new instance of
* @return \bovigo\callmap\ClassProxy
*/
public static function stub($target): ClassProxy
{
return self::callMapClass($target)
->newInstanceWithoutConstructor()
->preventParentCalls();
}
/**
* returns the class name of any new instance for given target class or interface
*
* @api
* @param string|object $target
* @return string
* @since 0.2.0
*/
public static function classname($target): string
{
return self::callMapClass($target)->getName();
}
/**
* returns the proxy class for given target class or interface
*
* @param string|object $target
* @return \ReflectionClass
*/
private static function callMapClass($target): \ReflectionClass
{
$class = self::reflect($target);
if (!isset(self::$classes[$class->getName()])) {
self::$classes[$class->getName()] = self::forkCallMapClass($class);
}
return self::$classes[$class->getName()];
}
/**
* reflects given class value
*
* @param string|object $class
* @return \ReflectionClass
* @throws \InvalidArgumentException
*/
private static function reflect($class): \ReflectionClass
{
if (is_string($class) && (class_exists($class) || interface_exists($class) || trait_exists($class))) {
return new \ReflectionClass($class);
} elseif (is_object($class)) {
return new \ReflectionObject($class);
}
throw new \InvalidArgumentException(
'Given class must either be an existing class, interface or'
. ' trait name or class instance, ' . \gettype($class)
. ' with value "' . $class . '" given'
);
}
/**
* reference to compile function
*
* @type callable
* @internal
*/
public static $compile = __NAMESPACE__ . '\compile';
/**
* creates a new class from the given class which uses the CallMap trait
*
* @param \ReflectionClass $class
* @return \ReflectionClass
* @throws ProxyCreationFailure
*/
private static function forkCallMapClass(\ReflectionClass $class): \ReflectionClass
{
if ($class->isTrait()) {
$class = self::forkTrait($class);
}
try {
$compile = self::$compile;
$compile(self::createCallmapProxyCode($class));
} catch (\ParseError $pe) {
throw new ProxyCreationFailure(
'Failure while creating CallMap instance of '
. $class->getName() . ': ' . $pe->getMessage(),
$pe
);
}
return new \ReflectionClass($class->getName() . 'CallMapProxy');
}
/**
* create an intermediate class for the trait so that any methods of the
* trait become callable as parent
*
* @param \ReflectionClass $class
* @return \ReflectionClass
* @throws ProxyCreationFailure
*/
private static function forkTrait(\ReflectionClass $class): \ReflectionClass
{
$code = sprintf(
"abstract class %sCallMapFork {\n"
. " use \%s;\n}",
$class->getShortName(),
$class->getName()
);
if ($class->inNamespace()) {
$code = sprintf(
"namespace %s {\n%s}\n",
$class->getNamespaceName(),
$code
);
}
try {
$compile = self::$compile;
$compile($code);
} catch (\ParseError $pe) {
throw new ProxyCreationFailure(
'Failure while creating forked trait instance of '
. $class->getName() . ': ' . $pe->getMessage(),
$pe
);
}
return new \ReflectionClass($class->getName() . 'CallMapFork');
}
/**
* creates code for new class
*
* @param \ReflectionClass $class
* @return string
*/
private static function createCallmapProxyCode(\ReflectionClass $class): string
{
if ($class->isFinal()) {
throw new \InvalidArgumentException(
'Can not create mapping proxy for final class '
. $class->getName()
);
}
$code = self::createClassDefinition($class)
. self::createMethods($class)
. "}\n";
if ($class->inNamespace()) {
return sprintf(
"namespace %s {\n%s}\n",
$class->getNamespaceName(),
$code
);
}
return $code;
}
/**
* creates class definition for the proxy
*
* @param \ReflectionClass $class
* @return string
*/
private static function createClassDefinition(\ReflectionClass $class): string
{
return sprintf(
"class %sCallMapProxy %s \\%s %s\bovigo\callmap\ClassProxy {\n"
. " use \bovigo\callmap\ClassProxyMethodHandler;\n",
$class->getShortName(),
$class->isInterface() ? 'implements ' : 'extends ',
$class->getName(),
$class->isInterface() ? ',' : ' implements '
);
}
/**
* creates methods for the proxy
*
* @param \ReflectionClass $class
* @return string
*/
private static function createMethods(\ReflectionClass $class): string
{
$code = '';
$methods = [];
$params = [];
$voidMethods = [];
foreach (self::methodsOf($class) as $method) {
$return = true;
$returnType = determineReturnTypeOf($method);
if ($returnType === ': void') {
$voidMethods[$method->getName()] = $method->getName();
$return = false;
}
$param = paramsOf($method);
/* @var $method \ReflectionMethod */
$code .= sprintf(
" %s function %s(%s)%s {\n"
. " %s\$this->handleMethodCall('%s', func_get_args(), %s);\n"
. " }\n",
($method->isPublic() ? 'public' : 'protected'),
$method->getName(),
$param['string'],
$returnType,
$return ? 'return ' : '',
$method->getName(),
self::shouldReturnSelf($class, $method) ? 'true' : 'false'
);
$methods[] = "'" . $method->getName() . "' => '" . $method->getName() . "'";
$params[$method->getName()] = $param['names'];
}
return $code . sprintf(
"\n private \$_allowedMethods = [%s];\n",
join(', ', $methods)
) . sprintf(
"\n private \$_methodParams = %s;\n",
var_export($params, true)
) . sprintf(
"\n private \$_voidMethods = %s;\n",
var_export($voidMethods, true)
);
}
/**
* returns applicable methods for given class
*
* @param \ReflectionClass $class
* @return \Iterator
*/
private static function methodsOf(\ReflectionClass $class): \Iterator
{
return new \CallbackFilterIterator(
new \ArrayIterator($class->getMethods()),
function(\ReflectionMethod $method)
{
return !$method->isPrivate()
&& !$method->isFinal()
&& !$method->isStatic()
&& !$method->isConstructor()
&& !$method->isDestructor();
}
);
}
/**
* detects whether a method should return the instance or null
*
* @param \ReflectionClass $class
* @param \ReflectionMethod $method
* @return bool
*/
private static function shouldReturnSelf(\ReflectionClass $class, \ReflectionMethod $method): bool
{
$returnType = self::detectReturnType($method);
if (null === $returnType) {
return false;
}
if (in_array($returnType, ['$this', 'self', $class->getName(), $class->getShortName()])) {
return true;
}
foreach ($class->getInterfaces() as $interface) {
if ($interface->getName() !== 'Traversable' && ($interface->getName() === $returnType || $interface->getShortName() === $returnType)) {
return true;
}
}
while ($parent = $class->getParentClass()) {
if ($parent->getName() === $returnType || $parent->getShortName() === $returnType) {
return true;
}
$class = $parent;
}
return false;
}
/**
* detects return type of method
*
* It will make use of reflection to detect the return type. In case this
* does not yield a result the doc comment will be parsed for the return
* annotation.
*
* @param \ReflectionMethod $method
* @return string|null
*/
private static function detectReturnType(\ReflectionMethod $method): ?string
{
$returnType = $method->getReturnType();
if (null !== $returnType) {
if ($returnType->allowsNull()) {
return null;
}
return $returnType->getName();
}
$docComment = $method->getDocComment();
if (false === $docComment) {
return null;
}
$returnPart = strstr($docComment, '@return');
if (false === $returnPart) {
return null;
}
$returnParts = explode(' ', trim(str_replace('@return', '', $returnPart)));
$returnType = ltrim(trim($returnParts[0]), '\\');
if (empty($returnType) || strpos($returnType, '*') !== false) {
return null;
}
return $returnType;
}
}
PK }mOB8ԕ " src/main/php/MissingInvocation.phpnu W+A getCode(), $cause);
}
}
PK }mO! ! src/main/php/ArgumentMismatch.phpnu W+A parentCallsAllowed = false;
return $this;
}
/**
* sets the call map with return values
*
* @api
* @since 3.2.0
* @param array $callMap
* @return ClassProxy
* @throws \InvalidArgumentException in case any of the mapped methods does not exist or is not applicable
*/
public function returns(array $callMap): ClassProxy
{
foreach (array_keys($callMap) as $method) {
if (!isset($this->_allowedMethods[$method]) || isset($this->_voidMethods[$method])) {
throw new \InvalidArgumentException(
$this->canNot('map', $method)
);
}
}
$this->callMap = new CallMap($callMap);
return $this;
}
/**
* handles actual method calls
*
* @param string $method actually called method
* @param mixed[] $arguments list of given arguments for methods
* @param bool $shouldReturnSelf whether the return value should be the instance itself
* @return mixed
* @throws \Exception
*/
protected function handleMethodCall(string $method, array $arguments, bool $shouldReturnSelf)
{
$invocation = $this->invocations($method)->recordCall($arguments);
if (null !== $this->callMap && $this->callMap->hasResultFor($method, $invocation)) {
return $this->callMap->resultFor($method, $arguments, $invocation);
}
if ($this->parentCallsAllowed && is_callable(['parent', $method])) {
// is_callable() returns true even for abstract methods
$refMethod = new \ReflectionMethod(get_parent_class(), $method);
if (!$refMethod->isAbstract()) {
return parent::$method(...$arguments);
}
}
if ($shouldReturnSelf) {
return $this;
}
return null;
}
/**
* returns recorded invocations for given method
*
* @param string $method
* @return Invocations
* @throws \InvalidArgumentException in case the method does not exist or is not applicable
* @since 3.1.0
*/
public function invocations(string $method): Invocations
{
if (empty($method)) {
throw new \InvalidArgumentException(
'Please provide a method name to retrieve invocations for.'
);
}
if (!isset($this->_allowedMethods[$method])) {
throw new \InvalidArgumentException(
$this->canNot('retrieve invocations for', $method)
);
}
if (!isset($this->invocations[$method])) {
$this->invocations[$method] = new Invocations(
$this->completeNameOf($method),
$this->_methodParams[$method]
);
}
return $this->invocations[$method];
}
/**
* returns complete name of the proxied class/interface/trait method
*
* @param string $method actual method to return name for
* @return string
*/
private function completeNameOf(string $method): string
{
return str_replace(
['CallMapProxy', 'CallMapFork'],
'',
get_class($this)
) . '::' . $method . '()';
}
/**
* creates complete error message that invalid method can not be used
*
* @param string $message
* @param string $invalidMethod
*/
private function canNot(string $message, string $invalidMethod): string
{
if (isset($this->_voidMethods[$invalidMethod])) {
$reason = 'is declared as returning void.';
} elseif (method_exists($this, $invalidMethod)) {
$reason = 'is not applicable for mapping.';
} else {
$reason = 'does not exist. Probably a typo?';
}
return sprintf(
'Trying to %s method %s, but it %s',
$message,
$this->completeNameOf($invalidMethod),
$reason
);
}
}
PK }mOʒ} } src/main/php/FunctionProxy.phpnu W+A name = $functionName;
$this->invocations = new Invocations($functionName, $this->paramNames);
}
/**
* sets the call map to use
*
* @api
* @param mixed $returnValue
* @return $this
* @throws \LogicException when mapped function is declared as returning void
* @since 3.2.0
*/
public function returns($returnValue): self
{
if ($this->returnVoid) {
throw new \LogicException(
'Trying to map function ' . $this->name
. '(), but it is declared as returning void.'
);
}
$this->callMap = new CallMap(['function' => $returnValue]);
return $this;
}
/**
* shortcut for returns(throws($e))
*
* @api
* @param \Throwable $e
* @return $this
* @since 3.2.0
*/
public function throws(\Throwable $e): self
{
$this->callMap = new CallMap(['function' => throws($e)]);
return $this;
}
/**
* handles actual function calls
*
* @param mixed[] $arguments list of given arguments for function
* @return mixed
*/
protected function handleFunctionCall(array $arguments)
{
$invocation = $this->invocations->recordCall($arguments);
if (null !== $this->callMap && $this->callMap->hasResultFor('function', $invocation)) {
return $this->callMap->resultFor('function', $arguments, $invocation);
}
if ($this->parentCallsAllowed) {
$originalFunction = $this->invocations->name();
return $originalFunction(...$arguments);
}
return null;
}
/**
* returns recorded invocations for function
*
* @internal use verify($proxy)->*() instead
* @param string $method param is ignored
* @return Invocations
*/
public function invocations(string $method): Invocations
{
return $this->invocations;
}
}
PK }mOZ~ src/main/php/CallMap.phpnu W+A callMap = $callMap;
}
/**
* checks whether callmap has a result for the invocation of method
*
* @param string $method name of invoked method
* @param int $invocationCount denotes which nth invocation of the method this is
* @return bool
*/
public function hasResultFor(string $method, int $invocationCount): bool
{
if (!array_key_exists($method, $this->callMap)) {
return false;
}
if ($this->callMap[$method] instanceof InvocationResults) {
return $this->callMap[$method]->hasResultForInvocation($invocationCount - 1);
}
return true;
}
/**
* returns the result for the method invocation done with given arguments
*
* @param string $method name of invoked method
* @param mixed[] $arguments arguments passed for the method call
* @param int $invocationCount denotes which nth invocation of the method this is
* @return mixed
* @throws \Exception
*/
public function resultFor(string $method, array $arguments, int $invocationCount)
{
if (!isset($this->callMap[$method])) {
return null;
}
if ($this->callMap[$method] instanceof InvocationResults) {
$result = $this->callMap[$method]->resultForInvocation($invocationCount - 1);
} else {
$result = $this->callMap[$method];
}
if (is_callable($result)) {
return $result(...$arguments);
}
return $result;
}
}
PK }mO src/main/php/NewCallable.phpnu W+A newInstanceArgs([$function]);
}
/**
* returns a new callable instance of the given function
*
* @api
* @param string $function function to create a new callable of
* @return \bovigo\callmap\FunctionProxy
*/
public static function stub(string $function): FunctionProxy
{
return self::of($function)->preventParentCalls();
}
/**
* returns the class name of any new instance for given function
*
* @api
* @param string $function
* @return string
*/
public static function classname(string $function): string
{
return self::callMapClass($function)->getName();
}
/**
* returns the proxy class for given function
*
* @param string $function
* @return \ReflectionClass
*/
private static function callMapClass(string $function): \ReflectionClass
{
if (!isset(self::$functions[$function])) {
self::$functions[$function] = self::forkCallMapClass(
new \ReflectionFunction($function)
);
}
return self::$functions[$function];
}
/**
* reference to compile function
*
* @type callable
* @internal
*/
public static $compile = __NAMESPACE__ . '\compile';
/**
* creates a new class from the given function which uses the CallMap trait
*
* @param \ReflectionFunction $function
* @return \ReflectionClass
* @throws ProxyCreationFailure
*/
private static function forkCallMapClass(\ReflectionFunction $function): \ReflectionClass
{
try {
$compile = self::$compile;
$compile(self::createProxyCode($function));
} catch (\ParseError $pe) {
throw new ProxyCreationFailure(
'Failure while creating callable CallMap instance of '
. $function->getName() . '(): ' . $pe->getMessage(),
$pe
);
}
return new \ReflectionClass($function->getName() . 'CallMapProxy');
}
/**
* creates code for new class
*
* @param \ReflectionFunction $function
* @return string
*/
private static function createProxyCode(\ReflectionFunction $function): string
{
$param = paramsOf($function);
$return = true;
$returnType = determineReturnTypeOf($function);
if ($returnType === ': void') {
$return = false;
}
$code = sprintf(
"class %sCallMapProxy extends \bovigo\callmap\FunctionProxy{\n"
. " protected \$paramNames = %s;\n"
. " public function preventParentCalls(): self\n"
. " {\n"
. " \$this->parentCallsAllowed = false;\n"
. " return \$this;\n"
. " }\n"
. " public function __invoke(%s)%s {\n"
. " %s\$this->handleFunctionCall(func_get_args());\n"
. " }\n"
. " protected \$returnVoid = %s;"
. "}\n",
ucfirst($function->getShortName()),
var_export($param['names'], true),
$param['string'],
determineReturnTypeOf($function),
$return ? 'return ' : '',
$return ? 'false' : 'true'
);
if ($function->inNamespace()) {
return sprintf(
"namespace %s {\n%s}\n",
$function->getNamespaceName(),
$code
);
}
return $code;
}
}
PK }mOFv/ / src/main/php/Verification.phpnu W+A invocations = $invocations;
}
/**
* verifies that the method on the class was not called more than $times
*
* @api
* @param int $times
* @return bool
* @throws \bovigo\callmap\CallAmountViolation
*/
public function wasCalledAtMost(int $times): bool
{
if (count($this->invocations) > $times) {
throw new CallAmountViolation(sprintf(
'%s was expected to be called at most %d time(s),'
. ' but actually called %d time(s).',
$this->invocations->name(),
$times,
count($this->invocations)
));
}
return true;
}
/**
* verifies that the method on the class was called at least once
*
* @api
* @return bool
* @throws \bovigo\callmap\CallAmountViolation
*/
public function wasCalledAtLeastOnce(): bool
{
if (count($this->invocations) < 1) {
throw new CallAmountViolation(sprintf(
'%s was expected to be called at least once,'
. ' but was never called.',
$this->invocations->name()
));
}
return true;
}
/**
* verifies that the method on the class was called at least $times
*
* @api
* @param int $times
* @return bool
* @throws \bovigo\callmap\CallAmountViolation
*/
public function wasCalledAtLeast(int $times): bool
{
if (count($this->invocations) < $times) {
throw new CallAmountViolation(sprintf(
'%s was expected to be called at least %d time(s),'
. ' but actually called %d time(s).',
$this->invocations->name(),
$times,
count($this->invocations)
));
}
return true;
}
/**
* verifies that the method on the class was called exactly once
*
* @api
* @return bool
* @throws \bovigo\callmap\CallAmountViolation
*/
public function wasCalledOnce(): bool
{
$callsReceived = count($this->invocations);
if (1 !== $callsReceived) {
throw new CallAmountViolation(sprintf(
'%s was expected to be called once, but actually %s.',
$this->invocations->name(),
1 < $callsReceived ?
'called ' . $callsReceived . ' time(s)' :
'never called'
));
}
return true;
}
/**
* verifies that the method on the class was called exactly $times
*
* @api
* @param int $times
* @return bool
* @throws \bovigo\callmap\CallAmountViolation
*/
public function wasCalled(int $times): bool
{
if (count($this->invocations) != $times) {
throw new CallAmountViolation(sprintf(
'%s was expected to be called %d time(s),'
. ' but actually called %d time(s).',
$this->invocations->name(),
$times,
count($this->invocations)
));
}
return true;
}
/**
* verifies that the method on the class was never called
*
* @api
* @return bool
* @throws \bovigo\callmap\CallAmountViolation
*/
public function wasNeverCalled(): bool
{
if (count($this->invocations) > 0) {
throw new CallAmountViolation(sprintf(
'%s was not expected to be called,'
. ' but actually called %d time(s).',
$this->invocations->name(),
count($this->invocations)
));
}
return true;
}
/**
* verifies that the method received nothing on the given invocation
*
* @api
* @param int $invocation optional nth invocation to check, defaults to 1 aka first invocation
* @return bool
* @throws \bovigo\callmap\ArgumentMismatch
*/
public function receivedNothing(int $invocation = 1): bool
{
$received = $this->invocations->argumentsOf($invocation);
if (count($received) === 0) {
return true;
}
throw new ArgumentMismatch(sprintf(
'Argument count for invocation #%d of %s is too'
. ' high: received %d argument(s), expected no arguments.',
$invocation,
$this->invocations->name(),
count($received)
));
}
/**
* verifies that the received arguments match expected arguments for the first invocation
*
* If a constraint is not an instance of PHPUnit\Framework\Constraint\Constraint it
* will automatically use PHPUnit\Framework\Constraint\IsEqual.
*
* @api
* @param mixed|\bovigo\assert\predicate\Predicate|\PHPUnit\Framework\Constraint\Constraint[] ...$expected constraints which describe expected parameters
* @return bool
*/
public function received(...$expected): bool
{
return $this->verifyArgs(1, $expected);
}
/**
* verifies that the received arguments match expected arguments for the given invocation
*
* If a constraint is not an instance of PHPUnit\Framework\Constraint\Constraint it
* will automatically use PHPUnit\Framework\Constraint\IsEqual.
*
* @api
* @param int $invocation nth invocation to check
* @param mixed|\bovigo\assert\predicate\Predicate|\PHPUnit\Framework\Constraint\Constraint[] ...$expected constraints which describe expected parameters
* @return bool
*/
public function receivedOn(int $invocation, ...$expected): bool
{
return $this->verifyArgs($invocation, $expected);
}
/**
* verifies arguments of given invocation with the expected constraints
*
* If a constraint is not an instance of PHPUnit\Framework\Constraint\Constraint it
* will automatically use PHPUnit\Framework\Constraint\IsEqual.
*
* @param int $invocation number of invocation to check
* @param array $expected constraints which describe expected parameters
* @return bool
* @throws \bovigo\callmap\ArgumentMismatch
*/
private function verifyArgs(int $invocation, array $expected): bool
{
$received = $this->invocations->argumentsOf($invocation);
if (count($received) < count($expected)) {
throw new ArgumentMismatch(sprintf(
'Argument count for invocation #%d of %s is too'
. ' low: received %d argument(s), expected %d argument(s).',
$invocation,
$this->invocations->name(),
count($received),
count($expected)
));
}
foreach ($expected as $atPosition => $constraint) {
$this->evaluate(
$constraint,
$received[$atPosition] ?? null,
sprintf(
'Parameter %sat position %d for invocation #%d of %s'
. ' does not match expected value.',
$this->invocations->argumentName($atPosition, ' '),
$atPosition,
$invocation,
$this->invocations->name()
)
);
}
return true;
}
/**
* evaluates given constraint given received argument
*
* @param mixed|\bovigo\assert\predicate\Predicate|\PHPUnit\Framework\Constraint\Constraint $constraint constraint for argument
* @param mixed $received actually received argument
* @param string $description description for invocation in case of error
* @return bool
* @throws \RuntimeException in case neither bovigo/assert, PHPUnit not xp-framework/unittest is present
*/
private function evaluate($constraint, $received, string $description): bool
{
if (function_exists('bovigo\assert\assertThat')) {
return \bovigo\assert\assertThat(
$received,
$this->predicateFor($constraint),
$description
);
}
if (class_exists('\PHPUnit\Framework\Constraint\IsEqual')) {
return $this->evaluateWithPhpUnit($constraint, $received, $description);
}
if (class_exists('\unittest\TestCase')) {
return $this->evaluateWithXpFrameworkCore($constraint, $received, $description);
}
throw new \RuntimeException('Neither bovigo/assert, PHPUnit nor xp-framework/unittest found, can not perform argument verification');
}
/**
* creates precicate for given constraint
*
* @param mixed|\bovigo\assert\predicate\Predicate|\PHPUnit\Framework\Constraint\Constraint $constraint
* @return \bovigo\assert\predicate\Predicate
*/
private function predicateFor($constraint): \bovigo\assert\predicate\Predicate
{
if ($constraint instanceof \PHPUnit\Framework\Constraint\Constraint) {
return new \bovigo\assert\phpunit\ConstraintAdapter($constraint);
}
if ($constraint instanceof \bovigo\assert\predicate\Predicate) {
return $constraint;
}
return \bovigo\assert\predicate\equals($constraint);
}
/**
* evaluates given constraint using PHPUnit
*
* If given constraint is not a instance of \PHPUnit\Framework\Constraint\Constraint it
* will be wrapped with \PHPUnit\Framework\Constraint\IsEqual.
*
* @param mixed|\PHPUnit\Framework\Constraint\Constraint $constraint constraint for argument
* @param mixed $received actually received argument
* @param string $description description for invocation in case of error
* @return bool
*/
protected function evaluateWithPhpUnit($constraint, $received, string $description): bool
{
if ($constraint instanceof \PHPUnit\Framework\Constraint\Constraint) {
return $constraint->evaluate($received, $description);
}
return (new \PHPUnit\Framework\Constraint\IsEqual($constraint))
->evaluate($received, $description);
}
/**
* evaluates given constraint using xp-framework/core unittest
*
* @param mixed $constraint constraint for argument
* @param mixed $received actually received argument
* @param string $description description for invocation in case of error
* @return bool
* @throws \unittest\AssertionFailedError
*/
protected function evaluateWithXpFrameworkCore($constraint, $received, string $description): bool
{
if (!\util\Objects::equal($received, $constraint)) {
throw new \unittest\AssertionFailedError(
new \unittest\ComparisonFailedMessage(
$description,
$constraint,
$received
)
);
}
return true;
}
}
PK }mOEwp]
]
" src/test/php/InternalClassTest.phpnu W+A proxy = NewInstance::of(\ReflectionObject::class, [$this]);
}
/**
* @test
*/
public function callsOriginalMethodIfNoMappingProvided()
{
assertThat($this->proxy->getName(), equals(__CLASS__));
}
/**
* @test
*/
public function mapToSimpleValueReturnsValueOnMethodCall()
{
$this->proxy->returns(['getName' => 'foo']);
assertThat($this->proxy->getName(), equals('foo'));
}
/**
* @test
*/
public function mapToClosureReturnsClosureReturnValueOnMethodCall()
{
$this->proxy->returns(['getName' => function() { return 'foo'; }]);
assertThat($this->proxy->getName(), equals('foo'));
}
/**
* @test
* @since 0.4.0
*/
public function mapToCallableReturnsCallableReturnValueOnMethodCall()
{
$this->proxy->returns(['getName' => 'strtoupper']);
assertThat($this->proxy->getName('foo'), equals('FOO'));
}
/**
* @test
* @doesNotPerformAssertions
*/
public function amountOfCallsToMethodIsZeroIfNotCalled()
{
verify($this->proxy, 'getNamespaceName')->wasNeverCalled();
}
/**
* @test
* @doesNotPerformAssertions
*/
public function recordsAmountOfCallsToMethod()
{
$this->proxy->getName();
$this->proxy->getName();
$this->proxy->getShortName();
verify($this->proxy,'getName')->wasCalled(2);
verify($this->proxy, 'getShortName')->wasCalledOnce();
}
/**
* @test
*/
public function canVerifyReceivedArguments()
{
$this->proxy->implementsInterface(Proxy::class);
verify($this->proxy, 'implementsInterface')->received(Proxy::class);
}
/**
* @test
*/
public function canVerifyReceivedArgumentsOfSpecificInvocation()
{
$this->proxy->hasProperty('foo');
$this->proxy->hasProperty('bar');
verify($this->proxy, 'hasProperty')->receivedOn(2, 'bar');
}
}
PK }mO= &