WP_Test_Jetpack   F
last analyzed

Complexity

Total Complexity 92

Size/Duplication

Total Lines 1235
Duplicated Lines 24.05 %

Coupling/Cohesion

Components 2
Dependencies 9

Importance

Changes 0
Metric Value
dl 297
loc 1235
rs 0.8
c 0
b 0
f 0
wmc 92
lcom 2
cbo 9

79 Methods

Rating   Name   Duplication   Size   Complexity  
A wpSetupBeforeClass() 0 5 1
A tearDown() 0 4 1
A test_static_binding() 0 4 1
A test_init() 0 3 1
A test_sort_modules_with_equal_sort_values() 0 9 1
A test_sort_modules_with_different_sort_values() 0 11 1
A test_absolutize_css_urls_properly_handles_use_cases() 0 50 1
B test_implode_frontend_css_enqueues_bundle_file_handle() 0 28 7
A test_implode_frontend_css_does_not_enqueue_bundle_when_disabled_through_filter() 0 22 3
A test_activating_deactivating_modules_fires_actions() 17 17 1
A test_activating_deactivating_modules_fires_specific_actions() 16 16 1
A test_active_modules_filter_restores_state() 0 26 1
A e2e_test_filter() 0 12 3
A test_get_other_linked_admins_one_admin_returns_false() 0 6 1
A test_get_other_linked_admins_more_than_one_not_false() 0 15 1
A test_promoting_admin_clears_other_linked_admins_transient() 7 7 1
A test_demoting_admin_clear_other_linked_admins_transiet() 7 7 1
A test_null_old_roles_clears_linked_admins_transient() 10 10 1
A test_changing_non_admin_roles_does_not_clear_other_linked_admins_transient() 0 10 2
A test_other_linked_admins_transient_set_to_zero_returns_false() 0 4 1
A test_idc_optin_default() 0 7 2
A test_idc_optin_filter_overrides_development_version() 0 7 1
A test_idc_optin_casts_to_bool() 0 5 1
A test_idc_optin_true_when_constant_true() 0 4 1
A test_idc_optin_false_when_constant_false() 0 4 1
A test_idc_optin_filter_overrides_constant() 0 6 1
A test_sync_error_idc_validation_returns_false_if_no_option() 0 4 1
A test_sync_error_idc_validation_returns_true_when_option_matches_expected() 0 7 1
A test_sync_error_idc_validation_returns_false_when_wpcom_option_matches_expected() 15 15 1
A test_sync_error_idc_validation_returns_true_when_wpcom_option_does_not_match_expected() 15 15 1
A test_sync_error_idc_validation_cleans_up_when_validation_fails() 0 9 1
A test_sync_error_idc_validation_cleans_up_when_part_of_validation_fails() 8 8 1
A test_sync_error_idc_validation_returns_false_and_cleans_up_when_opted_out() 0 7 1
A test_is_staging_site_true_when_sync_error_idc_is_valid() 0 5 1
A test_is_dev_version_true_with_alpha() 0 4 1
A test_is_dev_version_true_with_beta() 0 4 1
A test_is_dev_version_true_with_rc() 0 4 1
A test_is_dev_version_false_with_number_dot_number() 0 4 1
A test_is_dev_version_false_with_number_dot_number_dot_number() 0 4 1
A test_is_offline_mode_filter() 0 5 1
A test_is_offline_mode_bool() 0 5 1
A test_get_sync_idc_option_sanitizes_out_www_and_protocol() 18 18 1
A test_get_sync_idc_option_with_ip_address_in_option() 18 18 1
A test_normalize_url_protocol_agnostic_strips_protocol_and_www_for_subdir_subdomain() 13 13 1
A test_normalize_url_protocol_agnostic_strips_protocol_and_www_for_normal_urls() 13 13 1
A test_normalize_url_protocol_agnostic_strips_protocol_for_ip() 0 9 1
A test_get_activation_source() 0 15 1
A test_get_assumed_site_creation_date_user_earliest() 15 15 1
A test_get_assumed_site_creation_date_post_earliest() 15 15 1
A test_get_assumed_site_creation_date_only_admins() 16 16 1
A test_get_file_url_for_environment() 0 7 1
A get_file_url_for_environment_data_provider() 18 18 1
A test_get_content_width() 0 4 1
A get_content_width_data() 0 24 1
A cyrillic_salt() 0 3 1
A kanji_salt() 0 3 1
A multiply_filter() 0 6 2
A return_string_1() 0 3 1
A reset_tracking_of_module_activation() 0 4 1
A track_activated_modules() 0 3 1
A track_deactivated_modules() 0 3 1
A mocked_setup_xmlrpc_handlers() 0 9 1
A assertXMLRPCMethodsComply() 0 4 1
A test_classic_xmlrpc_when_active_and_signed_with_no_user() 29 29 1
A test_classic_xmlrpc_when_active_and_signed_with_user() 0 34 1
A test_classic_xmlrpc_when_active_and_signed_with_user_with_edit() 0 49 1
A test_classic_xmlrpc_when_active_and_not_signed() 0 14 1
A test_classic_xmlrpc_when_not_active_and_not_signed() 0 17 1
A test_classic_xmlrpc_when_not_active_and_signed() 31 31 1
A test_wp_getOptions_hook_in_place() 0 5 1
A test_partner_codes_are_added_to_authorize_url() 0 18 1
A partner_code_provider() 16 16 1
A test_login_url_add_redirect() 0 8 1
A test_login_init_redirect() 0 27 1
A test_get_calypso_host() 0 19 1
A test_should_set_cookie() 0 9 1
A should_set_cookie_provider() 0 10 1
A test_deprecated_action_fires() 0 5 1
A test_deprecated_filter_fires() 0 5 1

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WP_Test_Jetpack often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WP_Test_Jetpack, and based on these observations, apply Extract Interface, too.

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\Identity_Crisis;
7
use Automattic\Jetpack\Partner;
8
use Automattic\Jetpack\Status;
9
10
// Extend with a public constructor so that can be mocked in tests
11
class MockJetpack extends Jetpack {
12
13
	/**
14
	 * Holds the singleton instance of this class
15
	 *
16
	 * @var MockJetpack
17
	 */
18
	public static $instance = false;
19
20
	/**
21
	 * We are redefining this to overcome the lack of late static binding in the parent Jetpack class.
22
	 *
23
	 * @static
24
	 */
25
	public static function init() {
26
		if ( ! self::$instance ) {
27
			self::$instance = new self();
28
		}
29
30
		return self::$instance;
31
	}
32
33
	public function __construct() {
34
		$this->connection_manager = new Connection_Manager();
35
	}
36
}
37
38
class MockJetpack_XMLRPC_Server extends Jetpack_XMLRPC_Server {
39
	private $mockLoginUser = false;
40
41
	public function __construct( $user ) {
42
		$this->mockLoginUser = $user;
43
	}
44
45
	public function login() {
46
		return $this->mockLoginUser;
47
	}
48
}
49
50
class WP_Test_Jetpack extends WP_UnitTestCase {
51
	static $admin_id = 0;
52
53
	static $activated_modules = array();
54
	static $deactivated_modules = array();
55
56
	public static function wpSetupBeforeClass() {
57
		self::$admin_id = self::factory()->user->create( array(
58
			'role' => 'administrator',
59
		) );
60
	}
61
62
	public function tearDown() {
63
		parent::tearDown();
64
		Constants::clear_constants();
65
	}
66
67
	/**
68
	 * Make sure that MockJetpack creates separate instances of `Jetpack` and `Automattic\Jetpack\Connection\Manager`.
69
	 */
70
	public function test_static_binding() {
71
		$this->assertNotEquals( spl_object_hash( MockJetpack::init() ), spl_object_hash( Jetpack::init() ) );
72
		$this->assertNotEquals( spl_object_hash( MockJetpack::connection() ), spl_object_hash( Jetpack::connection() ) );
73
	}
74
75
	/**
76
	 * @author blobaugh
77
	 * @covers Jetpack::init
78
	 * @since 2.3.3
79
	 */
80
	public function test_init() {
81
		$this->assertInstanceOf( 'Jetpack', Jetpack::init() );
82
	}
83
84
	/**
85
	 * @author enkrates
86
	 * @covers Jetpack::sort_modules
87
	 * @since 3.2
88
	 */
89
	public function test_sort_modules_with_equal_sort_values() {
90
91
		$first_file  = array( 'sort' => 5 );
92
		$second_file = array( 'sort' => 5 );
93
94
		$sort_value = Jetpack::sort_modules( $first_file, $second_file );
95
96
		$this->assertEquals( 0, $sort_value );
97
	}
98
99
	/**
100
	 * @author enkrates
101
	 * @covers Jetpack::sort_modules
102
	 * @since 3.2
103
	 */
104
	public function test_sort_modules_with_different_sort_values() {
105
106
		$first_file  = array( 'sort' => 10 );
107
		$second_file = array( 'sort' => 5 );
108
109
		$sort_value = Jetpack::sort_modules( $first_file, $second_file );
110
		$reversed_sort_value = Jetpack::sort_modules( $second_file, $first_file );
111
112
		$this->assertEquals( 1, $sort_value );
113
		$this->assertEquals( -1, $reversed_sort_value );
114
	}
115
116
	/**
117
	 * @author georgestephanis
118
	 * @covers Jetpack::absolutize_css_urls
119
	 */
120
	public function test_absolutize_css_urls_properly_handles_use_cases() {
121
122
		$css = <<<CSS
123
.test-it {
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(./same-dir.png);
134
	background: url(down/down-dir.png);
135
	background: url(../up-dir.png);
136
	background: url(../../up-2-dirs.png);
137
	background: url(/at-root.png);
138
	background: url(//other-domain.com/root.png);
139
	background: url(https://other-domain.com/root.png);
140
	background: url(data:image/gif;base64,eh129ehiuehjdhsa==);
141
}
142
CSS;
143
144
		$expected = <<<EXPECTED
145
.test-it {
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/./same-dir.png");
156
	background: url("http://example.com/dir1/dir2/down/down-dir.png");
157
	background: url("http://example.com/dir1/dir2/../up-dir.png");
158
	background: url("http://example.com/dir1/dir2/../../up-2-dirs.png");
159
	background: url("http://example.com/at-root.png");
160
	background: url(//other-domain.com/root.png);
161
	background: url(https://other-domain.com/root.png);
162
	background: url(data:image/gif;base64,eh129ehiuehjdhsa==);
163
}
164
EXPECTED;
165
166
		$result = Jetpack::absolutize_css_urls( $css, 'http://example.com/dir1/dir2/style.css' );
167
		$this->assertEquals( $expected, $result );
168
169
	}
170
171
	/*
172
	 * @author tonykova
173
	 * @covers Jetpack::implode_frontend_css
174
	 */
175
	public function test_implode_frontend_css_enqueues_bundle_file_handle() {
176
		global $wp_styles;
177
		$wp_styles = new WP_styles();
178
179
		add_filter( 'jetpack_implode_frontend_css', '__return_true' );
180
181
		if ( ! file_exists( plugins_url( 'jetpack-carousel.css', __FILE__ ) ) ) {
182
			$this->markTestSkipped( 'Required CSS file not found.' );
183
		}
184
185
		// Enqueue some script on the $to_dequeue list
186
		$style_handle = 'jetpack-carousel';
187
		wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ) );
188
189
		Jetpack::init()->implode_frontend_css( true );
190
191
		$seen_bundle = false;
192
		foreach ( $wp_styles->registered as $handle => $handle_obj ) {
193
			if ( $style_handle === $handle ) {
194
				$expected = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? "<!-- `{$style_handle}` is included in the concatenated jetpack.css -->\r\n" : '';
195
				$this->assertEquals( $expected, get_echo( array( $wp_styles, 'do_item' ), array( $handle ) ) );
196
			} elseif ( 'jetpack_css' === $handle ) {
197
				$seen_bundle = true;
198
			}
199
		}
200
201
		$this->assertTrue( $seen_bundle );
202
	}
203
204
	/**
205
	 * @author tonykova
206
	 * @covers Jetpack::implode_frontend_css
207
	 * @since 3.2.0
208
	 */
209
	public function test_implode_frontend_css_does_not_enqueue_bundle_when_disabled_through_filter() {
210
		global $wp_styles;
211
		$wp_styles = new WP_styles();
212
213
		add_filter( 'jetpack_implode_frontend_css', '__return_false' );
214
215
		// Enqueue some script on the $to_dequeue list
216
		$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...
217
		wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ) );
218
219
		Jetpack::init()->implode_frontend_css();
220
221
		$seen_orig = false;
222
		foreach ( $wp_styles->registered as $handle => $handle_obj ) {
223
			$this->assertNotEquals( 'jetpack_css', $handle );
224
			if ( 'jetpack-carousel' === $handle ) {
225
				$seen_orig = true;
226
			}
227
		}
228
229
		$this->assertTrue( $seen_orig );
230
	}
231
232 View Code Duplication
	public function test_activating_deactivating_modules_fires_actions() {
233
		self::reset_tracking_of_module_activation();
234
235
		add_action( 'jetpack_activate_module', array( __CLASS__, 'track_activated_modules' ) );
236
		add_action( 'jetpack_deactivate_module', array( __CLASS__, 'track_deactivated_modules' ) );
237
238
		Jetpack::update_active_modules( array( 'stats' ) );
239
		Jetpack::update_active_modules( array( 'stats' ) );
240
		Jetpack::update_active_modules( array( 'json-api' ) );
241
		Jetpack::update_active_modules( array( 'json-api' ) );
242
243
		$this->assertEquals( self::$activated_modules, array( 'stats', 'json-api' ) );
244
		$this->assertEquals(  self::$deactivated_modules, array( 'stats' ) );
245
246
		remove_action( 'jetpack_activate_module', array( __CLASS__, 'track_activated_modules' ) );
247
		remove_action( 'jetpack_deactivate_module', array( __CLASS__, 'track_deactivated_modules' ) );
248
	}
249
250 View Code Duplication
	public function test_activating_deactivating_modules_fires_specific_actions() {
251
		self::reset_tracking_of_module_activation();
252
		add_action( 'jetpack_activate_module_stats', array( __CLASS__, 'track_activated_modules' ) );
253
		add_action( 'jetpack_deactivate_module_stats', array( __CLASS__, 'track_deactivated_modules' ) );
254
255
		Jetpack::update_active_modules( array( 'stats' ) );
256
		Jetpack::update_active_modules( array( 'stats' ) );
257
		Jetpack::update_active_modules( array( 'json-api' ) );
258
		Jetpack::update_active_modules( array( 'json-api' ) );
259
260
		$this->assertEquals( self::$activated_modules, array( 'stats' ) );
261
		$this->assertEquals(  self::$deactivated_modules, array( 'stats' ) );
262
263
		remove_action( 'jetpack_activate_module_stats', array( __CLASS__, 'track_activated_modules' ) );
264
		remove_action( 'jetpack_deactivate_module_stats', array( __CLASS__, 'track_deactivated_modules' ) );
265
	}
266
267
	public function test_active_modules_filter_restores_state() {
268
		self::reset_tracking_of_module_activation();
269
270
		add_action( 'jetpack_activate_module', array( __CLASS__, 'track_activated_modules' ) );
271
		add_action( 'jetpack_deactivate_module', array( __CLASS__, 'track_deactivated_modules' ) );
272
		add_filter( 'jetpack_active_modules', array( __CLASS__, 'e2e_test_filter' ) );
273
274
		Jetpack::update_active_modules( array( 'monitor' ) );
275
		$this->assertEquals( self::$activated_modules, array( 'monitor' ) );
276
		$this->assertEquals(  self::$deactivated_modules, array() );
277
278
		// Simce we override the 'monitor' module, verify it does not appear in get_active_modules().
279
		$active_modules = Jetpack::get_active_modules();
280
		$this->assertEquals(  $active_modules, array() );
281
282
		// Verify that activating a new module does not deactivate 'monitor' module.
283
		Jetpack::update_active_modules( array( 'stats' ) );
284
		$this->assertEquals( self::$activated_modules, array( 'monitor', 'stats') );
285
		$this->assertEquals(  self::$deactivated_modules, array() );
286
287
		remove_filter( 'jetpack_active_modules', array( __CLASS__, 'e2e_test_filter' ) );
288
289
		// With the module override filter removed, verify that monitor module appears in get_active_modules().
290
		$active_modules = Jetpack::get_active_modules();
291
		$this->assertEquals(  $active_modules, array( 'monitor', 'stats' ) );
292
	}
293
294
	 // This filter overrides the 'monitor' module.
295
	public static function e2e_test_filter( $modules ) {
296
		$disabled_modules = array( 'monitor' );
297
298
		foreach ( $disabled_modules as $module_slug ) {
299
			$found = array_search( $module_slug, $modules );
300
			if ( false !== $found ) {
301
				unset( $modules[ $found ] );
302
			}
303
		}
304
305
		return $modules;
306
	}
307
308
	public function test_get_other_linked_admins_one_admin_returns_false() {
309
		delete_transient( 'jetpack_other_linked_admins' );
310
		$other_admins = Jetpack::get_other_linked_admins();
311
		$this->assertFalse( $other_admins );
312
		$this->assertEquals( 0, get_transient( 'jetpack_other_linked_admins' ) );
313
	}
314
315
	public function test_get_other_linked_admins_more_than_one_not_false() {
316
		delete_transient( 'jetpack_other_linked_admins' );
317
		$master_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
318
		$connected_admin = $this->factory->user->create( array( 'role' => 'administrator' ) );
319
320
		Jetpack_Options::update_option( 'master_user', $master_user );
321
		Jetpack_Options::update_option( 'user_tokens', array(
322
			$connected_admin => 'apple.a.' . $connected_admin,
323
			$master_user     => 'kiwi.a.' . $master_user
324
		) );
325
326
		$other_admins = Jetpack::get_other_linked_admins();
327
		$this->assertInternalType( 'int', $other_admins );
328
		$this->assertInternalType( 'int', get_transient( 'jetpack_other_linked_admins' ) );
329
	}
330
331 View Code Duplication
	public function test_promoting_admin_clears_other_linked_admins_transient() {
332
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
333
		$editor_user = $this->factory->user->create( array( 'role' => 'editor' ) );
334
		wp_update_user( array( 'ID' => $editor_user, 'role' => 'administrator' ) );
335
336
		$this->assertFalse( get_transient( 'jetpack_other_linked_admins' ) );
337
	}
338
339 View Code Duplication
	public function test_demoting_admin_clear_other_linked_admins_transiet() {
340
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
341
		$admin_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
342
		wp_update_user( array( 'ID' => $admin_user, 'role' => 'editor' ) );
343
344
		$this->assertFalse( get_transient( 'jetpack_other_linked_admins' ) );
345
	}
346
347 View Code Duplication
	public function test_null_old_roles_clears_linked_admins_transient() {
348
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
349
		$admin_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
350
		wp_update_user( array( 'ID' => $admin_user, 'role' => 'editor' ) );
351
352
		/** This action is documented in wp-includes/class-wp-user.php */
353
		do_action( 'set_user_role', $admin_user, 'contributor' );
354
355
		$this->assertFalse( get_transient( 'jetpack_other_linked_admins' ) );
356
	}
357
358
	function test_changing_non_admin_roles_does_not_clear_other_linked_admins_transient() {
359
		set_transient( 'jetpack_other_linked_admins', 2, HOUR_IN_SECONDS );
360
		$user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
361
362
		foreach ( array( 'contributor', 'author', 'editor' ) as $role ) {
363
			wp_update_user( array( 'ID' => $user_id, 'role' => $role) );
364
		}
365
366
		$this->assertEquals( 2, get_transient( 'jetpack_other_linked_admins' ) );
367
	}
368
369
	function test_other_linked_admins_transient_set_to_zero_returns_false() {
370
		set_transient( 'jetpack_other_linked_admins', 0, HOUR_IN_SECONDS );
371
		$this->assertFalse( Jetpack::get_other_linked_admins() );
372
	}
373
374
	function test_idc_optin_default() {
375
		if ( is_multisite() ) {
376
			$this->assertFalse( Identity_Crisis::sync_idc_optin() );
377
		} else {
378
			$this->assertTrue( Identity_Crisis::sync_idc_optin() );
379
		}
380
	}
381
382
	function test_idc_optin_filter_overrides_development_version() {
383
		add_filter( 'jetpack_development_version', '__return_true' );
384
		add_filter( 'jetpack_sync_idc_optin', '__return_false' );
385
		$this->assertFalse( Identity_Crisis::sync_idc_optin() );
386
		remove_filter( 'jetpack_development_version', '__return_true' );
387
		remove_filter( 'jetpack_sync_idc_optin', '__return_false' );
388
	}
389
390
	function test_idc_optin_casts_to_bool() {
391
		add_filter( 'jetpack_sync_idc_optin', array( $this, 'return_string_1' ) );
392
		$this->assertTrue( Identity_Crisis::sync_idc_optin() );
393
		remove_filter( 'jetpack_sync_idc_optin', array( $this, 'return_string_1' ) );
394
	}
395
396
	function test_idc_optin_true_when_constant_true() {
397
		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...
398
		$this->assertTrue( Identity_Crisis::sync_idc_optin() );
399
	}
400
401
	function test_idc_optin_false_when_constant_false() {
402
		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...
403
		$this->assertFalse( Identity_Crisis::sync_idc_optin() );
404
	}
405
406
	function test_idc_optin_filter_overrides_constant() {
407
		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...
408
		add_filter( 'jetpack_sync_idc_optin', '__return_false' );
409
		$this->assertFalse( Identity_Crisis::sync_idc_optin() );
410
		remove_filter( 'jetpack_sync_idc_optin', '__return_false' );
411
	}
412
413
	function test_sync_error_idc_validation_returns_false_if_no_option() {
414
		Jetpack_Options::delete_option( 'sync_error_idc' );
415
		$this->assertFalse( Identity_Crisis::validate_sync_error_idc_option() );
416
	}
417
418
	function test_sync_error_idc_validation_returns_true_when_option_matches_expected() {
419
		add_filter( 'jetpack_sync_idc_optin', '__return_true' );
420
		Jetpack_Options::update_option( 'sync_error_idc', Identity_Crisis::get_sync_error_idc_option() );
421
		$this->assertTrue( Identity_Crisis::validate_sync_error_idc_option() );
422
		Jetpack_Options::delete_option( 'sync_error_idc' );
423
		remove_filter( 'jetpack_sync_idc_optin', '__return_true' );
424
	}
425
426
	/**
427
	 * Verify that validate_sync_error returns false if wpcom_ is set and matches expected.
428
	 */
429 View Code Duplication
	public function test_sync_error_idc_validation_returns_false_when_wpcom_option_matches_expected() {
430
		add_filter( 'jetpack_sync_idc_optin', '__return_true' );
431
		$option                  = Identity_Crisis::get_sync_error_idc_option();
432
		$option['wpcom_home']    = $option['home'];
433
		$option['wpcom_siteurl'] = $option['siteurl'];
434
		Jetpack_Options::update_option( 'sync_error_idc', $option );
435
		$this->assertFalse( Identity_Crisis::validate_sync_error_idc_option() );
436
437
		// Verify the migrate_for_idc is set.
438
		$this->assertTrue( Jetpack_Options::get_option( 'migrate_for_idc' ) );
439
440
		Jetpack_Options::delete_option( 'sync_error_idc' );
441
		Jetpack_Options::delete_option( 'migrate_for_idc' );
442
		remove_filter( 'jetpack_sync_idc_optin', '__return_true' );
443
	}
444
445
	/**
446
	 * Verify that validate_sync_error returns true if wpcom_ is set and does not match.
447
	 */
448 View Code Duplication
	public function test_sync_error_idc_validation_returns_true_when_wpcom_option_does_not_match_expected() {
449
		add_filter( 'jetpack_sync_idc_optin', '__return_true' );
450
		$option                  = Identity_Crisis::get_sync_error_idc_option();
451
		$option['wpcom_home']    = $option['home'];
452
		$option['wpcom_siteurl'] = 'coolrunnings.test';
453
		Jetpack_Options::update_option( 'sync_error_idc', $option );
454
		$this->assertTrue( Identity_Crisis::validate_sync_error_idc_option() );
455
456
		// Verify the migrate_for_idc is not set.
457
		$this->assertNotTrue( Jetpack_Options::get_option( 'migrate_for_idc' ) );
458
459
		Jetpack_Options::delete_option( 'sync_error_idc' );
460
		Jetpack_Options::delete_option( 'migrate_for_idc' );
461
		remove_filter( 'jetpack_sync_idc_optin', '__return_true' );
462
	}
463
464
	function test_sync_error_idc_validation_cleans_up_when_validation_fails() {
465
		Jetpack_Options::update_option( 'sync_error_idc', array(
466
			'home'    => 'coolsite.com/',
467
			'siteurl' => 'coolsite.com/wp/',
468
		) );
469
470
		$this->assertFalse( Identity_Crisis::validate_sync_error_idc_option() );
471
		$this->assertFalse( Jetpack_Options::get_option( 'sync_error_idc' ) );
472
	}
473
474 View Code Duplication
	function test_sync_error_idc_validation_cleans_up_when_part_of_validation_fails() {
475
		$test            = Identity_Crisis::get_sync_error_idc_option();
476
		$test['siteurl'] = 'coolsite.com/wp/';
477
		Jetpack_Options::update_option( 'sync_error_idc', $test );
478
479
		$this->assertFalse( Identity_Crisis::validate_sync_error_idc_option() );
480
		$this->assertFalse( Jetpack_Options::get_option( 'sync_error_idc' ) );
481
	}
482
483
	function test_sync_error_idc_validation_returns_false_and_cleans_up_when_opted_out() {
484
		Jetpack_Options::update_option( 'sync_error_idc', Identity_Crisis::get_sync_error_idc_option() );
485
		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...
486
487
		$this->assertFalse( Identity_Crisis::validate_sync_error_idc_option() );
488
		$this->assertFalse( Jetpack_Options::get_option( 'sync_error_idc' ) );
489
	}
490
491
	function test_is_staging_site_true_when_sync_error_idc_is_valid() {
492
		add_filter( 'jetpack_sync_error_idc_validation', '__return_true' );
493
		$this->assertTrue( ( new Status() )->is_staging_site() );
494
		remove_filter( 'jetpack_sync_error_idc_validation', '__return_false' );
495
	}
496
497
	function test_is_dev_version_true_with_alpha() {
498
		Constants::set_constant( 'JETPACK__VERSION', '4.3.1-alpha' );
499
		$this->assertTrue( Jetpack::is_development_version() );
500
	}
501
502
	function test_is_dev_version_true_with_beta() {
503
		Constants::set_constant( 'JETPACK__VERSION', '4.3-beta2' );
504
		$this->assertTrue( Jetpack::is_development_version() );
505
	}
506
507
	function test_is_dev_version_true_with_rc() {
508
		Constants::set_constant( 'JETPACK__VERSION', '4.3-rc2' );
509
		$this->assertTrue( Jetpack::is_development_version() );
510
	}
511
512
	function test_is_dev_version_false_with_number_dot_number() {
513
		Constants::set_constant( 'JETPACK__VERSION', '4.3' );
514
		$this->assertFalse( Jetpack::is_development_version() );
515
	}
516
517
	function test_is_dev_version_false_with_number_dot_number_dot_number() {
518
		Constants::set_constant( 'JETPACK__VERSION', '4.3.1' );
519
		$this->assertFalse( Jetpack::is_development_version() );
520
	}
521
522
	/**
523
	 * Tests is_offline_mode filter.
524
	 *
525
	 * @covers \Automattic\Jetpack\Status::is_offline_mode
526
	 */
527
	public function test_is_offline_mode_filter() {
528
		add_filter( 'jetpack_offline_mode', '__return_true' );
529
		$this->assertTrue( ( new Status() )->is_offline_mode() );
530
		remove_filter( 'jetpack_offline_mode', '__return_true' );
531
	}
532
533
	/**
534
	 * Tests is_offline_mode filter's bool type casting.
535
	 *
536
	 * @covers \Automattic\Jetpack\Status::is_offline_mode
537
	 */
538
	public function test_is_offline_mode_bool() {
539
		add_filter( 'jetpack_offline_mode', '__return_zero' );
540
		$this->assertFalse( ( new Status() )->is_offline_mode() );
541
		remove_filter( 'jetpack_offline_mode', '__return_zero' );
542
	}
543
544 View Code Duplication
	function test_get_sync_idc_option_sanitizes_out_www_and_protocol() {
545
		$original_home    = get_option( 'home' );
546
		$original_siteurl = get_option( 'siteurl' );
547
548
		update_option( 'home', 'http://www.coolsite.com' );
549
		update_option( 'siteurl', 'http://www.coolsite.com/wp' );
550
551
		$expected = array(
552
			'home' => 'coolsite.com/',
553
			'siteurl' => 'coolsite.com/wp/'
554
		);
555
556
		$this->assertSame( $expected, Identity_Crisis::get_sync_error_idc_option() );
557
558
		// Cleanup
559
		update_option( 'home', $original_home );
560
		update_option( 'siteurl', $original_siteurl );
561
	}
562
563 View Code Duplication
	function test_get_sync_idc_option_with_ip_address_in_option() {
564
		$original_home    = get_option( 'home' );
565
		$original_siteurl = get_option( 'siteurl' );
566
567
		update_option( 'home', 'http://72.182.131.109/~wordpress' );
568
		update_option( 'siteurl', 'http://72.182.131.109/~wordpress/wp' );
569
570
		$expected = array(
571
			'home' => '72.182.131.109/~wordpress/',
572
			'siteurl' => '72.182.131.109/~wordpress/wp/'
573
		);
574
575
		$this->assertSame( $expected, Identity_Crisis::get_sync_error_idc_option() );
576
577
		// Cleanup
578
		update_option( 'home', $original_home );
579
		update_option( 'siteurl', $original_siteurl );
580
	}
581
582 View Code Duplication
	function test_normalize_url_protocol_agnostic_strips_protocol_and_www_for_subdir_subdomain() {
583
		$url = 'https://www.subdomain.myfaketestsite.com/what';
584
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
585
		$this->assertTrue( 'subdomain.myfaketestsite.com/what/' === $url_normalized );
586
587
		$url = 'http://subdomain.myfaketestsite.com';
588
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
589
		$this->assertTrue( 'subdomain.myfaketestsite.com/' === $url_normalized );
590
591
		$url = 'www.subdomain.myfaketestsite.com';
592
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
593
		$this->assertTrue( 'subdomain.myfaketestsite.com/' === $url_normalized );
594
	}
595
596 View Code Duplication
	function test_normalize_url_protocol_agnostic_strips_protocol_and_www_for_normal_urls() {
597
		$url = 'https://www.myfaketestsite.com';
598
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
599
		$this->assertTrue( 'myfaketestsite.com/' === $url_normalized );
600
601
		$url = 'www.myfaketestsite.com';
602
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
603
		$this->assertTrue( 'myfaketestsite.com/' === $url_normalized );
604
605
		$url = 'myfaketestsite.com';
606
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
607
		$this->assertTrue( 'myfaketestsite.com/' === $url_normalized );
608
	}
609
610
	function test_normalize_url_protocol_agnostic_strips_protocol_for_ip() {
611
		$url = 'http://123.456.789.0';
612
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
613
		$this->assertTrue( '123.456.789.0/' === $url_normalized );
614
615
		$url = '123.456.789.0';
616
		$url_normalized = Jetpack::normalize_url_protocol_agnostic( $url );
617
		$this->assertTrue( '123.456.789.0/' === $url_normalized );
618
	}
619
620
	/**
621
	 * Parse the referer on plugin activation and record the activation source
622
	 * - featured plugins page
623
	 * - popular plugins page
624
	 * - search (with query)
625
	 * - plugins list
626
	 * - other
627
	 */
628
	function test_get_activation_source() {
629
		$plugins_url = admin_url( 'plugins.php' );
630
		$plugin_install_url = admin_url( 'plugin-install.php' );
631
		$unknown_url = admin_url( 'unknown.php' );
632
633
		$this->assertEquals( array( 'list', null ), Jetpack::get_activation_source( $plugins_url . '?plugin_status=all&paged=1&s' ) );
634
		$this->assertEquals( array( 'featured', null ), Jetpack::get_activation_source( $plugin_install_url ) );
635
		$this->assertEquals( array( 'popular', null ), Jetpack::get_activation_source( $plugin_install_url . '?tab=popular' ) );
636
		$this->assertEquals( array( 'recommended', null ), Jetpack::get_activation_source( $plugin_install_url . '?tab=recommended' ) );
637
		$this->assertEquals( array( 'favorites', null ), Jetpack::get_activation_source( $plugin_install_url . '?tab=favorites' ) );
638
		$this->assertEquals( array( 'search-term', 'jetpack' ), Jetpack::get_activation_source( $plugin_install_url . '?s=jetpack&tab=search&type=term' ) );
639
		$this->assertEquals( array( 'search-author', 'foo' ), Jetpack::get_activation_source( $plugin_install_url . '?s=foo&tab=search&type=author' ) );
640
		$this->assertEquals( array( 'search-tag', 'social' ), Jetpack::get_activation_source( $plugin_install_url . '?s=social&tab=search&type=tag' ) );
641
		$this->assertEquals( array( 'unknown', null ), Jetpack::get_activation_source( $unknown_url ) );
642
	}
643
644
	/**
645
	 * @author tyxla
646
	 * @covers Jetpack::get_assumed_site_creation_date()
647
	 */
648 View Code Duplication
	function test_get_assumed_site_creation_date_user_earliest() {
649
		$user_id = $this->factory->user->create( array(
650
			'role'            => 'administrator',
651
			'user_registered' => '1990-01-01 00:00:00',
652
		) );
653
		$post_id = $this->factory->post->create( array(
654
			'post_date' => '1995-01-01 00:00:00',
655
		) );
656
657
		$jetpack = new MockJetpack();
658
		$this->assertEquals( '1990-01-01 00:00:00', $jetpack::connection()->get_assumed_site_creation_date() );
659
660
		wp_delete_user( $user_id );
661
		wp_delete_post( $post_id, true );
662
	}
663
664
	/**
665
	 * @author tyxla
666
	 * @covers Jetpack::get_assumed_site_creation_date()
667
	 */
668 View Code Duplication
	function test_get_assumed_site_creation_date_post_earliest() {
669
		$user_id = $this->factory->user->create( array(
670
			'role'            => 'administrator',
671
			'user_registered' => '1994-01-01 00:00:00',
672
		) );
673
		$post_id = $this->factory->post->create( array(
674
			'post_date' => '1991-01-01 00:00:00',
675
		) );
676
677
		$jetpack = new MockJetpack();
678
		$this->assertEquals( '1991-01-01 00:00:00', $jetpack::connection()->get_assumed_site_creation_date() );
679
680
		wp_delete_user( $user_id );
681
		wp_delete_post( $post_id, true );
682
	}
683
684
	/**
685
	 * @author tyxla
686
	 * @covers Jetpack::get_assumed_site_creation_date()
687
	 */
688 View Code Duplication
	function test_get_assumed_site_creation_date_only_admins() {
689
		$admin_id = $this->factory->user->create( array(
690
			'role'            => 'administrator',
691
			'user_registered' => '1994-01-01 00:00:00',
692
		) );
693
		$editor_id = $this->factory->user->create( array(
694
			'role'            => 'editor',
695
			'user_registered' => '1992-01-01 00:00:00',
696
		) );
697
698
		$jetpack = new MockJetpack();
699
		$this->assertEquals( '1994-01-01 00:00:00', $jetpack::connection()->get_assumed_site_creation_date() );
700
701
		wp_delete_user( $admin_id );
702
		wp_delete_user( $editor_id );
703
	}
704
705
	/**
706
	 * @author ebinnion
707
	 * @dataProvider get_file_url_for_environment_data_provider
708
	 */
709
	function test_get_file_url_for_environment( $min_path, $non_min_path, $is_script_debug, $expected, $not_expected ) {
710
		Constants::set_constant( 'SCRIPT_DEBUG', $is_script_debug );
711
		$file_url = Jetpack::get_file_url_for_environment( $min_path, $non_min_path );
712
713
		$this->assertContains( $$expected, $file_url );
714
		$this->assertNotContains( $$not_expected, $file_url );
715
	}
716
717 View Code Duplication
	function get_file_url_for_environment_data_provider() {
718
		return array(
719
			'script-debug-true' => array(
720
				'_inc/build/shortcodes/js/recipes.js',
721
				'modules/shortcodes/js/recipes.js',
722
				true,
723
				'non_min_path',
724
				'min_path'
725
			),
726
			'script-debug-false' => array(
727
				'_inc/build/shortcodes/js/recipes.js',
728
				'modules/shortcodes/js/recipes.js',
729
				false,
730
				'min_path',
731
				'non_min_path'
732
			),
733
		);
734
	}
735
736
	/**
737
	 * @dataProvider get_content_width_data
738
	 */
739
	public function test_get_content_width( $expected, $content_width ) {
740
		$GLOBALS['content_width'] = $content_width;
741
		$this->assertSame( $expected, Jetpack::get_content_width() );
742
	}
743
744
	public function get_content_width_data() {
745
		return array(
746
			'zero' => array(
747
				0,
748
				0,
749
			),
750
			'int' => array(
751
				100,
752
				100,
753
			),
754
			'numeric_string' => array(
755
				'100',
756
				'100',
757
			),
758
			'non_numeric_string' => array(
759
				false,
760
				'meh'
761
			),
762
			'content_width_not_set' => array(
763
				false,
764
				null,
765
			),
766
		);
767
	}
768
769
	/**
770
	 * Return a Cyrillic salt.
771
	 *
772
	 * @param string $password String to add salt to.
773
	 * @return string
774
	 */
775
	public static function cyrillic_salt( $password ) {
776
		return 'ленка' . $password . 'пенка';
777
	}
778
779
	/**
780
	 * Return a Kanji salt.
781
	 *
782
	 * @param string $password String to add salt to.
783
	 * @return string
784
	 */
785
	public static function kanji_salt( $password ) {
786
		return '強熊' . $password . '清珠';
787
	}
788
789
	/**
790
	 * Filter to increase a string length.
791
	 *
792
	 * @param string $password String to expand.
793
	 * @return string
794
	 */
795
	public static function multiply_filter( $password ) {
796
		for ( $i = 0; $i < 10; $i++ ) {
797
			$password .= $password;
798
		}
799
		return $password;
800
	}
801
802
	/**
803
	 * Return string '1'.
804
	 *
805
	 * @return string
806
	 */
807
	public function return_string_1() {
808
		return '1';
809
	}
810
811
	/**
812
	 * Reset tracking of module activation.
813
	 */
814
	public static function reset_tracking_of_module_activation() {
815
		self::$activated_modules   = array();
816
		self::$deactivated_modules = array();
817
	}
818
819
	/**
820
	 * Track activated modules.
821
	 *
822
	 * @param mixed $module Module.
823
	 */
824
	public static function track_activated_modules( $module ) {
825
		self::$activated_modules[] = $module;
826
	}
827
828
	/**
829
	 * Track deactivated modules.
830
	 *
831
	 * @param mixed $module Module.
832
	 */
833
	public static function track_deactivated_modules( $module ) {
834
		self::$deactivated_modules[] = $module;
835
	}
836
837
	/**
838
	 * Mocked `setup_xmlrpc_handlers`.
839
	 *
840
	 * @param array         $request_params Incoming request parameters.
841
	 * @param bool          $has_connected_owner Whether the site has a connected owner.
842
	 * @param bool          $is_signed Whether the signature check has been successful.
843
	 * @param WP_User|false $user User for the mocked Jetpack_XMLRPC_Server.
844
	 * @return bool
845
	 */
846
	private function mocked_setup_xmlrpc_handlers( $request_params, $has_connected_owner, $is_signed, $user = false ) {
847
		$GLOBALS['HTTP_RAW_POST_DATA'] = '';
848
849
		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...
850
851
		$jetpack       = new MockJetpack();
852
		$xmlrpc_server = new MockJetpack_XMLRPC_Server( $user );
853
		return $jetpack::connection()->setup_xmlrpc_handlers( $request_params, $has_connected_owner, $is_signed, $xmlrpc_server );
854
	}
855
856
	/**
857
	 * Asserts that:
858
	 *   - all of the required xmlrpc methods are in the actual method list.
859
	 *   - all of the actual xmlrpc methods are in the required or allowed lists.
860
	 *
861
	 * @param string[] $required List of XML-RPC methods that must be contained in $actual.
862
	 * @param string[] $allowed  Additional list of XML-RPC methods that may be contained in $actual.
863
	 *                           Useful for listing methods that are added by modules that may or may
864
	 *                           not be active during the test run.
865
	 * @param string[] $actual   The list of XML-RPC methods.
866
	 */
867
	private function assertXMLRPCMethodsComply( $required, $allowed, $actual ) {
868
		$this->assertEquals( array(), array_diff( $required, $actual ) );
869
		$this->assertEquals( array(), array_diff( $actual, $required, $allowed ) );
870
	}
871
872
	/**
873
	 * Tests the setup of the xmlrpc methods when the site is active, the request is signed, and without a user.
874
	 *
875
	 * @group xmlrpc
876
	 */
877 View Code Duplication
	public function test_classic_xmlrpc_when_active_and_signed_with_no_user() {
878
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), true, true );
879
880
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
881
882
		$required = array(
883
			'jetpack.verifyAction',
884
			'jetpack.getUser',
885
			'jetpack.remoteRegister',
886
			'jetpack.remoteProvision',
887
			'jetpack.remoteConnect',
888
			'jetpack.jsonAPI',
889
			'jetpack.idcUrlValidation',
890
			'jetpack.unlinkUser',
891
			'jetpack.testConnection',
892
			'jetpack.featuresAvailable',
893
			'jetpack.featuresEnabled',
894
			'jetpack.disconnectBlog',
895
		);
