Completed
Push — h/allow-multiple-named-params ( 2eb7f0 )
by Christian
05:00
created

testReplaceNamedParametersWithPositionalsMultiple()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 15
rs 9.4285
cc 1
eloc 12
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\PDO;
26
use Crate\PDO\PDOStatement;
27
use Crate\Stdlib\Collection;
28
use Crate\Stdlib\CollectionInterface;
29
use Crate\Stdlib\CrateConst;
30
use PHPUnit_Framework_MockObject_MockObject;
31
use PHPUnit_Framework_TestCase;
32
use ReflectionClass;
33
use ReflectionMethod;
34
use ReflectionProperty;
35
36
/**
37
 * Tests for {@see \Crate\PDO\PDOStatement}
38
 *
39
 * @coversDefaultClass \Crate\PDO\PDOStatement
40
 * @covers ::<!public>
41
 *
42
 * @group unit
43
 * @group statement
44
 */
45
class PDOStatementTest extends PHPUnit_Framework_TestCase
46
{
47
    const SQL = 'SELECT * FROM table_name';
48
49
    /**
50
     * @var PDO|PHPUnit_Framework_MockObject_MockObject
51
     */
52
    protected $pdo;
53
54
    /**
55
     * @var PDOStatement
56
     */
57
    protected $statement;
58
59
    /**
60
     * @var mixed
61
     */
62
    protected $callbackReturnValue;
63
64
    /**
65
     * @var array
66
     */
67
    protected $callbackCallParams;
68
69
    protected function setUp()
70
    {
71
        $this->pdo = $this->getMock('Crate\PDO\PDOInterface');
72
73
74
        $callback = function() {
75
76
            $args = func_get_args();
77
78
            if ($this->callbackCallParams !== null) {
79
                $this->assertEquals($args, $this->callbackCallParams);
80
            }
81
82
            return $this->callbackReturnValue;
83
        };
84
85
        $this->statement = new PDOStatement($this->pdo, $callback, static::SQL, []);
86
    }
87
88
    /**
89
     * @return CollectionInterface
90
     */
91
    private function getPopulatedCollection()
92
    {
93
        $data = [
94
            [1, 'foo', false],
95
            [2, 'bar', true],
96
        ];
97
98
        $columns = ['id', 'name', 'active'];
99
100
        return new Collection($data, $columns, 0, count($data));
101
    }
102
103
    /**
104
     * @covers ::__construct
105
     */
106
    public function testInstantiation()
107
    {
108
        $this->assertInstanceOf('Crate\PDO\PDOStatement', $this->statement);
109
        $this->assertInstanceOf('PDOStatement', $this->statement);
110
    }
111
112
    /**
113
     * @covers ::execute
114
     */
115
    public function testExecuteWithErrorResponse()
116
    {
117
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'failed'];
118
119
        $this->assertFalse($this->statement->execute());
120
121
        list ($ansiErrorCode, $driverCode, $message) = $this->statement->errorInfo();
0 ignored issues
show
Unused Code introduced by
The assignment to $ansiErrorCode is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
122
123
        $this->assertEquals(1337, $driverCode);
124
        $this->assertEquals('failed', $message);
125
    }
126
127
    /**
128
     * @covers ::execute
129
     */
130
    public function testExecute()
131
    {
132
        $parameters = ['bar'];
133
134
        $this->callbackCallParams  = [$this->statement, static::SQL, $parameters];
135
        $this->callbackReturnValue = $this->getPopulatedCollection();
136
137
        $this->assertTrue($this->statement->execute($parameters));
138
    }
139
140
    /**
141
     * @covers ::bindParam
142
     */
143
    public function testBindParam()
144
    {
145
        $initial  = 'foo';
146
        $expected = 'bar';
147
148
        $this->callbackCallParams  = [$this->statement, static::SQL, [0 => $expected]];
149
        $this->callbackReturnValue = $this->getPopulatedCollection();
150
151
        $this->statement->bindParam(1, $initial);
152
153
        // Update bar prior to calling execute
154
        $initial = $expected;
0 ignored issues
show
Unused Code introduced by
$initial is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
155
156
        $this->statement->execute();
157
    }
158
159
    /**
160
     * @covers ::bindParam
161
     */
162
    public function testBindParamInvalidPosition()
