Completed
Push — update/tracking-assets ( 294fcb...ba0029 )
by
unknown
31:15 queued 15:24
created

WP_Test_Jetpack::test_get_content_width()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
4
use Automattic\Jetpack\Constants;
5
use Automattic\Jetpack\Assets;
6
use Automattic\Jetpack\Partner;
7
use Automattic\Jetpack\Status;
8
9
// Extend with a public constructor so that can be mocked in tests
10
class MockJetpack extends Jetpack {
11
12
	/**
13
	 * Holds the singleton instance of this class
14
	 *
15
	 * @var MockJetpack
16
	 */
17
	public static $instance = false;
18
19
	/**
20
	 * We are redefining this to overcome the lack of late static binding in the parent Jetpack class.
21
	 *
22
	 * @static
23
	 */
24
	public static function init() {
25
		if ( ! self::$instance ) {
26
			self::$instance = new self();
27
		}
28
29
		return self::$instance;
30
	}
31
32
	public function __construct() {
33
		$this->connection_manager = new Connection_Manager();
34
	}
35
}
36
37
class MockJetpack_XMLRPC_Server extends Jetpack_XMLRPC_Server {
38
	private $mockLoginUser = false;
39
40
	public function __construct( $user ) {
41
		$this->mockLoginUser = $user;
42
	}
43
44
	public function login() {
45
		return $this->mockLoginUser;
46
	}
47
}
48
49
class WP_Test_Jetpack extends WP_UnitTestCase {
50
	static $admin_id = 0;
51
52
	static $activated_modules = array();
53
	static $deactivated_modules = array();
54
55
	public static function wpSetupBeforeClass() {
56
		self::$admin_id = self::factory()->user->create( array(
57
			'role' => 'administrator',
58
		) );
59
	}
60
61
	public function tearDown() {
62
		parent::tearDown();
63
		Constants::clear_constants();
64
	}
65
66
	/**
67
	 * Make sure that MockJetpack creates separate instances of `Jetpack` and `Automattic\Jetpack\Connection\Manager`.
68
	 */
69
	public function test_static_binding() {
70
		$this->assertNotEquals( spl_object_hash( MockJetpack::init() ), spl_object_hash( Jetpack::init() ) );
71
		$this->assertNotEquals( spl_object_hash( MockJetpack::connection() ), spl_object_hash( Jetpack::connection() ) );
72
	}
73
74
	/**
75
	 * @author blobaugh
76
	 * @covers Jetpack::init
77
	 * @since 2.3.3
78
	 */
79
	public function test_init() {
80
		$this->assertInstanceOf( 'Jetpack', Jetpack::init() );
81
	}
82
83
	/**
84
	 * @author enkrates
85
	 * @covers Jetpack::sort_modules
86
	 * @since 3.2
87
	 */
88
	public function test_sort_modules_with_equal_sort_values() {
89
90
		$first_file  = array( 'sort' => 5 );
91
		$second_file = array( 'sort' => 5 );
92
93
		$sort_value = Jetpack::sort_modules( $first_file, $second_file );
94
95
		$this->assertEquals( 0, $sort_value );
96
	}
97
98
	/**
99
	 * @author enkrates
100
	 * @covers Jetpack::sort_modules
101
	 * @since 3.2
102
	 */
103
	public function test_sort_modules_with_different_sort_values() {
104
105
		$first_file  = array( 'sort' => 10 );
106
		$second_file = array( 'sort' => 5 );
107
108
		$sort_value = Jetpack::sort_modules( $first_file, $second_file );
109
		$reversed_sort_value = Jetpack::sort_modules( $second_file, $first_file );
110
111
		$this->assertEquals( 1, $sort_value );
112
		$this->assertEquals( -1, $reversed_sort_value );
113
	}
114
115
	/**
116
	 * @author georgestephanis
117
	 * @covers Jetpack::absolutize_css_urls
118
	 */
119
	public function test_absolutize_css_urls_properly_handles_use_cases() {
120
121
		$css = <<<CSS
122
.test-it {
123
	background: url(same-dir.png);
124
	background: url('same-dir.png');
125
	background: url("same-dir.png");
126
	background: url( same-dir.png );
127
	background: url( 'same-dir.png' );
128
	background: url( "same-dir.png" );
129
	background: url(		same-dir.png		);
130
	background: url(		'same-dir.png'	);
131
	background: url(		"same-dir.png"	);
132
	background: url(./same-dir.png);
133
	background: url(down/down-dir.png);
134
	background: url(../up-dir.png);
135
	background: url(../../up-2-dirs.png);
136
	background: url(/at-root.png);
137
	background: url(//other-domain.com/root.png);
138
	background: url(https://other-domain.com/root.png);
139
	background: url(data:image/gif;base64,eh129ehiuehjdhsa==);
140
}
141
CSS;
142
143
		$expected = <<<EXPECTED
144
.test-it {
145
	background: url("http://example.com/dir1/dir2/same-dir.png");
146
	background: url("http://example.com/dir1/dir2/same-dir.png");
147
	background: url("http://example.com/dir1/dir2/same-dir.png");
148
	background: url("http://example.com/dir1/dir2/same-dir.png");
149
	background: url("http://example.com/dir1/dir2/same-dir.png");
150
	background: url("http://example.com/dir1/dir2/same-dir.png");
151
	background: url("http://example.com/dir1/dir2/same-dir.png");
152
	background: url("http://example.com/dir1/dir2/same-dir.png");
153
	background: url("http://example.com/dir1/dir2/same-dir.png");
154
	background: url("http://example.com/dir1/dir2/./same-dir.png");
155
	background: url("http://example.com/dir1/dir2/down/down-dir.png");
156
	background: url("http://example.com/dir1/dir2/../up-dir.png");
157
	background: url("http://example.com/dir1/dir2/../../up-2-dirs.png");
158
	background: url("http://example.com/at-root.png");
159
	background: url(//other-domain.com/root.png);
160
	background: url(https://other-domain.com/root.png);
161
	background: url(data:image/gif;base64,eh129ehiuehjdhsa==);
162
}
163
EXPECTED;
164
165
		$result = Jetpack::absolutize_css_urls( $css, 'http://example.com/dir1/dir2/style.css' );
166
		$this->assertEquals( $expected, $result );
167
168
	}
169
170
	/*
171
	 * @author tonykova
172
	 * @covers Jetpack::implode_frontend_css
173
	 */
174
	public function test_implode_frontend_css_enqueues_bundle_file_handle() {
175
		global $wp_styles;
176
		$wp_styles = new WP_styles();
177
178
		add_filter( 'jetpack_implode_frontend_css', '__return_true' );
179
180
		if ( ! file_exists( plugins_url( 'jetpack-carousel.css', __FILE__ ) ) ) {
181
			$this->markTestSkipped( 'Required CSS file not found.' );
182
		}
183
184
		// Enqueue some script on the $to_dequeue list
185
		$style_handle = 'jetpack-carousel';
186
		wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ) );
187
188
		Jetpack::init()->implode_frontend_css( true );
189
190
		$seen_bundle = false;
191
		foreach ( $wp_styles->registered as $handle => $handle_obj ) {
192
			if ( $style_handle === $handle ) {
193
				$expected = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? "<!-- `{$style_handle}` is included in the concatenated jetpack.css -->\r\n" : '';
194
				$this->assertEquals( $expected, get_echo( array( $wp_styles, 'do_item' ), array( $handle ) ) );
195
			} elseif ( 'jetpack_css' === $handle ) {
196
				$seen_bundle = true;
197
			}
198
		}
199
200
		$this->assertTrue( $seen_bundle );
201
	}
202
203
	/**
204
	 * @author tonykova
205
	 * @covers Jetpack::implode_frontend_css
206
	 * @since 3.2.0
207
	 */
208
	public function test_implode_frontend_css_does_not_enqueue_bundle_when_disabled_through_filter() {
209
		global $wp_styles;
210
		$wp_styles = new WP_styles();
211
212
		add_filter( 'jetpack_implode_frontend_css', '__return_false' );
213
214
		// Enqueue some script on the $to_dequeue list
215
		$style_handle = 'jetpack-carousel';
0 ignored issues
show
Unused Code introduced by
$style_handle is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
216
		wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ) );
217
218
		Jetpack::init()->implode_frontend_css();
219
220
		$seen_orig = false;
221
		foreach ( $wp_styles->registered as $handle => $handle_obj ) {
222
			$this->assertNotEquals( 'jetpack_css', $handle );
223
			if ( 'jetpack-carousel' === $handle ) {
224
				$seen_orig = true;
225
			}
226
		}
227
228
		$this->assertTrue( $seen_orig );
229
	}
230
231 View Code Duplication
	public function test_activating_deactivating_modules_fires_actions() {
232
		self::reset_tracking_of_module_activation();
233
234
		add_action( 'jetpack_activate_module', array( __CLASS__, 'track_activated_modules' ) );
235
		add_action( 'jetpack_deactivate_module', array( __CLASS__, 'track_deactivated_modules' ) );
236
237
		Jetpack::update_active_modules( array( 'stats' ) );
238
		Jetpack::update_active_modules( array( 'stats' ) );
239
		Jetpack::update_active_modules( array( 'json-api' ) );
240
		Jetpack::update_active_modules( array( 'json-api' ) );
241
242
		$this->assertEquals( self::$activated_modules, array( 'stats', 'json-api' ) );
243
		$this->assertEquals(  self::$deactivated_modules, array( 'stats' ) );
244
245
		remove_action( 'jetpack_activate_module', array( __CLASS__, 'track_activated_modules' ) );
246
		remove_action( 'jetpack_deactivate_module', array( __CLASS__, 'track_deactivated_modules' ) );
247
	}
248
249 View Code Duplication
	public function test_activating_deactivating_modules_fires_specific_actions() {
250
		self::reset_tracking_of_module_activation();
251
		add_action( 'jetpack_activate_module_stats', array( __CLASS__, 'track_activated_modules' ) );
252
		add_action( 'jetpack_deactivate_module_stats', array( __CLASS__, 'track_deactivated_modules' ) );
253
254
		Jetpack::update_active_modules( array( 'stats' ) );
255
		Jetpack::update_active_modules( array( 'stats' ) );
256
		Jetpack::update_active_modules( array( 'json-api' ) );
257
		Jetpack::update_active_modules( array( 'json-api' ) );
258
259
		$this->assertEquals( self::$activated_modules, array( 'stats' ) );
260
		$this->assertEquals(  self::$deactivated_modules, array( 'stats' ) );
261
262
		remove_action( 'jetpack_activate_module_stats', array( __CLASS__, 'track_activated_modules' ) );
263
		remove_action( 'jetpack_deactivate_module_stats', array( __CLASS__, 'track_deactivated_modules' ) );
264
	}
265
266
	public function test_active_modules_filter_restores_state() {
267
		self::reset_tracking_of_module_activation();
268
269
		add_action( 'jetpack_activate_module', array( __CLASS__, 'track_activated_modules' ) );
270
		add_action( 'jetpack_deactivate_module', array( __CLASS__, 'track_deactivated_modules' ) );
271
		add_filter( 'jetpack_active_modules', array( __CLASS__, 'e2e_test_filter' ) );
272
273
		Jetpack::update_active_modules( array( 'monitor' ) );
274
		$this->assertEquals( self::$activated_modules, array( 'monitor' ) );
275
		$this->assertEquals(  self::$deactivated_modules, array() );
276
277
		// Simce we override the 'monitor' module, verify it does not appear in get_active_modules().
278
		$active_modules = Jetpack::get_active_modules();
279
		$this->assertEquals(  $active_modules, array() );
280
281
		// Verify that activating a new module does not deactivate 'monitor' module.
282
		Jetpack::update_active_modules( array( 'stats' ) );
283
		$this->assertEquals( self::$activated_modules, array( 'monitor', 'stats') );
284
		$this->assertEquals(  self::$deactivated_modules, array() );
285
286
		remove_filter( 'jetpack_active_modules', array( __CLASS__, 'e2e_test_filter' ) );
287
288
		// With the module override filter removed, verify that monitor module appears in get_active_modules().
289
		$active_modules = Jetpack::get_active_modules();
290
		$this->assertEquals(  $active_modules, array( 'monitor', 'stats' ) );
291
	}
292
293
	 // This filter overrides the 'monitor' module.
294
	public static function e2e_test_filter( $modules ) {
295
		$disabled_modules = array( 'monitor' );
296
297
		foreach ( $disabled_modules as $module_slug ) {
298
			$found = array_search( $module_slug, $modules );
299
			if ( false !== $found ) {
300
				unset( $modules[ $found ] );
301
			}
302
		}
303
304
		return $modules;
305
	}
306
307
	public function test_get_other_linked_admins_one_admin_returns_false() {
308
		delete_transient( 'jetpack_other_linked_admins' );
309
		$other_admins = Jetpack::get_other_linked_admins();
310
		$this->assertFalse( $other_admins );
311
		$this->assertEquals( 0, get_transient( 'jetpack_other_linked_admins' ) );
312
	}
313
314
	public function test_get_other_linked_admins_more_than_one_not_false() {
315
		delete_transient( 'jetpack_other_linked_admins' );
316
		$master_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
317
		$connected_admin = $this->factory->user->create( array( 'role' => 'administrator' ) );
318
319
		Jetpack_Options::update_option( 'master_user', $master_user );
320
		Jetpack_Options::update_option( 'user_tokens', array(
321
			$connected_admin => 'apple.a.' . $connected_admin,
322
			$master_user     => 'kiwi.a.' . $master_user
323
		) );
324
325
		$other_admins = Jetpack::get_other_linked_admins();
326
		$this->assertInternalType( 'int', $other_admins );
327
		$this->assertInternalType( 'int', get_transient( 'jetpack_other_linked_admins' ) );
328
	}
329
330 View Code Duplication
	public function test_promoting_admin_clears_other_linked_admins_transient() {
331
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
332
		$editor_user = $this->factory->user->create( array( 'role' => 'editor' ) );
333
		wp_update_user( array( 'ID' => $editor_user, 'role' => 'administrator' ) );
334
335
		$this->assertFalse( get_transient( 'jetpack_other_linked_admins' ) );
336
	}
337
338 View Code Duplication
	public function test_demoting_admin_clear_other_linked_admins_transiet() {
339
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
340
		$admin_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
341
		wp_update_user( array( 'ID' => $admin_user, 'role' => 'editor' ) );
342
343
		$this->assertFalse( get_transient( 'jetpack_other_linked_admins' ) );
344
	}
345
346 View Code Duplication
	public function test_null_old_roles_clears_linked_admins_transient() {
347
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
348
		$admin_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
349
		wp_update_user( array( 'ID' => $admin_user, 'role' => 'editor' ) );
350
351
		/** This action is documented in wp-includes/class-wp-user.php */
352
		do_action( 'set_user_role', $admin_user, 'contributor' );
353
354
		$this->assertFalse( get_transient( 'jetpack_other_linked_admins' ) );
355
	}
356
357
	function test_changing_non_admin_roles_does_not_clear_other_linked_admins_transient() {
358
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
359
		$user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
360
361
		foreach ( array( 'contributor', 'author', 'editor' ) as $role ) {
362
			wp_update_user( array( 'ID' => $user_id, 'role' => $role) );
363
		}
364
365
		$this->assertEquals( 2, get_transient( 'jetpack_other_linked_admins' ) );
366
	}
367
368
	function test_other_linked_admins_transient_set_to_zero_returns_false() {
369
		set_transient( 'jetpack_other_linked_admins', 0, HOUR_IN_SECONDS );
370
		$this->assertFalse( Jetpack::get_other_linked_admins() );
371
	}
372
373
	function test_idc_optin_default() {
374
		if ( is_multisite() ) {
375
			$this->assertFalse( Jetpack::sync_idc_optin() );
376
		} else {
377
			$this->assertTrue( Jetpack::sync_idc_optin() );
378
		}
379
	}
380
381
	function test_idc_optin_filter_overrides_development_version() {
382
		add_filter( 'jetpack_development_version', '__return_true' );
383
		add_filter( 'jetpack_sync_idc_optin', '__return_false' );
384
		$this->assertFalse( Jetpack::sync_idc_optin() );
385
		remove_filter( 'jetpack_development_version', '__return_true' );
386
		remove_filter( 'jetpack_sync_idc_optin', '__return_false' );
387
	}
388
389
	function test_idc_optin_casts_to_bool() {
390
		add_filter( 'jetpack_sync_idc_optin', array( $this, 'return_string_1' ) );
391
		$this->assertTrue( Jetpack::sync_idc_optin() );
392
		remove_filter( 'jetpack_sync_idc_optin', array( $this, 'return_string_1' ) );
393
	}
394
395
	function test_idc_optin_true_when_constant_true() {
396
		Constants::set_constant( 'JETPACK_SYNC_IDC_OPTIN', true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

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...
397
		$this->assertTrue( Jetpack::sync_idc_optin() );
398
	}
399
400
	function test_idc_optin_false_when_constant_false() {
401
		Constants::set_constant( 'JETPACK_SYNC_IDC_OPTIN', false );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

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...
402
		$this->assertFalse( Jetpack::sync_idc_optin() );
403
	}
404
405
	function test_idc_optin_filter_overrides_constant() {
406
		Constants::set_constant( 'JETPACK_SYNC_IDC_OPTIN', true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

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...
407
		add_filter( 'jetpack_sync_idc_optin', '__return_false' );
408
		$this->assertFalse( Jetpack::sync_idc_optin() );
409
		remove_filter( 'jetpack_sync_idc_optin', '__return_false' );
410
	}
411
412
	function test_sync_error_idc_validation_returns_false_if_no_option() {
413
		Jetpack_Options::delete_option( 'sync_error_idc' );
414
		$this->assertFalse( Jetpack::validate_sync_error_idc_option() );
415
	}
416
417
	function test_sync_error_idc_validation_returns_true_when_option_matches_expected() {
418
		add_filter( 'jetpack_sync_idc_optin', '__return_true' );
419
		Jetpack_Options::update_option( 'sync_error_idc', Jetpack::get_sync_error_idc_option() );
420
		$this->assertTrue( Jetpack::validate_sync_error_idc_option() );
421
		Jetpack_Options::delete_option( 'sync_error_idc' );
422
		remove_filter( 'jetpack_sync_idc_optin', '__return_true' );
423
	}
424
425
	/**
426
	 * Verify that validate_sync_error returns false if wpcom_ is set and matches expected.
427
	 */
428 View Code Duplication
	public function test_sync_error_idc_validation_returns_false_when_wpcom_option_matches_expected() {
429
		add_filter( 'jetpack_sync_idc_optin', '__return_true' );
430
		$option                  = Jetpack::get_sync_error_idc_option();
431
		$option['wpcom_home']    = $option['home'];
432
		$option['wpcom_siteurl'] = $option['siteurl'];
433
		Jetpack_Options::update_option( 'sync_error_idc', $option );
434
		$this->assertFalse( Jetpack::validate_sync_error_idc_option() );
435
436
		// Verify the migrate_for_idc is set.
437
		$this->assertTrue( Jetpack_Options::get_option( 'migrate_for_idc' ) );
438
439
		Jetpack_Options::delete_option( 'sync_error_idc' );
440
		Jetpack_Options::delete_option( 'migrate_for_idc' );
441
		remove_filter( 'jetpack_sync_idc_optin', '__return_true' );
442
	}
443
444
	/**
445
	 * Verify that validate_sync_error returns true if wpcom_ is set and does not match.
446
	 */
447 View Code Duplication
	public function test_sync_error_idc_validation_returns_true_when_wpcom_option_does_not_match_expected() {
448
		add_filter( 'jetpack_sync_idc_optin', '__return_true' );
449
		$option                  = Jetpack::get_sync_error_idc_option();
450
		$option['wpcom_home']    = $option['home'];
451
		$option['wpcom_siteurl'] = 'coolrunnings.test';
452
		Jetpack_Options::update_option( 'sync_error_idc', $option );
453
		$this->assertTrue( Jetpack::validate_sync_error_idc_option() );
454
455
		// Verify the migrate_for_idc is not set.
456
		$this->assertNotTrue( Jetpack_Options::get_option( 'migrate_for_idc' ) );
457
458
		Jetpack_Options::delete_option( 'sync_error_idc' );
459
		Jetpack_Options::delete_option( 'migrate_for_idc' );
460
		remove_filter( 'jetpack_sync_idc_optin', '__return_true' );
461
	}
462
463
	function test_sync_error_idc_validation_cleans_up_when_validation_fails() {
464
		Jetpack_Options::update_option( 'sync_error_idc', array(
465
			'home'    => 'coolsite.com/',
466
			'siteurl' => 'coolsite.com/wp/',
467
		) );
468
469
		$this->assertFalse( Jetpack::validate_sync_error_idc_option() );
470
		$this->assertFalse( Jetpack_Options::get_option( 'sync_error_idc' ) );
471
	}
472
473 View Code Duplication
	function test_sync_error_idc_validation_cleans_up_when_part_of_validation_fails() {
474
		$test = Jetpack::get_sync_error_idc_option();
475
		$test['siteurl'] = 'coolsite.com/wp/';
476
		Jetpack_Options::update_option( 'sync_error_idc', $test );
477
478
		$this->assertFalse( Jetpack::validate_sync_error_idc_option() );
479
		$this->assertFalse( Jetpack_Options::get_option( 'sync_error_idc' ) );
480
	}
481
482
	function test_sync_error_idc_validation_returns_false_and_cleans_up_when_opted_out() {
483
		Jetpack_Options::update_option( 'sync_error_idc', Jetpack::get_sync_error_idc_option() );
484
		Constants::set_constant( 'JETPACK_SYNC_IDC_OPTIN', false );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

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...
485
486
		$this->assertFalse( Jetpack::validate_sync_error_idc_option() );
487
		$this->assertFalse( Jetpack_Options::get_option( 'sync_error_idc' ) );
488
	}
489
490
	function test_is_staging_site_true_when_sync_error_idc_is_valid() {
491
		add_filter( 'jetpack_sync_error_idc_validation', '__return_true' );
492
		$this->assertTrue( ( new Status() )->is_staging_site() );
493
		remove_filter( 'jetpack_sync_error_idc_validation', '__return_false' );
494
	}
495
496
	function test_is_dev_version_true_with_alpha() {
497
		Constants::set_constant( 'JETPACK__VERSION', '4.3.1-alpha' );
498
		$this->assertTrue( Jetpack::is_development_version() );
499
	}
500
501
	function test_is_dev_version_true_with_beta() {
502
		Constants::set_constant( 'JETPACK__VERSION', '4.3-beta2' );
503
		$this->assertTrue( Jetpack::is_development_version() );
504
	}
505
506
	function test_is_dev_version_true_with_rc() {
507
		Constants::set_constant( 'JETPACK__VERSION', '4.3-rc2' );
508
		$this->assertTrue( Jetpack::is_development_version() );
509
	}
510
511
	function test_is_dev_version_false_with_number_dot_number() {
512
		Constants::set_constant( 'JETPACK__VERSION', '4.3' );
513
		$this->assertFalse( Jetpack::is_development_version() );
514
	}
515
516
	function test_is_dev_version_false_with_number_dot_number_dot_number() {
517
		Constants::set_constant( 'JETPACK__VERSION', '4.3.1' );
518
		$this->assertFalse( Jetpack::is_development_version() );
519
	}
520
521
	/**
522
	 * Tests is_offline_mode filter.
523
	 *
524
	 * @covers \Automattic\Jetpack\Status::is_offline_mode
525
	 */
526
	public function test_is_offline_mode_filter() {
527
		add_filter( 'jetpack_offline_mode', '__return_true' );
528
		$this->assertTrue( ( new Status() )->is_offline_mode() );
529
		remove_filter( 'jetpack_offline_mode', '__return_true' );
530
	}
531
532
	/**
533
	 * Tests is_offline_mode filter's bool type casting.
534
	 *
535
	 * @covers \Automattic\Jetpack\Status::is_offline_mode
536
	 */
537
	public function test_is_offline_mode_bool() {
538
		add_filter( 'jetpack_offline_mode', '__return_zero' );
539
		$this->assertFalse( ( new Status() )->is_offline_mode() );
540
		remove_filter( 'jetpack_offline_mode', '__return_zero' );
541
	}
542
543 View Code Duplication
	function test_get_sync_idc_option_sanitizes_out_www_and_protocol() {
544
		$original_home    = get_option( 'home' );
545
		$original_siteurl = get_option( 'siteurl' );
546
547
		update_option( 'home', 'http://www.coolsite.com' );
548
		update_option( 'siteurl', 'http://www.coolsite.com/wp' );
549
550
		$expected = array(
551
			'home' => 'coolsite.com/',
552
			'siteurl' => 'coolsite.com/wp/'
553
		);
554
555
		$this->assertSame( $expected, Jetpack::get_sync_error_idc_option() );
556
557
		// Cleanup
558
		update_option( 'home', $original_home );
559
		update_option( 'siteurl', $original_siteurl );
560
	}
561
562 View Code Duplication
	function test_get_sync_idc_option_with_ip_address_in_option() {
563
		$original_home    = get_option( 'home' );
564
		$original_siteurl = get_option( 'siteurl' );
565
566
		update_option( 'home', 'http://72.182.131.109/~wordpress' );
567
		update_option( 'siteurl', 'http://72.182.131.109/~wordpress/wp' );
568
569
		$expected = array(
570
			'home' => '72.182.131.109/~wordpress/',
571
			'siteurl' => '72.182.131.109/~wordpress/wp/'
572
		);
573
574
		$this->assertSame( $expected, Jetpack::get_sync_error_idc_option() );
575
576
		// Cleanup
577
		update_option( 'home', $original_home );
578
		update_option( 'siteurl', $original_siteurl );
579
	}
580
581 View Code Duplication
	function test_normalize_url_protocol_agnostic_strips_protocol_and_www_for_subdir_subdomain() {
582
		$url = 'https://www.subdomain.myfaketestsite.com/what';
583
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
584
		$this->assertTrue( 'subdomain.myfaketestsite.com/what/' === $url_normalized );
585
586
		$url = 'http://subdomain.myfaketestsite.com';
587
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
588
		$this->assertTrue( 'subdomain.myfaketestsite.com/' === $url_normalized );
589
590
		$url = 'www.subdomain.myfaketestsite.com';
591
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
592
		$this->assertTrue( 'subdomain.myfaketestsite.com/' === $url_normalized );
593
	}
594
595 View Code Duplication
	function test_normalize_url_protocol_agnostic_strips_protocol_and_www_for_normal_urls() {
596
		$url = 'https://www.myfaketestsite.com';
597
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
598
		$this->assertTrue( 'myfaketestsite.com/' === $url_normalized );
599
600
		$url = 'www.myfaketestsite.com';
601
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
602
		$this->assertTrue( 'myfaketestsite.com/' === $url_normalized );
603
604
		$url = 'myfaketestsite.com';
605
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
606
		$this->assertTrue( 'myfaketestsite.com/' === $url_normalized );
607
	}
608
609
	function test_normalize_url_protocol_agnostic_strips_protocol_for_ip() {
610
		$url = 'http://123.456.789.0';
611
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
612
		$this->assertTrue( '123.456.789.0/' === $url_normalized );
613
614
		$url = '123.456.789.0';
615
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
616
		$this->assertTrue( '123.456.789.0/' === $url_normalized );
617
	}
618
619
	/**
620
	 * The generate_secrets method should return and store the secret.
621
	 *
622
	 * @author zinigor
623
	 * @covers Jetpack::generate_secrets
624
	 */
625
	function test_generate_secrets_stores_secrets() {
626
		$secret = Jetpack::generate_secrets( 'name' );
627
628
		$this->assertEquals( $secret, Jetpack::get_secrets( 'name', get_current_user_id() ) );
629
	}
630
631
	/**
632
	 * The generate_secrets method should return the same secret after calling generate several times.
633
	 *
634
	 * @author zinigor
635
	 * @covers Jetpack::generate_secrets
636
	 */
637
	function test_generate_secrets_does_not_regenerate_secrets() {
638
		$secret = Jetpack::generate_secrets( 'name' );
639
		$secret2 = Jetpack::generate_secrets( 'name' );
640
		$secret3 = Jetpack::generate_secrets( 'name' );
641
642
		$this->assertEquals( $secret, $secret2 );
643
		$this->assertEquals( $secret, $secret3 );
644
		$this->assertEquals( $secret, Jetpack::get_secrets( 'name', get_current_user_id() ) );
645
	}
646
647
	/**
648
	 * The generate_secrets method should work with filters on wp_generate_password.
649
	 *
650
	 * @author zinigor
651
	 * @covers Jetpack::generate_secrets
652
	 */
653
	function test_generate_secrets_works_with_filters() {
654
		add_filter( 'random_password', array( __CLASS__, 'cyrillic_salt' ), 20 );
655
		add_filter( 'random_password', array( __CLASS__, 'kanji_salt' ), 21 );
656
657
		$secret = Jetpack::generate_secrets( 'name' );
658
659
		$this->assertEquals( $secret, Jetpack::get_secrets( 'name', get_current_user_id() ) );
660
661
		remove_filter( 'random_password', array( __CLASS__, 'cyrillic_salt' ), 20 );
662
		remove_filter( 'random_password', array( __CLASS__, 'kanji_salt' ), 21 );
663
	}
664
665
	/**
666
	 * The generate_secrets method should work with long strings.
667
	 *
668
	 * @author zinigor
669
	 * @covers Jetpack::generate_secrets
670
	 */
671
	function test_generate_secrets_works_with_long_strings() {
672
		add_filter( 'random_password', array( __CLASS__, 'multiply_filter' ), 20 );
673
674
		$secret = Jetpack::generate_secrets( 'name' );
675
676
		$this->assertEquals( $secret, Jetpack::get_secrets( 'name', get_current_user_id() ) );
677
678
		remove_filter( 'random_password', array( __CLASS__, 'multiply_filter' ), 20 );
679
	}
680
681
	/**
682
	 * The get_secrets method should return an error for unknown secrets
683
	 *
684
	 * @author roccotripaldi
685
	 * @covers Jetpack::generate_secrets
686
	 */
687
	function test_generate_secrets_returns_error_for_unknown_secrets() {
688
		Jetpack::generate_secrets( 'name' );
689
		$unknown_action = Jetpack::get_secrets( 'unknown', get_current_user_id() );
690
		$unknown_user_id = Jetpack::get_secrets( 'name', 5 );
691
692
		$this->assertInstanceOf( 'WP_Error', $unknown_action );
693
		$this->assertArrayHasKey( 'verify_secrets_missing', $unknown_action->errors );
694
		$this->assertInstanceOf( 'WP_Error', $unknown_user_id );
695
		$this->assertArrayHasKey( 'verify_secrets_missing', $unknown_user_id->errors );
696
	}
697
698
	/**
699
	 * The get_secrets method should return an error for expired secrets
700
	 *
701
	 * @author roccotripaldi
702
	 * @covers Jetpack::generate_secrets
703
	 */
704
	function test_generate_secrets_returns_error_for_expired_secrets() {
705
		Jetpack::generate_secrets( 'name', get_current_user_id(), -600 );
706
		$expired = Jetpack::get_secrets( 'name', get_current_user_id() );
707
		$this->assertInstanceOf( 'WP_Error', $expired );
708
		$this->assertArrayHasKey( 'verify_secrets_expired', $expired->errors );
709
	}
710
711
	/**
712
	 * Parse the referer on plugin activation and record the activation source
713
	 * - featured plugins page
714
	 * - popular plugins page
715
	 * - search (with query)
716
	 * - plugins list
717
	 * - other
718
	 */
719
	function test_get_activation_source() {
720
		$plugins_url = admin_url( 'plugins.php' );
721
		$plugin_install_url = admin_url( 'plugin-install.php' );
722
		$unknown_url = admin_url( 'unknown.php' );
723
724
		$this->assertEquals( array( 'list', null ), Jetpack::get_activation_source( $plugins_url . '?plugin_status=all&paged=1&s' ) );
725
		$this->assertEquals( array( 'featured', null ), Jetpack::get_activation_source( $plugin_install_url ) );
726
		$this->assertEquals( array( 'popular', null ), Jetpack::get_activation_source( $plugin_install_url . '?tab=popular' ) );
727
		$this->assertEquals( array( 'recommended', null ), Jetpack::get_activation_source( $plugin_install_url . '?tab=recommended' ) );
728
		$this->assertEquals( array( 'favorites', null ), Jetpack::get_activation_source( $plugin_install_url . '?tab=favorites' ) );
729
		$this->assertEquals( array( 'search-term', 'jetpack' ), Jetpack::get_activation_source( $plugin_install_url . '?s=jetpack&tab=search&type=term' ) );
730
		$this->assertEquals( array( 'search-author', 'foo' ), Jetpack::get_activation_source( $plugin_install_url . '?s=foo&tab=search&type=author' ) );
731
		$this->assertEquals( array( 'search-tag', 'social' ), Jetpack::get_activation_source( $plugin_install_url . '?s=social&tab=search&type=tag' ) );
732
		$this->assertEquals( array( 'unknown', null ), Jetpack::get_activation_source( $unknown_url ) );
733
	}
734
735
	/**
736
	 * @author tyxla
737
	 * @covers Jetpack::get_assumed_site_creation_date()
738
	 */
739 View Code Duplication
	function test_get_assumed_site_creation_date_user_earliest() {
740
		$user_id = $this->factory->user->create( array(
741
			'role'            => 'administrator',
742
			'user_registered' => '1990-01-01 00:00:00',
743
		) );
744
		$post_id = $this->factory->post->create( array(
745
			'post_date' => '1995-01-01 00:00:00',
746
		) );
747
748
		$jetpack = new MockJetpack();
749
		$this->assertEquals( '1990-01-01 00:00:00', $jetpack::connection()->get_assumed_site_creation_date() );
750
751
		wp_delete_user( $user_id );
752
		wp_delete_post( $post_id, true );
753
	}
754
755
	/**
756
	 * @author tyxla
757
	 * @covers Jetpack::get_assumed_site_creation_date()
758
	 */
759 View Code Duplication
	function test_get_assumed_site_creation_date_post_earliest() {
760
		$user_id = $this->factory->user->create( array(
761
			'role'            => 'administrator',
762
			'user_registered' => '1994-01-01 00:00:00',
763
		) );
764
		$post_id = $this->factory->post->create( array(
765
			'post_date' => '1991-01-01 00:00:00',
766
		) );
767
768
		$jetpack = new MockJetpack();
769
		$this->assertEquals( '1991-01-01 00:00:00', $jetpack::connection()->get_assumed_site_creation_date() );
770
771
		wp_delete_user( $user_id );
772
		wp_delete_post( $post_id, true );
773
	}
774
775
	/**
776
	 * @author tyxla
777
	 * @covers Jetpack::get_assumed_site_creation_date()
778
	 */
779 View Code Duplication
	function test_get_assumed_site_creation_date_only_admins() {
780
		$admin_id = $this->factory->user->create( array(
781
			'role'            => 'administrator',
782
			'user_registered' => '1994-01-01 00:00:00',
783
		) );
784
		$editor_id = $this->factory->user->create( array(
785
			'role'            => 'editor',
786
			'user_registered' => '1992-01-01 00:00:00',
787
		) );
788
789
		$jetpack = new MockJetpack();
790
		$this->assertEquals( '1994-01-01 00:00:00', $jetpack::connection()->get_assumed_site_creation_date() );
791
792
		wp_delete_user( $admin_id );
793
		wp_delete_user( $editor_id );
794
	}
795
796
	/**
797
	 * @author ebinnion
798
	 * @dataProvider get_file_url_for_environment_data_provider
799
	 */
800
	function test_get_file_url_for_environment( $min_path, $non_min_path, $is_script_debug, $expected, $not_expected ) {
801
		Constants::set_constant( 'SCRIPT_DEBUG', $is_script_debug );
802
		$file_url = Jetpack::get_file_url_for_environment( $min_path, $non_min_path );
803
804
		$this->assertContains( $$expected, $file_url );
805
		$this->assertNotContains( $$not_expected, $file_url );
806
	}
807
808 View Code Duplication
	function get_file_url_for_environment_data_provider() {
809
		return array(
810
			'script-debug-true' => array(
811
				'_inc/build/shortcodes/js/recipes.js',
812
				'modules/shortcodes/js/recipes.js',
813
				true,
814
				'non_min_path',
815
				'min_path'
816
			),
817
			'script-debug-false' => array(
818
				'_inc/build/shortcodes/js/recipes.js',
819
				'modules/shortcodes/js/recipes.js',
820
				false,
821
				'min_path',
822
				'non_min_path'
823
			),
824
		);
825
	}
826
827
	/**
828
	 * @dataProvider get_content_width_data
829
	 */
830
	public function test_get_content_width( $expected, $content_width ) {
831
		$GLOBALS['content_width'] = $content_width;
832
		$this->assertSame( $expected, Jetpack::get_content_width() );
833
	}
834
835
	public function get_content_width_data() {
836
		return array(
837
			'zero' => array(
838
				0,
839
				0,
840
			),
841
			'int' => array(
842
				100,
843
				100,
844
			),
845
			'numeric_string' => array(
846
				'100',
847
				'100',
848
			),
849
			'non_numeric_string' => array(
850
				false,
851
				'meh'
852
			),
853
			'content_width_not_set' => array(
854
				false,
855
				null,
856
			),
857
		);
858
	}
859
860
	/**
861
	 * Return a Cyrillic salt.
862
	 *
863
	 * @param string $password String to add salt to.
864
	 * @return string
865
	 */
866
	public static function cyrillic_salt( $password ) {
867
		return 'ленка' . $password . 'пенка';
868
	}
869
870
	/**
871
	 * Return a Kanji salt.
872
	 *
873
	 * @param string $password String to add salt to.
874
	 * @return string
875
	 */
876
	public static function kanji_salt( $password ) {
877
		return '強熊' . $password . '清珠';
878
	}
879
880
	/**
881
	 * Filter to increase a string length.
882
	 *
883
	 * @param string $password String to expand.
884
	 * @return string
885
	 */
886
	public static function multiply_filter( $password ) {
887
		for ( $i = 0; $i < 10; $i++ ) {
888
			$password .= $password;
889
		}
890
		return $password;
891
	}
892
893
	/**
894
	 * Return string '1'.
895
	 *
896
	 * @return string
897
	 */
898
	public function return_string_1() {
899
		return '1';
900
	}
901
902
	/**
903
	 * Reset tracking of module activation.
904
	 */
905
	public static function reset_tracking_of_module_activation() {
906
		self::$activated_modules   = array();
907
		self::$deactivated_modules = array();
908
	}
909
910
	/**
911
	 * Track activated modules.
912
	 *
913
	 * @param mixed $module Module.
914
	 */
915
	public static function track_activated_modules( $module ) {
916
		self::$activated_modules[] = $module;
917
	}
918
919
	/**
920
	 * Track deactivated modules.
921
	 *
922
	 * @param mixed $module Module.
923
	 */
924
	public static function track_deactivated_modules( $module ) {
925
		self::$deactivated_modules[] = $module;
926
	}
927
928
	/**
929
	 * Mocked `setup_xmlrpc_handlers`.
930
	 *
931
	 * @param array         $request_params Incoming request parameters.
932
	 * @param bool          $is_active Whether the connection is currently active.
933
	 * @param bool          $is_signed Whether the signature check has been successful.
934
	 * @param WP_User|false $user User for the mocked Jetpack_XMLRPC_Server.
935
	 * @return bool
936
	 */
937
	private function mocked_setup_xmlrpc_handlers( $request_params, $is_active, $is_signed, $user = false ) {
938
		$GLOBALS['HTTP_RAW_POST_DATA'] = '';
939
940
		Constants::set_constant( 'XMLRPC_REQUEST', true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

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...
941
942
		$jetpack       = new MockJetpack();
943
		$xmlrpc_server = new MockJetpack_XMLRPC_Server( $user );
944
		return $jetpack::connection()->setup_xmlrpc_handlers( $request_params, $is_active, $is_signed, $xmlrpc_server );
945
	}
946
947
	/**
948
	 * Asserts that:
949
	 *   - all of the required xmlrpc methods are in the actual method list.
950
	 *   - all of the actual xmlrpc methods are in the required or allowed lists.
951
	 *
952
	 * @param string[] $required List of XML-RPC methods that must be contained in $actual.
953
	 * @param string[] $allowed  Additional list of XML-RPC methods that may be contained in $actual.
954
	 *                           Useful for listing methods that are added by modules that may or may
955
	 *                           not be active during the test run.
956
	 * @param string[] $actual   The list of XML-RPC methods.
957
	 */
958
	private function assertXMLRPCMethodsComply( $required, $allowed, $actual ) {
959
		$this->assertEquals( array(), array_diff( $required, $actual ) );
960
		$this->assertEquals( array(), array_diff( $actual, $required, $allowed ) );
961
	}
962
963
	/**
964
	 * Tests the setup of the xmlrpc methods when the site is active, the request is signed, and without a user.
965
	 *
966
	 * @group xmlrpc
967
	 */
968
	public function test_classic_xmlrpc_when_active_and_signed_with_no_user() {
969
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), true, true );
970
971
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
972
973
		$required = array(
974
			'jetpack.verifyAction',
975
			'jetpack.getUser',
976
			'jetpack.remoteRegister',
977
			'jetpack.remoteProvision',
978
			'jetpack.jsonAPI',
979
			'jetpack.idcUrlValidation',
980
			'jetpack.unlinkUser',
981
			'jetpack.testConnection',
982
			'jetpack.featuresAvailable',
983
			'jetpack.featuresEnabled',
984
		);
985
986
		$allowed = array(
987
			'jetpack.getHeartbeatData',
988
			'jetpack.syncObject',
989
			'jetpack.updatePublicizeConnections',
990
			'jetpack.getBlog',
991
		);
992
993
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
994
	}
995
996
	/**
997
	 * Tests the setup of the xmlrpc methods when the site is active, the request is signed, and with a user.
998
	 *
999
	 * @group xmlrpc
1000
	 */
1001
	public function test_classic_xmlrpc_when_active_and_signed_with_user() {
1002
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), true, true, get_user_by( 'ID', self::$admin_id ) );
1003
1004
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1005
1006
		$required = array(
1007
			'jetpack.verifyAction',
1008
			'jetpack.getUser',
1009
			'jetpack.remoteRegister',
1010
			'jetpack.remoteProvision',
1011
			'jetpack.jsonAPI',
1012
1013
			'jetpack.testAPIUserCode',
1014
			'jetpack.disconnectBlog',
1015
			'jetpack.unlinkUser',
1016
			'jetpack.idcUrlValidation',
1017
			'jetpack.testConnection',
1018
			'jetpack.featuresAvailable',
1019
			'jetpack.featuresEnabled',
1020
1021
			'jetpack.syncObject',
1022
		);
1023
1024
		// It's OK if these module-added methods are present (module active in tests).
1025
		// It's OK if they are not (module inactive in tests).
1026
		$allowed = array(
1027
			'jetpack.subscriptions.subscribe',
1028
			'jetpack.updatePublicizeConnections',
1029
			'jetpack.getHeartbeatData',
1030
		);
1031
1032
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1033
	}