896
897
		$allowed = array(
898
			'jetpack.getHeartbeatData',
899
			'jetpack.syncObject',
900
			'jetpack.updatePublicizeConnections',
901
			'jetpack.getBlog',
902
		);
903
904
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
905
	}
906
907
	/**
908
	 * Tests the setup of the xmlrpc methods when the site is active, the request is signed, and with a user.
909
	 *
910
	 * @group xmlrpc
911
	 */
912
	public function test_classic_xmlrpc_when_active_and_signed_with_user() {
913
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), true, true, get_user_by( 'ID', self::$admin_id ) );
914
915
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
916
917
		$required = array(
918
			'jetpack.verifyAction',
919
			'jetpack.getUser',
920
			'jetpack.remoteRegister',
921
			'jetpack.remoteProvision',
922
			'jetpack.remoteConnect',
923
			'jetpack.jsonAPI',
924
925
			'jetpack.testAPIUserCode',
926
			'jetpack.disconnectBlog',
927
			'jetpack.unlinkUser',
928
			'jetpack.idcUrlValidation',
929
			'jetpack.testConnection',
930
			'jetpack.featuresAvailable',
931
			'jetpack.featuresEnabled',
932
933
			'jetpack.syncObject',
934
		);
935
936
		// It's OK if these module-added methods are present (module active in tests).
