Completed
Push — renovate/css-loader-5.x ( 70942c...c43e3d )
by
unknown
124:26 queued 114:47
created

WriteCommandTest::testDeleteChanges_error()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
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
				),
157
				array(),
158
				array(),
159
				0,
160
				array( '/^$/' ),
161
				true,
162
				"# Changelog\n\n## [1.0.2-dev+g1234567] - $date\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",
163
			),
164
165
			'Invalid formatter'                            => array(
166
				array(),
167
				array( 'composer.json' => array( 'formatter' => 'bogus' ) ),
168
				array(),
169
				WriteCommand::FATAL_EXIT,
170
				array( '/^Unknown formatter plugin "bogus"$/' ),
171
			),
172
			'Invalid versioning'                           => array(
173
				array(),
174
				array( 'composer.json' => array( 'versioning' => 'bogus' ) ),
175
				array(),
176
				WriteCommand::FATAL_EXIT,
177
				array( '/^Unknown versioning plugin "bogus"$/' ),
178
			),
179
180
			'No changelog file, interactive'               => array(
181
				array(),
182
				array( 'changelog' => null ),
183
				array( 'N' ),
184
				WriteCommand::ASKED_EXIT,
185
				array( '{^Changelog file /.*/CHANGELOG\.md does not exist! Proceed\? \[y/N\]}m' ),
186
			),
187
			'No changelog file, interactive (2)'           => array(
188
				array(),
189
				array( 'changelog' => null ),
190
				array( 'Y' ),
191
				WriteCommand::FATAL_EXIT,
192
				array( '/Changelog file contains no entries! Use --use-version to specify the initial version\.$/m' ),
193
			),
194
			'No changelog file, interactive (3)'           => array(
195
				array(
196
					'--default-first-version' => true,
197
					'--prerelease'            => 'beta',
198
				),
199
				array( 'changelog' => null ),
200
				array( 'Y' ),
201
				0,
202
				array(),
203
				true,
204
				"## 0.1.0-beta - $date\n### Fixed\n- Fixed a thing.\n",
205
			),
206
			'No changelog file, non-interactive'           => array(
207
				array(),
208
				array(
209
					'interactive' => false,
210
					'changelog'   => null,
211
				),
212
				array(),
213
				WriteCommand::ASKED_EXIT,
214
				array( '{^Changelog file /.*/CHANGELOG\.md does not exist!$}m' ),
215
			),
216
			'No changelog file, non-interactive, --yes'    => array(
217
				array( '--yes' => true ),
218
				array(
219
					'interactive' => false,
220
					'changelog'   => null,
221
				),
222
				array(),
223
				WriteCommand::FATAL_EXIT,
224
				array(
225
					'{^<warning>Changelog file /.*/CHANGELOG\.md does not exist! Continuing anyway\.$}m',
226
					'/Changelog file contains no entries! Use --use-version to specify the initial version\.$/m',
227
				),
228
			),
229
			'No changelog file, non-interactive, --yes (2)' => array(
230
				array(
231
					'--yes'         => true,
232
					'--use-version' => '1.0.0',
233
				),
234
				array(
235
					'interactive' => false,
236
					'changelog'   => null,
237
				),
238
				array(),
239
				0,
240
				array(
241
					'{^<warning>Changelog file /.*/CHANGELOG\.md does not exist! Continuing anyway\.$}m',
242
				),
243
				true,
244
				"## 1.0.0 - $date\n### Fixed\n- Fixed a thing.\n",
245
			),
246
247
			'Unparseable changelog'                        => array(
248
				array(),
249
				array( 'changelog' => "## bogus\n" ),
250
				array(),
251
				WriteCommand::FATAL_EXIT,
252
				array( '{^Failed to parse changelog: Invalid heading: ## bogus$}' ),
253
			),
254
255
			'No changes directory'                         => array(
256
				array(),
257
				array( 'composer.json' => array( 'changes-dir' => 'changes' ) ),
258
				array( 'N' ),
259
				WriteCommand::NO_CHANGE_EXIT,
260
				array( '{^Changes directory does not exist, so there are no changes to write! Proceed\? \[y/N\]}m' ),
261
			),
