Completed
Push — add/testing-info ( be1095...03b7e9 )
by
unknown
09:20
created

WriteCommandTest::testExecute()   F

Complexity

Conditions 13
Paths 3072

Size

Total Lines 57

Duplication

Lines 4
Ratio 7.02 %

Importance

Changes 0
Metric Value
cc 13
nc 3072
nop 7
dl 4
loc 57
rs 2.45
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
3
 * Tests for the changelogger write command.
4
 *
5
 * @package automattic/jetpack-changelogger
6
 */
7
8
// phpcs:disable WordPress.WP.AlternativeFunctions, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
9
10
namespace Automattic\Jetpack\Changelogger\Tests;
11
12
use Automattic\Jetpack\Changelog\Changelog;
13
use Automattic\Jetpack\Changelogger\FormatterPlugin;
14
use Automattic\Jetpack\Changelogger\WriteCommand;
15
use InvalidArgumentException;
16
use Symfony\Component\Console\Input\ArrayInput;
17
use Symfony\Component\Console\Output\BufferedOutput;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Tester\CommandTester;
20
use Wikimedia\TestingAccessWrapper;
21
22
/**
23
 * Tests for the changelogger write command.
24
 *
25
 * @covers \Automattic\Jetpack\Changelogger\WriteCommand
26
 */