937
		// It's OK if they are not (module inactive in tests).
938
		$allowed = array(
939
			'jetpack.subscriptions.subscribe',
940
			'jetpack.updatePublicizeConnections',
941
			'jetpack.getHeartbeatData',
942
		);
943
944
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
945
	}
946
947
	/**
948
	 * Tests the setup of the xmlrpc methods when the site is active, the request is signed, with a user,
949
	 * and with edit methods enabled.
950
	 *
951
	 * @group xmlrpc
952
	 */
953
	public function test_classic_xmlrpc_when_active_and_signed_with_user_with_edit() {
954
		$this->mocked_setup_xmlrpc_handlers(
955
			array( 'for' => 'jetpack' ),
956
			true,
957
			true,
958
			get_user_by( 'ID', self::$admin_id )
959
		);
960
961
		$methods = apply_filters(
962
			'xmlrpc_methods',
963
			array(
964
				'test.test'                 => '__return_true',
965
				'metaWeblog.editPost'       => '__return_true',
966
				'metaWeblog.newMediaObject' => '__return_true',
967
			)
968
		);
969
970
		$required = array(
971
			'jetpack.verifyAction',
972
			'jetpack.getUser',
973
			'jetpack.remoteRegister',
974
			'jetpack.remoteProvision',
975
			'jetpack.remoteConnect',
976
			'jetpack.jsonAPI',
977
978
			'jetpack.testAPIUserCode',
979
			'jetpack.disconnectBlog',
980
			'jetpack.unlinkUser',
981
			'jetpack.idcUrlValidation',
982
			'jetpack.testConnection',
983
			'jetpack.featuresAvailable',
984
			'jetpack.featuresEnabled',
985
986
			'metaWeblog.newMediaObject',
987
			'jetpack.updateAttachmentParent',
988
989
			'jetpack.syncObject',
990
		);
991
992
		// It's OK if these module-added methods are present (module active in tests).
993
		// It's OK if they are not (module inactive in tests).
994
		$allowed = array(
995
			'jetpack.subscriptions.subscribe',
996
			'jetpack.updatePublicizeConnections',
997
			'jetpack.getHeartbeatData',
998
		);
999
1000
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1001
	}