163
    {
164
        $initial  = 'foo';
165
        $expected = 'bar';
166
167
        $this->callbackCallParams  = [$this->statement, static::SQL, [0 => $expected]];
168
        $this->callbackReturnValue = $this->getPopulatedCollection();
169
170
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
171
        $this->statement->bindParam(0, $initial);
172
    }
173
174
    /**
175
     * @covers ::bindColumn
176
     */
177
    public function testBindColumn()
178
    {
179
        $column     = 'column';
180
        $value      = 'value1';
181
        $type       = PDO::PARAM_STR;
182
        $maxlen     = 1000;
183
        $driverData = null;
184
185
        $this->statement->bindColumn($column, $value, $type, $maxlen, $driverData);
186
187
        $reflection = new ReflectionClass('Crate\PDO\PDOStatement');
188
189
        $property = $reflection->getProperty('columnBinding');
190
        $property->setAccessible(true);
191
192
        $columnBinding = $property->getValue($this->statement);
193
194
        $this->assertArrayHasKey($column, $columnBinding);
195
        $this->assertEquals($value, $columnBinding[$column]['ref']);
196
197
        $value = 'value2';
198
199
        $this->assertEquals($value, $columnBinding[$column]['ref']);
200
    }
201
202
    public function bindValueParameterProvider()
203
    {
204
        return [
205
            [PDO::PARAM_INT, '1', 1],
206
            [PDO::PARAM_NULL, '1', null],
207
            [PDO::PARAM_BOOL, '1', true],
208
            [PDO::PARAM_STR, '1', '1']
209
        ];
210
    }
211
212
    /**
213
     * @dataProvider bindValueParameterProvider
214
     * @covers ::bindValue
215
     *
216
     * @param int    $type
217
     * @param string $value
218
     * @param mixed  $expectedValue
219
     */
220
    public function testBindValue($type, $value, $expectedValue)
221
    {
222
        $this->statement->bindValue(1, $value, $type);
223
224
        $reflection = new ReflectionClass('Crate\PDO\PDOStatement');
225
226
        $property = $reflection->getProperty('parameters');
227
        $property->setAccessible(true);
228
229
        $castedValue = $property->getValue($this->statement);
230
231
        $this->assertSame($expectedValue, $castedValue[0]);
232
    }
233
234
    /**
235
     * @covers ::fetch
236
     */
237
    public function testFetchWithUnsuccessfulExecution()
238
    {
239
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
240
241
        $this->assertFalse($this->statement->fetch());
242
    }
243
244
    /**
245
     * @covers ::fetch
246
     */
247
    public function testFetchWithEmptyResult()
248
    {
249
        $collection = $this->getMock('Crate\Stdlib\CollectionInterface');
250
        $collection
251
            ->expects($this->once())
252
            ->method('valid')
253
            ->will($this->returnValue(false));
254
255
        $this->callbackReturnValue = $collection;
256
257
        $this->assertFalse($this->statement->fetch(PDO::FETCH_NUM));
258
    }
259
260
    /**
261
     * @covers ::fetch
262
     */
263
    public function testFetchWithBoundStyle()
264
    {
265
        $id     = null;
266
        $name   = null;
267
        $active = null;
268
269
        $this->statement->bindColumn('id', $id, PDO::PARAM_INT);
270
        $this->statement->bindColumn('name', $name, PDO::PARAM_STR);
271
        $this->statement->bindColumn('active', $active, PDO::PARAM_BOOL);
272
273
        $this->assertNull($id);
274
        $this->assertNull($name);
275
        $this->assertNull($active);
276
277
        $this->callbackReturnValue = $this->getPopulatedCollection();
278
279
        $this->statement->fetch(PDO::FETCH_BOUND);
280
281
        $this->assertSame(1, $id);
282
        $this->assertSame('foo', $name);
283
        $this->assertFalse($active);
284
285
        $this->statement->fetch(PDO::FETCH_BOUND);
286
287
        $this->assertSame(2, $id);
288
        $this->assertSame('bar', $name);
289
        $this->assertTrue($active);
290
    }
291
292
    public function fetchStyleProvider()
