GitBucket
4.21.2
Toggle navigation
Snippets
Sign in
Files
Branches
1
Releases
Issues
Pull requests
Labels
Priorities
Milestones
Wiki
Forks
nigel.stanger
/
sqlmarker
Browse code
• Updated to use PHPUnit 5.2.3 PHAR installation.
master
1 parent
fdacd12
commit
bdbbe0061524fe5bf556cf517fbf13afa18c8b30
Nigel Stanger
authored
on 29 Apr 2016
Patch
Showing
4 changed files
Unit_testing/.gitignore
Unit_testing/ArrayDataSet.php
Unit_testing/SimpleTestListener.php
Unit_testing/test.php
Ignore Space
Show notes
View
Unit_testing/.gitignore
test_config.php *.phar
test_config.php
Ignore Space
Show notes
View
Unit_testing/ArrayDataSet.php
<?php class SchemaTesting_DbUnit_ArrayDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet { /** * @var array */ protected $tables = array(); /** * @param array $data */ public function __construct( array $data ) { foreach ( $data AS $tableName => $rows ) { $columns = array(); if ( isset( $rows[0] ) ) { $columns = array_keys($rows[0]); } $metaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData( $tableName, $columns ); $table = new PHPUnit_Extensions_Database_DataSet_DefaultTable( $metaData ); foreach ( $rows AS $row ) { $table->addRow( $row ); } $this->tables[$tableName] = $table; } } protected function createIterator( $reverse = FALSE ) { return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator( $this->tables, $reverse ); } public function getTable( $tableName ) { if ( !isset( $this->tables[$tableName] ) ) { throw new InvalidArgumentException( "$tableName is not a table in the current database." ); } return $this->tables[$tableName]; } } ?>
<?php require_once 'PHPUnit/Extensions/Database/DataSet/AbstractDataSet.php'; require_once 'PHPUnit/Extensions/Database/DataSet/DefaultTableIterator.php'; require_once 'PHPUnit/Extensions/Database/DataSet/DefaultTable.php'; require_once 'PHPUnit/Extensions/Database/DataSet/DefaultTableMetaData.php'; class SchemaTesting_DbUnit_ArrayDataSet extends PHPUnit_Extensions_Database_DataSet_AbstractDataSet { /** * @var array */ protected $tables = array(); /** * @param array $data */ public function __construct( array $data ) { foreach ( $data AS $tableName => $rows ) { $columns = array(); if ( isset( $rows[0] ) ) { $columns = array_keys($rows[0]); } $metaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData( $tableName, $columns ); $table = new PHPUnit_Extensions_Database_DataSet_DefaultTable( $metaData ); foreach ( $rows AS $row ) { $table->addRow( $row ); } $this->tables[$tableName] = $table; } } protected function createIterator( $reverse = FALSE ) { return new PHPUnit_Extensions_Database_DataSet_DefaultTableIterator( $this->tables, $reverse ); } public function getTable( $tableName ) { if ( !isset( $this->tables[$tableName] ) ) { throw new InvalidArgumentException( "$tableName is not a table in the current database." ); } return $this->tables[$tableName]; } } ?>
Ignore Space
Show notes
View
Unit_testing/SimpleTestListener.php
<?php abstract class SimpleTestListener implements PHPUnit_Framework_TestListener { /** * When you're running test suites, the various count methods in TestResult return only the total number of tests, fails, etc., for the entire Test, even if you filter the tests to be run within a given suite. We therefore need to keep track of these within the test listener for each suite and test. The results are indexed by suite/test name, which will be something like "BDL_Test_Staff_structure::testFoo" or just "testFoo". */ private $passes = array(); private $fails = array(); private $errors = array(); private $incompletes = array(); private $skips = array(); private $tests = array(); /** * These keep track of the counts within a given suite execution, and are reset at the start of every new suite. I'm not sure whether nested suites are stored as actual TestSuite objects. If not, this could mean that the counts for the enclosing suites may be wrong? */ private $suitePassCount = 0; private $suiteFailCount = 0; private $suiteErrorCount = 0; private $incompleteCount = 0; private $suiteSkipCount = 0; private $suiteTestCount = 0; public function reset() { $this->passes = array(); $this->fails = array(); $this->errors = array(); $this->incompletes = array(); $this->skips = array(); $this->tests = array(); $this->suitePassCount = 0; $this->suiteFailCount = 0; $this->suiteErrorCount = 0; $this->incompleteCount = 0; $this->suiteSkipCount = 0; $this->suiteTestCount = 0; } public function countPasses( $name ) { return $this->passes[ $name ]; } // Should this also include incompletes? public function countNonPasses( $name ) { return $this->tests[ $name ] - $this->passes[ $name ]; } public function countFails( $name ) { return $this->fails[ $name ]; } public function countErrors( $name ) { return $this->errors[ $name ]; } public function countIncompletes( $name ) { return $this->incompletes[ $name ]; } public function countSkips( $name ) { return $this->skips[ $name ]; } public function countTests( $name ) { return $this->tests[ $name ]; } public function wasSuccessful( $name ) { return ( $this->countPasses( $name ) === $this->countTests( $name ) ); } public function getPasses( $name = NULL ) { if ( $name === NULL ) return $this->passes; else return $this->passes[ $name ]; } public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->printError( $e ); $this->suiteErrorCount++; $this->errors[ $test->getName() ] = 1; } public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) { $this->printFailure( $e ); $this->suiteFailCount++; $this->fails[ $test->getName() ] = 1; } public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->printIncomplete( $e ); $this->incompleteCount++; $this->incompletes[ $test->getName() ] = 1; } public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time) { } public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->printSkip( $e ); $this->suiteSkipCount++; $this->skips[ $test->getName() ] = 1; } public function startTest(PHPUnit_Framework_Test $test) { // printf( "@@@ Test '%s' started.\n", $test->getName() ); $this->suiteTestCount++; $this->tests[ $test->getName() ] = 1; } public function endTest(PHPUnit_Framework_Test $test, $time) { // printf( "@@@ Test '%s' ended with status %d.\n", $test->getName(), $test->getStatus() ); if ( $test->getStatus() === PHPUnit_Runner_BaseTestRunner::STATUS_PASSED ) { $this->printPass(); $this->suitePassCount++; $this->passes[ $test->getName() ] = 1; } else { $this->passes[ $test->getName() ] = 0; } } public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { // printf( "@@@ TestSuite '%s' started.\n", $suite->getName() ); $this->suitePassCount = $this->suiteFailCount = $this->suiteErrorCount = $this->incompleteCount = $this->suiteSkipCount = $this->suiteTestCount = 0; } public function endTestSuite(PHPUnit_Framework_TestSuite $suite) { // printf( "@@@ TestSuite '%s' ended with a count of %d.\n", $suite->getName(), $this->suiteTestCount ); /* The suite registers as having been started even if its tests have been filtered out. If so, the number of tests will be zero, and the results shouldn't be recorded, otherwise this could wipe out the results of earlier actual runs. */ if ( $this->suiteTestCount ) { $this->passes[ $suite->getName() ] = $this->suitePassCount; $this->fails[ $suite->getName() ] = $this->suiteFailCount; $this->errors[ $suite->getName() ] = $this->suiteErrorCount; $this->incompletes[ $suite->getName() ] = $this->incompleteCount; $this->skips[ $suite->getName() ] = $this->suiteSkipCount; $this->tests[ $suite->getName() ] = $this->suiteTestCount; } } abstract public function printPass(); abstract public function printFailure( Exception $e ); abstract public function printError( Exception $e ); abstract public function printIncomplete( Exception $e ); abstract public function printSkip( Exception $e ); } ?>
<?php abstract class SimpleTestListener implements PHPUnit_Framework_TestListener { /** * When you're running test suites, the various count methods in TestResult return only the total number of tests, fails, etc., for the entire Test, even if you filter the tests to be run within a given suite. We therefore need to keep track of these within the test listener for each suite and test. The results are indexed by suite/test name, which will be something like "BDL_Test_Staff_structure::testFoo" or just "testFoo". */ private $passes = array(); private $fails = array(); private $errors = array(); private $incompletes = array(); private $skips = array(); private $tests = array(); /** * These keep track of the counts within a given suite execution, and are reset at the start of every new suite. I'm not sure whether nested suites are stored as actual TestSuite objects. If not, this could mean that the counts for the enclosing suites may be wrong? */ private $suitePassCount = 0; private $suiteFailCount = 0; private $suiteErrorCount = 0; private $incompleteCount = 0; private $suiteSkipCount = 0; private $suiteTestCount = 0; public function reset() { $this->passes = array(); $this->fails = array(); $this->errors = array(); $this->incompletes = array(); $this->skips = array(); $this->tests = array(); $this->suitePassCount = 0; $this->suiteFailCount = 0; $this->suiteErrorCount = 0; $this->incompleteCount = 0; $this->suiteSkipCount = 0; $this->suiteTestCount = 0; } public function countPasses( $name ) { return $this->passes[ $name ]; } // Should this also include incompletes? public function countNonPasses( $name ) { return $this->tests[ $name ] - $this->passes[ $name ]; } public function countFails( $name ) { return $this->fails[ $name ]; } public function countErrors( $name ) { return $this->errors[ $name ]; } public function countIncompletes( $name ) { return $this->incompletes[ $name ]; } public function countSkips( $name ) { return $this->skips[ $name ]; } public function countTests( $name ) { return $this->tests[ $name ]; } public function wasSuccessful( $name ) { return ( $this->countPasses( $name ) === $this->countTests( $name ) ); } public function getPasses( $name = NULL ) { if ( $name === NULL ) return $this->passes; else return $this->passes[ $name ]; } public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->printError( $e ); $this->suiteErrorCount++; $this->errors[ $test->getName() ] = 1; } public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) { $this->printFailure( $e ); $this->suiteFailCount++; $this->fails[ $test->getName() ] = 1; } public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->printIncomplete( $e ); $this->incompleteCount++; $this->incompletes[ $test->getName() ] = 1; } public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) { $this->printSkip( $e ); $this->suiteSkipCount++; $this->skips[ $test->getName() ] = 1; } public function startTest(PHPUnit_Framework_Test $test) { // printf( "@@@ Test '%s' started.\n", $test->getName() ); $this->suiteTestCount++; $this->tests[ $test->getName() ] = 1; } public function endTest(PHPUnit_Framework_Test $test, $time) { // printf( "@@@ Test '%s' ended with status %d.\n", $test->getName(), $test->getStatus() ); if ( $test->getStatus() === PHPUnit_Runner_BaseTestRunner::STATUS_PASSED ) { $this->printPass(); $this->suitePassCount++; $this->passes[ $test->getName() ] = 1; } else { $this->passes[ $test->getName() ] = 0; } } public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { // printf( "@@@ TestSuite '%s' started.\n", $suite->getName() ); $this->suitePassCount = $this->suiteFailCount = $this->suiteErrorCount = $this->incompleteCount = $this->suiteSkipCount = $this->suiteTestCount = 0; } public function endTestSuite(PHPUnit_Framework_TestSuite $suite) { // printf( "@@@ TestSuite '%s' ended with a count of %d.\n", $suite->getName(), $this->suiteTestCount ); /* The suite registers as having been started even if its tests have been filtered out. If so, the number of tests will be zero, and the results shouldn't be recorded, otherwise this could wipe out the results of earlier actual runs. */ if ( $this->suiteTestCount ) { $this->passes[ $suite->getName() ] = $this->suitePassCount; $this->fails[ $suite->getName() ] = $this->suiteFailCount; $this->errors[ $suite->getName() ] = $this->suiteErrorCount; $this->incompletes[ $suite->getName() ] = $this->incompleteCount; $this->skips[ $suite->getName() ] = $this->suiteSkipCount; $this->tests[ $suite->getName() ] = $this->suiteTestCount; } } abstract public function printPass(); abstract public function printFailure( Exception $e ); abstract public function printError( Exception $e ); abstract public function printIncomplete( Exception $e ); abstract public function printSkip( Exception $e ); } ?>
Ignore Space
Show notes
View
Unit_testing/test.php
<?php require_once 'test_config.php'; include "phpunit-5.3.2.phar"; require_once 'TestListener/HTMLTestListener.php'; require_once 'TestListener/TextTestListener.php'; require_once 'TestListener/ANSITestListener.php'; require_once 'Reporter/TextReporter.php'; require_once 'Reporter/ANSIReporter.php'; require_once 'Reporter/HTMLReporter.php'; require_once 'Searchable_TestSuite.php'; require_once "Schema.php"; // I don't know that these two settings make any difference, but I'll leave them in for now. PHPUnit_Framework_Error_Warning::$enabled = FALSE; PHPUnit_Framework_Error_Notice::$enabled = FALSE; switch ( $outputMode ) { case 'HTML': $reporter = new HTMLReporter( OUTPUT_VERBOSITY ); $listener = new HTMLTestListener; break; case 'TEXT': $reporter = new TextReporter( OUTPUT_VERBOSITY ); $listener = new TextTestListener; break; case 'ANSI': $reporter = new ANSIReporter( OUTPUT_VERBOSITY ); $listener = new ANSITestListener; break; } $result = new PHPUnit_Framework_TestResult; $result->addListener( $listener ); // List of tables to be tested. This is used to build the corresponding test class names. require_once "${scenario}_table_list.php"; /* Hack! There's no easy way to create a global object constant, so the global report object is stored as a private static member in PHPUnit_Extensions_Database_TestCase_CreateTable, with corresponding public get/set static methods. Set it once at the start, and it'll stay set for the entire test run. Yay! */ PHPUnit_Extensions_Database_TestCase_CreateTable::setReporter( $reporter ); foreach ( $testTables as $table ) { $structureTest = "${scenario}_Test_${table}_structure"; $dataTest = "${scenario}_Test_${table}_data"; $runDataTests = true; require_once "${table}/${structureTest}.php"; require_once "${table}/${dataTest}.php"; $structurePassed = false; $listener->reset(); $reporter->hr(); $reporter->report( Reporter::STATUS_NOTE, 'Checking structure of table %s.', array( $table ) ); $suite = new Searchable_TestSuite( $structureTest ); // Critical to data testing. // TODO: is $testResult needed anymore? if ( $suite->testExists( 'testTableExists' ) ) { $testResult = $suite->run( $result, '/testTableExists/' ); $structurePassed = $listener->wasSuccessful( 'testTableExists' ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'Table %s exists.', array( $table ) ); // Critical to data testing. if ( $suite->testExists( "${structureTest}::testColumnExists" ) ) { $testResult = $suite->run( $result, '/testColumnExists/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnExists" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'Table %s contains all the expected columns.', array( $table ) ); if ( $suite->testExists( "${structureTest}::testColumnDataType" ) ) { $testResult = $suite->run( $result, '/testColumnDataType/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnDataType" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'All columns of table %s have data types compatible with the specification.', array( $table ) ); if ( $suite->testExists( "${structureTest}::testColumnLength" ) ) { $testResult = $suite->run( $result, '/testColumnLength/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnLength" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'All columns of table %s have lengths compatible with the specification.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d columns of table %s %s an unexpected column length.', array( $listener->countNonPasses( "${structureTest}::testColumnLength" ), $listener->countTests( "${structureTest}::testColumnLength" ), $table, Reporter::pluralise( "${structureTest}::testColumnLength", 'has', 'have' ) ) ) ; $runDataTests = false; } } } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d columns of table %s %s an unexpected data type.', array( $listener->countNonPasses( "${structureTest}::testColumnDataType" ), $listener->countTests( "${structureTest}::testColumnDataType" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnDataType" ), "has", "have" ) ) ) ; $reporter->report( Reporter::STATUS_SKIPPED, 'column length tests, as the data types do not match what was expected.', null ); $runDataTests = false; } } if ( RUN_MODE !== 'student' ) { // Critical to data testing. if ( $suite->testExists( "${structureTest}::testColumnNullability" ) ) { $testResult = $suite->run( $result, '/testColumnNullability/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnNullability" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'All columns of table %s have the expected nullability.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d columns of table %s %s an unexpected nullability.', array( $listener->countNonPasses( "${structureTest}::testColumnNullability" ), $listener->countTests( "${structureTest}::testColumnNullability" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnNullability" ), "has", "have" ) ) ) ; $runDataTests = false; } } if ( $suite->testExists( "${structureTest}::testColumnDefault" ) ) { $testResult = $suite->run( $result, '/testColumnDefault/' ); if ( $listener->wasSuccessful( "${structureTest}::testColumnDefault" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All expected columns of table %s have the correct default values.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d expected columns of table %s %s an incorrect default value.', array( $listener->countNonPasses( "${structureTest}::testColumnDefault" ), $listener->countTests( "${structureTest}::testColumnDefault" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnDefault" ), "has", "have" ) ) ) ; } } } } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d expected columns of table %s %s either missing or misnamed.', array( $listener->countNonPasses( "${structureTest}::testColumnExists" ), $listener->countTests( "${structureTest}::testColumnExists" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnExists" ), 'is', 'are' ) ) ) ; $reporter->report( Reporter::STATUS_SKIPPED, 'data type, length and nullability tests as they will include spurious errors.', null ); $runDataTests = false; } } if ( RUN_MODE !== 'student' ) { // Not critical to data testing. Need to run both PK tests in one pass as the columns test depends on the existence test. // Note that this causes a slight weirdness in the output where the "skipped test" message for testPKColumns is printed // before the "test failed" message for testPKExists. Not much we can do about this. if ( $suite->testExists( 'testPKExists' ) && $suite->testExists( 'testPKColumns' ) ) { $testResult = $suite->run( $result, '/testPK.*/' ); if ( $listener->wasSuccessful( 'testPKExists' ) ) { $reporter->report( Reporter::STATUS_PASS, 'Primary key of table %s exists.', array( $table ) ); if ( $listener->wasSuccessful( 'testPKColumns' ) ) { $reporter->report( Reporter::STATUS_PASS, 'Primary key of table %s includes (only) the expected columns.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, 'Primary key of table %s does not include (only) the expected columns.', array( $table ) ); } } else { $reporter->report( Reporter::STATUS_FAILURE, 'Primary key of table %s missing.', array( $table ) ); } } // Not critical to data testing. if ( $suite->testExists( "${structureTest}::testFKsExist" ) ) { $testResult = $suite->run( $result, '/testFKsExist/' ); if ( $listener->wasSuccessful( "${structureTest}::testFKsExist" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All expected foreign keys for table %s exist.', array( $table ) ); if ( $suite->testExists( "${structureTest}::testFKColumns" ) ) { $testResult = $suite->run( $result, '/testFKColumns/' ); if ( $listener->wasSuccessful( "${structureTest}::testFKColumns" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All foreign keys for table %s include (only) the expected columns.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d foreign keys for table %s %s not include (only) the expected columns.', array( $listener->countNonPasses( "${structureTest}::testFKColumns" ), $listener->countTests( "${structureTest}::testFKColumns" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testFKColumns" ), 'does', 'do' ) ) ); } } } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d expected foreign keys for table %s %s missing.', array( $listener->countNonPasses( "${structureTest}::testFKsExist" ), $listener->countTests( "${structureTest}::testFKsExist" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testFKsExist" ), 'is', 'are' ) ) ); $reporter->report( Reporter::STATUS_SKIPPED, 'testing expected columns of FKs to avoid spurious errors', null ); } } // Not critical to data testing. if ( $suite->testExists( "${structureTest}::testConstraintsNamed" ) ) { $testResult = $suite->run( $result, '/testConstraintsNamed/' ); if ( $listener->wasSuccessful( "${structureTest}::testConstraintsNamed" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All constraints of table %s that should be are explicitly named.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, 'Some constraints of table %s are not explicitly named that should be.', array( $table ) ); } } } } else { $reporter->report( Reporter::STATUS_FAILURE, 'Table %s does not exist.', array( $table ) ); $runDataTests = false; } } if ( RUN_MODE !== 'student' ) { $reporter->report( Reporter::STATUS_NOTE, 'Testing constraints of table %s.', array( $table ) ); /* If the table or required columns are missing or misnamed, or have issues like incorrect data types or lengths, we need to skip the data testing entirely, as the INSERTs will (may) just error out. We can't incorporate this into the if above, because we're using a completely different test suite. */ if ( $runDataTests ) { $suite = new Searchable_TestSuite( $dataTest ); if ( $suite->testExists( "${dataTest}::testColumnLegalValue" ) ) { $testResult = $suite->run( $result, '/testColumnLegalValue/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnLegalValue" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d legal values tested were accepted.', array( $listener->countTests( "${dataTest}::testColumnLegalValue" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d legal values tested %s rejected by a CHECK constraint.', array( $listener->countFails( "${dataTest}::testColumnLegalValue" ), $listener->countTests( "${dataTest}::testColumnLegalValue" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnLegalValue" ), 'was', 'were' ) ) ) ; } } if ( $suite->testExists( "${dataTest}::testColumnUnderflowValue" ) ) { $testResult = $suite->run( $result, '/testColumnUnderflowValue/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnUnderflowValue" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d underflow values were rejected by a CHECK constraint.', array( $listener->countTests( "${dataTest}::testColumnUnderflowValue" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d underflow values %s not rejected by a CHECK constraint.', array( $listener->countFails( "${dataTest}::testColumnUnderflowValue" ), $listener->countTests( "${dataTest}::testColumnUnderflowValue" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnUnderflowValue" ), 'was', 'were' ) ) ) ; } } if ( $suite->testExists( "${dataTest}::testColumnOverflowValueExplicit" ) ) { $testResult = $suite->run( $result, '/testColumnOverflowValueExplicit/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnOverflowValueExplicit" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d overflow values were rejected by a CHECK constraint.', array( $listener->countTests( "${dataTest}::testColumnOverflowValueExplicit" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d overflow values %s not rejected by a CHECK constraint.', array( $listener->countFails( "${dataTest}::testColumnOverflowValueExplicit" ), $listener->countTests( "${dataTest}::testColumnOverflowValueExplicit" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnOverflowValueExplicit" ), 'was', 'were' ) ) ) ; $reporter->report( Reporter::STATUS_WARNING, 'Checking values against column length...', null ); if ( $suite->testExists( "${dataTest}::testColumnOverflowValueImplicit" ) ) { /* Unfortunately, we can't test just the columns that failed the CHECK test. The failed TestCases are in $testResult->failures(), but we need the column name, which is hidden away in the private $data member of TestCase. We therefore have to test all the illegal values again to see if they're larger than the column. */ $testResult = $suite->run( $result, '/testColumnOverflowValueImplicit/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnOverflowValueImplicit" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d overflow values were rejected by exceeding the column length.', array( $listener->countTests( "${dataTest}::testColumnOverflowValueImplicit" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d overflow values %s not rejected by exceeding the column length.', array( $listener->countFails( "${dataTest}::testColumnOverflowValueImplicit" ), $listener->countTests( "${dataTest}::testColumnOverflowValueImplicit" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnOverflowValueImplicit" ), 'was', 'were' ) ) ) ; } } else { $reporter->report( Reporter::STATUS_SKIPPED, 'testColumnOverflowValueImplicit() because it is missing.', null ); } } } // Now do much the same for the enumerated values. This needs to be refactored! if ( $suite->testExists( "${dataTest}::testColumnIllegalValueExplicit" ) ) { $testResult = $suite->run( $result, '/testColumnIllegalValueExplicit/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnIllegalValueExplicit" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d illegal values tested were rejected by a CHECK constraint.', array( $listener->countTests( "${dataTest}::testColumnIllegalValueExplicit" ) ) ); } else { $checkFails = $listener->countFails( "${dataTest}::testColumnIllegalValueExplicit" ); $reporter->report( Reporter::STATUS_WARNING, '%d of %d illegal values tested %s not rejected by a CHECK constraint.', array( $checkFails, $listener->countTests( "${dataTest}::testColumnIllegalValueExplicit" ), Reporter::pluralise( $checkFails, 'was', 'were' ) ) ) ; $reporter->report( Reporter::STATUS_WARNING, 'Checking values against column length...', null ); if ( $suite->testExists( "${dataTest}::testColumnIllegalValueImplicit" ) ) { /* Unfortunately, we can't test just the columns that failed the CHECK test. The failed TestCases are in $testResult->failures(), but we need the column name, which is hidden away in the private $data member of TestCase. We therefore have to test all the illegal values again to see if they're larger than the column. We then make the big assumption that if all the values that failed the CHECK test did so because they exceeded the column length. If this is correct, then the number of CHECK fails will equal the number of column length passes. If not, then something more serious has probably gone wrong! */ $testResult = $suite->run( $result, '/testColumnIllegalValueImplicit/' ); $implicitPasses = $listener->countPasses( "${dataTest}::testColumnIllegalValueImplicit" ); $reporter->report( Reporter::STATUS_PASS, '%d of %d illegal values tested %s rejected by exceeding the column length.', array( $implicitPasses, $listener->countTests( "${dataTest}::testColumnIllegalValueImplicit" ), Reporter::pluralise( $implicitPasses, 'was', 'were' ) ) ) ; // Any leftovers? if ( $implicitPasses != $checkFails ) { /* $checkFails must by definition be >= $implicitPasses, as a "length exceeded" will /always/ fail the CHECK test, and a "check constraint" will /always/ fail the column length test. The two values will only differ when there are other exceptions in the mix, which will fail both tests. For example, suppose that two values fail the CHECK test with "length exceeded", one fails with "foo exception" and the remaining two pass. The first two will pass the column length test, and the remaining three will fail. */ $reporter->report( Reporter::STATUS_FAILURE, '%d illegal %s rejected in both tests—check for something unusual.', array( $checkFails - $implicitPasses, Reporter::pluralise( $checkFails - $implicitPasses, 'value was', 'values were' ) ) ) ; } else { $reporter->report( Reporter::STATUS_NOTE, 'This is OK, but not necessarily safe, as the column length may change in future.', null ); } } else { $reporter->report( Reporter::STATUS_SKIPPED, 'testColumnIllegalValueImplicit() because it is missing.', null ); } } } } else { $reporter->report( Reporter::STATUS_SKIPPED, 'data tests, as failures in the structure testing mean that they may not work.', null ); } } } $reporter->hr(); ?>
<?php require_once 'test_config.php'; require_once "PHPUnit/Autoload.php"; require_once 'TestListener/HTMLTestListener.php'; require_once 'TestListener/TextTestListener.php'; require_once 'TestListener/ANSITestListener.php'; require_once 'Reporter/TextReporter.php'; require_once 'Reporter/ANSIReporter.php'; require_once 'Reporter/HTMLReporter.php'; require_once 'Searchable_TestSuite.php'; require_once "Schema.php"; // I don't know that these two settings make any difference, but I'll leave them in for now. PHPUnit_Framework_Error_Warning::$enabled = FALSE; PHPUnit_Framework_Error_Notice::$enabled = FALSE; switch ( $outputMode ) { case 'HTML': $reporter = new HTMLReporter( OUTPUT_VERBOSITY ); $listener = new HTMLTestListener; break; case 'TEXT': $reporter = new TextReporter( OUTPUT_VERBOSITY ); $listener = new TextTestListener; break; case 'ANSI': $reporter = new ANSIReporter( OUTPUT_VERBOSITY ); $listener = new ANSITestListener; break; } $result = new PHPUnit_Framework_TestResult; $result->addListener( $listener ); // List of tables to be tested. This is used to build the corresponding test class names. require_once "${scenario}_table_list.php"; /* Hack! There's no easy way to create a global object constant, so the global report object is stored as a private static member in PHPUnit_Extensions_Database_TestCase_CreateTable, with corresponding public get/set static methods. Set it once at the start, and it'll stay set for the entire test run. Yay! */ PHPUnit_Extensions_Database_TestCase_CreateTable::setReporter( $reporter ); foreach ( $testTables as $table ) { $structureTest = "${scenario}_Test_${table}_structure"; $dataTest = "${scenario}_Test_${table}_data"; $runDataTests = true; require_once "${table}/${structureTest}.php"; require_once "${table}/${dataTest}.php"; $structurePassed = false; $listener->reset(); $reporter->hr(); $reporter->report( Reporter::STATUS_NOTE, 'Checking structure of table %s.', array( $table ) ); $suite = new Searchable_TestSuite( $structureTest ); // Critical to data testing. // TODO: is $testResult needed anymore? if ( $suite->testExists( 'testTableExists' ) ) { $testResult = $suite->run( $result, '/testTableExists/' ); $structurePassed = $listener->wasSuccessful( 'testTableExists' ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'Table %s exists.', array( $table ) ); // Critical to data testing. if ( $suite->testExists( "${structureTest}::testColumnExists" ) ) { $testResult = $suite->run( $result, '/testColumnExists/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnExists" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'Table %s contains all the expected columns.', array( $table ) ); if ( $suite->testExists( "${structureTest}::testColumnDataType" ) ) { $testResult = $suite->run( $result, '/testColumnDataType/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnDataType" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'All columns of table %s have data types compatible with the specification.', array( $table ) ); if ( $suite->testExists( "${structureTest}::testColumnLength" ) ) { $testResult = $suite->run( $result, '/testColumnLength/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnLength" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'All columns of table %s have lengths compatible with the specification.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d columns of table %s %s an unexpected column length.', array( $listener->countNonPasses( "${structureTest}::testColumnLength" ), $listener->countTests( "${structureTest}::testColumnLength" ), $table, Reporter::pluralise( "${structureTest}::testColumnLength", 'has', 'have' ) ) ) ; $runDataTests = false; } } } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d columns of table %s %s an unexpected data type.', array( $listener->countNonPasses( "${structureTest}::testColumnDataType" ), $listener->countTests( "${structureTest}::testColumnDataType" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnDataType" ), "has", "have" ) ) ) ; $reporter->report( Reporter::STATUS_SKIPPED, 'column length tests, as the data types do not match what was expected.', null ); $runDataTests = false; } } if ( RUN_MODE !== 'student' ) { // Critical to data testing. if ( $suite->testExists( "${structureTest}::testColumnNullability" ) ) { $testResult = $suite->run( $result, '/testColumnNullability/' ); $structurePassed = $listener->wasSuccessful( "${structureTest}::testColumnNullability" ); if ( $structurePassed ) { $reporter->report( Reporter::STATUS_PASS, 'All columns of table %s have the expected nullability.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d columns of table %s %s an unexpected nullability.', array( $listener->countNonPasses( "${structureTest}::testColumnNullability" ), $listener->countTests( "${structureTest}::testColumnNullability" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnNullability" ), "has", "have" ) ) ) ; $runDataTests = false; } } if ( $suite->testExists( "${structureTest}::testColumnDefault" ) ) { $testResult = $suite->run( $result, '/testColumnDefault/' ); if ( $listener->wasSuccessful( "${structureTest}::testColumnDefault" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All expected columns of table %s have the correct default values.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d expected columns of table %s %s an incorrect default value.', array( $listener->countNonPasses( "${structureTest}::testColumnDefault" ), $listener->countTests( "${structureTest}::testColumnDefault" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnDefault" ), "has", "have" ) ) ) ; } } } } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d expected columns of table %s %s either missing or misnamed.', array( $listener->countNonPasses( "${structureTest}::testColumnExists" ), $listener->countTests( "${structureTest}::testColumnExists" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testColumnExists" ), 'is', 'are' ) ) ) ; $reporter->report( Reporter::STATUS_SKIPPED, 'data type, length and nullability tests as they will include spurious errors.', null ); $runDataTests = false; } } if ( RUN_MODE !== 'student' ) { // Not critical to data testing. Need to run both PK tests in one pass as the columns test depends on the existence test. // Note that this causes a slight weirdness in the output where the "skipped test" message for testPKColumns is printed // before the "test failed" message for testPKExists. Not much we can do about this. if ( $suite->testExists( 'testPKExists' ) && $suite->testExists( 'testPKColumns' ) ) { $testResult = $suite->run( $result, '/testPK.*/' ); if ( $listener->wasSuccessful( 'testPKExists' ) ) { $reporter->report( Reporter::STATUS_PASS, 'Primary key of table %s exists.', array( $table ) ); if ( $listener->wasSuccessful( 'testPKColumns' ) ) { $reporter->report( Reporter::STATUS_PASS, 'Primary key of table %s includes (only) the expected columns.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, 'Primary key of table %s does not include (only) the expected columns.', array( $table ) ); } } else { $reporter->report( Reporter::STATUS_FAILURE, 'Primary key of table %s missing.', array( $table ) ); } } // Not critical to data testing. if ( $suite->testExists( "${structureTest}::testFKsExist" ) ) { $testResult = $suite->run( $result, '/testFKsExist/' ); if ( $listener->wasSuccessful( "${structureTest}::testFKsExist" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All expected foreign keys for table %s exist.', array( $table ) ); if ( $suite->testExists( "${structureTest}::testFKColumns" ) ) { $testResult = $suite->run( $result, '/testFKColumns/' ); if ( $listener->wasSuccessful( "${structureTest}::testFKColumns" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All foreign keys for table %s include (only) the expected columns.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d foreign keys for table %s %s not include (only) the expected columns.', array( $listener->countNonPasses( "${structureTest}::testFKColumns" ), $listener->countTests( "${structureTest}::testFKColumns" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testFKColumns" ), 'does', 'do' ) ) ); } } } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of the %d expected foreign keys for table %s %s missing.', array( $listener->countNonPasses( "${structureTest}::testFKsExist" ), $listener->countTests( "${structureTest}::testFKsExist" ), $table, Reporter::pluralise( $listener->countNonPasses( "${structureTest}::testFKsExist" ), 'is', 'are' ) ) ); $reporter->report( Reporter::STATUS_SKIPPED, 'testing expected columns of FKs to avoid spurious errors', null ); } } // Not critical to data testing. if ( $suite->testExists( "${structureTest}::testConstraintsNamed" ) ) { $testResult = $suite->run( $result, '/testConstraintsNamed/' ); if ( $listener->wasSuccessful( "${structureTest}::testConstraintsNamed" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All constraints of table %s that should be are explicitly named.', array( $table ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, 'Some constraints of table %s are not explicitly named that should be.', array( $table ) ); } } } } else { $reporter->report( Reporter::STATUS_FAILURE, 'Table %s does not exist.', array( $table ) ); $runDataTests = false; } } if ( RUN_MODE !== 'student' ) { $reporter->report( Reporter::STATUS_NOTE, 'Testing constraints of table %s.', array( $table ) ); /* If the table or required columns are missing or misnamed, or have issues like incorrect data types or lengths, we need to skip the data testing entirely, as the INSERTs will (may) just error out. We can't incorporate this into the if above, because we're using a completely different test suite. */ if ( $runDataTests ) { $suite = new Searchable_TestSuite( $dataTest ); if ( $suite->testExists( "${dataTest}::testColumnLegalValue" ) ) { $testResult = $suite->run( $result, '/testColumnLegalValue/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnLegalValue" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d legal values tested were accepted.', array( $listener->countTests( "${dataTest}::testColumnLegalValue" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d legal values tested %s rejected by a CHECK constraint.', array( $listener->countFails( "${dataTest}::testColumnLegalValue" ), $listener->countTests( "${dataTest}::testColumnLegalValue" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnLegalValue" ), 'was', 'were' ) ) ) ; } } if ( $suite->testExists( "${dataTest}::testColumnUnderflowValue" ) ) { $testResult = $suite->run( $result, '/testColumnUnderflowValue/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnUnderflowValue" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d underflow values were rejected by a CHECK constraint.', array( $listener->countTests( "${dataTest}::testColumnUnderflowValue" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d underflow values %s not rejected by a CHECK constraint.', array( $listener->countFails( "${dataTest}::testColumnUnderflowValue" ), $listener->countTests( "${dataTest}::testColumnUnderflowValue" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnUnderflowValue" ), 'was', 'were' ) ) ) ; } } if ( $suite->testExists( "${dataTest}::testColumnOverflowValueExplicit" ) ) { $testResult = $suite->run( $result, '/testColumnOverflowValueExplicit/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnOverflowValueExplicit" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d overflow values were rejected by a CHECK constraint.', array( $listener->countTests( "${dataTest}::testColumnOverflowValueExplicit" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d overflow values %s not rejected by a CHECK constraint.', array( $listener->countFails( "${dataTest}::testColumnOverflowValueExplicit" ), $listener->countTests( "${dataTest}::testColumnOverflowValueExplicit" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnOverflowValueExplicit" ), 'was', 'were' ) ) ) ; $reporter->report( Reporter::STATUS_WARNING, 'Checking values against column length...', null ); if ( $suite->testExists( "${dataTest}::testColumnOverflowValueImplicit" ) ) { /* Unfortunately, we can't test just the columns that failed the CHECK test. The failed TestCases are in $testResult->failures(), but we need the column name, which is hidden away in the private $data member of TestCase. We therefore have to test all the illegal values again to see if they're larger than the column. */ $testResult = $suite->run( $result, '/testColumnOverflowValueImplicit/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnOverflowValueImplicit" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d overflow values were rejected by exceeding the column length.', array( $listener->countTests( "${dataTest}::testColumnOverflowValueImplicit" ) ) ); } else { $reporter->report( Reporter::STATUS_FAILURE, '%d of %d overflow values %s not rejected by exceeding the column length.', array( $listener->countFails( "${dataTest}::testColumnOverflowValueImplicit" ), $listener->countTests( "${dataTest}::testColumnOverflowValueImplicit" ), Reporter::pluralise( $listener->countFails( "${dataTest}::testColumnOverflowValueImplicit" ), 'was', 'were' ) ) ) ; } } else { $reporter->report( Reporter::STATUS_SKIPPED, 'testColumnOverflowValueImplicit() because it is missing.', null ); } } } // Now do much the same for the enumerated values. This needs to be refactored! if ( $suite->testExists( "${dataTest}::testColumnIllegalValueExplicit" ) ) { $testResult = $suite->run( $result, '/testColumnIllegalValueExplicit/' ); if ( $listener->wasSuccessful( "${dataTest}::testColumnIllegalValueExplicit" ) ) { $reporter->report( Reporter::STATUS_PASS, 'All %d illegal values tested were rejected by a CHECK constraint.', array( $listener->countTests( "${dataTest}::testColumnIllegalValueExplicit" ) ) ); } else { $checkFails = $listener->countFails( "${dataTest}::testColumnIllegalValueExplicit" ); $reporter->report( Reporter::STATUS_WARNING, '%d of %d illegal values tested %s not rejected by a CHECK constraint.', array( $checkFails, $listener->countTests( "${dataTest}::testColumnIllegalValueExplicit" ), Reporter::pluralise( $checkFails, 'was', 'were' ) ) ) ; $reporter->report( Reporter::STATUS_WARNING, 'Checking values against column length...', null ); if ( $suite->testExists( "${dataTest}::testColumnIllegalValueImplicit" ) ) { /* Unfortunately, we can't test just the columns that failed the CHECK test. The failed TestCases are in $testResult->failures(), but we need the column name, which is hidden away in the private $data member of TestCase. We therefore have to test all the illegal values again to see if they're larger than the column. We then make the big assumption that if all the values that failed the CHECK test did so because they exceeded the column length. If this is correct, then the number of CHECK fails will equal the number of column length passes. If not, then something more serious has probably gone wrong! */ $testResult = $suite->run( $result, '/testColumnIllegalValueImplicit/' ); $implicitPasses = $listener->countPasses( "${dataTest}::testColumnIllegalValueImplicit" ); $reporter->report( Reporter::STATUS_PASS, '%d of %d illegal values tested %s rejected by exceeding the column length.', array( $implicitPasses, $listener->countTests( "${dataTest}::testColumnIllegalValueImplicit" ), Reporter::pluralise( $implicitPasses, 'was', 'were' ) ) ) ; // Any leftovers? if ( $implicitPasses != $checkFails ) { /* $checkFails must by definition be >= $implicitPasses, as a "length exceeded" will /always/ fail the CHECK test, and a "check constraint" will /always/ fail the column length test. The two values will only differ when there are other exceptions in the mix, which will fail both tests. For example, suppose that two values fail the CHECK test with "length exceeded", one fails with "foo exception" and the remaining two pass. The first two will pass the column length test, and the remaining three will fail. */ $reporter->report( Reporter::STATUS_FAILURE, '%d illegal %s rejected in both tests—check for something unusual.', array( $checkFails - $implicitPasses, Reporter::pluralise( $checkFails - $implicitPasses, 'value was', 'values were' ) ) ) ; } else { $reporter->report( Reporter::STATUS_NOTE, 'This is OK, but not necessarily safe, as the column length may change in future.', null ); } } else { $reporter->report( Reporter::STATUS_SKIPPED, 'testColumnIllegalValueImplicit() because it is missing.', null ); } } } } else { $reporter->report( Reporter::STATUS_SKIPPED, 'data tests, as failures in the structure testing mean that they may not work.', null ); } } } $reporter->hr(); ?>
Show line notes below