Completed
Push — add/changelog-tooling ( fa9ac3...7f5585 )
by
unknown
517:08 queued 507:24
created

ChangeEntryTest   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 419
Duplicated Lines 2.39 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
dl 10
loc 419
rs 10
c 0
b 0
f 0
wmc 14
lcom 0
cbo 1

9 Methods

Rating   Name   Duplication   Size   Complexity  
A testGetters() 0 38 1
A testConstructor_error() 0 5 1
A testSetTimestamp_error() 0 6 1
A testSetSignificance_error() 0 6 1
A testCompare() 0 11 5
B provideCompare() 0 262 1
A testCompare_error() 0 11 1
A testJson() 10 10 2
A provideJson() 0 20 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
3
 * Tests for the changelog ChangeEntry class.
4
 *
5
 * @package automattic/jetpack-changelogger
6
 */
7
8
// phpcs:disable WordPress.WP.AlternativeFunctions
9
10
namespace Automattic\Jetpack\Changelog\Tests;
11
12
use Automattic\Jetpack\Changelog\ChangeEntry;
13
use DateTime;
14
use InvalidArgumentException;
15
use PHPUnit\Framework\TestCase;
16
17
/**
18
 * Tests for the changelog ChangeEntry class.
19
 *
20
 * @covers \Automattic\Jetpack\Changelog\ChangeEntry
21
 */