262
			'No changes directory (2)'                     => array(
263
				array(),
264
				array( 'composer.json' => array( 'changes-dir' => 'changes' ) ),
265
				array( 'Y' ),
266
				0,
267
				array( '{^Changes directory does not exist, so there are no changes to write! Proceed\? \[y/N\]}m' ),
268
				false,
269
				"# 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",
270
			),
271
			'No changes directory, non-interactive'        => array(
272
				array(),
273
				array(
274
					'composer.json' => array( 'changes-dir' => 'changes' ),
275
					'interactive'   => false,
276
				),
277
				array(),
278
				WriteCommand::NO_CHANGE_EXIT,
279
				array( '{^Changes directory does not exist, so there are no changes to write!$}m' ),
280
			),
281
			'No changes directory, non-interactive, --yes' => array(
282
				array( '--yes' => true ),
283
				array(
284
					'composer.json' => array( 'changes-dir' => 'changes' ),
285
					'interactive'   => false,
286
				),
287
				array(),
288
				0,
289
				array( '{^<warning>Changes directory does not exist, so there are no changes to write! Continuing anyway\.$}m' ),
290
				false,
291
				"# 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",
292
			),
293
294
			'Change files with warnings'                   => array(
295
				array(),
296
				array(
297
					'changes' => array(
298
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
299
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
300
					),
301
				),
302
				array( 'N' ),
303
				WriteCommand::ASKED_EXIT,
304
				array( '{^Warnings were encountered while reading changes! Proceed\? \[y/N\]}m' ),
305
			),
306
			'Change files with warnings (2)'               => array(
307
				array(),
308
				array(
309
					'changes' => array(
310
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
311
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
312
					),
313
				),
314
				array( 'Y' ),
315
				0,
316
				array( '{^Warnings were encountered while reading changes! Proceed\? \[y/N\]}m' ),
317
				true,
318
				"# 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",
319
			),
320
			'Change files with warnings, non-interactive'  => array(
321
				array(),
322
				array(
323
					'interactive' => false,
324
					'changes'     => array(
325
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
326
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
327
					),
328
				),
329
				array(),
330
				WriteCommand::ASKED_EXIT,
331
				array( '{^Warnings were encountered while reading changes!$}m' ),
332
			),
333
			'Change files with warnings, non-interactive, --yes' => array(
334
				array( '--yes' => true ),
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
				0,
344
				array( '{^<warning>Warnings were encountered while reading changes! Continuing anyway\.$}m' ),
345
				true,
346
				"# 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",
347
			),
348
349
			'Change files with errors'                     => array(
350
				array(),
351
				array(
352
					'changes' => array(
353
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
354
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
355
						'error'    => "Bogus\n",
356
					),
357
				),
358
				array( 'N' ),
359
				WriteCommand::ASKED_EXIT,
360
				array( '{^Errors were encountered while reading changes! Proceed\? \[y/N\]}m' ),
361
			),
362
			'Change files with errors (2)'                 => 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( 'Y' ),
372
				0,
373
				array( '{^Errors were encountered while reading changes! Proceed\? \[y/N\]}m' ),
374
				array( 'a-change', 'b-change' ),
375
				"# 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",
376
			),
377
			'Change files with errors, non-interactive'    => array(
378
				array(),
379
				array(
380
					'interactive' => false,
381
					'changes'     => array(
382
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
383
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
384
						'error'    => "Bogus\n",
385
					),
386
				),
387
				array(),
388
				WriteCommand::ASKED_EXIT,
389
				array( '{^Errors were encountered while reading changes!$}m' ),
390
			),
391
			'Change files with errors, non-interactive, --yes' => array(
392
				array( '--yes' => true ),
393
				array(
394
					'interactive' => false,
395
					'changes'     => array(
396
						'a-change' => "Significance: patch\nType: fixed\n\nFixed a thing.\n",
397
						'b-change' => "Significance: patch\nType: fixed\nType: fixed\n\nDid a thing.\n",
398
						'error'    => "Bogus\n",
399
					),
400
				),
401
				array(),
402
				0,
403
				array( '{^<warning>Errors were encountered while reading changes! Continuing anyway\.$}m' ),
404
				array( 'a-change', 'b-change' ),
405
				"# 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",
406
			),
