toThrow(InvalidArgumentException::class, 'Class name cannot be empty'); }); it('returns false for whitespace-only strings', function () { expect(function () { ClassName::create(' '); })->toThrow(InvalidArgumentException::class, 'Invalid class name: '); expect(function () { ClassName::create("\t"); })->toThrow(InvalidArgumentException::class, 'Invalid class name: '); expect(function () { ClassName::create("\n"); })->toThrow(InvalidArgumentException::class, 'Invalid class name: '); }); it('returns true for existing classes', function () { $className = ClassName::create('stdClass'); expect($className->exists())->toBeTrue(); $className = ClassName::create('Exception'); expect($className->exists())->toBeTrue(); $className = ClassName::create('DateTime'); expect($className->exists())->toBeTrue(); }); it('returns true for existing interfaces', function () { $className = ClassName::create('Countable'); expect($className->exists())->toBeTrue(); $className = ClassName::create('Traversable'); expect($className->exists())->toBeTrue(); $className = ClassName::create('JsonSerializable'); expect($className->exists())->toBeTrue(); }); it('returns true for existing traits', function () { // PHP doesn't have many built-in traits, but let's test with a custom one // We'll create a simple trait for testing eval('trait TestTrait { public function testMethod() { return "test"; } }'); $className = ClassName::create('TestTrait'); expect($className->exists())->toBeTrue(); }); it('returns false for non-existent classes', function () { $className = ClassName::create('NonExistentClass'); expect($className->exists())->toBeFalse(); $className = ClassName::create('App\\NonExistent\\Class\\Name'); expect($className->exists())->toBeFalse(); $className = ClassName::create('Some\\Random\\ClassName'); expect($className->exists())->toBeFalse(); }); it('handles fully qualified class names correctly', function () { $className = ClassName::create('\\stdClass'); expect($className->exists())->toBeTrue(); $className = ClassName::create('\\Exception'); expect($className->exists())->toBeTrue(); $className = ClassName::create('\\NonExistentClass'); expect($className->exists())->toBeFalse(); }); it('handles framework classes correctly', function () { $className = ClassName::create('App\\Framework\\Core\\ValueObjects\\ClassName'); expect($className->exists())->toBeTrue(); $className = ClassName::create('App\\Framework\\DI\\Container'); expect($className->exists())->toBeTrue(); $className = ClassName::create('App\\Framework\\NonExistent\\Class'); expect($className->exists())->toBeFalse(); }); it('handles different case variations (PHP classes are case-insensitive)', function () { $className = ClassName::create('stdclass'); // lowercase expect($className->exists())->toBeTrue(); // PHP classes are case-insensitive $className = ClassName::create('STDCLASS'); // uppercase expect($className->exists())->toBeTrue(); // PHP classes are case-insensitive $className = ClassName::create('stdClass'); // correct case expect($className->exists())->toBeTrue(); }); it('handles invalid class name formats gracefully', function () { // These should be caught by constructor validation expect(function () { ClassName::create('123InvalidName'); })->toThrow(InvalidArgumentException::class); expect(function () { ClassName::create('Invalid-Name'); })->toThrow(InvalidArgumentException::class); expect(function () { ClassName::create('Invalid Name'); })->toThrow(InvalidArgumentException::class); }); it('performance test - does not cause memory leaks with many calls', function () { $memoryBefore = memory_get_usage(); // Test with many exists() calls for ($i = 0; $i < 1000; $i++) { $className = ClassName::create('stdClass'); $className->exists(); $className = ClassName::create('NonExistentClass' . $i); $className->exists(); } $memoryAfter = memory_get_usage(); $memoryIncrease = $memoryAfter - $memoryBefore; // Memory increase should be reasonable (less than 1MB for 2000 calls) expect($memoryIncrease)->toBeLessThan(1024 * 1024); }); it('works correctly with autoloader edge cases', function () { // Test that exists() doesn't trigger warnings or errors with edge cases $className = ClassName::create('App\\NonExistent\\VeryLongClassNameThatDefinitelyDoesNotExist\\WithMultipleNamespaces\\AndMore\\Classes'); expect($className->exists())->toBeFalse(); // Test with special characters that are valid in namespaces $className = ClassName::create('App\\Test\\ClassName123'); expect($className->exists())->toBeFalse(); }); it('handles concurrent access correctly', function () { // Simulate concurrent access to exists() method $results = []; for ($i = 0; $i < 10; $i++) { $className = ClassName::create('stdClass'); $results[] = $className->exists(); } // All results should be true foreach ($results as $result) { expect($result)->toBeTrue(); } // Test with non-existent class $results = []; for ($i = 0; $i < 10; $i++) { $className = ClassName::create('NonExistentClass'); $results[] = $className->exists(); } // All results should be false foreach ($results as $result) { expect($result)->toBeFalse(); } }); }); describe('ClassName::exists() integration with container', function () { it('prevents empty string issues in DI container context', function () { // This test ensures that ClassName::exists() works correctly when used // in the context that was causing the original "Uninitialized string offset 0" issue // Test the exact scenario that was failing $testCases = [ 'stdClass', // Should exist 'Exception', // Should exist 'NonExistentClass', // Should not exist 'App\\Framework\\DI\\Container', // Should exist (interface) 'App\\NonExistent\\Interface', // Should not exist ]; foreach ($testCases as $testClass) { $className = ClassName::create($testClass); $result = $className->exists(); // The important thing is that no warnings or errors are generated expect($result)->toBeIn([true, false]); } }); it('handles the AtomicStorage interface case that was failing', function () { // Test the specific case that was causing issues $className = ClassName::create('App\\Framework\\Filesystem\\AtomicStorage'); expect($className->exists())->toBeTrue(); // Interface should exist $className = ClassName::create('App\\Framework\\Filesystem\\Storage'); expect($className->exists())->toBeTrue(); // Interface should exist $className = ClassName::create('App\\Framework\\Filesystem\\FileStorage'); expect($className->exists())->toBeTrue(); // Implementation should exist }); it('regression test - ensures no "Uninitialized string offset 0" warnings', function () { // This is a regression test for the specific bug we fixed // The bug occurred when empty strings were passed to class_exists() // Capture any warnings or errors $errorLevel = error_reporting(E_ALL); $errors = []; set_error_handler(function ($severity, $message, $file, $line) use (&$errors) { $errors[] = [ 'severity' => $severity, 'message' => $message, 'file' => $file, 'line' => $line, ]; }); try { // Test various scenarios that could potentially cause the issue $testCases = [ 'stdClass', 'Exception', 'NonExistentClass', 'App\\Framework\\Filesystem\\AtomicStorage', 'App\\Framework\\Filesystem\\Storage', 'App\\Framework\\DI\\Container', 'App\\NonExistent\\Class\\Name', 'Very\\Long\\NonExistent\\Namespace\\ClassName', ]; foreach ($testCases as $testCase) { $className = ClassName::create($testCase); $result = $className->exists(); // Result should be boolean, no errors should occur expect($result)->toBeBool(); } // Ensure no "Uninitialized string offset" or similar warnings occurred foreach ($errors as $error) { expect($error['message'])->not->toContain('Uninitialized string offset'); expect($error['message'])->not->toContain('ClassLoader.php'); } // Should have no errors at all expect($errors)->toBeEmpty(); } finally { restore_error_handler(); error_reporting($errorLevel); } }); });