1034
1035
	/**
1036
	 * Tests the setup of the xmlrpc methods when the site is active, the request is signed, with a user,
1037
	 * and with edit methods enabled.
1038
	 *
1039
	 * @group xmlrpc
1040
	 */
1041
	public function test_classic_xmlrpc_when_active_and_signed_with_user_with_edit() {
1042
		$this->mocked_setup_xmlrpc_handlers(
1043
			array( 'for' => 'jetpack' ),
1044
			true,
1045
			true,
1046
			get_user_by( 'ID', self::$admin_id )
1047
		);
1048
1049
		$methods = apply_filters(
1050
			'xmlrpc_methods',
1051
			array(
1052
				'test.test'                 => '__return_true',
1053
				'metaWeblog.editPost'       => '__return_true',
1054
				'metaWeblog.newMediaObject' => '__return_true',
1055
			)
1056
		);
1057
1058
		$required = array(
1059
			'jetpack.verifyAction',
1060
			'jetpack.getUser',
1061
			'jetpack.remoteRegister',
1062
			'jetpack.remoteProvision',
1063
			'jetpack.jsonAPI',
1064
1065
			'jetpack.testAPIUserCode',
1066
			'jetpack.disconnectBlog',
1067
			'jetpack.unlinkUser',
1068
			'jetpack.idcUrlValidation',
1069
			'jetpack.testConnection',
1070
			'jetpack.featuresAvailable',
1071
			'jetpack.featuresEnabled',
1072
1073
			'metaWeblog.newMediaObject',
1074
			'jetpack.updateAttachmentParent',
1075
1076
			'jetpack.syncObject',
1077
		);
1078
1079
		// It's OK if these module-added methods are present (module active in tests).
1080
		// It's OK if they are not (module inactive in tests).
1081
		$allowed = array(
1082
			'jetpack.subscriptions.subscribe',
1083
			'jetpack.updatePublicizeConnections',
1084
			'jetpack.getHeartbeatData',
1085
		);
1086
1087
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1088
	}
