/
home
/
sjslayjy
/
public_html
/
theweavenest
/
vendor
/
rmccue
/
requests
/
tests
/
Upload File
HOME
<?php namespace WpOrg\Requests\Tests; use Closure; use stdClass; use WpOrg\Requests\Exception\InvalidArgument; use WpOrg\Requests\Hooks; use WpOrg\Requests\Tests\Fixtures\ArrayAccessibleObject; use WpOrg\Requests\Tests\Fixtures\StringableObject; use WpOrg\Requests\Tests\TestCase; /** * @coversDefaultClass \WpOrg\Requests\Hooks */ class HooksTest extends TestCase { /** * Object under test. * * @var \Requests\Hooks */ public $hooks; /** * Initialize object under test. * * @return void */ protected function set_up() { $this->hooks = new Hooks(); } /** * Technical test to verify the functionality of the Hooks::register() method. * * @covers ::register * * @return void */ public function testRegister() { // Verify initial state or the hooks property. $this->assertSame( [], $this->getPropertyValue($this->hooks, 'hooks'), 'Initial state of $hooks is not an empty array' ); // Verify that the subkeys are created correctly when they don't exist yet. $this->hooks->register('hookname', [$this, 'dummyCallback1']); $this->assertSame( [ 'hookname' => [ 0 => [ [$this, 'dummyCallback1'], ], ], ], $this->getPropertyValue($this->hooks, 'hooks'), 'Initial hook registration failed' ); // Verify that the subkeys are re-used when they already exist. $this->hooks->register('hookname', [$this, 'dummyCallback2']); $this->assertSame( [ 'hookname' => [ 0 => [ [$this, 'dummyCallback1'], [$this, 'dummyCallback2'], ], ], ], $this->getPropertyValue($this->hooks, 'hooks'), 'Registering a second callback on the same hook with the same priority failed' ); /* * Verify that new subkeys are created when needed. * Also verifies that the input validation isn't too strict for the priority. */ $this->hooks->register('hookname', 'is_int', '10'); $this->assertSame( [ 'hookname' => [ 0 => [ [$this, 'dummyCallback1'], [$this, 'dummyCallback2'], ], 10 => [ 'is_int', ], ], ], $this->getPropertyValue($this->hooks, 'hooks'), 'Registering a callback on a different priority for an existing hook failed' ); } /** * Technical test to verify and safeguard Hooks::register() accepts closure callbacks. * * @covers ::register * * @return void */ public function testRegisterClosureCallback() { $this->hooks->register( 'hookname', function($param) { return true; } ); $hooks_prop = $this->getPropertyValue($this->hooks, 'hooks'); $this->assertArrayHasKey('hookname', $hooks_prop, '$hooks property does not have key ["hookname"]'); $this->assertArrayHasKey(0, $hooks_prop['hookname'], '$hooks property does not have key ["hookname"][0]'); $this->assertArrayHasKey(0, $hooks_prop['hookname'][0], '$hooks property does not have key ["hookname"][0][0]'); $this->assertInstanceof(Closure::class, $hooks_prop['hookname'][0][0], 'Closure callback is not registered correctly'); } /** * Verify that the return value of the dispatch method is false when no hooks are registered. * * @covers ::dispatch * * @return void */ public function testDispatchWithoutRegisteredHooks() { $this->assertFalse($this->hooks->dispatch('hookname')); } /** * Verify that the return value of the dispatch method is false when no hooks are registered for the hook called. * * @covers ::dispatch * * @return void */ public function testDispatchWithoutRegisteredHooksOnDispatchedHook() { $this->hooks->register('hookname', [$this, 'dummyCallback1']); $this->assertFalse($this->hooks->dispatch('other.hookname')); } /** * Technical test to verify that the hook callbacks are called. * * @covers ::dispatch * * @return void */ public function testDispatchWithSingleRegisteredHook() { $mock = $this->getMockBuilder(stdClass::class) ->setMethods(['callback']) ->getMock(); $mock->expects($this->once()) ->method('callback'); $this->hooks->register('hookname', [$mock, 'callback']); $this->assertTrue($this->hooks->dispatch('hookname')); } /** * Technical test to verify that the hook callbacks are called on the correct hook and with the expected arguments. * * @covers ::dispatch * * @return void */ public function testDispatchWithMultipleRegisteredHooks() { $mock = $this->getMockBuilder(stdClass::class) ->setMethods(['callback_a', 'callback_b', 'callback_c']) ->getMock(); $mock->expects($this->never()) ->method('callback_a'); $mock->expects($this->exactly(2)) ->method('callback_b') ->with( $this->identicalTo(10), $this->identicalTo('text') ); $mock->expects($this->once()) ->method('callback_c') ->with( $this->identicalTo(10), $this->identicalTo('text') ); $this->hooks->register('hook_a', [$mock, 'callback_a']); $this->hooks->register('hook_b', [$mock, 'callback_b']); $this->hooks->register('hook_b', [$mock, 'callback_b'], 10); $this->hooks->register('hook_b', [$mock, 'callback_c']); $this->assertTrue($this->hooks->dispatch('hook_b', [10, 'text'])); } /** * Technical test to verify that the dispatch method handles parameters passed by reference correctly. * * @covers ::dispatch * * @return void */ public function testDispatchHandlesParametersPassedByReference() { $this->hooks->register('hookname', [$this, 'dummyCallbackExpectingReferences']); $url = 'original'; $headers = ['original']; $unchanged = 'original'; $not_a_reference = 'original'; $this->assertTrue( $this->hooks->dispatch('hookname', [&$url, &$headers, &$unchanged, $not_a_reference]), 'Hook dispatch did not return true' ); // Verify that the variables were updated by reference (when passed as reference). $this->assertSame('changed', $url, 'Value of $url was not changed by reference'); $this->assertSame(['changed'], $headers, 'Value of $headers was not changed by reference'); $this->assertSame('original', $unchanged, 'Value of unchanged parameter passed by reference, did not match original value'); $this->assertSame('original', $not_a_reference, 'Value of parameter not passed by reference, did not match original value'); } /** * Technical test to verify that the dispatch method doesn't break on PHP 8.0 when passed an associative array. * * @covers ::dispatch * * @return void */ public function testDispatchDoesntBreakWithKeyedParametersArray() { $this->hooks->register('hookname', [$this, 'dummyCallback1']); $this->assertTrue($this->hooks->dispatch('hookname', ['paramA' => 10, 'paramB' => 'text'])); } /** * Verify that hooks are executed based on their priority order. * * Issue https://github.com/WordPress/Requests/issues/452 * * @covers ::dispatch * * @return void */ public function testDispatchRespectsHookPriority() { // Register multiple callbacks for the same hook with a variation of priorities. $this->hooks->register( 'hook_a', function(&$text) { $text .= "no prio 0\n"; } ); $this->hooks->register( 'hook_a', function(&$text) { $text .= "prio 10-1\n"; }, 10 ); $this->hooks->register( 'hook_a', function(&$text) { $text .= "prio -3\n"; }, -3 ); $this->hooks->register( 'hook_a', function(&$text) { $text .= "prio 5\n"; }, 5 ); $this->hooks->register( 'hook_a', function(&$text) { $text .= "prio 2-1\n"; }, 2 ); $this->hooks->register( 'hook_a', function(&$text) { $text .= "prio 2-2\n"; }, 2 ); $this->hooks->register( 'hook_a', function(&$text) { $text .= "prio 10-2\n"; }, 10 ); $text = ''; $expected = "prio -3\nno prio 0\nprio 2-1\nprio 2-2\nprio 5\nprio 10-1\nprio 10-2\n"; $this->assertTrue($this->hooks->dispatch('hook_a', [&$text])); $this->assertSame($expected, $text); } /** * Tests receiving an exception when an invalid input type is passed to `register()` as `$hook`. * * @dataProvider dataInvalidHookname * * @covers ::register * * @param mixed $input Invalid hook name input. * * @return void */ public function testRegisterInvalidHookname($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #1 ($hook) must be of type string'); $this->hooks->register($input, 'is_string'); } /** * Tests receiving an exception when an invalid input type is passed to `dispatch()` as `$hook`. * * @dataProvider dataInvalidHookname * * @covers ::dispatch * * @param mixed $input Invalid hook name input. * * @return void */ public function testDispatchInvalidHookname($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #1 ($hook) must be of type string'); $this->hooks->dispatch($input); } /** * Data Provider. * * @return array */ public function dataInvalidHookname() { return [ 'null' => [null], 'float' => [1.1], 'stringable object' => [new StringableObject('value')], ]; } /** * Tests receiving an exception when an invalid input type is passed to `register()` as `$callback`. * * @dataProvider dataRegisterInvalidCallback * * @covers ::register * * @param mixed $input Invalid callback. * * @return void */ public function testRegisterInvalidCallback($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #2 ($callback) must be of type callable'); $this->hooks->register('hookname', $input); } /** * Data Provider. * * @return array */ public function dataRegisterInvalidCallback() { return [ 'null' => [null], 'non-existent function' => ['functionname'], 'non-existent method' => [[$this, 'dummyCallbackDoesNotExist']], 'empty array' => [[]], 'plain object' => [new stdClass(), 'method'], ]; } /** * Tests receiving an exception when an invalid input type is passed to `register()` as `$priority`. * * @dataProvider dataRegisterInvalidPriority * * @covers ::register * * @param mixed $input Invalid priority. * * @return void */ public function testRegisterInvalidPriority($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #3 ($priority) must be of type int'); $this->hooks->register('hookname', [$this, 'dummyCallback1'], $input); } /** * Data Provider. * * @return array */ public function dataRegisterInvalidPriority() { return [ 'null' => [null], 'float' => [1.1], 'string "123 abc"' => ['123 abc'], ]; } /** * Tests receiving an exception when an invalid input type is passed to `dispatch()` as `$parameters`. * * @dataProvider dataDispatchInvalidParameters * * @covers ::dispatch * * @param mixed $input Invalid parameters array. * * @return void */ public function testDispatchInvalidParameters($input) { $this->expectException(InvalidArgument::class); $this->expectExceptionMessage('Argument #2 ($parameters) must be of type array'); $this->hooks->dispatch('hookname', $input); } /** * Data Provider. * * @return array */ public function dataDispatchInvalidParameters() { return [ 'null' => [null], 'bool false' => [false], 'float' => [1.1], 'string' => ['param'], 'object implementing ArrayAccess' => [new ArrayAccessibleObject()], ]; } /** * Dummy callback method. * * @return void */ public function dummyCallback1() {} /** * Dummy callback method. * * @return void */ public function dummyCallback2() {} /** * Dummy callback method. * * @return void */ public function dummyCallbackExpectingReferences(&$url, &$headers, &$unchanged, $not_a_reference) { $url = 'changed'; $headers = ['changed']; $not_a_reference = 'changed'; } }