293
    {
294
        return [
295
            [PDO::FETCH_NAMED, ['id' => 1, 'name' => 'foo', 'active' => false]],
296
            [PDO::FETCH_ASSOC, ['id' => 1, 'name' => 'foo', 'active' => false]],
297
            [PDO::FETCH_BOTH, [0 => 1, 1 => 'foo', 2 => false, 'id' => 1, 'name' => 'foo', 'active' => false]],
298
            [PDO::FETCH_NUM, [0 => 1, 1 => 'foo', 2 => false]]
299
        ];
300
    }
301
302
    /**
303
     * @dataProvider fetchStyleProvider
304
     * @covers ::fetch
305
     *
306
     * @param int   $fetchStyle
307
     * @param array $expected
308
     */
309
    public function testFetch($fetchStyle, array $expected)
310
    {
311
        $this->callbackReturnValue = $this->getPopulatedCollection();
312
313
        $result = $this->statement->fetch($fetchStyle);
314
315
        $this->assertEquals($expected, $result);
316
    }
317
318
    /**
319
     * @covers ::fetch
320
     */
321
    public function testFetchWithUnsupportedFetchStyle()
322
    {
323
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
324
325
        $this->callbackReturnValue = $this->getPopulatedCollection();
326
327
        $this->statement->fetch(PDO::FETCH_INTO);
328
    }
329
330
    /**
331
     * @covers ::rowCount
332
     */
333
    public function testRowCountWithFailedExecution()
334
    {
335
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
336
337
        $this->assertEquals(0, $this->statement->rowCount());
338
    }
339
340
    /**
341
     * @covers ::rowCount
342
     */
343
    public function testRowCount()
344
    {
345
        $this->callbackReturnValue = $this->getPopulatedCollection();
346
        $this->assertEquals(2, $this->statement->rowCount());
347
    }
348
349
    /**
350
     * @covers ::fetchColumn
351
     */
352
    public function testFetchColumnWithInvalidColumnNumberType()
353
    {
354
        $this->setExpectedException('Crate\PDO\Exception\InvalidArgumentException');
355
        $this->statement->fetchColumn('test');
356
    }
357
358
    /**
359
     * @covers ::fetchColumn
360
     */
361
    public function testFetchColumnWithFailedExecution()
362
    {
363
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
364
        $this->assertFalse($this->statement->fetchColumn());
365
    }
366
367
    /**
368
     * @covers ::fetchColumn
369
     */
370
    public function testFetchColumnWithWithEmptyCollection()
371
    {
372
        $collection = $this->getMock('Crate\Stdlib\CollectionInterface');
373
        $collection
374
            ->expects($this->once())
375
            ->method('valid')
376
            ->will($this->returnValue(false));
377
378
        $this->callbackReturnValue = $collection;
379
        $this->assertFalse($this->statement->fetchColumn());
380
    }
381
382
    /**
383
     * @covers ::fetchColumn
384
     */
385
    public function testFetchColumnWithInvalidColumnIndex()
386
    {
387
        $this->setExpectedException('Crate\PDO\Exception\OutOfBoundsException');
388
389
        $this->callbackReturnValue = $this->getPopulatedCollection();
390
        $this->statement->fetchColumn(10);
391
    }
392
393
    /**
394
     * @covers ::fetchColumn
395
     */
396
    public function testFetchColumn()
397
    {
398
        $this->callbackReturnValue = $this->getPopulatedCollection();
399
400
        $this->assertEquals(1, $this->statement->fetchColumn());
401
        $this->assertEquals(2, $this->statement->fetchColumn());
402
        $this->assertFalse($this->statement->fetchColumn());
403
    }
404
405
    /**
406
     * @covers ::fetchAll
407
     */
408
    public function testFetchAllWithFailedExecution()
409
    {
410
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
411
412
        $this->assertFalse($this->statement->fetchAll());
413
    }
414
415
    /**
416
     * @covers ::fetchAll
417
     */
418
    public function testFetchAllWithInvalidFetchStyle()
419
    {
420
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
421
        $this->callbackReturnValue = $this->getPopulatedCollection();
422
423
        $this->statement->fetchAll(PDO::FETCH_INTO);
424
    }
425
426
    /**
427
     * @return array
428
     */
429
    public function fetchAllStyleProvider()
