Completed
Pull Request — master (#63)
by
unknown
01:15
created

testMultiplePackagesComparison()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 33

Duplication

Lines 33
Ratio 100 %

Importance

Changes 0
Metric Value
dl 33
loc 33
rs 9.392
c 0
b 0
f 0
cc 4
nc 5
nop 3
1
<?php
2
3
namespace SLLH\ComposerVersionsCheck\Tests;
4
5
use Composer\Package\Link;
6
use Composer\Package\Package;
7
use Composer\Package\RootPackage;
8
use Composer\Repository\ArrayRepository;
9
use Composer\Repository\WritableArrayRepository;
10
use SLLH\ComposerVersionsCheck\VersionsCheck;
11
12
/**
13
 * @author Sullivan Senechal <[email protected]>
14
 */
15
class VersionsCheckTest extends \PHPUnit_Framework_TestCase
16
{
17
    /**
18
     * @var ArrayRepository
19
     */
20
    private $distRepository;
21
22
    /**
23
     * @var WritableArrayRepository
24
     */
25
    private $localRepository;
26
27
    /**
28
     * @var RootPackage
29
     */
30
    private $rootPackage;
31
32
    /**
33
     * @var VersionsCheck
34
     */
35
    private $versionsCheck;
36
37
    /**
38
     * {@inheritdoc}
39
     */
40
    protected function setUp()
41
    {
42
        $this->distRepository = new ArrayRepository();
43
        $this->localRepository = new WritableArrayRepository();
44
45
        $this->rootPackage = new RootPackage('my/project', '1.0.0', '1.0.0');
46
        $this->versionsCheck = new VersionsCheck();
47
    }
48
49
    /**
50
     * @dataProvider getOutdatedDetectionTestData
51
     *
52
     * @param string $actualVersion
53
     * @param string $higherVersion
54
     * @param bool   $shouldBeUpdated
55
     * @param bool   $preferStable
56
     */
57
    public function testOutdatedDetection($actualVersion, $higherVersion, $shouldBeUpdated, $preferStable = false)
58
    {
59
        $this->distRepository->addPackage(new Package('foo/bar', $higherVersion, $higherVersion));
60
        $this->localRepository->addPackage(new Package('foo/bar', $actualVersion, $actualVersion));
61
62
        $this->rootPackage->setPreferStable($preferStable);
63
        $this->checkPackages();
64
65
        // Must have one outdatedPackage if this should be updated
66
        if (true === $shouldBeUpdated) {
67
            $this->assertAttributeCount(1, 'outdatedPackages', $this->versionsCheck);
68
            $this->assertSame(sprintf(<<<'EOF'
69
<warning>1 package is not up to date:</warning>
70
71
  - <info>foo/bar</info> (<comment>%s</comment>) latest is <comment>%s</comment>
72
73
74
EOF
75
                , $actualVersion, $higherVersion), $this->versionsCheck->getOutput());
76
        } else {
77
            $this->assertAttributeCount(0, 'outdatedPackages', $this->versionsCheck);
78
            $this->assertSame("<info>All packages are up to date.</info>\n", $this->versionsCheck->getOutput());
79
        }
80
    }
81
82
    /**
83
     * @return array
84
     */
85
    public function getOutdatedDetectionTestData()
86
    {
87
        return array(
88
            array('1.0.0', '1.0.0', false),
89
            array('1.0.0', '1.0.0', false),
90
            array('1.0.0', '2.0.0', true),
91
            array('2.0.0', '1.0.0', false),
92
            array('2.0.0', '2.0.0', false),
93
            array('2.0.0', '1.9.9', false),
94
            array('1.9.9', '2.0.0', true),
95
            array('2.0.0', '2.1.0-alpha1', true),        // Should be true because no stable package available
96
            array('2.0.0', '2.1.0-alpha1', false, true), // Should be false because of minimum stability
97
            array('2.0.0-alpha1', '2.1.0-alpha2', true),
98
        );
99
    }
100
101
    /**
102
     * @dataProvider getMultiplePackagesComparisonTestsData
103
     *
104
     * @param bool $preferStable
105
     * @param int  $outdatedPackagesCount
106
     */
107 View Code Duplication
    public function testMultiplePackagesComparison(array $packagesData, $preferStable, $outdatedPackagesCount)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
    {
109
        $this->rootPackage->setMinimumStability('dev');
110
        $this->rootPackage->setPreferStable($preferStable);
111
112
        $shouldBeUpdatedOutput = array();
113
114
        foreach ($packagesData as $name => $packageData) {
115
            list($actualVersion, $availableVersions, $expectedVersion) = $packageData;
116
            $this->localRepository->addPackage(new Package($name, $actualVersion, $actualVersion));
117
            foreach ($availableVersions as $availableVersion) {
118
                $this->distRepository->addPackage(new Package($name, $availableVersion, $availableVersion));
119
            }
120
121
            if (false !== $expectedVersion) {
122
                $shouldBeUpdatedOutput[] = sprintf(
123
                    '  - <info>%s</info> (<comment>%s</comment>) latest is <comment>%s</comment>',
124
                    $name, $actualVersion, $expectedVersion
125
                );
126
            }
127
        }
128
129
        $this->checkPackages();
130
131
        $this->assertSame(sprintf(<<<'EOF'
132
<warning>%d packages are not up to date:</warning>
133
134
%s
135
136
137
EOF
138
        , $outdatedPackagesCount, implode("\n\n", $shouldBeUpdatedOutput)), $this->versionsCheck->getOutput());
139
    }
140
141
    /**
142
     * @return array
143
     */
144
    public function getMultiplePackagesComparisonTestsData()
145
    {
146
        return array(
147
            array(array(
148
                'foo/bar' => array('1.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
149
                'some/package' => array('1.0.4', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
150
                'vendor/package-1' => array('2.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), false),
151
                'vendor/up-to-date' => array('9.9.0', array('8.0.0', '9.9.0', '1.0-dev'), false),
152
                'vendor/dev-master' => array('9.9.0', array('8.0.0', '9.9.0', '10.0-dev'), '10.0-dev'),
153
                'vendor/package-2' => array('1.0.0', array('1.0.0', '1.0.1', '2.0.0', '2.0.0-alpha1'), '2.0.0'),
154
                'vendor/package-3' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), '2.0.0-alpha1'),
155
                'vendor/prefer-stable' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), '2.0.0-alpha1'),
156
            ), false, 6),
157
            array(array(
158
                'foo/bar' => array('1.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
159
                'some/package' => array('1.0.4', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
160
                'vendor/package-1' => array('2.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), false),
161
                'vendor/up-to-date' => array('9.9.0', array('8.0.0', '9.9.0', 'dev-master'), false),
162
                'vendor/package-2' => array('1.0.0', array('1.0.0', '1.0.1', '2.0.0', '2.0.0-alpha1'), '2.0.0'),
163
                'vendor/package-3' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), false),
164
                'vendor/prefer-stable' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), false),
165
            ), true, 3),
166
        );
167
    }