1002
1003
	/**
1004
	 * Tests the setup of the xmlrpc methods when the site is active and the request is not signed.
1005
	 *
1006
	 * @group xmlrpc
1007
	 */
1008
	public function test_classic_xmlrpc_when_active_and_not_signed() {
1009
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), true, false );
1010
1011
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1012
1013
		$required = array(
1014
			'jetpack.remoteAuthorize',
1015
		);
1016
1017
		// Nothing else is allowed.
1018
		$allowed = array();
1019
1020
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1021
	}
1022
1023
	/**
1024
	 * Tests the setup of the xmlrpc methods when the site is not active and the request is not signed.
1025
	 *
1026
	 * @group xmlrpc
1027
	 */
1028
	public function test_classic_xmlrpc_when_not_active_and_not_signed() {
1029
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), false, false );
1030
1031
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1032
1033
		$required = array(
1034
			'jetpack.remoteAuthorize',
1035
			'jetpack.remoteRegister',
1036
1037
			'jetpack.verifyRegistration',
1038
		);
1039
1040
		// Nothing else is allowed.
1041
		$allowed = array();
1042
1043
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1044
	}
1045
1046
	/**
1047
	 * Tests the setup of the xmlrpc methods when the site is not active and the request is signed.
1048
	 *
1049
	 * @group xmlrpc
1050
	 */