1089
1090
	/**
1091
	 * Tests the setup of the xmlrpc methods when the site is active and the request is not signed.
1092
	 *
1093
	 * @group xmlrpc
1094
	 */
1095
	public function test_classic_xmlrpc_when_active_and_not_signed() {
1096
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), true, false );
1097
1098
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1099
1100
		$required = array(
1101
			'jetpack.remoteAuthorize',
1102
		);
1103
1104
		// Nothing else is allowed.
1105
		$allowed = array();
1106
1107
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1108
	}
1109
1110
	/**
1111
	 * Tests the setup of the xmlrpc methods when the site is not active and the request is not signed.
1112
	 *
1113
	 * @group xmlrpc
1114
	 */
1115 View Code Duplication
	public function test_classic_xmlrpc_when_not_active_and_not_signed() {
1116
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), false, false );
1117
1118
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1119
1120
		$required = array(
1121
			'jetpack.remoteAuthorize',
1122
			'jetpack.remoteRegister',
1123
1124
			'jetpack.verifyRegistration',
1125
		);
1126
1127
		// Nothing else is allowed.
1128
		$allowed = array();
1129
1130
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1131
	}
1132
1133
	/**
1134
	 * Tests the setup of the xmlrpc methods when the site is not active and the request is signed.
1135
	 *
1136
	 * @group xmlrpc
1137
	 */
