connection = Mockery::mock(ConnectionInterface::class); $this->manager = new StoredProcedureManager($this->connection); }); afterEach(function () { Mockery::close(); }); test('creates a stored procedure', function () { $procedure = StoredProcedureDefinition::create('get_user_by_id') ->withParameter('user_id', 'INT') ->withBody('SELECT * FROM users WHERE id = user_id') ->returnsType('TABLE'); $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $this->connection->shouldReceive('execute') ->with(Mockery::pattern('/CREATE PROCEDURE/'), []) ->once() ->andReturn(1); $result = $this->manager->createProcedure($procedure); expect($result)->toBeTrue(); }); test('drops a stored procedure', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $this->connection->shouldReceive('execute') ->with('DROP PROCEDURE IF EXISTS `get_user_by_id`', []) ->once() ->andReturn(1); $result = $this->manager->dropProcedure('get_user_by_id'); expect($result)->toBeTrue(); }); test('checks if a stored procedure exists', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $this->connection->shouldReceive('queryScalar') ->with(Mockery::pattern('/INFORMATION_SCHEMA.ROUTINES/'), ['get_user_by_id']) ->once() ->andReturn(1); $result = $this->manager->procedureExists('get_user_by_id'); expect($result)->toBeTrue(); }); test('executes a stored procedure with parameters', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $mockResult = Mockery::mock(ResultInterface::class); $mockResult->shouldReceive('fetchAll')->andReturn([ ['id' => 1, 'name' => 'John Doe', 'email' => 'john@example.com'], ]); $this->connection->shouldReceive('query') ->with('CALL get_user_by_id(?)', [42]) ->once() ->andReturn($mockResult); $result = $this->manager->executeProcedure('get_user_by_id', [42]); expect($result)->toBeInstanceOf(ResultInterface::class); expect($result->fetchAll())->toHaveCount(1); expect($result->fetchAll()[0]['name'])->toBe('John Doe'); }); test('executes a stored function with parameters', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $this->connection->shouldReceive('queryScalar') ->with('SELECT calculate_order_total(?, ?)', [123, true]) ->once() ->andReturn(99.99); $result = $this->manager->executeFunction('calculate_order_total', [123, true]); expect($result)->toBe(99.99); }); test('lists all stored procedures', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $mockResult = Mockery::mock(ResultInterface::class); $mockResult->shouldReceive('fetchAll')->andReturn([ ['ROUTINE_NAME' => 'get_user_by_id', 'ROUTINE_TYPE' => 'PROCEDURE'], ['ROUTINE_NAME' => 'calculate_order_total', 'ROUTINE_TYPE' => 'FUNCTION'], ]); $this->connection->shouldReceive('query') ->with(Mockery::pattern('/INFORMATION_SCHEMA.ROUTINES/'), []) ->once() ->andReturn($mockResult); $procedures = $this->manager->listProcedures(); expect($procedures)->toHaveCount(2); expect($procedures[0]['name'])->toBe('get_user_by_id'); expect($procedures[0]['type'])->toBe('PROCEDURE'); expect($procedures[1]['name'])->toBe('calculate_order_total'); expect($procedures[1]['type'])->toBe('FUNCTION'); }); test('gets procedure definition', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('mysql'); $mockResult = Mockery::mock(ResultInterface::class); $mockResult->shouldReceive('fetchOne')->andReturn([ 'ROUTINE_NAME' => 'get_user_by_id', 'ROUTINE_TYPE' => 'PROCEDURE', 'ROUTINE_DEFINITION' => 'SELECT * FROM users WHERE id = user_id', 'DTD_IDENTIFIER' => null, 'PARAMETER_STYLE' => 'SQL', ]); $this->connection->shouldReceive('query') ->with(Mockery::pattern('/INFORMATION_SCHEMA.ROUTINES/'), ['get_user_by_id']) ->once() ->andReturn($mockResult); $paramResult = Mockery::mock(ResultInterface::class); $paramResult->shouldReceive('fetchAll')->andReturn([ ['PARAMETER_NAME' => 'user_id', 'DATA_TYPE' => 'INT', 'PARAMETER_MODE' => 'IN'], ]); $this->connection->shouldReceive('query') ->with(Mockery::pattern('/INFORMATION_SCHEMA.PARAMETERS/'), ['get_user_by_id']) ->once() ->andReturn($paramResult); $definition = $this->manager->getProcedureDefinition('get_user_by_id'); expect($definition)->toBeInstanceOf(StoredProcedureDefinition::class); expect($definition->getName())->toBe('get_user_by_id'); expect($definition->getBody())->toBe('SELECT * FROM users WHERE id = user_id'); expect($definition->getParameters())->toHaveCount(1); expect($definition->getParameters()[0]['name'])->toBe('user_id'); expect($definition->getParameters()[0]['type'])->toBe('INT'); }); test('handles unsupported database driver', function () { $this->connection->shouldReceive('getPdo->getAttribute') ->with(\PDO::ATTR_DRIVER_NAME) ->andReturn('unsupported_driver'); expect(fn () => $this->manager->procedureExists('test_procedure')) ->toThrow(\InvalidArgumentException::class, 'Unsupported database driver: unsupported_driver'); });