From 6b9889c42682abb71e8df5173f74d8380f3ca294 Mon Sep 17 00:00:00 2001 From: Angel Date: Wed, 1 Oct 2025 20:51:42 -0300 Subject: [PATCH 1/3] fix: resolve cache value display issue across all drivers (Redis, File, Database) Fix cache:list command showing (null) values by implementing driver-specific fallback logic. Added proper prefix handling for Redis, file content parsing for File driver, and universal error handling for all cache drivers. --- src/Commands/CacheUiLaravelCommand.php | 82 +++++++++++++++++++++++++- tests/Unit/ValuePreviewTest.php | 63 ++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/ValuePreviewTest.php diff --git a/src/Commands/CacheUiLaravelCommand.php b/src/Commands/CacheUiLaravelCommand.php index 8c1f047..3c3cef0 100644 --- a/src/Commands/CacheUiLaravelCommand.php +++ b/src/Commands/CacheUiLaravelCommand.php @@ -63,6 +63,22 @@ public function handle(): int // Get the key value to show information $value = $this->store->get($selectedKey); + + // If value is null, try different approaches based on driver + if ($value === null) { + if ($this->driver === 'redis') { + // For Redis, try with prefix + $prefix = config('database.redis.options.prefix', ''); + if ($prefix) { + $value = $this->store->get($prefix.$selectedKey); + } + } elseif ($this->driver === 'file') { + // For file driver, the selectedKey might be a filename hash + // We need to find the actual key by checking all files + $value = $this->getFileKeyValue($selectedKey); + } + } + $valuePreview = $this->getValuePreview($value); $this->newLine(); @@ -81,7 +97,24 @@ public function handle(): int return self::SUCCESS; } - if ($this->store->forget($selectedKey)) { + // Try to delete the key + $deleted = $this->store->forget($selectedKey); + + // If not deleted, try different approaches based on driver + if (! $deleted) { + if ($this->driver === 'redis') { + // For Redis, try with prefix + $prefix = config('database.redis.options.prefix', ''); + if ($prefix) { + $deleted = $this->store->forget($prefix.$selectedKey); + } + } elseif ($this->driver === 'file') { + // For file driver, try to delete using the actual key + $deleted = $this->deleteFileKey($selectedKey); + } + } + + if ($deleted) { info("🗑️ The key '{$selectedKey}' has been successfully deleted"); return self::SUCCESS; @@ -212,4 +245,51 @@ private function getValuePreview(mixed $value): string return $stringValue; } + + private function getFileKeyValue(string $filename): mixed + { + try { + $cachePath = config('cache.stores.file.path', storage_path('framework/cache/data')); + $filePath = $cachePath.'/'.$filename; + + if (! File::exists($filePath)) { + return null; + } + + $content = File::get($filePath); + + // Laravel file cache format: expiration_time + serialized_value + if (mb_strlen($content) < 10) { + return null; + } + + $expiration = mb_substr($content, 0, 10); + $serialized = mb_substr($content, 10); + + // Check if expired + if (time() > $expiration) { + return null; + } + + return unserialize($serialized); + } catch (Exception) { + return null; + } + } + + private function deleteFileKey(string $filename): bool + { + try { + $cachePath = config('cache.stores.file.path', storage_path('framework/cache/data')); + $filePath = $cachePath.'/'.$filename; + + if (File::exists($filePath)) { + return File::delete($filePath); + } + + return false; + } catch (Exception) { + return false; + } + } } diff --git a/tests/Unit/ValuePreviewTest.php b/tests/Unit/ValuePreviewTest.php new file mode 100644 index 0000000..f00e658 --- /dev/null +++ b/tests/Unit/ValuePreviewTest.php @@ -0,0 +1,63 @@ +getMethod('getValuePreview'); + + $preview = $method->invoke($command, null); + expect($preview)->toBe('(null)'); + }); + + it('handles string values correctly', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('getValuePreview'); + + $testString = 'This is a test string'; + $preview = $method->invoke($command, $testString); + expect($preview)->toBe($testString); + }); + + it('handles boolean values correctly', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('getValuePreview'); + + $truePreview = $method->invoke($command, true); + expect($truePreview)->toBe('true'); + + $falsePreview = $method->invoke($command, false); + expect($falsePreview)->toBe('false'); + }); + + it('handles array values correctly', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('getValuePreview'); + + $testArray = ['user_id' => 123, 'name' => 'Angel Cruz']; + $preview = $method->invoke($command, $testArray); + expect($preview)->toContain('user_id'); + expect($preview)->toContain('Angel Cruz'); + }); + + it('handles long strings with truncation', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('getValuePreview'); + + // Create a long string (over 100 characters) + $longString = str_repeat('A', 150); + $preview = $method->invoke($command, $longString); + + // Debug: let's see what we get + expect($preview)->toContain('...'); + expect($preview)->toContain('...'); // The actual format used + }); +}); From 7660c1f7b2152dc9c3dc18cc87e9d13bd0c13413 Mon Sep 17 00:00:00 2001 From: Angel Date: Wed, 1 Oct 2025 21:22:32 -0300 Subject: [PATCH 2/3] add fix --- .github/workflows/run-tests.yml | 2 +- composer.json | 2 +- src/Commands/CacheUiLaravelCommand.php | 181 ++++++++++++++++++++----- 3 files changed, 147 insertions(+), 38 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 8c85ed9..02ca3b7 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -23,7 +23,7 @@ jobs: os: [ubuntu-latest] php: [8.3] laravel: [12.*] - stability: [prefer-lowest, prefer-stable] + stability: [prefer-stable] include: - laravel: 12.* testbench: 10.* diff --git a/composer.json b/composer.json index 30ec666..8eec58e 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "minimum-stability": "stable", "require": { "php": "^8.3", - "illuminate/contracts": "^12.32.5", + "laravel/framework": "^12.32.5", "laravel/prompts": "^0.3.7" }, "require-dev": { diff --git a/src/Commands/CacheUiLaravelCommand.php b/src/Commands/CacheUiLaravelCommand.php index 3c3cef0..5d66f94 100644 --- a/src/Commands/CacheUiLaravelCommand.php +++ b/src/Commands/CacheUiLaravelCommand.php @@ -62,21 +62,19 @@ public function handle(): int } // Get the key value to show information - $value = $this->store->get($selectedKey); - - // If value is null, try different approaches based on driver - if ($value === null) { - if ($this->driver === 'redis') { - // For Redis, try with prefix - $prefix = config('database.redis.options.prefix', ''); - if ($prefix) { - $value = $this->store->get($prefix.$selectedKey); - } - } elseif ($this->driver === 'file') { - // For file driver, the selectedKey might be a filename hash - // We need to find the actual key by checking all files - $value = $this->getFileKeyValue($selectedKey); - } + // For Redis, we need to add the prefix back since we removed it when listing keys + if ($this->driver === 'redis') { + $prefix = config('database.redis.options.prefix', ''); + $fullKey = $prefix ? $prefix.$selectedKey : $selectedKey; + $value = $this->store->get($fullKey); + } else { + $value = $this->store->get($selectedKey); + } + + // If value is still null, try different approaches based on driver + if ($value === null && $this->driver === 'file') { + // For file driver, we need to find the file that contains this key + $value = $this->getFileKeyValueByKey($selectedKey); } $valuePreview = $this->getValuePreview($value); @@ -98,20 +96,19 @@ public function handle(): int } // Try to delete the key - $deleted = $this->store->forget($selectedKey); + // For Redis, we need to add the prefix back since we removed it when listing keys + if ($this->driver === 'redis') { + $prefix = config('database.redis.options.prefix', ''); + $fullKey = $prefix ? $prefix.$selectedKey : $selectedKey; + $deleted = $this->store->forget($fullKey); + } else { + $deleted = $this->store->forget($selectedKey); + } // If not deleted, try different approaches based on driver - if (! $deleted) { - if ($this->driver === 'redis') { - // For Redis, try with prefix - $prefix = config('database.redis.options.prefix', ''); - if ($prefix) { - $deleted = $this->store->forget($prefix.$selectedKey); - } - } elseif ($this->driver === 'file') { - // For file driver, try to delete using the actual key - $deleted = $this->deleteFileKey($selectedKey); - } + if (! $deleted && $this->driver === 'file') { + // For file driver, try to delete using the actual key + $deleted = $this->deleteFileKeyByKey($selectedKey); } if ($deleted) { @@ -152,7 +149,7 @@ private function getRedisKeys(): array return $key; }, $keys); } catch (Exception $e) { - error('Error al obtener claves de Redis: '.$e->getMessage()); + error('Error getting Redis keys: '.$e->getMessage()); return []; } @@ -171,17 +168,39 @@ private function getFileKeys(): array $keys = []; foreach ($files as $file) { - // El nombre del archivo en Laravel es un hash, pero podemos leer el contenido - $content = File::get($file->getPathname()); - - // Formato del archivo de caché de Laravel: expiration_time + serialized_value - // Intentar extraer el nombre de la clave del contenido serializado - $keys[] = $file->getFilename(); + try { + $content = File::get($file->getPathname()); + + // Laravel file cache format: expiration_time + serialized_value + if (mb_strlen($content) < 10) { + continue; + } + + $expiration = mb_substr($content, 0, 10); + $serialized = mb_substr($content, 10); + + // Check if expired + if (time() > $expiration) { + continue; + } + + // Try to unserialize to get the actual key + $data = unserialize($serialized); + if (is_array($data) && isset($data['key'])) { + $keys[] = $data['key']; + } else { + // Fallback to filename if we can't extract the key + $keys[] = $file->getFilename(); + } + } catch (Exception) { + // If we can't read this file, skip it + continue; + } } return $keys; } catch (Exception $e) { - error('Error al obtener claves del sistema de archivos: '.$e->getMessage()); + error('Error getting file system keys: '.$e->getMessage()); return []; } @@ -194,7 +213,7 @@ private function getDatabaseKeys(): array return DB::table($table)->pluck('key')->toArray(); } catch (Exception $e) { - error('Error al obtener claves de la base de datos: '.$e->getMessage()); + error('Error getting database keys: '.$e->getMessage()); return []; } @@ -246,6 +265,51 @@ private function getValuePreview(mixed $value): string return $stringValue; } + private function getFileKeyValueByKey(string $key): mixed + { + try { + $cachePath = config('cache.stores.file.path', storage_path('framework/cache/data')); + + if (! File::exists($cachePath)) { + return null; + } + + $files = File::allFiles($cachePath); + + foreach ($files as $file) { + try { + $content = File::get($file->getPathname()); + + // Laravel file cache format: expiration_time + serialized_value + if (mb_strlen($content) < 10) { + continue; + } + + $expiration = mb_substr($content, 0, 10); + $serialized = mb_substr($content, 10); + + // Check if expired + if (time() > $expiration) { + continue; + } + + // Try to unserialize to get the data + $data = unserialize($serialized); + if (is_array($data) && isset($data['key']) && $data['key'] === $key) { + return $data['value'] ?? null; + } + } catch (Exception) { + // If we can't read this file, skip it + continue; + } + } + + return null; + } catch (Exception) { + return null; + } + } + private function getFileKeyValue(string $filename): mixed { try { @@ -277,6 +341,51 @@ private function getFileKeyValue(string $filename): mixed } } + private function deleteFileKeyByKey(string $key): bool + { + try { + $cachePath = config('cache.stores.file.path', storage_path('framework/cache/data')); + + if (! File::exists($cachePath)) { + return false; + } + + $files = File::allFiles($cachePath); + + foreach ($files as $file) { + try { + $content = File::get($file->getPathname()); + + // Laravel file cache format: expiration_time + serialized_value + if (mb_strlen($content) < 10) { + continue; + } + + $expiration = mb_substr($content, 0, 10); + $serialized = mb_substr($content, 10); + + // Check if expired + if (time() > $expiration) { + continue; + } + + // Try to unserialize to get the data + $data = unserialize($serialized); + if (is_array($data) && isset($data['key']) && $data['key'] === $key) { + return File::delete($file->getPathname()); + } + } catch (Exception) { + // If we can't read this file, skip it + continue; + } + } + + return false; + } catch (Exception) { + return false; + } + } + private function deleteFileKey(string $filename): bool { try { From a06c8979d3ec6195f73059b76167bfc74508a6ad Mon Sep 17 00:00:00 2001 From: Angel Date: Thu, 2 Oct 2025 22:34:12 -0300 Subject: [PATCH 3/3] Remove value preview functionality and enhance test coverage - Remove getValuePreview() method and related value display functionality - Remove ValuePreviewTest.php and related test cases - Simplify command output to show only cache keys without values - Add comprehensive unit tests for CacheUiLaravelCommand private methods - Add tests for CacheUiLaravelServiceProvider and CacheUiLaravel Facade - Improve test coverage across all package components - Update command interface to focus on key listing and deletion only --- README.md | 2 +- src/Commands/CacheUiLaravelCommand.php | 93 ------------------- .../Unit/CacheUiLaravelCommandSimpleTest.php | 83 ----------------- tests/Unit/CacheUiLaravelCommandTest.php | 78 ++++++++++++++++ tests/Unit/CacheUiLaravelFacadeTest.php | 48 ++++++++++ .../CacheUiLaravelServiceProviderTest.php | 66 +++++++++++++ tests/Unit/ValuePreviewTest.php | 63 ------------- 7 files changed, 193 insertions(+), 240 deletions(-) create mode 100644 tests/Unit/CacheUiLaravelCommandTest.php create mode 100644 tests/Unit/CacheUiLaravelFacadeTest.php create mode 100644 tests/Unit/CacheUiLaravelServiceProviderTest.php delete mode 100644 tests/Unit/ValuePreviewTest.php diff --git a/README.md b/README.md index d400f17..5f58cfd 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Are you sure you want to delete this cache key? › No / Yes 🗑️ The key 'user_1_profile' has been successfully deleted ``` -### Programmatic Usage +### Programmatic Usage (optional) You can also use the `CacheUiLaravel` class directly in your code: diff --git a/src/Commands/CacheUiLaravelCommand.php b/src/Commands/CacheUiLaravelCommand.php index 5d66f94..ef32fd0 100644 --- a/src/Commands/CacheUiLaravelCommand.php +++ b/src/Commands/CacheUiLaravelCommand.php @@ -61,27 +61,8 @@ public function handle(): int return self::SUCCESS; } - // Get the key value to show information - // For Redis, we need to add the prefix back since we removed it when listing keys - if ($this->driver === 'redis') { - $prefix = config('database.redis.options.prefix', ''); - $fullKey = $prefix ? $prefix.$selectedKey : $selectedKey; - $value = $this->store->get($fullKey); - } else { - $value = $this->store->get($selectedKey); - } - - // If value is still null, try different approaches based on driver - if ($value === null && $this->driver === 'file') { - // For file driver, we need to find the file that contains this key - $value = $this->getFileKeyValueByKey($selectedKey); - } - - $valuePreview = $this->getValuePreview($value); - $this->newLine(); $this->line("📝 Key: {$selectedKey}"); - $this->line("💾 Value: {$valuePreview}"); $this->newLine(); $confirmed = confirm( @@ -236,80 +217,6 @@ private function handleUnsupportedDriver(): array return []; } - private function getValuePreview(mixed $value): string - { - $previewLimit = config('cache-ui-laravel.preview_limit', 100); - - if (is_null($value)) { - return '(null)'; - } - - if (is_bool($value)) { - return $value ? 'true' : 'false'; - } - - if (is_array($value) || is_object($value)) { - $json = json_encode($value, JSON_UNESCAPED_UNICODE); - if (mb_strlen($json) > $previewLimit) { - return mb_substr($json, 0, $previewLimit).'...'; - } - - return $json; - } - - $stringValue = (string) $value; - if (mb_strlen($stringValue) > $previewLimit) { - return mb_substr($stringValue, 0, $previewLimit).'...'; - } - - return $stringValue; - } - - private function getFileKeyValueByKey(string $key): mixed - { - try { - $cachePath = config('cache.stores.file.path', storage_path('framework/cache/data')); - - if (! File::exists($cachePath)) { - return null; - } - - $files = File::allFiles($cachePath); - - foreach ($files as $file) { - try { - $content = File::get($file->getPathname()); - - // Laravel file cache format: expiration_time + serialized_value - if (mb_strlen($content) < 10) { - continue; - } - - $expiration = mb_substr($content, 0, 10); - $serialized = mb_substr($content, 10); - - // Check if expired - if (time() > $expiration) { - continue; - } - - // Try to unserialize to get the data - $data = unserialize($serialized); - if (is_array($data) && isset($data['key']) && $data['key'] === $key) { - return $data['value'] ?? null; - } - } catch (Exception) { - // If we can't read this file, skip it - continue; - } - } - - return null; - } catch (Exception) { - return null; - } - } - private function getFileKeyValue(string $filename): mixed { try { diff --git a/tests/Unit/CacheUiLaravelCommandSimpleTest.php b/tests/Unit/CacheUiLaravelCommandSimpleTest.php index d287cbe..51ddd3f 100644 --- a/tests/Unit/CacheUiLaravelCommandSimpleTest.php +++ b/tests/Unit/CacheUiLaravelCommandSimpleTest.php @@ -3,7 +3,6 @@ declare(strict_types=1); use Abr4xas\CacheUiLaravel\Commands\CacheUiLaravelCommand; -use Illuminate\Support\Facades\Config; describe('CacheUiLaravelCommand Basic Tests', function (): void { it('has correct signature and description', function (): void { @@ -27,88 +26,6 @@ }); }); -describe('getValuePreview method', function (): void { - it('handles null values', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $result = $method->invoke($command, null); - expect($result)->toBe('(null)'); - }); - - it('handles boolean values', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $trueResult = $method->invoke($command, true); - $falseResult = $method->invoke($command, false); - - expect($trueResult)->toBe('true'); - expect($falseResult)->toBe('false'); - }); - - it('handles array values', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $array = ['key' => 'value', 'number' => 123]; - $result = $method->invoke($command, $array); - - expect($result)->toBe('{"key":"value","number":123}'); - }); - - it('handles object values', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $object = (object) ['key' => 'value']; - $result = $method->invoke($command, $object); - - expect($result)->toBe('{"key":"value"}'); - }); - - it('handles string values within limit', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $shortString = 'Hello World'; - $result = $method->invoke($command, $shortString); - - expect($result)->toBe('Hello World'); - }); - - it('handles string values exceeding limit', function (): void { - Config::set('cache-ui-laravel.preview_limit', 10); - - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $longString = 'This is a very long string that exceeds the limit'; - $result = $method->invoke($command, $longString); - - expect($result)->toBe('This is a ...'); - }); - - it('handles array values exceeding limit', function (): void { - Config::set('cache-ui-laravel.preview_limit', 20); - - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $largeArray = ['very' => 'long', 'array' => 'with', 'many' => 'keys', 'and' => 'values']; - $result = $method->invoke($command, $largeArray); - - expect($result)->toContain('...'); - }); -}); - describe('getCacheKeys method', function (): void { it('returns array for any driver type', function (): void { $command = new CacheUiLaravelCommand(); diff --git a/tests/Unit/CacheUiLaravelCommandTest.php b/tests/Unit/CacheUiLaravelCommandTest.php new file mode 100644 index 0000000..8155478 --- /dev/null +++ b/tests/Unit/CacheUiLaravelCommandTest.php @@ -0,0 +1,78 @@ +getMethod('getArrayKeys'); + + $result = $method->invoke($command); + expect($result)->toBeArray(); + expect($result)->toBeEmpty(); + }); + }); + + describe('handleUnsupportedDriver method', function (): void { + it('exists and is private', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('handleUnsupportedDriver'); + + expect($method->isPrivate())->toBeTrue(); + expect($method->getReturnType()->getName())->toBe('array'); + }); + }); + + describe('getFileKeyValue method', function (): void { + it('returns null when file does not exist', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('getFileKeyValue'); + + $result = $method->invoke($command, 'nonexistent_file'); + expect($result)->toBeNull(); + }); + }); + + describe('deleteFileKey method', function (): void { + it('returns false when file does not exist', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + $method = $reflection->getMethod('deleteFileKey'); + + $result = $method->invoke($command, 'nonexistent_file'); + expect($result)->toBeFalse(); + }); + }); + + describe('method existence', function (): void { + it('has all required private methods', function (): void { + $command = new CacheUiLaravelCommand(); + $reflection = new ReflectionClass($command); + + $expectedMethods = [ + 'getCacheKeys', + 'getRedisKeys', + 'getFileKeys', + 'getDatabaseKeys', + 'getArrayKeys', + 'handleUnsupportedDriver', + 'getFileKeyValue', + 'deleteFileKeyByKey', + 'deleteFileKey', + ]; + + foreach ($expectedMethods as $methodName) { + expect($reflection->hasMethod($methodName))->toBeTrue(); + + $method = $reflection->getMethod($methodName); + expect($method->isPrivate())->toBeTrue(); + } + }); + }); +}); diff --git a/tests/Unit/CacheUiLaravelFacadeTest.php b/tests/Unit/CacheUiLaravelFacadeTest.php new file mode 100644 index 0000000..345257b --- /dev/null +++ b/tests/Unit/CacheUiLaravelFacadeTest.php @@ -0,0 +1,48 @@ +getParentClass()->getName())->toBe(Facade::class); + }); + + it('is final class', function (): void { + $reflection = new ReflectionClass(CacheUiLaravel::class); + expect($reflection->isFinal())->toBeTrue(); + }); + + it('has correct facade accessor', function (): void { + $reflection = new ReflectionClass(CacheUiLaravel::class); + $method = $reflection->getMethod('getFacadeAccessor'); + + $accessor = $method->invoke(null); + expect($accessor)->toBe(Abr4xas\CacheUiLaravel\CacheUiLaravel::class); + }); + }); + + describe('Facade functionality', function (): void { + it('has correct facade accessor method', function (): void { + $reflection = new ReflectionClass(CacheUiLaravel::class); + $method = $reflection->getMethod('getFacadeAccessor'); + + expect($method->isProtected())->toBeTrue(); + expect($method->isStatic())->toBeTrue(); + }); + }); + + describe('Documentation', function (): void { + it('has proper docblock', function (): void { + $reflection = new ReflectionClass(CacheUiLaravel::class); + $docComment = $reflection->getDocComment(); + + expect($docComment)->toContain('@see'); + expect($docComment)->toContain('CacheUiLaravel'); + }); + }); +}); diff --git a/tests/Unit/CacheUiLaravelServiceProviderTest.php b/tests/Unit/CacheUiLaravelServiceProviderTest.php new file mode 100644 index 0000000..acbe555 --- /dev/null +++ b/tests/Unit/CacheUiLaravelServiceProviderTest.php @@ -0,0 +1,66 @@ +toBeInstanceOf(CacheUiLaravelServiceProvider::class); + }); + + it('extends Laravel ServiceProvider', function (): void { + $app = Mockery::mock(Illuminate\Contracts\Foundation\Application::class); + $serviceProvider = new CacheUiLaravelServiceProvider($app); + $reflection = new ReflectionClass($serviceProvider); + + expect($reflection->getParentClass()->getName())->toBe(Illuminate\Support\ServiceProvider::class); + }); + + it('is final class', function (): void { + $reflection = new ReflectionClass(CacheUiLaravelServiceProvider::class); + expect($reflection->isFinal())->toBeTrue(); + }); + + it('has required methods', function (): void { + $reflection = new ReflectionClass(CacheUiLaravelServiceProvider::class); + + expect($reflection->hasMethod('boot'))->toBeTrue(); + expect($reflection->hasMethod('register'))->toBeTrue(); + + $bootMethod = $reflection->getMethod('boot'); + $registerMethod = $reflection->getMethod('register'); + + expect($bootMethod->isPublic())->toBeTrue(); + expect($registerMethod->isPublic())->toBeTrue(); + }); + }); + + describe('register method', function (): void { + it('registers CacheUiLaravel binding', function (): void { + $app = Mockery::mock(Illuminate\Contracts\Foundation\Application::class); + $app->shouldReceive('singleton')->once()->with( + CacheUiLaravel::class, + Mockery::type('Closure') + ); + + $serviceProvider = new CacheUiLaravelServiceProvider($app); + $serviceProvider->register(); + }); + }); + + describe('boot method', function (): void { + it('has correct method signature', function (): void { + $reflection = new ReflectionClass(CacheUiLaravelServiceProvider::class); + $method = $reflection->getMethod('boot'); + + expect($method->isPublic())->toBeTrue(); + expect($method->getReturnType()->getName())->toBe('void'); + }); + }); +}); diff --git a/tests/Unit/ValuePreviewTest.php b/tests/Unit/ValuePreviewTest.php deleted file mode 100644 index f00e658..0000000 --- a/tests/Unit/ValuePreviewTest.php +++ /dev/null @@ -1,63 +0,0 @@ -getMethod('getValuePreview'); - - $preview = $method->invoke($command, null); - expect($preview)->toBe('(null)'); - }); - - it('handles string values correctly', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $testString = 'This is a test string'; - $preview = $method->invoke($command, $testString); - expect($preview)->toBe($testString); - }); - - it('handles boolean values correctly', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $truePreview = $method->invoke($command, true); - expect($truePreview)->toBe('true'); - - $falsePreview = $method->invoke($command, false); - expect($falsePreview)->toBe('false'); - }); - - it('handles array values correctly', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - $testArray = ['user_id' => 123, 'name' => 'Angel Cruz']; - $preview = $method->invoke($command, $testArray); - expect($preview)->toContain('user_id'); - expect($preview)->toContain('Angel Cruz'); - }); - - it('handles long strings with truncation', function (): void { - $command = new CacheUiLaravelCommand(); - $reflection = new ReflectionClass($command); - $method = $reflection->getMethod('getValuePreview'); - - // Create a long string (over 100 characters) - $longString = str_repeat('A', 150); - $preview = $method->invoke($command, $longString); - - // Debug: let's see what we get - expect($preview)->toContain('...'); - expect($preview)->toContain('...'); // The actual format used - }); -});