<?php /* Test-Simple-OO.php: A workalike of Perl's Test::Simple for PHP. Why Test-Simple? Test-Simple is a super simple way to start testing RIGHT NOW. Why ok and not ok? Test-Simple produces TAP compliant output. For more on TAP, see: http://testanything.org For the TAP spec, see: http://search.cpan.org/dist/TAP/TAP.pm Why plan? Planning is enforced because, unless you explicitly declare your intent, the test set cannot ensure that all the required testing was performed. An assumption could be made, but error prone assumptions are exactly what testing is here to prevent. Other testing libraries: You can replace Test-Simple with Test-More without making any changes to existing test code, providing access to further testing methods. You can also replace any other PHP Test::More workalike library out there with Test-More.php and it will work without making any changes to the code. Assertions: produce TAP output provide basic testing functions (plan, ok) exit with error code: 0 all tests successful 255 test died or all passed but wrong # of tests run any other number how many failed (including missing or extras) Example: require_once('Test-More-OO.php'); $t = new TestMore(); $t->plan(2); $t->ok(1 + 1 = 2, 'One plus one equals two'); $t->ok( doSomethingAndReturnTrue() , 'doSomethingAndReturnTrue() successful'); Procedural Example: require_once('Test-Simple'); plan(2); ok(1 + 1 = 2, 'One plus one equals two'); ok( doSomethingAndReturnTrue() , 'doSomethingAndReturnTrue() successful'); From a browser If you are running Test-Simple on a web server and want slightly more web-readable output, call the web_output() method/function. Updates Updates will be posted to the Google code page: http://code.google.com/p/test-more-php/ Bugs Please file bug reports via the Issues tracker at the google code page. Acknowledgements Michael G Schwern: http://search.cpan.org/~mschwern/Test-Simple/ Chris Shiflet: http://shiflett.org/code/test-more.php Author Copyright RJ Herrick <RJHerrick@beyondlogical.net> 2009, 2010 */ class TestSimple { protected $Results = array('Failed'=>NULL,'Passed'=>NULL); protected $TestName = array(); protected $TestsRun = 0; protected $Skips; protected $NumberOfTests; protected $CurrentTestNumber; protected $Filter; protected $notes; function plan ($NumberOfTests = NULL, $SkipReason = '') { // Get/set intended number of tests if ( is_int($this->NumberOfTests) && !is_null($NumberOfTests) ) $this->diag('The plan was already output.'); if ( $NumberOfTests === 'no_plan' ) { // Equivalent to done_testing() at end of test script $this->NumberOfTests = $NumberOfTests; return; } else if ( $NumberOfTests === 'skip_all' ) { // Equivalent to done_testing() at end of test script $this->NumberOfTests = $NumberOfTests; $this->SkipAllReason = $SkipReason; $this->diag("Skipping all tests: $SkipReason"); return; } // Return current value if no params passed (query to the plan) if ( !func_num_args() && isset($this->NumberOfTests) ) return $this->NumberOfTests; // Number of tests looks acceptable if (!is_int($NumberOfTests) || 0 > $NumberOfTests) $this->bail( "Number of tests must be a positive integer. You gave it '$NumberOfTests'" ); // If just reporting $skipinfo = ''; if ($this->NumberOfTests === 'skip_all') $skipinfo = ' # '.$this->SkipAllReason; echo "1..${NumberOfTests}${skipinfo}\n"; $this->NumberOfTests = $NumberOfTests; return; } function ok ($Result = NULL, $TestName = NULL) { // Confirm param 1 is true (in the PHP sense) // Unload the buffer regularly if ($this->Filter) { ob_flush(); } $this->CurrentTestNumber++; $this->TestsRun++; if ($this->Skips) { $this->Skips--; $this->TestsSkipped++; echo('ok '.$this->CurrentTestNumber.' # skip '.$this->SkipReason."\n"); return TRUE; } if ($this->NumberOfTests === 'skip_all') { $this->TestsSkipped++; $this->diag("SKIP '$TestName'"); echo('ok '.$this->CurrentTestNumber." # skip\n"); return TRUE; } if ( func_num_args() == 0 ) $this->bail('You must pass ok() a result to evaluate.'); if ( func_num_args() == 2 ) $this->TestName[$this->CurrentTestNumber] = $TestName; if ( func_num_args() > 2 ) $this->bail('Wrong number of arguments passed to ok()'); $verdict = $Result ? 'Passed' : 'Failed'; $this->Results[$verdict]++; #$this->TestResult[$this->CurrentTestNumber] = $verdict; $caption = isset($this->TestName[$this->CurrentTestNumber]) ? $this->TestName[$this->CurrentTestNumber] : ''; $title = $this->CurrentTestNumber . (isset($this->TestName[$this->CurrentTestNumber]) ? (' - '.$this->TestName[$this->CurrentTestNumber]) : ''); if ($verdict === 'Passed') { echo "ok $title\n"; return TRUE; } else { echo $this->LastFail = "not ok $title\n"; $stack = isset($this->Backtrace) ? $this->Backtrace : debug_backtrace(); foreach (array_reverse($stack) as $frame) { if (isset($frame["object"]) && $frame["object"] == $this) { $file = $frame["file"]; $line = $frame["line"]; break; } } unset($this->Backtrace); if ($caption) { $this->diag(" Failed test '$caption'"," at $file line $line."); $this->LastFail .= "# Failed test '$caption'\n# at $file line $line."; } else { $this->diag(" Failed test at $file line $line."); $this->LastFail .= "# Failed test at $file line $line."; } return FALSE; } } function done_testing () { // Change of plans (if there was one in the first place) $this->plan((int)$this->TestsRun); return; } function bail ($message = '') { // Problem running the program TestSimple::_bail($message); } static function _bail ($message = '') { echo "Bail out! $message\n"; throw new RuntimeException("Bail out! $message"); } function diag() { // Print a diagnostic comment $diagnostics = func_get_args(); $msg = ''; foreach ($diagnostics as $line) $msg .= "# ".str_replace("\n","\n# ",$line)."\n"; echo $msg; if ($this->Filter) ob_flush(); return $msg; } function __destruct () { // Parting remarks and proper exit code # if ($this->NumberOfTests === 'no_plan') done_testing(); # if ($this->NumberOfTests === 'skip_all') plan(0); if ($this->TestsRun && !isset($this->NumberOfTests)) { echo "# Tests were run but no plan() was declared and done_testing() was not seen.\n"; } else { if ($this->TestsRun !== $this->NumberOfTests) echo("# Looks like you planned ".(int)$this->NumberOfTests .' tests but ran '.(int)$this->TestsRun.".\n"); if ($this->Results['Failed']) echo("# Looks like you failed ". $this->Results['Failed'] .' tests of '.(int)$this->TestsRun.".\n"); } // an extension to help debug if ($this->notes) echo $this->notes; if ($this->Filter) ob_end_flush(); $retval = ($this->Results['Failed'] > 254) ? 254 : $this->Results['Failed']; return; } function web_output($callback = NULL) { // Basic web formatting (newlines) of output via ob filter if (isset($callback)) $this->Filter = $callback; if (!isset($this->Filter)) $this->Filter = create_function('$string','$output = str_replace("\n","<br />\n",$string); return $output;'); ob_start($this->Filter); } } ?>