Skip to content

Commit b230450

Browse files
westonruterclaude
andcommitted
Add unit tests for new fallback returns in _load_script_textdomain_from_src()
Cover the three new short-circuit branches added in 8f38b36 (unparseable $src, unparseable content_url(), non-string $relative filter return) plus the $src_url['path'] default added in bfe0eca. Each test uses a pre_load_script_translations spy to assert the early-return branch was the one actually taken, rather than the result coincidentally matching the fallback-path behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 8f38b36 commit b230450

1 file changed

Lines changed: 156 additions & 0 deletions

File tree

tests/phpunit/tests/l10n/loadScriptTextdomain.php

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,160 @@ public function test_does_not_throw_deprecation_notice_for_rtrim_with_default_pa
172172
$expected = file_get_contents( DIR_TESTDATA . '/languages/en_US-813e104eb47e13dd4cc5af844c618754.json' );
173173
$this->assertSame( $expected, load_script_textdomain( $handle ) );
174174
}
175+
176+
/**
177+
* Records every `$file` value passed to `load_script_translations()`
178+
* so individual tests can assert which code path produced the result.
179+
*
180+
* @return list<string|false> Reference to the array updated by the spy filter.
181+
*/
182+
private function &spy_load_script_translations_files(): array {
183+
/** @var list<string|false> $files_seen */
184+
$files_seen = array();
185+
add_filter(
186+
'pre_load_script_translations',
187+
static function ( $translations, $file ) use ( &$files_seen ) {
188+
assert( is_string( $file ) || false === $file );
189+
$files_seen[] = $file;
190+
return $translations;
191+
},
192+
10,
193+
2
194+
);
195+
return $files_seen;
196+
}
197+
198+
/**
199+
* Tests that an unparseable script source URL short-circuits to
200+
* `load_script_translations( false, ... )` instead of falling through
201+
* to the relative-path computation.
202+
*
203+
* @ticket 65015
204+
*/
205+
public function test_unparseable_src_returns_false(): void {
206+
$handle = 'test-unparseable-src';
207+
$src = 'http:///example';
208+
209+
$this->assertFalse( wp_parse_url( $src ), 'Test prerequisite failed: the test src should be unparseable.' );
210+
211+
$files_seen = &$this->spy_load_script_translations_files();
212+
213+
wp_enqueue_script( $handle, $src, array(), null );
214+
215+
$this->assertFalse( load_script_textdomain( $handle, 'default', DIR_TESTDATA . '/languages' ) );
216+
$this->assertSame(
217+
array(
218+
DIR_TESTDATA . '/languages/en_US-' . $handle . '.json',
219+
false,
220+
),
221+
$files_seen,
222+
'Expected the unparseable $src branch to short-circuit before any relative-path lookup.'
223+
);
224+
}
225+
226+
/**
227+
* Tests that an unparseable `content_url()` return value short-circuits
228+
* to `load_script_translations( false, ... )` instead of computing
229+
* `$relative` from a corrupted parsed-URL array.
230+
*
231+
* @ticket 65015
232+
*/
233+
public function test_unparseable_content_url_returns_false(): void {
234+
$handle = 'test-unparseable-content-url';
235+
$src = '/wp-includes/js/script.js';
236+
237+
add_filter(
238+
'content_url',
239+
static function () {
240+
return 'http:///example';
241+
}
242+
);
243+
244+
$files_seen = &$this->spy_load_script_translations_files();
245+
246+
wp_enqueue_script( $handle, $src, array(), null );
247+
248+
$this->assertFalse( load_script_textdomain( $handle, 'default', DIR_TESTDATA . '/languages' ) );
249+
$this->assertSame(
250+
array(
251+
DIR_TESTDATA . '/languages/en_US-' . $handle . '.json',
252+
false,
253+
),
254+
$files_seen,
255+
'Expected the unparseable content_url branch to short-circuit before any relative-path lookup.'
256+
);
257+
}
258+
259+
/**
260+
* Tests that the `load_script_textdomain_relative_path` filter returning
261+
* a non-string, non-false value short-circuits via the
262+
* `! is_string( $relative )` guard rather than falling through to
263+
* string functions like `str_ends_with()` and `md5()`.
264+
*
265+
* @ticket 65015
266+
*
267+
* @dataProvider data_non_string_relative_path_filter_values
268+
*
269+
* @param mixed $filter_value Value returned from the filter.
270+
*/
271+
public function test_non_string_relative_path_filter_returns_false( $filter_value ): void {
272+
$handle = 'test-non-string-relative-path';
273+
$src = '/wp-includes/js/script.js';
274+
275+
add_filter(
276+
'load_script_textdomain_relative_path',
277+
static function () use ( $filter_value ) {
278+
return $filter_value;
279+
}
280+
);
281+
282+
$files_seen = &$this->spy_load_script_translations_files();
283+
284+
wp_enqueue_script( $handle, $src, array(), null );
285+
286+
$this->assertFalse( load_script_textdomain( $handle, 'default', DIR_TESTDATA . '/languages' ) );
287+
$this->assertSame(
288+
array(
289+
DIR_TESTDATA . '/languages/en_US-' . $handle . '.json',
290+
false,
291+
),
292+
$files_seen,
293+
'Expected the non-string $relative branch to short-circuit before md5 path computation.'
294+
);
295+
}
296+
297+
/**
298+
* Provides data for {@see self::test_non_string_relative_path_filter_returns_false()}.
299+
*
300+
* @return array<string, array{0: mixed}>
301+
*/
302+
public static function data_non_string_relative_path_filter_values(): array {
303+
return array(
304+
'null' => array( null ),
305+
'true' => array( true ),
306+
'array' => array( array( 'wp-includes/js/script.js' ) ),
307+
'int' => array( 0 ),
308+
);
309+
}
310+
311+
/**
312+
* Tests that a script source URL with no path component does not trigger
313+
* an undefined index warning when the path is read further down in the
314+
* function. The result is reached via the regular fallback path
315+
* (no host/path match) rather than an early return.
316+
*
317+
* @ticket 65015
318+
*/
319+
public function test_src_without_path_component_does_not_warn(): void {
320+
$handle = 'test-src-without-path';
321+
$src = 'https://example.com';
322+
323+
$parsed = wp_parse_url( $src );
324+
$this->assertIsArray( $parsed, 'Test prerequisite failed: the test src should parse.' );
325+
$this->assertArrayNotHasKey( 'path', $parsed, 'Test prerequisite failed: the test src should have no path component.' );
326+
327+
wp_enqueue_script( $handle, $src, array(), null );
328+
329+
$this->assertFalse( load_script_textdomain( $handle, 'default', DIR_TESTDATA . '/languages' ) );
330+
}
175331
}

0 commit comments

Comments
 (0)