LoggingToolWrapperTest.php•3.98 kB
<?php
declare(strict_types=1);
namespace OpenFGA\MCP\Tests\Unit;
use Exception;
use OpenFGA\MCP\LoggingToolWrapper;
use ReflectionClass;
beforeEach(function (): void {
    $this->tool = new TestTool;
});
describe('LoggingToolWrapper', function (): void {
    describe('wrapTool', function (): void {
        it('wraps and executes simple method successfully', function (): void {
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'simpleMethod');
            expect($wrapped)->toBeCallable();
            $result = $wrapped();
            expect($result)->toBe('success');
        });
        it('wraps and executes method with arguments', function (): void {
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'methodWithArgs');
            $result = $wrapped(['arg1' => 'test', 'arg2' => 42]);
            expect($result)->toBeArray();
            expect($result['arg1'])->toBe('test');
            expect($result['arg2'])->toBe(42);
        });
        it('handles exceptions from wrapped method', function (): void {
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'methodThatThrows');
            expect(fn () => $wrapped())->toThrow(Exception::class, 'Test exception');
        });
        it('throws exception for non-existent method', function (): void {
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'nonExistentMethod');
            // Exception will be thrown when trying to invoke non-existent method
            expect(fn () => $wrapped())
                ->toThrow(Exception::class, 'Method nonExistentMethod not found');
        });
        it('handles private method access attempts', function (): void {
            // The wrapper will succeed in creating the wrapper, but calling it will throw
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'privateMethod');
            // Exception will be thrown when trying to invoke the private method
            expect(fn () => $wrapped())
                ->toThrow(Exception::class);
        });
        it('preserves argument order and types', function (): void {
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'methodWithArgs');
            // Test with different argument orders
            $result1 = $wrapped(['arg1' => 'first', 'arg2' => 1]);
            expect($result1)->toBe(['arg1' => 'first', 'arg2' => 1]);
            $result2 = $wrapped(['arg2' => 2, 'arg1' => 'second']);
            expect($result2)->toBe(['arg1' => 'second', 'arg2' => 2]);
        });
        it('returns callable that preserves context', function (): void {
            $wrapped1 = LoggingToolWrapper::wrapTool($this->tool, 'simpleMethod');
            $wrapped2 = LoggingToolWrapper::wrapTool($this->tool, 'simpleMethod');
            // Both should work independently
            expect($wrapped1())->toBe('success');
            expect($wrapped2())->toBe('success');
        });
        it('handles complex return types', function (): void {
            $wrapped = LoggingToolWrapper::wrapTool($this->tool, 'complexReturnType');
            $result = $wrapped();
            expect($result)->toBeObject();
            expect($result->key)->toBe('value');
            expect($result->nested)->toBeArray();
            expect($result->nested['data'])->toBeTrue();
        });
    });
    describe('static method behavior', function (): void {
        it('is a static method', function (): void {
            $reflection = new ReflectionClass(LoggingToolWrapper::class);
            $method = $reflection->getMethod('wrapTool');
            expect($method->isStatic())->toBeTrue();
            expect($method->isPublic())->toBeTrue();
        });
    });
    describe('class structure', function (): void {
        it('is a final class', function (): void {
            $reflection = new ReflectionClass(LoggingToolWrapper::class);
            expect($reflection->isFinal())->toBeTrue();
        });
    });
});