407
408
			'No changes'                                   => array(
409
				array(),
410
				array( 'changes' => array() ),
411
				array( 'N' ),
412
				WriteCommand::NO_CHANGE_EXIT,
413
				array( '{^No changes were found! Proceed\? \[y/N\]}m' ),
414
			),
415
			'No changes (2)'                               => array(
416
				array(),
417
				array( 'changes' => array() ),
418
				array( 'Y' ),
419
				0,
420
				array( '{^No changes were found! Proceed\? \[y/N\]}m' ),
421
				true,
422
				"# 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",
423
			),
424
			'No changes, non-interactive'                  => array(
425
				array(),
426
				array(
427
					'interactive' => false,
428
					'changes'     => array(),
429
				),
430
				array(),
431
				WriteCommand::NO_CHANGE_EXIT,
432
				array( '{^No changes were found!$}m' ),
433
			),
434
			'No changes, non-interactive, --yes'           => array(
435
				array( '--yes' => true ),
436
				array(
437
					'interactive' => false,
438
					'changes'     => array(),
439
				),
440
				array(),
441
				0,
442
				array( '{^<warning>No changes were found! Continuing anyway\.$}m' ),
443
				true,
444
				"# 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",
445
			),
446
447
			'Deduplication'                                => array(
448
				array(),
449
				array(
450
					'changes' => array(
451
						'initial-release' => "Significance: patch\nType: added\n\nInitial release.\n",
452
						'added-stuff'     => "Significance: patch\nType: added\n\nStuff.\n",
453
						'added-stuff-2'   => "Significance: patch\nType: added\n\nStuff. And more stuff.\n",
454
					),
455
				),
456
				array(),
457
				0,
458
				array( '{^$}m' ),
459
				true,
460
				"# 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",
461
			),
462
			'Deduplication, --dedupliacte=0'               => array(
463
				array( '--deduplicate' => '0' ),
464
				array(
465
					'changes' => array(
466
						'initial-release' => "Significance: patch\nType: added\n\nInitial release.\n",
467
						'added-stuff'     => "Significance: patch\nType: added\n\nStuff.\n",
468
						'added-stuff-2'   => "Significance: patch\nType: added\n\nStuff. And more stuff.\n",
469
					),
470
				),
471
				array(),
472
				0,
473
				array( '{^$}m' ),
474
				true,
475
				"# 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",
476
			),
477
			'Deduplication, --dedupliacte=2'               => array(
478
				array( '--deduplicate' => '2' ),
479
				array(
480
					'changes' => array(
481
						'initial-release' => "Significance: patch\nType: added\n\nInitial release.\n",
482
						'added-stuff'     => "Significance: patch\nType: added\n\nStuff.\n",
483
						'added-stuff-2'   => "Significance: patch\nType: added\n\nStuff. And more stuff.\n",
484
					),
485
				),
486
				array(),
487
				0,
488
				array( '{^$}m' ),
489
				true,
490
				"# 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",
491
			),
492
493
			'Deduplication removes all changes'            => array(
494
				array(),
495
				array(
496
					'changes' => array(
497
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
498
					),
499
				),
500
				array( 'N' ),
501
				WriteCommand::NO_CHANGE_EXIT,
502
				array( '{^All changes were duplicates\. Proceed\? \[y/N\]}m' ),
503
			),
504
			'Deduplication removes all changes (2)'        => array(
505
				array(),
506
				array(
507
					'changes' => array(
508
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
509
					),
510
				),
511
				array( 'Y' ),
512
				0,
513
				array( '{^All changes were duplicates\. Proceed\? \[y/N\]}m' ),
514
				true,
515
				"# 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",
516
			),
517
			'Deduplication removes all changes, non-interactive' => array(
518
				array(),
519
				array(
520
					'interactive' => false,
521
					'changes'     => array(
522
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
523
					),
524
				),
525
				array(),
526
				WriteCommand::NO_CHANGE_EXIT,
527
				array( '{^All changes were duplicates\.$}m' ),
528
			),