1051 View Code Duplication
	public function test_classic_xmlrpc_when_not_active_and_signed() {
1052
		$this->mocked_setup_xmlrpc_handlers( array( 'for' => 'jetpack' ), false, true );
1053
1054
		$methods = apply_filters( 'xmlrpc_methods', array( 'test.test' => '__return_true' ) );
1055
1056
		$required = array(
1057
			'jetpack.verifyAction',
1058
			'jetpack.getUser',
1059
			'jetpack.remoteRegister',
1060
			'jetpack.remoteProvision',
1061
			'jetpack.remoteConnect',
1062
			'jetpack.jsonAPI',
1063
1064
			'jetpack.disconnectBlog',
1065
			'jetpack.unlinkUser',
1066
			'jetpack.idcUrlValidation',
1067
			'jetpack.testConnection',
1068
			'jetpack.featuresAvailable',
1069
			'jetpack.featuresEnabled',
1070
1071
			'jetpack.syncObject',
1072
		);
1073
1074
		$allowed = array(
1075
			'jetpack.subscriptions.subscribe',
1076
			'jetpack.updatePublicizeConnections',
1077
			'jetpack.getHeartbeatData',
1078
		);
1079
1080
		$this->assertXMLRPCMethodsComply( $required, $allowed, array_keys( $methods ) );
1081
	}
