Skip to content

Commit 0789e4f

Browse files
author
Paul Bearne
committed
Add unit tests for save_mod_rewrite_rules() in src/wp-admin/includes/misc.php
1 parent acebfd0 commit 0789e4f

1 file changed

Lines changed: 268 additions & 0 deletions

File tree

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
<?php
2+
3+
/**
4+
* Tests for the save_mod_rewrite_rules() function.
5+
*
6+
* @group admin
7+
* @group rewrite
8+
*
9+
* @covers ::save_mod_rewrite_rules
10+
*/
11+
class Tests_save_mod_rewrite_rules extends WP_UnitTestCase {
12+
13+
/**
14+
* Original home path.
15+
* @var string|bool
16+
*/
17+
private $orig_home;
18+
19+
/**
20+
* Original siteurl path.
21+
* @var string|bool
22+
*/
23+
private $orig_siteurl;
24+
25+
/**
26+
* Temporary home directory.
27+
* @var string
28+
*/
29+
private $temp_home;
30+
31+
/**
32+
* Original $_SERVER['SCRIPT_FILENAME']
33+
* @var string|null
34+
*/
35+
private $orig_script_filename;
36+
37+
/**
38+
* Original $_SERVER['SERVER_SOFTWARE']
39+
* @var string|null
40+
*/
41+
private $orig_server_software;
42+
43+
public function set_up() {
44+
parent::set_up();
45+
46+
// Multisite test should be handled in test method if possible or skipped if globally multisite.
47+
if ( is_multisite() ) {
48+
// This test class is not intended for multisite.
49+
return;
50+
}
51+
52+
// Ensure the function is available.
53+
require_once ABSPATH . 'wp-admin/includes/misc.php';
54+
55+
$this->orig_home = get_option( 'home' );
56+
$this->orig_siteurl = get_option( 'siteurl' );
57+
$this->orig_script_filename = isset( $_SERVER['SCRIPT_FILENAME'] ) ? $_SERVER['SCRIPT_FILENAME'] : null;
58+
$this->orig_server_software = isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : null;
59+
60+
$this->temp_home = get_temp_dir() . 'wp_test_home/';
61+
if ( ! is_dir( $this->temp_home ) ) {
62+
mkdir( $this->temp_home );
63+
}
64+
}
65+
66+
public function tear_down() {
67+
if ( $this->temp_home && is_dir( $this->temp_home ) ) {
68+
$this->recursive_delete( $this->temp_home );
69+
}
70+
71+
update_option( 'home', $this->orig_home );
72+
update_option( 'siteurl', $this->orig_siteurl );
73+
if ( null !== $this->orig_script_filename ) {
74+
$_SERVER['SCRIPT_FILENAME'] = $this->orig_script_filename;
75+
} else {
76+
unset( $_SERVER['SCRIPT_FILENAME'] );
77+
}
78+
if ( null !== $this->orig_server_software ) {
79+
$_SERVER['SERVER_SOFTWARE'] = $this->orig_server_software;
80+
} else {
81+
unset( $_SERVER['SERVER_SOFTWARE'] );
82+
}
83+
84+
parent::tear_down();
85+
}
86+
87+
/**
88+
* Helper to delete a directory and its contents.
89+
*
90+
* @param string $dir Path to the directory.
91+
*/
92+
private function recursive_delete( $dir ) {
93+
foreach ( scandir( $dir ) as $file ) {
94+
if ( '.' === $file || '..' === $file ) {
95+
continue;
96+
}
97+
$path = $dir . DIRECTORY_SEPARATOR . $file;
98+
if ( is_dir( $path ) ) {
99+
$this->recursive_delete( $path );
100+
} else {
101+
unlink( $path );
102+
}
103+
}
104+
rmdir( $dir );
105+
}
106+
107+
/**
108+
* Tests that save_mod_rewrite_rules() correctly writes rules to .htaccess.
109+
*
110+
* @ticket 65146
111+
*/
112+
public function test_save_mod_rewrite_rules_success() {
113+
global $wp_rewrite;
114+
115+
// Setup temporary home.
116+
$home_url = 'http://example.org';
117+
$site_url = 'http://example.org/wp';
118+
update_option( 'home', $home_url );
119+
update_option( 'siteurl', $site_url );
120+
121+
$_SERVER['SCRIPT_FILENAME'] = $this->temp_home . 'wp/index.php';
122+
if ( ! is_dir( $this->temp_home . 'wp' ) ) {
123+
mkdir( $this->temp_home . 'wp' );
124+
}
125+
126+
$_SERVER['SERVER_SOFTWARE'] = 'Apache';
127+
128+
// Mock got_mod_rewrite().
129+
add_filter( 'got_rewrite', '__return_true' );
130+
131+
// Mock WP_Rewrite rules.
132+
$orig_structure = $wp_rewrite->permalink_structure;
133+
$wp_rewrite->set_permalink_structure( '/%postname%/' );
134+
135+
$htaccess_file = $this->temp_home . '.htaccess';
136+
touch( $htaccess_file );
137+
138+
$result = save_mod_rewrite_rules();
139+
140+
// Cleanup structure.
141+
$wp_rewrite->set_permalink_structure( $orig_structure );
142+
remove_filter( 'got_rewrite', '__return_true' );
143+
144+
$this->assertTrue( $result, 'save_mod_rewrite_rules() should return true on success.' );
145+
$this->assertFileExists( $htaccess_file );
146+
147+
$content = file_get_contents( $htaccess_file );
148+
$this->assertStringContainsString( '# BEGIN WordPress', $content );
149+
$this->assertStringContainsString( 'RewriteEngine On', $content );
150+
}
151+
152+
/**
153+
* Tests that save_mod_rewrite_rules() returns false if mod_rewrite is not available.
154+
*
155+
* @ticket 65146
156+
*/
157+
public function test_save_mod_rewrite_rules_no_mod_rewrite() {
158+
// Mock got_mod_rewrite() as false.
159+
add_filter( 'got_rewrite', '__return_false' );
160+
161+
// Setup path.
162+
$home_url = 'http://example.org';
163+
$site_url = 'http://example.org/wp';
164+
update_option( 'home', $home_url );
165+
update_option( 'siteurl', $site_url );
166+
$_SERVER['SCRIPT_FILENAME'] = $this->temp_home . 'wp/index.php';
167+
if ( ! is_dir( $this->temp_home . 'wp' ) ) {
168+
mkdir( $this->temp_home . 'wp' );
169+
}
170+
171+
touch( $this->temp_home . '.htaccess' );
172+
173+
$_SERVER['SERVER_SOFTWARE'] = 'Apache';
174+
175+
$result = save_mod_rewrite_rules();
176+
177+
remove_filter( 'got_rewrite', '__return_false' );
178+
179+
$this->assertFalse( $result, 'save_mod_rewrite_rules() should return false when mod_rewrite is not available.' );
180+
}
181+
/**
182+
* Tests that save_mod_rewrite_rules() returns false if the .htaccess file is not writable.
183+
*
184+
* @ticket 65146
185+
*/
186+
public function test_save_mod_rewrite_rules_non_writable() {
187+
// Mock is_writable to return false.
188+
// Since we can't easily mock is_writable, we try the chmod approach.
189+
// If it is skipped, we'll know.
190+
if ( 'root' === posix_getpwuid( posix_geteuid() )['name'] ) {
191+
$this->markTestSkipped( 'Cannot test non-writable files as root.' );
192+
}
193+
194+
// Setup path.
195+
$home_url = 'http://example.org';
196+
$site_url = 'http://example.org/wp';
197+
update_option( 'home', $home_url );
198+
update_option( 'siteurl', $site_url );
199+
$_SERVER['SCRIPT_FILENAME'] = $this->temp_home . 'wp/index.php';
200+
if ( ! is_dir( $this->temp_home . 'wp' ) ) {
201+
mkdir( $this->temp_home . 'wp' );
202+
}
203+
204+
$htaccess_file = $this->temp_home . '.htaccess';
205+
touch( $htaccess_file );
206+
chmod( $htaccess_file, 0444 ); // Read-only.
207+
208+
$_SERVER['SERVER_SOFTWARE'] = 'Apache';
209+
210+
// Mock got_mod_rewrite().
211+
add_filter( 'got_rewrite', '__return_true' );
212+
213+
$result = save_mod_rewrite_rules();
214+
215+
chmod( $htaccess_file, 0666 ); // Restore for cleanup.
216+
remove_filter( 'got_rewrite', '__return_true' );
217+
218+
$this->assertFalse( $result, 'save_mod_rewrite_rules() should return false when .htaccess is not writable.' );
219+
}
220+
221+
/**
222+
* Tests that save_mod_rewrite_rules() returns false if the directory is not writable and file doesn't exist.
223+
*
224+
* @ticket 65146
225+
*/
226+
public function test_save_mod_rewrite_rules_non_writable_dir() {
227+
if ( 'root' === posix_getpwuid( posix_geteuid() )['name'] ) {
228+
$this->markTestSkipped( 'Cannot test non-writable directories as root.' );
229+
}
230+
231+
$home_dir = $this->temp_home . 'non_writable_home/';
232+
mkdir( $home_dir );
233+
234+
// Setup path.
235+
$home_url = 'http://example.org';
236+
$site_url = 'http://example.org/wp';
237+
update_option( 'home', $home_url );
238+
update_option( 'siteurl', $site_url );
239+
$_SERVER['SCRIPT_FILENAME'] = $home_dir . 'wp/index.php';
240+
mkdir( $home_dir . 'wp' );
241+
242+
chmod( $home_dir, 0555 ); // Read-only dir.
243+
244+
$_SERVER['SERVER_SOFTWARE'] = 'Apache';
245+
246+
// Mock got_mod_rewrite().
247+
add_filter( 'got_rewrite', '__return_true' );
248+
249+
$result = save_mod_rewrite_rules();
250+
251+
chmod( $home_dir, 0777 ); // Restore for cleanup.
252+
remove_filter( 'got_rewrite', '__return_true' );
253+
254+
$this->assertFalse( $result, 'save_mod_rewrite_rules() should return false when home directory is not writable.' );
255+
}
256+
/**
257+
* Tests that save_mod_rewrite_rules() returns null in multisite.
258+
*
259+
* @ticket 65146
260+
*/
261+
public function test_save_mod_rewrite_rules_multisite() {
262+
if ( ! is_multisite() ) {
263+
$this->markTestSkipped( 'This test requires multisite.' );
264+
}
265+
266+
$this->assertNull( save_mod_rewrite_rules() );
267+
}
268+
}

0 commit comments

Comments
 (0)