Added php-test-helpers to the vendors directory
Seemed easier than trying to figure out how to force the prompt to accept the unknown IP (perhaps not possible at all as it is part of SSH?). `yes` didn't work, unfortunately.
This commit is contained in:
parent
ebc9b7fb38
commit
8f3c623e5d
32 changed files with 1629 additions and 2 deletions
|
@ -10,8 +10,7 @@ matrix:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- composer install
|
- composer install
|
||||||
- yes | git clone git@github.com:php-test-helpers/php-test-helpers.git
|
- cd vendors/php-test-helpers
|
||||||
- cd php-test-helpers
|
|
||||||
- phpize
|
- phpize
|
||||||
- ./configure --enable-test-helpers
|
- ./configure --enable-test-helpers
|
||||||
- make
|
- make
|
||||||
|
|
32
vendors/php-test-helpers/.gitignore
vendored
Executable file
32
vendors/php-test-helpers/.gitignore
vendored
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
.deps
|
||||||
|
.libs
|
||||||
|
build
|
||||||
|
modules
|
||||||
|
*.lo
|
||||||
|
*.loT
|
||||||
|
*.la
|
||||||
|
Makefile
|
||||||
|
Makefile.fragments
|
||||||
|
Makefile.global
|
||||||
|
Makefile.objects
|
||||||
|
acinclude.m4
|
||||||
|
aclocal.m4
|
||||||
|
config.cache
|
||||||
|
config.guess
|
||||||
|
config.h
|
||||||
|
config.h.in
|
||||||
|
config.log
|
||||||
|
config.nice
|
||||||
|
config.status
|
||||||
|
config.sub
|
||||||
|
configure
|
||||||
|
configure.in
|
||||||
|
install-sh
|
||||||
|
libtool
|
||||||
|
ltmain.sh
|
||||||
|
missing
|
||||||
|
mkinstalldirs
|
||||||
|
run-tests.php
|
||||||
|
test.ini
|
||||||
|
tmp-php.ini
|
||||||
|
autom4te.cache
|
15
vendors/php-test-helpers/.travis.yml
vendored
Executable file
15
vendors/php-test-helpers/.travis.yml
vendored
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- phpize
|
||||||
|
- ./configure --enable-test-helpers
|
||||||
|
- make
|
||||||
|
- sed -i -e 's/save_or_mail_results();//g' -e 's/\($failed_test_data\['\''test_name'\''\] . $failed_test_data\['\''info'\''\]\)/str_repeat('\''='\'', 80) . "\\n" . \1 . "\\n" . str_repeat('\''='\'', 80) . "\\n" . file_get_contents(realpath($failed_test_data['\''output'\'']), FILE_BINARY) . "\\n" . str_repeat('\''='\'', 80) . "\\n" . file_get_contents(realpath($failed_test_data['\''diff'\'']), FILE_BINARY)/g' run-tests.php
|
||||||
|
- sed -i -e 's/-\(@if test ! -z\)/\1/' -e 's/rm $(top_builddir)\/tmp-php.ini;//' -e 's/^\(.*TEST_PHP_EXECUTABLE=$(PHP_EXECUTABLE) \\\)/\t\t$(SED) -i '\''s\/^\\(.*xdebug.so\\)\/;\\1\/'\'' $\(top_builddir\)\/tmp-php.ini; \\\n\1/' Makefile
|
||||||
|
|
||||||
|
script: REPORT_EXIT_STATUS=1 make test
|
2
vendors/php-test-helpers/CREDITS
vendored
Executable file
2
vendors/php-test-helpers/CREDITS
vendored
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
test_helpers
|
||||||
|
Sebastian Bergmann, Johannes Schlüter
|
197
vendors/php-test-helpers/README.markdown
vendored
Executable file
197
vendors/php-test-helpers/README.markdown
vendored
Executable file
|
@ -0,0 +1,197 @@
|
||||||
|
# ext/test_helpers #
|
||||||
|
|
||||||
|
`ext/test_helpers` is an extension for the PHP Interpreter to ease testing of PHP code.
|
||||||
|
|
||||||
|
## Installation ##
|
||||||
|
|
||||||
|
`ext/test_helpers` should be installed using the [PEAR Installer](http://pear.php.net/). This installer is the backbone of PEAR and PECL, which provides a distribution system for PHP packages and extensions, and is shipped with every release of PHP since version 4.3.0.
|
||||||
|
|
||||||
|
The PEAR channel (`pear.phpunit.de`) that is used to distribute `ext/test_helpers` needs to be registered with the local PEAR environment:
|
||||||
|
|
||||||
|
sb@ubuntu ~ % pear channel-discover pear.phpunit.de
|
||||||
|
Adding Channel "pear.phpunit.de" succeeded
|
||||||
|
Discovery of channel "pear.phpunit.de" succeeded
|
||||||
|
|
||||||
|
This has to be done only once. Now the PEAR Installer can be used to install extensions and packages from the PHPUnit channel:
|
||||||
|
|
||||||
|
sb@ubuntu ~ % pecl install phpunit/test_helpers
|
||||||
|
downloading test_helpers-1.0.0.tgz ...
|
||||||
|
Starting to download test_helpers-1.0.0.tgz (6,980 bytes)
|
||||||
|
.....done: 6,980 bytes
|
||||||
|
4 source files, building
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
install ok: channel://pear.phpunit.de/test_helpers-1.0.0
|
||||||
|
You should add "extension=test_helpers.so" to php.ini
|
||||||
|
|
||||||
|
Further information about building stand-alone extensions for PHP can be found in the [Installation of PECL extensions](http://php.net/install.pecl) section of the PHP manual.
|
||||||
|
|
||||||
|
## Usage ##
|
||||||
|
|
||||||
|
### Intercepting the Exit Statement ###
|
||||||
|
|
||||||
|
When a [unit test](http://en.wikipedia.org/wiki/Unit_test) exercises code that contains an `exit` / `die` statement, the execution of the whole test suite is aborted. This is not a good thing.
|
||||||
|
|
||||||
|
With the `set_exit_overload()` function it is possible to overload the `exit` / `die` statement and make it a no-op, for instance:
|
||||||
|
|
||||||
|
<?php
|
||||||
|
set_exit_overload(function() { return FALSE; });
|
||||||
|
exit;
|
||||||
|
print 'We did not exit.';
|
||||||
|
unset_exit_overload();
|
||||||
|
exit;
|
||||||
|
print 'We exited and this will not be printed.';
|
||||||
|
?>
|
||||||
|
|
||||||
|
The code above will output
|
||||||
|
|
||||||
|
We did not exit.
|
||||||
|
|
||||||
|
The callback registered by `set_exit_overload()` might receive a parameter in case `exit` / `die` was called with a parameter:
|
||||||
|
|
||||||
|
<?php
|
||||||
|
set_exit_overload(function($param = NULL) { echo ($param ?: "No value given"), "\n"; return FALSE; }
|
||||||
|
die("Hello");
|
||||||
|
die;
|
||||||
|
?>
|
||||||
|
|
||||||
|
The code above will output
|
||||||
|
|
||||||
|
Hello
|
||||||
|
No value given
|
||||||
|
|
||||||
|
Another way of dealing with low-level functions and statements such as `die()` and `exit` is to wrap them in a proxy that by default (in production) delegates to the native implementation but for testing has a "testable" behaviour.
|
||||||
|
|
||||||
|
### Intercepting Object Creation ###
|
||||||
|
|
||||||
|
In a [unit test](http://en.wikipedia.org/wiki/Unit_test), [mock objects](http://en.wikipedia.org/wiki/Mock_Object) can simulate the behavior of complex, real (non-mock) objects and are therefore useful when a real object is difficult or impossible to incorporate into a unit test.
|
||||||
|
|
||||||
|
A mock object can be used anywhere in the program where the program expects an object of the mocked class. However, this only works as long as the object can be passed into the context where the original object is used.
|
||||||
|
|
||||||
|
Consider the following example:
|
||||||
|
|
||||||
|
<?php
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
public function doSomething()
|
||||||
|
{
|
||||||
|
$object = new SomeOtherClass;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
With the code above, it is impossible to run a unit test for the `SomeClass::doSomething()` method without also creating an object of `SomeOtherClass`. As the method creates the object of `SomeOtherClass` itself, we cannot inject a mock object in its stead.
|
||||||
|
|
||||||
|
In a perfect world, code such as the above could be refactored using [Dependency Injection](http://en.wikipedia.org/wiki/Dependency_Injection):
|
||||||
|
|
||||||
|
<?php
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
protected $object;
|
||||||
|
|
||||||
|
public function __construct(SomeOtherClass $object)
|
||||||
|
{
|
||||||
|
$this->object = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doSomething()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
Unfortunately, this is not always possible (not because of technical reasons, though).
|
||||||
|
|
||||||
|
This is where the `set_new_overload()` function comes into play. It can be used to register a [callback](http://www.php.net/manual/en/language.pseudo-types.php) that is automatically invoked when the `new` operator is executed:
|
||||||
|
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback($className) {
|
||||||
|
if ($className == 'Foo') {
|
||||||
|
$className = 'Bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $className;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(get_class(new Foo));
|
||||||
|
|
||||||
|
set_new_overload('callback');
|
||||||
|
var_dump(get_class(new Foo));
|
||||||
|
?>
|
||||||
|
|
||||||
|
string(3) "Foo"
|
||||||
|
string(3) "Bar"
|
||||||
|
|
||||||
|
The `new` operator callback can be unset when it is no longer required:
|
||||||
|
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback($className) {
|
||||||
|
return 'Bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
set_new_overload('callback');
|
||||||
|
var_dump(get_class(new Foo));
|
||||||
|
|
||||||
|
unset_new_overload();
|
||||||
|
var_dump(get_class(new Foo));
|
||||||
|
?>
|
||||||
|
|
||||||
|
string(3) "Bar"
|
||||||
|
string(3) "Foo"
|
||||||
|
|
||||||
|
#### Class Posing ####
|
||||||
|
|
||||||
|
The `set_new_overload()` function can be used to implement a programming language feature named *Class Posing*. [The implementation of Class Posing in Objective-C](http://en.wikipedia.org/wiki/Objective-C#Posing), for instance, permits a class to wholly replace another class within a program. The replacing class is said to "pose as" the target class.
|
||||||
|
|
||||||
|
Class Posing has the following restrictions
|
||||||
|
|
||||||
|
* A class may only pose as one of its direct or indirect superclasses
|
||||||
|
* The posing class must not define any new instance variables which are absent from the target class (though it may define or override methods).
|
||||||
|
* The target class may not have received any messages prior to the posing.
|
||||||
|
|
||||||
|
These restrictions are not enforced by `ext/test_helpers` because the extension is only intended to ease the development of unit tests (for legacy software systems that cannot be refactored to use Dependency Injection).
|
||||||
|
|
||||||
|
### Renaming Functions ###
|
||||||
|
|
||||||
|
The `rename_function()` function can be used to rename function:
|
||||||
|
|
||||||
|
<?php
|
||||||
|
function foo()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
function foo_stub()
|
||||||
|
{
|
||||||
|
return 'stubbed result';
|
||||||
|
}
|
||||||
|
|
||||||
|
rename_function('foo', 'foo_orig');
|
||||||
|
rename_function('foo_stub', 'foo');
|
||||||
|
var_dump(foo());
|
||||||
|
rename_function('foo', 'foo_stub');
|
||||||
|
rename_function('foo_orig', 'foo');
|
||||||
|
?>
|
||||||
|
|
||||||
|
string(14) "stubbed result"
|
||||||
|
|
||||||
|
This allows the stubbing/mocking of functions.
|
||||||
|
|
||||||
|
## Notes ##
|
||||||
|
|
||||||
|
If this extension is used in combination with other extensions, such as Xdebug, which are also overloading the `ZEND_NEW` opcode you have to load it as `zend_extension` after loading the conflicting extension. This can be done in your `php.ini` like this:
|
||||||
|
|
||||||
|
zend_extension=xdebug.so
|
||||||
|
zend_extension=test-helpers.so
|
||||||
|
|
||||||
|
Please refer to `phpinfo()` to verify whether a conflict was detected and whether the work-around was enabled.
|
||||||
|
|
6
vendors/php-test-helpers/config.m4
vendored
Executable file
6
vendors/php-test-helpers/config.m4
vendored
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
PHP_ARG_ENABLE(test_helpers, whether to enable test_helpers support,
|
||||||
|
[ --enable-test-helpers Enable test_helpers support])
|
||||||
|
|
||||||
|
if test "$PHP_TEST_HELPERS" != "no"; then
|
||||||
|
PHP_NEW_EXTENSION(test_helpers, test_helpers.c, $ext_shared)
|
||||||
|
fi
|
6
vendors/php-test-helpers/config.w32
vendored
Executable file
6
vendors/php-test-helpers/config.w32
vendored
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
ARG_ENABLE("test_helpers", "enable test_helpers support", "no");
|
||||||
|
|
||||||
|
if (PHP_TEST_HELPERS != "no") {
|
||||||
|
EXTENSION("test_helpers", "test_helpers.c");
|
||||||
|
}
|
||||||
|
|
75
vendors/php-test-helpers/package.xml
vendored
Executable file
75
vendors/php-test-helpers/package.xml
vendored
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<package packagerversion="1.4.9"
|
||||||
|
version="2.0"
|
||||||
|
xmlns="http://pear.php.net/dtd/package-2.0"
|
||||||
|
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
||||||
|
http://pear.php.net/dtd/tasks-1.0.xsd
|
||||||
|
http://pear.php.net/dtd/package-2.0
|
||||||
|
http://pear.php.net/dtd/package-2.0.xsd">
|
||||||
|
<name>test_helpers</name>
|
||||||
|
<channel>pear.phpunit.de</channel>
|
||||||
|
<summary>An extension for the PHP Interpreter to ease testing of PHP code.</summary>
|
||||||
|
<description>An extension for the PHP Interpreter to ease testing of PHP code.</description>
|
||||||
|
<lead>
|
||||||
|
<name>Sebastian Bergmann</name>
|
||||||
|
<user>sebastian</user>
|
||||||
|
<email>sebastian@php.net</email>
|
||||||
|
<active>yes</active>
|
||||||
|
</lead>
|
||||||
|
<lead>
|
||||||
|
<name>Johannes Schlueter</name>
|
||||||
|
<user>johannes</user>
|
||||||
|
<email>johannes@php.net</email>
|
||||||
|
<active>yes</active>
|
||||||
|
</lead>
|
||||||
|
<date>2010-10-25</date>
|
||||||
|
<version>
|
||||||
|
<release>1.1.0</release>
|
||||||
|
<api>1.1.0</api>
|
||||||
|
</version>
|
||||||
|
<stability>
|
||||||
|
<release>stable</release>
|
||||||
|
<api>stable</api>
|
||||||
|
</stability>
|
||||||
|
<license>BSD License</license>
|
||||||
|
<notes>http://github.com/sebastianbergmann/php-test-helpers</notes>
|
||||||
|
<contents>
|
||||||
|
<dir name="/">
|
||||||
|
<dir name="tests">
|
||||||
|
<file name="set_exit_overload.phpt" role="test" />
|
||||||
|
<file name="unset_exit_overload.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_closure.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_error_non_existing_class.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_error_return_non_existing_class.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_error_undefined_callback.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_function.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_functor.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_multiple.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_non_static_method.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_non_static_method_same_object.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_private_method.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_static_method.phpt" role="test" />
|
||||||
|
<file name="set_new_overload_unset_reset.phpt" role="test" />
|
||||||
|
</dir>
|
||||||
|
<file name="config.m4" role="src" />
|
||||||
|
<file name="config.w32" role="src" />
|
||||||
|
<file name="php_test_helpers.h" role="src" />
|
||||||
|
<file name="README.markdown" role="doc" />
|
||||||
|
<file name="test_helpers.c" role="src" />
|
||||||
|
</dir>
|
||||||
|
</contents>
|
||||||
|
<dependencies>
|
||||||
|
<required>
|
||||||
|
<php>
|
||||||
|
<min>5.2.1</min>
|
||||||
|
</php>
|
||||||
|
<pearinstaller>
|
||||||
|
<min>1.4.0b1</min>
|
||||||
|
</pearinstaller>
|
||||||
|
</required>
|
||||||
|
</dependencies>
|
||||||
|
<providesextension>test_helpers</providesextension>
|
||||||
|
<extsrcrelease />
|
||||||
|
</package>
|
59
vendors/php-test-helpers/php_test_helpers.h
vendored
Executable file
59
vendors/php-test-helpers/php_test_helpers.h
vendored
Executable file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| ext/test_helper |
|
||||||
|
| An extension for the PHP Interpreter to ease testing of PHP code. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 2009-2013 Sebastian Bergmann. All rights reserved. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Redistribution and use in source and binary forms, with or without |
|
||||||
|
| modification, are permitted provided that the following conditions |
|
||||||
|
| are met: |
|
||||||
|
| |
|
||||||
|
| * Redistributions of source code must retain the above copyright |
|
||||||
|
| notice, this list of conditions and the following disclaimer. |
|
||||||
|
| |
|
||||||
|
| * Redistributions in binary form must reproduce the above copyright |
|
||||||
|
| notice, this list of conditions and the following disclaimer in |
|
||||||
|
| the documentation and/or other materials provided with the |
|
||||||
|
| distribution. |
|
||||||
|
| |
|
||||||
|
| * Neither the name of Sebastian Bergmann nor the names of his |
|
||||||
|
| contributors may be used to endorse or promote products derived |
|
||||||
|
| from this software without specific prior written permission. |
|
||||||
|
| |
|
||||||
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||||
|
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||||
|
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||||
|
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||||
|
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||||
|
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||||
|
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||||
|
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||||
|
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||||
|
| POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Author: Sebastian Bergmann <sb@sebastian-bergmann.de> |
|
||||||
|
| Johannes Schlüter <johannes@schlueters.de> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PHP_TEST_HELPERS_H
|
||||||
|
#define PHP_TEST_HELPERS_H
|
||||||
|
|
||||||
|
extern zend_module_entry test_helpers_module_entry;
|
||||||
|
#define phpext_test_helpers_ptr &test_helpers_module_entry
|
||||||
|
|
||||||
|
#define TEST_HELPERS_VERSION "1.0.1-dev"
|
||||||
|
|
||||||
|
#endif /* PHP_TEST_HELPERS_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* End:
|
||||||
|
* vim600: noet sw=4 ts=4 fdm=marker
|
||||||
|
* vim<600: noet sw=4 ts=4
|
||||||
|
*/
|
671
vendors/php-test-helpers/test_helpers.c
vendored
Executable file
671
vendors/php-test-helpers/test_helpers.c
vendored
Executable file
|
@ -0,0 +1,671 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| ext/test_helper |
|
||||||
|
| An extension for the PHP Interpreter to ease testing of PHP code. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 2009-2013 Sebastian Bergmann. All rights reserved. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Redistribution and use in source and binary forms, with or without |
|
||||||
|
| modification, are permitted provided that the following conditions |
|
||||||
|
| are met: |
|
||||||
|
| |
|
||||||
|
| * Redistributions of source code must retain the above copyright |
|
||||||
|
| notice, this list of conditions and the following disclaimer. |
|
||||||
|
| |
|
||||||
|
| * Redistributions in binary form must reproduce the above copyright |
|
||||||
|
| notice, this list of conditions and the following disclaimer in |
|
||||||
|
| the documentation and/or other materials provided with the |
|
||||||
|
| distribution. |
|
||||||
|
| |
|
||||||
|
| * Neither the name of Sebastian Bergmann nor the names of his |
|
||||||
|
| contributors may be used to endorse or promote products derived |
|
||||||
|
| from this software without specific prior written permission. |
|
||||||
|
| |
|
||||||
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
||||||
|
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||||
|
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
||||||
|
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
||||||
|
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||||
|
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||||
|
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
||||||
|
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
||||||
|
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
||||||
|
| POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Author: Johannes Schlüter <johannes@schlueters.de> |
|
||||||
|
| Scott MacVicar <scott@macvicar.net> |
|
||||||
|
| Sebastian Bergmann <sb@sebastian-bergmann.de> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "php.h"
|
||||||
|
#include "php_ini.h"
|
||||||
|
#include "ext/standard/info.h"
|
||||||
|
#include "php_test_helpers.h"
|
||||||
|
#include "Zend/zend_exceptions.h"
|
||||||
|
#include "Zend/zend_extensions.h"
|
||||||
|
|
||||||
|
#ifdef PHP_WIN32
|
||||||
|
# define PHP_TEST_HELPERS_API __declspec(dllexport)
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
# define PHP_TEST_HELPERS_API __attribute__ ((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define PHP_TEST_HELPERS_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* {{{ PHP < 5.3.0 */
|
||||||
|
#if PHP_VERSION_ID < 50300
|
||||||
|
typedef opcode_handler_t user_opcode_handler_t;
|
||||||
|
|
||||||
|
#define Z_ADDREF_P(z) ((z)->refcount++)
|
||||||
|
|
||||||
|
#define zend_parse_parameters_none() zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
|
||||||
|
|
||||||
|
static void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* {{{ */
|
||||||
|
{
|
||||||
|
if (fci->params) {
|
||||||
|
if (free_mem) {
|
||||||
|
efree(fci->params);
|
||||||
|
fci->params = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fci->param_count = 0;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int zend_fcall_info_argv(zend_fcall_info *fci TSRMLS_DC, int argc, va_list *argv) /* {{{ */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
zval **arg;
|
||||||
|
|
||||||
|
if (argc < 0) {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_fcall_info_args_clear(fci, !argc);
|
||||||
|
|
||||||
|
if (argc) {
|
||||||
|
fci->param_count = argc;
|
||||||
|
fci->params = (zval ***) erealloc(fci->params, fci->param_count * sizeof(zval **));
|
||||||
|
|
||||||
|
for (i = 0; i < argc; ++i) {
|
||||||
|
arg = va_arg(*argv, zval **);
|
||||||
|
fci->params[i] = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int zend_fcall_info_argn(zend_fcall_info *fci TSRMLS_DC, int argc, ...) /* {{{ */
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list argv;
|
||||||
|
|
||||||
|
va_start(argv, argc);
|
||||||
|
ret = zend_fcall_info_argv(fci TSRMLS_CC, argc, &argv);
|
||||||
|
va_end(argv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
#endif /* PHP_VERSION_ID < 50300 */
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static user_opcode_handler_t old_new_handler = NULL;
|
||||||
|
static user_opcode_handler_t old_exit_handler = NULL;
|
||||||
|
static int test_helpers_module_initialized = 0;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
zend_fcall_info fci;
|
||||||
|
zend_fcall_info_cache fcc;
|
||||||
|
} user_handler_t;
|
||||||
|
|
||||||
|
ZEND_BEGIN_MODULE_GLOBALS(test_helpers)
|
||||||
|
user_handler_t new_handler;
|
||||||
|
user_handler_t exit_handler;
|
||||||
|
ZEND_END_MODULE_GLOBALS(test_helpers)
|
||||||
|
|
||||||
|
ZEND_DECLARE_MODULE_GLOBALS(test_helpers)
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
#define THG(v) TSRMG(test_helpers_globals_id, zend_test_helpers_globals *, v)
|
||||||
|
#else
|
||||||
|
#define THG(v) (test_helpers_globals.v)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef EX
|
||||||
|
#define EX(element) execute_data->element
|
||||||
|
|
||||||
|
#if PHP_VERSION_ID >= 50500
|
||||||
|
# define EX_T(offset) (*EX_TMP_VAR(execute_data, offset))
|
||||||
|
#else
|
||||||
|
# define EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PHP_VERSION_ID >= 50399
|
||||||
|
# define PTH_ZNODE znode_op
|
||||||
|
# define PTH_TYPE(t) t##_type
|
||||||
|
#else
|
||||||
|
# define PTH_ZNODE znode
|
||||||
|
# define PTH_TYPE(t) t.op_type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
zval *pth_get_zval_ptr(int node_type, PTH_ZNODE *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC)
|
||||||
|
{
|
||||||
|
*freeval = NULL;
|
||||||
|
|
||||||
|
switch (node_type) {
|
||||||
|
case IS_CONST:
|
||||||
|
#if PHP_VERSION_ID >= 50399
|
||||||
|
return node->zv;
|
||||||
|
#else
|
||||||
|
return &node->u.constant;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IS_VAR:
|
||||||
|
#if PHP_VERSION_ID >= 50399
|
||||||
|
if (EX_T(node->var).var.ptr) {
|
||||||
|
return EX_T(node->var).var.ptr;
|
||||||
|
#else
|
||||||
|
if (EX_T(node->u.var).var.ptr) {
|
||||||
|
return EX_T(node->u.var).var.ptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IS_TMP_VAR:
|
||||||
|
#if PHP_VERSION_ID >= 50399
|
||||||
|
return (*freeval = &EX_T(node->var).tmp_var);
|
||||||
|
#else
|
||||||
|
return (*freeval = &EX_T(node->u.var).tmp_var);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IS_CV: {
|
||||||
|
zval **tmp;
|
||||||
|
#if PHP_VERSION_ID >= 50399
|
||||||
|
tmp = zend_get_compiled_variable_value(execute_data, node->constant);
|
||||||
|
#else
|
||||||
|
tmp = zend_get_compiled_variable_value(execute_data, node->u.constant.value.lval);
|
||||||
|
#endif
|
||||||
|
if (tmp) {
|
||||||
|
return *tmp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_helpers_free_handler(zend_fcall_info *fci TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
if (fci->function_name) {
|
||||||
|
zval_ptr_dtor(&fci->function_name);
|
||||||
|
fci->function_name = NULL;
|
||||||
|
}
|
||||||
|
#if PHP_VERSION_ID >= 50300
|
||||||
|
if (fci->object_ptr) {
|
||||||
|
zval_ptr_dtor(&fci->object_ptr);
|
||||||
|
fci->object_ptr = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int pth_new_handler(ZEND_OPCODE_HANDLER_ARGS) /* {{{ */
|
||||||
|
{
|
||||||
|
zval *retval, *arg;
|
||||||
|
zend_op *opline = EX(opline);
|
||||||
|
zend_class_entry *old_ce, **new_ce;
|
||||||
|
|
||||||
|
if (THG(new_handler).fci.function_name == NULL) {
|
||||||
|
if (old_new_handler) {
|
||||||
|
return old_new_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||||
|
} else {
|
||||||
|
return ZEND_USER_OPCODE_DISPATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ZEND_EXTENSION_API_NO >= 220100525
|
||||||
|
old_ce = EX_T(opline->op1.var).class_entry;
|
||||||
|
#else
|
||||||
|
old_ce = EX_T(opline->op1.u.var).class_entry;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MAKE_STD_ZVAL(arg);
|
||||||
|
ZVAL_STRINGL(arg, old_ce->name, old_ce->name_length, 1);
|
||||||
|
|
||||||
|
zend_fcall_info_argn(&THG(new_handler).fci TSRMLS_CC, 1, &arg);
|
||||||
|
zend_fcall_info_call(&THG(new_handler).fci, &THG(new_handler).fcc, &retval, NULL TSRMLS_CC);
|
||||||
|
zend_fcall_info_args_clear(&THG(new_handler).fci, 1);
|
||||||
|
|
||||||
|
convert_to_string_ex(&retval);
|
||||||
|
if (zend_lookup_class(Z_STRVAL_P(retval), Z_STRLEN_P(retval), &new_ce TSRMLS_CC) == FAILURE) {
|
||||||
|
if (!EG(exception)) {
|
||||||
|
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), -1 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(retval));
|
||||||
|
}
|
||||||
|
zval_ptr_dtor(&arg);
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
|
||||||
|
return ZEND_USER_OPCODE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
zval_ptr_dtor(&arg);
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
|
||||||
|
|
||||||
|
#if ZEND_EXTENSION_API_NO >= 220100525
|
||||||
|
EX_T(opline->op1.var).class_entry = *new_ce;
|
||||||
|
#else
|
||||||
|
EX_T(opline->op1.u.var).class_entry = *new_ce;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (old_new_handler) {
|
||||||
|
return old_new_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||||
|
} else {
|
||||||
|
return ZEND_USER_OPCODE_DISPATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int pth_exit_handler(ZEND_OPCODE_HANDLER_ARGS) /* {{{ */
|
||||||
|
{
|
||||||
|
zval *msg, *freeop;
|
||||||
|
zend_op *opline = EX(opline);
|
||||||
|
zval *retval = NULL;
|
||||||
|
|
||||||
|
if (THG(exit_handler).fci.function_name == NULL) {
|
||||||
|
if (old_exit_handler) {
|
||||||
|
return old_exit_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||||
|
} else {
|
||||||
|
return ZEND_USER_OPCODE_DISPATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = pth_get_zval_ptr(opline->PTH_TYPE(op1), &opline->op1, &freeop, execute_data TSRMLS_CC);
|
||||||
|
|
||||||
|
if (msg) {
|
||||||
|
zend_fcall_info_argn(&THG(exit_handler).fci TSRMLS_CC, 1, &msg);
|
||||||
|
}
|
||||||
|
zend_fcall_info_call(&THG(exit_handler).fci, &THG(exit_handler).fcc, &retval, NULL TSRMLS_CC);
|
||||||
|
zend_fcall_info_args_clear(&THG(exit_handler).fci, 1);
|
||||||
|
|
||||||
|
if(UNEXPECTED(retval == NULL)) {
|
||||||
|
EX(opline)++;
|
||||||
|
return ZEND_USER_OPCODE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_to_boolean(retval);
|
||||||
|
if (Z_LVAL_P(retval)) {
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
if (old_exit_handler) {
|
||||||
|
return old_exit_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||||
|
} else {
|
||||||
|
return ZEND_USER_OPCODE_DISPATCH;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zval_ptr_dtor(&retval);
|
||||||
|
EX(opline)++;
|
||||||
|
return ZEND_USER_OPCODE_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static void php_test_helpers_init_globals(zend_test_helpers_globals *globals) /* {{{ */
|
||||||
|
{
|
||||||
|
globals->new_handler.fci.function_name = NULL;
|
||||||
|
globals->exit_handler.fci.function_name = NULL;
|
||||||
|
#if PHP_VERSION_ID >= 50300
|
||||||
|
globals->new_handler.fci.object_ptr = NULL;
|
||||||
|
globals->exit_handler.fci.object_ptr = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ PHP_MINIT_FUNCTION
|
||||||
|
*/
|
||||||
|
static PHP_MINIT_FUNCTION(test_helpers)
|
||||||
|
{
|
||||||
|
if (test_helpers_module_initialized) {
|
||||||
|
/* This should never happen as it is handled by the module loader, but let's play safe */
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "test_helpers had already been initialized! Either load it as regular PHP extension or zend_extension");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_INIT_MODULE_GLOBALS(test_helpers, php_test_helpers_init_globals, NULL);
|
||||||
|
old_new_handler = zend_get_user_opcode_handler(ZEND_NEW);
|
||||||
|
zend_set_user_opcode_handler(ZEND_NEW, pth_new_handler);
|
||||||
|
|
||||||
|
old_exit_handler = zend_get_user_opcode_handler(ZEND_EXIT);
|
||||||
|
zend_set_user_opcode_handler(ZEND_EXIT, pth_exit_handler);
|
||||||
|
|
||||||
|
test_helpers_module_initialized = 1;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ PHP_RSHUTDOWN_FUNCTION
|
||||||
|
*/
|
||||||
|
static PHP_RSHUTDOWN_FUNCTION(test_helpers)
|
||||||
|
{
|
||||||
|
test_helpers_free_handler(&THG(new_handler).fci TSRMLS_CC);
|
||||||
|
test_helpers_free_handler(&THG(exit_handler).fci TSRMLS_CC);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ PHP_MINFO_FUNCTION
|
||||||
|
*/
|
||||||
|
static PHP_MINFO_FUNCTION(test_helpers)
|
||||||
|
{
|
||||||
|
char *conflict_text;
|
||||||
|
|
||||||
|
if (pth_new_handler != zend_get_user_opcode_handler(ZEND_NEW)) {
|
||||||
|
conflict_text = "Yes. The work-around was NOT enabled. Please make sure test_helpers was loaded as zend_extension AFTER conflicting extensions like Xdebug!";
|
||||||
|
} else if (old_new_handler != NULL) {
|
||||||
|
conflict_text = "Yes, work-around enabled";
|
||||||
|
} else {
|
||||||
|
conflict_text = "No conflict detected";
|
||||||
|
}
|
||||||
|
php_info_print_table_start();
|
||||||
|
php_info_print_table_header(2, "test_helpers support", "enabled");
|
||||||
|
php_info_print_table_row(2, "Conflicting extension found", conflict_text);
|
||||||
|
php_info_print_table_end();
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static void overload_helper(user_opcode_handler_t op_handler, int opcode, user_handler_t *handler, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
||||||
|
{
|
||||||
|
zend_fcall_info fci;
|
||||||
|
zend_fcall_info_cache fcc;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", &fci, &fcc) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op_handler != zend_get_user_opcode_handler(opcode)) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "A conflicting extension was detected. Make sure to load test_helpers as zend_extension after other extensions");
|
||||||
|
}
|
||||||
|
|
||||||
|
test_helpers_free_handler(&handler->fci TSRMLS_CC);
|
||||||
|
|
||||||
|
handler->fci = fci;
|
||||||
|
handler->fcc = fcc;
|
||||||
|
Z_ADDREF_P(handler->fci.function_name);
|
||||||
|
#if PHP_VERSION_ID >= 50300
|
||||||
|
if (handler->fci.object_ptr) {
|
||||||
|
Z_ADDREF_P(handler->fci.object_ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto bool set_new_overload(callback cb)
|
||||||
|
Register a callback, called on instantiation of a new object */
|
||||||
|
static PHP_FUNCTION(set_new_overload)
|
||||||
|
{
|
||||||
|
overload_helper(pth_new_handler, ZEND_NEW, &THG(new_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto bool set_exit_overload(callback cb)
|
||||||
|
Register a callback, called on exit()/die() */
|
||||||
|
static PHP_FUNCTION(set_exit_overload)
|
||||||
|
{
|
||||||
|
overload_helper(pth_exit_handler, ZEND_EXIT, &THG(exit_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static void unset_overload_helper(user_handler_t *handler, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
||||||
|
{
|
||||||
|
if (zend_parse_parameters_none() == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_helpers_free_handler(&handler->fci TSRMLS_CC);
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto bool unset_new_overload()
|
||||||
|
Remove the current new handler */
|
||||||
|
static PHP_FUNCTION(unset_new_overload)
|
||||||
|
{
|
||||||
|
unset_overload_helper(&THG(new_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto bool unset_exit_overload()
|
||||||
|
Remove the current exit handler */
|
||||||
|
static PHP_FUNCTION(unset_exit_overload)
|
||||||
|
{
|
||||||
|
unset_overload_helper(&THG(exit_handler), INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int pth_rename_function_impl(HashTable *table, char *orig, int orig_len, char *new, int new_len TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
zend_function *func, *dummy_func;
|
||||||
|
|
||||||
|
if (zend_hash_find(table, orig, orig_len + 1, (void **) &func) == FAILURE) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s(%s, %s) failed: %s does not exist!" ,
|
||||||
|
get_active_function_name(TSRMLS_C),
|
||||||
|
orig, new, orig);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Add infrastructure for resetting internal funcs */
|
||||||
|
if (func->type != ZEND_USER_FUNCTION) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "\"%s\" is an internal function", orig);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zend_hash_find(table, new, new_len + 1, (void **) &dummy_func) == SUCCESS) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s(%s, %s) failed: %s already exists!" ,
|
||||||
|
get_active_function_name(TSRMLS_C),
|
||||||
|
orig, new, new);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zend_hash_add(table, new, new_len + 1, func, sizeof(zend_function), NULL) == FAILURE) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s() failed to insert %s into EG(function_table)", get_active_function_name(TSRMLS_C), new);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func->type == ZEND_USER_FUNCTION) {
|
||||||
|
function_add_ref(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zend_hash_del(table, orig, orig_len + 1) == FAILURE) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s() failed to remove %s from function table", get_active_function_name(TSRMLS_C), orig);
|
||||||
|
|
||||||
|
zend_hash_del(table, new, new_len + 1);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int pth_rename_function(HashTable *table, char *orig, int orig_len, char *new, int new_len TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
char *lower_orig, *lower_new;
|
||||||
|
int success;
|
||||||
|
|
||||||
|
lower_orig = zend_str_tolower_dup(orig, orig_len);
|
||||||
|
lower_new = zend_str_tolower_dup(new, new_len);
|
||||||
|
|
||||||
|
success = pth_rename_function_impl(table, lower_orig, orig_len, lower_new, new_len TSRMLS_CC);
|
||||||
|
|
||||||
|
efree(lower_orig);
|
||||||
|
efree(lower_new);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto bool rename_method(string class name, string orig_method_name, string new_method_name)
|
||||||
|
Rename a method inside a class. The method whil remain partof the same class */
|
||||||
|
static PHP_FUNCTION(rename_method)
|
||||||
|
{
|
||||||
|
zend_class_entry *ce = NULL;
|
||||||
|
char *orig_fname, *new_fname;
|
||||||
|
int orig_fname_len, new_fname_len;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Css", &ce, &orig_fname, &orig_fname_len, &new_fname, &new_fname_len) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCESS == pth_rename_function(&ce->function_table, orig_fname, orig_fname_len, new_fname, new_fname_len TSRMLS_CC)) {
|
||||||
|
RETURN_TRUE;
|
||||||
|
} else {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto bool rename_function(string orig_func_name, string new_func_name)
|
||||||
|
Rename a function from its original to a new name. This is mainly useful in
|
||||||
|
unittest to stub out untested functions */
|
||||||
|
static PHP_FUNCTION(rename_function)
|
||||||
|
{
|
||||||
|
char *orig_fname, *new_fname;
|
||||||
|
int orig_fname_len, new_fname_len;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &orig_fname, &orig_fname_len, &new_fname, &new_fname_len) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCESS == pth_rename_function(EG(function_table), orig_fname, orig_fname_len, new_fname, new_fname_len TSRMLS_CC)) {
|
||||||
|
RETURN_TRUE;
|
||||||
|
} else {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ arginfo */
|
||||||
|
/* {{{ unset_new_overload */
|
||||||
|
ZEND_BEGIN_ARG_INFO(arginfo_unset_new_overload, 0)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ unset_exit_overload */
|
||||||
|
ZEND_BEGIN_ARG_INFO(arginfo_unset_exit_overload, 0)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ set_new_overload */
|
||||||
|
ZEND_BEGIN_ARG_INFO(arginfo_set_new_overload, 0)
|
||||||
|
ZEND_ARG_INFO(0, callback)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ rename_method */
|
||||||
|
ZEND_BEGIN_ARG_INFO(arginfo_rename_method, 0)
|
||||||
|
ZEND_ARG_INFO(0, class_name)
|
||||||
|
ZEND_ARG_INFO(0, orig_method_name)
|
||||||
|
ZEND_ARG_INFO(0, new_method_name)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ rename_function */
|
||||||
|
ZEND_BEGIN_ARG_INFO(arginfo_rename_function, 0)
|
||||||
|
ZEND_ARG_INFO(0, orig_func_name)
|
||||||
|
ZEND_ARG_INFO(0, new_func_name)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ set_exit_overload */
|
||||||
|
ZEND_BEGIN_ARG_INFO(arginfo_set_exit_overload, 0)
|
||||||
|
ZEND_ARG_INFO(0, "callback")
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ test_helpers_functions[]
|
||||||
|
*/
|
||||||
|
static const zend_function_entry test_helpers_functions[] = {
|
||||||
|
PHP_FE(unset_new_overload, arginfo_unset_new_overload)
|
||||||
|
PHP_FE(set_new_overload, arginfo_set_new_overload)
|
||||||
|
PHP_FE(unset_exit_overload, arginfo_unset_exit_overload)
|
||||||
|
PHP_FE(set_exit_overload, arginfo_set_exit_overload)
|
||||||
|
PHP_FE(rename_method, arginfo_rename_method)
|
||||||
|
PHP_FE(rename_function, arginfo_rename_function)
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ test_helpers_module_entry
|
||||||
|
*/
|
||||||
|
zend_module_entry test_helpers_module_entry = {
|
||||||
|
STANDARD_MODULE_HEADER,
|
||||||
|
"test_helpers",
|
||||||
|
test_helpers_functions,
|
||||||
|
PHP_MINIT(test_helpers),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
PHP_RSHUTDOWN(test_helpers),
|
||||||
|
PHP_MINFO(test_helpers),
|
||||||
|
TEST_HELPERS_VERSION,
|
||||||
|
STANDARD_MODULE_PROPERTIES
|
||||||
|
};
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int test_helpers_zend_startup(zend_extension *extension) /* {{{ */
|
||||||
|
{
|
||||||
|
return zend_startup_module(&test_helpers_module_entry);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
#ifndef ZEND_EXT_API
|
||||||
|
#define ZEND_EXT_API ZEND_DLEXPORT
|
||||||
|
#endif
|
||||||
|
ZEND_EXTENSION();
|
||||||
|
|
||||||
|
zend_extension zend_extension_entry = {
|
||||||
|
"test_helpers",
|
||||||
|
TEST_HELPERS_VERSION,
|
||||||
|
"Johannes Schlueter, Scott MacVicar, Sebastian Bergmann",
|
||||||
|
"http://github.com/johannes/php-test-helpers",
|
||||||
|
"Copyright (c) 2009-2013",
|
||||||
|
test_helpers_zend_startup,
|
||||||
|
NULL, /* shutdown_func_t */
|
||||||
|
NULL, /* activate_func_t */
|
||||||
|
NULL, /* deactivate_func_t */
|
||||||
|
NULL, /* message_handler_func_t */
|
||||||
|
NULL, /* op_array_handler_func_t */
|
||||||
|
NULL, /* statement_handler_func_t */
|
||||||
|
NULL, /* fcall_begin_handler_func_t */
|
||||||
|
NULL, /* fcall_end_handler_func_t */
|
||||||
|
NULL, /* op_array_ctor_func_t */
|
||||||
|
NULL, /* op_array_dtor_func_t */
|
||||||
|
STANDARD_ZEND_EXTENSION_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef COMPILE_DL_TEST_HELPERS
|
||||||
|
ZEND_GET_MODULE(test_helpers)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* End:
|
||||||
|
* vim600: noet sw=4 ts=4 fdm=marker
|
||||||
|
* vim<600: noet sw=4 ts=4
|
||||||
|
*/
|
6
vendors/php-test-helpers/tests/.gitignore
vendored
Executable file
6
vendors/php-test-helpers/tests/.gitignore
vendored
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
*.diff
|
||||||
|
*.exp
|
||||||
|
*.log
|
||||||
|
*.mem
|
||||||
|
*.out
|
||||||
|
*.php
|
21
vendors/php-test-helpers/tests/load_as_zend_extension-php5.5.phpt
vendored
Executable file
21
vendors/php-test-helpers/tests/load_as_zend_extension-php5.5.phpt
vendored
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
Loading test_helpers as zend_extension
|
||||||
|
--INI--
|
||||||
|
zend_extension=test_helpers.so
|
||||||
|
error_log=
|
||||||
|
display_errors=0
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (version_compare(PHP_VERSION, '5.5', '<')) die("skip this test is for PHP 5.5+.");
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
if (!file_exists('modules/test_helpers.so')) die('skip test_helpers.so not found Static build? out-of-src-dir build?');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
// The test framework will load the extension as PHP extension, we verify that a second load attempt is made
|
||||||
|
// This test has some flaws, the major one is that it expects a specific .so file at a specific location ...
|
||||||
|
echo "done";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
PHP Warning: Module 'test_helpers' already loaded in Unknown on line 0
|
||||||
|
done
|
21
vendors/php-test-helpers/tests/load_as_zend_extension.phpt
vendored
Executable file
21
vendors/php-test-helpers/tests/load_as_zend_extension.phpt
vendored
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
Loading test_helpers as zend_extension
|
||||||
|
--INI--
|
||||||
|
zend_extension=modules/test_helpers.so
|
||||||
|
error_log=
|
||||||
|
display_errors=0
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (version_compare(PHP_VERSION, '5.5', '>=')) die("skip test is for PHP < 5.5.");
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
if (!file_exists('modules/test_helpers.so')) die('skip test_helpers.so not found Static build? out-of-src-dir build?');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
// The test framework will load the extension as PHP extension, we verify that a second load attempt is made
|
||||||
|
// This test has some flaws, the major one is that it expects a specific .so file at a specific location ...
|
||||||
|
echo "done";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
PHP Warning: Module 'test_helpers' already loaded in Unknown on line 0
|
||||||
|
done
|
17
vendors/php-test-helpers/tests/rename_function.phpt
vendored
Executable file
17
vendors/php-test-helpers/tests/rename_function.phpt
vendored
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
--TEST--
|
||||||
|
rename_function() and user-defined functions
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
function foo()
|
||||||
|
{
|
||||||
|
print 'foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
rename_function('foo', 'bar');
|
||||||
|
bar();
|
||||||
|
--EXPECT--
|
||||||
|
foo
|
28
vendors/php-test-helpers/tests/rename_internal_function.phpt
vendored
Executable file
28
vendors/php-test-helpers/tests/rename_internal_function.phpt
vendored
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
--TEST--
|
||||||
|
rename_function() and internal functions
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--XFAIL--
|
||||||
|
Not yet implemented
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$headers = array();
|
||||||
|
|
||||||
|
function my_header($header)
|
||||||
|
{
|
||||||
|
$GLOBALS['headers'][] = $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
rename_function('header', 'internal_header');
|
||||||
|
rename_function('my_header', 'header');
|
||||||
|
header('Location: http://www.example.com/');
|
||||||
|
rename_function('header', 'my_header');
|
||||||
|
rename_function('internal_header', 'header');
|
||||||
|
var_dump($headers);
|
||||||
|
--EXPECT--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
string(33) "Location: http://www.example.com/"
|
||||||
|
}
|
19
vendors/php-test-helpers/tests/rename_method.phpt
vendored
Executable file
19
vendors/php-test-helpers/tests/rename_method.phpt
vendored
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
--TEST--
|
||||||
|
rename_method() and user-defined functions
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class A {
|
||||||
|
static function foo()
|
||||||
|
{
|
||||||
|
print 'foo';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rename_method('A', 'foo', 'bar');
|
||||||
|
A::bar();
|
||||||
|
--EXPECT--
|
||||||
|
foo
|
26
vendors/php-test-helpers/tests/set_exit_overload.phpt
vendored
Executable file
26
vendors/php-test-helpers/tests/set_exit_overload.phpt
vendored
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
--TEST--
|
||||||
|
set_exit_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
set_exit_overload(function($arg = NULL) { var_dump($arg); echo "FALSE\n"; return false; });
|
||||||
|
die("DIE 1");
|
||||||
|
die;
|
||||||
|
exit;
|
||||||
|
set_exit_overload(function($arg) { var_dump($arg); echo "TRUE\n"; return true; });
|
||||||
|
die("DIE 4");
|
||||||
|
echo "HAHA";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
string(5) "DIE 1"
|
||||||
|
FALSE
|
||||||
|
NULL
|
||||||
|
FALSE
|
||||||
|
NULL
|
||||||
|
FALSE
|
||||||
|
string(5) "DIE 4"
|
||||||
|
TRUE
|
||||||
|
DIE 4
|
17
vendors/php-test-helpers/tests/set_exit_overload_exception.phpt
vendored
Executable file
17
vendors/php-test-helpers/tests/set_exit_overload_exception.phpt
vendored
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
--TEST--
|
||||||
|
set_exit_overload() with an uncaught exception
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
set_exit_overload(function($arg = NULL) { throw new Exception("Please don't segfault"); });
|
||||||
|
try {
|
||||||
|
exit("hi");
|
||||||
|
} catch(Exception $exception) {
|
||||||
|
echo $exception->getMessage();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Please don't segfault
|
28
vendors/php-test-helpers/tests/set_new_overload_backtrace.phpt
vendored
Executable file
28
vendors/php-test-helpers/tests/set_new_overload_backtrace.phpt
vendored
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
--TEST--
|
||||||
|
debug_print_backtrace() should work inside the callback.
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback($className) {
|
||||||
|
debug_print_backtrace();
|
||||||
|
return 'Foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getObject() {
|
||||||
|
return new Bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload('callback'));
|
||||||
|
var_dump(getObject());
|
||||||
|
--EXPECTF--
|
||||||
|
bool(true)
|
||||||
|
#0 callback(Bar) called at [%s:%d]
|
||||||
|
#1 getObject() called at [%s:%d]
|
||||||
|
object(Foo)#1 (0) {
|
||||||
|
}
|
18
vendors/php-test-helpers/tests/set_new_overload_closure.phpt
vendored
Executable file
18
vendors/php-test-helpers/tests/set_new_overload_closure.phpt
vendored
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
--TEST--
|
||||||
|
A closure can be registered as a callback with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
if (version_compare(PHP_VERSION, '5.3.0') < 0) die('skip Test requires PHP 5.3');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
var_dump(set_new_overload(function ($className) { return 'Foo'; }));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(3) "Foo"
|
21
vendors/php-test-helpers/tests/set_new_overload_error_non_existing_class.phpt
vendored
Executable file
21
vendors/php-test-helpers/tests/set_new_overload_error_non_existing_class.phpt
vendored
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
Callback for the new operator is invoked for non-existing classes
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--XFAIL--
|
||||||
|
Currently not supported by the implementation but nice to have
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
|
||||||
|
function callback($className) {
|
||||||
|
return 'Foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
set_new_overload('callback');
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
string(3) "Foo"
|
24
vendors/php-test-helpers/tests/set_new_overload_error_return_non_existing_class.phpt
vendored
Executable file
24
vendors/php-test-helpers/tests/set_new_overload_error_return_non_existing_class.phpt
vendored
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
--TEST--
|
||||||
|
A fatal error is triggered when the class returned by the callback does not exist
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback($className) {
|
||||||
|
return 'Foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload('callback'));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECTF--
|
||||||
|
bool(true)
|
||||||
|
|
||||||
|
Fatal error: Uncaught exception 'Exception' with message 'Class Foo does not exist' in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 {main}
|
||||||
|
thrown in %s on line %d
|
17
vendors/php-test-helpers/tests/set_new_overload_error_undefined_callback.phpt
vendored
Executable file
17
vendors/php-test-helpers/tests/set_new_overload_error_undefined_callback.phpt
vendored
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
--TEST--
|
||||||
|
A warning is triggered when the callback passed to set_new_overload() is not defined
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
var_dump(set_new_overload('callback'));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: set_new_overload() expects parameter 1 to be a valid callback, function 'callback' not found or invalid function name in %s on line %d
|
||||||
|
NULL
|
||||||
|
string(3) "Bar"
|
21
vendors/php-test-helpers/tests/set_new_overload_function.phpt
vendored
Executable file
21
vendors/php-test-helpers/tests/set_new_overload_function.phpt
vendored
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
A function can be registered as a callback with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback($className) {
|
||||||
|
return 'Foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload('callback'));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(3) "Foo"
|
26
vendors/php-test-helpers/tests/set_new_overload_functor.phpt
vendored
Executable file
26
vendors/php-test-helpers/tests/set_new_overload_functor.phpt
vendored
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
--TEST--
|
||||||
|
A functor can be registered as a callback with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
if (version_compare(PHP_VERSION, '5.3.0') < 0) die('skip Test requires PHP 5.3');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
class Callback
|
||||||
|
{
|
||||||
|
public function __invoke($className)
|
||||||
|
{
|
||||||
|
return 'Foo';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload(new Callback));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(3) "Foo"
|
33
vendors/php-test-helpers/tests/set_new_overload_multiple.phpt
vendored
Executable file
33
vendors/php-test-helpers/tests/set_new_overload_multiple.phpt
vendored
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
set_new_overload() can be called multiple times and unset_new_overload() works
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo1 {}
|
||||||
|
class Foo2 {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback1($className) {
|
||||||
|
return 'Foo1';
|
||||||
|
}
|
||||||
|
|
||||||
|
function callback2($className) {
|
||||||
|
return 'foo2';
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload('callback1'));
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
var_dump(set_new_overload('callback2'));
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
var_dump(unset_new_overload());
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(4) "Foo1"
|
||||||
|
bool(true)
|
||||||
|
string(4) "Foo2"
|
||||||
|
bool(true)
|
||||||
|
string(3) "Bar"
|
27
vendors/php-test-helpers/tests/set_new_overload_non_static_method.phpt
vendored
Executable file
27
vendors/php-test-helpers/tests/set_new_overload_non_static_method.phpt
vendored
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
--TEST--
|
||||||
|
A non-static method can be registered as a callback with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
class CB {
|
||||||
|
function callback($className) {
|
||||||
|
if ($className == 'Bar') {
|
||||||
|
return 'Foo';
|
||||||
|
} else {
|
||||||
|
return $className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload(array(new CB(), 'callback')));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(3) "Foo"
|
86
vendors/php-test-helpers/tests/set_new_overload_non_static_method_same_object.phpt
vendored
Executable file
86
vendors/php-test-helpers/tests/set_new_overload_non_static_method_same_object.phpt
vendored
Executable file
|
@ -0,0 +1,86 @@
|
||||||
|
--TEST--
|
||||||
|
A non-static method of the same object can be registered as a callback with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo
|
||||||
|
{
|
||||||
|
public function doSomething()
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
$bar = new Bar;
|
||||||
|
$bar->doSomethingElse();
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar
|
||||||
|
{
|
||||||
|
public function doSomethingElse()
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BarMock extends Bar
|
||||||
|
{
|
||||||
|
public function doSomethingElse()
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FooTest
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
|
||||||
|
set_new_overload(array($this, 'newCallback'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
|
||||||
|
unset_new_overload();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newCallback($className)
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
|
||||||
|
switch ($className) {
|
||||||
|
case 'Bar': return 'BarMock';
|
||||||
|
default: return $className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoSomething()
|
||||||
|
{
|
||||||
|
var_dump(__METHOD__);
|
||||||
|
|
||||||
|
$foo = new Foo;
|
||||||
|
$foo->doSomething();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$test = new FooTest;
|
||||||
|
$test->setUp();
|
||||||
|
$test->testDoSomething();
|
||||||
|
$test->tearDown();
|
||||||
|
--EXPECT--
|
||||||
|
string(14) "FooTest::setUp"
|
||||||
|
string(24) "FooTest::testDoSomething"
|
||||||
|
string(20) "FooTest::newCallback"
|
||||||
|
string(16) "Foo::doSomething"
|
||||||
|
string(20) "FooTest::newCallback"
|
||||||
|
string(24) "BarMock::doSomethingElse"
|
||||||
|
string(17) "FooTest::tearDown"
|
38
vendors/php-test-helpers/tests/set_new_overload_private_method.phpt
vendored
Executable file
38
vendors/php-test-helpers/tests/set_new_overload_private_method.phpt
vendored
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
--TEST--
|
||||||
|
A private method can be registered from the right context with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
class CB {
|
||||||
|
private function callback($className) {
|
||||||
|
if ($className == 'Bar') {
|
||||||
|
return 'Foo';
|
||||||
|
} else {
|
||||||
|
return $className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_overload() {
|
||||||
|
return set_new_overload(array($this, 'callback'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$cb = new CB();
|
||||||
|
|
||||||
|
var_dump(set_new_overload(array($cb, 'callback')));
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
|
||||||
|
var_dump($cb->set_overload());
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: set_new_overload() expects parameter 1 to be a valid callback, cannot access private method CB::callback() in %s on line %d
|
||||||
|
NULL
|
||||||
|
string(3) "Bar"
|
||||||
|
bool(true)
|
||||||
|
string(3) "Foo"
|
23
vendors/php-test-helpers/tests/set_new_overload_static_method.phpt
vendored
Executable file
23
vendors/php-test-helpers/tests/set_new_overload_static_method.phpt
vendored
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
--TEST--
|
||||||
|
A static method can be registered as a callback with set_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
class CB {
|
||||||
|
static function callback($className) {
|
||||||
|
return 'Foo';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload(array('CB', 'callback')));
|
||||||
|
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(3) "Foo"
|
33
vendors/php-test-helpers/tests/set_new_overload_unset_reset.phpt
vendored
Executable file
33
vendors/php-test-helpers/tests/set_new_overload_unset_reset.phpt
vendored
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
set_new_overload() can be called after unset_new_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo1 {}
|
||||||
|
class Foo2 {}
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
function callback1($className) {
|
||||||
|
return 'Foo1';
|
||||||
|
}
|
||||||
|
|
||||||
|
function callback2($className) {
|
||||||
|
return 'foo2';
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(set_new_overload('callback1'));
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
var_dump(unset_new_overload());
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
var_dump(set_new_overload('callback2'));
|
||||||
|
var_dump(get_class(new Bar));
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
string(4) "Foo1"
|
||||||
|
bool(true)
|
||||||
|
string(3) "Bar"
|
||||||
|
bool(true)
|
||||||
|
string(4) "Foo2"
|
15
vendors/php-test-helpers/tests/unset_exit_overload.phpt
vendored
Executable file
15
vendors/php-test-helpers/tests/unset_exit_overload.phpt
vendored
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
--TEST--
|
||||||
|
set_exit_overload()
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (!extension_loaded('test_helpers')) die('skip test_helpers extension not loaded');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
set_exit_overload(function() { echo "FALSE\n"; return false; });
|
||||||
|
unset_exit_overload();
|
||||||
|
die("DIE");
|
||||||
|
echo "HAHA";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
DIE
|
Loading…
Add table
Add a link
Reference in a new issue