529
			'Deduplication removes all changes, non-interactive, --yes' => array(
530
				array( '--yes' => true ),
531
				array(
532
					'interactive' => false,
533
					'changes'     => array(
534
						'added-stuff' => "Significance: patch\nType: added\n\nStuff.\n",
535
					),
536
				),
537
				array(),
538
				0,
539
				array( '{^<warning>All changes were duplicates\. Continuing anyway\.$}m' ),
540
				true,
541
				"# 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",
542
			),
543
544
			'All changes are empty'                        => array(
545
				array(),
546
				array(
547
					'changes' => array(
548
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
549
						'error'     => "Bogus\n",
550
						'empty'     => "Significance: patch\nType: fixed\n\n",
551
					),
552
				),
553
				array( 'Y', 'N' ),
554
				WriteCommand::NO_CHANGE_EXIT,
555
				array( '{There are no changes with content for this write\. Proceed\? \[y/N\]}m' ),
556
			),
557
			'All changes are empty (2)'                    => 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', 'Y' ),
567
				0,
568
				array( '{There are no changes with content for this write\. Proceed\? \[y/N\]}m' ),
569
				array( 'duplicate', 'empty' ),
570
				"# 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",
571
			),
572
			'All changes are empty, non-interactive'       => array(
573
				array(),
574
				array(
575
					'interactive' => false,
576
					'changes'     => array(
577
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
578
						'empty'     => "Significance: patch\nType: fixed\n\n",
579
					),
580
				),
581
				array(),
582
				WriteCommand::NO_CHANGE_EXIT,
583
				array( '{^There are no changes with content for this write\.$}m' ),
584
			),
585
			'All changes are empty, non-interactive, --yes' => array(
586
				array( '--yes' => true ),
587
				array(
588
					'interactive' => false,
589
					'changes'     => array(
590
						'duplicate' => "Significance: patch\nType: added\n\nStuff.\n",
591
						'error'     => "Bogus\n",
592
						'empty'     => "Significance: patch\nType: fixed\n\n",
593
					),
594
				),
595
				array(),
596
				0,
597
				array( '{^<warning>There are no changes with content for this write\. Continuing anyway\.$}m' ),
598
				array( 'duplicate', 'empty' ),
599
				"# 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",
600
			),
601
602
			'Amend'                                        => array(
603
				array( '--amend' => true ),
604
				array(
605
					'changes' => array(
606
						'added'  => "Significance: patch\nType: added\n\nNew stuff.\n",
607
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
608
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
609
					),
610
				),
611
				array(),
612
				0,
613
				array( '{^$}' ),
614
				true,
615
				"# 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",
616
			),
617
			'Amend, upgrade version'                       => array(
618
				array( '--amend' => true ),
619
				array(
620
					'changes' => array(
621
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
622
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
623
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
624
					),
625
				),
626
				array(),
627
				0,
628
				array( '{^$}' ),
629
				true,
630
				"# 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",
631
			),
632
			'Amend, no downgrade version'                  => array(
633
				array( '--amend' => true ),
634
				array(
635
					'changes'   => array(
636
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
637
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
638
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
639
					),
640
					'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",
641
				),
642
				array(),
643
				0,
644
				array( '{^$}' ),
645
				true,
646
				"# 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",
647
			),
648
			'Amend initial release'                        => array(
649
				array( '--amend' => true ),
650
				array(
651
					'changes'   => array(
652
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
653
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
654
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
655
					),
656
					'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",
657
				),
658
				array(),
659
				0,
660
				array( '{^$}' ),
661
				true,
662
				"# 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",
663
			),
664
			'Amend empty changelog'                        => array(
665
				array(
666
					'--amend'       => true,
667
					'--use-version' => '0.1.0',
668
				),
669
				array(
670
					'changes'   => array(
671
						'added'  => "Significance: minor\nType: added\n\nNew stuff.\n",
672
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
673
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
674
					),
675
					'changelog' => '',
676
				),
677
				array(),
678
				0,
679
				array( '{^$}' ),
680
				true,
681
				"## 0.1.0 - $date\n### Added\n- New stuff.\n- ZZZ.\n\n### Fixed\n- Broken stuff.\n",
682
			),
