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

ChangelogEntryTest::testSetChanges_error1()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 6
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 6
loc 6
rs 10
c 0
b 0
f 0
1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
3
 * Tests for the changelog ChangelogEntry 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 Automattic\Jetpack\Changelog\ChangelogEntry;
14
use DateTime;
15
use InvalidArgumentException;
16
use PHPUnit\Framework\TestCase;
17
18
/**
19
 * Tests for the changelog ChangelogEntry class.
20
 *
21
 * @covers \Automattic\Jetpack\Changelog\ChangelogEntry
22
 */
23
class ChangelogEntryTest extends TestCase {
24
	use \Yoast\PHPUnitPolyfills\Polyfills\ExpectException;
25
26
	/**
27
	 * Test general getters.
28
	 */
29
	public function testGetters() {
30
		$then  = new DateTime( 'now' );
31
		$entry = new ChangelogEntry( '1.0' );
32
		$now   = new DateTime( 'now' );
33
		$this->assertSame( '1.0', $entry->getVersion() );
34
		$this->assertGreaterThanOrEqual( $then, $entry->getTimestamp() );
35
		$this->assertLessThanOrEqual( $now, $entry->getTimestamp() );
36
		$this->assertSame( null, $entry->getLink() );
37
		$this->assertSame( '', $entry->getPrologue() );
38
		$this->assertSame( '', $entry->getEpilogue() );
39
40
		$this->assertSame( $entry, $entry->setVersion( '2.0' )->setPrologue( 'Foo' )->setEpilogue( 'Bar' )->setLink( 'https://example.org' ) );
41
		$this->assertSame( 'https://example.org', $entry->getLink() );
42
		$this->assertSame( '2.0', $entry->getVersion() );
43
		$this->assertSame( 'Foo', $entry->getPrologue() );
44
		$this->assertSame( 'Bar', $entry->getEpilogue() );
45
46
		$this->assertSame( $entry, $entry->setVersion( 111 )->setPrologue( 222 )->setEpilogue( 333 )->setLink( '' ) );
47
		$this->assertSame( '111', $entry->getVersion() );
48
		$this->assertSame( null, $entry->getLink() );
49
		$this->assertSame( '222', $entry->getPrologue() );
50
		$this->assertSame( '333', $entry->getEpilogue() );
51
52
		$entry = new ChangelogEntry(
53
			'1.0',
54
			array(
55
				'version'   => '2.0',
56
				'prologue'  => 'XXX',
57
				'timestamp' => '2021-02-12',
58
			)
59
		);
60
		$this->assertSame( '1.0', $entry->getVersion() );
61
		$this->assertSame( 'XXX', $entry->getPrologue() );
62
		$this->assertSame( '2021-02-12 00:00:00', $entry->getTimestamp()->format( 'Y-m-d H:i:s' ) );
63
	}
64
65
	/**
66
	 * Test changes.
67
	 */
68
	public function testChanges() {
69
		$entry   = new ChangelogEntry( '1.0' );
70
		$changes = array(
71
			new ChangeEntry(
72
				array(
73
					'subheading' => 'A',
74
					'content'    => '14',
75
				)
76
			),
77
			new ChangeEntry(
78
				array(
79
					'subheading' => 'B',
80
					'content'    => '2',
81
				)
82
			),
83
			new ChangeEntry(
84
				array(
85
					'subheading' => 'B',
86
					'content'    => '8',
87
				)
88
			),
89
			new ChangeEntry(
90
				array(
91
					'subheading' => 'C',
92
					'content'    => '6',
93
				)
94
			),
95
		);
96
97
		$this->assertSame( array(), $entry->getChanges() );
98
		$this->assertSame( array(), $entry->getChangesBySubheading() );
99
		$this->assertSame( array(), $entry->getChangesBySubheading( 'B' ) );
100
101
		$this->assertSame( $entry, $entry->setChanges( $changes ) );
102
		$this->assertSame( $changes, $entry->getChanges() );
103
		$this->assertSame(
104
			array(
105
				'A' => array( $changes[0] ),
106
				'B' => array( $changes[1], $changes[2] ),
107
				'C' => array( $changes[3] ),
108
			),
109
			$entry->getChangesBySubheading()
110
		);
111
		$this->assertSame( array( $changes[1], $changes[2] ), $entry->getChangesBySubheading( 'B' ) );
112
113
		$c1 = new ChangeEntry(
114
			array(
115
				'subheading' => 'B',
116
				'content'    => '5',
117
			)
118
		);
119
		$c2 = new ChangeEntry(
120
			array(
121
				'subheading' => 'B',
122
				'content'    => '5',
123
			)
124
		);
125
		$c3 = new ChangeEntry(
126
			array(
127
				'subheading' => 'X',
128
				'content'    => '1',
129
			)
130
		);
131
		$this->assertSame( $entry, $entry->insertChange( $c1 ) );
132
		$this->assertSame( $entry, $entry->insertChange( $c2, array( 'ordering' => array( 'content' ) ) ) );
133
		$this->assertSame( $entry, $entry->insertChange( $c3 ) );
134
		$this->assertSame( array( $c2, $changes[0], $changes[1], $c1, $changes[2], $changes[3], $c3 ), $entry->getChanges() );
135
		$this->assertSame(
136
			array(
137
				'B' => array( $c2, $changes[1], $c1, $changes[2] ),
138
				'A' => array( $changes[0] ),
139
				'C' => array( $changes[3] ),
140
				'X' => array( $c3 ),
141
			),
142
			$entry->getChangesBySubheading()
143
		);
144
		$this->assertSame( array( $c2, $changes[1], $c1, $changes[2] ), $entry->getChangesBySubheading( 'B' ) );
145
146
		$entry = new ChangelogEntry( '1.0' );
147
		$this->assertSame( $entry, $entry->appendChange( $c1 )->appendChange( $c2 )->appendChange( $c3 ) );
148
		$this->assertSame( array( $c1, $c2, $c3 ), $entry->getChanges() );
149
	}
150
151
	/**
152
	 * Test constructor error.
153
	 */
154
	public function testConstructor_error() {
155
		$this->expectException( InvalidArgumentException::class );
156
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangelogEntry::__construct: Unrecognized data item "foo"' );
157
		new ChangelogEntry( '1.0', array( 'foo' => 'bar' ) );
158
	}
159
160
	/**
161
	 * Test setVersion error.
162
	 */
163
	public function testSetVersion_error() {
164
		$entry = new ChangelogEntry( '1.0' );
165
		$this->expectException( InvalidArgumentException::class );
166
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangelogEntry::setVersion: Version may not be empty' );
167
		$entry->setVersion( '' );
168
	}
169
170
	/**
171
	 * Test setLink error.
172
	 */
173
	public function testSetLink_error() {
174
		$entry = new ChangelogEntry( '1.0' );
175
		$this->expectException( InvalidArgumentException::class );
176
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangelogEntry::setLink: Invalid URL' );
177
		$entry->setLink( '/bogus' );
178
	}
179
180
	/**
181
	 * Test setTimestamp error.
182
	 */
183
	public function testSetTimestamp_error() {
184
		$entry = new ChangelogEntry( '1.0' );
185
		$this->expectException( InvalidArgumentException::class );
186
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangelogEntry::setTimestamp: Invalid timestamp' );
187
		$entry->setTimestamp( 'bogus' );
188
	}
189
190
	/**
191
	 * Test setChanges error.
192
	 */
193 View Code Duplication
	public function testSetChanges_error1() {
194
		$entry = new ChangelogEntry( '1.0' );
195
		$this->expectException( InvalidArgumentException::class );
196
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangelogEntry::setChanges: Expected a ChangeEntry, got NULL at index 0' );
197
		$entry->setChanges( array( null ) );
0 ignored issues
show
Documentation introduced by
array(null) is of type array<integer,null,{"0":"null"}>, but the function expects a array<integer,object<Aut...Changelog\ChangeEntry>>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
198
	}
199
200
	/**
201
	 * Test setChanges error.
202
	 */
203 View Code Duplication
	public function testSetChanges_error2() {
204
		$entry = new ChangelogEntry( '1.0' );
205
		$this->expectException( InvalidArgumentException::class );
206
		$this->expectExceptionMessage( 'Automattic\\Jetpack\\Changelog\\ChangelogEntry::setChanges: Expected a ChangeEntry, got Automattic\\Jetpack\\Changelog\\ChangelogEntry at index 0' );
207
		$entry->setChanges( array( $entry ) );
0 ignored issues
show
Documentation introduced by
array($entry) is of type array<integer,object<Aut...log\\ChangelogEntry>"}>, but the function expects a array<integer,object<Aut...Changelog\ChangeEntry>>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
208
	}
209
210
	/**
211
	 * Test JSON serialization.
212
	 *
213
	 * @dataProvider provideJson
214
	 * @param string                $json JSON data.
215
	 * @param ChangelogEntry|string $entry Changelog entry, or error message if decoding should fail.
216
	 */
217 View Code Duplication
	public function testJson( $json, $entry ) {
218
		if ( is_string( $entry ) ) {
219
			$this->expectException( InvalidArgumentException::class );
220
			$this->expectExceptionMessage( $entry );
221
			ChangelogEntry::jsonUnserialize( json_decode( $json ) );
222
		} else {
223
			$this->assertSame( $json, json_encode( $entry ) );
224
			$this->assertEquals( $entry, ChangelogEntry::jsonUnserialize( json_decode( $json ) ) );
225
		}
226
	}
227
228
	/**
229
	 * Data provider for testJson.
230
	 */
231
	public function provideJson() {
232
		return array(
233
			'Basic serialization'              => array(
234
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangelogEntry","version":"1.0","link":null,"timestamp":"2021-02-18T00:00:00+00:00","prologue":"","epilogue":"","changes":[]}',
235
				( new ChangelogEntry( '1.0' ) )->setTimestamp( '2021-02-18' ),
236
			),
237
			'Serialization with data'          => array(
238
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangelogEntry","version":"1.0","link":"https:\\/\\/example.org","timestamp":"2021-02-18T12:07:16-05:00","prologue":"Foo","epilogue":"Bar","changes":[{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangeEntry","significance":null,"timestamp":"2021-02-17T00:00:00+00:00","subheading":"","author":"","content":""},{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangeEntry","significance":null,"timestamp":"2021-02-18T00:00:00+00:00","subheading":"","author":"","content":""}]}',
239
				( new ChangelogEntry( '1.0' ) )->setTimestamp( '2021-02-18T12:07:16-05:00' )->setPrologue( 'Foo' )->setEpilogue( 'Bar' )->setLink( 'https://example.org' )->setChanges(
240
					array(
241
						new ChangeEntry( array( 'timestamp' => '2021-02-17' ) ),
242
						new ChangeEntry( array( 'timestamp' => '2021-02-18' ) ),
243
					)
244
				),
245
			),
246
			'Bad unserialization, no class'    => array(
247
				'{"version":"1.0","link":null,"timestamp":"2021-02-18T00:00:00+00:00","prologue":"","epilogue":"","changes":[]}',
248
				'Invalid data',
249
			),
250
			'Bad unserialization, no version'  => array(
251
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\ChangelogEntry","link":null,"timestamp":"2021-02-18T00:00:00+00:00","prologue":"","epilogue":"","changes":[]}',
252
				'Invalid data',
253
			),
254
			'Bad unserialization, wrong class' => array(
255
				'{"__class__":"Automattic\\\\Jetpack\\\\Changelog\\\\Changelog","version":"1.0","prologue":"","epilogue":"","entries":[]}',
256
				'Cannot instantiate Automattic\\Jetpack\\Changelog\\Changelog via Automattic\\Jetpack\\Changelog\\ChangelogEntry::jsonUnserialize',
257
			),
258
		);
259
	}
260
261
}
262