TYPO3 API  SVNRelease
t3lib_db_preparedstatementTest.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 2010-2011 Helmut Hummel <helmut@typo3.org>
00006  *  All rights reserved
00007  *
00008  *  This script is part of the TYPO3 project. The TYPO3 project is
00009  *  free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  The GNU General Public License can be found at
00015  *  http://www.gnu.org/copyleft/gpl.html.
00016  *
00017  *  This script is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU General Public License for more details.
00021  *
00022  *  This copyright notice MUST APPEAR in all copies of the script!
00023  ***************************************************************/
00024 
00025 
00026 /**
00027  * Testcase for the prepared statement database class
00028  *
00029  * @author  Helmut Hummel <helmut@typo3.org>
00030  * @package TYPO3
00031  * @subpackage tests
00032  */
00033 class t3lib_db_PreparedStatementTest extends tx_phpunit_testcase {
00034 
00035     /**
00036      * Backup and restore of the $GLOBALS array.
00037      *
00038      * @var boolean
00039      */
00040     protected $backupGlobalsArray = array();
00041 
00042     /**
00043      * Mock object of t3lib_db
00044      *
00045      * @var PHPUnit_Framework_MockObject_MockObject
00046      */
00047     private $databaseStub;
00048 
00049     /**
00050      * Create a new database mock object for every test
00051      * and backup the original global database object.
00052      *
00053      * @return void
00054      */
00055     protected function setUp() {
00056         $this->backupGlobalsArray['TYPO3_DB'] = $GLOBALS['TYPO3_DB'];
00057         $this->databaseStub = $this->setUpAndReturnDatabaseStub();
00058     }
00059 
00060     /**
00061      * Restore global database object.
00062      *
00063      * @return void
00064      */
00065     protected function tearDown() {
00066         $GLOBALS['TYPO3_DB'] = $this->backupGlobalsArray['TYPO3_DB'];
00067     }
00068 
00069     //////////////////////
00070     // Utility functions
00071     //////////////////////
00072 
00073     /**
00074      * Set up the stub to be able to get the result of the prepared statement.
00075      *
00076      * @return PHPUnit_Framework_MockObject_MockObject
00077      */
00078     private function setUpAndReturnDatabaseStub() {
00079         $databaseLink = $GLOBALS['TYPO3_DB']->link;
00080         $GLOBALS['TYPO3_DB'] = $this->getMock('t3lib_DB', array('exec_PREPAREDquery'), array(), '', FALSE, FALSE);
00081         $GLOBALS['TYPO3_DB']->link = $databaseLink;
00082         return $GLOBALS['TYPO3_DB'];
00083     }
00084 
00085     /**
00086      * Create a object fo the subject to be tested.
00087      *
00088      * @param string $query
00089      * @return t3lib_db_PreparedStatement
00090      */
00091     private function createPreparedStatement($query) {
00092         return new t3lib_db_PreparedStatement($query, 'pages');
00093     }
00094 
00095     ////////////////////////////////////
00096     // Tests for the utility functions
00097     ////////////////////////////////////
00098 
00099     /**
00100      * Checks if setUpAndReturnDatabaseStub() really returns
00101      * a mock of t3lib_DB.
00102      *
00103      * @test
00104      * @return void
00105      */
00106     public function setUpAndReturnDatabaseStubReturnsMockObjectOf_t3lib_DB() {
00107         $this->assertTrue($this->setUpAndReturnDatabaseStub() instanceof t3lib_DB);
00108     }
00109 
00110     /**
00111      * Checks if createPreparedStatement() really returns an instance of t3lib_db_PreparedStatement.
00112      *
00113      * @test
00114      * @return void
00115      */
00116     public function createPreparedStatementReturnsInstanceOfPreparedStatementClass() {
00117         $this->assertTrue($this->createPreparedStatement('dummy') instanceof t3lib_db_PreparedStatement);
00118     }
00119 
00120     ///////////////////////////////////////
00121     // Tests for t3lib_db_PreparedStatement
00122     ///////////////////////////////////////
00123 
00124     /**
00125      * Data Provider for two tests, providing sample queries, parameters and expected result queries.
00126      *
00127      * @see parametersAreReplacedInQueryByCallingExecute
00128      * @see parametersAreReplacedInQueryWhenBoundWithBindValues
00129      * @return array
00130      */
00131     public function parametersAndQueriesDataProvider() {
00132         return array(
00133             'one named integer parameter' => array('SELECT * FROM pages WHERE pid=:pid', array(':pid' => 1), 'SELECT * FROM pages WHERE pid=1'),
00134             'one unnamed integer parameter' => array('SELECT * FROM pages WHERE pid=?', array(1), 'SELECT * FROM pages WHERE pid=1'),
00135             'one named integer parameter is replaced multiple times' => array('SELECT * FROM pages WHERE pid=:pid OR uid=:pid', array(':pid' => 1), 'SELECT * FROM pages WHERE pid=1 OR uid=1'),
00136             'two named integer parameters are replaced' => array('SELECT * FROM pages WHERE pid=:pid OR uid=:uid', array(':pid' => 1, ':uid' => 10), 'SELECT * FROM pages WHERE pid=1 OR uid=10'),
00137             'two unnamed integer parameters are replaced' => array('SELECT * FROM pages WHERE pid=? OR uid=?', array(1,1), 'SELECT * FROM pages WHERE pid=1 OR uid=1'),
00138             'php bool true parameter is replaced with 1' => array('SELECT * FROM pages WHERE deleted=?', array(TRUE), 'SELECT * FROM pages WHERE deleted=1'),
00139             'php bool false parameter is replaced with 0' => array('SELECT * FROM pages WHERE deleted=?', array(FALSE), 'SELECT * FROM pages WHERE deleted=0'),
00140             'php null parameter is replaced with NULL' => array('SELECT * FROM pages WHERE deleted=?', array(NULL), 'SELECT * FROM pages WHERE deleted=NULL'),
00141             'string parameter is wrapped in quotes' => array('SELECT * FROM pages WHERE title=?', array('Foo bar'), "SELECT * FROM pages WHERE title='Foo bar'"),
00142             'string single quotes in parameter are properly escaped' => array('SELECT * FROM pages WHERE title=?', array("'Foo'"), "SELECT * FROM pages WHERE title='\\'Foo\\''"),
00143         );
00144     }
00145 
00146     /**
00147      * Checking if calling execute() with parameters, they are
00148      * properly relpaced in the query.
00149      *
00150      * @test
00151      * @dataProvider parametersAndQueriesDataProvider
00152      * @param string $query             Query with unreplaced markers
00153      * @param array  $parameters        Array of parameters to be replaced in the query
00154      * @param string $expectedResult    Query with all markers replaced
00155      * @return void
00156      */
00157     public function parametersAreReplacedInQueryByCallingExecute($query, $parameters, $expectedResult) {
00158         $statement = $this->createPreparedStatement($query);
00159         $this->databaseStub->expects($this->any())
00160             ->method('exec_PREPAREDquery')
00161             ->with(
00162                 $this->equalTo($expectedResult)
00163             );
00164         $statement->execute($parameters);
00165     }
00166 
00167     /**
00168      * Checking if parameters bound to the statement by bindValues()
00169      * are properly replaced in the query.
00170      *
00171      * @test
00172      * @dataProvider parametersAndQueriesDataProvider
00173      * @param string $query             Query with unreplaced markers
00174      * @param array  $parameters        Array of parameters to be replaced in the query
00175      * @param string $expectedResult    Query with all markers replaced
00176      * @return void
00177      */
00178     public function parametersAreReplacedInQueryWhenBoundWithBindValues($query, $parameters, $expectedResult) {
00179         $statement = $this->createPreparedStatement($query);
00180         $this->databaseStub->expects($this->any())
00181             ->method('exec_PREPAREDquery')
00182             ->with(
00183                 $this->equalTo($expectedResult)
00184             );
00185         $statement->bindValues($parameters);
00186         $statement->execute();
00187     }
00188 
00189     /**
00190      * Data Provider with invalid parameters.
00191      *
00192      * @see invalidParameterTypesPassedToBindValueThrowsException
00193      * @return array
00194      */
00195     public function invalidParameterTypesPassedToBindValueThrowsExceptionDataProvider() {
00196         return array(
00197             'integer passed with param type NULL' => array(1, t3lib_db_PreparedStatement::PARAM_NULL),
00198             'string passed with param type NULL' => array('1', t3lib_db_PreparedStatement::PARAM_NULL),
00199             'bool passed with param type NULL' => array(TRUE, t3lib_db_PreparedStatement::PARAM_NULL),
00200             'null passed with param type INT' => array(NULL, t3lib_db_PreparedStatement::PARAM_INT),
00201             'string passed with param type INT' => array('1', t3lib_db_PreparedStatement::PARAM_INT),
00202             'bool passed with param type INT' => array(TRUE, t3lib_db_PreparedStatement::PARAM_INT),
00203             'null passed with param type BOOL' => array(NULL, t3lib_db_PreparedStatement::PARAM_BOOL),
00204             'string passed with param type BOOL' => array('1', t3lib_db_PreparedStatement::PARAM_BOOL),
00205             'integer passed with param type BOOL' => array(1, t3lib_db_PreparedStatement::PARAM_BOOL),
00206         );
00207     }
00208 
00209     /**
00210      * Checking if an exception is thrown if invalid parameters are
00211      * provided vor bindValue().
00212      *
00213      * @test
00214      * @expectedException InvalidArgumentException
00215      * @dataProvider invalidParameterTypesPassedToBindValueThrowsExceptionDataProvider
00216      * @param mixed   $parameter    Parameter to be replaced in the query
00217      * @param integer $type         Type of the parameter value
00218      * @return void
00219      */
00220     public function invalidParameterTypesPassedToBindValueThrowsException($parameter, $type) {
00221         $statement = $this->createPreparedStatement('');
00222         $statement->bindValue(1, $parameter, $type);
00223     }
00224 
00225     /**
00226      * Checking if formerly bound values are replaced by the values passed to execute().
00227      *
00228      * @test
00229      * @return void
00230      */
00231     public function parametersPassedToExecuteOverrulesFormerlyBoundValues() {
00232         $query = 'SELECT * FROM pages WHERE pid=? OR uid=?';
00233         $expectedResult = 'SELECT * FROM pages WHERE pid=30 OR uid=40';
00234         $this->databaseStub->expects($this->any())
00235             ->method('exec_PREPAREDquery')
00236             ->with(
00237                 $this->equalTo($expectedResult)
00238             );
00239 
00240         $statement = $this->createPreparedStatement($query);
00241         $statement->bindValues(array(10, 20));
00242         $statement->execute(array(30, 40));
00243     }
00244 
00245     /**
00246      * Data Provieder for invalid marker names.
00247      *
00248      * @see passingInvalidMarkersThrowsExeption
00249      * @return array
00250      */
00251     public function passingInvalidMarkersThrowsExeptionDataProvider() {
00252         return array(
00253             'using other prefix than colon' => array('SELECT * FROM pages WHERE pid=#pid', array('#pid' => 1)),
00254             'using non alphanumerical character' => array('SELECT * FROM pages WHERE title=:stra≠e', array(':stra≠e' => 1)),
00255             'no colon used' => array('SELECT * FROM pages WHERE pid=pid', array('pid' => 1)),
00256             'colon at the end' => array('SELECT * FROM pages WHERE pid=pid:', array('pid:' => 1)),
00257             'colon without alphanumerical character' => array('SELECT * FROM pages WHERE pid=:', array(':' => 1)),
00258         );
00259     }
00260 
00261     /**
00262      * Checks if an exception is thrown, if parameter have invalid marker named.
00263      *
00264      * @test
00265      * @expectedException InvalidArgumentException
00266      * @dataProvider passingInvalidMarkersThrowsExeptionDataProvider
00267      * @param string $query             Query with unreplaced markers
00268      * @param array  $parameters        Array of parameters to be replaced in the query
00269      * @return void
00270      */
00271     public function passingInvalidMarkersThrowsExeption($query, $parameters) {
00272         $statement = $this->createPreparedStatement($query);
00273         $statement->execute($parameters);
00274     }
00275 }
00276 
00277 ?>