1138 View Code Duplication
	public function test_classic_xmlrpc_when_not_active_and_signed() {
1139
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), false, true );
1140
1141
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1142
1143
		$required = array(
1144
			'jetpack.remoteRegister',
1145
			'jetpack.remoteProvision',
1146
			'jetpack.remoteConnect',
1147
			'jetpack.getUser',
1148
		);
1149
1150
		// Nothing else is allowed.
1151
		$allowed = array();
1152
1153
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1154
	}
1155
1156
	/**
1157
	 * Test "wp_getOptions_hook_in_place".
1158
	 *
1159
	 * @see https://github.com/Automattic/jetpack/pull/13514
1160
	 *
1161
	 * @group xmlrpc
1162
	 */
1163
	public function test_wp_getOptions_hook_in_place() {
1164
		$options = apply_filters( 'xmlrpc_blog_options', array() );
1165
1166
		$this->assertArrayHasKey( 'jetpack_version', $options );
1167
	}
1168
1169
	/**
1170
	 * Tests if Partner codes are added to the connect url.
1171
	 *
1172
	 * @dataProvider partner_code_provider
1173
	 *
1174
	 * @param string $code_type Partner code type.
1175
	 * @param string $option_name Option and filter name.
1176
	 * @param string $query_string_name Query string variable name.
1177
	 */