430
    {
431
        return [
432
            [
433
                // Null mean it will use the default which is PDO::FETCH_BOTH
434
                null,
435
                [
436
                    [
437
                        0        => 1,
438
                        1        => 'foo',
439
                        2        => false,
440
                        'id'     => 1,
441
                        'name'   => 'foo',
442
                        'active' => false
443
                    ],
444
                    [
445
                        0        => 2,
446
                        1        => 'bar',
447
                        2        => true,
448
                        'id'     => 2,
449
                        'name'   => 'bar',
450
                        'active' => true
451
                    ]
452
                ]
453
            ],
454
            [
455
                PDO::FETCH_BOTH,
456
                [
457
                    [
458
                        0        => 1,
459
                        1        => 'foo',
460
                        2        => false,
461
                        'id'     => 1,
462
                        'name'   => 'foo',
463
                        'active' => false
464
                    ],
465
                    [
466
                        0        => 2,
467
                        1        => 'bar',
468
                        2        => true,
469
                        'id'     => 2,
470
                        'name'   => 'bar',
471
                        'active' => true
472
                    ]
473
                ]
474
            ],
475
            [
476
                PDO::FETCH_ASSOC,
477
                [
478
                    [
479
                        'id'     => 1,
480
                        'name'   => 'foo',
481
                        'active' => false
482
                    ],
483
                    [
484
                        'id'     => 2,
485
                        'name'   => 'bar',
486
                        'active' => true
487
                    ]
488
                ]
489
            ],
490
            [
491
                PDO::FETCH_NAMED,
492
                [
493
                    [
494
                        'id'     => 1,
495
                        'name'   => 'foo',
496
                        'active' => false
497
                    ],
498
                    [
499
                        'id'     => 2,
500
                        'name'   => 'bar',
501
                        'active' => true
502
                    ]
503
                ]
504
            ],
505
            [
506
                PDO::FETCH_NUM,
507
                [
508
                    [
509
                        0        => 1,
510
                        1        => 'foo',
511
                        2        => false,
512
                    ],
513
                    [
514
                        0        => 2,
515
                        1        => 'bar',
516
                        2        => true,
517
                    ]
518
                ]
519
            ],
520
            [
521
                PDO::FETCH_COLUMN,
522
                [
523
                    1,
524
                    2
525
                ]
526
            ],
527
528
        ];
529
    }
530
531
    /**
532
     * @dataProvider fetchAllStyleProvider
533
     * @covers ::fetchAll
534
     *
535
     * @param string $fetchStyle
536
     * @param array  $expected
537
     */
538
    public function testFetchAll($fetchStyle, array $expected)
539
    {
540
        $this->callbackReturnValue = $this->getPopulatedCollection();
541
542
        $this->pdo
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Crate\PDO\PDO.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
543
            ->expects($this->any())
544
            ->method('getAttribute')
545
            ->with(PDO::ATTR_DEFAULT_FETCH_MODE)
546
            ->will($this->returnValue(PDO::FETCH_BOTH));
547
548
549
        $result = $this->statement->fetchAll($fetchStyle);
550
551
        $this->assertEquals($expected, $result);
552
    }
553
554
    /**
555
     * @covers ::fetchAll
556
     */
557
    public function testFetchAllWithFetchStyleFuncAndInvalidCallback()
558
    {
559
        $this->setExpectedException('Crate\PDO\Exception\InvalidArgumentException');
560
        $this->callbackReturnValue = $this->getPopulatedCollection();
561
562
        $this->statement->fetchAll(PDO::FETCH_FUNC, 'void');
563
    }
564
565
    /**
566
     * @covers ::fetchAll
567
     */
568
    public function testFetchAllWithFetchStyleFunc()
569
    {
570
        $this->callbackReturnValue = $this->getPopulatedCollection();
571
572
        $result = $this->statement->fetchAll(PDO::FETCH_FUNC, function($id, $name, $active) {
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $active is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
573
            return $id;
574
        });
575
576
        $this->assertEquals([1, 2], $result);
577
    }
578
579
    /**
580
     * @covers ::fetchAll
581
     */
582
    public function testFetchAllWithFetchStyleColumnAndInvalidColumnIndexType()
583
    {
584
        $this->setExpectedException('Crate\PDO\Exception\InvalidArgumentException');
585
        $this->callbackReturnValue = $this->getPopulatedCollection();
586
587
        $this->statement->fetchAll(PDO::FETCH_COLUMN, 'test');
588
    }