683
			'Amend and options'                            => array(
684
				array(
685
					'--amend'    => true,
686
					'--prologue' => 'New prologue',
687
					'--link'     => 'https://example.org/new-link',
688
				),
689
				array(
690
					'changes' => array(
691
						'added'  => "Significance: patch\nType: added\n\nNew stuff.\n",
692
						'added2' => "Significance: patch\nType: added\n\nZZZ.\n",
693
						'fixed'  => "Significance: patch\nType: fixed\n\nBroken stuff.\n",
694
					),
695
				),
696
				array(),
697
				0,
698
				array( '{^$}' ),
699
				true,
700
				"# 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",
701
			),
702
			'Amend without sorting by content'             => array(
703
				array( '--amend' => true ),
704
				array(
705
					'composer.json' => array( 'ordering' => array( 'subheading' ) ),
706
					'changes'       => array(
707
						'added'   => "Significance: patch\nType: added\n\nZZZ.\n",
708
						'removed' => "Significance: patch\nType: removed\n\nBroken stuff.\n",
709
					),
710
				),
711
				array(),
712
				0,
713
				array( '{^$}' ),
714
				true,
715
				"# 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",
716
			),
717
718
			'--use-version invalid'                        => array(
719
				array( '--use-version' => '2.0' ),
720
				array(),
721
				array( 'N' ),
722
				WriteCommand::ASKED_EXIT,
723
				array(
724
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
725
					'{^The specified version is not valid\. This may cause problems in the future! Proceed\? \[y/N\]}m',
726
				),
727
			),
728
			'--use-version invalid (2)'                    => array(
729
				array( '--use-version' => '2.0' ),
730
				array(),
731
				array( 'Y' ),
732
				0,
733
				array(
734
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
735
					'{^The specified version is not valid\. This may cause problems in the future! Proceed\? \[y/N\]}m',
736
				),
737
				true,
738
				"# 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",
739
			),
740
			'--use-version invalid, non-interactive'       => array(
741
				array( '--use-version' => '2.0' ),
742
				array( 'interactive' => false ),
743
				array(),
744
				WriteCommand::ASKED_EXIT,
745
				array(
746
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
747
					'{^The specified version is not valid\. This may cause problems in the future!$}m',
748
				),
749
			),
750
			'--use-version invalid, non-interactive, --yes' => array(
751
				array(
752
					'--use-version' => '2.0',
753
					'--yes'         => true,
754
				),
755
				array( 'interactive' => false ),
756
				array(),
757
				0,
758
				array(
759
					'{^Invalid --use-version: Version number "2.0" is not in a recognized format\.$}m',
760
					'{^<warning>The specified version is not valid\. This may cause problems in the future! Continuing anyway\.$}m',
761
				),
762
				true,
763
				"# 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",
764
			),
765
766
			'--use-version not normalized'                 => array(
767
				array( '--use-version' => '2.0.00' ),
768
				array(),
769
				array( 'abort' ),
770
				WriteCommand::ASKED_EXIT,
771
				array(
772
					'{^The supplied version 2.0.00 is not normalized\.$}m',
773
					'{^\s*\[proceed\s*\] Proceed with 2\.0\.00$}m',
774
					'{^\s*\[normalize\s*\] Normalize to 2\.0\.0$}m',
775
					'{^\s*\[abort\s*\] Abort$}m',
776
				),
777
			),
778
			'--use-version not normalized, proceed'        => array(
779
				array( '--use-version' => '2.0.00' ),
780
				array(),
781
				array( 'proceed' ),
782
				0,
783
				array(
784
					'{^The supplied version 2.0.00 is not normalized\.$}m',
785
					'{^\s*\[proceed\s*\] Proceed with 2\.0\.00$}m',
786
					'{^\s*\[normalize\s*\] Normalize to 2\.0\.0$}m',
787
					'{^\s*\[abort\s*\] Abort$}m',
788
				),
789
				true,
790
				"# 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",
791
			),
