Passed
Branch main (45b422)
by Andreas
01:40
created

PDOStatementTest::testBindColumn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
c 0
b 0
f 0
rs 9.536
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Licensed to CRATE Technology GmbH("Crate") under one or more contributor
4
 * license agreements.  See the NOTICE file distributed with this work for
5
 * additional information regarding copyright ownership.  Crate licenses
6
 * this file to you under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.  You may
8
 * obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
15
 * License for the specific language governing permissions and limitations
16
 * under the License.
17
 *
18
 * However, if you have executed another commercial license agreement
19
 * with Crate these terms will supersede the license and you may use the
20
 * software solely pursuant to the terms of the relevant commercial agreement.
21
 */
22
23
namespace CrateTest\PDO;
24
25
use Crate\PDO\Exception\UnsupportedException;
26
use Crate\PDO\PDO;
27
use Crate\PDO\PDOInterface;
28
use Crate\PDO\PDOStatement;
29
use Crate\Stdlib\Collection;
30
use Crate\Stdlib\CollectionInterface;
31
use Crate\Stdlib\CrateConst;
32
use PHPUnit\Framework\TestCase;
33
use PHPUnit_Framework_MockObject_MockObject;
34
use ReflectionClass;
35
use ReflectionMethod;
36
use ReflectionProperty;
37
38
/**
39
 * Tests for {@see \Crate\PDO\PDOStatement}
40
 *
41
 * @coversDefaultClass \Crate\PDO\PDOStatement
42
 * @covers ::<!public>
43
 *
44
 * @group unit
45
 * @group statement
46
 */
47
class PDOStatementTest extends TestCase
48
{
49
    private const SQL = 'SELECT * FROM table_name';
50
51
    /**
52
     * @var PDO|PHPUnit_Framework_MockObject_MockObject
53
     */
54
    protected $pdo;
55
56
    /**
57
     * @var PDOStatement
58
     */
59
    protected $statement;
60
61
    /**
62
     * @var mixed
63
     */
64
    protected $callbackReturnValue;
65
66
    /**
67
     * @var array
68
     */
69
    protected $callbackCallParams;
70
71
    protected function setUp(): void
72
    {
73
        $this->pdo = $this->createMock(PDOInterface::class);
74
75
        $callback = function () {
76
77
            $args = func_get_args();
78
79
            if ($this->callbackCallParams !== null) {
80
                $this->assertEquals($args, $this->callbackCallParams);
81
            }
82
83
            return $this->callbackReturnValue;
84
        };
85
86
        $this->statement = new PDOStatement($this->pdo, $callback, static::SQL, []);
87
    }
88
89
    /**
90
     * @return CollectionInterface
91
     */
92
    private function getPopulatedCollection()
93
    {
94
        $data = [
95
            [1, 'foo', false],
96
            [2, 'bar', true],
97
        ];
98
99
        $columns = ['id', 'name', 'active'];
100
101
        return new Collection($data, $columns, 0, count($data));
102
    }
103
104
    /**
105
     * @covers ::__construct
106
     */
107
    public function testInstantiation()
108
    {
109
        $this->assertInstanceOf(PDOStatement::class, $this->statement);
110
        $this->assertInstanceOf(\PDOStatement::class, $this->statement);
111
    }
112
113
    /**
114
     * @covers ::execute
115
     */
116
    public function testExecuteWithErrorResponse()
117
    {
118
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'failed'];
119
120
        $this->assertFalse($this->statement->execute());
121
122
        list ($ansiErrorCode, $driverCode, $message) = $this->statement->errorInfo();
123
124
        $this->assertEquals(1337, $driverCode);
125
        $this->assertEquals('failed', $message);
126
    }
127
128
    /**
129
     * @covers ::execute
130
     */
131
    public function testExecute()
132
    {
133
        $parameters = ['bar'];
134
135
        $this->callbackCallParams  = [$this->statement, static::SQL, $parameters];
136
        $this->callbackReturnValue = $this->getPopulatedCollection();
137
138
        $this->assertTrue($this->statement->execute($parameters));
139
    }