1082
1083
	/**
1084
	 * Test "wp_getOptions_hook_in_place".
1085
	 *
1086
	 * @see https://github.com/Automattic/jetpack/pull/13514
1087
	 *
1088
	 * @group xmlrpc
1089
	 */
1090
	public function test_wp_getOptions_hook_in_place() {
1091
		$options = apply_filters( 'xmlrpc_blog_options', array() );
1092
1093
		$this->assertArrayHasKey( 'jetpack_version', $options );
1094
	}
1095
1096
	/**
1097
	 * Tests if Partner codes are added to the connect url.
1098
	 *
1099
	 * @dataProvider partner_code_provider
1100
	 *
1101
	 * @param string $code_type Partner code type.
1102
	 * @param string $option_name Option and filter name.
1103
	 * @param string $query_string_name Query string variable name.
1104
	 */
1105
	public function test_partner_codes_are_added_to_authorize_url( $code_type, $option_name, $query_string_name ) {
1106
		$test_code = 'abc-123';
1107
		Partner::init();
1108
		add_filter(
1109
			$option_name,
1110
			function () use ( $test_code ) {
1111
				return $test_code;
1112
			}
1113
		);
1114
		$jetpack = \Jetpack::init();
1115
		$url     = $jetpack->build_authorize_url();
1116
1117
		$parsed_vars = array();
1118
		parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $parsed_vars );