1178
	public function test_partner_codes_are_added_to_authorize_url( $code_type, $option_name, $query_string_name ) {
1179
		$test_code = 'abc-123';
1180
		Partner::init();
1181
		add_filter(
1182
			$option_name,
1183
			function () use ( $test_code ) {
1184
				return $test_code;
1185
			}
1186
		);
1187
		$jetpack = \Jetpack::init();
1188
		$url     = $jetpack->build_authorize_url();
1189
1190
		$parsed_vars = array();
1191
		parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $parsed_vars );
1192
1193
		$this->assertArrayHasKey( $query_string_name, $parsed_vars );
1194
		$this->assertSame( $test_code, $parsed_vars[ $query_string_name ] );
1195
	}
1196
1197
	/**
1198
	 * Provides code for test_partner_codes_are_added_to_authorize_url.
1199
	 *
1200
	 * @return array
1201
	 */
1202 View Code Duplication
	public function partner_code_provider() {
1203
		return array(
1204
			'subsidiary_code' =>
1205
				array(
1206
					Partner::SUBSIDIARY_CODE,            // Code type.
1207
					'jetpack_partner_subsidiary_id',     // filter/option key.
1208
					'subsidiaryId',                      // Query string parameter.
1209
				),
1210
			'affiliate_code'  =>
1211
				array(
1212
					Partner::AFFILIATE_CODE,
1213
					'jetpack_affiliate_code',
1214
					'aff',
1215
				),
1216
		);
1217
	}
