From 30a9ea3374f3246a287bcfce8f1df594957d4f46 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Mon, 8 Jun 2026 13:21:26 -0400 Subject: [PATCH] fix: keep workspace ls sizes schema-safe --- inc/Workspace/WorkspaceReader.php | 11 ++- tests/smoke-workspace-list-directory.php | 104 +++++++++++++++++++++++ 2 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 tests/smoke-workspace-list-directory.php diff --git a/inc/Workspace/WorkspaceReader.php b/inc/Workspace/WorkspaceReader.php index 54eef76f..2b9b37ff 100644 --- a/inc/Workspace/WorkspaceReader.php +++ b/inc/Workspace/WorkspaceReader.php @@ -168,16 +168,19 @@ public function list_directory( string $name, ?string $path = null ): array|\WP_ $entry_path = $target_path . '/' . $entry; $is_dir = is_dir($entry_path); + $size = 0; + + if ( ! $is_dir && is_file($entry_path) ) { + $file_size = filesize($entry_path); + $size = false === $file_size ? 0 : (int) $file_size; + } $item = array( 'name' => $entry, 'type' => $is_dir ? 'directory' : 'file', + 'size' => $size, ); - if ( ! $is_dir ) { - $item['size'] = filesize($entry_path); - } - $items[] = $item; } diff --git a/tests/smoke-workspace-list-directory.php b/tests/smoke-workspace-list-directory.php new file mode 100644 index 00000000..a3913ac9 --- /dev/null +++ b/tests/smoke-workspace-list-directory.php @@ -0,0 +1,104 @@ +code; + } + public function get_error_message(): string + { + return $this->message; + } + public function get_error_data(): array + { + return $this->data; + } + } + } + + if (! function_exists('is_wp_error') ) { + function is_wp_error( $value ): bool + { + return $value instanceof WP_Error; + } + } + + if (! function_exists('size_format') ) { + function size_format( $bytes ): string + { + return (string) $bytes . ' B'; + } + } + + include __DIR__ . '/../inc/Support/PathSecurity.php'; + include __DIR__ . '/../inc/Workspace/Workspace.php'; + include __DIR__ . '/../inc/Workspace/WorkspaceReader.php'; + + use DataMachineCode\Workspace\Workspace; + use DataMachineCode\Workspace\WorkspaceReader; + + $failures = array(); + $total = 0; + $assert = function ( string $label, bool $condition ) use ( &$failures, &$total ): void { + ++$total; + if ($condition ) { + echo " ok {$label}\n"; + return; + } + $failures[] = $label; + echo " fail {$label}\n"; + }; + + echo "Workspace list directory - smoke\n"; + + @mkdir(DATAMACHINE_WORKSPACE_PATH . '/example/src', 0777, true); + file_put_contents(DATAMACHINE_WORKSPACE_PATH . '/example/README.md', "hello\n"); + + $reader = new WorkspaceReader(new Workspace()); + $list = $reader->list_directory('example'); + + $entries = array(); + if (! is_wp_error($list) ) { + foreach ( $list['entries'] as $entry ) { + $entries[$entry['name']] = $entry; + } + } + + $assert('list directory succeeds', ! is_wp_error($list) && true === $list['success']); + $assert('directory entry includes integer size', isset($entries['src']) && 'directory' === $entries['src']['type'] && 0 === $entries['src']['size']); + $assert('file entry includes integer byte size', isset($entries['README.md']) && 'file' === $entries['README.md']['type'] && 6 === $entries['README.md']['size']); + $assert('every entry exposes schema-safe integer size', ! is_wp_error($list) && array_reduce($list['entries'], fn( bool $carry, array $entry ): bool => $carry && array_key_exists('size', $entry) && is_int($entry['size']), true)); + + if (! empty($failures) ) { + echo "\nFAIL: " . count($failures) . " assertion(s) failed out of {$total}\n"; + foreach ( $failures as $failure ) { + echo " - {$failure}\n"; + } + exit(1); + } + + echo "\nOK ({$total} assertions)\n"; + exit(0); +}