589
590
    /**
591
     * @covers ::fetchAll
592
     */
593
    public function testFetchAllWithFetchStyleColumnAndInvalidColumnIndex()
594
    {
595
        $this->setExpectedException('Crate\PDO\Exception\OutOfBoundsException');
596
        $this->callbackReturnValue = $this->getPopulatedCollection();
597
598
        $this->statement->fetchAll(PDO::FETCH_COLUMN, 100);
599
    }
600
601
    /**
602
     * @covers ::fetchObject
603
     */
604
    public function testFetchObject()
605
    {
606
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
607
        $this->statement->fetchObject();
608
    }
609
610
    /**
611
     * @covers ::errorCode
612
     */
613
    public function testErrorCode()
614
    {
615
        $this->assertNull($this->statement->errorCode());
616
617
        $reflection = new ReflectionClass('Crate\PDO\PDOStatement');
618
619
        $property = $reflection->getProperty('errorCode');
620
        $property->setAccessible(true);
621
        $property->setValue($this->statement, 1337);
622
623
        $this->assertEquals(1337, $this->statement->errorCode());
624
    }
625
626
    /**
627
     * @return array
628
     */
629
    public function errorInfoAnsiCodeProvider()
630
    {
631
        return [
632
            [42000, CrateConst::ERR_INVALID_SQL, 'le error message'],
633
            ['Not available', 1337, 'le error message']
634
        ];
635
    }
636
637
    /**
638
     * @covers ::errorInfo
639
     * @dataProvider errorInfoAnsiCodeProvider
640
     *
641
     * @param mixed  $ansiCode
642
     * @param int    $errorCode
643
     * @param string $errorMessage
644
     */
645
    public function testErrorInfo($ansiCode, $errorCode, $errorMessage)
646
    {
647
        $this->assertNull($this->statement->errorInfo());
648
649
        $reflection = new ReflectionClass('Crate\PDO\PDOStatement');
650
651
        $errorCodeProp = $reflection->getProperty('errorCode');
652
        $errorCodeProp->setAccessible(true);
653
        $errorCodeProp->setValue($this->statement, $errorCode);
654
655
        $errorMessageProp = $reflection->getProperty('errorMessage');
656
        $errorMessageProp->setAccessible(true);
657
        $errorMessageProp->setValue($this->statement, $errorMessage);
658
659
        $this->assertEquals([$ansiCode, $errorCode, $errorMessage], $this->statement->errorInfo());
660
    }
661
662
    /**
663
     * @covers ::getAttribute
664
     */
665
    public function testGetAttribute()
666
    {
667
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
668
        $this->statement->getAttribute(null, null);
0 ignored issues
show
Unused Code introduced by
The call to PDOStatement::getAttribute() has too many arguments starting with null.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
669
    }
670
671
    /**
672
     * @covers ::setAttribute
673
     */
674
    public function testSetAttribute()
675
    {
676
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
677
        $this->statement->setAttribute(null, null);
678
    }
679
680
    /**
681
     * @covers ::columnCount
682
     */
683
    public function testColumnCount()
684
    {
685
        $this->callbackReturnValue = $this->getPopulatedCollection();
686
        $this->assertEquals(3, $this->statement->columnCount());
687
    }
688
689
    /**
690
     * @covers ::getColumnMeta
691
     */
692
    public function testGetColumnMeta()
693
    {
694
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
695
        $this->statement->getColumnMeta(null);
696
    }
697
698
    /**
699
     * @covers ::setFetchMode
700
     */
701
    public function testSetFetchModeWithColumnAndMissingColNo()
702
    {
703
        $this->setExpectedException(
704
            'Crate\PDO\Exception\InvalidArgumentException',
705
            'fetch mode requires the colno argument'
706
        );
707
708
        $this->statement->setFetchMode(PDO::FETCH_COLUMN);
709
    }
710
711
    /**
712
     * @covers ::setFetchMode
713
     */
714
    public function testSetFetchModeWithColumnAndInvalidColNo()
715
    {
716
        $this->setExpectedException(
717
            'Crate\PDO\Exception\InvalidArgumentException',
718
            'colno must be an integer'
719
        );
720
721
        $this->statement->setFetchMode(PDO::FETCH_COLUMN, 'test');
722
    }