22
class ChangeEntryTest extends TestCase {
23
	use \Yoast\PHPUnitPolyfills\Polyfills\ExpectException;
24
25
	/**
26
	 * Test general getters.
27
	 */
28
	public function testGetters() {
29
		$then   = new DateTime( 'now' );
30
		$change = new ChangeEntry();
31
		$now    = new DateTime( 'now' );
32
		$this->assertGreaterThanOrEqual( $then, $change->getTimestamp() );
33
		$this->assertLessThanOrEqual( $now, $change->getTimestamp() );
34
		$this->assertSame( null, $change->getSignificance() );
35
		$this->assertSame( '', $change->getSubheading() );
36
		$this->assertSame( '', $change->getAuthor() );
37
		$this->assertSame( '', $change->getContent() );
38
39
		$this->assertSame( $change, $change->setSignificance( 'patch' )->setAuthor( 'me!' )->setSubheading( 'Foo' )->setContent( 'Bar' ) );
40
		$this->assertSame( 'patch', $change->getSignificance() );
41
		$this->assertSame( 'Foo', $change->getSubheading() );
42
		$this->assertSame( 'me!', $change->getAuthor() );
43
		$this->assertSame( 'Bar', $change->getContent() );
44
45
		$this->assertSame( $change, $change->setSignificance( null )->setAuthor( 111 )->setSubheading( 222 )->setContent( 333 ) );
46
		$this->assertSame( null, $change->getSignificance() );
47
		$this->assertSame( '111', $change->getAuthor() );
48
		$this->assertSame( '222', $change->getSubheading() );
49
		$this->assertSame( '333', $change->getContent() );
50
51
		$change = new ChangeEntry(
52
			array(
53
				'significance' => 'minor',
54
				'author'       => 'that guy',
55
				'subheading'   => 'Things',
56
				'content'      => 'Stuff',
57
				'timestamp'    => '2021-02-16',
58
			)
59
		);
60
		$this->assertSame( 'minor', $change->getSignificance() );
61
		$this->assertSame( 'Things', $change->getSubheading() );
62
		$this->assertSame( 'that guy', $change->getAuthor() );
63
		$this->assertSame( 'Stuff', $change->getContent() );
64
		$this->assertSame( '2021-02-16 00:00:00', $change->getTimestamp()->format( 'Y-m-d H:i:s' ) );
65
	}
66
67
	/**
68
	 * Test constructor error.
69
	 */
70
	public function testConstructor_error() {
71
		$this->expectException( InvalidArgumentException::class );
72
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangeEntry::__construct: Unrecognized data item "foo"' );
73
		new ChangeEntry( array( 'foo' => 'bar' ) );
74
	}
75
76
	/**
77
	 * Test setTimestamp error.
78
	 */
79
	public function testSetTimestamp_error() {
80
		$change = new ChangeEntry();
81
		$this->expectException( InvalidArgumentException::class );
82
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangeEntry::setTimestamp: Invalid timestamp' );
83
		$change->setTimestamp( 'bogus' );
84
	}
85
86
	/**
87
	 * Test setSignificance error.
88
	 */
89
	public function testSetSignificance_error() {
90
		$change = new ChangeEntry();
91
		$this->expectException( InvalidArgumentException::class );
92
		$this->expectExceptionMessage( "Automattic\\Jetpack\\Changelog\\ChangeEntry::setSignificance: Significance must be 'patch', 'minor', or 'major' (or null)" );
93
		$change->setSignificance( 'bogus' );
94
	}
95
96
	/**
97
	 * Test compare.
98
	 *
99
	 * @dataProvider provideCompare
100
	 * @param ChangeEntry $a First change entry.
101
	 * @param ChangeEntry $b Second change entry.
102
	 * @param array       $config Compare config.
103
	 * @param int         $expect Expected value.
104
	 */
105
	public function testCompare( ChangeEntry $a, ChangeEntry $b, array $config, $expect ) {
106
		$ret = ChangeEntry::compare( $a, $b, $config );
107
		// We only care about the sign of the return value.
108
		$ret = $ret < 0 ? -1 : ( $ret > 0 ? 1 : 0 );
109
		$this->assertSame( $expect, $ret );
110
111
		$ret = ChangeEntry::compare( $b, $a, $config );
112
		// We only care about the sign of the return value.
113
		$ret = $ret < 0 ? -1 : ( $ret > 0 ? 1 : 0 );
114
		$this->assertSame( -$expect, $ret );
115
	}
116
117
	/**
118
	 * Data provider for testCompare.
119
	 */
120
	public function provideCompare() {
121
		return array(
122
			'Default config, equal'                        => array(
123
				new ChangeEntry(
124
					array(
125
						'significance' => 'major',
126
						'subheading'   => 'Head',
127
						'author'       => 'XXX',
128
						'timestamp'    => '2020-01-01',
129
						'content'      => 'A change.',
130
					)
131
				),
132
				new ChangeEntry(
133
					array(
134
						'significance' => 'patch',
135
						'subheading'   => 'Head',
136
						'author'       => 'YYY',
137
						'timestamp'    => '2020-02-02',
138
						'content'      => 'A change.',
139
					)
140
				),
141
				array(),
142
				0,
143
			),
144
			'Default config, equal but for case'           => array(
145
				new ChangeEntry(
146
					array(
147
						'significance' => 'major',
148
						'subheading'   => 'Head',
149
						'author'       => 'Xxx',
150
						'timestamp'    => '2020-01-01',
151
						'content'      => 'A change.',
152
					)
153
				),
154
				new ChangeEntry(
155
					array(
156
						'significance' => 'patch',
157
						'subheading'   => 'hEAD',
158
						'author'       => 'xXX',
159
						'timestamp'    => '2020-02-02',
160
						'content'      => 'a CHANGE.',
161
					)
162
				),
163
				array(
164
					'ordering' => array( 'subheading', 'author', 'content' ),
165
				),
166
				0,
167
			),
168
			'Default config, subheading before content'    => array(
169
				new ChangeEntry(
170
					array(
171
						'significance' => 'major',
172
						'subheading'   => 'A',
173
						'author'       => 'XXX',
174
						'timestamp'    => '2020-01-01',
175
						'content'      => 'B',
176
					)
177
				),
178
				new ChangeEntry(
179
					array(
180
						'significance' => 'patch',
181
						'subheading'   => 'B',
182
						'author'       => 'YYY',
183
						'timestamp'    => '2020-01-01',
184
						'content'      => 'A',
185
					)
186
				),
187
				array(),
188
				-1,
189
			),
190
			'Default config, content differs'              => array(
191
				new ChangeEntry(
192
					array(
193
						'significance' => 'major',
194
						'subheading'   => 'Head',
195
						'author'       => 'XXX',
196
						'timestamp'    => '2020-01-01',
197
						'content'      => 'B',
198
					)
199
				),
200
				new ChangeEntry(
201
					array(
202
						'significance' => 'patch',
203
						'subheading'   => 'Head',
204
						'author'       => 'YYY',
205
						'timestamp'    => '2020-02-02',
206
						'content'      => 'A',
207
					)
208
				),
209
				array(),
210
				1,
211
			),
212
			'Add timestamp to config'                      => array(
213
				new ChangeEntry(
214
					array(
215
						'significance' => 'major',
216
						'subheading'   => 'Head',
217
						'author'       => 'XXX',
218
						'timestamp'    => '2020-01-01',
219
						'content'      => 'B',
220
					)
221
				),
222
				new ChangeEntry(
223
					array(
224
						'significance' => 'patch',
225
						'subheading'   => 'Head',
226
						'author'       => 'YYY',
227
						'timestamp'    => '2020-02-02',
228
						'content'      => 'A',
229
					)
230
				),
231
				array(
232
					'ordering' => array( 'subheading', 'timestamp', 'content' ),
233
				),
234
				-1,
235
			),
236
			'Add significance to config'                   => array(
237
				new ChangeEntry(
238
					array(
239
						'significance' => 'major',
240
						'subheading'   => 'Head',
241
						'author'       => 'XXX',
242
						'timestamp'    => '2020-01-01',
243
						'content'      => 'B',
244
					)
245
				),
246
				new ChangeEntry(
247
					array(
248
						'significance' => 'patch',
249
						'subheading'   => 'Head',
250
						'author'       => 'YYY',
251
						'timestamp'    => '2020-02-02',
252
						'content'      => 'A',
253
					)
254
				),
255
				array(
256
					'ordering' => array( 'subheading', 'significance', 'content' ),
257
				),
258
				-1,
259
			),
260
			'Use knownSubheadings'                         => array(
261
				new ChangeEntry(
262
					array(
263
						'significance' => 'major',
264
						'subheading'   => 'AAA',
265
						'author'       => 'XXX',
266
						'timestamp'    => '2020-01-01',
267
						'content'      => 'Content',
268
					)
269
				),
270
				new ChangeEntry(
271
					array(
272
						'significance' => 'major',
273
						'subheading'   => 'BBB',
274
						'author'       => 'XXX',
275
						'timestamp'    => '2020-01-01',
276
						'content'      => 'Content',
277
					)
278
				),
279
				array(
280
					'knownSubheadings' => array( 'BBB', 'AAA' ),
281
				),
282
				1,
283
			),
284
			'Use knownSubheadings, case mismatch'          => array(
285
				new ChangeEntry(
286
					array(
287
						'significance' => 'major',
288
						'subheading'   => 'aAa',
289
						'author'       => 'XXX',
290
						'timestamp'    => '2020-01-01',
291
						'content'      => 'Content',
292
					)
293
				),
294
				new ChangeEntry(
295
					array(
296
						'significance' => 'major',
297
						'subheading'   => 'AaA',
298
						'author'       => 'XXX',
299
						'timestamp'    => '2020-01-01',
300
						'content'      => 'Content',
301
					)
302
				),
303
				array(
304
					'knownSubheadings' => array( 'BBB', 'AAA' ),
305
				),
306
				0,
307
			),
308
			'Use knownSubheadings, one subheading unknown' => array(
309
				new ChangeEntry(
310
					array(
311
						'significance' => 'major',
312
						'subheading'   => 'AAA?',
313
						'author'       => 'XXX',
314
						'timestamp'    => '2020-01-01',
315
						'content'      => 'Content',
316
					)
317
				),
318
				new ChangeEntry(
319
					array(
320
						'significance' => 'major',
321
						'subheading'   => 'BBB',
322
						'author'       => 'XXX',
323
						'timestamp'    => '2020-01-01',
324
						'content'      => 'Content',
325
					)
326
				),
327
				array(
328
					'knownSubheadings' => array( 'AAA', 'BBB' ),
329
				),
330
				1,
331
			),
332
			'Use knownSubheadings, both subheadings unknown' => array(
333
				new ChangeEntry(
334
					array(
335
						'significance' => 'major',
336
						'subheading'   => 'AAA?',
337
						'author'       => 'XXX',
338
						'timestamp'    => '2020-01-01',
339
						'content'      => 'Content',
340
					)
341
				),
342
				new ChangeEntry(
343
					array(
344
						'significance' => 'major',
345
						'subheading'   => 'BBB?',
346
						'author'       => 'XXX',
347
						'timestamp'    => '2020-01-01',
348
						'content'      => 'Content',
349
					)
350
				),
351
				array(
352
					'knownSubheadings' => array( 'BBB', 'AAA' ),
353
				),
354
				-1,
355
			),
356
			'Use knownSubheadings, empty subheading cannot be known' => array(
357
				new ChangeEntry(
358
					array(
359
						'significance' => 'major',
360
						'subheading'   => '',
361
						'author'       => 'XXX',
362
						'timestamp'    => '2020-01-01',
363
						'content'      => 'Content',
364
					)
365
				),
366
				new ChangeEntry(
367
					array(
368
						'significance' => 'major',
369
						'subheading'   => 'BBB',
370
						'author'       => 'XXX',
371
						'timestamp'    => '2020-01-01',
372
						'content'      => 'Content',
373
					)
374
				),
375
				array(
376
					'knownSubheadings' => array( 'BBB', 'AAA', '' ),
377
				),
378
				-1,
379
			),
380
		);
381
	}
382
383
	/**
384
	 * Test compare error.
385
	 */
386
	public function testCompare_error() {
387
		$this->expectException( InvalidArgumentException::class );
388
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangeEntry::compare: Invalid field in ordering' );
389
		ChangeEntry::compare(
390
			new ChangeEntry(),
391
			new ChangeEntry(),
392
			array(
393
				'ordering' => array( 'subheading', 'bogus', 'content' ),
394
			)
395
		);
396
	}
397
398
	/**
399
	 * Test JSON serialization.
400
	 *
401
	 * @dataProvider provideJson
402
	 * @param string             $json JSON data.
403
	 * @param ChangeEntry|string $change Change entry, or error message if decoding should fail.
404
	 */
405 View Code Duplication
	public function testJson( $json, $change ) {
406
		if ( is_string( $change ) ) {
407
			$this->expectException( InvalidArgumentException::class );
408
			$this->expectExceptionMessage( $change );
409
			ChangeEntry::jsonUnserialize( json_decode( $json ) );
410
		} else {
411
			$this->assertSame( $json, json_encode( $change ) );
412
			$this->assertEquals( $change, ChangeEntry::jsonUnserialize( json_decode( $json ) ) );
413
		}
414
	}
415
416
	/**
417
	 * Data provider for testJson.
418
	 */
419
	public function provideJson() {
420
		return array(
421
			'Basic serialization'              => array(
422
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangeEntry","significance":null,"timestamp":"2021-02-18T00:00:00+00:00","subheading":"","author":"","content":""}',
423
				( new ChangeEntry() )->setTimestamp( '2021-02-18' ),
424
			),
425
			'Serialization with data'          => array(
426
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangeEntry","significance":"minor","timestamp":"2021-02-18T12:07:16-05:00","subheading":"Heading","author":"Me!","content":"A change."}',
427
				( new ChangeEntry() )->setTimestamp( '2021-02-18T12:07:16-05:00' )->setSignificance( 'minor' )->setSubheading( 'Heading' )->setAuthor( 'Me!' )->setContent( 'A change.' ),
428
			),
429
			'Bad unserialization, no class'    => array(
430
				'{"significance":"minor","timestamp":"2021-02-18T12:07:16-05:00","subheading":"Heading","author":"Me!","content":"A change."}',
431
				'Invalid data',
432
			),
433
			'Bad unserialization, wrong class' => array(
434
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\Changelog","prologue":"","epilogue":"","entries":[]}',
435
				'Cannot instantiate Automattic\\Jetpack\\Changelog\\Changelog via Automattic\\Jetpack\\Changelog\\ChangeEntry::jsonUnserialize',
436
			),
437
		);
438
	}
439
440
}
441