792
			'--use-version not normalized, normalize'      => array(
793
				array( '--use-version' => '2.0.00' ),
794
				array(),
795
				array( 'normalize' ),
796
				0,
797
				array(
798
					'{^The supplied version 2.0.00 is not normalized\.$}m',
799
					'{^\s*\[proceed\s*\] Proceed with 2\.0\.00$}m',
800
					'{^\s*\[normalize\s*\] Normalize to 2\.0\.0$}m',
801
					'{^\s*\[abort\s*\] Abort$}m',
802
				),
803
				true,
804
				"# 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",
805
			),
806
			'--use-version not normalized, non-interactive' => array(
807
				array( '--use-version' => '2.0.00' ),
808
				array( 'interactive' => false ),
809
				array(),
810
				WriteCommand::ASKED_EXIT,
811
				array( '{^The supplied version 2.0.00 is not normalized, it should be 2.0.0\.$}m' ),
812
			),
813
			'--use-version not normalized, non-interactive, --yes' => array(
814
				array(
815
					'--use-version' => '2.0.00',
816
					'--yes'         => true,
817
				),
818
				array( 'interactive' => false ),
819
				array(),
820
				0,
821
				array( '{^<warning>The supplied version 2.0.00 is not normalized, it should be 2.0.0\. Continuing anyway\.$}m' ),
822
				true,
823
				"# 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",
824
			),
825
826
			'--use-version older'                          => array(
827
				array( '--use-version' => '1.0.1-dev' ),
828
				array(),
829
				array( 'N' ),
830
				WriteCommand::ASKED_EXIT,
831
				array( '{^The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\. Proceed\? \[y/N\]}m' ),
832
			),
833
			'--use-version older (2)'                      => array(
834
				array( '--use-version' => '1.0.1-dev' ),
835
				array(),
836
				array( 'Y' ),
837
				0,
838
				array( '{^The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\. Proceed\? \[y/N\]}m' ),
839
				true,
840
				"# 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",
841
			),
842
			'--use-version older, non-interactive'         => array(
843
				array( '--use-version' => '1.0.1-dev' ),
844
				array( 'interactive' => false ),
845
				array(),
846
				WriteCommand::ASKED_EXIT,
847
				array( '{^The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\.$}m' ),
848
			),
849
			'--use-version older, non-interactive, --yes'  => array(
850
				array(
851
					'--use-version' => '1.0.1-dev',
852
					'--yes'         => true,
853
				),
854
				array( 'interactive' => false ),
855
				array(),
856
				0,
857
				array( '{^<warning>The most recent version in the changelog is 1\.0\.1, which comes after 1\.0\.1-dev\. Continuing anyway\.$}m' ),
858
				true,
859
				"# 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",
860
			),
861
862
			'--use-version equal'                          => array(
863
				array( '--use-version' => '1.0.1' ),
864
				array(),
865
				array( 'N' ),
866
				WriteCommand::ASKED_EXIT,
867
				array( '{^The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\. Proceed\? \[y/N\]}m' ),
868
			),
869
			'--use-version equal (2)'                      => array(
870
				array( '--use-version' => '1.0.1' ),
871
				array(),
872
				array( 'Y' ),
873
				0,
874
				array( '{^The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\. Proceed\? \[y/N\]}m' ),
875
				true,
876
				"# 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",
877
			),
878
			'--use-version equal, non-interactive'         => array(
879
				array( '--use-version' => '1.0.1' ),
880
				array( 'interactive' => false ),
881
				array(),
882
				WriteCommand::ASKED_EXIT,
883
				array( '{^The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\.$}m' ),
884
			),
885
			'--use-version equal, non-interactive, --yes'  => array(
886
				array(
887
					'--use-version' => '1.0.1',
888
					'--yes'         => true,
889
				),
890
				array( 'interactive' => false ),
891
				array(),
892
				0,
893
				array( '{^<warning>The most recent version in the changelog is 1\.0\.1, which is equivalent to 1\.0\.1\. Continuing anyway\.$}m' ),
894
				true,
895
				"# 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",
896
			),