1119
1120
		$this->assertArrayHasKey( $query_string_name, $parsed_vars );
1121
		$this->assertSame( $test_code, $parsed_vars[ $query_string_name ] );
1122
	}
1123
1124
	/**
1125
	 * Provides code for test_partner_codes_are_added_to_authorize_url.
1126
	 *
1127
	 * @return array
1128
	 */
1129 View Code Duplication
	public function partner_code_provider() {
1130
		return array(
1131
			'subsidiary_code' =>
1132
				array(
1133
					Partner::SUBSIDIARY_CODE,            // Code type.
1134
					'jetpack_partner_subsidiary_id',     // filter/option key.
1135
					'subsidiaryId',                      // Query string parameter.
1136
				),
1137
			'affiliate_code'  =>
1138
				array(
1139
					Partner::AFFILIATE_CODE,
1140
					'jetpack_affiliate_code',
1141
					'aff',
1142
				),
1143
		);
1144
	}
1145
1146
	/**
1147
	 * Tests login URL only adds redirect param when redirect param is in original request.
1148
	 *
1149
	 * @since 8.4.0
1150
	 * @return void
1151
	 */
1152
	public function test_login_url_add_redirect() {
1153
		$login_url = wp_login_url( '/wp-admin' );
1154
		$this->assertFalse( strpos( $login_url, Jetpack::$jetpack_redirect_login ) );
1155
1156
		$login_url = wp_login_url( '/wp-admin?' . Jetpack::$jetpack_redirect_login . '=true' );
1157
		parse_str( wp_parse_url( $login_url, PHP_URL_QUERY ), $login_parts );
1158
		$this->assertArraySubset( array( Jetpack::$jetpack_redirect_login => 'true' ), $login_parts, true );
1159
	}