27
class WriteCommandTest extends CommandTestCase {
28
	use \Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
29
	use \Yoast\PHPUnitPolyfills\Polyfills\AssertStringContains;
30
31
	/**
32
	 * Set up.
33
	 *
34
	 * @before
35
	 */
36
	public function set_up() {
37
		parent::set_up();
38
		$this->useTempDir();
39
		mkdir( 'changelog' );
40
		file_put_contents( 'changelog/.gitkeep', '' );
41
	}
42
43
	/**
44
	 * Test the command.
45
	 *
46
	 * @dataProvider provideExecute
47
	 * @param string[]    $args Command line arguments.
48
	 * @param array       $options Options for the test and CommandTester.
49
	 * @param string[]    $inputs User inputs.
50
	 * @param int         $expectExitCode Expected exit code.
51
	 * @param string[]    $expectOutputRegexes Regexes to run against the output.
52
	 * @param bool|array  $expectChangesDeleted Whether change files should have been deleted, or an array of files that should have been deleted.
53
	 * @param string|null $expectChangelog Expected changelog file contents, or null if it should be the same as $options['changelog'].
54
	 */
55
	public function testExecute( array $args, array $options, array $inputs, $expectExitCode, $expectOutputRegexes = array(), $expectChangesDeleted = false, $expectChangelog = null ) {
56
		$options += array(
57
			'changelog' => "# Changelog\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
58
			'changes'   => array(
59
				'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
60
			),
61
		);
62
63 View Code Duplication
		if ( isset( $options['composer.json'] ) ) {
64
			file_put_contents( 'composer.json', json_encode( array( 'extra' => array( 'changelogger' => $options['composer.json'] ) ), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) );
65
			unset( $options['composer.json'] );
66
		}
67
		$changelog = isset( $options['changelog'] ) ? $options['changelog'] : null;
68
		$changes   = isset( $options['changes'] ) ? $options['changes'] : array();
69
		unset( $options['changelog'], $options['changes'] );
70
		if ( null !== $changelog ) {
71
			file_put_contents( 'CHANGELOG.md', $changelog );
72
		}
73
		foreach ( $changes as $name => $change ) {
74
			file_put_contents( "changelog/$name", $change );
75
		}
76
77
		$tester = $this->getTester( 'write' );
78
		$tester->setInputs( $inputs );
79
		$code = $tester->execute( $args, $options );
80
		foreach ( $expectOutputRegexes as $re ) {
81
			$this->assertMatchesRegularExpression( $re, $tester->getDisplay() );
82
		}
83
		$this->assertSame( $expectExitCode, $code );
84
85
		$expectExisting = array( '.gitkeep' );
86
		$expectDeleted  = array();
87
		if ( false === $expectChangesDeleted ) {
88
			$expectExisting = array_merge( $expectExisting, array_keys( $changes ) );
89
		} elseif ( true === $expectChangesDeleted ) {
90
			$expectDeleted = array_merge( $expectDeleted, array_keys( $changes ) );
91
		} else {
92
			$expectExisting = array_merge( $expectExisting, array_diff( array_keys( $changes ), $expectChangesDeleted ) );
93
			$expectDeleted  = array_merge( $expectDeleted, array_intersect( array_keys( $changes ), $expectChangesDeleted ) );
94
		}
95
		foreach ( $expectDeleted as $name ) {
96
			$this->assertFileDoesNotExist( "changelog/$name" );
97
		}
98
		foreach ( $expectExisting as $name ) {
99
			$this->assertFileExists( "changelog/$name" );
100
		}
101
102
		if ( null === $expectChangelog ) {
103
			$expectChangelog = $changelog;
104
		}
105
		if ( null === $expectChangelog ) {
106
			$this->assertFileDoesNotExist( 'CHANGELOG.md' );
107
		} else {
108
			$this->assertFileExists( 'CHANGELOG.md' );
109
			$this->assertSame( $expectChangelog, file_get_contents( 'CHANGELOG.md' ) );
110
		}
111
	}
112
113
	/**
114
	 * Data provider for testExecute.
115
	 */
116
	public function provideExecute() {
117
		$date = gmdate( 'Y-m-d' );
118
119
		return array(
120
			'Normal run'                                   => array(
121
				array(),
122
				array(),
123
				array(),
124
				0,
125
				array( '/^$/' ),
126
				true,
127
				"# Changelog\n\n## 1.0.2 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
128
			),
129
			'Debug run'                                    => array(
130
				array(),
131
				array( 'verbosity' => OutputInterface::VERBOSITY_DEBUG ),
132
				array(),
133
				0,
134
				array(
135
					'{^Reading changelog from /.*/CHANGELOG.md\\.\\.\\.$}m',
136
					'{^Reading changes from /.*/changelog\\.\\.\\.$}m',
137
					'{^Deduplicating changes from the last 1 version\\(s\\)\\.\\.\\.$}m',
138
					'{^Checking if any changes have content\\.\\.\\.$}m',
139
					'{^Yes, a-change has content\\.$}m',
140
					'{^Latest version from changelog is 1\\.0\\.1\\.$}m',
141
					'{^Next version is 1\\.0\\.2\\.$}m',
142
					'{^Creating new changelog entry\\.$}m',
143
					'{^Writing changelog to /.*/CHANGELOG.md\\.\\.\\.$}m',
144
					'{^Deleted change file a-change\\.$}m',
145
				),
146
				true,
147
				"# Changelog\n\n## 1.0.2 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
148
			),
149
			'Run with extra command line args'             => array(
150
				array(
151
					'--prerelease'   => 'dev',
152
					'--buildinfo'    => 'g1234567',
153
					'--prologue'     => 'Prologue for the new entry',
154
					'--epilogue'     => 'Epilogue for the new entry',
155
					'--link'         => 'https://example.org/link',
156
					'--release-date' => '2021-02-06',
157
				),
158
				array(),
159
				array(),
160
				0,
161
				array( '/^$/' ),
162
				true,
163
				"# Changelog\n\n## [1.0.2-dev+g1234567] - 2021-02-06\n\nPrologue for the new entry\n\n### Fixed\n- Fixed a thing.\n\nEpilogue for the new entry\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n\n[1.0.2-dev+g1234567]: https://example.org/link\n",
164
			),
165
			'Run with extra command line args (2)'         => array(
166
				array(
167
					'--prerelease'   => 'alpha',
168
					'--release-date' => 'unreleased',
169
				),
170
				array(),
171
				array(),
172
				0,
173
				array( '/^$/' ),
174
				true,
175
				"# Changelog\n\n## 1.0.2-alpha - unreleased\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
176
			),
177
178
			'Invalid formatter'                            => array(
179
				array(),
180
				array( 'composer.json' => array( 'formatter' => 'bogus' ) ),
181
				array(),
182
				WriteCommand::FATAL_EXIT,
183
				array( '/^Unknown formatter plugin "bogus"$/' ),
184
			),
185
			'Invalid versioning'                           => array(
186
				array(),
187
				array( 'composer.json' => array( 'versioning' => 'bogus' ) ),
188
				array(),
189
				WriteCommand::FATAL_EXIT,
190
				array( '/^Unknown versioning plugin "bogus"$/' ),
191
			),
192
193
			'No changelog file, interactive'               => array(
194
				array(),
195
				array( 'changelog' => null ),
196
				array( 'N' ),
197
				WriteCommand::ASKED_EXIT,
198
				array( '{^Changelog file /.*/CHANGELOG\.md does not exist! Proceed\? \[y/N\]}m' ),
199
			),
200
			'No changelog file, interactive (2)'           => array(
201
				array(),
202
				array( 'changelog' => null ),
203
				array( 'Y' ),
204
				WriteCommand::FATAL_EXIT,
205
				array( '/Changelog file contains no entries! Use --use-version to specify the initial version\.$/m' ),
206
			),
207
			'No changelog file, interactive (3)'           => array(
208
				array(
209
					'--default-first-version' => true,
210
					'--prerelease'            => 'beta',
211
				),
212
				array( 'changelog' => null ),
213
				array( 'Y' ),
214
				0,
215
				array(),
216
				true,
217
				"## 0.1.0-beta - $date\n### Fixed\n- Fixed a thing.\n",
218
			),
219
			'No changelog file, non-interactive'           => array(
220
				array(),
221
				array(
222
					'interactive' => false,
223
					'changelog'   => null,
224
				),
225
				array(),
226
				WriteCommand::ASKED_EXIT,
227
				array( '{^Changelog file /.*/CHANGELOG\.md does not exist!$}m' ),
228
			),
229
			'No changelog file, non-interactive, --yes'    => array(
230
				array( '--yes' => true ),
231
				array(
232
					'interactive' => false,
233
					'changelog'   => null,
234
				),
235
				array(),
236
				WriteCommand::FATAL_EXIT,
237
				array(
238
					'{^<warning>Changelog file /.*/CHANGELOG\.md does not exist! Continuing anyway\.$}m',
239
					'/Changelog file contains no entries! Use --use-version to specify the initial version\.$/m',
240
				),
241
			),
242
			'No changelog file, non-interactive, --yes (2)' => array(
243
				array(
244
					'--yes'         => true,
245
					'--use-version' => '1.0.0',
246
				),
247
				array(
248
					'interactive' => false,
249
					'changelog'   => null,
250
				),
251
				array(),
252
				0,
253
				array(
254
					'{^<warning>Changelog file /.*/CHANGELOG\.md does not exist! Continuing anyway\.$}m',
255
				),
256
				true,
257
				"## 1.0.0 - $date\n### Fixed\n- Fixed a thing.\n",
258
			),
259
260
			'Unparseable changelog'                        => array(
261
				array(),
262
				array( 'changelog' => "## bogus\n" ),
263
				array(),
264
				WriteCommand::FATAL_EXIT,
265
				array( '{^Failed to parse changelog: Invalid heading: ## bogus$}' ),
266
			),
267
268
			'No changes directory'                         => array(
269
				array(),
270
				array( 'composer.json' => array( 'changes-dir' => 'changes' ) ),
271
				array( 'N' ),
272
				WriteCommand::NO_CHANGE_EXIT,
273
				array( '{^Changes directory does not exist, so there are no changes to write! Proceed\? \[y/N\]}m' ),
274
			),
275
			'No changes directory (2)'                     => array(
276
				array(),
277
				array( 'composer.json' => array( 'changes-dir' => 'changes' ) ),
278
				array( 'Y' ),
279
				0,
280
				array( '{^Changes directory does not exist, so there are no changes to write! Proceed\? \[y/N\]}m' ),
281
				false,
282
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
283
			),
284
			'No changes directory, non-interactive'        => array(
285
				array(),
286
				array(
287
					'composer.json' => array( 'changes-dir' => 'changes' ),
288
					'interactive'   => false,
289
				),
290
				array(),
291
				WriteCommand::NO_CHANGE_EXIT,
292
				array( '{^Changes directory does not exist, so there are no changes to write!$}m' ),
293
			),
294
			'No changes directory, non-interactive, --yes' => array(
295
				array( '--yes' => true ),
296
				array(
297
					'composer.json' => array( 'changes-dir' => 'changes' ),
298
					'interactive'   => false,
299
				),
300
				array(),
301
				0,
302
				array( '{^<warning>Changes directory does not exist, so there are no changes to write! Continuing anyway\.$}m' ),
303
				false,
304
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
305
			),
306
307
			'Change files with warnings'                   => array(
308
				array(),
309
				array(
310
					'changes' => array(
311
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
312
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
313
					),
314
				),
315
				array( 'N' ),
316
				WriteCommand::ASKED_EXIT,
317
				array( '{^Warnings were encountered while reading changes! Proceed\? \[y/N\]}m' ),
318
			),
319
			'Change files with warnings (2)'               => array(
320
				array(),
321
				array(
322
					'changes' => array(
323
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
324
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
325
					),
326
				),
327
				array( 'Y' ),
328
				0,
329
				array( '{^Warnings were encountered while reading changes! Proceed\? \[y/N\]}m' ),
330
				true,
331
				"# Changelog\n\n## 1.0.2 - $date\n### Fixed\n- Did a thing.\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
332
			),
333
			'Change files with warnings, non-interactive'  => array(
334
				array(),
335
				array(
336
					'interactive' => false,
337
					'changes'     => array(
338
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
339
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
340
					),
341
				),
342
				array(),
343
				WriteCommand::ASKED_EXIT,
344
				array( '{^Warnings were encountered while reading changes!$}m' ),
345
			),
346
			'Change files with warnings, non-interactive, --yes' => array(
347
				array( '--yes' => true ),
348
				array(
349
					'interactive' => false,
350
					'changes'     => array(
351
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
352
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
353
					),
354
				),
355
				array(),
356
				0,
357
				array( '{^<warning>Warnings were encountered while reading changes! Continuing anyway\.$}m' ),
358
				true,
359
				"# Changelog\n\n## 1.0.2 - $date\n### Fixed\n- Did a thing.\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
360
			),
361
362
			'Change files with errors'                     => array(
363
				array(),
364
				array(
365
					'changes' => array(
366
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
367
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
368
						'error'    => "Bogus\n",
369
					),
370
				),
371
				array( 'N' ),
372
				WriteCommand::ASKED_EXIT,
373
				array( '{^Errors were encountered while reading changes! Proceed\? \[y/N\]}m' ),
374
			),
375
			'Change files with errors (2)'                 => array(
376
				array(),
377
				array(
378
					'changes' => array(
379
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
380
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
381
						'error'    => "Bogus\n",
382
					),
383
				),
384
				array( 'Y' ),
385
				0,
386
				array( '{^Errors were encountered while reading changes! Proceed\? \[y/N\]}m' ),
387
				array( 'a-change', 'b-change' ),
388
				"# Changelog\n\n## 1.0.2 - $date\n### Fixed\n- Did a thing.\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
389
			),
390
			'Change files with errors, non-interactive'    => array(
391
				array(),
392
				array(
393
					'interactive' => false,
394
					'changes'     => array(
395
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
396
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
397
						'error'    => "Bogus\n",
398
					),
399
				),
400
				array(),
401
				WriteCommand::ASKED_EXIT,
402
				array( '{^Errors were encountered while reading changes!$}m' ),
403
			),
404
			'Change files with errors, non-interactive, --yes' => array(
405
				array( '--yes' => true ),
406
				array(
407
					'interactive' => false,
408
					'changes'     => array(
409
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
410
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
411
						'error'    => "Bogus\n",
412
					),
413
				),
414
				array(),
415
				0,
416
				array( '{^<warning>Errors were encountered while reading changes! Continuing anyway\.$}m' ),
417
				array( 'a-change', 'b-change' ),
418
				"# Changelog\n\n## 1.0.2 - $date\n### Fixed\n- Did a thing.\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
419
			),
420
421
			'No changes'                                   => array(
422
				array(),
423
				array( 'changes' => array() ),
424
				array( 'N' ),
425
				WriteCommand::NO_CHANGE_EXIT,
426
				array( '{^No changes were found! Proceed\? \[y/N\]}m' ),
427
			),
428
			'No changes (2)'                               => array(
429
				array(),
430
				array( 'changes' => array() ),
431
				array( 'Y' ),
432
				0,
433
				array( '{^No changes were found! Proceed\? \[y/N\]}m' ),
434
				true,
435
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
436
			),
437
			'No changes, non-interactive'                  => array(
438
				array(),
439
				array(
440
					'interactive' => false,
441
					'changes'     => array(),
442
				),
443
				array(),
444
				WriteCommand::NO_CHANGE_EXIT,
445
				array( '{^No changes were found!$}m' ),
446
			),
447
			'No changes, non-interactive, --yes'           => array(
448
				array( '--yes' => true ),
449
				array(
450
					'interactive' => false,
451
					'changes'     => array(),
452
				),
453
				array(),
454
				0,
455
				array( '{^<warning>No changes were found! Continuing anyway\.$}m' ),
456
				true,
457
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
458
			),
459
460
			'Deduplication'                                => array(
461
				array(),
462
				array(
463
					'changes' => array(
464
						'initial-release' => "Significance: patch\nType: added\n\nInitial release.\n",
465
						'added-stuff'     => "Significance: patch\nType: added\n\nStuff.\n",
466
						'added-stuff-2'   => "Significance: patch\nType: added\n\nStuff. And more stuff.\n",
467
					),
468
				),
469
				array(),
470
				0,
471
				array( '{^$}m' ),
472
				true,
473
				"# Changelog\n\n## 1.0.2 - $date\n### Added\n- Initial release.\n- Stuff. And more stuff.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
474
			),
475
			'Deduplication, --dedupliacte=0'               => array(
476
				array( '--deduplicate' => '0' ),
477
				array(
478
					'changes' => array(
479
						'initial-release' => "Significance: patch\nType: added\n\nInitial release.\n",
480
						'added-stuff'     => "Significance: patch\nType: added\n\nStuff.\n",
481
						'added-stuff-2'   => "Significance: patch\nType: added\n\nStuff. And more stuff.\n",
482
					),
483
				),
484
				array(),
485
				0,
486
				array( '{^$}m' ),
487
				true,
488
				"# Changelog\n\n## 1.0.2 - $date\n### Added\n- Initial release.\n- Stuff.\n- Stuff. And more stuff.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
489
			),
490
			'Deduplication, --dedupliacte=2'               => array(
491
				array( '--deduplicate' => '2' ),
492
				array(
493
					'changes' => array(
494
						'initial-release' => "Significance: patch\nType: added\n\nInitial release.\n",
495
						'added-stuff'     => "Significance: patch\nType: added\n\nStuff.\n",
496
						'added-stuff-2'   => "Significance: patch\nType: added\n\nStuff. And more stuff.\n",
497
					),
498
				),
499
				array(),
500
				0,
501
				array( '{^$}m' ),
502
				true,
503
				"# Changelog\n\n## 1.0.2 - $date\n### Added\n- Stuff. And more stuff.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
504
			),
505
506
			'Deduplication removes all changes'            => array(
507
				array(),
508
				array(
509
					'changes' => array(
510
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
511
					),
512
				),
513
				array( 'N' ),
514
				WriteCommand::NO_CHANGE_EXIT,
515
				array( '{^All changes were duplicates\. Proceed\? \[y/N\]}m' ),
516
			),
517
			'Deduplication removes all changes (2)'        => array(
518
				array(),
519
				array(
520
					'changes' => array(
521
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
522
					),
523
				),
524
				array( 'Y' ),
525
				0,
526
				array( '{^All changes were duplicates\. Proceed\? \[y/N\]}m' ),
527
				true,
528
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
529
			),
530
			'Deduplication removes all changes, non-interactive' => array(
531
				array(),
532
				array(
533
					'interactive' => false,
534
					'changes'     => array(
535
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
536
					),
537
				),
538
				array(),
539
				WriteCommand::NO_CHANGE_EXIT,
540
				array( '{^All changes were duplicates\.$}m' ),
541
			),
542
			'Deduplication removes all changes, non-interactive, --yes' => array(
543
				array( '--yes' => true ),
544
				array(
545
					'interactive' => false,
546
					'changes'     => array(
547
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
548
					),
549
				),
550
				array(),
551
				0,
552
				array( '{^<warning>All changes were duplicates\. Continuing anyway\.$}m' ),
553
				true,
554
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
555
			),
556
557
			'All changes are empty'                        => array(
558
				array(),
559
				array(
560
					'changes' => array(
561
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
562
						'error'     => "Bogus\n",
563
						'empty'     => "Significance: patch\nType: fixed\n\n",
564
					),
565
				),
566
				array( 'Y', 'N' ),
567
				WriteCommand::NO_CHANGE_EXIT,
568
				array( '{There are no changes with content for this write\. Proceed\? \[y/N\]}m' ),
569
			),
570
			'All changes are empty (2)'                    => array(
571
				array(),
572
				array(
573
					'changes' => array(
574
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
575
						'error'     => "Bogus\n",
576
						'empty'     => "Significance: patch\nType: fixed\n\n",
577
					),
578
				),
579
				array( 'Y', 'Y' ),
580
				0,
581
				array( '{There are no changes with content for this write\. Proceed\? \[y/N\]}m' ),
582
				array( 'duplicate', 'empty' ),
583
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
584
			),
585
			'All changes are empty, non-interactive'       => array(
586
				array(),
587
				array(
588
					'interactive' => false,
589
					'changes'     => array(
590
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
591
						'empty'     => "Significance: patch\nType: fixed\n\n",
592
					),
593
				),
594
				array(),
595
				WriteCommand::NO_CHANGE_EXIT,
596
				array( '{^There are no changes with content for this write\.$}m' ),
597
			),
598
			'All changes are empty, non-interactive, --yes' => array(
599
				array( '--yes' => true ),
600
				array(
601
					'interactive' => false,
602
					'changes'     => array(
603
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
604
						'error'     => "Bogus\n",
605
						'empty'     => "Significance: patch\nType: fixed\n\n",
606
					),
607
				),
608
				array(),
609
				0,
610
				array( '{^<warning>There are no changes with content for this write\. Continuing anyway\.$}m' ),
611
				array( 'duplicate', 'empty' ),
612
				"# Changelog\n\n## 1.0.2 - $date\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
613
			),
614
615
			'Amend'                                        => array(
616
				array( '--amend' => true ),
617
				array(
618
					'changes' => array(
619
						'added'  => "Significance: patch\nType: added\n\nNew stuff.\n",
620
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
621
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
622
					),
623
				),
624
				array(),
625
				0,
626
				array( '{^$}' ),
627
				true,
628
				"# Changelog\n\n## 1.0.1 - $date\n\nPrologue for v1.0.1\n\n### Added\n- New stuff.\n- Stuff.\n- ZZZ.\n\n### Removed\n- Other stuff.\n\n### Fixed\n- Broken stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
629
			),
630
			'Amend, upgrade version'                       => array(
631
				array( '--amend' => true ),
632
				array(
633
					'changes' => array(
634
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
635
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
636
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
637
					),
638
				),
639
				array(),
640
				0,
641
				array( '{^$}' ),
642
				true,
643
				"# Changelog\n\n## 1.1.0 - $date\n\nPrologue for v1.0.1\n\n### Added\n- New stuff.\n- Stuff.\n- ZZZ.\n\n### Removed\n- Other stuff.\n\n### Fixed\n- Broken stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
644
			),
645
			'Amend, no downgrade version'                  => array(
646
				array( '--amend' => true ),
647
				array(
648
					'changes'   => array(
649
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
650
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
651
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
652
					),
653
					'changelog' => "# Changelog\n\n## 2.0.0 - 2021-02-23\n### Changed\n- Stuff.\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
654
				),
655
				array(),
656
				0,
657
				array( '{^$}' ),
658
				true,
659
				"# Changelog\n\n## 2.0.0 - $date\n### Added\n- New stuff.\n- ZZZ.\n\n### Changed\n- Stuff.\n\n### Fixed\n- Broken stuff.\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
660
			),
661
			'Amend initial release'                        => array(
662
				array( '--amend' => true ),
663
				array(
664
					'changes'   => array(
665
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
666
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
667
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
668
					),
669
					'changelog' => "# Changelog\n\n## [1.0.0] - 2021-02-23\n\n- Initial release.\n\n### Added\n- Everything.\n\n[1.0.0]: https://example.org/new-thing\n",
670
				),
671
				array(),
672
				0,
673
				array( '{^$}' ),
674
				true,
675
				"# Changelog\n\n## [1.0.0] - $date\n\n- Initial release.\n\n### Added\n- Everything.\n- New stuff.\n- ZZZ.\n\n### Fixed\n- Broken stuff.\n\n[1.0.0]: https://example.org/new-thing\n",
676
			),
677
			'Amend empty changelog'                        => array(
678
				array(
679
					'--amend'       => true,
680
					'--use-version' => '0.1.0',
681
				),
682
				array(
683
					'changes'   => array(
684
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
685
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
686
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
687
					),
688
					'changelog' => '',
689
				),
690
				array(),
691
				0,
692
				array( '{^$}' ),
693
				true,
694
				"## 0.1.0 - $date\n### Added\n- New stuff.\n- ZZZ.\n\n### Fixed\n- Broken stuff.\n",
695
			),
696
			'Amend and options'                            => array(
697
				array(
698
					'--amend'    => true,
699
					'--prologue' => 'New prologue',
700
					'--link'     => 'https://example.org/new-link',
701
				),
702
				array(
703
					'changes' => array(
704
						'added'  => "Significance: patch\nType: added\n\nNew stuff.\n",
705
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
706
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
707
					),
708
				),
709
				array(),
710
				0,
711
				array( '{^$}' ),
712
				true,
713
				"# Changelog\n\n## [1.0.1] - $date\n\nNew prologue\n\n### Added\n- New stuff.\n- Stuff.\n- ZZZ.\n\n### Removed\n- Other stuff.\n\n### Fixed\n- Broken stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n\n[1.0.1]: https://example.org/new-link\n",
714
			),
715
			'Amend without sorting by content'             => array(
716
				array( '--amend' => true ),
717
				array(
718
					'composer.json' => array( 'ordering' => array( 'subheading' ) ),
719
					'changes'       => array(
720
						'added'   => "Significance: patch\nType: added\n\nZZZ.\n",
721
						'removed' => "Significance: patch\nType: removed\n\nBroken stuff.\n",
722
					),
723
				),
724
				array(),
725
				0,
726
				array( '{^$}' ),
727
				true,
728
				"# Changelog\n\n## 1.0.1 - $date\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n- ZZZ.\n\n### Removed\n- Other stuff.\n- Broken stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
729
			),
730
731
			'--use-version invalid'                        => array(
732
				array( '--use-version' => '2.0' ),
733
				array(),
734
				array( 'N' ),
735
				WriteCommand::ASKED_EXIT,
736
				array(
737
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
738
					'{^The specified version is not valid\. This may cause problems in the future! Proceed\? \[y/N\]}m',
739
				),
740
			),
741
			'--use-version invalid (2)'                    => array(
742
				array( '--use-version' => '2.0' ),
743
				array(),
744
				array( 'Y' ),
745
				0,
746
				array(
747
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
748
					'{^The specified version is not valid\. This may cause problems in the future! Proceed\? \[y/N\]}m',
749
				),
750
				true,
751
				"# Changelog\n\n## 2.0 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
752
			),
753
			'--use-version invalid, non-interactive'       => array(
754
				array( '--use-version' => '2.0' ),
755
				array( 'interactive' => false ),
756
				array(),
757
				WriteCommand::ASKED_EXIT,
758
				array(
759
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
760
					'{^The specified version is not valid\. This may cause problems in the future!$}m',
761
				),
762
			),
763
			'--use-version invalid, non-interactive, --yes' => array(
764
				array(
765
					'--use-version' => '2.0',
766
					'--yes'         => true,
767
				),
768
				array( 'interactive' => false ),
769
				array(),
770
				0,
771
				array(
772
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
773
					'{^<warning>The specified version is not valid\. This may cause problems in the future! Continuing anyway\.$}m',
774
				),
775
				true,
776
				"# Changelog\n\n## 2.0 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
777
			),
778
779
			'--use-version not normalized'                 => array(
780
				array( '--use-version' => '2.0.00' ),
781
				array(),
782
				array( 'abort' ),
783
				WriteCommand::ASKED_EXIT,
784
				array(
785
					'{^The supplied version 2.0.00 is not normalized\.$}m',
786
					'{^\s*\[proceed\s*\] Proceed with 2\.0\.00$}m',
787
					'{^\s*\[normalize\s*\] Normalize to 2\.0\.0$}m',
788
					'{^\s*\[abort\s*\] Abort$}m',
789
				),
790
			),
791
			'--use-version not normalized, proceed'        => array(
792
				array( '--use-version' => '2.0.00' ),
793
				array(),
794
				array( 'proceed' ),
795
				0,
796
				array(
797
					'{^The supplied version 2.0.00 is not normalized\.$}m',
798
					'{^\s*\[proceed\s*\] Proceed with 2\.0\.00$}m',
799
					'{^\s*\[normalize\s*\] Normalize to 2\.0\.0$}m',
800
					'{^\s*\[abort\s*\] Abort$}m',
801
				),
802
				true,
803
				"# Changelog\n\n## 2.0.00 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
804
			),
805
			'--use-version not normalized, normalize'      => array(
806
				array( '--use-version' => '2.0.00' ),
807
				array(),
808
				array( 'normalize' ),
809
				0,
810
				array(
811
					'{^The supplied version 2.0.00 is not normalized\.$}m',
812
					'{^\s*\[proceed\s*\] Proceed with 2\.0\.00$}m',
813
					'{^\s*\[normalize\s*\] Normalize to 2\.0\.0$}m',
814
					'{^\s*\[abort\s*\] Abort$}m',
815
				),
816
				true,
817
				"# Changelog\n\n## 2.0.0 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
818
			),
819
			'--use-version not normalized, non-interactive' => array(
820
				array( '--use-version' => '2.0.00' ),
821
				array( 'interactive' => false ),
822
				array(),
823
				WriteCommand::ASKED_EXIT,
824
				array( '{^The supplied version 2.0.00 is not normalized, it should be 2.0.0\.$}m' ),
825
			),
826
			'--use-version not normalized, non-interactive, --yes' => array(
827
				array(
828
					'--use-version' => '2.0.00',
829
					'--yes'         => true,
830
				),
831
				array( 'interactive' => false ),
832
				array(),
833
				0,
834
				array( '{^<warning>The supplied version 2.0.00 is not normalized, it should be 2.0.0\. Continuing anyway\.$}m' ),
835
				true,
836
				"# Changelog\n\n## 2.0.00 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
837
			),
838
839
			'--use-version older'                          => array(
840
				array( '--use-version' => '1.0.1-dev' ),
841
				array(),
842
				array( 'N' ),
843
				WriteCommand::ASKED_EXIT,
844
				array( '{^The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\. Proceed\? \[y/N\]}m' ),
845
			),
846
			'--use-version older (2)'                      => array(
847
				array( '--use-version' => '1.0.1-dev' ),
848
				array(),
849
				array( 'Y' ),
850
				0,
851
				array( '{^The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\. Proceed\? \[y/N\]}m' ),
852
				true,
853
				"# Changelog\n\n## 1.0.1-dev - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
854
			),
855
			'--use-version older, non-interactive'         => array(
856
				array( '--use-version' => '1.0.1-dev' ),
857
				array( 'interactive' => false ),
858
				array(),
859
				WriteCommand::ASKED_EXIT,
860
				array( '{^The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\.$}m' ),
861
			),
862
			'--use-version older, non-interactive, --yes'  => array(
863
				array(
864
					'--use-version' => '1.0.1-dev',
865
					'--yes'         => true,
866
				),
867
				array( 'interactive' => false ),
868
				array(),
869
				0,
870
				array( '{^<warning>The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\. Continuing anyway\.$}m' ),
871
				true,
872
				"# Changelog\n\n## 1.0.1-dev - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
873
			),
874
875
			'--use-version equal'                          => array(
876
				array( '--use-version' => '1.0.1' ),
877
				array(),
878
				array( 'N' ),
879
				WriteCommand::ASKED_EXIT,
880
				array( '{^The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\. Proceed\? \[y/N\]}m' ),
881
			),
882
			'--use-version equal (2)'                      => array(
883
				array( '--use-version' => '1.0.1' ),
884
				array(),
885
				array( 'Y' ),
886
				0,
887
				array( '{^The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\. Proceed\? \[y/N\]}m' ),
888
				true,
889
				"# Changelog\n\n## 1.0.1 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
890
			),
891
			'--use-version equal, non-interactive'         => array(
892
				array( '--use-version' => '1.0.1' ),
893
				array( 'interactive' => false ),
894
				array(),
895
				WriteCommand::ASKED_EXIT,
896
				array( '{^The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\.$}m' ),
897
			),
898
			'--use-version equal, non-interactive, --yes'  => array(
899
				array(
900
					'--use-version' => '1.0.1',
901
					'--yes'         => true,
902
				),
903
				array( 'interactive' => false ),
904
				array(),
905
				0,
906
				array( '{^<warning>The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\. Continuing anyway\.$}m' ),
907
				true,
908
				"# Changelog\n\n## 1.0.1 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
909
			),
910
911
			'--use-significance'                           => array(
912
				array( '--use-significance' => 'major' ),
913
				array(),
914
				array(),
915
				0,
916
				array( '{^$}' ),
917
				true,
918
				"# Changelog\n\n## 2.0.0 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
919
			),
920
			'--use-significance invalid'                   => array(
921
				array( '--use-significance' => 'bogus' ),
922
				array(),
923
				array(),
924
				WriteCommand::FATAL_EXIT,
925
				array( '/^' . preg_quote( "Automattic\\Jetpack\\Changelog\\ChangeEntry::setSignificance: Significance must be 'patch', 'minor', or 'major' (or null)", '/' ) . '$/' ),
926
			),
927
928
			'--prerelease invalid'                         => array(
929
				array( '--prerelease' => '???' ),
930
				array(),
931
				array(),
932
				WriteCommand::FATAL_EXIT,
933
				array( '{^Failed to determine new version: Invalid prerelease data$}m' ),
934
			),
935
			'Version in changelog valid'                   => array(
936
				array(),
937
				array(
938
					'changelog' => "## 2.0 - 2021-02-24\n\nThis is the \"problem in the future\" that comes of ignoring the warning about an invalid --use-version...\n",
939
				),
940
				array(),
941
				WriteCommand::FATAL_EXIT,
942
				array( '{^Changelog file contains invalid version 2\.0! Use --use-version to specify the new version\.$}m' ),
943
			),
944
			'Version in changelog valid, amending'         => array(
945
				array( '--amend' => true ),
946
				array(
947
					'changelog' => "## 2.0 - 2021-02-24\n\nThis is the \"problem in the future\" that comes of ignoring the warning about an invalid --use-version...\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
948
				),
949
				array(),
950
				0,
951
				array( '{^$}m' ),
952
				true,
953
				"## 1.0.1 - $date\n\nThis is the \"problem in the future\" that comes of ignoring the warning about an invalid --use-version...\n\n### Fixed\n- Fixed a thing.\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n",
954
			),
955
956
			'Entry creation fail'                          => array(
957
				array( '--link' => '???' ),
958
				array(),
959
				array(),
960
				WriteCommand::FATAL_EXIT,
961
				array( '/^' . preg_quote( 'Failed to create changelog entry: Automattic\\Jetpack\\Changelog\\ChangelogEntry::setLink: Invalid URL', '/' ) . '$/' ),
962
			),
963
			'Link template'                                => array(
964
				array(),
965
				array(
966
					'composer.json' => array( 'link-template' => 'https://example.org/diff/${old}..${new}' ),
967
				),
968
				array(),
969
				0,
970
				array( '{^$}' ),
971
				true,
972
				"# Changelog\n\n## [1.0.2] - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0.1 - 2021-02-23\n\nPrologue for v1.0.1\n\n### Added\n- Stuff.\n\n### Removed\n- Other stuff.\n\nEpilogue for v1.0.1\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n\n[1.0.2]: https://example.org/diff/1.0.1..1.0.2\n",
973
			),
974
			'Link template, initial version'               => array(
975
				array( '--use-version' => '1.0.0' ),
976
				array(
977
					'composer.json' => array( 'link-template' => 'https://example.org/diff/${old}..${new}' ),
978
					'changelog'     => "# Changelog\n",
979
				),
980
				array(),
981
				0,
982
				array( '{^$}' ),
983
				true,
984
				"# Changelog\n\n## 1.0.0 - $date\n### Fixed\n- Fixed a thing.\n",
985
			),
986
987
			'Interactive defaulting'                       => array(
988
				array(),
989
				array( 'changelog' => null ),
990
				array( '' ),
991
				WriteCommand::ASKED_EXIT,
992
				array( '{^Changelog file /.*/CHANGELOG\.md does not exist! Proceed\? \[y/N\]}m' ),
993
			),
994
			'Interactive defaulting, --yes'                => array(
995
				array( '--yes' => true ),
996
				array( 'changelog' => null ),
997
				array( '' ),
998
				WriteCommand::FATAL_EXIT,
999
				array(
1000
					'{^Changelog file /.*/CHANGELOG\.md does not exist! Proceed\? \[Y/n\]}m',
1001
					'/Changelog file contains no entries! Use --use-version to specify the initial version\.$/m',
1002
				),
1003
			),
1004
1005
			'Options from versioning plugin'               => array(
1006
				array( '--point-release' => true ),
1007
				array(
1008
					'composer.json' => array( 'versioning' => 'wordpress' ),
1009
					'changelog'     => "# Changelog\n\n## 1.0 - 2021-02-24\n\n- Initial release\n",
1010
				),
1011
				array(),
1012
				0,
1013
				array( '{^$}' ),
1014
				true,
1015
				'changelog' => "# Changelog\n\n## 1.0.1 - $date\n### Fixed\n- Fixed a thing.\n\n## 1.0 - 2021-02-24\n\n- Initial release\n",
1016
			),
1017
		);
1018
	}
1019
1020
	/**
1021
	 * Test failure to format changelog.
1022
	 */
1023
	public function testWriteChangelog_formatError() {
1024
		$formatter = $this->getMockBuilder( FormatterPlugin::class )
1025
			->setMethodsExcept( array() )
1026
			->getMock();
1027
		$formatter->expects( $this->never() )->method( $this->logicalNot( $this->matches( 'format' ) ) );
1028
		$formatter->method( 'format' )->willThrowException( new InvalidArgumentException( 'Exception for test.' ) );
1029
1030
		$w            = TestingAccessWrapper::newFromObject( $this->getCommand( 'write' ) );
1031
		$w->formatter = $formatter;
1032
1033
		$input  = new ArrayInput( array() );
1034
		$output = new BufferedOutput();
1035
		$ret    = $w->writeChangelog( $input, $output, new Changelog() );
1036
		$this->assertSame( WriteCommand::FATAL_EXIT, $ret );
1037
		$this->assertSame( "Failed to write the changelog: Exception for test.\n", $output->fetch() );
1038
	}
1039
1040
	/**
1041
	 * Test failure to write changelog.
1042
	 */
1043
	public function testWriteChangelog_writeError() {
1044
		mkdir( 'CHANGELOG.md' );
1045
1046
		$formatter = $this->getMockBuilder( FormatterPlugin::class )
1047
			->setMethodsExcept( array() )
1048
			->getMock();
1049
		$formatter->expects( $this->never() )->method( $this->logicalNot( $this->matches( 'format' ) ) );
1050
		$formatter->method( 'format' )->willReturn( "Changelog!\n" );
1051
1052
		$w            = TestingAccessWrapper::newFromObject( $this->getCommand( 'write' ) );
1053
		$w->formatter = $formatter;
1054
1055
		$input  = new ArrayInput( array() );
1056
		$output = new BufferedOutput();
1057
		$ret    = $w->writeChangelog( $input, $output, new Changelog() );
1058
		$this->assertSame( WriteCommand::FATAL_EXIT, $ret );
1059
		$cwd = getcwd();
1060
		$this->assertStringContainsString( "Failed to write $cwd/CHANGELOG.md: ", $output->fetch() );
1061
	}
1062
1063
	/**
1064
	 * Test delete changes failure.
1065
	 */
1066
	public function testDeleteChanges_error() {
1067
		$w = TestingAccessWrapper::newFromObject( $this->getCommand( 'write' ) );
1068
1069
		$input  = new ArrayInput( array() );
1070
		$output = new BufferedOutput();
1071
		$ret    = $w->deleteChanges(
1072
			$input,
1073
			$output,
1074
			array(
1075
				'doesnotexist' => 0,
1076
				'.gitkeep'     => 0,
1077
			)
1078
		);
1079
		$this->assertSame( WriteCommand::DELETE_FAILED_EXIT, $ret );
1080
		$out = $output->fetch();
1081
		$this->assertStringContainsString( 'Failed to delete doesnotexist: ', $out );
1082
		$this->assertStringNotContainsString( 'Failed to delete .gitkeep: ', $out );
1083
	}
1084
1085
	/**
1086
	 * Test execute handling of writeChangelog failing.
1087
	 */
1088
	public function testExecute_writeChangelog_fail() {
1089
		$command = $this->getMockBuilder( WriteCommand::class )
1090
			->setMethods( array( 'writeChangelog', 'deleteChanges' ) )
1091
			->getMock();
1092
		$command->setApplication( $this->getCommand( 'write' )->getApplication() );
1093
		$command->method( 'writeChangelog' )->willReturn( WriteCommand::FATAL_EXIT );
1094
		$command->expects( $this->never() )->method( 'deleteChanges' );
1095
1096
		file_put_contents( 'CHANGELOG.md', "# Changelog\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n" );
1097
		file_put_contents( 'changelog/a-change', "Significance: patch\nType: fixed\n\nFixed a thing.\n" );
1098
1099
		$tester = new CommandTester( $command );
1100
		$code   = $tester->execute( array() );
1101
		$this->assertSame( WriteCommand::FATAL_EXIT, $code );
1102
	}
1103
1104
}
1105