168
169
    public function testOutdatedWithLinks()
170
    {
171
        $this->distRepository->addPackage(new Package('foo/bar', '2.0', '2.0'));
172
        $this->localRepository->addPackage(new Package('foo/bar', '1.1', '1.1'));
173
174
        $linkedPackage = new Package('dummy/link', '1.0', '1.0');
175
        $linkedPackage->setRequires(array(new Link('dummy/link', 'foo/bar', null, '', '1.*')));
176
        $this->localRepository->addPackage($linkedPackage);
177
178
        // To test root package detection
179
        $this->localRepository->addPackage($this->rootPackage);
180
181
        $this->checkPackages();
182
183
        // Must have one outdatedPackage if this should be updated
184
        $this->assertAttributeCount(1, 'outdatedPackages', $this->versionsCheck);
185
        $this->assertSame(<<<'EOF'
186
<warning>1 package is not up to date:</warning>
187
188
  - <info>foo/bar</info> (<comment>1.1</comment>) latest is <comment>2.0</comment>
189
    Required by <info>dummy/link</info> (<comment>1.*</comment>)
190
191
192
EOF
193
            , $this->versionsCheck->getOutput());
194
        // Test with disabled show-links option
195
        $this->assertSame(<<<'EOF'
196
<warning>1 package is not up to date:</warning>
197
198
  - <info>foo/bar</info> (<comment>1.1</comment>) latest is <comment>2.0</comment>
199
200
201
EOF
202
            , $this->versionsCheck->getOutput(false));
203
    }