140
141
    /**
142
     * @covers ::bindParam
143
     */
144
    public function testBindParam()
145
    {
146
        $initial  = 'foo';
147
        $expected = 'bar';
148
149
        $this->callbackCallParams  = [$this->statement, static::SQL, [0 => $expected]];
150
        $this->callbackReturnValue = $this->getPopulatedCollection();
151
152
        $this->statement->bindParam(1, $initial);
153
154
        // Update bar prior to calling execute
155
        $initial = $expected;
156
157
        $this->statement->execute();
158
    }
159
160
    /**
161
     * @covers ::bindParam
162
     */
163
    public function testBindParamInvalidPosition()
164
    {
165
        $initial  = 'foo';
166
        $expected = 'bar';
167
168
        $this->callbackCallParams  = [$this->statement, static::SQL, [0 => $expected]];
169
        $this->callbackReturnValue = $this->getPopulatedCollection();
170
171
        $this->expectException(UnsupportedException::class);
172
        $this->statement->bindParam(0, $initial);
173
    }
174
175
    /**
176
     * @covers ::bindColumn
177
     */
178
    public function testBindColumn()
179
    {
180
        $column     = 'column';
181
        $value      = 'value1';
182
        $type       = PDO::PARAM_STR;
183
        $maxlen     = 1000;
184
        $driverData = null;
185
186
        $this->statement->bindColumn($column, $value, $type, $maxlen, $driverData);
187
188
        $reflection = new ReflectionClass(PDOStatement::class);
189
190
        $property = $reflection->getProperty('columnBinding');
191
        $property->setAccessible(true);
192
193
        $columnBinding = $property->getValue($this->statement);
194
195
        $this->assertArrayHasKey($column, $columnBinding);
196
        $this->assertEquals($value, $columnBinding[$column]['ref']);
197
198
        $value = 'value2';
199
200
        $this->assertEquals($value, $columnBinding[$column]['ref']);
201
    }
202
203
    public function bindValueParameterProvider()
204
    {
205
        return [
206
            [PDO::PARAM_INT, '1', 1],
207
            [PDO::PARAM_NULL, '1', null],
208
            [PDO::PARAM_BOOL, '1', true],
209
            [PDO::PARAM_BOOL, 'false', false],
210
            [PDO::PARAM_BOOL, 'true', true],
211
            [PDO::PARAM_BOOL, '1', true],
212
            [PDO::PARAM_BOOL, '0', false],
213
            [PDO::PARAM_BOOL, '', false],
214
            [PDO::PARAM_STR, '1', '1'],
215
            [PDO::PARAM_INT, null, null],
216
            [PDO::PARAM_TIMESTAMP, null, null],
217
            [PDO::PARAM_BOOL, null, null],
218
        ];
219
    }
220
221
    /**
222
     * @dataProvider bindValueParameterProvider
223
     * @covers ::bindValue
224
     *
225
     * @param int    $type
226
     * @param string $value
227
     * @param mixed  $expectedValue
228
     */
229
    public function testBindValue($type, $value, $expectedValue)
230
    {
231
        $this->statement->bindValue(1, $value, $type);
232
233
        $reflection = new ReflectionClass(PDOStatement::class);
234
235
        $property = $reflection->getProperty('parameters');
236
        $property->setAccessible(true);
237
238
        $castedValue = $property->getValue($this->statement);
239
240
        $this->assertSame($expectedValue, $castedValue[0]);
241
    }
242
243
    /**
244
     * @covers ::fetch
245
     */
246
    public function testFetchWithUnsuccessfulExecution()
247
    {
248
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
249
250
        $this->assertFalse($this->statement->fetch());
251
    }
252
253
    /**
254
     * @covers ::fetch
255
     */
256
    public function testFetchWithEmptyResult()
