From 21a08914bc5f13d063ddb51472ef96d573710a73 Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 18 Dec 2023 16:26:53 +0100 Subject: [PATCH 01/27] Add test for empty Redmine response --- src/Redmine/Api/AbstractApi.php | 5 ++++ tests/Unit/Api/AbstractApiTest.php | 37 ++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/Redmine/Api/AbstractApi.php b/src/Redmine/Api/AbstractApi.php index 3a15ddf9..58a5587a 100644 --- a/src/Redmine/Api/AbstractApi.php +++ b/src/Redmine/Api/AbstractApi.php @@ -307,6 +307,11 @@ protected function attachCustomFieldXML(SimpleXMLElement $xml, array $fields) private function getLastResponseBodyAsArray(): array { $body = $this->client->getLastResponseBody(); + + if ($body === '') { + return []; + } + $contentType = $this->client->getLastResponseContentType(); $returnData = null; diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index 0c186115..a0d41fa6 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -163,12 +163,12 @@ public function testJsonDecodingFromGetMethod($response, $decode, $expected) public static function getJsonDecodingFromGetMethodData(): array { return [ - ['{"foo_bar": 12345}', null, ['foo_bar' => 12345]], // test decode by default - ['{"foo_bar": 12345}', false, '{"foo_bar": 12345}'], - ['{"foo_bar": 12345}', true, ['foo_bar' => 12345]], + 'test decode by default' => ['{"foo_bar": 12345}', null, ['foo_bar' => 12345]], + 'test decode by default, JSON decode: false' => ['{"foo_bar": 12345}', false, '{"foo_bar": 12345}'], + 'test decode by default, JSON decode: true' => ['{"foo_bar": 12345}', true, ['foo_bar' => 12345]], 'Empty body, JSON decode: false' => ['', false, false], 'Empty body, JSON decode: true' => ['', true, false], - ['{"foo_bar":', true, 'Error decoding body as JSON: Syntax error'], // test invalid JSON + 'test invalid JSON' => ['{"foo_bar":', true, 'Error decoding body as JSON: Syntax error'], ]; } @@ -218,6 +218,35 @@ public static function getXmlDecodingFromGetMethodData(): array ]; } + /** + * @covers \Redmine\Api\AbstractApi::retrieveData + * + * @dataProvider retrieveDataData + */ + public function testRetrieveData($response, $contentType, $expected) + { + $client = $this->createMock(Client::class); + $client->method('requestGet')->willReturn(true); + $client->method('getLastResponseBody')->willReturn($response); + $client->method('getLastResponseContentType')->willReturn($contentType); + + $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + + $method = new ReflectionMethod($api, 'retrieveData'); + $method->setAccessible(true); + + $this->assertSame($expected, $method->invoke($api, '/issues.json')); + + } + + public static function retrieveDataData(): array + { + return [ + 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], + 'Empty body' => ['', 'application/json', []], + ]; + } + /** * @covers \Redmine\Api\AbstractApi::retrieveAll */ From e237917112f8933a48c9c52d88c3f70ed02d9a05 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 19 Dec 2023 11:34:30 +0100 Subject: [PATCH 02/27] Replace deprecated PHPUnit method getMockForAbstractClass() --- tests/Unit/Api/AbstractApiTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index a0d41fa6..0a767967 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -21,7 +21,7 @@ public function testIsNotNullReturnsCorrectBoolean(bool $expected, $value) { $client = $this->createMock(Client::class); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, 'isNotNull'); $method->setAccessible(true); @@ -61,7 +61,7 @@ public function testLastCallFailedReturnsCorrectBoolean($statusCode, $expectedBo $client = $this->createMock(Client::class); $client->method('getLastResponseStatusCode')->willReturn($statusCode); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $this->assertSame($expectedBoolean, $api->lastCallFailed()); } @@ -147,7 +147,7 @@ public function testJsonDecodingFromGetMethod($response, $decode, $expected) $client->method('getLastResponseBody')->willReturn($response); $client->method('getLastResponseContentType')->willReturn('application/json'); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, 'get'); $method->setAccessible(true); @@ -183,7 +183,7 @@ public function testXmlDecodingFromRequestMethods($methodName, $response, $decod $client->method('getLastResponseBody')->willReturn($response); $client->method('getLastResponseContentType')->willReturn('application/xml'); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, $methodName); $method->setAccessible(true); @@ -230,7 +230,7 @@ public function testRetrieveData($response, $contentType, $expected) $client->method('getLastResponseBody')->willReturn($response); $client->method('getLastResponseContentType')->willReturn($contentType); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, 'retrieveData'); $method->setAccessible(true); @@ -257,7 +257,7 @@ public function testDeprecatedRetrieveAll() $client->method('getLastResponseBody')->willReturn(''); $client->method('getLastResponseContentType')->willReturn('application/xml'); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, 'retrieveAll'); $method->setAccessible(true); @@ -273,7 +273,7 @@ public function testDeprecatedAttachCustomFieldXML() { $client = $this->createMock(Client::class); - $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, 'attachCustomFieldXML'); $method->setAccessible(true); From 9fa08c3b8d9c86007af6b94a611c4be25cbcd6f8 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 19 Dec 2023 13:11:02 +0100 Subject: [PATCH 03/27] Add dataProvider for testDeprecatedRetrieveAll --- tests/Unit/Api/AbstractApiTest.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index 0a767967..e0710347 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -249,21 +249,30 @@ public static function retrieveDataData(): array /** * @covers \Redmine\Api\AbstractApi::retrieveAll + * + * @dataProvider retrieveAllData */ - public function testDeprecatedRetrieveAll() + public function testDeprecatedRetrieveAll($content, $contentType, $expected) { $client = $this->createMock(Client::class); $client->method('requestGet')->willReturn(true); - $client->method('getLastResponseBody')->willReturn(''); - $client->method('getLastResponseContentType')->willReturn('application/xml'); + $client->method('getLastResponseBody')->willReturn($content); + $client->method('getLastResponseContentType')->willReturn($contentType); $api = new class($client) extends AbstractApi {}; $method = new ReflectionMethod($api, 'retrieveAll'); $method->setAccessible(true); - $this->assertSame([], $method->invoke($api, '/issues.xml')); + $this->assertSame($expected, $method->invoke($api, '')); + } + public static function retrieveAllData(): array + { + return [ + 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], + 'Empty body' => ['', 'application/json', []], + ]; } /** From 308be81ae56ee4d5f2f60c93a44187c397a61c7b Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 20 Dec 2023 16:55:21 +0100 Subject: [PATCH 04/27] restore BC in AbstractApi::retrieveAll() --- src/Redmine/Api/AbstractApi.php | 9 ++++---- tests/Unit/Api/AbstractApiTest.php | 35 +++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Redmine/Api/AbstractApi.php b/src/Redmine/Api/AbstractApi.php index 58a5587a..fa830dad 100644 --- a/src/Redmine/Api/AbstractApi.php +++ b/src/Redmine/Api/AbstractApi.php @@ -4,6 +4,7 @@ use Redmine\Api; use Redmine\Client\Client; +use Redmine\Exception; use Redmine\Exception\SerializerException; use Redmine\Serializer\JsonSerializer; use Redmine\Serializer\PathSerializer; @@ -169,7 +170,7 @@ protected function sanitizeParams(array $defaults, array $params) * @param string $endpoint API end point * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array|false elements found + * @return string|array|false elements found or error message of false */ protected function retrieveAll($endpoint, array $params = []) { @@ -178,6 +179,8 @@ protected function retrieveAll($endpoint, array $params = []) try { $data = $this->retrieveData(strval($endpoint), $params); } catch (SerializerException $e) { + return 'Error decoding body as JSON: '.$e->getPrevious()->getMessage(); + } catch (Exception $e) { $data = false; } @@ -308,10 +311,6 @@ private function getLastResponseBodyAsArray(): array { $body = $this->client->getLastResponseBody(); - if ($body === '') { - return []; - } - $contentType = $this->client->getLastResponseContentType(); $returnData = null; diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index e0710347..d088a946 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -5,6 +5,7 @@ use PHPUnit\Framework\TestCase; use Redmine\Api\AbstractApi; use Redmine\Client\Client; +use Redmine\Exception\SerializerException; use ReflectionMethod; use SimpleXMLElement; @@ -236,14 +237,42 @@ public function testRetrieveData($response, $contentType, $expected) $method->setAccessible(true); $this->assertSame($expected, $method->invoke($api, '/issues.json')); - } public static function retrieveDataData(): array { return [ 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], - 'Empty body' => ['', 'application/json', []], + ]; + } + + /** + * @covers \Redmine\Api\AbstractApi::retrieveData + * + * @dataProvider retrieveDataToExceptionData + */ + public function testRetrieveDataThrowsException($response, $contentType, $expectedException, $expectedMessage) + { + $client = $this->createMock(Client::class); + $client->method('requestGet')->willReturn(true); + $client->method('getLastResponseBody')->willReturn($response); + $client->method('getLastResponseContentType')->willReturn($contentType); + + $api = new class($client) extends AbstractApi {}; + + $method = new ReflectionMethod($api, 'retrieveData'); + $method->setAccessible(true); + + $this->expectException($expectedException); + $this->expectExceptionMessage($expectedMessage); + + $method->invoke($api, '/issues.json'); + } + + public static function retrieveDataToExceptionData(): array + { + return [ + 'Empty body' => ['', 'application/json', SerializerException::class, 'Syntax error" while decoding JSON: '], ]; } @@ -271,7 +300,7 @@ public static function retrieveAllData(): array { return [ 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], - 'Empty body' => ['', 'application/json', []], + 'Empty body' => ['', 'application/json', 'Error decoding body as JSON: Syntax error'], ]; } From e8649fdff528b9db5f23260610664199e4af01ba Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 10:44:21 +0100 Subject: [PATCH 05/27] Add test for json response not containing object or array --- src/Redmine/Api/AbstractApi.php | 2 +- tests/Unit/Api/AbstractApiTest.php | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Redmine/Api/AbstractApi.php b/src/Redmine/Api/AbstractApi.php index fa830dad..7a7b9a1f 100644 --- a/src/Redmine/Api/AbstractApi.php +++ b/src/Redmine/Api/AbstractApi.php @@ -179,7 +179,7 @@ protected function retrieveAll($endpoint, array $params = []) try { $data = $this->retrieveData(strval($endpoint), $params); } catch (SerializerException $e) { - return 'Error decoding body as JSON: '.$e->getPrevious()->getMessage(); + return $e->getMessage(); } catch (Exception $e) { $data = false; } diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index d088a946..6bd2cc20 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -249,7 +249,7 @@ public static function retrieveDataData(): array /** * @covers \Redmine\Api\AbstractApi::retrieveData * - * @dataProvider retrieveDataToExceptionData + * @dataProvider getRetrieveDataToExceptionData */ public function testRetrieveDataThrowsException($response, $contentType, $expectedException, $expectedMessage) { @@ -269,7 +269,7 @@ public function testRetrieveDataThrowsException($response, $contentType, $expect $method->invoke($api, '/issues.json'); } - public static function retrieveDataToExceptionData(): array + public static function getRetrieveDataToExceptionData(): array { return [ 'Empty body' => ['', 'application/json', SerializerException::class, 'Syntax error" while decoding JSON: '], @@ -279,7 +279,7 @@ public static function retrieveDataToExceptionData(): array /** * @covers \Redmine\Api\AbstractApi::retrieveAll * - * @dataProvider retrieveAllData + * @dataProvider getRetrieveAllData */ public function testDeprecatedRetrieveAll($content, $contentType, $expected) { @@ -296,11 +296,12 @@ public function testDeprecatedRetrieveAll($content, $contentType, $expected) $this->assertSame($expected, $method->invoke($api, '')); } - public static function retrieveAllData(): array + public static function getRetrieveAllData(): array { return [ 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], - 'Empty body' => ['', 'application/json', 'Error decoding body as JSON: Syntax error'], + 'String' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'Empty body' => ['', 'application/json', 'Catched error "Syntax error" while decoding JSON: '], ]; } From 83b5762df46c584190a2ec3e824cac585c45bd17 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 10:54:43 +0100 Subject: [PATCH 06/27] BC: let retrieveAll return false on empty response body --- src/Redmine/Api/AbstractApi.php | 10 ++++++---- tests/Unit/Api/AbstractApiTest.php | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Redmine/Api/AbstractApi.php b/src/Redmine/Api/AbstractApi.php index 7a7b9a1f..e404266b 100644 --- a/src/Redmine/Api/AbstractApi.php +++ b/src/Redmine/Api/AbstractApi.php @@ -170,7 +170,7 @@ protected function sanitizeParams(array $defaults, array $params) * @param string $endpoint API end point * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return string|array|false elements found or error message of false + * @return string|array|false elements found or error message or false */ protected function retrieveAll($endpoint, array $params = []) { @@ -178,10 +178,12 @@ protected function retrieveAll($endpoint, array $params = []) try { $data = $this->retrieveData(strval($endpoint), $params); - } catch (SerializerException $e) { - return $e->getMessage(); } catch (Exception $e) { - $data = false; + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); } return $data; diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index 6bd2cc20..85783596 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -301,7 +301,7 @@ public static function getRetrieveAllData(): array return [ 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], 'String' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], - 'Empty body' => ['', 'application/json', 'Catched error "Syntax error" while decoding JSON: '], + 'Empty body' => ['', 'application/json', false], ]; } From 44be88bf51b865f091162841ea54d31ed02ef0ee Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 12:41:43 +0100 Subject: [PATCH 07/27] restore BC in CustomField::all() --- src/Redmine/Api/AbstractApi.php | 2 +- src/Redmine/Api/CustomField.php | 14 ++++++++++++-- tests/Unit/Api/AbstractApiTest.php | 6 +++--- tests/Unit/Api/CustomFieldTest.php | 26 +++++++++++++++----------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/Redmine/Api/AbstractApi.php b/src/Redmine/Api/AbstractApi.php index e404266b..5a86f4d5 100644 --- a/src/Redmine/Api/AbstractApi.php +++ b/src/Redmine/Api/AbstractApi.php @@ -170,7 +170,7 @@ protected function sanitizeParams(array $defaults, array $params) * @param string $endpoint API end point * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return string|array|false elements found or error message or false + * @return array|string|false elements found or error message or false */ protected function retrieveAll($endpoint, array $params = []) { diff --git a/src/Redmine/Api/CustomField.php b/src/Redmine/Api/CustomField.php index 8aa3d8ed..e8744e8d 100644 --- a/src/Redmine/Api/CustomField.php +++ b/src/Redmine/Api/CustomField.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Listing custom fields. * @@ -38,13 +40,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of custom fields found + * @return array|string|false list of custom fields found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index 85783596..7e79a8e4 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -299,9 +299,9 @@ public function testDeprecatedRetrieveAll($content, $contentType, $expected) public static function getRetrieveAllData(): array { return [ - 'test decode by default' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], - 'String' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], - 'Empty body' => ['', 'application/json', false], + 'array response' => ['{"foo_bar": 12345}', 'application/json', ['foo_bar' => 12345]], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], ]; } diff --git a/tests/Unit/Api/CustomFieldTest.php b/tests/Unit/Api/CustomFieldTest.php index 399c390a..dba2bd2d 100644 --- a/tests/Unit/Api/CustomFieldTest.php +++ b/tests/Unit/Api/CustomFieldTest.php @@ -47,28 +47,23 @@ function ($errno, $errstr): bool { * @covers ::get * @covers ::retrieveAll * @covers ::isNotNull + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedResponse = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/custom_fields.json') - ) + ->with('/custom_fields.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new CustomField($client); @@ -77,6 +72,15 @@ public function testAllReturnsClientGetResponse() $this->assertSame($expectedResponse, $api->all()); } + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; + } + /** * Test all(). * From 53e4f70f21e16f2488c6f398d615627642f8ed2c Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 12:50:53 +0100 Subject: [PATCH 08/27] restore BC in Group::all() --- src/Redmine/Api/Group.php | 12 ++++++++++-- tests/Unit/Api/GroupTest.php | 28 ++++++++++++++++------------ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Redmine/Api/Group.php b/src/Redmine/Api/Group.php index a361acae..9893016c 100644 --- a/src/Redmine/Api/Group.php +++ b/src/Redmine/Api/Group.php @@ -43,13 +43,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of groups found + * @return array|string|false list of groups found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/GroupTest.php b/tests/Unit/Api/GroupTest.php index f8773a59..d6081c6d 100644 --- a/tests/Unit/Api/GroupTest.php +++ b/tests/Unit/Api/GroupTest.php @@ -45,34 +45,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/groups.json') - ) + ->with('/groups.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Group($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 6a7a13992567a37d65a63fc7c7a7ac10faecc6f2 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 12:58:44 +0100 Subject: [PATCH 09/27] restore BC in Issue::all() --- src/Redmine/Api/Group.php | 4 ++-- src/Redmine/Api/Issue.php | 13 +++++++++++-- tests/Unit/Api/IssueTest.php | 28 ++++++++++++++++------------ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/Redmine/Api/Group.php b/src/Redmine/Api/Group.php index 9893016c..70414011 100644 --- a/src/Redmine/Api/Group.php +++ b/src/Redmine/Api/Group.php @@ -2,7 +2,7 @@ namespace Redmine\Api; -use Exception; +use Redmine\Exception; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -122,7 +122,7 @@ public function create(array $params = []) */ public function update($id, array $params = []) { - throw new Exception('Not implemented'); + throw new \Exception('Not implemented'); } /** diff --git a/src/Redmine/Api/Issue.php b/src/Redmine/Api/Issue.php index e896885c..c8e8f047 100644 --- a/src/Redmine/Api/Issue.php +++ b/src/Redmine/Api/Issue.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Serializer\JsonSerializer; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -64,13 +65,21 @@ final public function list(array $params = []): array * * @param array $params the additional parameters (cf available $params above) * - * @return array list of issues found + * @return array|string|false list of issues found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/IssueTest.php b/tests/Unit/Api/IssueTest.php index 12bd75db..772decf2 100644 --- a/tests/Unit/Api/IssueTest.php +++ b/tests/Unit/Api/IssueTest.php @@ -67,34 +67,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/issues.json') - ) + ->with('/issues.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Issue($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From c60b11fcaafdba7e09ca078337172f55ca4272eb Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 16:59:28 +0100 Subject: [PATCH 10/27] Restore BC in IssueCategory::all() --- src/Redmine/Api/IssueCategory.php | 13 +++++++++++-- tests/Unit/Api/IssueCategoryTest.php | 26 ++++++++++++++++---------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/Redmine/Api/IssueCategory.php b/src/Redmine/Api/IssueCategory.php index 46ef4afc..9dfbf92d 100644 --- a/src/Redmine/Api/IssueCategory.php +++ b/src/Redmine/Api/IssueCategory.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\PathSerializer; @@ -54,13 +55,21 @@ final public function listByProject($projectIdentifier, array $params = []): arr * @param string|int $project project id or literal identifier * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of issue categories found + * @return array|string|false list of issue categories found or error message or false */ public function all($project, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::listByProject()` instead.', E_USER_DEPRECATED); - return $this->listByProject(strval($project), $params); + try { + return $this->listByProject(strval($project), $params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/IssueCategoryTest.php b/tests/Unit/Api/IssueCategoryTest.php index affdd957..f0dc68fc 100644 --- a/tests/Unit/Api/IssueCategoryTest.php +++ b/tests/Unit/Api/IssueCategoryTest.php @@ -45,35 +45,41 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllDAta * @test */ - public function testAllReturnsClientGetResponseWithProject() + public function testAllReturnsClientGetResponseWithProject($response, $responseType, $expectedResponse) { // Test values $projectId = 5; - $response = '["API Response"]'; - $expectedReturn = ['API Response']; // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/projects/5/issue_categories.json') - ) + ->with('/projects/5/issue_categories.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new IssueCategory($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all($projectId)); + $this->assertSame($expectedResponse, $api->all($projectId)); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 1e166d24b3d5ec1a08300462747c1cf433148eb1 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 23:12:49 +0100 Subject: [PATCH 11/27] restore BC in IssuePriority::all() --- src/Redmine/Api/IssuePriority.php | 12 +++++++++++- tests/Unit/Api/IssuePriorityTest.php | 28 ++++++++++++++++------------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/Redmine/Api/IssuePriority.php b/src/Redmine/Api/IssuePriority.php index 70b07157..4455768d 100644 --- a/src/Redmine/Api/IssuePriority.php +++ b/src/Redmine/Api/IssuePriority.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Listing issue priorities. * @@ -44,6 +46,14 @@ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } } diff --git a/tests/Unit/Api/IssuePriorityTest.php b/tests/Unit/Api/IssuePriorityTest.php index 699e7e21..08911274 100644 --- a/tests/Unit/Api/IssuePriorityTest.php +++ b/tests/Unit/Api/IssuePriorityTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/enumerations/issue_priorities.json') - ) + ->with('/enumerations/issue_priorities.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new IssuePriority($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 96d5bf15f7db7707eaf872453c859621586e26af Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 23:17:26 +0100 Subject: [PATCH 12/27] Restore BC in IssueRelation::all() --- src/Redmine/Api/IssuePriority.php | 2 +- src/Redmine/Api/IssueRelation.php | 13 +++++++++++-- tests/Unit/Api/IssueRelationTest.php | 28 ++++++++++++++++------------ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/Redmine/Api/IssuePriority.php b/src/Redmine/Api/IssuePriority.php index 4455768d..5963af2d 100644 --- a/src/Redmine/Api/IssuePriority.php +++ b/src/Redmine/Api/IssuePriority.php @@ -40,7 +40,7 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of issue priorities found + * @return array|string|false list of issue priorities found or error message or false */ public function all(array $params = []) { diff --git a/src/Redmine/Api/IssueRelation.php b/src/Redmine/Api/IssueRelation.php index 158c5c08..9e4607fc 100644 --- a/src/Redmine/Api/IssueRelation.php +++ b/src/Redmine/Api/IssueRelation.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Serializer\JsonSerializer; /** @@ -42,13 +43,21 @@ final public function listByIssueId(int $issueId, array $params = []): array * @param int $issueId the issue id * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of relations found + * @return array|string|false list of relations found or error message or false */ public function all($issueId, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::listByIssueId()` instead.', E_USER_DEPRECATED); - return $this->listByIssueId($issueId, $params); + try { + return $this->listByIssueId($issueId, $params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/IssueRelationTest.php b/tests/Unit/Api/IssueRelationTest.php index f2236b79..a75e3708 100644 --- a/tests/Unit/Api/IssueRelationTest.php +++ b/tests/Unit/Api/IssueRelationTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponseWithProject() + public function testAllReturnsClientGetResponseWithProject($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/issues/5/relations.json') - ) + ->with('/issues/5/relations.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new IssueRelation($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all(5)); + $this->assertSame($expectedResponse, $api->all(5)); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 8c44e5e1d7bdc0bdfd2e404762460dc1fbdc115d Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 23:20:43 +0100 Subject: [PATCH 13/27] Restore BC in IssueStatus::all() --- src/Redmine/Api/IssueStatus.php | 14 ++++++++++++-- tests/Unit/Api/IssueStatusTest.php | 24 +++++++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/Redmine/Api/IssueStatus.php b/src/Redmine/Api/IssueStatus.php index bcb68eea..68b8eaba 100644 --- a/src/Redmine/Api/IssueStatus.php +++ b/src/Redmine/Api/IssueStatus.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Listing issue statuses. * @@ -38,13 +40,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of issue statuses found + * @return array|string|false list of issue statuses found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/IssueStatusTest.php b/tests/Unit/Api/IssueStatusTest.php index 4e795b1e..e98e5b42 100644 --- a/tests/Unit/Api/IssueStatusTest.php +++ b/tests/Unit/Api/IssueStatusTest.php @@ -44,34 +44,40 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with( $this->stringStartsWith('/issue_statuses.json') ) ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new IssueStatus($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 287cc08338537417be00f8ff1990f91b1a8fb2be Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 23:26:04 +0100 Subject: [PATCH 14/27] Restore BC in Membership::all() --- src/Redmine/Api/Membership.php | 13 +++++++++++-- tests/Unit/Api/IssueStatusTest.php | 4 +--- tests/Unit/Api/MembershipTest.php | 28 ++++++++++++++++------------ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/Redmine/Api/Membership.php b/src/Redmine/Api/Membership.php index c46f77bf..1b569c25 100644 --- a/src/Redmine/Api/Membership.php +++ b/src/Redmine/Api/Membership.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\XmlSerializer; @@ -53,13 +54,21 @@ final public function listByProject($projectIdentifier, array $params = []): arr * @param string|int $project project id or literal identifier * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of memberships found + * @return array|string|false list of memberships found or error message or false */ public function all($project, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::listByProject()` instead.', E_USER_DEPRECATED); - return $this->listByProject(strval($project), $params); + try { + return $this->listByProject(strval($project), $params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/IssueStatusTest.php b/tests/Unit/Api/IssueStatusTest.php index e98e5b42..9651565a 100644 --- a/tests/Unit/Api/IssueStatusTest.php +++ b/tests/Unit/Api/IssueStatusTest.php @@ -53,9 +53,7 @@ public function testAllReturnsClientGetResponse($response, $responseType, $expec $client = $this->createMock(Client::class); $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/issue_statuses.json') - ) + ->with('/issue_statuses.json') ->willReturn(true); $client->expects($this->atLeast(1)) ->method('getLastResponseBody') diff --git a/tests/Unit/Api/MembershipTest.php b/tests/Unit/Api/MembershipTest.php index a27035a2..fd88ec5d 100644 --- a/tests/Unit/Api/MembershipTest.php +++ b/tests/Unit/Api/MembershipTest.php @@ -46,34 +46,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponseWithProject() + public function testAllReturnsClientGetResponseWithProject($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/projects/5/memberships.json') - ) + ->with('/projects/5/memberships.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Membership($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all(5)); + $this->assertSame($expectedResponse, $api->all(5)); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 9c7dd6380b5097659f0f0a39ede1f9b7c6ff6212 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 23:29:48 +0100 Subject: [PATCH 15/27] Restore BC in News::all() --- src/Redmine/Api/News.php | 19 ++++++++++++++----- tests/Unit/Api/NewsTest.php | 28 ++++++++++++++++------------ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Redmine/Api/News.php b/src/Redmine/Api/News.php index 03c816f5..7097c5ca 100644 --- a/src/Redmine/Api/News.php +++ b/src/Redmine/Api/News.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\InvalidParameterException; /** @@ -63,16 +64,24 @@ final public function list(array $params = []): array * @param string|int $project project id or literal identifier [optional] * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of news found + * @return array|string|false list of news found or error message or false */ public function all($project = null, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` or `'.__CLASS__.'::listByProject()` instead.', E_USER_DEPRECATED); - if (null === $project) { - return $this->list($params); - } else { - return $this->listByProject(strval($project), $params); + try { + if (null === $project) { + return $this->list($params); + } else { + return $this->listByProject(strval($project), $params); + } + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); } } } diff --git a/tests/Unit/Api/NewsTest.php b/tests/Unit/Api/NewsTest.php index fd868599..7fbb4b6c 100644 --- a/tests/Unit/Api/NewsTest.php +++ b/tests/Unit/Api/NewsTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/news.json') - ) + ->with('/news.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new News($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 8707b840671f20073134c09586f17c370966b2e7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 21 Dec 2023 23:55:27 +0100 Subject: [PATCH 16/27] Restore BC in Project::all() --- src/Redmine/Api/Project.php | 13 +++++++++++-- tests/Unit/Api/ProjectTest.php | 24 +++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Redmine/Api/Project.php b/src/Redmine/Api/Project.php index 4e4b5655..2aa89bfe 100755 --- a/src/Redmine/Api/Project.php +++ b/src/Redmine/Api/Project.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -42,13 +43,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of projects found + * @return array|string|false list of projects found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/ProjectTest.php b/tests/Unit/Api/ProjectTest.php index f780fc37..6025c916 100644 --- a/tests/Unit/Api/ProjectTest.php +++ b/tests/Unit/Api/ProjectTest.php @@ -47,32 +47,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with('/projects.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Project($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 93f7d4da52d10dbcc6765232182d875bf0a717f4 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 00:04:29 +0100 Subject: [PATCH 17/27] Restore BC in Query::all() --- src/Redmine/Api/Query.php | 14 ++++++++++++-- tests/Unit/Api/QueryTest.php | 28 ++++++++++++++++------------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Redmine/Api/Query.php b/src/Redmine/Api/Query.php index 04c4a9d3..8a4daac1 100644 --- a/src/Redmine/Api/Query.php +++ b/src/Redmine/Api/Query.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Custom queries retrieval. * @@ -38,12 +40,20 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of queries found + * @return array|string|false list of queries found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } } diff --git a/tests/Unit/Api/QueryTest.php b/tests/Unit/Api/QueryTest.php index 659079f3..0b22773e 100644 --- a/tests/Unit/Api/QueryTest.php +++ b/tests/Unit/Api/QueryTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/queries.json') - ) + ->with('/queries.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Query($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 6aed6289e621ed5ecfc0c23a823c506ebc94ab4b Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 00:08:28 +0100 Subject: [PATCH 18/27] Restore BC in Role::all() --- src/Redmine/Api/Role.php | 14 ++++++++++++-- tests/Unit/Api/RoleTest.php | 28 ++++++++++++++++------------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Redmine/Api/Role.php b/src/Redmine/Api/Role.php index 63de7996..9221b197 100644 --- a/src/Redmine/Api/Role.php +++ b/src/Redmine/Api/Role.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Listing roles. * @@ -38,13 +40,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of roles found + * @return array|string|false list of roles found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/RoleTest.php b/tests/Unit/Api/RoleTest.php index 61558ef7..38022ceb 100644 --- a/tests/Unit/Api/RoleTest.php +++ b/tests/Unit/Api/RoleTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/roles.json') - ) + ->with('/roles.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Role($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 8615d5abea42029e7b618810561b1f2453f50e1c Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 00:12:31 +0100 Subject: [PATCH 19/27] restore BC in Search::search() --- src/Redmine/Api/Search.php | 12 +++++++++++- tests/Unit/Api/Search/SearchTest.php | 26 +++++++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Redmine/Api/Search.php b/src/Redmine/Api/Search.php index e2cd5b26..54ca7fb9 100644 --- a/src/Redmine/Api/Search.php +++ b/src/Redmine/Api/Search.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * @see http://www.redmine.org/projects/redmine/wiki/Rest_Search */ @@ -43,6 +45,14 @@ public function search($query, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::listByQuery()` instead.', E_USER_DEPRECATED); - return $this->listByQuery($query, $params); + try { + return $this->listByQuery($query, $params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } } diff --git a/tests/Unit/Api/Search/SearchTest.php b/tests/Unit/Api/Search/SearchTest.php index b604d290..2eb9126d 100644 --- a/tests/Unit/Api/Search/SearchTest.php +++ b/tests/Unit/Api/Search/SearchTest.php @@ -33,30 +33,38 @@ function ($errno, $errstr): bool { $api->search('query'); } - public function testSearchReturnsClientGetResponse() + /** + * @dataProvider getAllData + */ + public function testSearchReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with('/search.json?limit=25&offset=0&q=query') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Search($client); // Perform the tests - $this->assertSame($expectedReturn, $api->search('query')); + $this->assertSame($expectedResponse, $api->search('query')); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } public function testSearchReturnsClientGetResponseWithParameters() From dd14a559a87e5073d52aa82a81ee20deb6f3896d Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 00:16:30 +0100 Subject: [PATCH 20/27] restore BC in TimeEntry::all() --- src/Redmine/Api/Search.php | 2 +- src/Redmine/Api/TimeEntry.php | 13 +++++++++++-- tests/Unit/Api/TimeEntryTest.php | 15 ++++++--------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/Redmine/Api/Search.php b/src/Redmine/Api/Search.php index 54ca7fb9..015fa766 100644 --- a/src/Redmine/Api/Search.php +++ b/src/Redmine/Api/Search.php @@ -39,7 +39,7 @@ final public function listByQuery(string $query, array $params = []): array * @param string $query string to search * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of results (projects, issues) + * @return array|string|false list of results (projects, issues) found or error message or false */ public function search($query, array $params = []) { diff --git a/src/Redmine/Api/TimeEntry.php b/src/Redmine/Api/TimeEntry.php index 2bf71752..9f233422 100644 --- a/src/Redmine/Api/TimeEntry.php +++ b/src/Redmine/Api/TimeEntry.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\XmlSerializer; @@ -41,13 +42,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of time entries found + * @return array|string|false list of time entries found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/TimeEntryTest.php b/tests/Unit/Api/TimeEntryTest.php index 5f407da4..582aaf9b 100644 --- a/tests/Unit/Api/TimeEntryTest.php +++ b/tests/Unit/Api/TimeEntryTest.php @@ -45,32 +45,29 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with('/time_entries.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new TimeEntry($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); } /** From 8a4f7c3ca22dab768d1758bf58ec5fd0ec4fbeaa Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 00:18:33 +0100 Subject: [PATCH 21/27] Add missing dataProvider --- tests/Unit/Api/TimeEntryTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Unit/Api/TimeEntryTest.php b/tests/Unit/Api/TimeEntryTest.php index 582aaf9b..e95fd591 100644 --- a/tests/Unit/Api/TimeEntryTest.php +++ b/tests/Unit/Api/TimeEntryTest.php @@ -70,6 +70,15 @@ public function testAllReturnsClientGetResponse($response, $responseType, $expec $this->assertSame($expectedResponse, $api->all()); } + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; + } + /** * Test all(). * From beeaaf77f96932877e6f9ad18026c997d716836e Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 08:21:52 +0100 Subject: [PATCH 22/27] Restore BC in TimeEntryActivity::all() --- src/Redmine/Api/TimeEntryActivity.php | 14 ++++++++++-- tests/Unit/Api/TimeEntryActivityTest.php | 28 ++++++++++++++---------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Redmine/Api/TimeEntryActivity.php b/src/Redmine/Api/TimeEntryActivity.php index c3e5bcd9..23adbe65 100644 --- a/src/Redmine/Api/TimeEntryActivity.php +++ b/src/Redmine/Api/TimeEntryActivity.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Listing time entry activities. * @@ -34,13 +36,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of time entry activities found + * @return array|string|false list of time entry activities found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/TimeEntryActivityTest.php b/tests/Unit/Api/TimeEntryActivityTest.php index da1a5ce6..492e563e 100644 --- a/tests/Unit/Api/TimeEntryActivityTest.php +++ b/tests/Unit/Api/TimeEntryActivityTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/enumerations/time_entry_activities.json') - ) + ->with('/enumerations/time_entry_activities.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new TimeEntryActivity($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From e458e976579c74819a9be3929c9120f45d131b80 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 09:36:55 +0100 Subject: [PATCH 23/27] Restore BC in Tracker::all() --- src/Redmine/Api/Tracker.php | 14 ++++++++++++-- tests/Unit/Api/TrackerTest.php | 28 ++++++++++++++++------------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Redmine/Api/Tracker.php b/src/Redmine/Api/Tracker.php index 95c66811..0df4e0b9 100644 --- a/src/Redmine/Api/Tracker.php +++ b/src/Redmine/Api/Tracker.php @@ -2,6 +2,8 @@ namespace Redmine\Api; +use Redmine\Exception; + /** * Listing trackers. * @@ -38,13 +40,21 @@ final public function list(array $params = []): array * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of trackers found + * @return array|string|false list of trackers found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/TrackerTest.php b/tests/Unit/Api/TrackerTest.php index 041aa14b..35343bf1 100644 --- a/tests/Unit/Api/TrackerTest.php +++ b/tests/Unit/Api/TrackerTest.php @@ -44,34 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') - ->with( - $this->stringStartsWith('/trackers.json') - ) + ->with('/trackers.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Tracker($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From e3c509b5a3833aefdc1e9df786415a1170444efa Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 10:41:51 +0100 Subject: [PATCH 24/27] Restore BC in User::all() --- src/Redmine/Api/User.php | 13 +++++++++++-- tests/Unit/Api/UserTest.php | 24 +++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Redmine/Api/User.php b/src/Redmine/Api/User.php index 33e6cdeb..5b575144 100644 --- a/src/Redmine/Api/User.php +++ b/src/Redmine/Api/User.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -42,13 +43,21 @@ final public function list(array $params = []): array * * @param array $params to allow offset/limit (and more) to be passed * - * @return array list of users found + * @return array|string|false list of users found or error message or false */ public function all(array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::list()` instead.', E_USER_DEPRECATED); - return $this->list($params); + try { + return $this->list($params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/UserTest.php b/tests/Unit/Api/UserTest.php index 9d1d7087..46d04dd0 100644 --- a/tests/Unit/Api/UserTest.php +++ b/tests/Unit/Api/UserTest.php @@ -119,32 +119,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with('/users.json') ->willReturn(true); - $client->expects($this->exactly(1)) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new User($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all()); + $this->assertSame($expectedResponse, $api->all()); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 8b8c54b7e8c20da5e0635ba15ddd0d556c42ae7d Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 10:47:16 +0100 Subject: [PATCH 25/27] Restore BC in Version::all() --- src/Redmine/Api/Version.php | 13 +++++++++++-- tests/Unit/Api/VersionTest.php | 24 +++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Redmine/Api/Version.php b/src/Redmine/Api/Version.php index 1cd2620f..18f7e354 100644 --- a/src/Redmine/Api/Version.php +++ b/src/Redmine/Api/Version.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Exception\MissingParameterException; use Redmine\Serializer\XmlSerializer; @@ -51,13 +52,21 @@ final public function listByProject($projectIdentifier, array $params = []): arr * @param string|int $project project id or literal identifier * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of versions found + * @return array|string|false list of versions found or error message or false */ public function all($project, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::listByProject()` instead.', E_USER_DEPRECATED); - return $this->listByProject(strval($project), $params); + try { + return $this->listByProject(strval($project), $params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/VersionTest.php b/tests/Unit/Api/VersionTest.php index 9efc32a8..cdf6d629 100644 --- a/tests/Unit/Api/VersionTest.php +++ b/tests/Unit/Api/VersionTest.php @@ -46,32 +46,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with('/projects/5/versions.json') ->willReturn(true); - $client->expects($this->once()) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Version($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all(5)); + $this->assertSame($expectedResponse, $api->all(5)); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 98f39bf9568c0a25ae2d280bdd8e7d95d72066cf Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 10:54:44 +0100 Subject: [PATCH 26/27] Restore BC in Wiki::all() --- src/Redmine/Api/Wiki.php | 13 +++++++++++-- tests/Unit/Api/WikiTest.php | 24 +++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Redmine/Api/Wiki.php b/src/Redmine/Api/Wiki.php index 549fd9a3..015b955f 100644 --- a/src/Redmine/Api/Wiki.php +++ b/src/Redmine/Api/Wiki.php @@ -2,6 +2,7 @@ namespace Redmine\Api; +use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -51,13 +52,21 @@ final public function listByProject($projectIdentifier, array $params = []): arr * @param int|string $project project name * @param array $params optional parameters to be passed to the api (offset, limit, ...) * - * @return array list of wiki pages found for the given project + * @return array|string|false list of wiki pages found or error message or false */ public function all($project, array $params = []) { @trigger_error('`'.__METHOD__.'()` is deprecated since v2.4.0, use `'.__CLASS__.'::listByProject()` instead.', E_USER_DEPRECATED); - return $this->listByProject(strval($project), $params); + try { + return $this->listByProject(strval($project), $params); + } catch (Exception $e) { + if ($this->client->getLastResponseBody() === '') { + return false; + } + + return $e->getMessage(); + } } /** diff --git a/tests/Unit/Api/WikiTest.php b/tests/Unit/Api/WikiTest.php index 6e10894b..6cdf9c47 100644 --- a/tests/Unit/Api/WikiTest.php +++ b/tests/Unit/Api/WikiTest.php @@ -44,32 +44,38 @@ function ($errno, $errstr): bool { * Test all(). * * @covers ::all + * @dataProvider getAllData * @test */ - public function testAllReturnsClientGetResponse() + public function testAllReturnsClientGetResponse($response, $responseType, $expectedResponse) { - // Test values - $response = '["API Response"]'; - $expectedReturn = ['API Response']; - // Create the used mock objects $client = $this->createMock(Client::class); - $client->expects($this->once()) + $client->expects($this->exactly(1)) ->method('requestGet') ->with('/projects/5/wiki/index.json') ->willReturn(true); - $client->expects($this->once()) + $client->expects($this->atLeast(1)) ->method('getLastResponseBody') ->willReturn($response); $client->expects($this->exactly(1)) ->method('getLastResponseContentType') - ->willReturn('application/json'); + ->willReturn($responseType); // Create the object under test $api = new Wiki($client); // Perform the tests - $this->assertSame($expectedReturn, $api->all(5)); + $this->assertSame($expectedResponse, $api->all(5)); + } + + public static function getAllData(): array + { + return [ + 'array response' => ['["API Response"]', 'application/json', ['API Response']], + 'string response' => ['"string"', 'application/json', 'Could not convert response body into array: "string"'], + 'false response' => ['', 'application/json', false], + ]; } /** From 5dbecd046379487d85bad755ad70f9f8822a3b29 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Dec 2023 11:28:03 +0100 Subject: [PATCH 27/27] Add throws phpdoc tag to list() methods --- src/Redmine/Api/CustomField.php | 3 +++ src/Redmine/Api/Group.php | 3 +++ src/Redmine/Api/Issue.php | 3 +++ src/Redmine/Api/IssueCategory.php | 2 ++ src/Redmine/Api/IssuePriority.php | 3 +++ src/Redmine/Api/IssueRelation.php | 3 +++ src/Redmine/Api/IssueStatus.php | 3 +++ src/Redmine/Api/Membership.php | 2 ++ src/Redmine/Api/News.php | 6 ++++++ src/Redmine/Api/Project.php | 3 +++ src/Redmine/Api/Query.php | 3 +++ src/Redmine/Api/Role.php | 3 +++ src/Redmine/Api/Search.php | 3 +++ src/Redmine/Api/TimeEntry.php | 3 +++ src/Redmine/Api/TimeEntryActivity.php | 3 +++ src/Redmine/Api/Tracker.php | 3 +++ src/Redmine/Api/User.php | 3 +++ src/Redmine/Api/Version.php | 3 +++ src/Redmine/Api/Wiki.php | 3 +++ 19 files changed, 58 insertions(+) diff --git a/src/Redmine/Api/CustomField.php b/src/Redmine/Api/CustomField.php index e8744e8d..4282d925 100644 --- a/src/Redmine/Api/CustomField.php +++ b/src/Redmine/Api/CustomField.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Listing custom fields. @@ -22,6 +23,8 @@ class CustomField extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of custom fields found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Group.php b/src/Redmine/Api/Group.php index 70414011..6bbfdc73 100644 --- a/src/Redmine/Api/Group.php +++ b/src/Redmine/Api/Group.php @@ -4,6 +4,7 @@ use Redmine\Exception; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -25,6 +26,8 @@ class Group extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of groups found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Issue.php b/src/Redmine/Api/Issue.php index c8e8f047..a9aae152 100644 --- a/src/Redmine/Api/Issue.php +++ b/src/Redmine/Api/Issue.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; use Redmine\Serializer\JsonSerializer; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -39,6 +40,8 @@ class Issue extends AbstractApi * * @param array $params the additional parameters (cf available $params above) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of issues found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/IssueCategory.php b/src/Redmine/Api/IssueCategory.php index 9dfbf92d..d4599970 100644 --- a/src/Redmine/Api/IssueCategory.php +++ b/src/Redmine/Api/IssueCategory.php @@ -5,6 +5,7 @@ use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -28,6 +29,7 @@ class IssueCategory extends AbstractApi * @param array $params optional parameters to be passed to the api (offset, limit, ...) * * @throws InvalidParameterException if $projectIdentifier is not of type int or string + * @throws SerializerException if response body could not be converted into array * * @return array list of issue categories found */ diff --git a/src/Redmine/Api/IssuePriority.php b/src/Redmine/Api/IssuePriority.php index 5963af2d..eb1eb5e1 100644 --- a/src/Redmine/Api/IssuePriority.php +++ b/src/Redmine/Api/IssuePriority.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Listing issue priorities. @@ -22,6 +23,8 @@ class IssuePriority extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of issue priorities found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/IssueRelation.php b/src/Redmine/Api/IssueRelation.php index 9e4607fc..262ebe2f 100644 --- a/src/Redmine/Api/IssueRelation.php +++ b/src/Redmine/Api/IssueRelation.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; use Redmine\Serializer\JsonSerializer; /** @@ -24,6 +25,8 @@ class IssueRelation extends AbstractApi * @param int $issueId the issue id * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of relations found */ final public function listByIssueId(int $issueId, array $params = []): array diff --git a/src/Redmine/Api/IssueStatus.php b/src/Redmine/Api/IssueStatus.php index 68b8eaba..3df6d5e1 100644 --- a/src/Redmine/Api/IssueStatus.php +++ b/src/Redmine/Api/IssueStatus.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Listing issue statuses. @@ -22,6 +23,8 @@ class IssueStatus extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of issue statuses found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Membership.php b/src/Redmine/Api/Membership.php index 1b569c25..e1570830 100644 --- a/src/Redmine/Api/Membership.php +++ b/src/Redmine/Api/Membership.php @@ -5,6 +5,7 @@ use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\XmlSerializer; /** @@ -27,6 +28,7 @@ class Membership extends AbstractApi * @param array $params optional parameters to be passed to the api (offset, limit, ...) * * @throws InvalidParameterException if $projectIdentifier is not of type int or string + * @throws SerializerException if response body could not be converted into array * * @return array list of memberships found */ diff --git a/src/Redmine/Api/News.php b/src/Redmine/Api/News.php index 7097c5ca..12953c0d 100644 --- a/src/Redmine/Api/News.php +++ b/src/Redmine/Api/News.php @@ -4,6 +4,7 @@ use Redmine\Exception; use Redmine\Exception\InvalidParameterException; +use Redmine\Exception\SerializerException; /** * @see http://www.redmine.org/projects/redmine/wiki/Rest_News @@ -22,6 +23,9 @@ class News extends AbstractApi * @param string|int $projectIdentifier project id or literal identifier * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws InvalidParameterException if $projectIdentifier is not of type int or string + * @throws SerializerException if response body could not be converted into array + * * @return array list of news found */ final public function listByProject($projectIdentifier, array $params = []): array @@ -45,6 +49,8 @@ final public function listByProject($projectIdentifier, array $params = []): arr * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of news found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Project.php b/src/Redmine/Api/Project.php index 2aa89bfe..3a5a82c1 100755 --- a/src/Redmine/Api/Project.php +++ b/src/Redmine/Api/Project.php @@ -4,6 +4,7 @@ use Redmine\Exception; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -25,6 +26,8 @@ class Project extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of projects found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Query.php b/src/Redmine/Api/Query.php index 8a4daac1..18694a05 100644 --- a/src/Redmine/Api/Query.php +++ b/src/Redmine/Api/Query.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Custom queries retrieval. @@ -22,6 +23,8 @@ class Query extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of queries found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Role.php b/src/Redmine/Api/Role.php index 9221b197..30b4e8a4 100644 --- a/src/Redmine/Api/Role.php +++ b/src/Redmine/Api/Role.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Listing roles. @@ -22,6 +23,8 @@ class Role extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of roles found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Search.php b/src/Redmine/Api/Search.php index 015fa766..c7c31c3d 100644 --- a/src/Redmine/Api/Search.php +++ b/src/Redmine/Api/Search.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * @see http://www.redmine.org/projects/redmine/wiki/Rest_Search @@ -19,6 +20,8 @@ class Search extends AbstractApi * @param string $query string to search * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of results (projects, issues) */ final public function listByQuery(string $query, array $params = []): array diff --git a/src/Redmine/Api/TimeEntry.php b/src/Redmine/Api/TimeEntry.php index 9f233422..e1586271 100644 --- a/src/Redmine/Api/TimeEntry.php +++ b/src/Redmine/Api/TimeEntry.php @@ -4,6 +4,7 @@ use Redmine\Exception; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\XmlSerializer; /** @@ -24,6 +25,8 @@ class TimeEntry extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of time entries found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/TimeEntryActivity.php b/src/Redmine/Api/TimeEntryActivity.php index 23adbe65..427a41ae 100644 --- a/src/Redmine/Api/TimeEntryActivity.php +++ b/src/Redmine/Api/TimeEntryActivity.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Listing time entry activities. @@ -20,6 +21,8 @@ class TimeEntryActivity extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of time entry activities found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Tracker.php b/src/Redmine/Api/Tracker.php index 0df4e0b9..4358ec0a 100644 --- a/src/Redmine/Api/Tracker.php +++ b/src/Redmine/Api/Tracker.php @@ -3,6 +3,7 @@ namespace Redmine\Api; use Redmine\Exception; +use Redmine\Exception\SerializerException; /** * Listing trackers. @@ -22,6 +23,8 @@ class Tracker extends AbstractApi * * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of trackers found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/User.php b/src/Redmine/Api/User.php index 5b575144..f4008aad 100644 --- a/src/Redmine/Api/User.php +++ b/src/Redmine/Api/User.php @@ -4,6 +4,7 @@ use Redmine\Exception; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -25,6 +26,8 @@ class User extends AbstractApi * * @param array $params to allow offset/limit (and more) to be passed * + * @throws SerializerException if response body could not be converted into array + * * @return array list of users found */ final public function list(array $params = []): array diff --git a/src/Redmine/Api/Version.php b/src/Redmine/Api/Version.php index 18f7e354..31863065 100644 --- a/src/Redmine/Api/Version.php +++ b/src/Redmine/Api/Version.php @@ -5,6 +5,7 @@ use Redmine\Exception; use Redmine\Exception\InvalidParameterException; use Redmine\Exception\MissingParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\XmlSerializer; /** @@ -26,6 +27,8 @@ class Version extends AbstractApi * @param string|int $projectIdentifier project id or literal identifier * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of versions found */ final public function listByProject($projectIdentifier, array $params = []): array diff --git a/src/Redmine/Api/Wiki.php b/src/Redmine/Api/Wiki.php index 015b955f..fba8abab 100644 --- a/src/Redmine/Api/Wiki.php +++ b/src/Redmine/Api/Wiki.php @@ -4,6 +4,7 @@ use Redmine\Exception; use Redmine\Exception\InvalidParameterException; +use Redmine\Exception\SerializerException; use Redmine\Serializer\PathSerializer; use Redmine\Serializer\XmlSerializer; @@ -26,6 +27,8 @@ class Wiki extends AbstractApi * @param int|string $projectIdentifier project id or slug * @param array $params optional parameters to be passed to the api (offset, limit, ...) * + * @throws SerializerException if response body could not be converted into array + * * @return array list of wiki pages found for the given project */ final public function listByProject($projectIdentifier, array $params = []): array