diff options
author | Noah Heck <noah@noahheck.com> | 2015-10-24 22:51:11 -0600 |
---|---|---|
committer | Noah Heck <noah@noahheck.com> | 2015-10-24 22:51:11 -0600 |
commit | 522594222f6165c82406bb47f9b0f94cc3542751 (patch) | |
tree | 50e19d4f90e7de9735b63e5e91e4618db6215aaf | |
parent | 7d94ae6ed6f3e63b72d0a5693033752181deaa3d (diff) | |
download | E_PDOStatement-522594222f6165c82406bb47f9b0f94cc3542751.zip E_PDOStatement-522594222f6165c82406bb47f9b0f94cc3542751.tar.gz E_PDOStatement-522594222f6165c82406bb47f9b0f94cc3542751.tar.bz2 |
Initial PHPUnit setup2.1.2
Implement tests and attain 100% code coverage
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | composer.json | 19 | ||||
-rw-r--r-- | src/EPDOStatement.php (renamed from EPDOStatement/EPDOStatement.php) | 23 | ||||
-rw-r--r-- | tests/README.md | 28 | ||||
-rw-r--r-- | tests/bootstrap.php | 21 | ||||
-rw-r--r-- | tests/config/config.dist.php | 41 | ||||
-rw-r--r-- | tests/phpunit.xml | 18 | ||||
-rwxr-xr-x | tests/run_tests | 84 | ||||
-rw-r--r-- | tests/src/EPDOStatementTest.php | 246 |
10 files changed, 477 insertions, 35 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..361d987 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Composer vendor directory +vendor + +# PHPUnit local config file +tests/config/config.php + +# PHPUnit Test Coverage Report directory (if included in project) +tests/coverage @@ -1,19 +1,15 @@ #E_PDOStatement -Drop in replacement for default PHP PDOStatement class allowing devs to view an interpolated version of a parameterized query +Drop in replacement for default PHP PDOStatement class allowing devs to view an interpolated version of a parameterized query. The result is generally suitable for logging activities, debugging and performance analysis. -###Update (2015-07-19) +####Update (2015-10-24) +Full PHPUnit Test Suite in place plus re-organization of code + +####Update (2015-07-19) Now takes into account bound arguments' datatypes when compiling interpolated string (previously, all values were quoted when it's likely inappropriate to quote INT datatypes). This allows for viewing/using bound values in e.g. LIMIT clauses where the quotes would interfere with processing the resultant query. Also, modified namespacing and file structure to allow default composer autoloader to work correctly. -###Update -Now allows for input parameters without leading : as per issue #3. - -###Update - -Please update and replace with new version (as of 2014-10-22) to address potential matching issues. This is a drop-in update, so no other changes should be necessary. - ##Usage PHP's PDO are a much improved way for handling database communications, but not being able to view a complete version of the query to be executed on the server after statement parameters have been interpolated can be frustrating. @@ -119,12 +115,10 @@ Add to your composer.json to have it loaded when you create your project: ```json "require" : { - "noahheck/e_pdostatement" : "dev-master" + "noahheck/e_pdostatement" : "2.*" } ``` -You can also clone (or fork) (or fork then clone). - ##Configuration The EPDOStatement class extends the native \PDOStatement object, so the PDO object must be configured to use the extended definition: @@ -132,7 +126,11 @@ The EPDOStatement class extends the native \PDOStatement object, so the PDO obje ```php <?php -require_once "EPDOStatement.php";// or allow your auto-loader to load the definition e.g.: use \EPDOStatement\EPDOStatement; +require_once "EPDOStatement.php"; + +-- OR -- + +require_once "path/to/composer/autoload.php"; $dsn = "mysql:host=localhost;dbname=myDatabase"; $pdo = new PDO($dsn, $dbUsername, $dbPassword); diff --git a/composer.json b/composer.json index 4337b67..12460f7 100644 --- a/composer.json +++ b/composer.json @@ -6,18 +6,23 @@ , "license" : "Apache-2.0" , "authors" : [ { - "name" : "noahheck" - , "role" : "developer" + "name" : "Noah Heck" + , "role" : "Developer/Project Manager" , "email" : "myesain84@gmail.com" , "homepage" : "https://github.com/noahheck" } ] , "require" : { - "php" : ">=5.1.0" - } + "php" : ">=5.1.0" + } + , "require-dev" : { + "phpunit/phpunit" : "4.8.*" + , "phpunit/php-invoker" : "*" + , "phpunit/dbunit" : "*" + } , "autoload" : { - "psr-0" : { - "EPDOStatement" : "" + "psr-4" : { + "EPDOStatement\\" : "src" } } -}
\ No newline at end of file +} diff --git a/EPDOStatement/EPDOStatement.php b/src/EPDOStatement.php index 8c1df76..6876e0d 100644 --- a/EPDOStatement/EPDOStatement.php +++ b/src/EPDOStatement.php @@ -28,9 +28,9 @@ class EPDOStatement extends PDOStatement * needed. * @param \PDO $pdo */ - protected function __construct($pdo) + protected function __construct(PDO $pdo = null) { - if ($pdo instanceof PDO) { + if ($pdo) { $this->_pdo = $pdo; } } @@ -190,31 +190,24 @@ class EPDOStatement extends PDOStatement * * addslashes is not suitable for production logging, etc. You can update this method to perform the necessary * escaping translations for your database driver. Please consider updating your processes to provide a valid - * PDO object that can perform the necessary translations and can be updated with your i.e. package management, - * PEAR updates, etc. + * PDO object that can perform the necessary translations and can be updated with your e.g. package management, + * etc. * * @param str $value - the value to be prepared for injection as a value in the query string * @return str $value - prepared $value */ private function _prepareValue($value) { - if ($this->_pdo && ($this->_pdo instanceof PDO)) { + if ($this->_pdo) { if (PDO::PARAM_INT === $value['datatype']) { - $value = (int) $value['value']; + return (int) $value['value']; } - else - { - $value = $this->_pdo->quote($value['value']); - } - - } else { - - $value = "'" . addslashes($value['value']) . "'"; + return $this->_pdo->quote($value['value']); } - return $value; + return "'" . addslashes($value['value']) . "'"; } } diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..7f21a1d --- /dev/null +++ b/tests/README.md @@ -0,0 +1,28 @@ +##Test Suite + +The E_PDOStatement project ships with a 100% coverage PHPUnit test suite. In addition to the test case, the following commponents are included: + +- `run_tests` shell script to execute the tests (see below) +- `phpunit.xml` configuration file +- `bootstrap.php` test suite configuration file +- configuration directory + +If you're interested in running the tests, copy the `config.dist.php` file to `config.php` and fill in the appropriate configuration values (Note: a valid PDO connection is created during test suite execution, but no modifications to the database are made). + +Invoke the `run_tests` script from the terminal in order to execute the test suite: + +``` + # path/to/tests/run_tests +``` + +The `run_tests` script includes an easy way to generate the PHPUnit code coverage report by invoking the command with the `--report` flag: + +``` + # path/to/tests/run_tests --report +``` + +Find out more about `run_tests` with the `--help` flag: + +``` + # path/to/tests/run_tests --help +``` diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..611b83e --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright 2015 github.com/noahheck + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Set up composer autoloader + */ +require_once __DIR__ . "/../vendor/autoload.php"; diff --git a/tests/config/config.dist.php b/tests/config/config.dist.php new file mode 100644 index 0000000..9092dd5 --- /dev/null +++ b/tests/config/config.dist.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright 2015 github.com/noahheck + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Test environment configuration info + * + * Copy this file to config.php (part of .gitignore) and fill in appropriate values for your environment + * + * @package E_PDOStatement + * @since 2015-10-24 + */ + + + +/** + * Environment configuration information + */ +return [ + 'db' => [ + 'dsn' => '' + , 'username' => '' + , 'password' => '' + , 'options' => [ + + ] + ] +]; diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 0000000..1c04ccb --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<phpunit + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd" + colors="true" + bootstrap="./bootstrap.php" +> + <testsuites> + <testsuite name="EPDOStatement Unit Test Suite"> + <directory>./</directory> + </testsuite> + </testsuites> + <filter> + <whitelist processUncoveredFilesFromWhiteList="true"> + <directory suffix='.php'>../src</directory> + </whitelist> + </filter> +</phpunit> diff --git a/tests/run_tests b/tests/run_tests new file mode 100755 index 0000000..959dd07 --- /dev/null +++ b/tests/run_tests @@ -0,0 +1,84 @@ +#!/usr/bin/env php +<?php +/** + * Copyright 2015 github.com/noahheck + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Executes the E_PDOStatement PHPUnit test suite + * + * Allows easy specification of common test suite parameters to provide an easier way to run the tests + * + * @package E_PDOStatement + * @since 2015-10-24 + */ + +chdir(dirname(__FILE__)); + +$report = ""; + +$argWphp = ""; +$argWTestPhp = ""; + +$numArgs = $argc; +$curArg = 0; + +$lastArg = false; + +foreach ($argv as $arg) +{ + $curArg++; + + // Skip the first arg; it will always be the name of this script + if ($curArg === 1) + { + continue; + } + + if ($arg == "--help") + { + $scriptName = basename(__FILE__, ".php"); + echo <<<EOH +E_PDOStatement PHPUnit Test Suite Runner + +Usage: $scriptName [Options] + +Options: + --report Generate html code coverage report in coverage directory + + +Miscellaneous Options: + --help Display this help and exit + +EOH; + exit; + } + + if ($arg == "--report") + { + $report = "--coverage-html coverage"; + continue; + } + + echo " +Unknown argument: {$arg} + +Exiting... + +"; + exit; +} + +passthru("../vendor/bin/phpunit --colors=always {$report} ./"); diff --git a/tests/src/EPDOStatementTest.php b/tests/src/EPDOStatementTest.php new file mode 100644 index 0000000..f16951c --- /dev/null +++ b/tests/src/EPDOStatementTest.php @@ -0,0 +1,246 @@ +<?php +/** + * Copyright 2015 github.com/noahheck + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class EPDOStatementTest extends PHPUnit_Framework_TestCase +{ + /** + * PDO object + */ + protected $pdo = false; + + protected function getConfig() + { + return include dirname(__FILE__) . "/../config/config.php"; + } + + protected function getPdo() + { + if ($this->pdo) + { + return $this->pdo; + } + + $config = $this->getConfig(); + + $this->pdo = new PDO($config['db']['dsn'], $config['db']['user'], $config['db']['password']); + + $this->pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array("EPDOStatement\EPDOStatement", array($this->pdo))); + + return $this->pdo; + } + + public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividuallyAsNamedParameters() + { + $pdo = $this->getPdo(); + + /** + * Generic type query with mix of camel-case and _ separated placeholders + */ + $query = "SELECT * FROM users WHERE user_id = :userId AND status = :user_status"; + $stmt = $pdo->prepare($query); + + $userId = 123; + $user_status = "active"; + + $stmt->bindParam(":userId" , $userId , PDO::PARAM_INT); + $stmt->bindParam(":user_status" , $user_status , PDO::PARAM_STR); + + $result = $stmt->interpolateQuery(); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/active/", $result)); + + $this->assertTrue(false == preg_match("/\:userId/", $result)); + $this->assertTrue(false == preg_match("/\:user_status/", $result)); + } + + public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividuallyAsNamedParametersWithoutLeadingColons() + { + $pdo = $this->getPdo(); + + /** + * Generic type query with mix of camel-case and _ separated placeholders + */ + $query = "SELECT * FROM users WHERE user_id = :userId AND status = :user_status"; + $stmt = $pdo->prepare($query); + + $userId = 123; + $user_status = "active"; + + $stmt->bindParam("userId" , $userId , PDO::PARAM_INT); + $stmt->bindParam("user_status" , $user_status , PDO::PARAM_STR); + + $result = $stmt->interpolateQuery(); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/active/", $result)); + + $this->assertTrue(false == preg_match("/\:userId/", $result)); + $this->assertTrue(false == preg_match("/\:user_status/", $result)); + } + + public function testValuesGetInterpolatedIntoQueryStatementWhenBoundIndividuallyAsUnnamedParameters() + { + $pdo = $this->getPdo(); + + /** + * Generic type query with mix of camel-case and _ separated placeholders + */ + $query = "SELECT * FROM users WHERE user_id = ? AND status = ?"; + $stmt = $pdo->prepare($query); + + $userId = 123; + $user_status = "active"; + + $stmt->bindValue(1, $userId , PDO::PARAM_INT); + $stmt->bindValue(2, $user_status , PDO::PARAM_STR); + + $result = $stmt->interpolateQuery(); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/active/", $result)); + + $this->assertTrue(false == preg_match("/\?/", $result)); + } + + public function testValuesGetInterpolatedIntoQueryWhenProvidedAsNamedInputParameters() + { + $pdo = $this->getPdo(); + + /** + * Generic type query with mix of camel-case and _ separated placeholders + */ + $query = "SELECT * FROM users WHERE user_id = :userId AND status = :user_status"; + $stmt = $pdo->prepare($query); + + $userId = 123; + $user_status = "active"; + + $parameters = array( + ":userId" => $userId + , ":user_status" => $user_status + ); + + $result = $stmt->interpolateQuery($parameters); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/active/", $result)); + + $this->assertTrue(false == preg_match("/\:userId/", $result)); + $this->assertTrue(false == preg_match("/\:user_status/", $result)); + } + + public function testValuesGetInterpolatedIntoQueryWhenProvidedAsUnnamedInputParameters() + { + $pdo = $this->getPdo(); + + /** + * Generic type query with mix of camel-case and _ separated placeholders + */ + $query = "SELECT * FROM users WHERE user_id = ? AND status = ?"; + $stmt = $pdo->prepare($query); + + $userId = 123; + $user_status = "active"; + + $parameters = array( + $userId + , $user_status + ); + + $result = $stmt->interpolateQuery($parameters); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/active/", $result)); + + $this->assertTrue(false == preg_match("/\?/", $result)); + } + + public function testValuesGetInterpolatedCorrectlyWhenSimilarlyNamedPlaceholdersAreUsed() + { + $pdo = $this->getPdo(); + + /** + * Specific query using similarly named placeholders + */ + $query = "UPDATE logs SET logContent = :logContent WHERE log = :log"; + $stmt = $pdo->prepare($query); + + /** + * Bind parameters in order to throw off the interpolation + */ + $log = 123; + $logContent = "Test log content"; + + $stmt->bindParam(":log" , $log , PDO::PARAM_INT); + $stmt->bindParam(":logContent" , $logContent , PDO::PARAM_STR); + + $result = $stmt->interpolateQuery(); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/log content/", $result)); + + $this->assertTrue(false == preg_match("/\:logContent/", $result)); + $this->assertTrue(false == preg_match("/\:log/", $result)); + } + + public function testInterpolationAllowsSuccessfulExecutionOfQueries() + { + $pdo = $this->getPdo(); + + $query = "SELECT ? + ? + ?"; + + $stmt = $pdo->prepare($query); + + $values = array(1, 1, 1); + + $stmt->execute($values); + + list($sum) = $stmt->fetch(); + + $this->assertEquals(3, $sum); + } + + public function testValuesAreSuccessfullyInterpolatedIfNoPdoProvidedToEPDOStatement() + { + $config = $this->getConfig(); + + $pdo = new PDO($config['db']['dsn'], $config['db']['user'], $config['db']['password']); + + $pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array("EPDOStatement\EPDOStatement", array())); + + /** + * Generic type query with mix of camel-case and _ separated placeholders + */ + $query = "SELECT * FROM users WHERE user_id = :userId AND status = :user_status"; + $stmt = $pdo->prepare($query); + + $userId = 123; + $user_status = "active"; + + $stmt->bindParam(":userId" , $userId , PDO::PARAM_INT); + $stmt->bindParam(":user_status" , $user_status , PDO::PARAM_STR); + + $result = $stmt->interpolateQuery(); + + $this->assertTrue(false != preg_match("/123/", $result)); + $this->assertTrue(false != preg_match("/active/", $result)); + + $this->assertTrue(false == preg_match("/\:userId/", $result)); + $this->assertTrue(false == preg_match("/\:user_status/", $result)); + } +} |