Skip to content

Commit a95278b

Browse files
committed
Add Version::listNamesByProject()
1 parent 20820d1 commit a95278b

File tree

5 files changed

+198
-0
lines changed

5 files changed

+198
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- New method `Redmine\Api\Role::listNames()` for listing the ids and names of all roles.
1818
- New method `Redmine\Api\TimeEntryActivity::listNames()` for listing the ids and names of all time entry activities.
1919
- New method `Redmine\Api\Tracker::listNames()` for listing the ids and names of all trackers.
20+
- New method `Redmine\Api\Version::listNamesByProject()` for listing the ids and names of all versions of a project.
2021

2122
### Deprecated
2223

src/Redmine/Api/Version.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Version extends AbstractApi
2323
{
2424
private $versions = [];
2525

26+
private $versionNames = [];
27+
2628
/**
2729
* List versions of a project.
2830
*
@@ -51,6 +53,41 @@ final public function listByProject($projectIdentifier, array $params = []): arr
5153
}
5254
}
5355

56+
/**
57+
* Returns an array of all versions by a project with id/name pairs.
58+
*
59+
* @param string|int $projectIdentifier project id or literal identifier
60+
*
61+
* @throws InvalidParameterException if $projectIdentifier is not of type int or string
62+
*
63+
* @return array<int,string> list of version names (id => name)
64+
*/
65+
final public function listNamesByProject($projectIdentifier): array
66+
{
67+
if (! is_int($projectIdentifier) && ! is_string($projectIdentifier)) {
68+
throw new InvalidParameterException(sprintf(
69+
'%s(): Argument #1 ($projectIdentifier) must be of type int or string',
70+
__METHOD__,
71+
));
72+
}
73+
74+
if (array_key_exists($projectIdentifier, $this->versionNames)) {
75+
return $this->versionNames[$projectIdentifier];
76+
}
77+
78+
$this->versionNames[$projectIdentifier] = [];
79+
80+
$list = $this->listByProject($projectIdentifier);
81+
82+
if (array_key_exists('versions', $list)) {
83+
foreach ($list['versions'] as $version) {
84+
$this->versionNames[$projectIdentifier][(int) $version['id']] = $version['name'];
85+
}
86+
}
87+
88+
return $this->versionNames[$projectIdentifier];
89+
}
90+
5491
/**
5592
* List versions.
5693
*

tests/Behat/Bootstrap/VersionContextTrait.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,20 @@ public function iListAllVersionsForProjectIdentifier($identifier)
7272
);
7373
}
7474

75+
/**
76+
* @When I list all version names for project identifier :identifier
77+
*/
78+
public function iListAllVersionNamesForProjectIdentifier($identifier)
79+
{
80+
/** @var Version */
81+
$api = $this->getNativeCurlClient()->getApi('version');
82+
83+
$this->registerClientResponse(
84+
$api->listNamesByProject($identifier),
85+
$api->getLastResponse(),
86+
);
87+
}
88+
7589
/**
7690
* @When I update the version with id :id and the following data
7791
*/

tests/Behat/features/version.feature

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,24 @@ Feature: Interacting with the REST API for versions
162162
| id | 1 |
163163
| name | Test Project |
164164

165+
@wip
166+
Scenario: Listing of multiple version names
167+
Given I have a "NativeCurlClient" client
168+
And I create a project with name "Test Project 1" and identifier "test-project-1"
169+
And I create a project with name "Test Project 2" and identifier "test-project-2"
170+
And I create a version with name "Test-Version 1B" and project identifier "test-project-1"
171+
And I create a version with name "Test-Version 1A" and project identifier "test-project-1"
172+
And I create a version with name "Test-Version 2B" and project identifier "test-project-2"
173+
And I create a version with name "Test-Version 2A" and project identifier "test-project-2"
174+
When I list all version names for project identifier "test-project-2"
175+
Then the response has the status code "200"
176+
And the response has the content type "application/json"
177+
And the returned data contains "2" items
178+
And the returned data contains the following data
179+
| property | value |
180+
| 3 | Test-Version 2B |
181+
| 4 | Test-Version 2A |
182+
165183
Scenario: Updating a version
166184
Given I have a "NativeCurlClient" client
167185
And I create a project with name "Test Project" and identifier "test-project"
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Redmine\Tests\Unit\Api\Version;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\Attributes\DataProviderExternal;
10+
use PHPUnit\Framework\TestCase;
11+
use Redmine\Api\Version;
12+
use Redmine\Exception\InvalidParameterException;
13+
use Redmine\Http\HttpClient;
14+
use Redmine\Tests\Fixtures\AssertingHttpClient;
15+
use Redmine\Tests\Fixtures\TestDataProvider;
16+
17+
#[CoversClass(Version::class)]
18+
class ListNamesByProjectTest extends TestCase
19+
{
20+
/**
21+
* @dataProvider getListNamesByProjectData
22+
*/
23+
#[DataProvider('getListNamesByProjectData')]
24+
public function testListNamesByProjectReturnsCorrectResponse($projectIdentifier, $expectedPath, $responseCode, $response, $expectedResponse)
25+
{
26+
$client = AssertingHttpClient::create(
27+
$this,
28+
[
29+
'GET',
30+
$expectedPath,
31+
'application/json',
32+
'',
33+
$responseCode,
34+
'application/json',
35+
$response,
36+
],
37+
);
38+
39+
// Create the object under test
40+
$api = new Version($client);
41+
42+
// Perform the tests
43+
$this->assertSame($expectedResponse, $api->listNamesByProject($projectIdentifier));
44+
}
45+
46+
public static function getListNamesByProjectData(): array
47+
{
48+
return [
49+
'test without versions' => [
50+
5,
51+
'/projects/5/versions.json',
52+
201,
53+
<<<JSON
54+
{
55+
"versions": []
56+
}
57+
JSON,
58+
[],
59+
],
60+
'test with multiple categories' => [
61+
'test-project',
62+
'/projects/test-project/versions.json',
63+
201,
64+
<<<JSON
65+
{
66+
"versions": [
67+
{"id": 7, "name": "Version 3"},
68+
{"id": 8, "name": "Version 2"},
69+
{"id": 9, "name": "Version 1"}
70+
]
71+
}
72+
JSON,
73+
[
74+
7 => "Version 3",
75+
8 => "Version 2",
76+
9 => "Version 1",
77+
],
78+
],
79+
];
80+
}
81+
82+
public function testListNamesByProjectCallsHttpClientOnlyOnce()
83+
{
84+
$client = AssertingHttpClient::create(
85+
$this,
86+
[
87+
'GET',
88+
'/projects/5/versions.json',
89+
'application/json',
90+
'',
91+
200,
92+
'application/json',
93+
<<<JSON
94+
{
95+
"versions": [
96+
{
97+
"id": 1,
98+
"name": "Version 1"
99+
}
100+
]
101+
}
102+
JSON,
103+
],
104+
);
105+
106+
// Create the object under test
107+
$api = new Version($client);
108+
109+
// Perform the tests
110+
$this->assertSame([1 => 'Version 1'], $api->listNamesByProject(5));
111+
$this->assertSame([1 => 'Version 1'], $api->listNamesByProject(5));
112+
$this->assertSame([1 => 'Version 1'], $api->listNamesByProject(5));
113+
}
114+
115+
/**
116+
* @dataProvider Redmine\Tests\Fixtures\TestDataProvider::getInvalidProjectIdentifiers
117+
*/
118+
#[DataProviderExternal(TestDataProvider::class, 'getInvalidProjectIdentifiers')]
119+
public function testListNamesByProjectWithWrongProjectIdentifierThrowsException($projectIdentifier)
120+
{
121+
$api = new Version($this->createMock(HttpClient::class));
122+
123+
$this->expectException(InvalidParameterException::class);
124+
$this->expectExceptionMessage('Redmine\Api\Version::listNamesByProject(): Argument #1 ($projectIdentifier) must be of type int or string');
125+
126+
$api->listNamesByProject($projectIdentifier);
127+
}
128+
}

0 commit comments

Comments
 (0)