897
898
			'--use-significance'                           => array(
899
				array( '--use-significance' => 'major' ),
900
				array(),
901
				array(),
902
				0,
903
				array( '{^$}' ),
904
				true,
905
				"# 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",
906
			),
907
			'--use-significance invalid'                   => array(
908
				array( '--use-significance' => 'bogus' ),
909
				array(),
910
				array(),
911
				WriteCommand::FATAL_EXIT,
912
				array( '/^' . preg_quote( "Automattic\\Jetpack\\Changelog\\ChangeEntry::setSignificance: Significance must be 'patch', 'minor', or 'major' (or null)", '/' ) . '$/' ),
913
			),
914
915
			'--prerelease invalid'                         => array(
916
				array( '--prerelease' => '???' ),
917
				array(),
918
				array(),
919
				WriteCommand::FATAL_EXIT,
920
				array( '{^Failed to determine new version: Invalid prerelease data$}m' ),
921
			),
922
			'Version in changelog valid'                   => array(
923
				array(),
924
				array(
925
					'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",
926
				),
927
				array(),
928
				WriteCommand::FATAL_EXIT,
929
				array( '{^Changelog file contains invalid version 2\.0! Use --use-version to specify the new version\.$}m' ),
930
			),
931
			'Version in changelog valid, amending'         => array(
932
				array( '--amend' => true ),
933
				array(
934
					'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",
935
				),
936
				array(),
937
				0,
938
				array( '{^$}m' ),
939
				true,
940
				"## 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",
941
			),
942
943
			'Entry creation fail'                          => array(
944
				array( '--link' => '???' ),
945
				array(),
946
				array(),
947
				WriteCommand::FATAL_EXIT,
948
				array( '/^' . preg_quote( 'Failed to create changelog entry: Automattic\\Jetpack\\Changelog\\ChangelogEntry::setLink: Invalid URL', '/' ) . '$/' ),
949
			),
950
			'Link template'                                => array(
951
				array(),
952
				array(
953
					'composer.json' => array( 'link-template' => 'https://example.org/diff/${old}..${new}' ),
954
				),
955
				array(),
956
				0,
957
				array( '{^$}' ),
958
				true,
959
				"# 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",
960
			),
961
			'Link template, initial version'               => array(
962
				array( '--use-version' => '1.0.0' ),
963
				array(
964
					'composer.json' => array( 'link-template' => 'https://example.org/diff/${old}..${new}' ),
965
					'changelog'     => "# Changelog\n",
966
				),
967
				array(),
968
				0,
969
				array( '{^$}' ),
970
				true,
971
				"# Changelog\n\n## 1.0.0 - $date\n### Fixed\n- Fixed a thing.\n",
972
			),
973
974
			'Interactive defaulting'                       => array(
975
				array(),
976
				array( 'changelog' => null ),
977
				array( '' ),
978
				WriteCommand::ASKED_EXIT,
979
				array( '{^Changelog file /.*/CHANGELOG\.md does not exist! Proceed\? \[y/N\]}m' ),
980
			),
981
			'Interactive defaulting, --yes'                => array(
982
				array( '--yes' => true ),
983
				array( 'changelog' => null ),
984
				array( '' ),
985
				WriteCommand::FATAL_EXIT,
986
				array(
987
					'{^Changelog file /.*/CHANGELOG\.md does not exist! Proceed\? \[Y/n\]}m',
988
					'/Changelog file contains no entries! Use --use-version to specify the initial version\.$/m',
989
				),
990
			),
991
992
			'Options from versioning plugin'               => array(
993
				array( '--point-release' => true ),
994
				array(
995
					'composer.json' => array( 'versioning' => 'wordpress' ),
996
					'changelog'     => "# Changelog\n\n## 1.0 - 2021-02-24\n\n- Initial release\n",
997
				),
998
				array(),
999
				0,
1000
				array( '{^$}' ),
1001
				true,
1002
				'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",
1003
			),
1004
		);
1005
	}
1006
1007
	/**
1008
	 * Test failure to format changelog.
1009
	 */