257
    {
258
        $collection = $this->createMock(CollectionInterface::class);
259
        $collection
260
            ->expects($this->once())
261
            ->method('valid')
262
            ->will($this->returnValue(false));
263
264
        $this->callbackReturnValue = $collection;
265
266
        $this->assertFalse($this->statement->fetch(PDO::FETCH_NUM));
267
    }
268
269
    /**
270
     * @covers ::fetch
271
     */
272
    public function testFetchWithBoundStyle()
273
    {
274
        $id     = null;
275
        $name   = null;
276
        $active = null;
277
278
        $this->statement->bindColumn('id', $id, PDO::PARAM_INT);
279
        $this->statement->bindColumn('name', $name, PDO::PARAM_STR);
280
        $this->statement->bindColumn('active', $active, PDO::PARAM_BOOL);
281
282
        $this->assertNull($id);
283
        $this->assertNull($name);
284
        $this->assertNull($active);
285
286
        $this->callbackReturnValue = $this->getPopulatedCollection();
287
288
        $this->statement->fetch(PDO::FETCH_BOUND);
289
290
        $this->assertSame(1, $id);
291
        $this->assertSame('foo', $name);
292
        $this->assertFalse($active);
293
294
        $this->statement->fetch(PDO::FETCH_BOUND);
295
296
        $this->assertSame(2, $id);
297
        $this->assertSame('bar', $name);
298
        $this->assertTrue($active);
299
    }
300
301
    public function fetchStyleProvider()
302
    {
303
        return [
304
            [PDO::FETCH_NAMED, ['id' => 1, 'name' => 'foo', 'active' => false]],
305
            [PDO::FETCH_ASSOC, ['id' => 1, 'name' => 'foo', 'active' => false]],
306
            [PDO::FETCH_BOTH, [0 => 1, 1 => 'foo', 2 => false, 'id' => 1, 'name' => 'foo', 'active' => false]],
307
            [PDO::FETCH_NUM, [0 => 1, 1 => 'foo', 2 => false]],
308
        ];
309
    }
310
311
    /**
312
     * @dataProvider fetchStyleProvider
313
     * @covers ::fetch
314
     *
315
     * @param int   $fetchStyle
316
     * @param array $expected
317
     */
318
    public function testFetch($fetchStyle, array $expected)
319
    {
320
        $this->callbackReturnValue = $this->getPopulatedCollection();
321
322
        $result = $this->statement->fetch($fetchStyle);
323
324
        $this->assertEquals($expected, $result);
325
    }
326
327
    /**
328
     * @covers ::fetch
329
     */
330
    public function testFetchWithUnsupportedFetchStyle()
331
    {
332
        $this->expectException(UnsupportedException::class);
333
334
        $this->callbackReturnValue = $this->getPopulatedCollection();
335
336
        $this->statement->fetch(PDO::FETCH_INTO);
337
    }
338
339
    /**
340
     * @covers ::rowCount
341
     */
342
    public function testRowCountWithFailedExecution()
343
    {
344
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
345
346
        $this->assertEquals(0, $this->statement->rowCount());
347
    }
348
349
    /**
350
     * @covers ::rowCount
351
     */
352
    public function testRowCount()
353
    {
354
        $this->callbackReturnValue = $this->getPopulatedCollection();
355
        $this->assertEquals(2, $this->statement->rowCount());
356
    }
357
358
    /**
359
     * @covers ::fetchColumn
360
     */
361
    public function testFetchColumnWithInvalidColumnNumberType()
362
    {
363
        $this->expectException('Crate\PDO\Exception\InvalidArgumentException');
364
        $this->statement->fetchColumn('test');
365
    }
366
367
    /**
368
     * @covers ::fetchColumn
369
     */
370
    public function testFetchColumnWithFailedExecution()
371
    {
372
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
373
        $this->assertFalse($this->statement->fetchColumn());
374
    }
375
376
    /**
377
     * @covers ::fetchColumn
378
     */
379
    public function testFetchColumnWithWithEmptyCollection()