1218
1219
	/**
1220
	 * Tests login URL only adds redirect param when redirect param is in original request.
1221
	 *
1222
	 * @since 8.4.0
1223
	 * @return void
1224
	 */
1225
	public function test_login_url_add_redirect() {
1226
		$login_url = wp_login_url( '/wp-admin' );
1227
		$this->assertFalse( strpos( $login_url, Jetpack::$jetpack_redirect_login ) );
1228
1229
		$login_url = wp_login_url( '/wp-admin?' . Jetpack::$jetpack_redirect_login . '=true' );
1230
		parse_str( wp_parse_url( $login_url, PHP_URL_QUERY ), $login_parts );
1231
		$this->assertArraySubset( array( Jetpack::$jetpack_redirect_login => 'true' ), $login_parts, true );
1232
	}
1233
1234
	/**
1235
	 * Tests login redirect sending users to Calypso when redirect param is set.
1236
	 *
1237
	 * @since 8.4.0
1238
	 * @return void
1239
	 */
1240
	public function test_login_init_redirect() {
1241
		tests_add_filter(
1242
			'wp_redirect',
1243
			function ( $location ) {
1244
				$expected_location = add_query_arg(
1245
					array(
1246
						'forceInstall' => 1,
1247
						'url'          => rawurlencode( get_site_url() ),
1248
					),
1249
					'https://wordpress.com/jetpack/connect'
1250
				);
1251
				$this->assertEquals( $location, $expected_location );
1252
				throw new Exception(); // Cause an exception, as we don't want to run exit.
1253
			}
1254
		);
1255
1256
		// Remove core filters that add headers.
1257
		remove_filter( 'login_init', 'wp_admin_headers' );
1258
		remove_filter( 'login_init', 'send_frame_options_header' );
1259
1260
		// Run it once and no exception is thrown.
1261
		do_action( 'login_init' );
1262
1263
		$this->expectException( Exception::class );
1264
		$_GET[ Jetpack::$jetpack_redirect_login ] = 'true';
1265
		do_action( 'login_init' ); // Now expect an exception.
1266
	}