1160
1161
	/**
1162
	 * Tests login redirect sending users to Calypso when redirect param is set.
1163
	 *
1164
	 * @since 8.4.0
1165
	 * @return void
1166
	 */
1167
	public function test_login_init_redirect() {
1168
		tests_add_filter(
1169
			'wp_redirect',
1170
			function ( $location ) {
1171
				$expected_location = add_query_arg(
1172
					array(
1173
						'forceInstall' => 1,
1174
						'url'          => rawurlencode( get_site_url() ),
1175
					),
1176
					'https://wordpress.com/jetpack/connect'
1177
				);
1178
				$this->assertEquals( $location, $expected_location );
1179
				throw new Exception(); // Cause an exception, as we don't want to run exit.
1180
			}
1181
		);
1182
1183
		// Remove core filters that add headers.
1184
		remove_filter( 'login_init', 'wp_admin_headers' );
1185
		remove_filter( 'login_init', 'send_frame_options_header' );
1186
1187
		// Run it once and no exception is thrown.
1188
		do_action( 'login_init' );
1189
1190
		$this->expectException( Exception::class );
1191
		$_GET[ Jetpack::$jetpack_redirect_login ] = 'true';
1192
		do_action( 'login_init' ); // Now expect an exception.
1193
	}
1194
1195
	/**
1196
	 * Tests getting the correct Calypso host.
1197
	 *
1198
	 * @since 8.4.0
1199
	 * @return void
1200
	 */
1201
	public function test_get_calypso_host() {
1202
		// No env.
1203
		$this->assertEquals( 'https://wordpress.com/', Jetpack::get_calypso_host() );
1204
1205
		$_GET['calypso_env'] = 'development';
1206
		$this->assertEquals( 'http://calypso.localhost:3000/', Jetpack::get_calypso_host() );
1207
1208
		$_GET['calypso_env'] = 'wpcalypso';
1209
		$this->assertEquals( 'https://wpcalypso.wordpress.com/', Jetpack::get_calypso_host() );
1210
1211
		$_GET['calypso_env'] = 'horizon';
1212
		$this->assertEquals( 'https://horizon.wordpress.com/', Jetpack::get_calypso_host() );
1213
1214
		$_GET['calypso_env'] = 'stage';
1215
		$this->assertEquals( 'https://wordpress.com/', Jetpack::get_calypso_host() );
1216
1217
		$_GET['calypso_env'] = 'production';
1218
		$this->assertEquals( 'https://wordpress.com/', Jetpack::get_calypso_host() );
1219
	}
1220
1221
	/**
1222
	 * Tests the Jetpack::should_set_cookie() method.
1223
	 *
1224
	 * @param string  $key The state key test value.
1225
	 * @param string  $set_screen The $current_screen->base test value.
1226
	 * @param boolean $expected_output The expected output of Jetpack::should_set_cookie().
1227
	 *
1228
	 * @covers Jetpack::should_set_cookie
1229
	 * @dataProvider should_set_cookie_provider
1230
	 */
1231
	public function test_should_set_cookie( $key, $set_screen, $expected_output ) {
1232
		global $current_screen;
1233
		$old_current_screen   = $current_screen;
1234
		$current_screen       = new stdClass();
1235
		$current_screen->base = $set_screen;
1236
1237
		$this->assertEquals( $expected_output, Jetpack::should_set_cookie( $key ) );
1238
		$current_screen = $old_current_screen;
1239
	}
1240
1241
	/**
1242
	 * The data provider for test_should_set_cookie(). Provides an array of
1243
	 * test data. Each data set is an array with the structure:
1244
	 *     [0] => The state key test value.
1245
	 *     [1] => The $current_screen->base test value.
1246
	 *     [2] => The expected output of Jetpack::should_set_cookie().
1247
	 */
1248
	public function should_set_cookie_provider() {
1249
		return array(
1250
			array( 'display_update_modal', 'toplevel_page_jetpack', false ),
1251
			array( 'display_update_modal', 'test_page', true ),
1252
			array( 'display_update_modal', null, true ),
1253
			array( 'message', 'toplevel_page_jetpack', true ),
1254
			array( 'message', 'test_page', true ),
1255
			array( 'message', null, true ),
1256
		);
1257
	}
1258
1259
	/**
1260
	 * Testing that a deprecated action triggers Jetpack functionality.
1261
	 *
1262
	 * Using the `jetpack_updated_theme` action for the sake of testing.
1263
	 *
1264
	 * @expectedDeprecated jetpack_updated_theme
1265
	 */
1266
	public function test_deprecated_action_fires() {
1267
		add_action( 'jetpack_updated_theme', '__return_false' );
1268
		Jetpack::init()->deprecated_hooks();
1269
		remove_action( 'jetpack_updated_theme', '__return_false' );
1270
	}
1271
1272
	/**
1273
	 * Testing that a deprecated filter triggers Jetpack functionality.
1274
	 *
1275
	 * Using the `jetpack_bail_on_shortcode` filter for the sake of testing.
1276
	 *
1277
	 * @expectedDeprecated jetpack_bail_on_shortcode
1278
	 */
1279
	public function test_deprecated_filter_fires() {
1280
		add_filter( 'jetpack_bail_on_shortcode', '__return_false' );
1281
		Jetpack::init()->deprecated_hooks();
1282
		remove_filter( 'jetpack_bail_on_shortcode', '__return_false' );
1283
	}
1284
} // end class
1285