380
    {
381
        $collection = $this->createMock('Crate\Stdlib\CollectionInterface');
382
        $collection
383
            ->expects($this->once())
384
            ->method('valid')
385
            ->will($this->returnValue(false));
386
387
        $this->callbackReturnValue = $collection;
388
        $this->assertFalse($this->statement->fetchColumn());
389
    }
390
391
    /**
392
     * @covers ::fetchColumn
393
     */
394
    public function testFetchColumnWithInvalidColumnIndex()
395
    {
396
        $this->expectException('Crate\PDO\Exception\OutOfBoundsException');
397
398
        $this->callbackReturnValue = $this->getPopulatedCollection();
399
        $this->statement->fetchColumn(10);
400
    }
401
402
    /**
403
     * @covers ::fetchColumn
404
     */
405
    public function testFetchColumn()
406
    {
407
        $this->callbackReturnValue = $this->getPopulatedCollection();
408
409
        $this->assertEquals(1, $this->statement->fetchColumn());
410
        $this->assertEquals(2, $this->statement->fetchColumn());
411
        $this->assertFalse($this->statement->fetchColumn());
412
    }
413
414
    /**
415
     * @covers ::fetchAll
416
     */
417
    public function testFetchAllWithFailedExecution()
418
    {
419
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
420
421
        $this->assertFalse($this->statement->fetchAll());
422
    }
423
424
    /**
425
     * @covers ::fetchAll
426
     */
427
    public function testFetchAllWithInvalidFetchStyle()
428
    {
429
        $this->expectException(UnsupportedException::class);
430
        $this->callbackReturnValue = $this->getPopulatedCollection();
431
432
        $this->statement->fetchAll(PDO::FETCH_INTO);
433
    }
434
435
    /**
436
     * @return array
437
     */
438
    public function fetchAllStyleProvider()
439
    {
440
        return [
441
            [
442
                // Null mean it will use the default which is PDO::FETCH_BOTH
443
                null,
444
                [
445
                    [
446
                        0        => 1,
447
                        1        => 'foo',
448
                        2        => false,
449
                        'id'     => 1,
450
                        'name'   => 'foo',
451
                        'active' => false,
452
                    ],
453
                    [
454
                        0        => 2,
455
                        1        => 'bar',
456
                        2        => true,
457
                        'id'     => 2,
458
                        'name'   => 'bar',
459
                        'active' => true,
460
                    ],
461
                ],
462
            ],
463
            [
464
                PDO::FETCH_BOTH,
465
                [
466
                    [
467
                        0        => 1,
468
                        1        => 'foo',
469
                        2        => false,
470
                        'id'     => 1,
471
                        'name'   => 'foo',
472
                        'active' => false,
473
                    ],
474
                    [
475
                        0        => 2,
476
                        1        => 'bar',
477
                        2        => true,
478
                        'id'     => 2,
479
                        'name'   => 'bar',
480
                        'active' => true,
481
                    ],
482
                ],
483
            ],
484
            [
485
                PDO::FETCH_ASSOC,
486
                [
487
                    [
488
                        'id'     => 1,
489
                        'name'   => 'foo',
490
                        'active' => false,
491
                    ],
492
                    [
493
                        'id'     => 2,
494
                        'name'   => 'bar',
495
                        'active' => true,
496
                    ],
497
                ],
498
            ],
499
            [
500
                PDO::FETCH_NAMED,
501
                [
502
                    [
503
                        'id'     => 1,
504
                        'name'   => 'foo',
505
                        'active' => false,
506
                    ],
507
                    [
508
                        'id'     => 2,
509
                        'name'   => 'bar',
510
                        'active' => true,
511
                    ],
512
                ],
513
            ],
514
            [
515
                PDO::FETCH_NUM,
516
                [
517
                    [
518
                        0 => 1,
519
                        1 => 'foo',
520
                        2 => false,
521
                    ],
522
                    [
523
                        0 => 2,
524
                        1 => 'bar',
525
                        2 => true,
526
                    ],
527
                ],
528
            ],
529
            [
530
                PDO::FETCH_COLUMN,
531
                [
532
                    1,
533
                    2,
534
                ],
535
            ],
536
537
        ];
538
    }
