Completed
Pull Request — master (#2)
by Stephen
13:19
created

WP_Canonical_UnitTestCase   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 219
rs 10
c 0
b 0
f 0
wmc 19
lcom 3
cbo 1

7 Methods

Rating   Name   Duplication   Size   Complexity  
A wpSetUpBeforeClass() 0 3 1
A wpTearDownAfterClass() 0 3 1
A setUp() 0 10 1
B generate_shared_fixtures() 0 89 1
A delete_shared_fixtures() 0 7 1
C assertCanonical() 0 46 12
A get_canonical() 0 9 2
1
<?php
2
3
class WP_Canonical_UnitTestCase extends WP_UnitTestCase {
4
	static $old_current_user;
5
	static $author_id;
6
	static $post_ids = array();
7
	static $comment_ids = array();
8
	static $term_ids = array();
9
	static $terms = array();
10
	static $old_options = array();
11
12
	/**
13
	 * This can be defined in a subclass of this class which contains its own data() method.
14
	 * Those tests will be run against the specified permastruct.
15
	 */
16
	public $structure = '/%year%/%monthnum%/%day%/%postname%/';
17
18
	public static function wpSetUpBeforeClass( $factory ) {
19
		self::generate_shared_fixtures( $factory );
20
	}
21
22
	public static function wpTearDownAfterClass() {
23
		self::delete_shared_fixtures();
24
	}
25
26
	public function setUp() {
27
		parent::setUp();
28
29
		update_option( 'page_comments', true );
30
		update_option( 'comments_per_page', 5 );
31
		update_option( 'posts_per_page', 5 );
32
33
		$this->set_permalink_structure( $this->structure );
34
		create_initial_taxonomies();
35
	}
36
37
	/**
38
	 * Generate fixtures to be shared between canonical tests.
39
	 *
40
	 * Abstracted here because it's invoked by setUpBeforeClass() in more than one class.
41
	 *
42
	 * @since 4.1.0
43
	 */
44
	public static function generate_shared_fixtures( $factory ) {
45
		self::$old_current_user = get_current_user_id();
46
		self::$author_id = $factory->user->create( array( 'user_login' => 'canonical-author' ) );
47
48
		/*
49
		 * Also set in self::setUp(), but we must configure here to make sure that
50
		 * post authorship is properly attributed for fixtures.
51
		 */
52
		wp_set_current_user( self::$author_id );
53
54
		// Already created by install defaults:
55
		// self::factory()->term->create( array( 'taxonomy' => 'category', 'name' => 'uncategorized' ) );
56
57
		self::$post_ids[] = $factory->post->create( array( 'import_id' => 587, 'post_title' => 'post-format-test-audio', 'post_date' => '2008-06-02 00:00:00' ) );
58
		self::$post_ids[] = $post_id = $factory->post->create( array( 'post_title' => 'post-format-test-gallery', 'post_date' => '2008-06-10 00:00:00' ) );
59
		self::$post_ids[] = $factory->post->create( array( 'import_id' => 611, 'post_type' => 'attachment', 'post_title' => 'canola2', 'post_parent' => $post_id ) );
60
61
		self::$post_ids[] = $factory->post->create( array(
62
			'post_title' => 'images-test',
63
			'post_date' => '2008-09-03 00:00:00',
64
			'post_content' => 'Page 1 <!--nextpage--> Page 2 <!--nextpage--> Page 3'
65
		) );
66
67
		self::$post_ids[] = $post_id = $factory->post->create( array( 'import_id' => 149, 'post_title' => 'comment-test', 'post_date' => '2008-03-03 00:00:00' ) );
68
		self::$comment_ids = $factory->comment->create_post_comments( $post_id, 15 );
69
70
		self::$post_ids[] = $factory->post->create( array( 'post_date' => '2008-09-05 00:00:00' ) );
71
72
		self::$post_ids[] = $factory->post->create( array( 'import_id' => 123 ) );
73
		self::$post_ids[] = $factory->post->create( array( 'import_id' => 1 ) );
74
		self::$post_ids[] = $factory->post->create( array( 'import_id' => 358 ) );
75
76
		self::$post_ids[] = $factory->post->create( array( 'post_type' => 'page', 'post_title' => 'sample-page' ) );
77
		self::$post_ids[] = $factory->post->create( array( 'post_type' => 'page', 'post_title' => 'about' ) );
78
		self::$post_ids[] = $post_id = $factory->post->create( array( 'post_type' => 'page', 'post_title' => 'parent-page' ) );
79
		self::$post_ids[] = $factory->post->create(
80
			array( 'import_id' => 144, 'post_type' => 'page', 'post_title' => 'child-page-1', 'post_parent' => $post_id,
81
		) );
82
83
		self::$post_ids[] = $parent_id = $factory->post->create( array(
84
			'post_name' => 'parent',
85
			'post_type' => 'page',
86
		) );
87
		self::$post_ids[] = $child_id_1 = $factory->post->create( array(
88
			'post_name'   => 'child1',
89
			'post_type'   => 'page',
90
			'post_parent' => $parent_id,
91
		) );
92
		self::$post_ids[] = $child_id_2 = $factory->post->create( array(
93
			'post_name'   => 'child2',
94
			'post_type'   => 'page',
95
			'post_parent' => $parent_id,
96
		) );
97
		self::$post_ids[] = $grandchild_id_1 = $factory->post->create( array(
0 ignored issues
show
Unused Code introduced by
$grandchild_id_1 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...
98
			'post_name'   => 'grandchild',
99
			'post_type'   => 'page',
100
			'post_parent' => $child_id_1,
101
		) );
102
		self::$post_ids[] = $grandchild_id_2 = $factory->post->create( array(
0 ignored issues
show
Unused Code introduced by
$grandchild_id_2 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...
103
			'post_name'   => 'grandchild',
104
			'post_type'   => 'page',
105
			'post_parent' => $child_id_2,
106
		) );
107
108
		$cat1 = $factory->term->create( array( 'taxonomy' => 'category', 'name' => 'parent' ) );
109
		self::$terms['/category/parent/'] = $cat1;
110
		self::$term_ids[ $cat1 ] = 'category';
111
112
		$cat2 = $factory->term->create( array(
113
			'taxonomy' => 'category', 'name' => 'child-1', 'parent' => self::$terms['/category/parent/'],
114
		) );
115
		self::$terms['/category/parent/child-1/'] = $cat2;
116
		self::$term_ids[ $cat2 ] = 'category';
117
118
		$cat3 = $factory->term->create( array(
119
			'taxonomy' => 'category', 'name' => 'child-2', 'parent' => self::$terms['/category/parent/child-1/'],
120
		) );
121
		self::$terms['/category/parent/child-1/child-2/'] = $cat3;
122
		self::$term_ids[ $cat3 ] = 'category';
123
124
		$cat4 = $factory->term->create( array( 'taxonomy' => 'category', 'name' => 'cat-a' ) );
125
		self::$term_ids[ $cat4 ] = 'category';
126
127
		$cat5 = $factory->term->create( array( 'taxonomy' => 'category', 'name' => 'cat-b' ) );
128
		self::$term_ids[ $cat5 ] = 'category';
129
130
		$tag1 = $factory->term->create( array( 'name' => 'post-formats' ) );
131
		self::$term_ids[ $tag1 ] = 'post_tag';
132
	}
133
134
	/**
135
	 * Clean up shared fixtures.
136
	 *
137
	 * @since 4.1.0
138
	 */
139
	public static function delete_shared_fixtures() {
140
		self::$author_id = null;
141
		self::$post_ids = array();
142
		self::$comment_ids = array();
143
		self::$term_ids = array();
144
		self::$terms = array();
145
	}
146
147
	/**
148
	 * Assert that a given URL is the same a the canonical URL generated by WP.
149
	 *
150
	 * @since 4.1.0
151
	 *
152
	 * @param string $test_url                Raw URL that will be run through redirect_canonical().
153
	 * @param string $expected                Expected string.
154
	 * @param int    $ticket                  Optional. Trac ticket number.
155
	 * @param array  $expected_doing_it_wrong Array of class/function names expected to throw _doing_it_wrong() notices.
156
	 */
157
	public function assertCanonical( $test_url, $expected, $ticket = 0, $expected_doing_it_wrong = array() ) {
158
		$this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, (array) $expected_doing_it_wrong );
159
160
		$ticket_ref = ($ticket > 0) ? 'Ticket #' . $ticket : null;
161
162
		if ( is_string($expected) )
163
			$expected = array('url' => $expected);
164
		elseif ( is_array($expected) && !isset($expected['url']) && !isset($expected['qv']) )
165
			$expected = array( 'qv' => $expected );
166
167
		if ( !isset($expected['url']) && !isset($expected['qv']) )
168
			$this->fail( 'No valid expected output was provided' );
169
170
		$this->go_to( home_url( $test_url ) );
171
172
		// Does the redirect match what's expected?
173
		$can_url = $this->get_canonical( $test_url );
174
		$parsed_can_url = parse_url($can_url);
175
176
		// Just test the Path and Query if present
177
		if ( isset($expected['url']) ) {
178
			$this->assertEquals( $expected['url'], $parsed_can_url['path'] . (!empty($parsed_can_url['query']) ? '?' . $parsed_can_url['query'] : ''), $ticket_ref );
179
		}
180
181
		// If the test data doesn't include expected query vars, then we're done here
182
		if ( ! isset($expected['qv']) )
183
			return;
184
185
		// "make" that the request and check the query is correct
186
		$this->go_to( $can_url );
187
188
		// Are all query vars accounted for, And correct?
189
		global $wp;
190
191
		$query_vars = array_diff($wp->query_vars, $wp->extra_query_vars);
192
		if ( !empty($parsed_can_url['query']) ) {
193
			parse_str($parsed_can_url['query'], $_qv);
194
195
			// $_qv should not contain any elements which are set in $query_vars already (ie. $_GET vars should not be present in the Rewrite)
196
			$this->assertEquals( array(), array_intersect( $query_vars, $_qv ), 'Query vars are duplicated from the Rewrite into $_GET; ' . $ticket_ref );
197
198
			$query_vars = array_merge($query_vars, $_qv);
199
		}
200
201
		$this->assertEquals( $expected['qv'], $query_vars );
202
	}
203
204
	/**
205
	 * Get the canonical URL given a raw URL.
206
	 *
207
	 * @param string $test_url Should be relative to the site "front", ie /category/uncategorized/
208
	 *                         as opposed to http://example.com/category/uncategorized/
209
	 * @return $can_url Returns the original $test_url if no canonical can be generated, otherwise returns
0 ignored issues
show
Documentation introduced by
The doc-type $can_url could not be parsed: Unknown type name "$can_url" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
210
	 *                  the fully-qualified URL as generated by redirect_canonical().
211
	 */
212
	public function get_canonical( $test_url ) {
213
		$test_url = home_url( $test_url );
214
215
		$can_url = redirect_canonical( $test_url, false );
216
		if ( ! $can_url )
0 ignored issues
show
Bug Best Practice introduced by
The expression $can_url of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
217
			return $test_url; // No redirect will take place for this request
218
219
		return $can_url;
220
	}
221
}
222