723
724
    /**
725
     * @covers ::setFetchMode
726
     */
727
    public function testSetFetchModeWithColumn()
728
    {
729
        $this->statement->setFetchMode(PDO::FETCH_COLUMN, 1);
730
731
        $reflection = new ReflectionClass('Crate\PDO\PDOStatement');
732
733
        $property = $reflection->getProperty('options');
734
        $property->setAccessible(true);;
735
736
        $options = $property->getValue($this->statement);
737
738
        $this->assertEquals(PDO::FETCH_COLUMN, $options['fetchMode']);
739
        $this->assertEquals(1, $options['fetchColumn']);
740
    }
741
742
    public function fetchModeStyleProvider()
743
    {
744
        return [
745
            [PDO::FETCH_ASSOC],
746
            [PDO::FETCH_NUM],
747
            [PDO::FETCH_BOTH],
748
            [PDO::FETCH_BOUND],
749
            [PDO::FETCH_NAMED]
750
        ];
751
    }
752
753
    /**
754
     * @covers ::setFetchMode
755
     * @dataProvider fetchModeStyleProvider
756
     *
757
     * @param int $fetchStyle
758
     */
759
    public function testSetFetchMode($fetchStyle)
760
    {
761
        $this->statement->setFetchMode($fetchStyle);
762
763
        $reflection = new ReflectionClass('Crate\PDO\PDOStatement');
764
765
        $property = $reflection->getProperty('options');
766
        $property->setAccessible(true);
767
768
        $options = $property->getValue($this->statement);
769
770
        $this->assertEquals($fetchStyle, $options['fetchMode']);
771
    }
772
773
    /**
774
     * @covers ::setFetchMode
775
     */
776
    public function testSetFetchModeWithInvalidFetchStyle()
777
    {
778
        $this->setExpectedException('Crate\PDO\Exception\UnsupportedException');
779
        $this->statement->setFetchMode(PDO::FETCH_INTO);
780
    }
781
782
    /**
783
     * @covers ::setFetchMode
784
     * @dataProvider fetchModeStyleProvider
785
     *
786
     * @param int $fetchStyle
787
     */
788
    public function testSetFetchModeWithInvalidExtraParam($fetchStyle)
789
    {
790
        $this->setExpectedException('Crate\PDO\Exception\InvalidArgumentException');
791
        $this->statement->setFetchMode($fetchStyle, 'fooBar');
792
    }
793
794
    /**
795
     * @covers ::nextRowset
796
     */
797
    public function testNextRowsetWithFailedExecution()
798
    {
799
        $this->callbackReturnValue = ['code' => 1337, 'message' => 'expected failure'];
800
        $this->assertFalse($this->statement->nextRowset());
801
    }
802
803
    /**
804
     * @covers ::nextRowset
805
     */
806
    public function testNextRowset()
807
    {
808
        $this->callbackReturnValue = $this->getPopulatedCollection();
809
810
        $this->assertTrue($this->statement->nextRowset());
811
        $this->assertFalse($this->statement->nextRowset());
812
    }
813
814
    /**
815
     * @covers ::debugDumpParams
816
     */
817
    public function testDumpDebugParams()
818
    {
819
        $this->setExpectedException('Crate\PDO\Exception\PDOException');
820
        $this->statement->debugDumpParams();
821
    }
822
823
    /**
824
     * @covers ::getIterator
825
     */
826
    public function testGetIterator()
827
    {
828
        $this->callbackReturnValue = $this->getPopulatedCollection();
829
        $this->statement->setFetchMode(PDO::FETCH_COLUMN, 0);
830
831
        $counter = 0;
832
833
        foreach ($this->statement->getIterator() as $id) {
834
            $this->assertEquals(++$counter, $id);
835
        }
836
837
        $this->assertEquals(2, $counter);
838
    }
839
840
    /**
841
     * @covers ::closeCursor
842
     */
843
    public function testCloseCursorReturnsTrue()
844
    {
845
        $this->assertTrue($this->statement->closeCursor());
846
    }
847
848
    /**
849
     * @covers ::typedValue
850
     */
851
    public function testTypedValue()