539
540
    /**
541
     * @dataProvider fetchAllStyleProvider
542
     * @covers ::fetchAll
543
     *
544
     * @param string $fetchStyle
545
     * @param array  $expected
546
     */
547
    public function testFetchAll($fetchStyle, array $expected)
548
    {
549
        $this->callbackReturnValue = $this->getPopulatedCollection();
550
551
        $this->pdo
552
            ->expects($this->any())
553
            ->method('getAttribute')
554
            ->with(PDO::ATTR_DEFAULT_FETCH_MODE)
555
            ->will($this->returnValue(PDO::FETCH_BOTH));
556
557
        $result = $this->statement->fetchAll($fetchStyle);
558
559
        $this->assertEquals($expected, $result);
560
    }
561
562
    /**
563
     * @covers ::fetchAll
564
     */
565
    public function testFetchAllWithFetchStyleFuncAndInvalidCallback()
566
    {
567
        $this->expectException('Crate\PDO\Exception\InvalidArgumentException');
568
        $this->callbackReturnValue = $this->getPopulatedCollection();
569
570
        $this->statement->fetchAll(PDO::FETCH_FUNC, 'void');
571
    }
572
573
    /**
574
     * @covers ::fetchAll
575
     */
576
    public function testFetchAllBothSameColumnTwice()
577
    {
578
        $columns                   = ['id', 'id', 'name'];
579
        $this->callbackReturnValue = new Collection([[1, 1, 'foo']], $columns, 0, 1);
580
        $result                    = $this->statement->fetchAll(PDO::FETCH_BOTH);
581
582
        $expected = [[0 => 1, 1 => 1, 2 => 'foo', 'id' => 1, 'id' => 1, 'name' => 'foo']];
583
        $this->assertEquals($expected, $result);
584
    }
585
586
    /**
587
     * @covers ::fetchAll
588
     */
589
    public function testFetchAllWithFetchStyleFunc()
590
    {
591
        $this->callbackReturnValue = $this->getPopulatedCollection();
592
593
        $result = $this->statement->fetchAll(PDO::FETCH_FUNC, function ($id, $name, $active) {
594
            return $id;
595
        });
596
597
        $this->assertEquals([1, 2], $result);
598
    }
599
600
    /**
601
     * @covers ::fetchAll
602
     */
603
    public function testFetchAllWithFetchStyleColumnAndInvalidColumnIndexType()
604
    {
605
        $this->expectException('Crate\PDO\Exception\InvalidArgumentException');
606
        $this->callbackReturnValue = $this->getPopulatedCollection();
607
608
        $this->statement->fetchAll(PDO::FETCH_COLUMN, 'test');
609
    }
610
611
    /**
612
     * @covers ::fetchAll
613
     */
614
    public function testFetchAllWithFetchStyleColumnAndInvalidColumnIndex()
615
    {
616
        $this->expectException('Crate\PDO\Exception\OutOfBoundsException');
617
        $this->callbackReturnValue = $this->getPopulatedCollection();
618
619
        $this->statement->fetchAll(PDO::FETCH_COLUMN, 100);
620
    }
621
622
    /**
623
     * @covers ::fetchObject
624
     */
625
    public function testFetchObject()
626
    {
627
        $this->expectException(UnsupportedException::class);
628
        $this->statement->fetchObject();
629
    }
630
631
    /**
632
     * @covers ::errorCode
633
     */
634
    public function testErrorCode()
635
    {
636
        $this->assertNull($this->statement->errorCode());
637
638
        $reflection = new ReflectionClass(PDOStatement::class);
639
640
        $property = $reflection->getProperty('errorCode');
641
        $property->setAccessible(true);
642
        $property->setValue($this->statement, 1337);
643
644
        $this->assertEquals(1337, $this->statement->errorCode());
645
    }
