Completed
Pull Request — master (#3738)
by
unknown
66:03
created

OCI8StatementTest   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 11
eloc 61
dl 0
loc 156
rs 10
c 1
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 7 2
A testExecute() 0 34 2
A executeDataProvider() 0 10 1
A testBindParam() 0 23 3
A testConvertNonTerminatedLiteral() 0 5 1
A bindParamsDataProvider() 0 12 1
A nonTerminatedLiteralProvider() 0 14 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL\Driver\OCI8;
6
7
use Doctrine\DBAL\Driver\OCI8\OCI8Connection;
8
use Doctrine\DBAL\Driver\OCI8\OCI8Exception;
9
use Doctrine\DBAL\Driver\OCI8\OCI8Statement;
10
use Doctrine\Tests\DbalTestCase;
11
use PHPUnit\Framework\MockObject\MockObject;
12
use ReflectionProperty;
13
use const OCI_NO_AUTO_COMMIT;
14
use function extension_loaded;
15
use function fopen;
16
17
class OCI8StatementTest extends DbalTestCase
18
{
19
    protected function setUp() : void
20
    {
21
        if (! extension_loaded('oci8')) {
22
            $this->markTestSkipped('oci8 is not installed.');
23
        }
24
25
        parent::setUp();
26
    }
27
28
    /**
29
     * This scenario shows that when the first parameter is not null
30
     * it properly sets $hasZeroIndex to 1 and calls bindValue starting at 1.
31
     *
32
     * This also verifies that the statement will check with the connection to
33
     * see what the current execution mode is.
34
     *
35
     * The expected exception is due to oci_execute failing due to no valid connection.
36
     *
37
     * @param mixed[] $params
38
     *
39
     * @dataProvider executeDataProvider
40
     */
41
    public function testExecute(array $params) : void
42
    {
43
        /** @var OCI8Statement|MockObject $statement */
44
        $statement = $this->getMockBuilder(OCI8Statement::class)
45
            ->onlyMethods(['bindValue'])
46
            ->disableOriginalConstructor()
47
            ->getMock();
48
49
        foreach ($params as $index => $value) {
50
            $statement->expects($this->at($index))
51
                ->method('bindValue')
52
                ->with(
53
                    $this->equalTo($index + 1),
54
                    $this->equalTo($value)
55
                );
56
        }
57
58
        // can't pass to constructor since we don't have a real database handle,
59
        // but execute must check the connection for the executeMode
60
        $conn = $this->createMock(OCI8Connection::class);
61
        $conn->expects($this->once())
62
            ->method('getExecuteMode')
63
            ->willReturn(OCI_NO_AUTO_COMMIT);
64
65
        $connectionReflection = new ReflectionProperty($statement, '_conn');
66
        $connectionReflection->setAccessible(true);
67
        $connectionReflection->setValue($statement, $conn);
68
69
        $handleReflection = new ReflectionProperty($statement, '_sth');
70
        $handleReflection->setAccessible(true);
71
        $handleReflection->setValue($statement, fopen('php://temp', 'r'));
72
73
        $this->expectException(OCI8Exception::class);
74
        $statement->execute($params);
75
    }
76
77
    /**
78
     * Testing binding named and positioned parameters
79
     *
80
     * @param mixed[] $params
81
     *
82
     * @dataProvider bindParamsDataProvider
83
     */
84
    public function testBindParam(array $params, string $query) : void
85
    {
86
        $conn = $this->createMock(OCI8Connection::class);
87
        /** @var OCI8Statement|MockObject $statement */
88
        $statement = $this->getMockBuilder(OCI8Statement::class)
89
            ->onlyMethods([  'prepareQuery', 'bindParamByName'])
90
            // $dbh, string $query, OCI8Connection $conn
91
            ->setConstructorArgs([null, $query, $conn])
92
            ->getMock();
93
94
        $i = 0;
95
        foreach ($params as $index => $value) {
96
            $statement->expects($this->at($i))
97
                ->method('bindParamByName')
98
                ->with(
99
                    $this->stringStartsWith(':'),
100
                    $this->equalTo($value)
101
                );
102
            $i++;
103
        }
104
105
        foreach ($params as $index => $value) {
106
            $statement->bindParam($index, $value);
107
        }
108
    }
109
110
    /**
111
     * @return array<int, array<int, mixed>>
112
     */
113
    public static function executeDataProvider() : iterable
114
    {
115
        return [
116
            // $hasZeroIndex = isset($params[0]); == true
117
            [
118
                [0 => 'test', 1 => null, 2 => 'value'],
119
            ],
120
            // $hasZeroIndex = isset($params[0]); == false
121
            [
122
                [0 => null, 1 => 'test', 2 => 'value'],
123
            ],
124
        ];
125
    }
126
127
    /**
128
     * @return array<int, array<int, mixed>|string>
129
     */
130
    public static function bindParamsDataProvider() : iterable
131
    {
132
        return [
133
            // Positional placeholders
134
            [
135
                [1 => 'test', 2 => null, 3 => 'value'],
136
                'select * from dual where 1 = ? and 2 = ? and 3 = ?',
137
            ],
138
            // Named placeholders
139
            [
140
                [':p1' => null, ':p2' => 'test', ':p3' => 'value'],
141
                'select * from dual where 1 = :p1 and 2 = :p2 and 3 = :p3',
142
            ],
143
        ];
144
    }
145
146
    /**
147
     * @dataProvider nonTerminatedLiteralProvider
148
     */
149
    public function testConvertNonTerminatedLiteral(string $sql, string $message) : void
150
    {
151
        $this->expectException(OCI8Exception::class);
152
        $this->expectExceptionMessageRegExp($message);
1 ignored issue
show
Deprecated Code introduced by
The function PHPUnit\Framework\TestCa...xceptionMessageRegExp() has been deprecated: Use expectExceptionMessageMatches() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

152
        /** @scrutinizer ignore-deprecated */ $this->expectExceptionMessageRegExp($message);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
153
        OCI8Statement::convertPositionalToNamedPlaceholders($sql);
154
    }
155
156
    /**
157
     * @return array<string, array<int, mixed>>
158
     */
159
    public static function nonTerminatedLiteralProvider() : iterable
160
    {
161
        return [
162
            'no-matching-quote' => [
163
                "SELECT 'literal FROM DUAL",
164
                '/offset 7./',
165
            ],
166
            'no-matching-double-quote' => [
167
                'SELECT 1 "COL1 FROM DUAL',
168
                '/offset 9./',
169
            ],
170
            'incorrect-escaping-syntax' => [
171
                "SELECT 'quoted \\'string' FROM DUAL",
172
                '/offset 23./',
173
            ],
174
        ];
175
    }
176
}
177