1267
1268
	/**
1269
	 * Tests getting the correct Calypso host.
1270
	 *
1271
	 * @since 8.4.0
1272
	 * @return void
1273
	 */
1274
	public function test_get_calypso_host() {
1275
		// No env.
1276
		$this->assertEquals( 'https://wordpress.com/', Jetpack::get_calypso_host() );
1277
1278
		$_GET['calypso_env'] = 'development';
1279
		$this->assertEquals( 'http://calypso.localhost:3000/', Jetpack::get_calypso_host() );
1280
1281
		$_GET['calypso_env'] = 'wpcalypso';
1282
		$this->assertEquals( 'https://wpcalypso.wordpress.com/', Jetpack::get_calypso_host() );
1283
1284
		$_GET['calypso_env'] = 'horizon';
1285
		$this->assertEquals( 'https://horizon.wordpress.com/', Jetpack::get_calypso_host() );
1286
1287
		$_GET['calypso_env'] = 'stage';
1288
		$this->assertEquals( 'https://wordpress.com/', Jetpack::get_calypso_host() );
1289
1290
		$_GET['calypso_env'] = 'production';
1291
		$this->assertEquals( 'https://wordpress.com/', Jetpack::get_calypso_host() );
1292
	}
1293
1294
	/**
1295
	 * Tests the Jetpack::should_set_cookie() method.
1296
	 *
1297
	 * @param string  $key The state key test value.
1298
	 * @param string  $set_screen The $current_screen->base test value.
1299
	 * @param boolean $expected_output The expected output of Jetpack::should_set_cookie().
1300
	 *
1301
	 * @covers Jetpack::should_set_cookie
1302
	 * @dataProvider should_set_cookie_provider
1303
	 */
