Repository navigation
Add a file existence check in class-wp-theme-json-resolver to avoid…
#10898
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
3665a3f
838b1dd
bbd7613
7f38aa0
2b96383
89e39fe
a68be02
9867d5a
4dafbae
a585ce6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * Test WP_Theme_JSON_Resolver::read_json_file(). | ||
| * | ||
| * @package WordPress | ||
| * @subpackage Theme | ||
| * | ||
| * @group themes | ||
| * | ||
| * @covers WP_Theme_JSON_Resolver::read_json_file | ||
| */ | ||
| class Tests_Theme_wpThemeJsonResolver_readJsonFile extends WP_UnitTestCase { | ||
|
|
||
| /** | ||
| * WP_Theme_JSON_Resolver::$theme_json_file_cache property. | ||
| * | ||
| * @var ReflectionProperty | ||
| */ | ||
| private static $property_theme_json_file_cache; | ||
|
|
||
| /** | ||
| * Original value of the WP_Theme_JSON_Resolver::$theme_json_file_cache property. | ||
| * | ||
| * @var array | ||
| */ | ||
| private static $property_theme_json_file_cache_orig_value; | ||
|
|
||
| public static function set_up_before_class() { | ||
| parent::set_up_before_class(); | ||
|
|
||
| static::$property_theme_json_file_cache = new ReflectionProperty( WP_Theme_JSON_Resolver::class, 'theme_json_file_cache' ); | ||
| if ( PHP_VERSION_ID < 80100 ) { | ||
| static::$property_theme_json_file_cache->setAccessible( true ); | ||
| } | ||
| static::$property_theme_json_file_cache_orig_value = static::$property_theme_json_file_cache->getValue(); | ||
| } | ||
|
|
||
| public static function tear_down_after_class() { | ||
| static::$property_theme_json_file_cache->setValue( null, static::$property_theme_json_file_cache_orig_value ); | ||
| parent::tear_down_after_class(); | ||
| } | ||
|
|
||
| public function tear_down() { | ||
| // Reset data between tests. | ||
| static::$property_theme_json_file_cache->setValue( null, array() ); | ||
| parent::tear_down(); | ||
| } | ||
|
|
||
| /** | ||
| * @ticket 64620 | ||
| */ | ||
| public function test_read_json_file() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one method covers six scenarios. The first failing assertion hides the rest. Could you split it into separate test methods or use a data provider? The unreadable-file case also skips itself without telling PHPUnit. On Windows, without the posix extension, or when tests run as root, it reports a pass for code it never ran. |
||
| $read_json_file = new ReflectionMethod( WP_Theme_JSON_Resolver::class, 'read_json_file' ); | ||
| if ( PHP_VERSION_ID < 80100 ) { | ||
| $read_json_file->setAccessible( true ); | ||
| } | ||
|
|
||
| // Test reading a valid JSON file. | ||
| $valid_file = DIR_TESTDATA . '/themedir1/block-theme/theme.json'; | ||
| $result = $read_json_file->invoke( null, $valid_file ); | ||
| $this->assertIsArray( $result ); | ||
| $this->assertArrayHasKey( 'version', $result ); | ||
| $this->assertSame( 3, $result['version'] ); | ||
|
|
||
| // Test that the result is cached. | ||
| $cache = static::$property_theme_json_file_cache->getValue(); | ||
| $this->assertArrayHasKey( $valid_file, $cache ); | ||
| $this->assertSame( $result, $cache[ $valid_file ] ); | ||
|
|
||
| // Test cache hit: modify cache and verify read_json_file returns cached value. | ||
| $cache[ $valid_file ] = array( | ||
| 'version' => 3, | ||
| 'cached' => true, | ||
| ); | ||
| static::$property_theme_json_file_cache->setValue( null, $cache ); | ||
| $result = $read_json_file->invoke( null, $valid_file ); | ||
| $this->assertSame( 3, $result['version'] ); | ||
| $this->assertTrue( $result['cached'] ); | ||
|
|
||
| // Test non-existent file. | ||
| $non_existent_file = DIR_TESTDATA . '/non-existent.json'; | ||
| $result = $read_json_file->invoke( null, $non_existent_file ); | ||
| $this->assertSame( array(), $result ); | ||
|
|
||
| // Test unreadable file. | ||
| if ( function_exists( 'posix_getpwuid' ) && function_exists( 'posix_geteuid' ) ) { | ||
| $pwuid = posix_getpwuid( posix_geteuid() ); | ||
| if ( is_array( $pwuid ) && isset( $pwuid['name'] ) && 'root' !== $pwuid['name'] ) { | ||
| $unreadable_file = tempnam( sys_get_temp_dir(), 'unreadable-json' ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the assertion below fails, |
||
| chmod( $unreadable_file, 0000 ); | ||
| $result = $read_json_file->invoke( null, $unreadable_file ); | ||
| $this->assertSame( array(), $result ); | ||
| chmod( $unreadable_file, 0644 ); | ||
| unlink( $unreadable_file ); | ||
| } | ||
| } | ||
|
|
||
| // Test invalid JSON. | ||
| $invalid_json_file = tempnam( sys_get_temp_dir(), 'invalid-json' ); | ||
| file_put_contents( $invalid_json_file, '{ invalid json }' ); | ||
| $result = @$read_json_file->invoke( null, $invalid_json_file ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| $this->assertSame( array(), $result ); | ||
| unlink( $invalid_json_file ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check returns
array()without any message. Before this change,wp_json_file_decode()reported the problem throughwp_trigger_error(). Now a theme author with a broken or unreadable variation file gets no hint on aWP_DEBUGsite.I think the fix belongs inside
wp_json_file_decode()instead. That function has two related bugs that other callers also hit, such as block.json registration:$filenamewithwp_normalize_path( realpath( $filename ) ).realpath()returnsfalsefor a missing file, so the notice prints an empty path:File doesn't exist!. You can see this withwp_json_file_decode( '/does/not/exist.json' );.file_get_contents()without checkingis_file()andis_readable(). An unreadable file or a directory raises a PHP warning.A check there, with a
wp_trigger_error()call that keeps the original path, would fix every caller and keep the diagnostic.