1010
	public function testWriteChangelog_formatError() {
1011
		$formatter = $this->getMockBuilder( FormatterPlugin::class )
1012
			->setMethodsExcept( array() )
1013
			->getMock();
1014
		$formatter->expects( $this->never() )->method( $this->logicalNot( $this->matches( 'format' ) ) );
1015
		$formatter->method( 'format' )->willThrowException( new InvalidArgumentException( 'Exception for test.' ) );
1016
1017
		$w            = TestingAccessWrapper::newFromObject( $this->getCommand( 'write' ) );
1018
		$w->formatter = $formatter;
1019
1020
		$input  = new ArrayInput( array() );
1021
		$output = new BufferedOutput();
1022
		$ret    = $w->writeChangelog( $input, $output, new Changelog() );
1023
		$this->assertSame( WriteCommand::FATAL_EXIT, $ret );
1024
		$this->assertSame( "Failed to write the changelog: Exception for test.\n", $output->fetch() );
1025
	}
1026
1027
	/**
1028
	 * Test failure to write changelog.
1029
	 */
1030
	public function testWriteChangelog_writeError() {
1031
		mkdir( 'CHANGELOG.md' );
1032
1033
		$formatter = $this->getMockBuilder( FormatterPlugin::class )
1034
			->setMethodsExcept( array() )
1035
			->getMock();
1036
		$formatter->expects( $this->never() )->method( $this->logicalNot( $this->matches( 'format' ) ) );
1037
		$formatter->method( 'format' )->willReturn( "Changelog!\n" );
1038
1039
		$w            = TestingAccessWrapper::newFromObject( $this->getCommand( 'write' ) );
1040
		$w->formatter = $formatter;
1041
1042
		$input  = new ArrayInput( array() );
1043
		$output = new BufferedOutput();
1044
		$ret    = $w->writeChangelog( $input, $output, new Changelog() );
1045
		$this->assertSame( WriteCommand::FATAL_EXIT, $ret );
1046
		$cwd = getcwd();
1047
		$this->assertStringContainsString( "Failed to write $cwd/CHANGELOG.md: ", $output->fetch() );
1048
	}
1049
1050
	/**
1051
	 * Test delete changes failure.
1052
	 */
1053
	public function testDeleteChanges_error() {
1054
		$w = TestingAccessWrapper::newFromObject( $this->getCommand( 'write' ) );
1055
1056
		$input  = new ArrayInput( array() );
1057
		$output = new BufferedOutput();
1058
		$ret    = $w->deleteChanges(
1059
			$input,
1060
			$output,
1061
			array(
1062
				'doesnotexist' => 0,
1063
				'.gitkeep'     => 0,
1064
			)
1065
		);
1066
		$this->assertSame( WriteCommand::DELETE_FAILED_EXIT, $ret );
1067
		$out = $output->fetch();
1068
		$this->assertStringContainsString( 'Failed to delete doesnotexist: ', $out );
1069
		$this->assertStringNotContainsString( 'Failed to delete .gitkeep: ', $out );
1070
	}
1071
1072
	/**
1073
	 * Test execute handling of writeChangelog failing.
1074
	 */
1075
	public function testExecute_writeChangelog_fail() {
1076
		$command = $this->getMockBuilder( WriteCommand::class )
1077
			->setMethods( array( 'writeChangelog', 'deleteChanges' ) )
1078
			->getMock();
1079
		$command->setApplication( $this->getCommand( 'write' )->getApplication() );
1080
		$command->method( 'writeChangelog' )->willReturn( WriteCommand::FATAL_EXIT );
1081
		$command->expects( $this->never() )->method( 'deleteChanges' );
1082
1083
		file_put_contents( 'CHANGELOG.md', "# Changelog\n\n## 1.0.0 - 2021-02-23\n\n- Initial release.\n" );
1084
		file_put_contents( 'changelog/a-change', "Significance: patch\nType: fixed\n\nFixed a thing.\n" );
1085
1086
		$tester = new CommandTester( $command );
1087
		$code   = $tester->execute( array() );
1088
		$this->assertSame( WriteCommand::FATAL_EXIT, $code );
1089
	}
1090
1091
}
1092