204
205
    /**
206
     * @dataProvider getRootOnlyPackageTestsData
207
     */
208 View Code Duplication
    public function testRootOnlyPackage(array $packagesData, array $packagesRequired, array $packagesDevRequired, $rootOnly, $outdatedPackagesCount)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
209
    {
210
211
        foreach ($packagesData as $name => $packageData) {
212
            list($actualVersion, $availableVersions, $expectedVersion) = $packageData;
213
            $this->localRepository->addPackage(new Package($name, $actualVersion, $actualVersion));
214
            foreach ($availableVersions as $availableVersion) {
215
                $this->distRepository->addPackage(new Package($name, $availableVersion, $availableVersion));
216
            }
217
218
            if (false !== $expectedVersion) {
219
                $shouldBeUpdatedOutput[] = sprintf(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$shouldBeUpdatedOutput was never initialized. Although not strictly required by PHP, it is generally a good practice to add $shouldBeUpdatedOutput = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
220
                    '  - <info>%s</info> (<comment>%s</comment>) latest is <comment>%s</comment>',
221
                    $name, $actualVersion, $expectedVersion
222
                );
223
            }
224
        }
225
226
        $this->rootPackage->setRequires($packagesRequired);
227
        $this->rootPackage->setDevRequires($packagesDevRequired);
228
229
        $this->checkPackages($rootOnly);
230
231
        $this->assertSame(sprintf(<<<'EOF'
232
<warning>%d packages are not up to date:</warning>
233
234
%s
235
236
237
EOF
238
            , $outdatedPackagesCount, implode("\n\n", $shouldBeUpdatedOutput)), $this->versionsCheck->getOutput());
0 ignored issues
show
Bug introduced by
The variable $shouldBeUpdatedOutput does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
239
    }
240
241
    /**
242
     * @return array
243
     */
244
    public function getRootOnlyPackageTestsData()
245
    {
246
        return array(
247
            array(array(
248
                'foo/bar' => array('1.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
249
                'some/package' => array('1.0.4', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), false),
250
                'vendor/package-1' => array('2.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), false),
251
                'vendor/up-to-date' => array('9.9.0', array('8.0.0', '9.9.0', '1.0-dev'), false),
252
                'vendor/dev-master' => array('9.9.0', array('8.0.0', '9.9.0', '10.0-dev'), false),
253
                'vendor/package-2' => array('1.0.0', array('1.0.0', '1.0.1', '2.0.0', '2.0.0-alpha1'), '2.0.0'),
254
                'vendor/package-3' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), false),
255
                'vendor/prefer-stable' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), false),
256
            ), array(
257
                'foo/bar' => new Link('foo/bar', 'foo/bar')
258
            ), array(
259
                'vendor/package-2' => new Link('vendor/package-2', 'vendor/package-2')
260
            ), true, 2),
261
            array(array(
262
                'foo/bar' => array('1.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
263
                'some/package' => array('1.0.4', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), '2.0.0'),
264
                'vendor/package-1' => array('2.0.0', array('1.0.0', '1.0.1', '1.0.2', '1.0.4', '2.0.0'), false),
265
                'vendor/up-to-date' => array('9.9.0', array('8.0.0', '9.9.0', '1.0-dev'), false),
266
                'vendor/dev-master' => array('9.9.0', array('8.0.0', '9.9.0', '10.0-dev'), '10.0-dev'),
267
                'vendor/package-2' => array('1.0.0', array('1.0.0', '1.0.1', '2.0.0', '2.0.0-alpha1'), '2.0.0'),
268
                'vendor/package-3' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), '2.0.0-alpha1'),
269
                'vendor/prefer-stable' => array('1.0.1', array('1.0.0', '1.0.1', '2.0.0-alpha1'), '2.0.0-alpha1'),
270
            ), array(
271
                'foo/bar' => new Link('foo/bar', 'foo/bar')
272
            ), array(
273
                'vendor/package-2' => new Link('vendor/package-2', 'vendor/package-2')
274
            ), false, 6),
275
        );
276
    }
277
278
    /**
279
     * Calls VersionsCheck::checkPackages.
280
     */
281
    private function checkPackages($rootPackageOnly = false)
282
    {
283
        $this->versionsCheck->checkPackages($this->distRepository, $this->localRepository, $this->rootPackage, $rootPackageOnly);
284
    }
285
}
286