646
647
    /**
648
     * @return array
649
     */
650
    public function errorInfoAnsiCodeProvider()
651
    {
652
        return [
653
            [42000, CrateConst::ERR_INVALID_SQL, 'le error message'],
654
            ['Not available', 1337, 'le error message'],
655
        ];
656
    }
657
658
    /**
659
     * @covers ::errorInfo
660
     * @dataProvider errorInfoAnsiCodeProvider
661
     *
662
     * @param mixed  $ansiCode
663
     * @param int    $errorCode
664
     * @param string $errorMessage
665
     */
666
    public function testErrorInfo($ansiCode, $errorCode, $errorMessage)
667
    {
668
        $this->assertNull($this->statement->errorInfo());
669
670
        $reflection = new ReflectionClass(PDOStatement::class);
671
672
        $errorCodeProp = $reflection->getProperty('errorCode');
673
        $errorCodeProp->setAccessible(true);
674
        $errorCodeProp->setValue($this->statement, $errorCode);
675
676
        $errorMessageProp = $reflection->getProperty('errorMessage');
677
        $errorMessageProp->setAccessible(true);
678
        $errorMessageProp->setValue($this->statement, $errorMessage);
679
680
        $this->assertEquals([$ansiCode, $errorCode, $errorMessage], $this->statement->errorInfo());
681
    }
682
683
    /**
684
     * @covers ::getAttribute
685
     */
686
    public function testGetAttribute()
687
    {
688
        $this->expectException(UnsupportedException::class);
689
        $this->statement->getAttribute(null, null);
690
    }
691
692
    /**
693
     * @covers ::setAttribute
694
     */
695
    public function testSetAttribute()
696
    {
697
        $this->expectException(UnsupportedException::class);
698
        $this->statement->setAttribute(null, null);
699
    }
700
701
    /**
702
     * @covers ::columnCount
703
     */
704
    public function testColumnCount()
705
    {
706
        $this->callbackReturnValue = $this->getPopulatedCollection();
707
        $this->assertEquals(3, $this->statement->columnCount());
708
    }
709
710
    /**
711
     * @covers ::columnCount
712
     */
713
    public function testColumnCountSameColumnTwice()
714
    {
715
        $data = [
716
            [1, 1],
717
            [2, 2],
718
        ];
719
720
        $this->callbackReturnValue = new Collection($data, ['id', 'id'], 0, 2);
721
        $this->assertEquals(2, $this->statement->columnCount());
722
    }
723
724
    /**
725
     * @covers ::getColumnMeta
726
     */
727
    public function testGetColumnMeta()
728
    {
729
        $this->expectException(UnsupportedException::class);
730
        $this->statement->getColumnMeta(null);
731
    }
732
733
    /**
734
     * @covers ::setFetchMode
735
     */
736
    public function testSetFetchModeWithColumnAndMissingColNo()
737
    {
738
        $this->expectException(
739
            'Crate\PDO\Exception\InvalidArgumentException',
740
            'fetch mode requires the colno argument'
741
        );
742
743
        $this->statement->setFetchMode(PDO::FETCH_COLUMN);
744
    }
745
746
    /**
747
     * @covers ::setFetchMode
748
     */
749
    public function testSetFetchModeWithColumnAndInvalidColNo()
750
    {
751
        $this->expectException(
752
            'Crate\PDO\Exception\InvalidArgumentException',
753
            'colno must be an integer'
754
        );
755
756
        $this->statement->setFetchMode(PDO::FETCH_COLUMN, 'test');
757
    }
758
759
    /**
760
     * @covers ::setFetchMode
761
     */
762
    public function testSetFetchModeWithColumn()
