Completed
Push — add/changelog-tooling ( 2b600a...28955c )
by
unknown
10:23
created

SemverVersioningTest::provideFirstVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20

Duplication

Lines 20
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 20
loc 20
rs 9.6
c 0
b 0
f 0
1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
3
 * Tests for the semver versioning plugin.
4
 *
5
 * @package automattic/jetpack-changelogger
6
 */
7
8
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
9
10
namespace Automattic\Jetpack\Changelogger\Tests\Plugins;
11
12
use Automattic\Jetpack\Changelog\ChangeEntry;
13
use Automattic\Jetpack\Changelogger\Plugins\SemverVersioning;
14
use InvalidArgumentException;
15
use PHPUnit\Framework\TestCase;
16
use Symfony\Component\Console\Input\ArrayInput;
17
use Symfony\Component\Console\Output\BufferedOutput;
18
19
/**
20
 * Tests for the semver versioning plugin.
21
 *
22
 * @covers \Automattic\Jetpack\Changelogger\Plugins\SemverVersioning
23
 */
24
class SemverVersioningTest extends TestCase {
25
	use \Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
26
	use \Yoast\PHPUnitPolyfills\Polyfills\ExpectException;
27
28
	/**
29
	 * Test normalizeVersion and parseVersion.
30
	 *
31
	 * @dataProvider provideNormalizeVersion
32
	 * @param string                          $version Version.
33
	 * @param string|InvalidArgumentException $expect Expected result.
34
	 */
35 View Code Duplication
	public function testNormalizeVersion( $version, $expect ) {
36
		$obj = new SemverVersioning( array() );
0 ignored issues
show
Unused Code introduced by
The call to SemverVersioning::__construct() has too many arguments starting with array().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
37
		if ( $expect instanceof InvalidArgumentException ) {
38
			$this->expectException( InvalidArgumentException::class );
39
			$this->expectExceptionMessage( $expect->getMessage() );
40
			$obj->normalizeVersion( $version );
41
		} else {
42
			$this->assertSame( $expect, $obj->normalizeVersion( $version ) );
43
		}
44
	}
45
46
	/**
47
	 * Data provider for testNormalizeVersion.
48
	 */
49
	public function provideNormalizeVersion() {
50
		return array(
51
			array( '1.2.3', '1.2.3' ),
52
			array( '11.22.33', '11.22.33' ),
53
			array( '0.0.0', '0.0.0' ),
54
			array( '1.2.3-alpha', '1.2.3-alpha' ),
55
			array( '1.2.3-alpha.1', '1.2.3-alpha.1' ),
56
			array( '1.2.3+foobar', '1.2.3+foobar' ),
57
			array( '1.2.3+foobar.2', '1.2.3+foobar.2' ),
58
			array( '1.2.3-alpha+foobar', '1.2.3-alpha+foobar' ),
59
			array( '1.2.3-alpha.1+foobar.2', '1.2.3-alpha.1+foobar.2' ),
60
			array( '0001.0002.000-000alpha000.0001+000foobar000.0002', '1.2.0-000alpha000.1+000foobar000.0002' ),
61
62
			array( '1.2', new InvalidArgumentException( 'Version number "1.2" is not in a recognized format.' ) ),
63
			array( '1.2.x', new InvalidArgumentException( 'Version number "1.2.x" is not in a recognized format.' ) ),
64
			array( '1.x.4', new InvalidArgumentException( 'Version number "1.x.4" is not in a recognized format.' ) ),
65
			array( '1..4', new InvalidArgumentException( 'Version number "1..4" is not in a recognized format.' ) ),
66
			array( '.2.3', new InvalidArgumentException( 'Version number ".2.3" is not in a recognized format.' ) ),
67
			array( '1.2.', new InvalidArgumentException( 'Version number "1.2." is not in a recognized format.' ) ),
68
			array( '1.2.-1', new InvalidArgumentException( 'Version number "1.2.-1" is not in a recognized format.' ) ),
69
			array( 'v1.2.3', new InvalidArgumentException( 'Version number "v1.2.3" is not in a recognized format.' ) ),
70
			array( '1.2.3.4', new InvalidArgumentException( 'Version number "1.2.3.4" is not in a recognized format.' ) ),
71
			array( '1.2-alpha', new InvalidArgumentException( 'Version number "1.2-alpha" is not in a recognized format.' ) ),
72
			array( '1.2.3-?', new InvalidArgumentException( 'Version number "1.2.3-?" is not in a recognized format.' ) ),
73
			array( '1.2.3+?', new InvalidArgumentException( 'Version number "1.2.3+?" is not in a recognized format.' ) ),
74
			array( '1.2.3-a..b', new InvalidArgumentException( 'Version number "1.2.3-a..b" is not in a recognized format.' ) ),
75
			array( '1.2.3+a..b', new InvalidArgumentException( 'Version number "1.2.3+a..b" is not in a recognized format.' ) ),
76
		);
77
	}
78
79
	/**
80
	 * Test nextVersion.
81
	 *
82
	 * @dataProvider provideNextVersion
83
	 * @param string                          $version Version.
84
	 * @param ChangeEntry[]                   $changes Changes.
85
	 * @param array                           $extra Extra components.
86
	 * @param string|InvalidArgumentException $expect Expected result.
87
	 * @param string                          $expectOutput Expected output.
88
	 */
89
	public function testNextVersion( $version, array $changes, array $extra, $expect, $expectOutput = '' ) {
90
		$obj = new SemverVersioning( array() );
0 ignored issues
show
Unused Code introduced by
The call to SemverVersioning::__construct() has too many arguments starting with array().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
91
92
		$out1 = $this->getMockBuilder( BufferedOutput::class )
93
			->setMethods( array( 'getErrorOutput' ) )
94
			->getMock();
95
		$out2 = new BufferedOutput();
96
		$out1->method( 'getErrorOutput' )->willReturn( $out2 );
97
98
		$obj->setIO( new ArrayInput( array() ), $out1 );
99
100
		if ( $expect instanceof InvalidArgumentException ) {
101
			$this->expectException( InvalidArgumentException::class );
102
			$this->expectExceptionMessage( $expect->getMessage() );
103
			$obj->nextVersion( $version, $changes, $extra );
0 ignored issues
show
Documentation introduced by
$changes is of type array<integer,object<Aut...Changelog\ChangeEntry>>, but the function expects a array<integer,object<Aut...r\Plugins\ChangeEntry>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
104
		} else {
105
			$this->assertSame( $expect, $obj->nextVersion( $version, $changes, $extra ) );
0 ignored issues
show
Documentation introduced by
$changes is of type array<integer,object<Aut...Changelog\ChangeEntry>>, but the function expects a array<integer,object<Aut...r\Plugins\ChangeEntry>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
106
			$this->assertSame( '', $out1->fetch() );
107
			$this->assertSame( $expectOutput, $out2->fetch() );
108
		}
109
	}
110
111
	/**
112
	 * Data provider for testNextVersion.
113
	 */
114
	public function provideNextVersion() {
115
		return array(
116
			'No changes'                               => array(
117
				'1.2.3',
118
				array(),
119
				array(),
120
				'1.2.4',
121
			),
122
			'Patch changes'                            => array(
123
				'1.2.3',
124
				array(
125
					new ChangeEntry( array( 'significance' => 'patch' ) ),
126
					new ChangeEntry( array( 'significance' => 'patch' ) ),
127
					new ChangeEntry( array( 'significance' => null ) ),
128
					new ChangeEntry( array( 'significance' => 'patch' ) ),
129
				),
130
				array(),
131
				'1.2.4',
132
			),
133
			'Minor change'                             => array(
134
				'1.2.3',
135
				array(
136
					new ChangeEntry( array( 'significance' => 'patch' ) ),
137
					new ChangeEntry( array( 'significance' => 'minor' ) ),
138
					new ChangeEntry( array( 'significance' => null ) ),
139
					new ChangeEntry( array( 'significance' => 'patch' ) ),
140
				),
141
				array(),
142
				'1.3.0',
143
			),
144
			'Major change'                             => array(
145
				'1.2.3',
146
				array(
147
					new ChangeEntry( array( 'significance' => 'patch' ) ),
148
					new ChangeEntry( array( 'significance' => 'minor' ) ),
149
					new ChangeEntry( array( 'significance' => null ) ),
150
					new ChangeEntry( array( 'significance' => 'major' ) ),
151
					new ChangeEntry( array( 'significance' => 'patch' ) ),
152
				),
153
				array(),
154
				'2.0.0',
155
			),
156
			'Version number with extra components'     => array(
157
				'1.2.3-foo',
158
				array(),
159
				array(),
160
				'1.2.4',
161
			),
162
			'Version number with extra components (2)' => array(
163
				'1.2.9+123',
164
				array(),
165
				array(),
166
				'1.2.10',
167
			),
168
			'Version number with extra components (3)' => array(
169
				'1.2.3-foo+bar',
170
				array(),
171
				array(),
172
				'1.2.4',
173
			),
174
175
			'Non-major update for version 0'           => array(
176
				'0.1.2',
177
				array(
178
					new ChangeEntry( array( 'significance' => 'patch' ) ),
179
					new ChangeEntry( array( 'significance' => 'minor' ) ),
180
					new ChangeEntry( array( 'significance' => null ) ),
181
					new ChangeEntry( array( 'significance' => 'patch' ) ),
182
				),
183
				array(),
184
				'0.2.0',
185
			),
186
			'Major update for version 0'               => array(
187
				'0.1.2',
188
				array(
189
					new ChangeEntry( array( 'significance' => 'patch' ) ),
190
					new ChangeEntry( array( 'significance' => 'major' ) ),
191
					new ChangeEntry( array( 'significance' => null ) ),
192
					new ChangeEntry( array( 'significance' => 'patch' ) ),
193
				),
194
				array(),
195
				'0.2.0',
196
				"<warning>Semver does not automatically move version 0.y.z to 1.0.0.\n<warning>You will have to do that manually when you're ready for the first release.\n",
197
			),
198
199
			'Including extra components'               => array(
200
				'1.2.3',
201
				array(),
202
				array(
203
					'prerelease' => 'alpha.002',
204
					'buildinfo'  => 'g12345678.003',
205
				),
206
				'1.2.4-alpha.2+g12345678.003',
207
			),
208
			'Including extra components (2)'           => array(
209
				'1.2.3-foo',
210
				array(),
211
				array( 'buildinfo' => 'g12345678' ),
212
				'1.2.4+g12345678',
213
			),
214
215
			'Invalid prerelease component'             => array(
216
				'1.2.3-foo',
217
				array(),
218
				array( 'prerelease' => 'delta?' ),
219
				new InvalidArgumentException( 'Invalid prerelease data' ),
220
			),
221
			'Invalid buildinfo component'              => array(
222
				'1.2.3-foo',
223
				array(),
224
				array( 'buildinfo' => 'build?' ),
225
				new InvalidArgumentException( 'Invalid buildinfo data' ),
226
			),
227
		);
228
	}
229
230
	/**
231
	 * Test nextVersion, 0.x version major update with non-console output.
232
	 */
233
	public function testNextVersion_majorNonConsole() {
234
		$obj = new SemverVersioning( array() );
0 ignored issues
show
Unused Code introduced by
The call to SemverVersioning::__construct() has too many arguments starting with array().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
235
		$out = new BufferedOutput();
236
		$obj->setIO( new ArrayInput( array() ), $out );
237
		$this->assertSame(
238
			'0.2.0',
239
			$obj->nextVersion( '0.1.2', array( new ChangeEntry( array( 'significance' => 'major' ) ) ) )
0 ignored issues
show
Documentation introduced by
array(new \Automattic\Je...ificance' => 'major'))) is of type array<integer,object<Aut...ngelog\\ChangeEntry>"}>, but the function expects a array<integer,object<Aut...r\Plugins\ChangeEntry>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
240
		);
241
		$this->assertSame( '', $out->fetch() );
242
	}
243
244
	/**
245
	 * Test compareVersions.
246
	 *
247
	 * @dataProvider provideCompareVersions
248
	 * @param string $a Version A.
249
	 * @param string $expect Expected result converted to a string, '>', '==', or '<'.
250
	 * @param string $b Version B.
251
	 */
252 View Code Duplication
	public function testCompareVersions( $a, $expect, $b ) {
253
		$obj = new SemverVersioning( array() );
0 ignored issues
show
Unused Code introduced by
The call to SemverVersioning::__construct() has too many arguments starting with array().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
254
		$ret = $obj->compareVersions( $a, $b );
255
		$this->assertIsInt( $ret );
256
		$ret = $ret < 0 ? '<' : ( $ret > 0 ? '>' : '==' );
257
		$this->assertSame( $expect, $ret );
258
	}
259
260
	/**
261
	 * Data provider for testCompareVersions.
262
	 */
263
	public function provideCompareVersions() {
264
		return array(
265
			array( '1.0.0', '==', '1.0.0' ),
266
			array( '1.0.0', '<', '2.0.0' ),
267
			array( '2.0.0', '>', '1.0.0' ),
268
			array( '1.1.0', '>', '1.0.0' ),
269
			array( '1.0.0', '<', '1.1.0' ),
270
			array( '1.999.999', '<', '2.0.0' ),
271
			array( '1.1.0', '<', '1.1.1' ),
272
			array( '1.0.999', '<', '1.1.0' ),
273
			array( '1.1.2', '>', '1.1.1' ),
274
			array( '1.1.1-dev', '<', '1.1.1' ),
275
			array( '1.1.1', '>', '1.1.1-p1' ),
276
			array( '1.1.1-alpha', '<', '1.1.1-beta' ),
277
			array( '1.1.1-dev', '>', '1.1.1-beta' ), // No special treatment for "dev".
278
			array( '1.1.1-alpha.9', '<', '1.1.1-beta.1' ),
279
			array( '1.1.1-beta.9', '>', '1.1.1-beta.1' ),
280
			array( '1.1.1-beta.9', '==', '1.1.1-beta.9' ),
281
			array( '1.1.1-beta.9.1', '>', '1.1.1-beta.9' ),
282
			array( '1.1.1-beta.9', '<', '1.1.1-beta.a' ),
283
			array( '1.1.1-beta.1a', '>', '1.1.1-beta.9' ),
284
			array( '1.1.1-BETA', '<', '1.1.1-beta' ), // Case sensitive.
285
			array( '1.1.1-ZETA', '<', '1.1.1-beta' ), // Case sensitive.
286
			array( '1.1.1-alpha2', '>', '1.1.1-alpha10' ), // No natural sorting.
287
			array( '1.1.1+beta.9.1', '==', '1.1.1+beta.9' ),
288
		);
289
	}
290
291
	/**
292
	 * Test firstVersion.
293
	 *
294
	 * @dataProvider provideFirstVersion
295
	 * @param array                           $extra Extra components.
296
	 * @param string|InvalidArgumentException $expect Expected result.
297
	 */
298 View Code Duplication
	public function testFirstVersion( array $extra, $expect ) {
299
		$obj = new SemverVersioning( array() );
0 ignored issues
show
Unused Code introduced by
The call to SemverVersioning::__construct() has too many arguments starting with array().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
300
301
		if ( $expect instanceof InvalidArgumentException ) {
302
			$this->expectException( InvalidArgumentException::class );
303
			$this->expectExceptionMessage( $expect->getMessage() );
304
			$obj->firstVersion( $extra );
305
		} else {
306
			$this->assertSame( $expect, $obj->firstVersion( $extra ) );
307
		}
308
	}
309
310
	/**
311
	 * Data provider for testFirstVersion.
312
	 */
313 View Code Duplication
	public function provideFirstVersion() {
314
		return array(
315
			'Normal'             => array(
316
				array(),
317
				'0.1.0',
318
			),
319
			'Some extra'         => array(
320
				array( 'prerelease' => 'alpha' ),
321
				'0.1.0-alpha',
322
			),
323
			'Invalid prerelease' => array(
324
				array( 'prerelease' => 'delta?' ),
325
				new InvalidArgumentException( 'Invalid prerelease data' ),
326
			),
327
			'Invalid buildinfo'  => array(
328
				array( 'buildinfo' => 'build?' ),
329
				new InvalidArgumentException( 'Invalid buildinfo data' ),
330
			),
331
		);
332
	}
333
334
}
335