1304
	public function test_should_set_cookie( $key, $set_screen, $expected_output ) {
1305
		global $current_screen;
1306
		$old_current_screen   = $current_screen;
1307
		$current_screen       = new stdClass();
1308
		$current_screen->base = $set_screen;
1309
1310
		$this->assertEquals( $expected_output, Jetpack::should_set_cookie( $key ) );
1311
		$current_screen = $old_current_screen;
1312
	}
1313
1314
	/**
1315
	 * The data provider for test_should_set_cookie(). Provides an array of
1316
	 * test data. Each data set is an array with the structure:
1317
	 *     [0] => The state key test value.
1318
	 *     [1] => The $current_screen->base test value.
1319
	 *     [2] => The expected output of Jetpack::should_set_cookie().
1320
	 */
1321
	public function should_set_cookie_provider() {
1322
		return array(
1323
			array( 'display_update_modal', 'toplevel_page_jetpack', false ),
1324
			array( 'display_update_modal', 'test_page', true ),
1325
			array( 'display_update_modal', null, true ),
1326
			array( 'message', 'toplevel_page_jetpack', true ),
1327
			array( 'message', 'test_page', true ),
1328
			array( 'message', null, true ),
1329
		);
1330
	}
1331
1332
	/**
1333
	 * Testing that a deprecated action triggers Jetpack functionality.
1334
	 *
1335
	 * Using the `jetpack_updated_theme` action for the sake of testing.
1336
	 *
1337
	 * @expectedDeprecated jetpack_updated_theme
1338
	 */
1339
	public function test_deprecated_action_fires() {
1340
		add_action( 'jetpack_updated_theme', '__return_false' );
1341
		Jetpack::init()->deprecated_hooks();
1342
		remove_action( 'jetpack_updated_theme', '__return_false' );
1343
	}
1344
1345
	/**
1346
	 * Testing that a deprecated filter triggers Jetpack functionality.
1347
	 *
1348
	 * Using the `jetpack_bail_on_shortcode` filter for the sake of testing.
1349
	 *
1350
	 * @expectedDeprecated jetpack_bail_on_shortcode
1351
	 */
1352
	public function test_deprecated_filter_fires() {
1353
		add_filter( 'jetpack_bail_on_shortcode', '__return_false' );
1354
		Jetpack::init()->deprecated_hooks();
1355
		remove_filter( 'jetpack_bail_on_shortcode', '__return_false' );
1356
	}
1357
} // end class
1358