763
    {
764
        $this->statement->setFetchMode(PDO::FETCH_COLUMN, 1);
765
766
        $reflection = new ReflectionClass(PDOStatement::class);
767
768
        $property = $reflection->getProperty('options');
769
        $property->setAccessible(true);;
770
771
        $options = $property->getValue($this->statement);
772
773
        $this->assertEquals(PDO::FETCH_COLUMN, $options['fetchMode']);
774
        $this->assertEquals(1, $options['fetchColumn']);
775
    }
776
777
    public function fetchModeStyleProvider()
778
    {
779
        return [
780
            [PDO::FETCH_ASSOC],
781
            [PDO::FETCH_NUM],
782
            [PDO::FETCH_BOTH],
783
            [PDO::FETCH_BOUND],
784
            [PDO::FETCH_NAMED],
785
        ];
786
    }
787
788
    /**
789
     * @covers ::setFetchMode
790
     * @dataProvider fetchModeStyleProvider
791
     *
792
     * @param int $fetchStyle
793
     */
794
    public function testSetFetchMode($fetchStyle)
795
    {
796
        $this->statement->setFetchMode($fetchStyle);
797
798
        $reflection = new ReflectionClass(PDOStatement::class);
799
800
        $property = $reflection->getProperty('options');
801
        $property->setAccessible(true);
802
803
        $options = $property->getValue($this->statement);
804
805
        $this->assertEquals($fetchStyle, $options['fetchMode']);
806
    }
807
808
    /**
809
     * @covers ::setFetchMode
810
     */
811
    public function testSetFetchModeWithInvalidFetchStyle()
812
    {
813
        $this->expectException(UnsupportedException::class);
814
        $this->statement->setFetchMode(PDO::FETCH_INTO);
815
    }
816
817
    /**
818
     * @covers ::setFetchMode
819
     * @dataProvider fetchModeStyleProvider
820
     *
821
     * @param int $fetchStyle
822
     */
823
    public function testSetFetchModeWithInvalidExtraParam($fetchStyle)
824
    {
825
        $this->expectException('Crate\PDO\Exception\InvalidArgumentException');
826
        $this->statement->setFetchMode($fetchStyle, 'fooBar');
827
    }
828
829
    /**
830
     * @covers ::nextRowset
831
     */
832
    public function testNextRowsetWithFailedExecution()
833
    {
834
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
835
        $this->assertFalse($this->statement->nextRowset());
836
    }
837
838
    /**
839
     * @covers ::nextRowset
840
     */
841
    public function testNextRowset()
842
    {
843
        $this->callbackReturnValue = $this->getPopulatedCollection();
844
845
        $this->assertTrue($this->statement->nextRowset());
846
        $this->assertFalse($this->statement->nextRowset());
847
    }
848
849
    /**
850
     * @covers ::debugDumpParams
851
     */
852
    public function testDumpDebugParams()
853
    {
854
        $this->expectException('Crate\PDO\Exception\PDOException');
855
        $this->statement->debugDumpParams();
856
    }
857
858
    /**
859
     * @covers ::getIterator
860
     */
861
    public function testGetIterator()
862
    {
863
        $this->callbackReturnValue = $this->getPopulatedCollection();
864
        $this->statement->setFetchMode(PDO::FETCH_COLUMN, 0);
865
866
        $counter = 0;
867
868
        foreach ($this->statement->getIterator() as $id) {
869
            $this->assertEquals(++$counter, $id);
870
        }
871
872
        $this->assertEquals(2, $counter);
873
    }
874
875
    /**
876
     * @covers ::closeCursor
877
     */
878
    public function testCloseCursorReturnsTrue()
879
    {
880
        $this->assertTrue($this->statement->closeCursor());
881
    }
882
883
    /**
884
     * @covers ::typedValue
885
     */
886
    public function testTypedValue()
