Skip to content

Commit ca7c852

Browse files
committed
Reject malformed parsed file entries
1 parent 9458b31 commit ca7c852

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

lib/class-command.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,35 @@ public function import( $args, $assoc_args ) {
6868
}
6969
preserve_json_object_shapes( $phpdoc );
7070

71+
// The importer dereferences these fields before it can report malformed
72+
// input. Validate the file envelope here so bad JSON data produces one
73+
// actionable CLI error instead of array-offset warnings or a type error.
74+
foreach ( $phpdoc as $index => $parsed_file ) {
75+
if (
76+
! is_array( $parsed_file ) ||
77+
! isset( $parsed_file['path'] ) ||
78+
! is_string( $parsed_file['path'] ) ||
79+
'' === $parsed_file['path'] ||
80+
! isset( $parsed_file['file'] ) ||
81+
! is_array( $parsed_file['file'] ) ||
82+
! isset( $parsed_file['file']['description'] ) ||
83+
! is_string( $parsed_file['file']['description'] ) ||
84+
! isset( $parsed_file['file']['long_description'] ) ||
85+
! is_string( $parsed_file['file']['long_description'] ) ||
86+
! isset( $parsed_file['file']['tags'] ) ||
87+
! is_array( $parsed_file['file']['tags'] )
88+
) {
89+
WP_CLI::error(
90+
sprintf(
91+
'JSON in %1$s entry %2$d must contain a parsed file object with a path and file metadata.',
92+
$file,
93+
$index + 1
94+
)
95+
);
96+
exit;
97+
}
98+
}
99+
71100
// Import data
72101
$this->_do_import( $phpdoc, isset( $assoc_args['quick'] ), isset( $assoc_args['import-internal'] ) );
73102
}

tests/phpunit/tests/import/command.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,39 @@ public function test_import_rejects_malformed_json() {
5252
$command->import( array( $file ), array() );
5353
}
5454

55+
/**
56+
* @dataProvider invalid_file_entries
57+
*/
58+
public function test_import_rejects_invalid_file_entries( $json ) {
59+
$file = $this->write_json_file( $json );
60+
61+
$this->expectException( RuntimeException::class );
62+
$this->expectExceptionMessage( 'entry 1 must contain a parsed file object with a path and file metadata' );
63+
64+
$command = new Command_Import_Test_Command;
65+
$command->import( array( $file ), array() );
66+
}
67+
68+
public function invalid_file_entries() {
69+
return array(
70+
'null' => array( '[null]' ),
71+
'number' => array( '[42]' ),
72+
'string' => array( '["parsed file"]' ),
73+
'list' => array( '[[]]' ),
74+
'empty object' => array( '[{}]' ),
75+
'missing file metadata' => array( '[{"path":"example.php"}]' ),
76+
'non-string path' => array( '[{"path":42,"file":{"description":"","long_description":"","tags":[]}}]' ),
77+
'empty path' => array( '[{"path":"","file":{"description":"","long_description":"","tags":[]}}]' ),
78+
'non-object file metadata' => array( '[{"path":"example.php","file":[]}]' ),
79+
'missing description' => array( '[{"path":"example.php","file":{"long_description":"","tags":[]}}]' ),
80+
'non-string description' => array( '[{"path":"example.php","file":{"description":42,"long_description":"","tags":[]}}]' ),
81+
'missing long description' => array( '[{"path":"example.php","file":{"description":"","tags":[]}}]' ),
82+
'non-string long description' => array( '[{"path":"example.php","file":{"description":"","long_description":42,"tags":[]}}]' ),
83+
'missing tags' => array( '[{"path":"example.php","file":{"description":"","long_description":""}}]' ),
84+
'non-list tags' => array( '[{"path":"example.php","file":{"description":"","long_description":"","tags":42}}]' ),
85+
);
86+
}
87+
5588
public function test_import_accepts_a_top_level_file_list() {
5689
$file = $this->write_json_file( '[]' );
5790
$command = new Command_Import_Test_Command;
@@ -61,6 +94,28 @@ public function test_import_accepts_a_top_level_file_list() {
6194
$this->assertSame( array(), $command->imported_data );
6295
}
6396

97+
public function test_import_accepts_a_parsed_file_entry() {
98+
$file = $this->write_json_file( '[{"file":{"description":"","long_description":"","tags":[]},"path":"example.php","root":"/tmp"}]' );
99+
$command = new Command_Import_Test_Command;
100+
101+
$command->import( array( $file ), array() );
102+
103+
$this->assertSame(
104+
array(
105+
array(
106+
'file' => array(
107+
'description' => '',
108+
'long_description' => '',
109+
'tags' => array(),
110+
),
111+
'path' => 'example.php',
112+
'root' => '/tmp',
113+
),
114+
),
115+
$command->imported_data
116+
);
117+
}
118+
64119
private function write_json_file( $json ) {
65120
$file = tempnam( sys_get_temp_dir(), 'phpdoc-parser-' );
66121
file_put_contents( $file, $json );

0 commit comments

Comments
 (0)