852
    {
853
        $method = new ReflectionMethod('Crate\PDO\PDOStatement', 'typedValue');
854
        $method->setAccessible(true);
855
856
        $this->assertEquals(1.23, $method->invoke($this->statement, 1.23, PDO::PARAM_FLOAT));
857
        $this->assertEquals(1.23, $method->invoke($this->statement, 1.23, PDO::PARAM_DOUBLE));
858
859
        $this->assertEquals(1, $method->invoke($this->statement, 1, PDO::PARAM_INT));
860
        $this->assertEquals(1, $method->invoke($this->statement, 1, PDO::PARAM_LONG));
861
862
        $this->assertEquals(null, $method->invoke($this->statement, 1, PDO::PARAM_NULL));
863
864
        $this->assertEquals("hello", $method->invoke($this->statement, "hello", PDO::PARAM_STR));
865
        $this->assertEquals("1234", $method->invoke($this->statement, 1234, PDO::PARAM_STR));
866
        $this->assertEquals("127.0.0.1", $method->invoke($this->statement, "127.0.0.1", PDO::PARAM_IP));
867
868
        $this->assertEquals([1, 2], $method->invoke($this->statement, [1, 2], PDO::PARAM_ARRAY));
869
        $this->assertEquals(["foo" =>  "bar"], $method->invoke($this->statement, ["foo" =>  "bar"], PDO::PARAM_ARRAY));
870
871
        $this->assertEquals(12345, $method->invoke($this->statement, 12345, PDO::PARAM_TIMESTAMP));
872
        $this->assertEquals(12345, $method->invoke($this->statement, "12345", PDO::PARAM_TIMESTAMP));
873
        $this->assertEquals("2014-03-04T18:45:20", $method->invoke($this->statement, "2014-03-04T18:45:20", PDO::PARAM_TIMESTAMP));
874
875
    }
876
877
    /**
878
     * @covers ::typedValue
879
     */
880
    public function testTypedValueInvalid()
881
    {
882
        $method = new ReflectionMethod('Crate\PDO\PDOStatement', 'typedValue');
883
        $method->setAccessible(true);
884
885
        $this->setExpectedException('Crate\PDO\Exception\PDOException');
886
        $method->invoke($this->statement, 1, PDO::PARAM_LOB);
887
    }
888
889
    /**
890
     * @covers ::replaceNamedParametersWithPositionals
891
     */
892
    public function testReplaceNamedParametersWithPositionals()
893
    {
894
        $method = new ReflectionMethod('Crate\PDO\PDOStatement', 'replaceNamedParametersWithPositionals');
895
        $method->setAccessible(true);
896
        $property = new ReflectionProperty('Crate\PDO\PDOStatement', 'namedToPositionalMap');
897
        $property->setAccessible(true);
898
899
        $sql = "select * from test_table where name = :name and hoschi = 'sld''fn:sdfsf' and id = :id";
900
        $sql_converted = $method->invoke($this->statement, $sql);
901
        $this->assertEquals("select * from test_table where name = ? and hoschi = 'sld''fn:sdfsf' and id = ?", $sql_converted);
902
        $nameToPositionalMap = $property->getValue($this->statement);
903
        $this->assertEquals("name", $nameToPositionalMap[1]);
904
        $this->assertEquals("id", $nameToPositionalMap[2]);
905
    }
906
    
907
    public function testReplaceNamedParametersWithPositionalsMultiple()
908
    {
909
        $method = new ReflectionMethod('Crate\PDO\PDOStatement', 'replaceNamedParametersWithPositionals');
910
        $method->setAccessible(true);
911
        $property = new ReflectionProperty('Crate\PDO\PDOStatement', 'namedToPositionalMap');
912
        $property->setAccessible(true);
913
914
        $sql = "update test_table set name = concat(name, :name) where id = :id and name != :name";
915
        $sql_converted = $method->invoke($this->statement, $sql);
916
        $this->assertEquals("update test_table set name = concat(name, ?) where id = ? and name != ?", $sql_converted);
917
        $nameToPositionalMap = $property->getValue($this->statement);
918
        $this->assertEquals("name", $nameToPositionalMap[1]);
919
        $this->assertEquals("id", $nameToPositionalMap[2]);
920
        $this->assertEquals("name", $nameToPositionalMap[3]);
921
    }
922
    
923
}
924
925