887
    {
888
        $method = new ReflectionMethod(PDOStatement::class, 'typedValue');
889
        $method->setAccessible(true);
890
891
        $this->assertEquals(1.23, $method->invoke($this->statement, 1.23, PDO::PARAM_FLOAT));
892
        $this->assertEquals(1.23, $method->invoke($this->statement, 1.23, PDO::PARAM_DOUBLE));
893
894
        $this->assertEquals(1, $method->invoke($this->statement, 1, PDO::PARAM_INT));
895
        $this->assertEquals(1, $method->invoke($this->statement, 1, PDO::PARAM_LONG));
896
897
        $this->assertEquals(null, $method->invoke($this->statement, 1, PDO::PARAM_NULL));
898
899
        $this->assertEquals("hello", $method->invoke($this->statement, "hello", PDO::PARAM_STR));
900
        $this->assertEquals("1234", $method->invoke($this->statement, 1234, PDO::PARAM_STR));
901
        $this->assertEquals("127.0.0.1", $method->invoke($this->statement, "127.0.0.1", PDO::PARAM_IP));
902
903
        $this->assertEquals([1, 2], $method->invoke($this->statement, [1, 2], PDO::PARAM_ARRAY));
904
        $this->assertEquals(["foo" => "bar"], $method->invoke($this->statement, ["foo" => "bar"], PDO::PARAM_ARRAY));
905
906
        $this->assertEquals(12345, $method->invoke($this->statement, 12345, PDO::PARAM_TIMESTAMP));
907
        $this->assertEquals(12345, $method->invoke($this->statement, "12345", PDO::PARAM_TIMESTAMP));
908
        $this->assertEquals("2014-03-04T18:45:20", $method->invoke($this->statement, "2014-03-04T18:45:20", PDO::PARAM_TIMESTAMP));
909
910
    }
911
912
    /**
913
     * @covers ::typedValue
914
     */
915
    public function testTypedValueInvalid()
916
    {
917
        $method = new ReflectionMethod(PDOStatement::class, 'typedValue');
918
        $method->setAccessible(true);
919
920
        $this->expectException('Crate\PDO\Exception\PDOException');
921
        $method->invoke($this->statement, 1, PDO::PARAM_LOB);
922
    }
923
924
    /**
925
     * @covers ::replaceNamedParametersWithPositionals
926
     */
927
    public function testReplaceNamedParametersWithPositionals()
928
    {
929
        $method = new ReflectionMethod(PDOStatement::class, 'replaceNamedParametersWithPositionals');
930
        $method->setAccessible(true);
931
        $property = new ReflectionProperty(PDOStatement::class, 'namedToPositionalMap');
932
        $property->setAccessible(true);
933
934
        $sql           = "select * from test_table where name = :name and hoschi = 'sld''fn:sdfsf' and id = :id";
935
        $sql_converted = $method->invoke($this->statement, $sql);
936
        $this->assertEquals("select * from test_table where name = ? and hoschi = 'sld''fn:sdfsf' and id = ?", $sql_converted);
937
        $nameToPositionalMap = $property->getValue($this->statement);
938
        $this->assertEquals("name", $nameToPositionalMap[1]);
939
        $this->assertEquals("id", $nameToPositionalMap[2]);
940
    }
941
942
    public function testReplaceNamedParametersWithPositionalsMultiple()
943
    {
944
        $method = new ReflectionMethod(PDOStatement::class, 'replaceNamedParametersWithPositionals');
945
        $method->setAccessible(true);
946
        $property = new ReflectionProperty(PDOStatement::class, 'namedToPositionalMap');
947
        $property->setAccessible(true);
948
949
        $sql           = "update test_table set name = concat(name, :name) where id = :id and name != :name";
950
        $sql_converted = $method->invoke($this->statement, $sql);
951
        $this->assertEquals("update test_table set name = concat(name, ?) where id = ? and name != ?", $sql_converted);
952
        $nameToPositionalMap = $property->getValue($this->statement);
953
        $this->assertEquals("name", $nameToPositionalMap[1]);
954
        $this->assertEquals("id", $nameToPositionalMap[2]);
955
        $this->assertEquals("name", $nameToPositionalMap[3]);
956
    }
957
958
}
959
960